Merge pull request #735 from NyxStudios/general-devel

Merge dev to master
This commit is contained in:
Lucas Nicodemus 2013-12-29 11:28:44 -08:00
commit 2f41b4dd84
50 changed files with 5832 additions and 3546 deletions

3
.gitmodules vendored Normal file
View file

@ -0,0 +1,3 @@
[submodule "TerrariaServerAPI"]
path = TerrariaServerAPI
url = https://github.com/Deathmax/TerrariaAPI-Server.git

View file

@ -13,6 +13,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UnitTests", "UnitTests\Unit
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TShockRestTestPlugin", "TShockRestTestPlugin\TShockRestTestPlugin.csproj", "{F2FEDAFB-58DE-4611-9168-A86112C346C7}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TShockRestTestPlugin", "TShockRestTestPlugin\TShockRestTestPlugin.csproj", "{F2FEDAFB-58DE-4611-9168-A86112C346C7}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TerrariaAPI-Server", "TerrariaServerAPI\TerrariaAPI-Server.csproj", "{549A7941-D9C9-4544-BAC8-D9EEEAB4D777}"
EndProject
Global Global
GlobalSection(TestCaseManagementSettings) = postSolution GlobalSection(TestCaseManagementSettings) = postSolution
CategoryFile = Terraria.vsmdi CategoryFile = Terraria.vsmdi
@ -52,6 +54,18 @@ Global
{F2FEDAFB-58DE-4611-9168-A86112C346C7}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU {F2FEDAFB-58DE-4611-9168-A86112C346C7}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{F2FEDAFB-58DE-4611-9168-A86112C346C7}.Release|Mixed Platforms.Build.0 = Release|Any CPU {F2FEDAFB-58DE-4611-9168-A86112C346C7}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{F2FEDAFB-58DE-4611-9168-A86112C346C7}.Release|x86.ActiveCfg = Release|Any CPU {F2FEDAFB-58DE-4611-9168-A86112C346C7}.Release|x86.ActiveCfg = Release|Any CPU
{549A7941-D9C9-4544-BAC8-D9EEEAB4D777}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{549A7941-D9C9-4544-BAC8-D9EEEAB4D777}.Debug|Any CPU.Build.0 = Debug|Any CPU
{549A7941-D9C9-4544-BAC8-D9EEEAB4D777}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{549A7941-D9C9-4544-BAC8-D9EEEAB4D777}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{549A7941-D9C9-4544-BAC8-D9EEEAB4D777}.Debug|x86.ActiveCfg = Debug|x86
{549A7941-D9C9-4544-BAC8-D9EEEAB4D777}.Debug|x86.Build.0 = Debug|x86
{549A7941-D9C9-4544-BAC8-D9EEEAB4D777}.Release|Any CPU.ActiveCfg = Release|Any CPU
{549A7941-D9C9-4544-BAC8-D9EEEAB4D777}.Release|Any CPU.Build.0 = Release|Any CPU
{549A7941-D9C9-4544-BAC8-D9EEEAB4D777}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{549A7941-D9C9-4544-BAC8-D9EEEAB4D777}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{549A7941-D9C9-4544-BAC8-D9EEEAB4D777}.Release|x86.ActiveCfg = Release|x86
{549A7941-D9C9-4544-BAC8-D9EEEAB4D777}.Release|x86.Build.0 = Release|x86
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE

2335
TShockAPI/Commands.cs Normal file → Executable file

File diff suppressed because it is too large Load diff

53
TShockAPI/ConfigFile.cs Normal file → Executable file
View file

@ -80,6 +80,7 @@ namespace TShockAPI
[Description("Bans a hardcore player on death.")] public bool BanOnMediumcoreDeath; [Description("Bans a hardcore player on death.")] public bool BanOnMediumcoreDeath;
[Description("Enable/disable Terraria's built in auto save.")] public bool AutoSave = 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;
@ -105,6 +106,8 @@ namespace TShockAPI
[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 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 [Description("Selects the default group name to place new registrants under.")] public string
@ -135,8 +138,6 @@ namespace TShockAPI
[Description("This will turn on token requirement for the public REST API endpoints.")] public bool [Description("This will turn on token requirement for the public REST API endpoints.")] public bool
EnableTokenEndpointAuthentication; EnableTokenEndpointAuthentication;
[Description("Deprecated. Use ServerName instead.")] public string ServerNickname = "TShock Server";
[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;
@ -145,19 +146,15 @@ namespace TShockAPI
[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(
"Some tiles are 'fixed' by not letting TShock handle them. Disabling this may break certain aesthetic tiles.")] public
bool EnableInsecureTileFixes = true;
[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 inventory checks, EXPERIMENTAL")] public bool ServerSideInventory; [Description("Enable server side characters, This stops the client from saving character data! EXPERIMENTAL!!!!!")] public bool ServerSideCharacter;
[Description("How often SSI should save, in minutes.")] public int ServerSideInventorySave = 15; [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("Time, in milliseconds, to disallow discarding items after logging in when ServerSideInventory is ON.")] public int LogonDiscardThreshold=250;
@ -169,7 +166,7 @@ namespace TShockAPI
"Changes ingame chat format: {0} = Group Name, {1} = Group Prefix, {2} = Player Name, {3} = Group Suffix, {4} = Chat Message" "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 chat format when using chat above heads. This begins with a player name wrapped in brackets, as per Terraria's formatting. Same formatting as ChatFormat.")] public string ChatAboveHeadsFormat = "{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("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";
@ -206,6 +203,10 @@ namespace TShockAPI
[Description("Disable users from being able to login with account password when joining.")] public bool [Description("Disable users from being able to login with account password when joining.")] public bool
DisableLoginBeforeJoin; DisableLoginBeforeJoin;
[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("Allows users to register any username with /register.")] public bool AllowRegisterAnyUsername;
[Description("Allows users to login with any username with /login.")] public bool AllowLoginAnyUsername = true; [Description("Allows users to login with any username with /login.")] public bool AllowLoginAnyUsername = true;
@ -222,7 +223,10 @@ namespace TShockAPI
[Description("Allow ice placement even when user does not have canbuild.")] public bool AllowIce = false; [Description("Allow ice placement even when user does not have canbuild.")] public bool AllowIce = false;
[Description("Allows corrutption to spread when a world is hardmode.")] public bool AllowCorruptionCreep = true; [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 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;
@ -234,8 +238,6 @@ namespace TShockAPI
[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 banks on SSI.")] public bool DisablePiggybanksOnSSI = false;
[Description("Prevent players from interacting with the world if dead.")] public bool PreventDeadModification = [Description("Prevent players from interacting with the world if dead.")] public bool PreventDeadModification =
true; true;
@ -263,11 +265,22 @@ namespace TShockAPI
[Description("A dictionary of REST tokens that external applications may use to make queries to your server.")] [Description("A dictionary of REST tokens that external applications may use to make queries to your server.")]
public Dictionary<string, SecureRest.TokenData> ApplicationRestTokens = new Dictionary<string, SecureRest.TokenData>(); public Dictionary<string, SecureRest.TokenData> ApplicationRestTokens = new Dictionary<string, SecureRest.TokenData>();
[Description("The maximum value that a character may have for health.")] public int MaxHealth = 400;
[Description("The maximum value that a character may have for health.")] public int MaxMana = 400;
[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 = 3;
[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;
/// <summary> /// <summary>
/// Reads a configuration file from a given path /// Reads a configuration file from a given path
/// </summary> /// </summary>
@ -351,10 +364,10 @@ namespace TShockAPI
var def = field.GetValue(defaults); var def = field.GetValue(defaults);
sb.AppendLine("## {0} ".SFormat(name)); sb.AppendLine("{0} ".SFormat(name));
sb.AppendLine("**Type:** {0} ".SFormat(type)); sb.AppendLine("Type: {0} ".SFormat(type));
sb.AppendLine("**Description:** {0} ".SFormat(desc)); sb.AppendLine("Description: {0} ".SFormat(desc));
sb.AppendLine("**Default:** \"{0}\" ".SFormat(def)); sb.AppendLine("Default: \"{0}\" ".SFormat(def));
sb.AppendLine(); sb.AppendLine();
} }

View file

@ -34,6 +34,7 @@ namespace TShockAPI.DB
var table = new SqlTable("Bans", var table = new SqlTable("Bans",
new SqlColumn("IP", MySqlDbType.String, 16) {Primary = true}, new SqlColumn("IP", MySqlDbType.String, 16) {Primary = true},
new SqlColumn("Name", MySqlDbType.Text), new SqlColumn("Name", MySqlDbType.Text),
new SqlColumn("UUID", MySqlDbType.Text),
new SqlColumn("Reason", MySqlDbType.Text), new SqlColumn("Reason", MySqlDbType.Text),
new SqlColumn("BanningUser", MySqlDbType.Text), new SqlColumn("BanningUser", MySqlDbType.Text),
new SqlColumn("Date", MySqlDbType.Text), new SqlColumn("Date", MySqlDbType.Text),
@ -54,6 +55,11 @@ namespace TShockAPI.DB
} }
} }
/// <summary>
/// Gets a ban by IP.
/// </summary>
/// <param name="ip">The IP.</param>
/// <returns>The ban.</returns>
public Ban GetBanByIp(string ip) public Ban GetBanByIp(string ip)
{ {
try try
@ -61,7 +67,7 @@ namespace TShockAPI.DB
using (var reader = database.QueryReader("SELECT * FROM Bans WHERE IP=@0", ip)) using (var reader = database.QueryReader("SELECT * FROM Bans WHERE IP=@0", ip))
{ {
if (reader.Read()) if (reader.Read())
return new Ban(reader.Get<string>("IP"), reader.Get<string>("Name"), reader.Get<string>("Reason"), reader.Get<string>("BanningUser"), reader.Get<string>("Date"), reader.Get<string>("Expiration")); return new Ban(reader.Get<string>("IP"), reader.Get<string>("Name"), reader.Get<string>("UUID"), reader.Get<string>("Reason"), reader.Get<string>("BanningUser"), reader.Get<string>("Date"), reader.Get<string>("Expiration"));
} }
} }
catch (Exception ex) catch (Exception ex)
@ -71,6 +77,9 @@ namespace TShockAPI.DB
return null; return null;
} }
/// <summary>
/// Gets a list of bans.
/// </summary>
public List<Ban> GetBans() public List<Ban> GetBans()
{ {
List<Ban> banlist = new List<Ban>(); List<Ban> banlist = new List<Ban>();
@ -80,7 +89,7 @@ namespace TShockAPI.DB
{ {
while (reader.Read()) while (reader.Read())
{ {
banlist.Add(new Ban(reader.Get<string>("IP"), reader.Get<string>("Name"), reader.Get<string>("Reason"), reader.Get<string>("BanningUser"), reader.Get<string>("Date"), reader.Get<string>("Expiration"))); banlist.Add(new Ban(reader.Get<string>("IP"), reader.Get<string>("Name"), reader.Get<string>("UUID"), reader.Get<string>("Reason"), reader.Get<string>("BanningUser"), reader.Get<string>("Date"), reader.Get<string>("Expiration")));
} }
return banlist; return banlist;
} }
@ -93,6 +102,12 @@ namespace TShockAPI.DB
return null; return null;
} }
/// <summary>
/// Gets a ban by name.
/// </summary>
/// <param name="name">The name.</param>
/// <param name="casesensitive">Whether to check with case sensitivity.</param>
/// <returns>The ban.</returns>
public Ban GetBanByName(string name, bool casesensitive = true) public Ban GetBanByName(string name, bool casesensitive = true)
{ {
try try
@ -103,7 +118,29 @@ namespace TShockAPI.DB
using (var reader = database.QueryReader("SELECT * FROM Bans WHERE " + namecol + "=@0", name)) using (var reader = database.QueryReader("SELECT * FROM Bans WHERE " + namecol + "=@0", name))
{ {
if (reader.Read()) if (reader.Read())
return new Ban(reader.Get<string>("IP"), reader.Get<string>("Name"), reader.Get<string>("Reason"), reader.Get<string>("BanningUser"), reader.Get<string>("Date"), reader.Get<string>("Expiration")); return new Ban(reader.Get<string>("IP"), reader.Get<string>("Name"), reader.Get<string>("UUID"), reader.Get<string>("Reason"), reader.Get<string>("BanningUser"), reader.Get<string>("Date"), reader.Get<string>("Expiration"));
}
}
catch (Exception ex)
{
Log.Error(ex.ToString());
}
return null;
}
/// <summary>
/// Gets a ban by UUID.
/// </summary>
/// <param name="uuid">The UUID.</param>
/// <returns>The ban.</returns>
public Ban GetBanByUUID(string uuid)
{
try
{
using (var reader = database.QueryReader("SELECT * FROM Bans WHERE UUID=@0", uuid))
{
if (reader.Read())
return new Ban(reader.Get<string>("IP"), reader.Get<string>("Name"), reader.Get<string>("UUID"), reader.Get<string>("Reason"), reader.Get<string>("BanningUser"), reader.Get<string>("Date"), reader.Get<string>("Expiration"));
} }
} }
catch (Exception ex) catch (Exception ex)
@ -117,14 +154,14 @@ namespace TShockAPI.DB
[Obsolete("This method is for signature compatibility for external code only")] [Obsolete("This method is for signature compatibility for external code only")]
public bool AddBan(string ip, string name, string reason) public bool AddBan(string ip, string name, string reason)
{ {
return AddBan(ip, name, reason, false, "", ""); return AddBan(ip, name, "", reason, false, "", "");
} }
#endif #endif
public bool AddBan(string ip, string name = "", string reason = "", bool exceptions = false, string banner = "", string expiration = "") public bool AddBan(string ip, string name = "", string uuid = "", string reason = "", bool exceptions = false, string banner = "", string expiration = "")
{ {
try try
{ {
return database.Query("INSERT INTO Bans (IP, Name, Reason, BanningUser, Date, Expiration) VALUES (@0, @1, @2, @3, @4, @5);", ip, name, reason, banner, DateTime.Now.ToString("G"), expiration) != 0; return database.Query("INSERT INTO Bans (IP, Name, UUID, Reason, BanningUser, Date, Expiration) VALUES (@0, @1, @2, @3, @4, @5, @6);", ip, name, uuid, reason, banner, DateTime.UtcNow.ToString("s"), expiration) != 0;
} }
catch (Exception ex) catch (Exception ex)
{ {
@ -181,6 +218,8 @@ namespace TShockAPI.DB
public string Name { get; set; } public string Name { get; set; }
public string UUID { get; set; }
public string Reason { get; set; } public string Reason { get; set; }
public string BanningUser { get; set; } public string BanningUser { get; set; }
@ -189,10 +228,11 @@ namespace TShockAPI.DB
public string Expiration { get; set; } public string Expiration { get; set; }
public Ban(string ip, string name, string reason, string banner, string date, string exp) public Ban(string ip, string name, string uuid, string reason, string banner, string date, string exp)
{ {
IP = ip; IP = ip;
Name = name; Name = name;
UUID = UUID;
Reason = reason; Reason = reason;
BanningUser = banner; BanningUser = banner;
Date = date; Date = date;
@ -203,6 +243,7 @@ namespace TShockAPI.DB
{ {
IP = string.Empty; IP = string.Empty;
Name = string.Empty; Name = string.Empty;
UUID = string.Empty;
Reason = string.Empty; Reason = string.Empty;
BanningUser = ""; BanningUser = "";
Date = ""; Date = "";

149
TShockAPI/DB/CharacterManager.cs Executable file
View file

@ -0,0 +1,149 @@
/*
TShock, a server mod for Terraria
Copyright (C) 2011-2013 Nyx Studios (fka. The TShock Team)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
using System;
using System.Data;
using MySql.Data.MySqlClient;
namespace TShockAPI.DB
{
public class CharacterManager
{
public IDbConnection database;
public CharacterManager(IDbConnection db)
{
database = db;
var table = new SqlTable("tsCharacter",
new SqlColumn("Account", MySqlDbType.Int32) {Primary = true},
new SqlColumn("Health", MySqlDbType.Int32),
new SqlColumn("MaxHealth", MySqlDbType.Int32),
new SqlColumn("Mana", MySqlDbType.Int32),
new SqlColumn("MaxMana", MySqlDbType.Int32),
new SqlColumn("Inventory", MySqlDbType.Text),
new SqlColumn("spawnX", MySqlDbType.Int32),
new SqlColumn("spawnY", MySqlDbType.Int32)
);
var creator = new SqlTableCreator(db,
db.GetSqlType() == SqlType.Sqlite
? (IQueryBuilder) new SqliteQueryCreator()
: new MysqlQueryCreator());
creator.EnsureExists(table);
}
public PlayerData GetPlayerData(TSPlayer player, int acctid)
{
PlayerData playerData = new PlayerData(player);
try
{
using (var reader = database.QueryReader("SELECT * FROM tsCharacter WHERE Account=@0", acctid))
{
if (reader.Read())
{
playerData.exists = true;
playerData.health = reader.Get<int>("Health");
playerData.maxHealth = reader.Get<int>("MaxHealth");
playerData.mana = reader.Get<int>("Mana");
playerData.maxMana = reader.Get<int>("MaxMana");
playerData.inventory = NetItem.Parse(reader.Get<string>("Inventory"));
playerData.spawnX = reader.Get<int>("spawnX");
playerData.spawnY = reader.Get<int>("spawnY");
return playerData;
}
}
}
catch (Exception ex)
{
Log.Error(ex.ToString());
}
return playerData;
}
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";
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);
return true;
}
catch (Exception ex)
{
Log.Error(ex.ToString());
}
return false;
}
public bool InsertPlayerData(TSPlayer player)
{
PlayerData playerData = player.PlayerData;
if (!player.IsLoggedIn)
return false;
if (!GetPlayerData(player, player.UserID).exists)
{
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);
return true;
}
catch (Exception ex)
{
Log.Error(ex.ToString());
}
}
else
{
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);
return true;
}
catch (Exception ex)
{
Log.Error(ex.ToString());
}
}
return false;
}
public bool RemovePlayer(int userid)
{
try
{
database.Query("DELETE FROM tsCharacter WHERE Account = @0;", userid);
return true;
}
catch (Exception ex)
{
Log.Error(ex.ToString());
}
return false;
}
}
}

View file

@ -53,18 +53,18 @@ namespace TShockAPI.DB
LoadPermisions(); LoadPermisions();
// Add default groups if they don't exist // Add default groups if they don't exist
AddDefaultGroup(TShock.Config.DefaultGuestGroupName, "", AddDefaultGroup("guest", "",
string.Join(",", Permissions.canbuild, Permissions.canregister, Permissions.canlogin, Permissions.canpartychat, string.Join(",", Permissions.canbuild, Permissions.canregister, Permissions.canlogin, Permissions.canpartychat,
Permissions.cantalkinthird)); Permissions.cantalkinthird, Permissions.canchat));
AddDefaultGroup("default", TShock.Config.DefaultGuestGroupName, AddDefaultGroup("default", "guest",
string.Join(",", Permissions.warp, Permissions.canchangepassword)); string.Join(",", Permissions.warp, Permissions.canchangepassword));
AddDefaultGroup("newadmin", "default", AddDefaultGroup("newadmin", "default",
string.Join(",", Permissions.kick, Permissions.editspawn, Permissions.reservedslot)); string.Join(",", Permissions.kick, Permissions.editspawn, Permissions.reservedslot));
AddDefaultGroup("admin", "newadmin", AddDefaultGroup("admin", "newadmin",
string.Join(",", Permissions.ban, Permissions.whitelist, Permissions.causeevents, Permissions.spawnboss, string.Join(",", Permissions.ban, Permissions.whitelist, "tshock.world.time.*", Permissions.spawnboss,
Permissions.spawnmob, Permissions.managewarp, Permissions.time, Permissions.tp, Permissions.slap, Permissions.spawnmob, Permissions.managewarp, Permissions.time, Permissions.tp, Permissions.slap,
Permissions.kill, Permissions.logs, Permissions.kill, Permissions.logs,
Permissions.immunetokick, Permissions.tphere)); Permissions.immunetokick, Permissions.tphere));
@ -181,7 +181,7 @@ namespace TShockAPI.DB
/// <param name="parentname">parent of group</param> /// <param name="parentname">parent of group</param>
/// <param name="permissions">permissions</param> /// <param name="permissions">permissions</param>
/// <param name="chatcolor">chatcolor</param> /// <param name="chatcolor">chatcolor</param>
public void UpdateGroup(string name, string parentname, string permissions, string chatcolor) public void UpdateGroup(string name, string parentname, string permissions, string chatcolor, string suffix, string prefix)
{ {
Group group = GetGroupByName(name); Group group = GetGroupByName(name);
if (group == null) if (group == null)
@ -210,13 +210,17 @@ namespace TShockAPI.DB
// Ensure any group validation is also persisted to the DB. // Ensure any group validation is also persisted to the DB.
var newGroup = new Group(name, parent, chatcolor, permissions); var newGroup = new Group(name, parent, chatcolor, permissions);
string query = "UPDATE GroupList SET Parent=@0, Commands=@1, ChatColor=@2 WHERE GroupName=@3"; newGroup.Prefix = prefix;
if (database.Query(query, parentname, newGroup.Permissions, string.Format("{0},{1},{2}", newGroup.R, newGroup.G, newGroup.B), name) != 1) newGroup.Suffix = suffix;
string query = "UPDATE GroupList SET Parent=@0, Commands=@1, ChatColor=@2, Suffix=@3, Prefix=@4 WHERE GroupName=@5";
if (database.Query(query, parentname, newGroup.Permissions, newGroup.ChatColor, suffix, prefix, name) != 1)
throw new GroupManagerException(string.Format("Failed to update group \"{0}\".", name)); throw new GroupManagerException(string.Format("Failed to update group \"{0}\".", name));
group.ChatColor = chatcolor; group.ChatColor = chatcolor;
group.Permissions = permissions; group.Permissions = permissions;
group.Parent = parent; group.Parent = parent;
group.Prefix = prefix;
group.Suffix = suffix;
} }
#if COMPAT_SIGS #if COMPAT_SIGS

View file

@ -57,14 +57,16 @@ namespace TShockAPI.DB
private static readonly Dictionary<MySqlDbType, string> TypesAsStrings = new Dictionary<MySqlDbType, string> private static readonly Dictionary<MySqlDbType, string> TypesAsStrings = new Dictionary<MySqlDbType, string>
{ {
{MySqlDbType.VarChar, "TEXT"}, { MySqlDbType.VarChar, "TEXT" },
{MySqlDbType.String, "TEXT"}, { MySqlDbType.String, "TEXT" },
{MySqlDbType.Text, "TEXT"}, { MySqlDbType.Text, "TEXT" },
{MySqlDbType.TinyText, "TEXT"}, { MySqlDbType.TinyText, "TEXT" },
{MySqlDbType.MediumText, "TEXT"}, { MySqlDbType.MediumText, "TEXT" },
{MySqlDbType.LongText, "TEXT"}, { MySqlDbType.LongText, "TEXT" },
{MySqlDbType.Int32, "INTEGER"}, { MySqlDbType.Float, "REAL" },
{MySqlDbType.Blob, "BLOB"}, { MySqlDbType.Double, "REAL" },
{ MySqlDbType.Int32, "INTEGER" },
{ MySqlDbType.Blob, "BLOB" },
}; };
public string DbTypeToString(MySqlDbType type, int? length) public string DbTypeToString(MySqlDbType type, int? length)
@ -72,7 +74,7 @@ namespace TShockAPI.DB
string ret; string ret;
if (TypesAsStrings.TryGetValue(type, out ret)) if (TypesAsStrings.TryGetValue(type, out ret))
return ret; return ret;
throw new NotImplementedException(Enum.GetName(typeof (MySqlDbType), type)); throw new NotImplementedException(Enum.GetName(typeof(MySqlDbType), type));
} }
protected override string EscapeTableName(string table) protected override string EscapeTableName(string table)
@ -104,21 +106,23 @@ namespace TShockAPI.DB
private static readonly Dictionary<MySqlDbType, string> TypesAsStrings = new Dictionary<MySqlDbType, string> private static readonly Dictionary<MySqlDbType, string> TypesAsStrings = new Dictionary<MySqlDbType, string>
{ {
{MySqlDbType.VarChar, "VARCHAR"}, { MySqlDbType.VarChar, "VARCHAR" },
{MySqlDbType.String, "CHAR"}, { MySqlDbType.String, "CHAR" },
{MySqlDbType.Text, "TEXT"}, { MySqlDbType.Text, "TEXT" },
{MySqlDbType.TinyText, "TINYTEXT"}, { MySqlDbType.TinyText, "TINYTEXT" },
{MySqlDbType.MediumText, "MEDIUMTEXT"}, { MySqlDbType.MediumText, "MEDIUMTEXT" },
{MySqlDbType.LongText, "LONGTEXT"}, { MySqlDbType.LongText, "LONGTEXT" },
{MySqlDbType.Int32, "INT"}, { MySqlDbType.Float, "FLOAT" },
{ MySqlDbType.Double, "DOUBLE" },
{ MySqlDbType.Int32, "INT" },
}; };
public string DbTypeToString(MySqlDbType type, int? length) public string DbTypeToString(MySqlDbType type, int? length)
{ {
string ret; string ret;
if (TypesAsStrings.TryGetValue(type, out ret)) if (TypesAsStrings.TryGetValue(type, out ret))
return ret + (length != null ? "({0})".SFormat((int) length) : ""); return ret + (length != null ? "({0})".SFormat((int)length) : "");
throw new NotImplementedException(Enum.GetName(typeof (MySqlDbType), type)); throw new NotImplementedException(Enum.GetName(typeof(MySqlDbType), type));
} }
protected override string EscapeTableName(string table) protected override string EscapeTableName(string table)

View file

@ -1,107 +0,0 @@
/*
TShock, a server mod for Terraria
Copyright (C) 2011-2013 Nyx Studios (fka. The TShock Team)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
using System;
using System.Data;
using MySql.Data.MySqlClient;
namespace TShockAPI.DB
{
public class InventoryManager
{
public IDbConnection database;
public InventoryManager(IDbConnection db)
{
database = db;
var table = new SqlTable("Inventory",
new SqlColumn("Account", MySqlDbType.Int32) {Primary = true},
new SqlColumn("MaxHealth", MySqlDbType.Int32),
new SqlColumn("MaxMana", MySqlDbType.Int32),
new SqlColumn("Inventory", MySqlDbType.Text)
);
var creator = new SqlTableCreator(db,
db.GetSqlType() == SqlType.Sqlite
? (IQueryBuilder) new SqliteQueryCreator()
: new MysqlQueryCreator());
creator.EnsureExists(table);
}
public PlayerData GetPlayerData(TSPlayer player, int acctid)
{
PlayerData playerData = new PlayerData(player);
try
{
using (var reader = database.QueryReader("SELECT * FROM Inventory WHERE Account=@0", acctid))
{
if (reader.Read())
{
playerData.exists = true;
playerData.maxHealth = reader.Get<int>("MaxHealth");
playerData.inventory = NetItem.Parse(reader.Get<string>("Inventory"));
return playerData;
}
}
}
catch (Exception ex)
{
Log.Error(ex.ToString());
}
return playerData;
}
public bool InsertPlayerData(TSPlayer player)
{
PlayerData playerData = player.PlayerData;
if (!player.IsLoggedIn)
return false;
if (!GetPlayerData(player, player.UserID).exists)
{
try
{
database.Query("INSERT INTO Inventory (Account, MaxHealth, Inventory) VALUES (@0, @1, @2);", player.UserID,
playerData.maxHealth, NetItem.ToString(playerData.inventory));
return true;
}
catch (Exception ex)
{
Log.Error(ex.ToString());
}
}
else
{
try
{
database.Query("UPDATE Inventory SET MaxHealth = @0, Inventory = @1 WHERE Account = @2;", playerData.maxHealth,
NetItem.ToString(playerData.inventory), player.UserID);
return true;
}
catch (Exception ex)
{
Log.Error(ex.ToString());
}
}
return false;
}
}
}

View file

@ -200,7 +200,26 @@ namespace TShockAPI.DB
{ {
if (ply == null) if (ply == null)
return false; return false;
return AllowedGroups.Contains(ply.Group.Name);
if (ply.Group.HasPermission(Permissions.usebanneditem))
return true;
var cur = ply.Group;
var traversed = new List<Group>();
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. // could add in the other permissions in this class instead of a giant if switch.
} }

View file

@ -27,11 +27,14 @@ namespace TShockAPI.DB
{ {
public class RegionManager public class RegionManager
{ {
/// <summary>
/// The list of regions.
/// </summary>
public List<Region> Regions = new List<Region>(); public List<Region> Regions = new List<Region>();
private IDbConnection database; private IDbConnection database;
public RegionManager(IDbConnection db) internal RegionManager(IDbConnection db)
{ {
database = db; database = db;
var table = new SqlTable("Regions", var table = new SqlTable("Regions",
@ -52,11 +55,12 @@ namespace TShockAPI.DB
? (IQueryBuilder) new SqliteQueryCreator() ? (IQueryBuilder) new SqliteQueryCreator()
: new MysqlQueryCreator()); : new MysqlQueryCreator());
creator.EnsureExists(table); creator.EnsureExists(table);
ReloadAllRegions();
} }
public void ReloadAllRegions() /// <summary>
/// Reloads all regions.
/// </summary>
public void Reload()
{ {
try try
{ {
@ -419,6 +423,33 @@ namespace TShockAPI.DB
return false; return false;
} }
/// <summary>
/// Sets the position of a region.
/// </summary>
/// <param name="regionName">The region name.</param>
/// <param name="x">The X position.</param>
/// <param name="y">The Y position.</param>
/// <param name="height">The height.</param>
/// <param name="width">The width.</param>
/// <returns>Whether the operation succeeded.</returns>
public bool PositionRegion(string regionName, int x, int y, int width, int height)
{
try
{
Region region = Regions.First(r => String.Equals(regionName, r.Name, StringComparison.OrdinalIgnoreCase));
region.Area = new Rectangle(x, y, width, height);
if (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()) > 0)
return true;
}
catch (Exception ex)
{
Log.Error(ex.ToString());
}
return false;
}
/// <summary> /// <summary>
/// Gets all the regions names from world /// Gets all the regions names from world
/// </summary> /// </summary>
@ -628,8 +659,7 @@ namespace TShockAPI.DB
return true; return true;
} }
return AllowedIDs.Contains(ply.UserID) || AllowedGroups.Contains(ply.Group.Name) || Owner == ply.UserAccountName || return AllowedIDs.Contains(ply.UserID) || AllowedGroups.Contains(ply.Group.Name) || Owner == ply.UserAccountName;
ply.Group.HasPermission("manageregion");
} }
public void setAllowedIDs(String ids) public void setAllowedIDs(String ids)

View file

@ -17,6 +17,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
using System; using System;
using System.CodeDom.Compiler;
using System.Data; using System.Data;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
@ -37,7 +38,9 @@ namespace TShockAPI.DB
new SqlColumn("ID", MySqlDbType.Int32) {Primary = true, AutoIncrement = true}, new SqlColumn("ID", MySqlDbType.Int32) {Primary = true, AutoIncrement = true},
new SqlColumn("Username", MySqlDbType.VarChar, 32) {Unique = true}, new SqlColumn("Username", MySqlDbType.VarChar, 32) {Unique = true},
new SqlColumn("Password", MySqlDbType.VarChar, 128), new SqlColumn("Password", MySqlDbType.VarChar, 128),
new SqlColumn("UUID", MySqlDbType.VarChar, 128),
new SqlColumn("Usergroup", MySqlDbType.Text), new SqlColumn("Usergroup", MySqlDbType.Text),
new SqlColumn("Registered", MySqlDbType.Text),
new SqlColumn("LastAccessed", MySqlDbType.Text), new SqlColumn("LastAccessed", MySqlDbType.Text),
new SqlColumn("KnownIPs", MySqlDbType.Text) new SqlColumn("KnownIPs", MySqlDbType.Text)
); );
@ -60,8 +63,8 @@ namespace TShockAPI.DB
int ret; int ret;
try try
{ {
ret = database.Query("INSERT INTO Users (Username, Password, UserGroup) VALUES (@0, @1, @2);", user.Name, ret = database.Query("INSERT INTO Users (Username, Password, UUID, UserGroup, Registered) VALUES (@0, @1, @2, @3, @4);", user.Name,
TShock.Utils.HashPassword(user.Password), user.Group); TShock.Utils.HashPassword(user.Password), user.UUID, user.Group, DateTime.UtcNow.ToString("s"));
} }
catch (Exception ex) catch (Exception ex)
{ {
@ -114,6 +117,26 @@ namespace TShockAPI.DB
} }
} }
/// <summary>
/// Sets the UUID for a given username
/// </summary>
/// <param name="user">User user</param>
/// <param name="group">string uuid</param>
public void SetUserUUID(User user, string uuid)
{
try
{
if (
database.Query("UPDATE Users SET UUID = @0 WHERE Username = @1;", uuid,
user.Name) == 0)
throw new UserNotExistException(user.Name);
}
catch (Exception ex)
{
throw new UserManagerException("SetUserUUID SQL returned an error", ex);
}
}
/// <summary> /// <summary>
/// Sets the group for a given username /// Sets the group for a given username
/// </summary> /// </summary>
@ -146,7 +169,7 @@ namespace TShockAPI.DB
{ {
try try
{ {
if (database.Query("UPDATE Users SET LastAccessed = @0, KnownIps = @1 WHERE Username = @2;", DateTime.Now.ToString("G"), user.KnownIps, user.Name) == 0) if (database.Query("UPDATE Users SET LastAccessed = @0, KnownIps = @1 WHERE Username = @2;", DateTime.UtcNow.ToString("s"), user.KnownIps, user.Name) == 0)
throw new UserNotExistException(user.Name); throw new UserNotExistException(user.Name);
} }
catch (Exception ex) catch (Exception ex)
@ -267,7 +290,9 @@ namespace TShockAPI.DB
user.ID = result.Get<int>("ID"); user.ID = result.Get<int>("ID");
user.Group = result.Get<string>("Usergroup"); user.Group = result.Get<string>("Usergroup");
user.Password = result.Get<string>("Password"); user.Password = result.Get<string>("Password");
user.UUID = result.Get<string>("UUID");
user.Name = result.Get<string>("Username"); user.Name = result.Get<string>("Username");
user.Registered = result.Get<string>("Registered");
user.LastAccessed = result.Get<string>("LastAccessed"); user.LastAccessed = result.Get<string>("LastAccessed");
user.KnownIps = result.Get<string>("KnownIps"); user.KnownIps = result.Get<string>("KnownIps");
return user; return user;
@ -279,15 +304,19 @@ namespace TShockAPI.DB
public int ID { get; set; } public int ID { get; set; }
public string Name { get; set; } public string Name { get; set; }
public string Password { get; set; } public string Password { get; set; }
public string UUID { get; set; }
public string Group { get; set; } public string Group { get; set; }
public string Registered { get; set; }
public string LastAccessed { get; set; } public string LastAccessed { get; set; }
public string KnownIps { get; set; } public string KnownIps { get; set; }
public User(string name, string pass, string group, string last, string known) public User(string name, string pass, string uuid, string group, string registered, string last, string known)
{ {
Name = name; Name = name;
Password = pass; Password = pass;
UUID = uuid;
Group = group; Group = group;
Registered = registered;
LastAccessed = last; LastAccessed = last;
KnownIps = known; KnownIps = known;
} }
@ -296,7 +325,9 @@ namespace TShockAPI.DB
{ {
Name = ""; Name = "";
Password = ""; Password = "";
UUID = "";
Group = ""; Group = "";
Registered = "";
LastAccessed = ""; LastAccessed = "";
KnownIps = ""; KnownIps = "";
} }

View file

@ -20,6 +20,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Data; using System.Data;
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
using System.Linq;
using MySql.Data.MySqlClient; using MySql.Data.MySqlClient;
using Terraria; using Terraria;
@ -28,9 +29,13 @@ namespace TShockAPI.DB
public class WarpManager public class WarpManager
{ {
private IDbConnection database; private IDbConnection database;
/// <summary>
/// The list of warps.
/// </summary>
public List<Warp> Warps = new List<Warp>();
[SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope")] [SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope")]
public WarpManager(IDbConnection db) internal WarpManager(IDbConnection db)
{ {
database = db; database = db;
@ -48,13 +53,24 @@ namespace TShockAPI.DB
creator.EnsureExists(table); creator.EnsureExists(table);
} }
public bool AddWarp(int x, int y, string name, string worldid) /// <summary>
/// Adds a warp.
/// </summary>
/// <param name="x">The X position.</param>
/// <param name="y">The Y position.</param>
/// <param name="name">The name.</param>
/// <returns>Whether the opration succeeded.</returns>
public bool Add(int x, int y, string name)
{ {
try try
{ {
database.Query("INSERT INTO Warps (X, Y, WarpName, WorldID) VALUES (@0, @1, @2, @3);", x, y, name, worldid); if (database.Query("INSERT INTO Warps (X, Y, WarpName, WorldID) VALUES (@0, @1, @2, @3);",
x, y, name, Main.worldID.ToString()) > 0)
{
Warps.Add(new Warp(new Point(x, y), name));
return true; return true;
} }
}
catch (Exception ex) catch (Exception ex)
{ {
Log.Error(ex.ToString()); Log.Error(ex.ToString());
@ -62,127 +78,164 @@ namespace TShockAPI.DB
return false; return false;
} }
public bool RemoveWarp(string name)
{
try
{
database.Query("DELETE FROM Warps WHERE WarpName=@0 AND WorldID=@1", name, Main.worldID.ToString());
return true;
}
catch (Exception ex)
{
Log.Error(ex.ToString());
}
return false;
}
public Warp FindWarp(string name)
{
try
{
using (
var reader = database.QueryReader("SELECT * FROM Warps WHERE WarpName=@0 AND WorldID=@1", name,
Main.worldID.ToString()))
{
if (reader.Read())
{
try
{
return new Warp(new Vector2(reader.Get<int>("X"), reader.Get<int>("Y")), reader.Get<string>("WarpName"),
reader.Get<string>("WorldID"), reader.Get<string>("Private"));
}
catch
{
return new Warp(new Vector2(reader.Get<int>("X"), reader.Get<int>("Y")), reader.Get<string>("WarpName"),
reader.Get<string>("WorldID"), "0");
}
}
}
}
catch (Exception ex)
{
Log.Error(ex.ToString());
}
return new Warp();
}
/// <summary> /// <summary>
/// Gets all the warps names from world /// Reloads all warps.
/// </summary> /// </summary>
/// <param name="worldid">World name to get warps from</param> public void ReloadWarps()
/// <returns>List of warps with only their names</returns>
public List<Warp> ListAllPublicWarps(string worldid)
{ {
var warps = new List<Warp>(); Warps.Clear();
try
{ using (var reader = database.QueryReader("SELECT * FROM Warps WHERE WorldID = @0",
using (var reader = database.QueryReader("SELECT * FROM Warps WHERE WorldID=@0", worldid)) Main.worldID.ToString()))
{ {
while (reader.Read()) while (reader.Read())
{ {
try Warps.Add(new Warp(
{ new Point(reader.Get<int>("X"), reader.Get<int>("Y")),
if (reader.Get<String>("Private") == "0" || reader.Get<String>("Private") == null) reader.Get<string>("WarpName"),
warps.Add(new Warp {WarpName = reader.Get<string>("WarpName")}); (reader.Get<string>("Private") ?? "0") != "0"));
}
catch
{
warps.Add(new Warp {WarpName = reader.Get<string>("WarpName")});
} }
} }
} }
}
catch (Exception ex)
{
Log.Error(ex.ToString());
}
return warps;
}
/// <summary> /// <summary>
/// Gets all the warps names from world /// Removes a warp.
/// </summary> /// </summary>
/// <param name="worldid">World name to get warps from</param> /// <param name="warpName">The warp name.</param>
/// <returns>List of warps with only their names</returns> /// <returns>Whether the operation succeeded.</returns>
public bool HideWarp(string warp, bool state) public bool Remove(string warpName)
{ {
try try
{ {
string query = "UPDATE Warps SET Private=@0 WHERE WarpName=@1 AND WorldID=@2"; if (database.Query("DELETE FROM Warps WHERE WarpName = @0 AND WorldID = @1",
warpName, Main.worldID.ToString()) > 0)
database.Query(query, state ? "1" : "0", warp, Main.worldID.ToString()); {
Warps.RemoveAll(w => String.Equals(w.Name, warpName, StringComparison.OrdinalIgnoreCase));
return true; return true;
} }
}
catch (Exception ex) catch (Exception ex)
{ {
Log.Error(ex.ToString()); Log.Error(ex.ToString());
}
return false;
}
/// <summary>
/// Finds the warp with the given name.
/// </summary>
/// <param name="warpName">The name.</param>
/// <returns>The warp, if it exists, or else null.</returns>
public Warp Find(string warpName)
{
return Warps.FirstOrDefault(w => String.Equals(w.Name, warpName, StringComparison.OrdinalIgnoreCase));
}
/// <summary>
/// Finds the warp with the given name.
/// </summary>
/// <param name="warpName">The name.</param>
/// <returns>The warp, if it exists, or else null.</returns>
[Obsolete]
public Warp FindWarp(string warpName)
{
return Warps.FirstOrDefault(w => String.Equals(w.Name, warpName, StringComparison.OrdinalIgnoreCase));
}
/// <summary>
/// Sets the position of a warp.
/// </summary>
/// <param name="warpName">The warp name.</param>
/// <param name="x">The X position.</param>
/// <param name="y">The Y position.</param>
/// <returns>Whether the operation suceeded.</returns>
public bool Position(string warpName, int x, int y)
{
try
{
if (database.Query("UPDATE Warps SET X = @0, Y = @1 WHERE WarpName = @2 AND WorldID = @3",
x, y, warpName, Main.worldID.ToString()) > 0)
{
Warps.Find(w => String.Equals(w.Name, warpName, StringComparison.OrdinalIgnoreCase)).Position = new Point(x, y);
return true;
}
}
catch (Exception ex)
{
Log.Error(ex.ToString());
}
return false;
}
/// <summary>
/// Sets the hidden state of a warp.
/// </summary>
/// <param name="warpName">The warp name.</param>
/// <param name="state">The state.</param>
/// <returns>Whether the operation suceeded.</returns>
public bool Hide(string warpName, bool state)
{
try
{
if (database.Query("UPDATE Warps SET Private = @0 WHERE WarpName = @1 AND WorldID = @2",
state ? "1" : "0", warpName, Main.worldID.ToString()) > 0)
{
Warps.Find(w => String.Equals(w.Name, warpName, StringComparison.OrdinalIgnoreCase)).IsPrivate = state;
return true;
}
}
catch (Exception ex)
{
Log.Error(ex.ToString());
}
return false; return false;
} }
} }
}
/// <summary>
/// Represents a warp.
/// </summary>
public class Warp public class Warp
{ {
public Vector2 WarpPos { get; set; } /// <summary>
public string WarpName { get; set; } /// Gets or sets the name.
public string WorldWarpID { get; set; } /// </summary>
public string Private { get; set; } public string Name { get; set; }
/// <summary>
public Warp(Vector2 warppos, string name, string worldid, string hidden) /// Gets or sets the warp's privacy state.
/// </summary>
public bool IsPrivate { get; set; }
/// <summary>
/// Gets or sets the position.
/// </summary>
public Point Position { get; set; }
/// <summary>
/// Gets or sets the position.
/// </summary>
[Obsolete]
public Vector2 WarpPos
{ {
WarpPos = warppos; get { return new Vector2(Position.X, Position.Y); }
WarpName = name; set { Position = new Point((int)value.X, (int)value.Y); }
WorldWarpID = worldid;
Private = hidden;
} }
public Warp(Point position, string name, bool isPrivate = false)
{
Name = name;
Position = position;
IsPrivate = isPrivate;
}
[Obsolete]
public Warp(Vector2 position, string name, bool isPrivate = false)
{
Name = name;
WarpPos = position;
IsPrivate = isPrivate;
}
public Warp() public Warp()
{ {
WarpPos = Vector2.Zero; Position = Point.Zero;
WarpName = null; Name = "";
WorldWarpID = string.Empty; IsPrivate = false;
Private = "0";
} }
} }
} }

1381
TShockAPI/GetDataHandlers.cs Normal file → Executable file

File diff suppressed because it is too large Load diff

View file

@ -70,11 +70,11 @@ namespace TShockAPI
/// <summary> /// <summary>
/// The chat color of the group. /// The chat color of the group.
/// Returns "255255255", sets "255,255,255" /// Returns "255,255,255", sets "255,255,255"
/// </summary> /// </summary>
public string ChatColor public string ChatColor
{ {
get { return string.Format("{0}{1}{2}", R.ToString("X2"), G.ToString("X2"), B.ToString("X2")); } get { return string.Format("{0},{1},{2}", R.ToString("D3"), G.ToString("D3"), B.ToString("D3")); }
set set
{ {
if (null != value) if (null != value)
@ -118,7 +118,7 @@ namespace TShockAPI
/// <summary> /// <summary>
/// The permissions of this group and all that it inherits from. /// The permissions of this group and all that it inherits from.
/// </summary> /// </summary>
public List<string> TotalPermissions public virtual List<string> TotalPermissions
{ {
get get
{ {
@ -176,23 +176,29 @@ namespace TShockAPI
/// <returns>Returns true if the user has that permission.</returns> /// <returns>Returns true if the user has that permission.</returns>
public virtual bool HasPermission(string permission) public virtual bool HasPermission(string permission)
{ {
if (String.IsNullOrEmpty(permission) || RealHasPermission(permission)) bool negated = false;
if (String.IsNullOrEmpty(permission) || (RealHasPermission(permission, ref negated) && !negated))
{ {
return true; return true;
} }
if (negated)
return false;
string[] nodes = permission.Split('.'); string[] nodes = permission.Split('.');
for (int i = nodes.Length - 1; i >= 0; i--) for (int i = nodes.Length - 1; i >= 0; i--)
{ {
nodes[i] = "*"; nodes[i] = "*";
if (RealHasPermission(String.Join(".", nodes, 0, i + 1))) if (RealHasPermission(String.Join(".", nodes, 0, i + 1), ref negated))
{ {
return true; return !negated;
} }
} }
return false; return false;
} }
private bool RealHasPermission(string permission) private bool RealHasPermission(string permission, ref bool negated)
{ {
negated = false;
if (string.IsNullOrEmpty(permission)) if (string.IsNullOrEmpty(permission))
return true; return true;
@ -201,7 +207,10 @@ namespace TShockAPI
while (cur != null) while (cur != null)
{ {
if (cur.negatedpermissions.Contains(permission)) if (cur.negatedpermissions.Contains(permission))
{
negated = true;
return false; return false;
}
if (cur.permissions.Contains(permission)) if (cur.permissions.Contains(permission))
return true; return true;
if (traversed.Contains(cur)) if (traversed.Contains(cur))
@ -226,6 +235,12 @@ namespace TShockAPI
negatedpermissions.Add(permission); negatedpermissions.Add(permission);
permissions.Remove(permission); // Ensure we don't have conflicting definitions for a permissions 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();
}
} }
/// <summary> /// <summary>
@ -245,6 +260,12 @@ namespace TShockAPI
permissions.Add(permission); permissions.Add(permission);
negatedpermissions.Remove(permission); // Ensure we don't have conflicting definitions for a permissions 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();
}
} }
/// <summary> /// <summary>
@ -272,6 +293,11 @@ namespace TShockAPI
return; return;
} }
permissions.Remove(permission); 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();
}
} }
/// <summary> /// <summary>
@ -300,6 +326,10 @@ namespace TShockAPI
/// </summary> /// </summary>
public class SuperAdminGroup : Group public class SuperAdminGroup : Group
{ {
public override List<string> TotalPermissions
{
get { return new List<string> { "*" }; }
}
public SuperAdminGroup() public SuperAdminGroup()
: base("superadmin") : base("superadmin")
{ {

View file

@ -58,7 +58,7 @@ namespace TShockAPI.Hooks
public static void OnPlayerPostLogin(TSPlayer ply) public static void OnPlayerPostLogin(TSPlayer ply)
{ {
if(PlayerPostLogin == null) if (PlayerPostLogin == null)
{ {
return; return;
} }

View file

@ -78,7 +78,7 @@ namespace TShockAPI
/// </summary> /// </summary>
/// <param name="format">The format of the message to be written.</param> /// <param name="format">The format of the message to be written.</param>
/// <param name="args">The format arguments.</param> /// <param name="args">The format arguments.</param>
public static void Data(String format, params String[] args) public static void Data(string format, params object[] args)
{ {
Data(String.Format(format, args)); Data(String.Format(format, args));
} }
@ -97,7 +97,7 @@ namespace TShockAPI
/// </summary> /// </summary>
/// <param name="format">The format of the message to be written.</param> /// <param name="format">The format of the message to be written.</param>
/// <param name="args">The format arguments.</param> /// <param name="args">The format arguments.</param>
public static void Error(String format, params String[] args) public static void Error(string format, params object[] args)
{ {
Error(String.Format(format, args)); Error(String.Format(format, args));
} }
@ -119,7 +119,7 @@ namespace TShockAPI
/// </summary> /// </summary>
/// <param name="format">The format of the message to be written.</param> /// <param name="format">The format of the message to be written.</param>
/// <param name="args">The format arguments.</param> /// <param name="args">The format arguments.</param>
public static void ConsoleError(String format, params String[] args) public static void ConsoleError(string format, params object[] args)
{ {
ConsoleError(String.Format(format, args)); ConsoleError(String.Format(format, args));
} }
@ -138,7 +138,7 @@ namespace TShockAPI
/// </summary> /// </summary>
/// <param name="format">The format of the message to be written.</param> /// <param name="format">The format of the message to be written.</param>
/// <param name="args">The format arguments.</param> /// <param name="args">The format arguments.</param>
public static void Warn(String format, params String[] args) public static void Warn(string format, params object[] args)
{ {
Warn(String.Format(format, args)); Warn(String.Format(format, args));
} }
@ -157,7 +157,7 @@ namespace TShockAPI
/// </summary> /// </summary>
/// <param name="format">The format of the message to be written.</param> /// <param name="format">The format of the message to be written.</param>
/// <param name="args">The format arguments.</param> /// <param name="args">The format arguments.</param>
public static void Info(String format, params String[] args) public static void Info(string format, params object[] args)
{ {
Info(String.Format(format, args)); Info(String.Format(format, args));
} }
@ -179,7 +179,7 @@ namespace TShockAPI
/// </summary> /// </summary>
/// <param name="format">The format of the message to be written.</param> /// <param name="format">The format of the message to be written.</param>
/// <param name="args">The format arguments.</param> /// <param name="args">The format arguments.</param>
public static void ConsoleInfo(String format, params String[] args) public static void ConsoleInfo(string format, params object[] args)
{ {
ConsoleInfo(String.Format(format, args)); ConsoleInfo(String.Format(format, args));
} }
@ -198,7 +198,7 @@ namespace TShockAPI
/// </summary> /// </summary>
/// <param name="format">The format of the message to be written.</param> /// <param name="format">The format of the message to be written.</param>
/// <param name="args">The format arguments.</param> /// <param name="args">The format arguments.</param>
public static void Debug(String format, params String[] args) public static void Debug(string format, params object[] args)
{ {
Debug(String.Format(format, args)); Debug(String.Format(format, args));
} }

View file

@ -29,10 +29,32 @@ namespace TShockAPI.Net
public byte Type { get; set; } public byte Type { get; set; }
public short FrameX { get; set; } public short FrameX { get; set; }
public short FrameY { get; set; } public short FrameY { get; set; }
public bool Lighted { get; set; }
public byte Wall { get; set; } public byte Wall { get; set; }
public byte Liquid { get; set; } public byte Liquid { get; set; }
public bool Lava { get; set; } public byte LiquidType { get; set; }
public bool Wire { get; set; } public bool Wire { get; set; }
public bool Wire2 { get; set; }
public bool Wire3 { get; set; }
public byte HalfBrick { get; set; }
public byte Actuator { get; set; }
public bool Inactive { get; set; }
public bool IsHalf { get; set; }
public bool IsActuator { get; set; }
public byte TileColor { get; set; }
public byte WallColor { get; set; }
public bool Slope { get; set; }
public bool Slope2 { get; set; }
public bool HasColor
{
get { return TileColor > 0; }
}
public bool HasWallColor
{
get { return WallColor > 0; }
}
public bool HasWall public bool HasWall
{ {
@ -57,8 +79,17 @@ namespace TShockAPI.Net
FrameY = -1; FrameY = -1;
Wall = 0; Wall = 0;
Liquid = 0; Liquid = 0;
Lava = false;
Wire = false; Wire = false;
Wire2 = false;
Wire3 = false;
HalfBrick = 0;
Actuator = 0;
Inactive = false;
TileColor = 0;
WallColor = 0;
Lighted = false;
Slope = false;
Slope2 = false;
} }
public NetTile(Stream stream) public NetTile(Stream stream)
@ -71,9 +102,12 @@ namespace TShockAPI.Net
{ {
var flags = TileFlags.None; var flags = TileFlags.None;
if (Active) if ((Active) && (!Inactive))
flags |= TileFlags.Active; flags |= TileFlags.Active;
if (Lighted)
flags |= TileFlags.Lighted;
if (HasWall) if (HasWall)
flags |= TileFlags.Wall; flags |= TileFlags.Wall;
@ -83,8 +117,52 @@ namespace TShockAPI.Net
if (Wire) if (Wire)
flags |= TileFlags.Wire; flags |= TileFlags.Wire;
if (IsHalf)
flags |= TileFlags.HalfBrick;
if (IsActuator)
flags |= TileFlags.Actuator;
if (Inactive)
{
flags |= TileFlags.Inactive;
}
stream.WriteInt8((byte) flags); stream.WriteInt8((byte) flags);
var flags2 = TileFlags2.None;
if ((Wire2))
flags2 |= TileFlags2.Wire2;
if (Wire3)
flags2 |= TileFlags2.Wire3;
if (HasColor)
flags2 |= TileFlags2.Color;
if (HasWallColor)
flags2 |= TileFlags2.WallColor;
if (Slope)
flags2 |= TileFlags2.Slope;
if (Slope2)
flags2 |= TileFlags2.Slope2;
stream.WriteInt8((byte)flags2);
if (HasColor)
{
stream.WriteByte(TileColor);
}
if (HasWallColor)
{
stream.WriteByte(WallColor);
}
if (Active) if (Active)
{ {
stream.WriteInt8(Type); stream.WriteInt8(Type);
@ -101,13 +179,29 @@ namespace TShockAPI.Net
if (HasLiquid) if (HasLiquid)
{ {
stream.WriteInt8(Liquid); stream.WriteInt8(Liquid);
stream.WriteBoolean(Lava); stream.WriteInt8(LiquidType);
} }
} }
public void Unpack(Stream stream) public void Unpack(Stream stream)
{ {
var flags = (TileFlags) stream.ReadInt8(); var flags = (TileFlags) stream.ReadInt8();
var flags2 = (TileFlags2)stream.ReadInt8();
Wire2 = flags2.HasFlag(TileFlags2.Wire2);
Wire3 = flags2.HasFlag(TileFlags2.Wire3);
Slope = flags2.HasFlag(TileFlags2.Slope);
Slope2 = flags2.HasFlag(TileFlags2.Slope2);
if (flags2.HasFlag(TileFlags2.Color))
{
TileColor = stream.ReadInt8();
}
if (flags2.HasFlag(TileFlags2.WallColor))
{
WallColor = stream.ReadInt8();
}
Active = flags.HasFlag(TileFlags.Active); Active = flags.HasFlag(TileFlags.Active);
if (Active) if (Active)
@ -120,6 +214,11 @@ namespace TShockAPI.Net
} }
} }
if (flags.HasFlag(TileFlags.Lighted))
{
Lighted = true;
}
if (flags.HasFlag(TileFlags.Wall)) if (flags.HasFlag(TileFlags.Wall))
{ {
Wall = stream.ReadInt8(); Wall = stream.ReadInt8();
@ -128,11 +227,23 @@ namespace TShockAPI.Net
if (flags.HasFlag(TileFlags.Liquid)) if (flags.HasFlag(TileFlags.Liquid))
{ {
Liquid = stream.ReadInt8(); Liquid = stream.ReadInt8();
Lava = stream.ReadBoolean(); LiquidType = stream.ReadInt8();
} }
if (flags.HasFlag(TileFlags.Wire)) if (flags.HasFlag(TileFlags.Wire))
Wire = true; Wire = true;
if (flags.HasFlag(TileFlags.HalfBrick))
IsHalf = true;
if (flags.HasFlag(TileFlags.Actuator))
IsActuator = true;
if (flags.HasFlag(TileFlags.Inactive))
{
Inactive = true;
Active = false;
}
} }
} }
@ -144,6 +255,21 @@ namespace TShockAPI.Net
Lighted = 2, Lighted = 2,
Wall = 4, Wall = 4,
Liquid = 8, Liquid = 8,
Wire = 16 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
} }
} }

View file

@ -25,7 +25,7 @@ namespace TShockAPI.Net
{ {
public override PacketTypes ID public override PacketTypes ID
{ {
get { return PacketTypes.ProjectileNew; } get{ return PacketTypes.ProjectileNew; }
} }
public short Index { get; set; } public short Index { get; set; }

View file

@ -24,7 +24,7 @@ using System.Text;
namespace TShockAPI.Net namespace TShockAPI.Net
{ {
[Flags] [Flags]
public enum WorldInfoFlag : byte public enum BossFlags : byte
{ {
None = 0, None = 0,
OrbSmashed = 1, OrbSmashed = 1,
@ -32,7 +32,21 @@ namespace TShockAPI.Net
DownedBoss2 = 4, DownedBoss2 = 4,
DownedBoss3 = 8, DownedBoss3 = 8,
HardMode = 16, HardMode = 16,
DownedClown = 32 DownedClown = 32,
ServerSideCharacter = 64
}
[Flags]
public enum BossFlags2 : byte
{
None = 0,
DownedMechBoss1 = 1,
DownedMechBoss2 = 2,
DownedMechBoss3 = 4,
DownedMechBossAny = 8,
CloudBg = 16,
Crimson = 32,
Pumpkin = 64
} }
public class WorldInfoMsg : BaseMsg public class WorldInfoMsg : BaseMsg
@ -41,6 +55,7 @@ namespace TShockAPI.Net
public bool DayTime { get; set; } public bool DayTime { get; set; }
public byte MoonPhase { get; set; } public byte MoonPhase { get; set; }
public bool BloodMoon { get; set; } public bool BloodMoon { get; set; }
public bool Eclipse { get; set; }
public int MaxTilesX { get; set; } public int MaxTilesX { get; set; }
public int MaxTilesY { get; set; } public int MaxTilesY { get; set; }
public int SpawnX { get; set; } public int SpawnX { get; set; }
@ -48,7 +63,37 @@ namespace TShockAPI.Net
public int WorldSurface { get; set; } public int WorldSurface { get; set; }
public int RockLayer { get; set; } public int RockLayer { get; set; }
public int WorldID { get; set; } public int WorldID { get; set; }
public WorldInfoFlag WorldFlags { get; set; } public byte MoonType { get; set; }
public int TreeX0 { get; set; }
public int TreeX1 { get; set; }
public int TreeX2 { get; set; }
public byte TreeStyle0 { get; set; }
public byte TreeStyle1 { get; set; }
public byte TreeStyle2 { get; set; }
public byte TreeStyle3 { get; set; }
public int CaveBackX0 { get; set; }
public int CaveBackX1 { get; set; }
public int CaveBackX2 { get; set; }
public byte CaveBackStyle0 { get; set; }
public byte CaveBackStyle1 { get; set; }
public byte CaveBackStyle2 { get; set; }
public byte CaveBackStyle3 { get; set; }
public byte SetBG0 { get; set; }
public byte SetBG1 { get; set; }
public byte SetBG2 { get; set; }
public byte SetBG3 { get; set; }
public byte SetBG4 { get; set; }
public byte SetBG5 { get; set; }
public byte SetBG6 { get; set; }
public byte SetBG7 { get; set; }
public byte IceBackStyle { get; set; }
public byte JungleBackStyle { get; set; }
public byte HellBackStyle { get; set; }
public float WindSpeed { get; set; }
public byte NumberOfClouds { get; set; }
public BossFlags BossFlags { get; set; }
public BossFlags2 BossFlags2 { get; set; }
public float Rain { get; set; }
public string WorldName { get; set; } public string WorldName { get; set; }
public override PacketTypes ID public override PacketTypes ID
@ -62,6 +107,7 @@ namespace TShockAPI.Net
stream.WriteBoolean(DayTime); stream.WriteBoolean(DayTime);
stream.WriteInt8(MoonPhase); stream.WriteInt8(MoonPhase);
stream.WriteBoolean(BloodMoon); stream.WriteBoolean(BloodMoon);
stream.WriteBoolean(Eclipse);
stream.WriteInt32(MaxTilesX); stream.WriteInt32(MaxTilesX);
stream.WriteInt32(MaxTilesY); stream.WriteInt32(MaxTilesY);
stream.WriteInt32(SpawnX); stream.WriteInt32(SpawnX);
@ -69,7 +115,37 @@ namespace TShockAPI.Net
stream.WriteInt32(WorldSurface); stream.WriteInt32(WorldSurface);
stream.WriteInt32(RockLayer); stream.WriteInt32(RockLayer);
stream.WriteInt32(WorldID); stream.WriteInt32(WorldID);
stream.WriteInt8((byte) WorldFlags); 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)); stream.WriteBytes(Encoding.UTF8.GetBytes(WorldName));
} }
} }

View file

@ -22,8 +22,8 @@ using System.ComponentModel;
using System.IO; using System.IO;
using System.Net.Sockets; using System.Net.Sockets;
using System.Text; using System.Text;
using Hooks;
using Terraria; using Terraria;
using TerrariaApi.Server;
namespace TShockAPI namespace TShockAPI
{ {
@ -34,6 +34,8 @@ namespace TShockAPI
/// </summary> /// </summary>
public int BytesPerUpdate { get; set; } public int BytesPerUpdate { get; set; }
private readonly TShock plugin;
private PacketBuffer[] buffers = new PacketBuffer[Netplay.serverSock.Length]; private PacketBuffer[] buffers = new PacketBuffer[Netplay.serverSock.Length];
private int[] Bytes = new int[52]; private int[] Bytes = new int[52];
@ -45,8 +47,9 @@ namespace TShockAPI
Command flush; Command flush;
#endif #endif
public PacketBufferer() public PacketBufferer(TShock p)
{ {
plugin = p;
BytesPerUpdate = 0xFFFF; BytesPerUpdate = 0xFFFF;
for (int i = 0; i < buffers.Length; i++) for (int i = 0; i < buffers.Length; i++)
buffers[i] = new PacketBuffer(); buffers[i] = new PacketBuffer();
@ -58,9 +61,9 @@ namespace TShockAPI
Commands.ChatCommands.Add(flush); Commands.ChatCommands.Add(flush);
#endif #endif
NetHooks.SendBytes += ServerHooks_SendBytes; ServerApi.Hooks.NetSendBytes.Register(plugin, ServerHooks_SendBytes);
ServerHooks.SocketReset += ServerHooks_SocketReset; ServerApi.Hooks.ServerSocketReset.Register(plugin, ServerHooks_SocketReset);
GameHooks.PostUpdate += GameHooks_Update; ServerApi.Hooks.GamePostUpdate.Register(plugin, GameHooks_Update);
} }
~PacketBufferer() ~PacketBufferer()
@ -82,9 +85,9 @@ namespace TShockAPI
Commands.ChatCommands.Remove(dump); Commands.ChatCommands.Remove(dump);
Commands.ChatCommands.Remove(flush); Commands.ChatCommands.Remove(flush);
#endif #endif
NetHooks.SendBytes -= ServerHooks_SendBytes; ServerApi.Hooks.NetSendBytes.Deregister(plugin, ServerHooks_SendBytes);
ServerHooks.SocketReset -= ServerHooks_SocketReset; ServerApi.Hooks.ServerSocketReset.Deregister(plugin, ServerHooks_SocketReset);
GameHooks.PostUpdate -= GameHooks_Update; ServerApi.Hooks.GamePostUpdate.Deregister(plugin, GameHooks_Update);
} }
} }
@ -107,7 +110,7 @@ namespace TShockAPI
Compressed = new int[52]; Compressed = new int[52];
} }
private void GameHooks_Update() private void GameHooks_Update(EventArgs args)
{ {
FlushAll(); FlushAll();
} }
@ -148,9 +151,9 @@ namespace TShockAPI
} }
private void ServerHooks_SocketReset(ServerSock socket) private void ServerHooks_SocketReset(SocketResetEventArgs args)
{ {
buffers[socket.whoAmI] = new PacketBuffer(); buffers[args.Socket.whoAmI] = new PacketBuffer();
} }
public bool SendBytes(ServerSock socket, byte[] buffer) public bool SendBytes(ServerSock socket, byte[] buffer)
@ -179,6 +182,12 @@ namespace TShockAPI
{ {
buffers[socket.whoAmI].AddRange(ms.ToArray()); buffers[socket.whoAmI].AddRange(ms.ToArray());
} }
if (TShock.Config.EnableMaxBytesInBuffer && buffers[socket.whoAmI].Count > TShock.Config.MaxBytesInBuffer)
{
buffers[socket.whoAmI].Clear();
socket.kill = true;
}
} }
} }
@ -204,6 +213,7 @@ namespace TShockAPI
switch ((uint)e.ErrorCode) switch ((uint)e.ErrorCode)
{ {
case 0x80004005: case 0x80004005:
case 10053:
break; break;
default: default:
Log.Warn(e.ToString()); Log.Warn(e.ToString());
@ -217,10 +227,10 @@ namespace TShockAPI
return false; return false;
} }
private void ServerHooks_SendBytes(ServerSock socket, byte[] buffer, int offset, int count, HandledEventArgs e) private void ServerHooks_SendBytes(SendBytesEventArgs args)
{ {
e.Handled = true; args.Handled = true;
BufferBytes(socket, buffer, offset, count); BufferBytes(args.Socket, args.Buffer, args.Offset, args.Count);
} }
#if DEBUG_NET #if DEBUG_NET

View file

@ -23,6 +23,9 @@ using System.Text;
namespace TShockAPI namespace TShockAPI
{ {
/// <summary>
/// Provides tools for sending paginated output.
/// </summary>
public static class PaginationTools public static class PaginationTools
{ {
public delegate Tuple<string, Color> LineFormatterDelegate(object lineData, int lineIndex, int pageNumber); public delegate Tuple<string, Color> LineFormatterDelegate(object lineData, int lineIndex, int pageNumber);
@ -105,7 +108,7 @@ namespace TShockAPI
this.FooterTextColor = Color.Yellow; this.FooterTextColor = Color.Yellow;
this.NothingToDisplayString = null; this.NothingToDisplayString = null;
this.LineFormatter = null; this.LineFormatter = null;
this.LineTextColor = Color.White; this.LineTextColor = Color.Yellow;
this.maxLinesPerPage = 4; this.maxLinesPerPage = 4;
this.pageLimit = 0; this.pageLimit = 0;
} }
@ -122,15 +125,11 @@ namespace TShockAPI
{ {
if (settings.NothingToDisplayString != null) if (settings.NothingToDisplayString != null)
{ {
if (player is TSServerPlayer) if (!player.RealPlayer)
{
player.SendSuccessMessage(settings.NothingToDisplayString); player.SendSuccessMessage(settings.NothingToDisplayString);
}
else else
{
player.SendMessage(settings.NothingToDisplayString, settings.HeaderTextColor); player.SendMessage(settings.NothingToDisplayString, settings.HeaderTextColor);
} }
}
return; return;
} }
@ -142,15 +141,11 @@ namespace TShockAPI
if (settings.IncludeHeader) if (settings.IncludeHeader)
{ {
if (player is TSServerPlayer) if (!player.RealPlayer)
{
player.SendSuccessMessage(string.Format(settings.HeaderFormat, pageNumber, pageCount)); player.SendSuccessMessage(string.Format(settings.HeaderFormat, pageNumber, pageCount));
}
else else
{
player.SendMessage(string.Format(settings.HeaderFormat, pageNumber, pageCount), settings.HeaderTextColor); player.SendMessage(string.Format(settings.HeaderFormat, pageNumber, pageCount), settings.HeaderTextColor);
} }
}
int listOffset = (pageNumber - 1) * settings.MaxLinesPerPage; int listOffset = (pageNumber - 1) * settings.MaxLinesPerPage;
int offsetCounter = 0; int offsetCounter = 0;
@ -196,54 +191,42 @@ namespace TShockAPI
if (lineMessage != null) if (lineMessage != null)
{ {
if (player is TSServerPlayer) if (!player.RealPlayer)
{ player.SendInfoMessage(lineMessage);
Console.WriteLine(lineMessage);
}
else else
{
player.SendMessage(lineMessage, lineColor); player.SendMessage(lineMessage, lineColor);
} }
} }
}
if (lineCounter == 0) if (lineCounter == 0)
{ {
if (settings.NothingToDisplayString != null) if (settings.NothingToDisplayString != null)
{ {
if (player is TSServerPlayer) if (!player.RealPlayer)
{
player.SendSuccessMessage(settings.NothingToDisplayString); player.SendSuccessMessage(settings.NothingToDisplayString);
}
else else
{
player.SendMessage(settings.NothingToDisplayString, settings.HeaderTextColor); player.SendMessage(settings.NothingToDisplayString, settings.HeaderTextColor);
} }
} }
}
else if (settings.IncludeFooter && pageNumber + 1 <= pageCount) else if (settings.IncludeFooter && pageNumber + 1 <= pageCount)
{ {
if (player is TSServerPlayer) if (!player.RealPlayer)
{
player.SendInfoMessage(string.Format(settings.FooterFormat, pageNumber + 1, pageNumber, pageCount)); player.SendInfoMessage(string.Format(settings.FooterFormat, pageNumber + 1, pageNumber, pageCount));
}
else else
{
player.SendMessage(string.Format(settings.FooterFormat, pageNumber + 1, pageNumber, pageCount), settings.FooterTextColor); player.SendMessage(string.Format(settings.FooterFormat, pageNumber + 1, pageNumber, pageCount), settings.FooterTextColor);
} }
} }
}
public static void SendPage(TSPlayer player, int pageNumber, IList dataToPaginate, Settings settings = null) public static void SendPage(TSPlayer player, int pageNumber, IList dataToPaginate, Settings settings = null)
{ {
PaginationTools.SendPage(player, pageNumber, dataToPaginate, dataToPaginate.Count, settings); PaginationTools.SendPage(player, pageNumber, dataToPaginate, dataToPaginate.Count, settings);
} }
public static List<string> BuildLinesFromTerms( public static List<string> BuildLinesFromTerms(IEnumerable terms, Func<object, string> termFormatter = null, string separator = ", ", int maxCharsPerLine = 80)
IEnumerable terms, Func<object, string> termFormatter = null, string separator = ", ", int maxCharsPerLine = 80)
{ {
List<string> lines = new List<string>(); List<string> lines = new List<string>();
StringBuilder lineBuilder = new StringBuilder(); StringBuilder lineBuilder = new StringBuilder();
foreach (object term in terms) foreach (object term in terms)
{ {
if (term == null && termFormatter == null) if (term == null && termFormatter == null)
@ -254,9 +237,7 @@ namespace TShockAPI
{ {
try try
{ {
termString = termFormatter(term); if ((termString = termFormatter(term)) == null)
if (termString == null)
continue; continue;
} }
catch (Exception ex) catch (Exception ex)
@ -270,41 +251,35 @@ namespace TShockAPI
termString = term.ToString(); termString = term.ToString();
} }
bool goesOnNextLine = (lineBuilder.Length + termString.Length > maxCharsPerLine); if (lineBuilder.Length + termString.Length + separator.Length < maxCharsPerLine)
if (!goesOnNextLine)
{ {
if (lineBuilder.Length > 0) lineBuilder.Append(termString).Append(separator);
lineBuilder.Append(separator);
lineBuilder.Append(termString);
} }
else else
{ {
// A separator should always be at the end of a line as we know it is followed by another line.
lineBuilder.Append(separator);
lines.Add(lineBuilder.ToString()); lines.Add(lineBuilder.ToString());
lineBuilder.Clear(); lineBuilder.Clear().Append(termString).Append(separator);
}
}
lineBuilder.Append(termString);
}
}
if (lineBuilder.Length > 0) if (lineBuilder.Length > 0)
lines.Add(lineBuilder.ToString()); {
lines.Add(lineBuilder.ToString().Substring(0, lineBuilder.Length - separator.Length));
}
return lines; return lines;
} }
public static bool TryParsePageNumber( public static bool TryParsePageNumber(List<string> commandParameters, int expectedParameterIndex, TSPlayer errorMessageReceiver, out int pageNumber)
List<string> commandParameters, int expectedParamterIndex, TSPlayer errorMessageReceiver, out int pageNumber)
{ {
pageNumber = 1; pageNumber = 1;
if (commandParameters.Count <= expectedParamterIndex) if (commandParameters.Count <= expectedParameterIndex)
return true; return true;
string pageNumberRaw = commandParameters[expectedParamterIndex]; string pageNumberRaw = commandParameters[expectedParameterIndex];
if (!int.TryParse(pageNumberRaw, out pageNumber) || pageNumber < 1) if (!int.TryParse(pageNumberRaw, out pageNumber) || pageNumber < 1)
{ {
if (errorMessageReceiver != null) if (errorMessageReceiver != null)
errorMessageReceiver.SendErrorMessage(string.Format("\"{0}\" is not a valid page number.", pageNumberRaw)); errorMessageReceiver.SendErrorMessage("\"{0}\" is not a valid page number.", pageNumberRaw);
pageNumber = 1; pageNumber = 1;
return false; return false;

View file

@ -40,6 +40,9 @@ namespace TShockAPI
// tshock.admin nodes // tshock.admin nodes
[Description("User can set build protection status.")]
public static readonly string antibuild = "tshock.admin.antibuild";
[Description("Prevents you from being kicked.")] [Description("Prevents you from being kicked.")]
public static readonly string immunetokick = "tshock.admin.nokick"; public static readonly string immunetokick = "tshock.admin.nokick";
@ -74,7 +77,7 @@ namespace TShockAPI
public static readonly string seeids = "tshock.admin.seeplayerids"; public static readonly string seeids = "tshock.admin.seeplayerids";
[Description("User can save all the players SSI state.")] [Description("User can save all the players SSI state.")]
public static readonly string savessi = "tshock.admin.savessi"; public static readonly string savessc = "tshock.admin.savessi";
[Description("User can elevate other users' groups temporarily.")] [Description("User can elevate other users' groups temporarily.")]
public static readonly string settempgroup = "tshock.admin.tempgroup"; public static readonly string settempgroup = "tshock.admin.tempgroup";
@ -107,12 +110,6 @@ namespace TShockAPI
[Description("User can reload the configurations file.")] [Description("User can reload the configurations file.")]
public static readonly string cfgreload = "tshock.cfg.reload"; public static readonly string cfgreload = "tshock.cfg.reload";
[Description("User can edit the max spawns.")]
public static readonly string cfgmaxspawns = "tshock.cfg.maxspawns";
[Description("User can edit the spawnrate.")]
public static readonly string cfgspawnrate = "tshock.cfg.spawnrate";
[Description("User can download updates to plugins that are currently running.")] [Description("User can download updates to plugins that are currently running.")]
public static readonly string updateplugins = "tshock.cfg.updateplugins"; public static readonly string updateplugins = "tshock.cfg.updateplugins";
@ -130,15 +127,15 @@ namespace TShockAPI
[Description("Prevents you from being disabled by projectile abuse detection.")] [Description("Prevents you from being disabled by projectile abuse detection.")]
public static readonly string ignoreprojectiledetection = "tshock.ignore.projectile"; public static readonly string ignoreprojectiledetection = "tshock.ignore.projectile";
[Description("Prevents you from being disabled by paint abuse detection.")]
public static readonly string ignorepaintdetection = "tshock.ignore.paint";
[Description("Prevents you from being reverted by no clip detection.")] [Description("Prevents you from being reverted by no clip detection.")]
public static readonly string ignorenoclipdetection = "tshock.ignore.noclip"; public static readonly string ignorenoclipdetection = "tshock.ignore.noclip";
[Description("Prevents you from being disabled by stack hack detection.")] [Description("Prevents you from being disabled by stack hack detection.")]
public static readonly string ignorestackhackdetection = "tshock.ignore.itemstack"; public static readonly string ignorestackhackdetection = "tshock.ignore.itemstack";
[Description("Prevents you from being kicked by hacked health detection.")]
public static readonly string ignorestathackdetection = "tshock.ignore.stats";
[Description("Prevents your actions from being ignored if damage is too high.")] [Description("Prevents your actions from being ignored if damage is too high.")]
public static readonly string ignoredamagecap = "tshock.ignore.damage"; public static readonly string ignoredamagecap = "tshock.ignore.damage";
@ -148,19 +145,28 @@ namespace TShockAPI
[Description("Allow unrestricted SendTileSquare usage, for client side world editing.")] [Description("Allow unrestricted SendTileSquare usage, for client side world editing.")]
public static readonly string allowclientsideworldedit = "tshock.ignore.sendtilesquare"; public static readonly string allowclientsideworldedit = "tshock.ignore.sendtilesquare";
[Description("Allow dropping banned items without the item being eaten.")]
public static readonly string allowdroppingbanneditems = "tshock.ignore.dropbanneditem";
// tshock.item nodes // tshock.item nodes
[Description("User can spawn items.")] [Description("User can spawn items.")]
public static readonly string item = "tshock.item.spawn"; public static readonly string item = "tshock.item.spawn";
[Description("User can clear items.")]
public static readonly string clearitems = "tshock.item.clear";
[Description("Allows you to use banned items.")] [Description("Allows you to use banned items.")]
public static readonly string usebanneditem = "tshock.item.usebanned"; public static readonly string usebanneditem = "tshock.item.usebanned";
// tshock.npc nodes // tshock.npc nodes
[Description("User can edit the max spawns.")]
public static readonly string maxspawns = "tshock.npc.maxspawns";
[Description("User can edit the spawnrate.")]
public static readonly string spawnrate = "tshock.npc.spawnrate";
[Description("User can start an invasion.")]
public static readonly string invade = "tshock.npc.invade";
[Description("User can spawn bosses.")] [Description("User can spawn bosses.")]
public static readonly string spawnboss = "tshock.npc.spawnboss"; public static readonly string spawnboss = "tshock.npc.spawnboss";
@ -207,13 +213,28 @@ namespace TShockAPI
[Description("User can use /spawn.")] [Description("User can use /spawn.")]
public static readonly string spawn = "tshock.tp.spawn"; public static readonly string spawn = "tshock.tp.spawn";
[Description("User can use the Rod of Discor.")]
public static readonly string rod = "tshock.tp.rod";
// tshock.world nodes // tshock.world nodes
[Description("Allows you to edit the spawn.")] [Description("Allows you to edit the spawn.")]
public static readonly string editspawn = "tshock.world.editspawn"; public static readonly string editspawn = "tshock.world.editspawn";
[Description("Allows you to edit regions.")]
public static readonly string editregion = "tshock.world.editregion";
[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.")] [Description("User can set the time.")]
public static readonly string time = "tshock.world.settime"; public static readonly string time = "tshock.world.time.set";
[Description("User can grow plants.")] [Description("User can grow plants.")]
public static readonly string grow = "tshock.world.grow"; public static readonly string grow = "tshock.world.grow";
@ -242,14 +263,29 @@ namespace TShockAPI
[Description("User can set the world spawn.")] [Description("User can set the world spawn.")]
public static readonly string worldspawn = "tshock.world.setspawn"; public static readonly string worldspawn = "tshock.world.setspawn";
[Description("User can cause some events.")] [Description("User can drop a meteor.")]
public static readonly string causeevents = "tshock.world.causeevents"; public static readonly string dropmeteor = "tshock.world.time.dropmeteor";
[Description("User can force an eclipse.")]
public static readonly string eclipse = "tshock.world.time.eclipse";
[Description("User can force a full moon.")]
public static readonly string fullmoon = "tshock.world.time.fullmoon";
[Description("User can modify the world.")] [Description("User can modify the world.")]
public static readonly string canbuild = "tshock.world.modify"; public static readonly string canbuild = "tshock.world.modify";
[Description("User can paint tiles.")]
public static readonly string canpaint = "tshock.world.paint";
[Description("User can turn on or off the rain.")]
public static readonly string rain = "tshock.world.rain";
// Non-grouped // Non-grouped
[Description("User can clear items or projectiles.")]
public static readonly string clear = "tshock.clear";
[Description("User can kill others.")] [Description("User can kill others.")]
public static readonly string kill = "tshock.kill"; public static readonly string kill = "tshock.kill";
@ -280,6 +316,12 @@ namespace TShockAPI
[Description("User can get the server info.")] [Description("User can get the server info.")]
public static readonly string serverinfo = "tshock.info"; public static readonly string serverinfo = "tshock.info";
[Description("Player recovers health as damage is taken. Can be one shotted.")]
public static readonly string godmode = "tshock.godmode";
[Description("Player can chat")]
public static readonly string canchat = "tshock.canchat";
/// <summary> /// <summary>
/// Lists all commands associated with a given permission /// Lists all commands associated with a given permission
/// </summary> /// </summary>
@ -300,7 +342,7 @@ namespace TShockAPI
var sb = new StringBuilder(); var sb = new StringBuilder();
foreach (var field in typeof(Permissions).GetFields().OrderBy(f => f.Name)) foreach (var field in typeof(Permissions).GetFields().OrderBy(f => f.Name))
{ {
var name = field.Name; var name = (string)field.GetValue(null);
var descattr = var descattr =
field.GetCustomAttributes(false).FirstOrDefault(o => o is DescriptionAttribute) as DescriptionAttribute; field.GetCustomAttributes(false).FirstOrDefault(o => o is DescriptionAttribute) as DescriptionAttribute;
@ -319,9 +361,9 @@ namespace TShockAPI
c => c =>
c.Name + (c.Names.Count > 1 ? "({0})".SFormat(string.Join(" ", c.Names.ToArray(), 1, c.Names.Count - 1)) : "")); c.Name + (c.Names.Count > 1 ? "({0})".SFormat(string.Join(" ", c.Names.ToArray(), 1, c.Names.Count - 1)) : ""));
sb.AppendLine("## <a id=\"{0}\">{0}</a> ".SFormat(name)); sb.AppendLine("{0}".SFormat(name));
sb.AppendLine("**Description:** {0} ".SFormat(desc)); sb.AppendLine("Description: {0} ".SFormat(desc));
sb.AppendLine("**Commands:** {0} ".SFormat(strs.Count() > 0 ? string.Join(" ", strs) : "None")); sb.AppendLine("Commands: {0} ".SFormat(strs.Count() > 0 ? string.Join(" ", strs) : "None"));
sb.AppendLine(); sb.AppendLine();
} }

View file

@ -1,87 +0,0 @@
/*
TShock, a server mod for Terraria
Copyright (C) 2011-2013 Nyx Studios (fka. The TShock Team)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
using System;
using System.IO;
using System.Threading;
using Terraria;
namespace TShockAPI.PluginUpdater
{
class PluginUpdaterThread
{
private TSPlayer invoker;
public PluginUpdaterThread(TSPlayer player)
{
invoker = player;
PluginVersionCheck.PluginUpdate += PluginUpdate;
HandleUpdate();
}
private void HandleUpdate()
{
foreach(PluginContainer cont in ProgramServer.Plugins)
new Thread(PluginVersionCheck.CheckPlugin).Start(cont.Plugin);
}
private int Updates = 0;
private void PluginUpdate(UpdateArgs args)
{
Updates++;
if(args.Success && String.IsNullOrEmpty(args.Error))
{
invoker.SendSuccessMessage(String.Format("{0} was downloaded successfully.", args.Plugin.Name));
}
else if(args.Success)
{
invoker.SendSuccessMessage(String.Format("{0} was skipped. Reason: {1}", args.Plugin.Name, args.Error));
}
else
{
invoker.SendSuccessMessage(String.Format("{0} failed to downloaded. Error: {1}", args.Plugin.Name, args.Error));
}
if(Updates >= Terraria.ProgramServer.Plugins.Count)
{
PluginVersionCheck.PluginUpdate -= PluginUpdate;
invoker.SendSuccessMessage("All plugins have been downloaded. Now copying them to the plugin folder...");
string folder = Path.Combine(TShock.SavePath, "UpdatedPlugins");
string dest = Path.Combine(TShock.SavePath, "..", "ServerPlugins");
foreach (string dir in Directory.GetDirectories(folder, "*", System.IO.SearchOption.AllDirectories))
{
string new_folder = dest + dir.Substring(folder.Length);
if (!Directory.Exists(new_folder))
Directory.CreateDirectory(new_folder);
}
foreach (string file_name in Directory.GetFiles(folder, "*.*", System.IO.SearchOption.AllDirectories))
{
TSPlayer.Server.SendSuccessMessage(String.Format("Copied {0}", file_name));
File.Copy(file_name, dest + file_name.Substring(folder.Length), true);
}
Directory.Delete(folder, true);
invoker.SendSuccessMessage("All plugins have been processed. Restart the server to have access to the new plugins.");
}
}
}
}

View file

@ -1,127 +0,0 @@
/*
TShock, a server mod for Terraria
Copyright (C) 2011-2013 Nyx Studios (fka. The TShock Team)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using JsonLoader;
using Newtonsoft.Json;
namespace TShockAPI.PluginUpdater
{
public class PluginVersionCheck
{
public delegate void PluginUpdateD(UpdateArgs e);
public static event PluginUpdateD PluginUpdate;
public static void OnPluginUpdate(UpdateArgs args)
{
if (PluginUpdate == null)
{
return;
}
PluginUpdate(args);
}
public static void CheckPlugin(object p)
{
TerrariaPlugin plugin = (TerrariaPlugin)p;
UpdateArgs args = new UpdateArgs {Plugin = plugin, Success = true, Error = ""};
List<string> files = new List<string>();
try
{
if (!String.IsNullOrEmpty(plugin.UpdateURL))
{
var request = HttpWebRequest.Create(plugin.UpdateURL);
VersionInfo vi;
request.Timeout = 5000;
using (var response = request.GetResponse())
{
using (var reader = new StreamReader(response.GetResponseStream()))
{
vi = JsonConvert.DeserializeObject<VersionInfo>(reader.ReadToEnd());
}
}
System.Version v = System.Version.Parse((vi.version.ToString()));
if (!v.Equals(plugin.Version))
{
DownloadPackage pkg;
request = HttpWebRequest.Create(vi.url);
request.Timeout = 5000;
using (var response = request.GetResponse())
{
using (var reader = new StreamReader(response.GetResponseStream()))
{
pkg = JsonConvert.DeserializeObject<DownloadPackage>(reader.ReadToEnd());
}
}
foreach (PluginFile f in pkg.files)
{
using (WebClient Client = new WebClient())
{
string dir = Path.Combine(TShock.SavePath, "UpdatedPlugins");
if (!Directory.Exists(dir))
Directory.CreateDirectory(dir);
Client.DownloadFile(f.url,
Path.Combine(dir, f.destination));
files.Add(Path.Combine(dir, f.destination));
}
}
}
else
{
args.Error = "Plugin is up to date.";
}
}
else
{
args.Error = "Plugin has no updater recorded.";
}
}
catch(Exception e)
{
args.Success = false;
args.Error = e.Message;
if(files.Count > 0)
{
foreach(string s in files)
{
File.Delete(s);
}
}
}
OnPluginUpdate(args);
}
}
public class UpdateArgs
{
public TerrariaPlugin Plugin { get; set; }
public bool Success { get; set; }
public string Error { get; set; }
}
}

View file

@ -1,87 +0,0 @@
/*
TShock, a server mod for Terraria
Copyright (C) 2011-2013 Nyx Studios (fka. The TShock Team)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
using System;
using System.Collections.Generic;
namespace JsonLoader
{
class VersionInfo
{
public Version version;
public string url;
}
public class Version
{
public int Major;
public int Minor;
public int Build;
public int Revision;
public int MajorRevision;
public int MinorRevision;
public Version()
{
SetVersion(0,0,0,0);
}
public Version(int m)
{
SetVersion(m, 0, 0, 0);
}
public Version(int ma, int mi)
{
SetVersion(ma, mi, 0, 0);
}
public Version(int ma, int mi, int b)
{
SetVersion(ma, mi, b, 0);
}
public Version(int ma, int mi, int b, int r)
{
SetVersion(ma, mi, b, r);
}
private void SetVersion(int ma, int mi, int b, int r)
{
Major = ma;
Minor = mi;
Build = b;
Revision = r;
}
public string ToString()
{
return String.Format("{0}.{1}.{2}.{3}", Major, Minor, Build, Revision);
}
}
class DownloadPackage
{
public List<PluginFile> files;
}
class PluginFile
{
public string url;
public string destination = "";
}
}

View file

@ -49,5 +49,5 @@ using System.Runtime.InteropServices;
// Build Number // Build Number
// MMdd of the build // MMdd of the build
[assembly: AssemblyVersion("4.1.0.0926")] [assembly: AssemblyVersion("4.2.2.1228")]
[assembly: AssemblyFileVersion("4.1.0.0926")] [assembly: AssemblyFileVersion("4.2.2.1228")]

View file

@ -0,0 +1,38 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace TShockAPI
{
/// <summary>
/// Custom packet types for use with Raptor.
/// </summary>
public enum RaptorPacketTypes : byte
{
/// <summary>
/// The packet sent to the server to be acknowledged as a Raptor client.
/// </summary>
Acknowledge = 0,
/// <summary>
/// The packet sent to the client which dictates its permissions.
/// </summary>
Permissions,
/// <summary>
/// The packet sent which sets region info.
/// </summary>
Region,
/// <summary>
/// The packet sent to delete a region.
/// </summary>
RegionDelete,
/// <summary>
/// The packet sent which sets warp info.
/// </summary>
Warp,
/// <summary>
/// The packet sent to delete a warp.
/// </summary>
WarpDelete
}
}

View file

@ -1,25 +1,7 @@
/* //------------------------------------------------------------------------------
TShock, a server mod for Terraria
Copyright (C) 2011-2013 Nyx Studios (fka. The TShock Team)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
//------------------------------------------------------------------------------
// <auto-generated> // <auto-generated>
// This code was generated by a tool. // This code was generated by a tool.
// Runtime Version:4.0.30319.235 // Runtime Version:4.0.30319.17929
// //
// Changes to this file may cause incorrect behavior and will be lost if // Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated. // the code is regenerated.
@ -27,6 +9,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
namespace TShockAPI { namespace TShockAPI {
using System;
/// <summary> /// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc. /// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary> /// </summary>
@ -74,48 +59,5 @@ namespace TShockAPI {
resourceCulture = value; resourceCulture = value;
} }
} }
/// <summary>
/// Looks up a localized string similar to #Format
///#name parent permisson1 permission2 permissionN
///#if there is no parent, put null instead
///#groups inherit permissions from their parents
///#put a ! before a permission to negate it
///#Do not remove the group default
///#Do not name a group SuperAdmin, that is hard-coded into the code, it grants total permissions
///#ALWAYS DECLARE A GROUP&apos;S PARENT BEFORE YOU DECLARE THE GROUP
///
///#currently avaliable permissions:
///#reservedslot - reserved slot for player
///#canwater - allow players to use water
///#canlav [rest of string was truncated]&quot;;.
/// </summary>
internal static string groups {
get {
return ResourceManager.GetString("groups", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to #see https://github.com/TShock/TShock/wiki/Item-List for a list of item ids
///#List each banned item ID below this, with each on a new line.
/// </summary>
internal static string itembans {
get {
return ResourceManager.GetString("itembans", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to #format
///#ip group
///#see groups.txt for a list of groups
///#127.0.0.1 superadmin.
/// </summary>
internal static string users {
get {
return ResourceManager.GetString("users", resourceCulture);
}
}
} }
} }

View file

@ -118,13 +118,4 @@
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader> </resheader>
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" /> <assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<data name="groups" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>config\groups.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;Windows-1252</value>
</data>
<data name="itembans" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>config\itembans.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value>
</data>
<data name="users" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>config\users.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;Windows-1252</value>
</data>
</root> </root>

View file

@ -196,8 +196,10 @@ namespace Rests
protected virtual object ExecuteCommand(RestCommand cmd, RestVerbs verbs, IParameterCollection parms) protected virtual object ExecuteCommand(RestCommand cmd, RestVerbs verbs, IParameterCollection parms)
{ {
object result = cmd.Execute(verbs, parms); object result = cmd.Execute(verbs, parms);
if (cmd.DoLog) if (cmd.DoLog && TShock.Config.LogRest)
{
Log.ConsoleInfo("Anonymous requested REST endpoint: " + BuildRequestUri(cmd, verbs, parms, false)); Log.ConsoleInfo("Anonymous requested REST endpoint: " + BuildRequestUri(cmd, verbs, parms, false));
}
return result; return result;
} }

View file

@ -50,7 +50,7 @@ namespace TShockAPI
else else
{ {
Rest.Register(new RestCommand("/v2/server/status", (a, b) => this.ServerStatusV2(a, b, SecureRest.TokenData.None))); Rest.Register(new RestCommand("/v2/server/status", (a, b) => this.ServerStatusV2(a, b, SecureRest.TokenData.None)));
Rest.Register(new RestCommand("/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/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("/v3/server/rules", (a, b) => this.ServerRules(a, b, SecureRest.TokenData.None)));
} }
@ -236,7 +236,7 @@ namespace TShockAPI
var players = new ArrayList(); var players = new ArrayList();
foreach (TSPlayer tsPlayer in TShock.Players.Where(p => null != p)) foreach (TSPlayer tsPlayer in TShock.Players.Where(p => null != p))
{ {
var p = PlayerFilter(tsPlayer, parameters); var p = PlayerFilter(tsPlayer, parameters, ((tokenData.UserGroupName) != "" && TShock.Utils.GetGroup(tokenData.UserGroupName).HasPermission(RestPermissions.viewips)));
if (null != p) if (null != p)
players.Add(p); players.Add(p);
} }
@ -258,7 +258,7 @@ namespace TShockAPI
rules.Add("PvPMode", TShock.Config.PvPMode); rules.Add("PvPMode", TShock.Config.PvPMode);
rules.Add("SpawnProtection", TShock.Config.SpawnProtection); rules.Add("SpawnProtection", TShock.Config.SpawnProtection);
rules.Add("SpawnProtectionRadius", TShock.Config.SpawnProtectionRadius); rules.Add("SpawnProtectionRadius", TShock.Config.SpawnProtectionRadius);
rules.Add("ServerSideInventory", TShock.Config.ServerSideInventory); rules.Add("ServerSideInventory", TShock.Config.ServerSideCharacter);
ret.Add("rules", rules); ret.Add("rules", rules);
} }
@ -307,7 +307,7 @@ namespace TShockAPI
return RestMissingParam("password"); return RestMissingParam("password");
// NOTE: ip can be blank // NOTE: ip can be blank
User user = new User(username, password, group, "", ""); User user = new User(username, password, "", group, "", "", "");
try try
{ {
TShock.Users.AddUser(user); TShock.Users.AddUser(user);
@ -404,7 +404,7 @@ namespace TShockAPI
try try
{ {
TShock.Bans.AddBan(ip, name, parameters["reason"], true, tokenData.Username); TShock.Bans.AddBan(ip, name, "", parameters["reason"], true, tokenData.Username);
} }
catch (Exception e) catch (Exception e)
{ {
@ -622,7 +622,7 @@ namespace TShockAPI
TSPlayer player = (TSPlayer)ret; TSPlayer player = (TSPlayer)ret;
var reason = null == parameters["reason"] ? "Banned via web" : parameters["reason"]; var reason = null == parameters["reason"] ? "Banned via web" : parameters["reason"];
TShock.Bans.AddBan(player.IP, player.Name, reason); TShock.Bans.AddBan(player.IP, player.Name, "", reason);
TShock.Utils.ForceKick(player, reason, false, true); TShock.Utils.ForceKick(player, reason, false, true);
return RestResponse("Player " + player.Name + " was banned"); return RestResponse("Player " + player.Name + " was banned");
} }
@ -719,7 +719,7 @@ namespace TShockAPI
var permissions = (null == parameters["permissions"]) ? group.Permissions : parameters["permissions"]; var permissions = (null == parameters["permissions"]) ? group.Permissions : parameters["permissions"];
try try
{ {
TShock.Groups.UpdateGroup(group.Name, parent, permissions, chatcolor); TShock.Groups.UpdateGroup(group.Name, parent, permissions, chatcolor, group.Suffix, group.Prefix);
} }
catch (Exception e) catch (Exception e)
{ {
@ -859,18 +859,22 @@ namespace TShockAPI
return group; return group;
} }
private Dictionary<string, object> PlayerFilter(TSPlayer tsPlayer, IParameterCollection parameters) private Dictionary<string, object> PlayerFilter(TSPlayer tsPlayer, IParameterCollection parameters, bool viewips = false)
{ {
var player = new Dictionary<string, object> var player = new Dictionary<string, object>
{ {
{"nickname", tsPlayer.Name}, {"nickname", tsPlayer.Name},
{"username", null == tsPlayer.UserAccountName ? "" : tsPlayer.UserAccountName}, {"username", tsPlayer.UserAccountName ?? ""},
{"ip", tsPlayer.IP},
{"group", tsPlayer.Group.Name}, {"group", tsPlayer.Group.Name},
{"active", tsPlayer.Active}, {"active", tsPlayer.Active},
{"state", tsPlayer.State}, {"state", tsPlayer.State},
{"team", tsPlayer.Team}, {"team", tsPlayer.Team},
}; };
if (viewips)
{
player.Add("ip", tsPlayer.IP);
}
foreach (IParameter filter in parameters) foreach (IParameter filter in parameters)
{ {
if (player.ContainsKey(filter.Name) && !player[filter.Name].Equals(filter.Value)) if (player.ContainsKey(filter.Name) && !player[filter.Name].Equals(filter.Value))

View file

@ -83,5 +83,8 @@ namespace Rests
[Description("REST user can run raw TShock commands (the raw command permissions are also checked though).")] [Description("REST user can run raw TShock commands (the raw command permissions are also checked though).")]
public static readonly string restrawcommand = "tshock.rest.command"; public static readonly string restrawcommand = "tshock.rest.command";
[Description("REST user can view the ips of players.")]
public static readonly string viewips = "tshock.rest.viewips";
} }
} }

View file

@ -192,7 +192,7 @@ namespace Rests
} }
object result = secureCmd.Execute(verbs, parms, tokenData); object result = secureCmd.Execute(verbs, parms, tokenData);
if (cmd.DoLog) if (cmd.DoLog && TShock.Config.LogRest)
TShock.Utils.SendLogs(string.Format( TShock.Utils.SendLogs(string.Format(
"\"{0}\" requested REST endpoint: {1}", tokenData.Username, this.BuildRequestUri(cmd, verbs, parms, false)), "\"{0}\" requested REST endpoint: {1}", tokenData.Username, this.BuildRequestUri(cmd, verbs, parms, false)),
Color.PaleVioletRed); Color.PaleVioletRed);

View file

@ -20,6 +20,7 @@ using System.Collections.Generic;
using System.ComponentModel; using System.ComponentModel;
using System.Threading; using System.Threading;
using Terraria; using Terraria;
using TerrariaApi.Server;
namespace TShockAPI namespace TShockAPI
{ {
@ -45,7 +46,9 @@ namespace TShockAPI
/// <summary> /// <summary>
/// SaveWorld event handler which notifies users that the server may lag /// SaveWorld event handler which notifies users that the server may lag
/// </summary> /// </summary>
public void OnSaveWorld(bool resettime = false, HandledEventArgs e = null) public void OnSaveWorld(WorldSaveEventArgs args)
{
if (TShock.Config.AnnounceSave)
{ {
// Protect against internal errors causing save failures // Protect against internal errors causing save failures
// These can be caused by an unexpected error such as a bad or out of date plugin // These can be caused by an unexpected error such as a bad or out of date plugin
@ -59,6 +62,7 @@ namespace TShockAPI
Log.Error(ex.ToString()); Log.Error(ex.ToString());
} }
} }
}
/// <summary> /// <summary>
/// Saves the map data /// Saves the map data
@ -120,7 +124,7 @@ namespace TShockAPI
{ {
if (task.direct) if (task.direct)
{ {
OnSaveWorld(); OnSaveWorld(new WorldSaveEventArgs());
WorldGen.realsaveWorld(task.resetTime); WorldGen.realsaveWorld(task.resetTime);
} }
else else

101
TShockAPI/StatTracker.cs Normal file
View file

@ -0,0 +1,101 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Threading;
using System.IO;
using System.Web;
namespace TShockAPI
{
public class StatTracker
{
private bool failed;
private bool initialized;
public StatTracker()
{
}
public void Initialize()
{
if (!initialized)
{
initialized = true;
ThreadPool.QueueUserWorkItem(SendUpdate);
}
}
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);
var data = new JsonData
{
port = Terraria.Netplay.serverPort,
currentPlayers = TShock.Utils.ActivePlayers(),
maxPlayers = TShock.Config.MaxSlots,
systemRam = 0,
systemCPUClock = 0,
version = TShock.VersionNum.ToString(),
terrariaVersion = Terraria.Main.versionNumber2,
mono = Terraria.Main.runningMono
};
var serialized = Newtonsoft.Json.JsonConvert.SerializeObject(data);
var encoded = HttpUtility.UrlEncode(serialized);
var uri = String.Format("http://96.47.231.227:8000?data={0}", encoded);
var client = (HttpWebRequest)WebRequest.Create(uri);
client.Timeout = 5000;
try
{
using (var resp = GetResponseNoException(client))
{
if (resp.StatusCode != HttpStatusCode.OK)
{
throw new IOException("Server did not respond with an OK.");
}
failed = false;
}
}
catch (Exception e)
{
if (!failed)
{
Log.ConsoleError("StatTracker Exception: {0}", e);
failed = true;
}
}
ThreadPool.QueueUserWorkItem(SendUpdate);
}
}
public struct JsonData
{
public int port;
public int currentPlayers;
public int maxPlayers;
public int systemRam;
public int systemCPUClock;
public string version;
public string terrariaVersion;
public bool mono;
}
}

679
TShockAPI/TSPlayer.cs Normal file → Executable file
View file

@ -20,8 +20,10 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.IO; using System.IO;
using System.Text;
using System.Threading; using System.Threading;
using Terraria; using Terraria;
using TShockAPI.DB;
using TShockAPI.Net; using TShockAPI.Net;
namespace TShockAPI namespace TShockAPI
@ -38,6 +40,11 @@ namespace TShockAPI
/// </summary> /// </summary>
public static readonly TSPlayer All = new TSPlayer("All"); public static readonly TSPlayer All = new TSPlayer("All");
/// <summary>
/// Gets whether the player is using Raptor.
/// </summary>
public bool IsRaptor { get; internal set; }
/// <summary> /// <summary>
/// The amount of tiles that the player has killed in the last second. /// The amount of tiles that the player has killed in the last second.
/// </summary> /// </summary>
@ -49,24 +56,44 @@ namespace TShockAPI
public int TilePlaceThreshold { get; set; } public int TilePlaceThreshold { get; set; }
/// <summary> /// <summary>
/// The amount of liquid( in tiles ) that the player has placed in the last second. /// The amount of liquid (in tiles) that the player has placed in the last second.
/// </summary> /// </summary>
public int TileLiquidThreshold { get; set; } public int TileLiquidThreshold { get; set; }
/// <summary>
/// The amount of tiles that the player has painted in the last second.
/// </summary>
public int PaintThreshold { get; set; }
/// <summary> /// <summary>
/// The number of projectiles created by the player in the last second. /// The number of projectiles created by the player in the last second.
/// </summary> /// </summary>
public int ProjectileThreshold { get; set; } public int ProjectileThreshold { get; set; }
/// <summary>
/// A timer to keep track of whether or not the player has recently thrown an explosive
/// </summary>
public int RecentFuse = 0;
/// <summary>
/// A system to delay Remembered Position Teleports a few seconds
/// </summary>
public int RPPending = 0;
public int sX = -1;
public int sY = -1;
/// <summary> /// <summary>
/// A queue of tiles destroyed by the player for reverting. /// A queue of tiles destroyed by the player for reverting.
/// </summary> /// </summary>
public Dictionary<Vector2, TileData> TilesDestroyed { get; protected set; } public Dictionary<Vector2, Tile> TilesDestroyed { get; protected set; }
/// <summary> /// <summary>
/// A queue of tiles placed by the player for reverting. /// A queue of tiles placed by the player for reverting.
/// </summary> /// </summary>
public Dictionary<Vector2, TileData> TilesCreated { get; protected set; } public Dictionary<Vector2, Tile> TilesCreated { get; protected set; }
public int FirstMaxHP { get; set; } public int FirstMaxHP { get; set; }
@ -103,7 +130,7 @@ namespace TShockAPI
/// <summary> /// <summary>
/// The last time the player changed their team or pvp status. /// The last time the player changed their team or pvp status.
/// </summary> /// </summary>
public DateTime LastPvpChange; public DateTime LastPvPTeamChange;
/// <summary> /// <summary>
/// Temp points for use in regions and other plugins. /// Temp points for use in regions and other plugins.
@ -129,11 +156,6 @@ namespace TShockAPI
/// </summary> /// </summary>
public DateTime LastThreat { get; set; } public DateTime LastThreat { get; set; }
/// <summary>
/// Not used, can be removed.
/// </summary>
public DateTime LastTileChangeNotify { get; set; }
public bool InitSpawn; public bool InitSpawn;
/// <summary> /// <summary>
@ -141,10 +163,8 @@ namespace TShockAPI
/// </summary> /// </summary>
public bool DisplayLogs = true; public bool DisplayLogs = true;
public Vector2 oldSpawn = Vector2.Zero;
/// <summary> /// <summary>
/// The last player that the player whispered with( to or from ). /// The last player that the player whispered with (to or from).
/// </summary> /// </summary>
public TSPlayer LastWhisper; public TSPlayer LastWhisper;
@ -195,8 +215,6 @@ namespace TShockAPI
/// </summary> /// </summary>
public bool mute; public bool mute;
public bool TpLock;
private Player FakePlayer; private Player FakePlayer;
public bool RequestedSection; public bool RequestedSection;
@ -277,6 +295,21 @@ namespace TShockAPI
/// </summary> /// </summary>
public bool LoginHarassed = false; public bool LoginHarassed = false;
/// <summary>
/// Player cant die, unless onehit
/// </summary>
public bool GodMode = false;
/// <summary>
/// Players controls are inverted if using SSC
/// </summary>
public bool Confused = false;
/// <summary>
/// The last projectile type this player tried to kill.
/// </summary>
public int LastKilledProjectile = 0;
/// <summary> /// <summary>
/// Whether the player is a real, human, player on the server. /// Whether the player is a real, human, player on the server.
/// </summary> /// </summary>
@ -294,12 +327,31 @@ namespace TShockAPI
} }
} }
/// <summary>
/// Gets the player's selected item.
/// </summary>
public Item SelectedItem
{
get { return TPlayer.inventory[TPlayer.selectedItem]; }
}
public int State public int State
{ {
get { return Netplay.serverSock[Index].state; } get { return Netplay.serverSock[Index].state; }
set { Netplay.serverSock[Index].state = value; } set { Netplay.serverSock[Index].state = value; }
} }
/// <summary>
/// Gets the player's UUID.
/// </summary>
public string UUID
{
get { return RealPlayer ? Netplay.serverSock[Index].clientUUID : ""; }
}
/// <summary>
/// Gets the player's IP.
/// </summary>
public string IP public string IP
{ {
get get
@ -321,16 +373,16 @@ namespace TShockAPI
/// Saves the player's inventory to SSI /// Saves the player's inventory to SSI
/// </summary> /// </summary>
/// <returns>bool - True/false if it saved successfully</returns> /// <returns>bool - True/false if it saved successfully</returns>
public bool SaveServerInventory() public bool SaveServerCharacter()
{ {
if (!TShock.Config.ServerSideInventory) if (!TShock.Config.ServerSideCharacter)
{ {
return false; return false;
} }
try try
{ {
PlayerData.CopyInventory(this); PlayerData.CopyCharacter(this);
TShock.InventoryDB.InsertPlayerData(this); TShock.CharacterDB.InsertPlayerData(this);
return true; return true;
} catch (Exception e) } catch (Exception e)
{ {
@ -338,6 +390,29 @@ namespace TShockAPI
return false; return false;
} }
}
/// <summary>
/// Sends the players server side character to client
/// </summary>
/// <returns>bool - True/false if it saved successfully</returns>
public bool SendServerCharacter()
{
if (!TShock.Config.ServerSideCharacter)
{
return false;
}
try
{
PlayerData.RestoreCharacter(this);
return true;
}
catch (Exception e)
{
Log.Error(e.Message);
return false;
}
} }
/// <summary> /// <summary>
@ -383,6 +458,8 @@ namespace TShockAPI
get { return (int) (Y/16); } get { return (int) (Y/16); }
} }
public bool TpLock;
public bool InventorySlotAvailable public bool InventorySlotAvailable
{ {
get get
@ -390,7 +467,7 @@ namespace TShockAPI
bool flag = false; bool flag = false;
if (RealPlayer) if (RealPlayer)
{ {
for (int i = 0; i < 40; i++) //41 is trash can, 42-45 is coins, 46-49 is ammo for (int i = 0; i < 50; i++) //51 is trash can, 52-55 is coins, 56-59 is ammo
{ {
if (TPlayer.inventory[i] == null || !TPlayer.inventory[i].active || TPlayer.inventory[i].name == "") if (TPlayer.inventory[i] == null || !TPlayer.inventory[i].active || TPlayer.inventory[i].name == "")
{ {
@ -405,8 +482,8 @@ namespace TShockAPI
public TSPlayer(int index) public TSPlayer(int index)
{ {
TilesDestroyed = new Dictionary<Vector2, TileData>(); TilesDestroyed = new Dictionary<Vector2, Tile>();
TilesCreated = new Dictionary<Vector2, TileData>(); TilesCreated = new Dictionary<Vector2, Tile>();
Index = index; Index = index;
Group = Group.DefaultGroup; Group = Group.DefaultGroup;
IceTiles = new List<Point>(); IceTiles = new List<Point>();
@ -415,8 +492,8 @@ namespace TShockAPI
protected TSPlayer(String playerName) protected TSPlayer(String playerName)
{ {
TilesDestroyed = new Dictionary<Vector2, TileData>(); TilesDestroyed = new Dictionary<Vector2, Tile>();
TilesCreated = new Dictionary<Vector2, TileData>(); TilesCreated = new Dictionary<Vector2, Tile>();
Index = -1; Index = -1;
FakePlayer = new Player {name = playerName, whoAmi = -1}; FakePlayer = new Player {name = playerName, whoAmi = -1};
Group = Group.DefaultGroup; Group = Group.DefaultGroup;
@ -457,12 +534,49 @@ namespace TShockAPI
//Sending a fake world id causes the client to not be able to find a stored spawnx/y. //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. //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, WorldID = !fakeid ? Main.worldID : -1,
WorldFlags = (WorldGen.shadowOrbSmashed ? WorldInfoFlag.OrbSmashed : WorldInfoFlag.None) | MoonType = (byte)Main.moonType,
(NPC.downedBoss1 ? WorldInfoFlag.DownedBoss1 : WorldInfoFlag.None) | TreeX0 = Main.treeX[0],
(NPC.downedBoss2 ? WorldInfoFlag.DownedBoss2 : WorldInfoFlag.None) | TreeX1 = Main.treeX[1],
(NPC.downedBoss3 ? WorldInfoFlag.DownedBoss3 : WorldInfoFlag.None) | TreeX2 = Main.treeX[2],
(Main.hardMode ? WorldInfoFlag.HardMode : WorldInfoFlag.None) | TreeStyle0 = (byte)Main.treeStyle[0],
(NPC.downedClown ? WorldInfoFlag.DownedClown : WorldInfoFlag.None), 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 WorldName = TShock.Config.UseServerName ? TShock.Config.ServerName : Main.worldName
}; };
msg.PackFull(ms); msg.PackFull(ms);
@ -470,45 +584,48 @@ namespace TShockAPI
} }
} }
public bool Teleport(int tilex, int tiley) public bool Teleport(float x, float y, byte style = 1)
{ {
InitSpawn = false; if (x > Main.rightWorld - 992)
SendWorldInfo(tilex, tiley, true);
//150 Should avoid all client crash errors
//The error occurs when a tile trys to update which the client hasnt load yet, Clients only update tiles withen 150 blocks
//Try 300 if it does not work (Higher number - Longer load times - Less chance of error)
//Should we properly send sections so that clients don't get tiles twice?
SendTileSquare(tilex, tiley, 150);
/* //We shouldn't need this section anymore -it can prevent otherwise acceptable teleportation under some circumstances.
if (!SendTileSquare(tilex, tiley, 150))
{ {
InitSpawn = true; x = Main.rightWorld - 992;
SendWorldInfo(Main.spawnTileX, Main.spawnTileY, false); }
return false; if (x < 992)
{
x = 992;
}
if (y > Main.bottomWorld - 992)
{
y = Main.bottomWorld - 992;
}
if (y < 992)
{
y = 992;
} }
*/ SendTileSquare((int) (x/16), (int) (y/16), 15);
Spawn(-1, -1); TPlayer.Teleport(new Vector2(x, y), style);
NetMessage.SendData((int)PacketTypes.Teleport, -1, -1, "", 0, TPlayer.whoAmi, x, y, style);
SendWorldInfo(Main.spawnTileX, Main.spawnTileY, false);
TPlayer.position.X = (float)(tilex * 16 + 8 - TPlayer.width /2);
TPlayer.position.Y = (float)(tiley * 16 - TPlayer.height);
//We need to send the tile data again to prevent clients from thinking they *really* destroyed blocks just now.
SendTileSquare(tilex, tiley, 10);
return true; return true;
} }
public void Heal(int health = 500)
{
NetMessage.SendData((int)PacketTypes.PlayerHealOther, -1, -1, "", this.TPlayer.whoAmi, health);
}
public void Spawn() public void Spawn()
{ {
// TPlayer.FindSpawn();
if (this.sX > 0 && this.sY > 0)
{
Spawn(this.sX, this.sY);
}
else
{
Spawn(TPlayer.SpawnX, TPlayer.SpawnY); Spawn(TPlayer.SpawnX, TPlayer.SpawnY);
} }
}
public void Spawn(int tilex, int tiley) public void Spawn(int tilex, int tiley)
{ {
@ -544,27 +661,35 @@ namespace TShockAPI
try try
{ {
int num = (size - 1)/2; int num = (size - 1)/2;
int m_x=0; int m_x = 0;
int m_y=0; int m_y = 0;
if (x - num <0){ if (x - num < 0)
m_x=0; {
}else{ m_x = 0;
}
else
{
m_x = x - num; m_x = x - num;
} }
if (y - num <0){ if (y - num < 0)
m_y=0; {
}else{ m_y = 0;
}
else
{
m_y = y - num; m_y = y - num;
} }
if (m_x + size > Main.maxTilesX){ if (m_x + size > Main.maxTilesX)
m_x=Main.maxTilesX - size; {
m_x = Main.maxTilesX - size;
} }
if (m_y + size > Main.maxTilesY){ if (m_y + size > Main.maxTilesY)
m_y=Main.maxTilesY - size; {
m_y = Main.maxTilesY - size;
} }
SendData(PacketTypes.TileSendSquare, "", size, m_x, m_y); SendData(PacketTypes.TileSendSquare, "", size, m_x, m_y);
@ -572,7 +697,6 @@ namespace TShockAPI
} }
catch (IndexOutOfRangeException) catch (IndexOutOfRangeException)
{ {
// This is expected if square exceeds array. // This is expected if square exceeds array.
} }
catch (Exception ex) catch (Exception ex)
@ -594,7 +718,7 @@ namespace TShockAPI
public virtual void GiveItem(int type, string name, int width, int height, int stack, int prefix = 0) public virtual void GiveItem(int type, string name, int width, int height, int stack, int prefix = 0)
{ {
int itemid = Item.NewItem((int) X, (int) Y, width, height, type, stack, true, prefix); int itemid = Item.NewItem((int) X, (int) Y, width, height, type, stack, true, prefix, true);
// This is for special pickaxe/hammers/swords etc // This is for special pickaxe/hammers/swords etc
Main.item[itemid].SetDefaults(name); Main.item[itemid].SetDefaults(name);
@ -604,8 +728,10 @@ namespace TShockAPI
Main.item[itemid].stack = stack; Main.item[itemid].stack = stack;
Main.item[itemid].owner = Index; Main.item[itemid].owner = Index;
Main.item[itemid].prefix = (byte) prefix; Main.item[itemid].prefix = (byte) prefix;
NetMessage.SendData((int) PacketTypes.ItemDrop, -1, -1, "", itemid, 0f, 0f, 0f); Main.item[itemid].noGrabDelay = 1;
NetMessage.SendData((int) PacketTypes.ItemOwner, -1, -1, "", itemid, 0f, 0f, 0f); Main.item[itemid].velocity = Main.player[this.Index].velocity;
NetMessage.SendData((int)PacketTypes.ItemDrop, -1, -1, "", itemid, 0f, 0f, 0f);
NetMessage.SendData((int)PacketTypes.ItemOwner, -1, -1, "", itemid, 0f, 0f, 0f);
} }
public virtual void SendInfoMessage(string msg) public virtual void SendInfoMessage(string msg)
@ -681,15 +807,37 @@ namespace TShockAPI
SendData(PacketTypes.PlayerTeam, "", Index); SendData(PacketTypes.PlayerTeam, "", Index);
} }
public virtual void Disable(string reason = "") private DateTime LastDisableNotification = DateTime.UtcNow;
public int ActiveChest = -1;
public virtual void Disable(string reason = "", bool displayConsole = true)
{ {
LastThreat = DateTime.UtcNow; LastThreat = DateTime.UtcNow;
SetBuff(33, 330, true); //Weak SetBuff(33, 330, true); //Weak
SetBuff(32, 330, true); //Slow SetBuff(32, 330, true); //Slow
SetBuff(23, 330, true); //Cursed SetBuff(23, 330, true); //Cursed
if (!string.IsNullOrEmpty(reason)) SetBuff(47, 330, true); //Frozen
Log.ConsoleInfo(string.Format("Player {0} has been disabled for {1}.", Name, reason));
if (ActiveChest != -1)
{
SendData(PacketTypes.ChestOpen, "", -1);
}
if (!string.IsNullOrEmpty(reason))
{
if ((DateTime.UtcNow - LastDisableNotification).TotalMilliseconds > 5000)
{
if (displayConsole)
{
Log.ConsoleInfo(string.Format("Player {0} has been disabled for {1}.", Name, reason));
}
else
{
Log.Info("Player {0} has been disabled for {1}.", Name, reason);
}
LastDisableNotification = DateTime.UtcNow;
}
}
var trace = new StackTrace(); var trace = new StackTrace();
StackFrame frame = null; StackFrame frame = null;
frame = trace.GetFrame(1); frame = trace.GetFrame(1);
@ -744,6 +892,177 @@ namespace TShockAPI
return TShock.SendBytes(Netplay.serverSock[Index], data); return TShock.SendBytes(Netplay.serverSock[Index], data);
} }
/// <summary>
/// Sends Raptor permissions to the player.
/// </summary>
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);
}
}
/// <summary>
/// Sends a region to the player.
/// <param name="region">The region.</param>
/// </summary>
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);
}
}
/// <summary>
/// Sends a region deletion to the player.
/// <param name="regionName">The region name.</param>
/// </summary>
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);
}
}
/// <summary>
/// Sends a warp to the player.
/// <param name="warp">The warp.</param>
/// </summary>
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);
}
}
/// <summary>
/// Sends a warp deletion to the player.
/// <param name="warpName">The warp name.</param>
/// </summary>
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);
}
}
/// <summary> /// <summary>
/// Adds a command callback to a specified command string. /// Adds a command callback to a specified command string.
/// </summary> /// </summary>
@ -877,6 +1196,24 @@ namespace TShockAPI
SetTime(false, 0); SetTime(false, 0);
} }
public void SetSnowMoon(bool snowMoon)
{
Main.snowMoon = snowMoon;
SetTime(false, 0);
}
public void SetPumpkinMoon(bool pumpkinMoon)
{
Main.pumpkinMoon = pumpkinMoon;
SetTime(false, 0);
}
public void SetEclipse(bool Eclipse)
{
Main.eclipse = Eclipse;
SetTime(true, 150);
}
public void SetTime(bool dayTime, double time) public void SetTime(bool dayTime, double time)
{ {
Main.dayTime = dayTime; Main.dayTime = dayTime;
@ -910,12 +1247,12 @@ namespace TShockAPI
NetMessage.SendData((int) PacketTypes.NpcStrike, -1, -1, "", npcid, damage, knockBack, hitDirection); NetMessage.SendData((int) PacketTypes.NpcStrike, -1, -1, "", npcid, damage, knockBack, hitDirection);
} }
public void RevertTiles(Dictionary<Vector2, TileData> tiles) public void RevertTiles(Dictionary<Vector2, Tile> tiles)
{ {
// Update Main.Tile first so that when tile sqaure is sent it is correct // Update Main.Tile first so that when tile sqaure is sent it is correct
foreach (KeyValuePair<Vector2, TileData> entry in tiles) foreach (KeyValuePair<Vector2, Tile> entry in tiles)
{ {
Main.tile[(int) entry.Key.X, (int) entry.Key.Y].Data = entry.Value; Main.tile[(int) entry.Key.X, (int) entry.Key.Y] = entry.Value;
} }
// Send all players updated tile sqaures // Send all players updated tile sqaures
foreach (Vector2 coords in tiles.Keys) foreach (Vector2 coords in tiles.Keys)
@ -928,9 +1265,14 @@ namespace TShockAPI
public class PlayerData public class PlayerData
{ {
public NetItem[] inventory = new NetItem[NetItem.maxNetInventory]; public NetItem[] inventory = new NetItem[NetItem.maxNetInventory];
public int health = 100;
public int maxHealth = 100; public int maxHealth = 100;
//public int maxMana = 100; public int mana = 20;
public int maxMana = 20;
public bool exists; public bool exists;
public int spawnX= -1;
public int spawnY= -1;
public PlayerData(TSPlayer player) public PlayerData(TSPlayer player)
{ {
@ -950,6 +1292,7 @@ namespace TShockAPI
this.inventory[2].stack = 1; this.inventory[2].stack = 1;
if (player.TPlayer.inventory[2] != null && player.TPlayer.inventory[2].netID == -16) if (player.TPlayer.inventory[2] != null && player.TPlayer.inventory[2].netID == -16)
this.inventory[2].prefix = player.TPlayer.inventory[2].prefix; this.inventory[2].prefix = player.TPlayer.inventory[2].prefix;
} }
public void StoreSlot(int slot, int netID, int prefix, int stack) public void StoreSlot(int slot, int netID, int prefix, int stack)
@ -972,14 +1315,28 @@ namespace TShockAPI
} }
} }
public void CopyInventory(TSPlayer player) public void CopyCharacter(TSPlayer player)
{ {
this.health = player.TPlayer.statLife > 0 ? player.TPlayer.statLife : 1;
this.maxHealth = player.TPlayer.statLifeMax; this.maxHealth = player.TPlayer.statLifeMax;
this.mana = player.TPlayer.statMana;
this.maxMana = player.TPlayer.statManaMax;
if (player.sX > 0 && player.sY > 0)
{
this.spawnX = player.sX;
this.spawnY = player.sY;
}
else
{
this.spawnX = player.TPlayer.SpawnX;
this.spawnY = player.TPlayer.SpawnY;
}
Item[] inventory = player.TPlayer.inventory; Item[] inventory = player.TPlayer.inventory;
Item[] armor = player.TPlayer.armor; Item[] armor = player.TPlayer.armor;
Item[] dye = player.TPlayer.dye;
for (int i = 0; i < NetItem.maxNetInventory; i++) for (int i = 0; i < NetItem.maxNetInventory; i++)
{ {
if (i < 49) if (i < NetItem.maxNetInventory - (NetItem.armorSlots + NetItem.dyeSlots))
{ {
if (player.TPlayer.inventory[i] != null) if (player.TPlayer.inventory[i] != null)
{ {
@ -1001,11 +1358,12 @@ namespace TShockAPI
this.inventory[i].prefix = 0; this.inventory[i].prefix = 0;
} }
} }
else else if (i < NetItem.maxNetInventory - NetItem.dyeSlots)
{ {
if (player.TPlayer.armor[i - 48] != null) var index = i - (NetItem.maxNetInventory - (NetItem.armorSlots + NetItem.dyeSlots));
if (player.TPlayer.armor[index] != null)
{ {
this.inventory[i].netID = armor[i - 48].netID; this.inventory[i].netID = armor[index].netID;
} }
else else
{ {
@ -1014,8 +1372,31 @@ namespace TShockAPI
if (this.inventory[i].netID != 0) if (this.inventory[i].netID != 0)
{ {
this.inventory[i].stack = armor[i - 48].stack; this.inventory[i].stack = armor[index].stack;
this.inventory[i].prefix = armor[i - 48].prefix; this.inventory[i].prefix = armor[index].prefix;
}
else
{
this.inventory[i].stack = 0;
this.inventory[i].prefix = 0;
}
}
else
{
var index = i - (NetItem.maxNetInventory - NetItem.dyeSlots);
if (player.TPlayer.dye[index] != null)
{
this.inventory[i].netID = dye[index].netID;
}
else
{
this.inventory[i].netID = 0;
}
if (this.inventory[i].netID != 0)
{
this.inventory[i].stack = dye[index].stack;
this.inventory[i].prefix = dye[index].prefix;
} }
else else
{ {
@ -1025,11 +1406,133 @@ namespace TShockAPI
} }
} }
} }
public void RestoreCharacter(TSPlayer player)
{
player.TPlayer.statLife = this.health;
player.TPlayer.statLifeMax = this.maxHealth;
player.TPlayer.statMana = this.maxMana;
player.TPlayer.statManaMax = this.maxMana;
player.TPlayer.SpawnX = this.spawnX;
player.TPlayer.SpawnY = this.spawnY;
player.sX = this.spawnX;
player.sY = this.spawnY;
for (int i = 0; i < NetItem.maxNetInventory; i++)
{
if (i < NetItem.maxNetInventory - (NetItem.armorSlots + NetItem.dyeSlots))
{
if (this.inventory[i] != null)
{
player.TPlayer.inventory[i].netDefaults(this.inventory[i].netID);
}
else
{
player.TPlayer.inventory[i].netDefaults(0);
}
if (player.TPlayer.inventory[i].netID != 0)
{
player.TPlayer.inventory[i].stack = this.inventory[i].stack;
player.TPlayer.inventory[i].prefix = (byte)this.inventory[i].prefix;
}
}
else if (i < NetItem.maxNetInventory - NetItem.dyeSlots)
{
var index = i - (NetItem.maxNetInventory - (NetItem.armorSlots + NetItem.dyeSlots));
if (this.inventory[i] != null)
{
player.TPlayer.armor[index].netDefaults(this.inventory[i].netID);
}
else
{
player.TPlayer.armor[index].netDefaults(0);
}
if (player.TPlayer.armor[index].netID != 0)
{
player.TPlayer.armor[index].stack = this.inventory[i].stack;
player.TPlayer.armor[index].prefix = (byte)this.inventory[i].prefix;
}
}
else
{
var index = i - (NetItem.maxNetInventory - NetItem.dyeSlots);
if (this.inventory[i] != null)
{
player.TPlayer.dye[index].netDefaults(this.inventory[i].netID);
}
else
{
player.TPlayer.dye[index].netDefaults(0);
}
if (player.TPlayer.dye[index].netID != 0)
{
player.TPlayer.dye[index].stack = this.inventory[i].stack;
player.TPlayer.dye[index].prefix = (byte)this.inventory[i].prefix;
}
}
}
for (int k = 0; k < 59; k++)
{
NetMessage.SendData(5, -1, -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, -1, -1, Main.player[player.Index].armor[0].name, player.Index, 59f, (float)Main.player[player.Index].armor[0].prefix, 0f, 0);
NetMessage.SendData(5, -1, -1, Main.player[player.Index].armor[1].name, player.Index, 60f, (float)Main.player[player.Index].armor[1].prefix, 0f, 0);
NetMessage.SendData(5, -1, -1, Main.player[player.Index].armor[2].name, player.Index, 61f, (float)Main.player[player.Index].armor[2].prefix, 0f, 0);
NetMessage.SendData(5, -1, -1, Main.player[player.Index].armor[3].name, player.Index, 62f, (float)Main.player[player.Index].armor[3].prefix, 0f, 0);
NetMessage.SendData(5, -1, -1, Main.player[player.Index].armor[4].name, player.Index, 63f, (float)Main.player[player.Index].armor[4].prefix, 0f, 0);
NetMessage.SendData(5, -1, -1, Main.player[player.Index].armor[5].name, player.Index, 64f, (float)Main.player[player.Index].armor[5].prefix, 0f, 0);
NetMessage.SendData(5, -1, -1, Main.player[player.Index].armor[6].name, player.Index, 65f, (float)Main.player[player.Index].armor[6].prefix, 0f, 0);
NetMessage.SendData(5, -1, -1, Main.player[player.Index].armor[7].name, player.Index, 66f, (float)Main.player[player.Index].armor[7].prefix, 0f, 0);
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(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);
for (int k = 0; k < 59; k++)
{
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(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++)
{
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);
}
} }
public class NetItem public class NetItem
{ {
public static int maxNetInventory = 59; public static readonly int maxNetInventory = 73;
public static readonly int armorSlots = 11;
public static readonly int dyeSlots = 3;
public int netID; public int netID;
public int stack; public int stack;
public int prefix; public int prefix;

883
TShockAPI/TShock.cs Normal file → Executable file

File diff suppressed because it is too large Load diff

View file

@ -38,6 +38,7 @@
<WarningLevel>4</WarningLevel> <WarningLevel>4</WarningLevel>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks> <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<DocumentationFile>bin\Debug\TShockAPI.XML</DocumentationFile> <DocumentationFile>bin\Debug\TShockAPI.XML</DocumentationFile>
<PlatformTarget>x86</PlatformTarget>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType> <DebugType>pdbonly</DebugType>
@ -48,6 +49,7 @@
<WarningLevel>4</WarningLevel> <WarningLevel>4</WarningLevel>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks> <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<DocumentationFile>bin\Release\TShockAPI.XML</DocumentationFile> <DocumentationFile>bin\Release\TShockAPI.XML</DocumentationFile>
<PlatformTarget>x86</PlatformTarget>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<Reference Include="HttpServer"> <Reference Include="HttpServer">
@ -66,11 +68,7 @@
</Reference> </Reference>
<Reference Include="System" /> <Reference Include="System" />
<Reference Include="System.Data" /> <Reference Include="System.Data" />
<Reference Include="TerrariaServer, Version=0.0.0.0, Culture=neutral, processorArchitecture=x86"> <Reference Include="System.Web" />
<SpecificVersion>False</SpecificVersion>
<ExecutableExtension>.exe</ExecutableExtension>
<HintPath>..\TerrariaServerBins\TerrariaServer.exe</HintPath>
</Reference>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="BackupManager.cs" /> <Compile Include="BackupManager.cs" />
@ -78,13 +76,11 @@
<Compile Include="Hooks\GeneralHooks.cs" /> <Compile Include="Hooks\GeneralHooks.cs" />
<Compile Include="Hooks\PlayerHooks.cs" /> <Compile Include="Hooks\PlayerHooks.cs" />
<Compile Include="PaginationTools.cs" /> <Compile Include="PaginationTools.cs" />
<Compile Include="PluginUpdater\PluginUpdaterThread.cs" /> <Compile Include="RaptorPacketTypes.cs" />
<Compile Include="PluginUpdater\PluginVersionCheck.cs" />
<Compile Include="PluginUpdater\VersionInfo.cs" />
<Compile Include="Rest\RestPermissions.cs" /> <Compile Include="Rest\RestPermissions.cs" />
<Compile Include="SaveManager.cs" /> <Compile Include="SaveManager.cs" />
<Compile Include="DB\BanManager.cs" /> <Compile Include="DB\BanManager.cs" />
<Compile Include="DB\InventoryManager.cs" /> <Compile Include="DB\CharacterManager.cs" />
<Compile Include="DB\IQueryBuilder.cs" /> <Compile Include="DB\IQueryBuilder.cs" />
<Compile Include="DB\ItemManager.cs" /> <Compile Include="DB\ItemManager.cs" />
<Compile Include="DB\SqlColumn.cs" /> <Compile Include="DB\SqlColumn.cs" />
@ -126,6 +122,7 @@
<Compile Include="Rest\RestObject.cs" /> <Compile Include="Rest\RestObject.cs" />
<Compile Include="Rest\RestVerbs.cs" /> <Compile Include="Rest\RestVerbs.cs" />
<Compile Include="Rest\SecureRest.cs" /> <Compile Include="Rest\SecureRest.cs" />
<Compile Include="StatTracker.cs" />
<Compile Include="Utils.cs" /> <Compile Include="Utils.cs" />
<Compile Include="TShock.cs" /> <Compile Include="TShock.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
@ -134,12 +131,8 @@
<Compile Include="DB\WarpsManager.cs" /> <Compile Include="DB\WarpsManager.cs" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Include="config\groups.txt" />
<None Include="TShockAPI.licenseheader" /> <None Include="TShockAPI.licenseheader" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<None Include="config\users.txt" />
</ItemGroup>
<ItemGroup> <ItemGroup>
<EmbeddedResource Include="Resources.resx"> <EmbeddedResource Include="Resources.resx">
<Generator>ResXFileCodeGenerator</Generator> <Generator>ResXFileCodeGenerator</Generator>
@ -170,9 +163,11 @@
</BootstrapperPackage> </BootstrapperPackage>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Content Include="config\itembans.txt" /> <ProjectReference Include="..\TerrariaServerAPI\TerrariaAPI-Server.csproj">
<Project>{549A7941-D9C9-4544-BAC8-D9EEEAB4D777}</Project>
<Name>TerrariaAPI-Server</Name>
</ProjectReference>
</ItemGroup> </ItemGroup>
<ItemGroup />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<PropertyGroup> <PropertyGroup>
<PreBuildEvent> <PreBuildEvent>

View file

@ -24,6 +24,7 @@ using System.Net;
using System.Net.Sockets; using System.Net.Sockets;
using System.Security.Cryptography; using System.Security.Cryptography;
using System.Text; using System.Text;
using System.Text.RegularExpressions;
using Terraria; using Terraria;
using TShockAPI.DB; using TShockAPI.DB;
@ -258,7 +259,7 @@ namespace TShockAPI
return found; return found;
byte plrID; byte plrID;
if (byte.TryParse(plr, out plrID)) if (byte.TryParse(plr, out plrID) && plrID < Main.maxPlayers)
{ {
TSPlayer player = TShock.Players[plrID]; TSPlayer player = TShock.Players[plrID];
if (player != null && player.Active) if (player != null && player.Active)
@ -307,11 +308,11 @@ namespace TShockAPI
tileX = startTileX + Random.Next(tileXRange*-1, tileXRange); tileX = startTileX + Random.Next(tileXRange*-1, tileXRange);
tileY = startTileY + Random.Next(tileYRange*-1, tileYRange); tileY = startTileY + Random.Next(tileYRange*-1, tileYRange);
j++; j++;
} while (TilePlacementValid(tileX, tileY) && !TileClear(tileX, tileY)); } while (TilePlacementValid(tileX, tileY) && TileSolid(tileX, tileY));
} }
/// <summary> /// <summary>
/// Determines if a tile is valid /// Determines if a tile is valid.
/// </summary> /// </summary>
/// <param name="tileX">Location X</param> /// <param name="tileX">Location X</param>
/// <param name="tileY">Location Y</param> /// <param name="tileY">Location Y</param>
@ -322,14 +323,16 @@ namespace TShockAPI
} }
/// <summary> /// <summary>
/// Checks to see if the tile is clear. /// Checks if the tile is solid.
/// </summary> /// </summary>
/// <param name="tileX">Location X</param> /// <param name="tileX">Location X</param>
/// <param name="tileY">Location Y</param> /// <param name="tileY">Location Y</param>
/// <returns>The state of the tile</returns> /// <returns>The tile's solidity.</returns>
private bool TileClear(int tileX, int tileY) public bool TileSolid(int tileX, int tileY)
{ {
return !Main.tile[tileX, tileY].active; return TilePlacementValid(tileX, tileY) && Main.tile[tileX, tileY] != null &&
Main.tile[tileX, tileY].active() && Main.tileSolid[Main.tile[tileX, tileY].type] &&
!Main.tile[tileX, tileY].inActive() && !Main.tile[tileX, tileY].halfBrick() && Main.tile[tileX, tileY].slope() == 0;
} }
/// <summary> /// <summary>
@ -371,7 +374,7 @@ namespace TShockAPI
var found = new List<Item>(); var found = new List<Item>();
Item item = new Item(); Item item = new Item();
string nameLower = name.ToLower(); string nameLower = name.ToLower();
for (int i = -24; i < Main.maxItemTypes; i++) for (int i = -48; i < Main.maxItemTypes; i++)
{ {
item.netDefaults(i); item.netDefaults(i);
if (item.name.ToLower() == nameLower) if (item.name.ToLower() == nameLower)
@ -571,10 +574,10 @@ namespace TShockAPI
/// <param name="reason">string reason (default: "Server shutting down!")</param> /// <param name="reason">string reason (default: "Server shutting down!")</param>
public void RestartServer(bool save = true, string reason = "Server shutting down!") public void RestartServer(bool save = true, string reason = "Server shutting down!")
{ {
if (TShock.Config.ServerSideInventory) if (TShock.Config.ServerSideCharacter)
foreach (TSPlayer player in TShock.Players) foreach (TSPlayer player in TShock.Players)
if (player != null && player.IsLoggedIn && !player.IgnoreActionsForClearingTrashCan) if (player != null && player.IsLoggedIn && !player.IgnoreActionsForClearingTrashCan)
TShock.InventoryDB.InsertPlayerData(player); TShock.CharacterDB.InsertPlayerData(player);
StopServer(true, reason); StopServer(true, reason);
System.Diagnostics.Process.Start(System.Reflection.Assembly.GetExecutingAssembly().GetName().CodeBase); System.Diagnostics.Process.Start(System.Reflection.Assembly.GetExecutingAssembly().GetName().CodeBase);
@ -589,7 +592,8 @@ namespace TShockAPI
FileTools.SetupConfig(); FileTools.SetupConfig();
TShock.HandleCommandLinePostConfigLoad(Environment.GetCommandLineArgs()); TShock.HandleCommandLinePostConfigLoad(Environment.GetCommandLineArgs());
TShock.Groups.LoadPermisions(); TShock.Groups.LoadPermisions();
TShock.Regions.ReloadAllRegions(); TShock.Regions.Reload();
TShock.Itembans.UpdateItemBans();
Hooks.GeneralHooks.OnReloadEvent(player); Hooks.GeneralHooks.OnReloadEvent(player);
} }
@ -636,16 +640,16 @@ namespace TShockAPI
string playerName = player.Name; string playerName = player.Name;
player.SilentKickInProgress = silent; player.SilentKickInProgress = silent;
if (player.IsLoggedIn && saveSSI) if (player.IsLoggedIn && saveSSI)
player.SaveServerInventory(); player.SaveServerCharacter();
player.Disconnect(string.Format("Kicked: {0}", reason)); player.Disconnect(string.Format("Kicked: {0}", reason));
Log.ConsoleInfo(string.Format("Kicked {0} for : {1}", playerName, reason)); Log.ConsoleInfo(string.Format("Kicked {0} for : '{1}'", playerName, reason));
string verb = force ? "force " : ""; string verb = force ? "force " : "";
if (!silent) if (!silent)
{ {
if (string.IsNullOrWhiteSpace(adminUserName)) if (string.IsNullOrWhiteSpace(adminUserName))
Broadcast(string.Format("{0} was {1}kicked for {2}", playerName, verb, reason.ToLower()), Color.Green); Broadcast(string.Format("{0} was {1}kicked for '{2}'", playerName, verb, reason.ToLower()), Color.Green);
else else
Broadcast(string.Format("{0} {1}kicked {2} for {3}", adminUserName, verb, playerName, reason.ToLower()), Color.Green); Broadcast(string.Format("{0} {1}kicked {2} for '{3}'", adminUserName, verb, playerName, reason.ToLower()), Color.Green);
} }
return true; return true;
} }
@ -673,15 +677,16 @@ namespace TShockAPI
if (force || !player.Group.HasPermission(Permissions.immunetoban)) if (force || !player.Group.HasPermission(Permissions.immunetoban))
{ {
string ip = player.IP; string ip = player.IP;
string uuid = player.UUID;
string playerName = player.Name; string playerName = player.Name;
TShock.Bans.AddBan(ip, playerName, reason, false, adminUserName); TShock.Bans.AddBan(ip, playerName, uuid, reason, false, adminUserName);
player.Disconnect(string.Format("Banned: {0}", reason)); player.Disconnect(string.Format("Banned: {0}", reason));
Log.ConsoleInfo(string.Format("Banned {0} for : {1}", playerName, reason)); Log.ConsoleInfo(string.Format("Banned {0} for : '{1}'", playerName, reason));
string verb = force ? "force " : ""; string verb = force ? "force " : "";
if (string.IsNullOrWhiteSpace(adminUserName)) if (string.IsNullOrWhiteSpace(adminUserName))
Broadcast(string.Format("{0} was {1}banned for {2}", playerName, verb, reason.ToLower())); Broadcast(string.Format("{0} was {1}banned for '{2}'", playerName, verb, reason.ToLower()));
else else
Broadcast(string.Format("{0} {1}banned {2} for {3}", adminUserName, verb, playerName, reason.ToLower())); Broadcast(string.Format("{0} {1}banned {2} for '{3}'", adminUserName, verb, playerName, reason.ToLower()));
return true; return true;
} }
return false; return false;
@ -693,7 +698,7 @@ namespace TShockAPI
bool expirationExists = DateTime.TryParse(ban.Expiration, out exp); bool expirationExists = DateTime.TryParse(ban.Expiration, out exp);
if (!string.IsNullOrWhiteSpace(ban.Expiration) && (expirationExists) && if (!string.IsNullOrWhiteSpace(ban.Expiration) && (expirationExists) &&
(DateTime.Now >= exp)) (DateTime.UtcNow >= exp))
{ {
if (byName) if (byName)
{ {
@ -713,7 +718,7 @@ namespace TShockAPI
/// <summary> /// <summary>
/// Shows a file to the user. /// Shows a file to the user.
/// </summary> /// </summary>
/// <param name="ply">int player</param> /// <param name="ply">TSPlayer player</param>
/// <param name="file">string filename reletave to savedir</param> /// <param name="file">string filename reletave to savedir</param>
public void ShowFileToUser(TSPlayer player, string file) public void ShowFileToUser(TSPlayer player, string file)
{ {
@ -722,31 +727,28 @@ namespace TShockAPI
{ {
while ((foo = tr.ReadLine()) != null) while ((foo = tr.ReadLine()) != null)
{ {
foo = foo.Replace("%map%", Main.worldName); if (string.IsNullOrWhiteSpace(foo))
foo = foo.Replace("%players%", GetPlayers());
//foo = SanitizeString(foo);
if (foo.Substring(0, 1) == "%" && foo.Substring(12, 1) == "%") //Look for a beginning color code.
{ {
string possibleColor = foo.Substring(0, 13);
foo = foo.Remove(0, 13);
float[] pC = {0, 0, 0};
possibleColor = possibleColor.Replace("%", "");
string[] pCc = possibleColor.Split(',');
if (pCc.Length == 3)
{
try
{
player.SendMessage(foo, (byte) Convert.ToInt32(pCc[0]), (byte) Convert.ToInt32(pCc[1]),
(byte) Convert.ToInt32(pCc[2]));
continue; continue;
} }
catch (Exception e)
foo = foo.Replace("%map%", Main.worldName);
foo = foo.Replace("%players%", GetPlayers());
Regex reg = new Regex("%\\s*(?<r>\\d{1,3})\\s*,\\s*(?<g>\\d{1,3})\\s*,\\s*(?<b>\\d{1,3})\\s*%");
var matches = reg.Matches(foo);
Color c = Color.White;
foreach (Match match in matches)
{ {
Log.Error(e.ToString()); byte r, g, b;
if (byte.TryParse(match.Groups["r"].Value, out r) &&
byte.TryParse(match.Groups["g"].Value, out g) &&
byte.TryParse(match.Groups["b"].Value, out b))
{
c = new Color(r, g, b);
} }
foo = foo.Remove(match.Index, match.Length);
} }
} player.SendMessage(foo, c);
player.SendMessage(foo);
} }
} }
} }
@ -787,6 +789,18 @@ namespace TShockAPI
return ""; return "";
} }
/// <summary>
/// Sends the player an error message stating that more than one match was found
/// appending a csv list of the matches.
/// </summary>
/// <param name="ply">Player to send the message to</param>
/// <param name="matches">An enumerable list with the matches</param>
public void SendMultipleMatchError(TSPlayer ply, IEnumerable<object> matches)
{
ply.SendErrorMessage("More than one match found: {0}", string.Join(",", matches));
ply.SendErrorMessage("Use \"my query\" for items with spaces");
}
/// <summary> /// <summary>
/// Default hashing algorithm. /// Default hashing algorithm.
/// </summary> /// </summary>
@ -866,6 +880,50 @@ namespace TShockAPI
return true; return true;
} }
/// <summary>
/// Attempts to parse a string as a timespan (_d_m_h_s).
/// </summary>
/// <param name="time">The time string.</param>
/// <param name="seconds">The seconds.</param>
/// <returns>Whether the string was parsed successfully.</returns>
public bool TryParseTime(string str, out int seconds)
{
seconds = 0;
var sb = new StringBuilder(3);
for (int i = 0; i < str.Length; i++)
{
if (char.IsDigit(str[i]) || (str[i] == '-' || str[i] == '+'))
sb.Append(str[i]);
else
{
int num;
if (!int.TryParse(sb.ToString(), out num))
return false;
sb.Clear();
switch (str[i])
{
case 's':
seconds += num;
break;
case 'm':
seconds += num * 60;
break;
case 'h':
seconds += num * 60 * 60;
break;
case 'd':
seconds += num * 60 * 60 * 24;
break;
default:
return false;
}
}
}
return true;
}
/// <summary> /// <summary>
/// Searches for a projectile by identity and owner /// Searches for a projectile by identity and owner
/// </summary> /// </summary>

View file

@ -1,53 +0,0 @@
#Format
#name parent permisson1 permission2 permissionN
#if there is no parent, put null instead
#groups inherit permissions from their parents
#put a ! before a permission to negate it
#Do not remove the group default
#Do not name a group SuperAdmin, that is hard-coded into the code, it grants total permissions
#ALWAYS DECLARE A GROUP'S PARENT BEFORE YOU DECLARE THE GROUP
#currently avaliable permissions:
#reservedslot - reserved slot for player
#canwater - allow players to use water
#canlava - allow players to use lava
#canspike - allow players to place spikes
#warp - allow players to use warps
#kick - kick users
#ban - ban players by name or ip
#unban - unban players by name or ip
#whitelist - add ip to whitelist
#maintenance - check for updates/turn off server
#causeevents - allow player to drop star/meteor and start invasion/bloodmoon
#spawnboss - allow player to spawn bosses
#spawnmob - allow player to spawn any npcs
#tp - allow player to teleport
#tphere - allow a player to teleport players to their position
#managewarp - allow player to add/delete warp locations
#managegroup - allow player to add/delete/modify groups
#manageitem - allow a player to add/delete item bans
#manageregion - allow a user to create/edit regions
#editspawn - allow player to enable/disable build protection
#cfg - allow player to view/change tshock configuration
#time - allow player to change time
#pvpfun - enable pvpfun commands
#logs - notify player when any command is executed
#kill - allow player to kill others
#butcher - allow player to kill all alive monsters
#item - allow player to spawn items
#heal - allow player to heal
#immunetokick - player can't be kick
#immunetoban - player can't be banned
#ignorecheatdetection - allow player to cheat (health/mana cheats)
#ignoregriefdetection - allow player to grief (use explosives, water, lava even if they dont have premission to)
#usebanneditem - allows player to use banned items
#manageusers - Grab player info
#whisper - allow player to whisper to other players
#adminchat - Colors and adds a prefix to the player's chats.
#canbuild - allow player to build (does not bypass other checks)
default null canwater canlava warp canbuild
vip default reservedslot
newadmin default kick editspawn reservedslot
admin newadmin ban unban whitelist causeevents spawnboss spawnmob managewarp time tp pvpfun kill logs immunetokick tphere
trustedadmin admin maintenance cfg butcher cheat immunetoban ignorecheatdetection ignoregriefdetection usebanneditem

View file

@ -1,2 +0,0 @@
#see https://github.com/TShock/TShock/wiki/Item-List for a list of item ids
#List each banned item ID below this, with each on a new line

View file

@ -1,4 +0,0 @@
#format
#ip group
#see groups.txt for a list of groups
#127.0.0.1 superadmin

1
TerrariaServerAPI Submodule

@ -0,0 +1 @@
Subproject commit 0ddd492aa03e5c97dddbc95b2e605fa2823804ab

View file

@ -54,7 +54,7 @@ namespace UnitTests
[TestMethod] [TestMethod]
public void AddBanTest() public void AddBanTest()
{ {
Assert.IsTrue(Bans.AddBan("127.0.0.1", "BanTest", "Ban Testing")); Assert.IsTrue(Bans.AddBan("127.0.0.1", "BanTest", "BanTest2", "Ban Testing"));
} }
[TestMethod] [TestMethod]
@ -62,6 +62,7 @@ namespace UnitTests
{ {
Assert.IsNotNull(Bans.GetBanByIp("127.0.0.1")); Assert.IsNotNull(Bans.GetBanByIp("127.0.0.1"));
Assert.IsNotNull(Bans.GetBanByName("BanTest")); Assert.IsNotNull(Bans.GetBanByName("BanTest"));
Assert.IsNotNull(Bans.GetBanByUUID("BanTest2"));
} }
} }
} }

111
create_release.py Normal file
View file

@ -0,0 +1,111 @@
# Hey there, this is used to compile TShock on the build server.
# Don't change it. Thanks!
import os
import shutil
import subprocess
import urllib2
import zipfile
cur_wd = os.getcwd()
release_dir = os.path.join(cur_wd, "releases")
terraria_bin_name = "TerrariaServer.exe"
sql_bins_names = ["Mono.Data.Sqlite.dll", "MySql.Data.dll", "MySql.Web.dll"]
sqlite_dep = "sqlite3.dll"
json_bin_name = "Newtonsoft.Json.dll"
http_bin_name = "HttpServer.dll"
tshock_bin_name = "TShockAPI.dll"
tshock_symbols = "TShockAPI.dll.mdb"
terraria_release_bin = os.path.join(cur_wd, "TerrariaServerAPI", "bin", "Release", terraria_bin_name)
terraria_debug_bin = os.path.join(cur_wd, "TerrariaServerAPI", "bin", "Debug", terraria_bin_name)
sql_dep = os.path.join(cur_wd, "SqlBins")
http_bin = os.path.join(cur_wd, "HttpBins", http_bin_name)
json_bin = os.path.join(cur_wd, "TShockAPI", json_bin_name)
release_bin = os.path.join(cur_wd, "TShockAPI", "bin", "Release", tshock_bin_name)
debug_folder = os.path.join(cur_wd, "TShockAPI", "bin", "Debug")
def create_release_folder():
os.mkdir(release_dir)
def copy_dependencies():
shutil.copy(http_bin, release_dir)
shutil.copy(json_bin, release_dir)
shutil.copy(os.path.join(sql_dep, sqlite_dep), release_dir)
for f in sql_bins_names:
shutil.copy(os.path.join(sql_dep, f), release_dir)
def copy_debug_files():
shutil.copy(terraria_debug_bin, release_dir)
shutil.copy(os.path.join(debug_folder, tshock_bin_name), release_dir)
shutil.copy(os.path.join(debug_folder, tshock_symbols), release_dir)
def copy_release_files():
shutil.copy(terraria_release_bin, release_dir)
shutil.copy(release_bin, release_dir)
shutil.copy(release_bin, release_dir)
def create_base_zip(name):
os.chdir(release_dir)
zip = zipfile.ZipFile(name, "w")
zip.write(terraria_bin_name)
zip.write(sqlite_dep)
zip.write(http_bin_name, os.path.join("ServerPlugins", http_bin_name))
zip.write(json_bin_name, os.path.join("ServerPlugins", json_bin_name))
for f in sql_bins_names:
zip.write(f, os.path.join("ServerPlugins", f))
return zip
def package_release():
copy_release_files()
zip = create_base_zip("tshock_release.zip")
zip.write(tshock_bin_name, os.path.join("ServerPlugins", tshock_bin_name))
zip.close()
os.remove(tshock_bin_name)
os.remove(terraria_bin_name)
os.chdir(cur_wd)
def package_debug():
copy_debug_files()
zip = create_base_zip("tshock_debug.zip")
zip.write(tshock_bin_name, os.path.join("ServerPlugins", tshock_bin_name))
zip.write(tshock_symbols, os.path.join("ServerPlugins", tshock_symbols))
zip.close()
os.remove(tshock_bin_name)
os.remove(tshock_symbols)
os.remove(terraria_bin_name)
os.chdir(cur_wd)
def delete_files():
os.chdir(release_dir)
for f in sql_bins_names:
os.remove(f)
os.remove(sqlite_dep)
os.remove(json_bin_name)
os.remove(http_bin_name)
os.chdir(cur_wd)
def update_terraria_source():
subprocess.check_call(['/usr/bin/git', 'submodule', 'init'])
subprocess.check_call(['/usr/bin/git', 'submodule', 'update'])
def build_software():
release_proc = subprocess.Popen(['/usr/local/bin/xbuild', './TShockAPI/TShockAPI.csproj', '/p:Configuration=Release'])
debug_proc = subprocess.Popen(['/usr/local/bin/xbuild', './TShockAPI/TShockAPI.csproj', '/p:Configuration=Debug'])
release_proc.wait()
debug_proc.wait()
if (release_proc.returncode != 0):
raise CalledProcessError(release_proc.returncode)
if (debug_proc.returncode != 0):
raise CalledProcessError(debug_proc.returncode)
if __name__ == '__main__':
create_release_folder()
update_terraria_source()
copy_dependencies()
build_software()
package_release()
package_debug()
delete_files()

View file

@ -42,6 +42,7 @@ An example configuration file is below.
"KickOnMediumcoreDeath": false, "KickOnMediumcoreDeath": false,
"BanOnMediumcoreDeath": false, "BanOnMediumcoreDeath": false,
"AutoSave": true, "AutoSave": true,
"AnnounceSave": true,
"MaximumLoginAttempts": 3, "MaximumLoginAttempts": 3,
"RconPassword": "", "RconPassword": "",
"RconPort": 7777, "RconPort": 7777,
@ -141,6 +142,11 @@ The following is the official documentation for the configuration file:
**Description:** Enable/Disable Terrarias built in auto save **Description:** Enable/Disable Terrarias built in auto save
**Default:** "True" **Default:** "True"
## AnnounceSave
**Type:** Boolean
**Description:** Enable/Disable save announcements
**Default:** "True"
## BackupInterval ## BackupInterval
**Type:** Int32 **Type:** Int32
**Description:** Backup frequency in minutes. So, a value of 60 = 60 minutes. Backups are stored in the \tshock\backups folder. **Description:** Backup frequency in minutes. So, a value of 60 = 60 minutes. Backups are stored in the \tshock\backups folder.