ReSharper code reformat to match naming conventions and stuff

This commit is contained in:
Lucas Nicodemus 2011-12-30 14:38:04 -07:00
parent 1147788154
commit c6abbfe4d2
45 changed files with 11639 additions and 11342 deletions

View file

@ -24,81 +24,79 @@ using Terraria;
namespace TShockAPI
{
public class BackupManager
{
public string BackupPath { get; set; }
public int Interval { get; set; }
public int KeepFor { get; set; }
public class BackupManager
{
public string BackupPath { get; set; }
public int Interval { get; set; }
public int KeepFor { get; set; }
DateTime lastbackup = DateTime.UtcNow;
public BackupManager(string path)
{
BackupPath = path;
}
private DateTime lastbackup = DateTime.UtcNow;
public bool IsBackupTime
{
get
{
return (Interval > 0) && ((DateTime.UtcNow - lastbackup).TotalMinutes >= Interval);
}
}
public BackupManager(string path)
{
BackupPath = path;
}
public void Backup()
{
lastbackup = DateTime.UtcNow;
ThreadPool.QueueUserWorkItem(DoBackup);
ThreadPool.QueueUserWorkItem(DeleteOld);
}
public bool IsBackupTime
{
get { return (Interval > 0) && ((DateTime.UtcNow - lastbackup).TotalMinutes >= Interval); }
}
void DoBackup(object o)
{
try
{
string worldname = Main.worldPathName;
string name = Path.GetFileName(worldname);
public void Backup()
{
lastbackup = DateTime.UtcNow;
ThreadPool.QueueUserWorkItem(DoBackup);
ThreadPool.QueueUserWorkItem(DeleteOld);
}
Main.worldPathName = Path.Combine(BackupPath, string.Format("{0}.{1:dd.MM.yy-HH.mm.ss}.bak", name, DateTime.UtcNow));
private void DoBackup(object o)
{
try
{
string worldname = Main.worldPathName;
string name = Path.GetFileName(worldname);
string worldpath = Path.GetDirectoryName(Main.worldPathName);
if (worldpath != null && !Directory.Exists(worldpath))
Directory.CreateDirectory(worldpath);
Main.worldPathName = Path.Combine(BackupPath, string.Format("{0}.{1:dd.MM.yy-HH.mm.ss}.bak", name, DateTime.UtcNow));
TShock.Utils.Broadcast("Server map saving, potential lag spike");
Console.WriteLine("Backing up world...");
string worldpath = Path.GetDirectoryName(Main.worldPathName);
if (worldpath != null && !Directory.Exists(worldpath))
Directory.CreateDirectory(worldpath);
Thread SaveWorld = new Thread(TShock.Utils.SaveWorld);
SaveWorld.Start();
TShock.Utils.Broadcast("Server map saving, potential lag spike");
Console.WriteLine("Backing up world...");
while (SaveWorld.ThreadState == ThreadState.Running)
Thread.Sleep(50);
Console.WriteLine("World backed up");
Console.ForegroundColor = ConsoleColor.Gray;
Log.Info(string.Format("World backed up ({0})", Main.worldPathName));
Thread SaveWorld = new Thread(TShock.Utils.SaveWorld);
SaveWorld.Start();
Main.worldPathName = worldname;
}
catch (Exception ex)
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine("Backup failed");
Console.ForegroundColor = ConsoleColor.Gray;
Log.Error("Backup failed");
Log.Error(ex.ToString());
}
}
while (SaveWorld.ThreadState == ThreadState.Running)
Thread.Sleep(50);
Console.WriteLine("World backed up");
Console.ForegroundColor = ConsoleColor.Gray;
Log.Info(string.Format("World backed up ({0})", Main.worldPathName));
void DeleteOld(object o)
{
if (KeepFor <= 0)
return;
foreach (var fi in new DirectoryInfo(BackupPath).GetFiles("*.bak"))
{
if ((DateTime.UtcNow - fi.LastWriteTimeUtc).TotalMinutes > KeepFor)
{
fi.Delete();
}
}
}
}
}
Main.worldPathName = worldname;
}
catch (Exception ex)
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine("Backup failed");
Console.ForegroundColor = ConsoleColor.Gray;
Log.Error("Backup failed");
Log.Error(ex.ToString());
}
}
private void DeleteOld(object o)
{
if (KeepFor <= 0)
return;
foreach (var fi in new DirectoryInfo(BackupPath).GetFiles("*.bak"))
{
if ((DateTime.UtcNow - fi.LastWriteTimeUtc).TotalMinutes > KeepFor)
{
fi.Delete();
}
}
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -24,274 +24,245 @@ using Newtonsoft.Json;
namespace TShockAPI
{
public class ConfigFile
{
[Description("The equation for calculating invasion size is 100 + (multiplier * (number of active players with greater than 200 health))")]
public int InvasionMultiplier = 1;
[Description("The default maximum mobs that will spawn per wave. Higher means more mobs in that wave.")]
public int DefaultMaximumSpawns = 5;
[Description("The delay between waves. Shorter values lead to less mobs.")]
public int DefaultSpawnRate = 600;
[Description("The port the server runs on.")]
public int ServerPort = 7777;
[Description("Enable or disable the whitelist based on IP addresses in whitelist.txt")]
public bool EnableWhitelist;
[Description("Enable the ability for invaison size to never decrease. Make sure to run /invade, and note that this adds 2 million+ goblins to the spawn que for the map.")]
public bool InfiniteInvasion;
[Description("Set the server pvp mode. Vaild types are, \"normal\", \"always\", \"disabled\"")]
public string PvPMode = "normal";
[Description("Prevents tiles from being placed within SpawnProtectionRadius of the default spawn.")]
public bool SpawnProtection = true;
[Description("Radius from spawn tile for SpawnProtection.")]
public int SpawnProtectionRadius = 10;
[Description("Max slots for the server. If you want people to be kicked with \"Server is full\" set this to how many players you want max and then set Terraria max players to 2 higher.")]
public int MaxSlots = 8;
[Description("Global protection agent for any block distance based anti-grief check.")]
public bool RangeChecks = true;
[Description("Disables any building; placing of blocks")]
public bool DisableBuild;
[Description("#.#.#. = Red/Blue/Green - RGB Colors for the Admin Chat Color. Max value: 255")]
public float[] SuperAdminChatRGB = { 255, 0, 0 };
[Description("Super admin group chat prefix")]
public string SuperAdminChatPrefix = "(Admin) ";
[Description("Super admin group chat suffix")]
public string SuperAdminChatSuffix = "";
[Description("Backup frequency in minutes. So, a value of 60 = 60 minutes. Backups are stored in the \\tshock\\backups folder.")]
public int BackupInterval;
[Description("How long backups are kept in minutes. 2880 = 2 days.")]
public int BackupKeepFor = 60;
public class ConfigFile
{
[Description(
"The equation for calculating invasion size is 100 + (multiplier * (number of active players with greater than 200 health))"
)] public int InvasionMultiplier = 1;
[Description("Remembers where a player left off. It works by remembering the IP, NOT the character. \neg. When you try to disconnect, and reconnect to be automatically placed at spawn, you'll be at your last location. Note: Won't save after server restarts.")]
public bool RememberLeavePos;
[Description("Hardcore players ONLY. This means softcore players cannot join.")]
public bool HardcoreOnly;
[Description("Mediumcore players ONLY. This means softcore players cannot join.")]
public bool MediumcoreOnly;
[Description("Kicks a Hardcore player on death.")]
public bool KickOnMediumcoreDeath;
[Description("Bans a Hardcore player on death.")]
public bool BanOnMediumcoreDeath;
[Description("The default maximum mobs that will spawn per wave. Higher means more mobs in that wave.")] public int
DefaultMaximumSpawns = 5;
[Description("Enable/Disable Terrarias built in auto save")]
public bool AutoSave = true;
[Description("The delay between waves. Shorter values lead to less mobs.")] public int DefaultSpawnRate = 600;
[Description("The port the server runs on.")] public int ServerPort = 7777;
[Description("Enable or disable the whitelist based on IP addresses in whitelist.txt")] public bool EnableWhitelist;
[Description("Number of failed login attempts before kicking the player.")]
public int MaximumLoginAttempts = 3;
[Description(
"Enable the ability for invaison size to never decrease. Make sure to run /invade, and note that this adds 2 million+ goblins to the spawn que for the map."
)] public bool InfiniteInvasion;
[Description("Not implemented")]
public string RconPassword = "";
[Description("Not implemented")]
public int RconPort = 7777;
[Description("Set the server pvp mode. Vaild types are, \"normal\", \"always\", \"disabled\"")] public string PvPMode
= "normal";
[Description("Not implemented")]
public string ServerName = "";
[Description("Not implemented")]
public string MasterServer = "127.0.0.1";
[Description("Prevents tiles from being placed within SpawnProtectionRadius of the default spawn.")] public bool
SpawnProtection = true;
[Description("Valid types are \"sqlite\" and \"mysql\"")]
public string StorageType = "sqlite";
[Description("Radius from spawn tile for SpawnProtection.")] public int SpawnProtectionRadius = 10;
[Description("The MySQL Hostname and port to direct connections to")]
public string MySqlHost = "localhost:3306";
[Description("Database name to connect to")]
public string MySqlDbName = "";
[Description("Database username to connect with")]
public string MySqlUsername = "";
[Description("Database password to connect with")]
public string MySqlPassword = "";
[Description(
"Max slots for the server. If you want people to be kicked with \"Server is full\" set this to how many players you want max and then set Terraria max players to 2 higher."
)] public int MaxSlots = 8;
[Description("Bans a Mediumcore player on death.")]
public string MediumcoreBanReason = "Death results in a ban";
[Description("Kicks a Mediumcore player on death.")]
public string MediumcoreKickReason = "Death results in a kick";
[Description("Global protection agent for any block distance based anti-grief check.")] public bool RangeChecks = true;
[Description("Disables any building; placing of blocks")] public bool DisableBuild;
[Description("Enables DNS resolution of incoming connections with GetGroupForIPExpensive.")]
public bool EnableDNSHostResolution;
[Description("#.#.#. = Red/Blue/Green - RGB Colors for the Admin Chat Color. Max value: 255")] public float[]
SuperAdminChatRGB = {255, 0, 0};
[Description("Enables kicking of banned users by matching their IP Address")]
public bool EnableIPBans = true;
[Description("Super admin group chat prefix")] public string SuperAdminChatPrefix = "(Admin) ";
[Description("Super admin group chat suffix")] public string SuperAdminChatSuffix = "";
[Description("Enables kicking of banned users by matching their Character Name")]
public bool EnableBanOnUsernames;
[Description(
"Backup frequency in minutes. So, a value of 60 = 60 minutes. Backups are stored in the \\tshock\\backups folder.")] public int BackupInterval;
[Description("Drops excessive sync packets")]
public bool EnableAntiLag = true;
[Description("Selects the default group name to place new registrants under")]
public string DefaultRegistrationGroupName = "default";
[Description("How long backups are kept in minutes. 2880 = 2 days.")] public int BackupKeepFor = 60;
[Description("Selects the default group name to place non registered users under")]
public string DefaultGuestGroupName = "guest";
[Description(
"Remembers where a player left off. It works by remembering the IP, NOT the character. \neg. When you try to disconnect, and reconnect to be automatically placed at spawn, you'll be at your last location. Note: Won't save after server restarts."
)] public bool RememberLeavePos;
[Description("Force-Disable printing logs to players with the log permission")]
public bool DisableSpewLogs = true;
[Description("Hardcore players ONLY. This means softcore players cannot join.")] public bool HardcoreOnly;
[Description("Mediumcore players ONLY. This means softcore players cannot join.")] public bool MediumcoreOnly;
[Description("Kicks a Hardcore player on death.")] public bool KickOnMediumcoreDeath;
[Description("Bans a Hardcore player on death.")] public bool BanOnMediumcoreDeath;
[Description("Valid types are \"sha512\", \"sha256\", \"md5\", append with \"-xp\" for the xp supported algorithms")]
public string HashAlgorithm = "sha512";
[Description("Enable/Disable Terrarias built in auto save")] public bool AutoSave = true;
[Description("Buffers up the packets and sends them out at the end of each frame")]
public bool BufferPackets = true;
[Description("Number of failed login attempts before kicking the player.")] public int MaximumLoginAttempts = 3;
[Description("String that is used when kicking people when the server is full.")]
public string ServerFullReason = "Server is full";
[Description("Not implemented")] public string RconPassword = "";
[Description("Not implemented")] public int RconPort = 7777;
[Description("String that is used when kicking people when the server is full with no reserved slots.")]
public string ServerFullNoReservedReason = "Server is full. No reserved slots open.";
[Description("Not implemented")] public string ServerName = "";
[Description("Not implemented")] public string MasterServer = "127.0.0.1";
[Description("This will save the world if Terraria crashes from an unhandled exception.")]
public bool SaveWorldOnCrash = true;
[Description("Valid types are \"sqlite\" and \"mysql\"")] public string StorageType = "sqlite";
[Description("This will announce a player's location on join")]
public bool EnableGeoIP;
[Description("The MySQL Hostname and port to direct connections to")] public string MySqlHost = "localhost:3306";
[Description("Database name to connect to")] public string MySqlDbName = "";
[Description("Database username to connect with")] public string MySqlUsername = "";
[Description("Database password to connect with")] public string MySqlPassword = "";
[Description("This will turn on a token requirement for the /status API endpoint.")]
public bool EnableTokenEndpointAuthentication;
[Description("Bans a Mediumcore player on death.")] public string MediumcoreBanReason = "Death results in a ban";
[Description("Kicks a Mediumcore player on death.")] public string MediumcoreKickReason = "Death results in a kick";
[Description("This is used when the API endpoint /status is queried.")]
public string ServerNickname = "TShock Server";
[Description("Enables DNS resolution of incoming connections with GetGroupForIPExpensive.")] public bool
EnableDNSHostResolution;
[Description("Enable/Disable the rest api.")]
public bool RestApiEnabled;
[Description("Enables kicking of banned users by matching their IP Address")] public bool EnableIPBans = true;
[Description("This is the port which the rest api will listen on.")]
public int RestApiPort = 7878;
[Description("Enables kicking of banned users by matching their Character Name")] public bool EnableBanOnUsernames;
[Description("Disable tombstones for all players.")]
public bool DisableTombstones = true;
[Description("Drops excessive sync packets")] public bool EnableAntiLag = true;
[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 asthetic tiles.")]
public bool EnableInsecureTileFixes = true;
[Description("Selects the default group name to place new registrants under")] public string
DefaultRegistrationGroupName = "default";
[Description("Kicks users using a proxy as identified with the GeoIP database")]
public bool KickProxyUsers = true;
[Description("Selects the default group name to place non registered users under")] public string
DefaultGuestGroupName = "guest";
[Description("Disables hardmode, can't never be activated. Overrides /starthardmode")]
public bool DisableHardmode;
[Description("Force-Disable printing logs to players with the log permission")] public bool DisableSpewLogs = true;
[Description("Disables Dungeon Guardian from being spawned by player packets, this will instead force a respawn")]
public bool DisableDungeonGuardian;
[Description("Valid types are \"sha512\", \"sha256\", \"md5\", append with \"-xp\" for the xp supported algorithms")] public string HashAlgorithm = "sha512";
[Description("Enable Server Side Inventory checks, EXPERIMENTAL")]
public bool ServerSideInventory;
[Description("Buffers up the packets and sends them out at the end of each frame")] public bool BufferPackets = true;
[Description("Disables reporting of playercount to the stat system.")]
public bool DisablePlayerCountReporting;
[Description("String that is used when kicking people when the server is full.")] public string ServerFullReason =
"Server is full";
[Description("Disables clown bomb projectiles from spawning")]
public bool DisableClownBombs;
[Description("String that is used when kicking people when the server is full with no reserved slots.")] public string
ServerFullNoReservedReason = "Server is full. No reserved slots open.";
[Description("Disables snow ball projectiles from spawning")]
public bool DisableSnowBalls;
[Description("This will save the world if Terraria crashes from an unhandled exception.")] public bool
SaveWorldOnCrash = true;
[Description("Change 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}";
[Description("This will announce a player's location on join")] public bool EnableGeoIP;
[Description("Force the world time to be normal, day, or night")]
public string ForceTime = "normal";
[Description("This will turn on a token requirement for the /status API endpoint.")] public bool
EnableTokenEndpointAuthentication;
[Description("Disable/Revert a player if they exceed this number of tile kills within 1 second.")]
public int TileKillThreshold = 60;
[Description("This is used when the API endpoint /status is queried.")] public string ServerNickname = "TShock Server";
[Description("Disable/Revert a player if they exceed this number of tile places within 1 second.")]
public int TilePlaceThreshold = 20;
[Description("Enable/Disable the rest api.")] public bool RestApiEnabled;
[Description("Disable a player if they exceed this number of liquid sets within 1 second.")]
public int TileLiquidThreshold = 15;
[Description("This is the port which the rest api will listen on.")] public int RestApiPort = 7878;
[Description("Disable a player if they exceed this number of projectile new within 1 second.")]
public int ProjectileThreshold = 50;
[Description("Disable tombstones for all players.")] public bool DisableTombstones = true;
[Description("Require all players to register or login before being allowed to play.")]
public bool RequireLogin;
[Description("Displays a player's IP on join to everyone who has the log permission")] public bool DisplayIPToAdmins;
[Description("Disables Invisibility potions from being used in PvP (Note, they can use them on the client, but the effect isn't sent to the rest of the server)")]
public bool DisableInvisPvP;
[Description(
"Some tiles are 'fixed' by not letting TShock handle them. Disabling this may break certain asthetic tiles.")] public
bool EnableInsecureTileFixes = true;
[Description("The maximum distance players disabled for various reasons can move from")]
public int MaxRangeForDisabled = 10;
[Description("Kicks users using a proxy as identified with the GeoIP database")] public bool KickProxyUsers = true;
[Description("Server password required to join server")]
public string ServerPassword = "";
[Description("Disables hardmode, can't never be activated. Overrides /starthardmode")] public bool DisableHardmode;
[Description("Protect chests with region and build permissions")]
public bool RegionProtectChests;
[Description("Disables Dungeon Guardian from being spawned by player packets, this will instead force a respawn")] public bool DisableDungeonGuardian;
[Description("Disable users from being able to login with account password when joining")]
public bool DisableLoginBeforeJoin;
[Description("Enable Server Side Inventory checks, EXPERIMENTAL")] public bool ServerSideInventory;
[Description("Disables reporting of playercount to the stat system.")] public bool DisablePlayerCountReporting;
[Description("Disables clown bomb projectiles from spawning")] public bool DisableClownBombs;
[Description("Disables snow ball projectiles from spawning")] public bool DisableSnowBalls;
[Description(
"Change 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}";
[Description("Force the world time to be normal, day, or night")] public string ForceTime = "normal";
[Description("Disable/Revert a player if they exceed this number of tile kills within 1 second.")] public int
TileKillThreshold = 60;
[Description("Disable/Revert a player if they exceed this number of tile places within 1 second.")] public int
TilePlaceThreshold = 20;
[Description("Disable a player if they exceed this number of liquid sets within 1 second.")] public int
TileLiquidThreshold = 15;
[Description("Disable a player if they exceed this number of projectile new within 1 second.")] public int
ProjectileThreshold = 50;
[Description("Require all players to register or login before being allowed to play.")] public bool RequireLogin;
[Description(
"Disables Invisibility potions from being used in PvP (Note, they can use them on the client, but the effect isn't sent to the rest of the server)"
)] public bool DisableInvisPvP;
[Description("The maximum distance players disabled for various reasons can move from")] public int
MaxRangeForDisabled = 10;
[Description("Server password required to join server")] public string ServerPassword = "";
[Description("Protect chests with region and build permissions")] public bool RegionProtectChests;
[Description("Disable users from being able to login with account password when joining")] public bool
DisableLoginBeforeJoin;
[Description("Allows users to register any username with /register")] public bool AllowRegisterAnyUsername;
[Description("Allows users to register any username with /register")]
public bool AllowRegisterAnyUsername;
public static ConfigFile Read(string path)
{
if (!File.Exists(path))
return new ConfigFile();
using (var fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read))
{
return Read(fs);
}
}
{
if (!File.Exists(path))
return new ConfigFile();
using (var fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read))
{
return Read(fs);
}
}
public static ConfigFile Read(Stream stream)
{
using (var sr = new StreamReader(stream))
{
var cf = JsonConvert.DeserializeObject<ConfigFile>(sr.ReadToEnd());
if (ConfigRead != null)
ConfigRead(cf);
return cf;
}
}
public static ConfigFile Read(Stream stream)
{
using (var sr = new StreamReader(stream))
{
var cf = JsonConvert.DeserializeObject<ConfigFile>(sr.ReadToEnd());
if (ConfigRead != null)
ConfigRead(cf);
return cf;
}
}
public void Write(string path)
{
using (var fs = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.Write))
{
Write(fs);
}
}
public void Write(string path)
{
using (var fs = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.Write))
{
Write(fs);
}
}
public void Write(Stream stream)
{
var str = JsonConvert.SerializeObject(this, Formatting.Indented);
using (var sw = new StreamWriter(stream))
{
sw.Write(str);
}
}
public void Write(Stream stream)
{
var str = JsonConvert.SerializeObject(this, Formatting.Indented);
using (var sw = new StreamWriter(stream))
{
sw.Write(str);
}
}
public static Action<ConfigFile> ConfigRead;
public static Action<ConfigFile> ConfigRead;
static void DumpDescriptions()
{
var sb = new StringBuilder();
var defaults = new ConfigFile();
private static void DumpDescriptions()
{
var sb = new StringBuilder();
var defaults = new ConfigFile();
foreach (var field in defaults.GetType().GetFields())
{
if (field.IsStatic)
continue;
foreach (var field in defaults.GetType().GetFields())
{
if (field.IsStatic)
continue;
var name = field.Name;
var type = field.FieldType.Name;
var name = field.Name;
var type = field.FieldType.Name;
var descattr = field.GetCustomAttributes(false).FirstOrDefault(o => o is DescriptionAttribute) as DescriptionAttribute;
var desc = descattr != null && !string.IsNullOrWhiteSpace(descattr.Description) ? descattr.Description : "None";
var descattr =
field.GetCustomAttributes(false).FirstOrDefault(o => o is DescriptionAttribute) as DescriptionAttribute;
var desc = descattr != null && !string.IsNullOrWhiteSpace(descattr.Description) ? descattr.Description : "None";
var def = field.GetValue(defaults);
var def = field.GetValue(defaults);
sb.AppendLine("## {0} ".SFormat(name));
sb.AppendLine("**Type:** {0} ".SFormat(type));
sb.AppendLine("**Description:** {0} ".SFormat(desc));
sb.AppendLine("**Default:** \"{0}\" ".SFormat(def));
sb.AppendLine();
}
sb.AppendLine("## {0} ".SFormat(name));
sb.AppendLine("**Type:** {0} ".SFormat(type));
sb.AppendLine("**Description:** {0} ".SFormat(desc));
sb.AppendLine("**Default:** \"{0}\" ".SFormat(def));
sb.AppendLine();
}
File.WriteAllText("ConfigDescriptions.txt", sb.ToString());
}
}
File.WriteAllText("ConfigDescriptions.txt", sb.ToString());
}
}
}

View file

@ -23,150 +23,153 @@ using MySql.Data.MySqlClient;
namespace TShockAPI.DB
{
public class BanManager
{
private IDbConnection database;
public class BanManager
{
private IDbConnection database;
public BanManager(IDbConnection db)
{
database = db;
public BanManager(IDbConnection db)
{
database = db;
var table = new SqlTable("Bans",
new SqlColumn("IP", MySqlDbType.String, 16) { Primary = true },
new SqlColumn("Name", MySqlDbType.Text),
new SqlColumn("Reason", MySqlDbType.Text)
);
var creator = new SqlTableCreator(db, db.GetSqlType() == SqlType.Sqlite ? (IQueryBuilder)new SqliteQueryCreator() : new MysqlQueryCreator());
creator.EnsureExists(table);
var table = new SqlTable("Bans",
new SqlColumn("IP", MySqlDbType.String, 16) {Primary = true},
new SqlColumn("Name", MySqlDbType.Text),
new SqlColumn("Reason", MySqlDbType.Text)
);
var creator = new SqlTableCreator(db,
db.GetSqlType() == SqlType.Sqlite
? (IQueryBuilder) new SqliteQueryCreator()
: new MysqlQueryCreator());
creator.EnsureExists(table);
String file = Path.Combine(TShock.SavePath, "bans.txt");
if (File.Exists(file))
{
using (StreamReader sr = new StreamReader(file))
{
String line;
while ((line = sr.ReadLine()) != null)
{
String[] info = line.Split('|');
string query;
if (TShock.Config.StorageType.ToLower() == "sqlite")
query = "INSERT OR IGNORE INTO Bans (IP, Name, Reason) VALUES (@0, @1, @2);";
else
query = "INSERT IGNORE INTO Bans SET IP=@0, Name=@1, Reason=@2;";
db.Query(query, info[0].Trim(), info[1].Trim(), info[2].Trim());
}
}
String path = Path.Combine(TShock.SavePath, "old_configs");
String file2 = Path.Combine(path, "bans.txt");
if (!Directory.Exists(path))
Directory.CreateDirectory(path);
if (File.Exists(file2))
File.Delete(file2);
File.Move(file, file2);
}
}
String file = Path.Combine(TShock.SavePath, "bans.txt");
if (File.Exists(file))
{
using (StreamReader sr = new StreamReader(file))
{
String line;
while ((line = sr.ReadLine()) != null)
{
String[] info = line.Split('|');
string query;
if (TShock.Config.StorageType.ToLower() == "sqlite")
query = "INSERT OR IGNORE INTO Bans (IP, Name, Reason) VALUES (@0, @1, @2);";
else
query = "INSERT IGNORE INTO Bans SET IP=@0, Name=@1, Reason=@2;";
db.Query(query, info[0].Trim(), info[1].Trim(), info[2].Trim());
}
}
String path = Path.Combine(TShock.SavePath, "old_configs");
String file2 = Path.Combine(path, "bans.txt");
if (!Directory.Exists(path))
Directory.CreateDirectory(path);
if (File.Exists(file2))
File.Delete(file2);
File.Move(file, file2);
}
}
public Ban GetBanByIp(string ip)
{
try
{
using (var reader = database.QueryReader("SELECT * FROM Bans WHERE IP=@0", ip))
{
if (reader.Read())
return new Ban(reader.Get<string>("IP"), reader.Get<string>("Name"), reader.Get<string>("Reason"));
}
}
catch (Exception ex)
{
Log.Error(ex.ToString());
}
return null;
}
public Ban GetBanByIp(string ip)
{
try
{
using (var reader = database.QueryReader("SELECT * FROM Bans WHERE IP=@0", ip))
{
if (reader.Read())
return new Ban(reader.Get<string>("IP"), reader.Get<string>("Name"), reader.Get<string>("Reason"));
}
}
catch (Exception ex)
{
Log.Error(ex.ToString());
}
return null;
}
public Ban GetBanByName(string name, bool casesensitive = true)
{
if (!TShock.Config.EnableBanOnUsernames)
{
return null;
}
try
{
var namecol = casesensitive ? "Name" : "UPPER(Name)";
if (!casesensitive)
name = name.ToUpper();
using (var reader = database.QueryReader("SELECT * FROM Bans WHERE " + namecol + "=@0", name))
{
if (reader.Read())
return new Ban(reader.Get<string>("IP"), reader.Get<string>("Name"), reader.Get<string>("Reason"));
public Ban GetBanByName(string name, bool casesensitive = true)
{
if (!TShock.Config.EnableBanOnUsernames)
{
return null;
}
try
{
var namecol = casesensitive ? "Name" : "UPPER(Name)";
if (!casesensitive)
name = name.ToUpper();
using (var reader = database.QueryReader("SELECT * FROM Bans WHERE " + namecol + "=@0", name))
{
if (reader.Read())
return new Ban(reader.Get<string>("IP"), reader.Get<string>("Name"), reader.Get<string>("Reason"));
}
}
catch (Exception ex)
{
Log.Error(ex.ToString());
}
return null;
}
}
}
catch (Exception ex)
{
Log.Error(ex.ToString());
}
return null;
}
public bool AddBan(string ip, string name = "", string reason = "")
{
try
{
return database.Query("INSERT INTO Bans (IP, Name, Reason) VALUES (@0, @1, @2);", ip, name, reason) != 0;
}
catch (Exception ex)
{
Log.Error(ex.ToString());
}
return false;
}
public bool AddBan(string ip, string name = "", string reason = "")
{
try
{
return database.Query("INSERT INTO Bans (IP, Name, Reason) VALUES (@0, @1, @2);", ip, name, reason) != 0;
}
catch (Exception ex)
{
Log.Error(ex.ToString());
}
return false;
}
public bool RemoveBan(string ip)
{
try
{
return database.Query("DELETE FROM Bans WHERE IP=@0", ip) != 0;
}
catch (Exception ex)
{
Log.Error(ex.ToString());
}
return false;
}
public bool RemoveBan(string ip)
{
try
{
return database.Query("DELETE FROM Bans WHERE IP=@0", ip) != 0;
}
catch (Exception ex)
{
Log.Error(ex.ToString());
}
return false;
}
public bool ClearBans()
{
try
{
return database.Query("DELETE FROM Bans") != 0;
}
catch (Exception ex)
{
Log.Error(ex.ToString());
}
return false;
}
}
public bool ClearBans()
{
try
{
return database.Query("DELETE FROM Bans") != 0;
}
catch (Exception ex)
{
Log.Error(ex.ToString());
}
return false;
}
}
public class Ban
{
public string IP { get; set; }
public class Ban
{
public string IP { get; set; }
public string Name { get; set; }
public string Name { get; set; }
public string Reason { get; set; }
public string Reason { get; set; }
public Ban(string ip, string name, string reason)
{
IP = ip;
Name = name;
Reason = reason;
}
public Ban(string ip, string name, string reason)
{
IP = ip;
Name = name;
Reason = reason;
}
public Ban()
{
IP = string.Empty;
Name = string.Empty;
Reason = string.Empty;
}
}
public Ban()
{
IP = string.Empty;
Name = string.Empty;
Reason = string.Empty;
}
}
}

View file

@ -7,254 +7,258 @@ using MySql.Data.MySqlClient;
namespace TShockAPI.DB
{
public class GroupManager
{
private IDbConnection database;
public class GroupManager
{
private IDbConnection database;
public List<Group> groups = new List<Group>();
public List<Group> groups = new List<Group>();
public GroupManager(IDbConnection db)
{
database = db;
public GroupManager(IDbConnection db)
{
database = db;
var table = new SqlTable("GroupList",
new SqlColumn("GroupName", MySqlDbType.VarChar, 32) { Primary = true },
new SqlColumn("Parent", MySqlDbType.VarChar, 32),
new SqlColumn("Commands", MySqlDbType.Text),
new SqlColumn("ChatColor", MySqlDbType.Text),
new SqlColumn("Prefix", MySqlDbType.Text),
new SqlColumn("Suffix", MySqlDbType.Text)
);
var creator = new SqlTableCreator(db, db.GetSqlType() == SqlType.Sqlite ? (IQueryBuilder)new SqliteQueryCreator() : new MysqlQueryCreator());
creator.EnsureExists(table);
var table = new SqlTable("GroupList",
new SqlColumn("GroupName", MySqlDbType.VarChar, 32) {Primary = true},
new SqlColumn("Parent", MySqlDbType.VarChar, 32),
new SqlColumn("Commands", MySqlDbType.Text),
new SqlColumn("ChatColor", MySqlDbType.Text),
new SqlColumn("Prefix", MySqlDbType.Text),
new SqlColumn("Suffix", MySqlDbType.Text)
);
var creator = new SqlTableCreator(db,
db.GetSqlType() == SqlType.Sqlite
? (IQueryBuilder) new SqliteQueryCreator()
: new MysqlQueryCreator());
creator.EnsureExists(table);
//Add default groups
AddGroup("guest", "canbuild,canregister,canlogin,canpartychat,cantalkinthird");
AddGroup("default", "guest", "warp,canchangepassword");
AddGroup("newadmin", "default", "kick,editspawn,reservedslot");
AddGroup("admin", "newadmin", "ban,unban,whitelist,causeevents,spawnboss,spawnmob,managewarp,time,tp,pvpfun,kill,logs,immunetokick,tphere");
AddGroup("trustedadmin", "admin", "maintenance,cfg,butcher,item,heal,immunetoban,usebanneditem,manageusers");
AddGroup("vip", "default", "reservedslot");
//Add default groups
AddGroup("guest", "canbuild,canregister,canlogin,canpartychat,cantalkinthird");
AddGroup("default", "guest", "warp,canchangepassword");
AddGroup("newadmin", "default", "kick,editspawn,reservedslot");
AddGroup("admin", "newadmin",
"ban,unban,whitelist,causeevents,spawnboss,spawnmob,managewarp,time,tp,pvpfun,kill,logs,immunetokick,tphere");
AddGroup("trustedadmin", "admin", "maintenance,cfg,butcher,item,heal,immunetoban,usebanneditem,manageusers");
AddGroup("vip", "default", "reservedslot");
String file = Path.Combine(TShock.SavePath, "groups.txt");
if (File.Exists(file))
{
using (StreamReader sr = new StreamReader(file))
{
String line;
while ((line = sr.ReadLine()) != null)
{
if (!line.Equals("") && !line.Substring(0, 1).Equals("#"))
{
String[] info = line.Split(' ');
String comms = "";
int size = info.Length;
for (int i = 1; i < size; i++)
{
if (!comms.Equals(""))
comms = comms + ",";
comms = comms + info[i].Trim();
}
String file = Path.Combine(TShock.SavePath, "groups.txt");
if (File.Exists(file))
{
using (StreamReader sr = new StreamReader(file))
{
String line;
while ((line = sr.ReadLine()) != null)
{
if (!line.Equals("") && !line.Substring(0, 1).Equals("#"))
{
String[] info = line.Split(' ');
String comms = "";
int size = info.Length;
for (int i = 1; i < size; i++)
{
if (!comms.Equals(""))
comms = comms + ",";
comms = comms + info[i].Trim();
}
string query = "";
if (TShock.Config.StorageType.ToLower() == "sqlite")
query = "INSERT OR IGNORE INTO GroupList (GroupName, Commands) VALUES (@0, @1);";
else if (TShock.Config.StorageType.ToLower() == "mysql")
query = "INSERT IGNORE INTO GroupList SET GroupName=@0, Commands=@1;";
string query = "";
if (TShock.Config.StorageType.ToLower() == "sqlite")
query = "INSERT OR IGNORE INTO GroupList (GroupName, Commands) VALUES (@0, @1);";
else if (TShock.Config.StorageType.ToLower() == "mysql")
query = "INSERT IGNORE INTO GroupList SET GroupName=@0, Commands=@1;";
db.Query(query, info[0].Trim(), comms);
}
}
}
String path = Path.Combine(TShock.SavePath, "old_configs");
String file2 = Path.Combine(path, "groups.txt");
if (!Directory.Exists(path))
Directory.CreateDirectory(path);
if (File.Exists(file2))
File.Delete(file2);
File.Move(file, file2);
}
}
db.Query(query, info[0].Trim(), comms);
}
}
}
String path = Path.Combine(TShock.SavePath, "old_configs");
String file2 = Path.Combine(path, "groups.txt");
if (!Directory.Exists(path))
Directory.CreateDirectory(path);
if (File.Exists(file2))
File.Delete(file2);
File.Move(file, file2);
}
}
public bool GroupExists(string group)
{
if (group == "superadmin")
return true;
public bool GroupExists(string group)
{
if (group == "superadmin")
return true;
return groups.Any(g => g.Name.Equals(group));
}
return groups.Any(g => g.Name.Equals(group));
}
/// <summary>
/// Adds group with name and permissions if it does not exist.
/// </summary>
/// <param name="name">name of group</param>
/// <param name="parentname">parent of group</param>
/// <param name="permissions">permissions</param>
public String AddGroup(String name, string parentname, String permissions, String chatcolor)
{
String message = "";
if (GroupExists(name))
return "Error: Group already exists. Use /modGroup to change permissions.";
/// <summary>
/// Adds group with name and permissions if it does not exist.
/// </summary>
/// <param name="name">name of group</param>
/// <param name="parentname">parent of group</param>
/// <param name="permissions">permissions</param>
public String AddGroup(String name, string parentname, String permissions, String chatcolor)
{
String message = "";
if (GroupExists(name))
return "Error: Group already exists. Use /modGroup to change permissions.";
var group = new Group(name, null, chatcolor);
group.permissions.Add(permissions);
if (!string.IsNullOrWhiteSpace(parentname))
{
var parent = groups.FirstOrDefault(gp => gp.Name == parentname);
if (parent == null)
{
var error = "Invalid parent {0} for group {1}".SFormat(group.Name, parentname);
Log.ConsoleError(error);
return error;
}
group.Parent = parent;
}
var group = new Group(name, null, chatcolor);
group.permissions.Add(permissions);
if (!string.IsNullOrWhiteSpace(parentname))
{
var parent = groups.FirstOrDefault(gp => gp.Name == parentname);
if (parent == null)
{
var error = "Invalid parent {0} for group {1}".SFormat(group.Name, parentname);
Log.ConsoleError(error);
return error;
}
group.Parent = parent;
}
string query = (TShock.Config.StorageType.ToLower() == "sqlite") ?
"INSERT OR IGNORE INTO GroupList (GroupName, Parent, Commands, ChatColor) VALUES (@0, @1, @2, @3);" :
"INSERT IGNORE INTO GroupList SET GroupName=@0, Parent=@1, Commands=@2, ChatColor=@3";
if (database.Query(query, name, parentname, permissions, chatcolor) == 1)
message = "Group " + name + " has been created successfully.";
string query = (TShock.Config.StorageType.ToLower() == "sqlite")
? "INSERT OR IGNORE INTO GroupList (GroupName, Parent, Commands, ChatColor) VALUES (@0, @1, @2, @3);"
: "INSERT IGNORE INTO GroupList SET GroupName=@0, Parent=@1, Commands=@2, ChatColor=@3";
if (database.Query(query, name, parentname, permissions, chatcolor) == 1)
message = "Group " + name + " has been created successfully.";
groups.Add(group);
groups.Add(group);
return message;
}
public String AddGroup(String name, String permissions)
{
return AddGroup(name, "", permissions, "255,255,255");
}
public String AddGroup(String name, string parent, String permissions)
{
return AddGroup(name, parent, permissions, "255,255,255");
}
return message;
}
public String DeleteGroup(String name)
{
String message = "";
if (!GroupExists(name))
return "Error: Group doesn't exists.";
public String AddGroup(String name, String permissions)
{
return AddGroup(name, "", permissions, "255,255,255");
}
if (database.Query("DELETE FROM GroupList WHERE GroupName=@0", name) == 1)
message = "Group " + name + " has been deleted successfully.";
groups.Remove(TShock.Utils.GetGroup(name));
public String AddGroup(String name, string parent, String permissions)
{
return AddGroup(name, parent, permissions, "255,255,255");
}
return message;
}
public String DeleteGroup(String name)
{
String message = "";
if (!GroupExists(name))
return "Error: Group doesn't exists.";
public String AddPermissions(String name, List<String> permissions)
{
String message = "";
if (!GroupExists(name))
return "Error: Group doesn't exists.";
if (database.Query("DELETE FROM GroupList WHERE GroupName=@0", name) == 1)
message = "Group " + name + " has been deleted successfully.";
groups.Remove(TShock.Utils.GetGroup(name));
var group = TShock.Utils.GetGroup(name);
//Add existing permissions (without duplicating)
permissions.AddRange(group.permissions.Where(s => !permissions.Contains(s)));
return message;
}
if (database.Query("UPDATE GroupList SET Commands=@0 WHERE GroupName=@1", String.Join(",", permissions), name) != 0)
{
message = "Group " + name + " has been modified successfully.";
group.SetPermission( permissions );
}
return message;
}
public String AddPermissions(String name, List<String> permissions)
{
String message = "";
if (!GroupExists(name))
return "Error: Group doesn't exists.";
public String DeletePermissions(String name, List<String> permissions)
{
String message = "";
if (!GroupExists(name))
return "Error: Group doesn't exists.";
var group = TShock.Utils.GetGroup(name);
//Add existing permissions (without duplicating)
permissions.AddRange(group.permissions.Where(s => !permissions.Contains(s)));
var group = TShock.Utils.GetGroup(name);
if (database.Query("UPDATE GroupList SET Commands=@0 WHERE GroupName=@1", String.Join(",", permissions), name) != 0)
{
message = "Group " + name + " has been modified successfully.";
group.SetPermission(permissions);
}
return message;
}
//Only get permissions that exist in the group.
var newperms = group.permissions.Except( permissions );
public String DeletePermissions(String name, List<String> permissions)
{
String message = "";
if (!GroupExists(name))
return "Error: Group doesn't exists.";
if (database.Query("UPDATE GroupList SET Commands=@0 WHERE GroupName=@1", String.Join(",", newperms), name) != 0)
{
message = "Group " + name + " has been modified successfully.";
group.SetPermission( newperms.ToList() );
}
return message;
}
var group = TShock.Utils.GetGroup(name);
public void LoadPermisions()
{
//Create a temporary list so if there is an error it doesn't override the currently loaded groups with broken groups.
var tempgroups = new List<Group>();
tempgroups.Add(new SuperAdminGroup());
//Only get permissions that exist in the group.
var newperms = group.permissions.Except(permissions);
if (groups == null || groups.Count < 2)
groups = tempgroups;
if (database.Query("UPDATE GroupList SET Commands=@0 WHERE GroupName=@1", String.Join(",", newperms), name) != 0)
{
message = "Group " + name + " has been modified successfully.";
group.SetPermission(newperms.ToList());
}
return message;
}
try
{
var groupsparents = new List<Tuple<Group, string>>();
using (var reader = database.QueryReader("SELECT * FROM GroupList"))
{
while (reader.Read())
{
string groupname = reader.Get<String>("GroupName");
var group = new Group(groupname);
public void LoadPermisions()
{
//Create a temporary list so if there is an error it doesn't override the currently loaded groups with broken groups.
var tempgroups = new List<Group>();
tempgroups.Add(new SuperAdminGroup());
group.Prefix = reader.Get<String>("Prefix");
group.Suffix= reader.Get<String>("Suffix");
if (groups == null || groups.Count < 2)
groups = tempgroups;
//Inherit Given commands
String[] commands = reader.Get<String>("Commands").Split(',');
foreach (var t in commands)
{
var str = t.Trim();
if (str.StartsWith("!"))
{
group.NegatePermission(str.Substring(1));
}
else
{
group.AddPermission(str);
}
}
String[] chatcolour = (reader.Get<String>("ChatColor") ?? "").Split(',');
if (chatcolour.Length == 3)
{
byte.TryParse(chatcolour[0], out group.R);
byte.TryParse(chatcolour[1], out group.G);
byte.TryParse(chatcolour[2], out group.B);
}
try
{
var groupsparents = new List<Tuple<Group, string>>();
using (var reader = database.QueryReader("SELECT * FROM GroupList"))
{
while (reader.Read())
{
string groupname = reader.Get<String>("GroupName");
var group = new Group(groupname);
groupsparents.Add(Tuple.Create(group, reader.Get<string>("Parent")));
}
}
group.Prefix = reader.Get<String>("Prefix");
group.Suffix = reader.Get<String>("Suffix");
foreach (var t in groupsparents)
{
var group = t.Item1;
var parentname = t.Item2;
if (!string.IsNullOrWhiteSpace(parentname))
{
var parent = groupsparents.FirstOrDefault(gp => gp.Item1.Name == parentname);
if (parent == null)
{
Log.ConsoleError("Invalid parent {0} for group {1}".SFormat(group.Name, parentname));
return;
}
group.Parent = parent.Item1;
}
tempgroups.Add(group);
}
//Inherit Given commands
String[] commands = reader.Get<String>("Commands").Split(',');
foreach (var t in commands)
{
var str = t.Trim();
if (str.StartsWith("!"))
{
group.NegatePermission(str.Substring(1));
}
else
{
group.AddPermission(str);
}
}
String[] chatcolour = (reader.Get<String>("ChatColor") ?? "").Split(',');
if (chatcolour.Length == 3)
{
byte.TryParse(chatcolour[0], out group.R);
byte.TryParse(chatcolour[1], out group.G);
byte.TryParse(chatcolour[2], out group.B);
}
groupsparents.Add(Tuple.Create(group, reader.Get<string>("Parent")));
}
}
foreach (var t in groupsparents)
{
var group = t.Item1;
var parentname = t.Item2;
if (!string.IsNullOrWhiteSpace(parentname))
{
var parent = groupsparents.FirstOrDefault(gp => gp.Item1.Name == parentname);
if (parent == null)
{
Log.ConsoleError("Invalid parent {0} for group {1}".SFormat(group.Name, parentname));
return;
}
group.Parent = parent.Item1;
}
tempgroups.Add(group);
}
groups = tempgroups;
}
catch (Exception ex)
{
Log.Error(ex.ToString());
}
}
}
}
groups = tempgroups;
}
catch (Exception ex)
{
Log.Error(ex.ToString());
}
}
}
}

View file

@ -7,42 +7,55 @@ using TShockAPI.Extensions;
namespace TShockAPI.DB
{
public interface IQueryBuilder
{
string CreateTable(SqlTable table);
string AlterTable(SqlTable from, SqlTable to);
string DbTypeToString(MySqlDbType type, int? length);
string UpdateValue(string table, List<SqlValue> values, List<SqlValue> wheres);
string InsertValues(string table, List<SqlValue> values);
string ReadColumn(string table, List<SqlValue> wheres);
string DeleteRow(string table, List<SqlValue> wheres);
}
public interface IQueryBuilder
{
string CreateTable(SqlTable table);
string AlterTable(SqlTable from, SqlTable to);
string DbTypeToString(MySqlDbType type, int? length);
string UpdateValue(string table, List<SqlValue> values, List<SqlValue> wheres);
string InsertValues(string table, List<SqlValue> values);
string ReadColumn(string table, List<SqlValue> wheres);
string DeleteRow(string table, List<SqlValue> wheres);
}
public class SqliteQueryCreator : IQueryBuilder
{
public string CreateTable(SqlTable table)
{
var columns = table.Columns.Select(c => "'{0}' {1} {2} {3} {4}".SFormat(c.Name, DbTypeToString(c.Type, c.Length), c.Primary ? "PRIMARY KEY" : "", c.AutoIncrement ? "AUTOINCREMENT" : "", c.NotNull ? "NOT NULL" : "", c.Unique ? "UNIQUE" : ""));
return "CREATE TABLE '{0}' ({1})".SFormat(table.Name, string.Join(", ", columns));
}
static Random rand = new Random();
/// <summary>
/// Alter a table from source to destination
/// </summary>
/// <param name="from">Must have name and column names. Column types are not required</param>
/// <param name="to">Must have column names and column types.</param>
/// <returns></returns>
public string AlterTable(SqlTable from, SqlTable to)
{
var rstr = rand.NextString(20);
var alter = "ALTER TABLE '{0}' RENAME TO '{1}_{0}'".SFormat(from.Name, rstr);
var create = CreateTable(to);
//combine all columns in the 'from' variable excluding ones that aren't in the 'to' variable.
//exclude the ones that aren't in 'to' variable because if the column is deleted, why try to import the data?
var insert = "INSERT INTO '{0}' ({1}) SELECT {1} FROM {2}_{0}".SFormat(from.Name, string.Join(", ", from.Columns.Where(c => to.Columns.Any(c2 => c2.Name == c.Name)).Select(c => c.Name)), rstr);
var drop = "DROP TABLE '{0}_{1}'".SFormat(rstr, from.Name);
return "{0}; {1}; {2}; {3};".SFormat(alter, create, insert, drop);
/*
public class SqliteQueryCreator : IQueryBuilder
{
public string CreateTable(SqlTable table)
{
var columns =
table.Columns.Select(
c =>
"'{0}' {1} {2} {3} {4}".SFormat(c.Name, DbTypeToString(c.Type, c.Length), c.Primary ? "PRIMARY KEY" : "",
c.AutoIncrement ? "AUTOINCREMENT" : "", c.NotNull ? "NOT NULL" : "",
c.Unique ? "UNIQUE" : ""));
return "CREATE TABLE '{0}' ({1})".SFormat(table.Name, string.Join(", ", columns));
}
private static Random rand = new Random();
/// <summary>
/// Alter a table from source to destination
/// </summary>
/// <param name="from">Must have name and column names. Column types are not required</param>
/// <param name="to">Must have column names and column types.</param>
/// <returns></returns>
public string AlterTable(SqlTable from, SqlTable to)
{
var rstr = rand.NextString(20);
var alter = "ALTER TABLE '{0}' RENAME TO '{1}_{0}'".SFormat(from.Name, rstr);
var create = CreateTable(to);
//combine all columns in the 'from' variable excluding ones that aren't in the 'to' variable.
//exclude the ones that aren't in 'to' variable because if the column is deleted, why try to import the data?
var insert = "INSERT INTO '{0}' ({1}) SELECT {1} FROM {2}_{0}".SFormat(from.Name,
string.Join(", ",
from.Columns.Where(
c =>
to.Columns.Any(
c2 => c2.Name == c.Name)).Select
(c => c.Name)), rstr);
var drop = "DROP TABLE '{0}_{1}'".SFormat(rstr, from.Name);
return "{0}; {1}; {2}; {3};".SFormat(alter, create, insert, drop);
/*
ALTER TABLE "main"."Bans" RENAME TO "oXHFcGcd04oXHFcGcd04_Bans"
CREATE TABLE "main"."Bans" ("IP" TEXT PRIMARY KEY ,"Name" TEXT)
INSERT INTO "main"."Bans" SELECT "IP","Name" FROM "main"."oXHFcGcd04oXHFcGcd04_Bans"
@ -50,238 +63,264 @@ namespace TShockAPI.DB
*
* Twitchy - Oh. I get it!
*/
}
public string DeleteRow(string table, List<SqlValue> wheres)
{
var sbwheres = new StringBuilder();
int count = 0;
foreach (SqlValue where in wheres)
{
sbwheres.Append(where.Name + "=" + where.Value);
if (count != wheres.Count - 1)
sbwheres.Append(" AND ");
count++;
}
if (wheres.Count > 0)
return "DELETE FROM '{0}' WHERE {1} ".SFormat(table, sbwheres.ToString());
else
return "DELETE FROM '{0}'".SFormat(table, sbwheres.ToString());
}
public string UpdateValue(string table, List<SqlValue> values, List<SqlValue> wheres)
{
var sbvalues = new StringBuilder();
var sbwheres = new StringBuilder();
int count = 0;
foreach (SqlValue value in values)
{
sbvalues.Append(value.Name + "=" + value.Value);
if (count != values.Count - 1)
sbvalues.Append(",");
count++;
}
count = 0;
foreach (SqlValue where in wheres)
{
sbwheres.Append(where.Name + "=" + where.Value);
if (count != wheres.Count - 1)
sbwheres.Append(" AND ");
count++;
}
}
if (wheres.Count > 0)
return "UPDATE '{0}' SET {1} WHERE {2}".SFormat(table, sbvalues.ToString(), sbwheres.ToString());
else
return "UPDATE '{0}' SET {1}".SFormat(table, sbvalues.ToString());
}
public string InsertValues(string table, List<SqlValue> values)
{
var sbnames = new StringBuilder();
var sbvalues = new StringBuilder();
int count = 0;
public string DeleteRow(string table, List<SqlValue> wheres)
{
var sbwheres = new StringBuilder();
int count = 0;
foreach (SqlValue where in wheres)
{
sbwheres.Append(where.Name + "=" + where.Value);
if (count != wheres.Count - 1)
sbwheres.Append(" AND ");
count++;
}
if (wheres.Count > 0)
return "DELETE FROM '{0}' WHERE {1} ".SFormat(table, sbwheres.ToString());
else
return "DELETE FROM '{0}'".SFormat(table, sbwheres.ToString());
}
foreach (SqlValue name in values)
{
sbnames.Append(name.Name);
public string UpdateValue(string table, List<SqlValue> values, List<SqlValue> wheres)
{
var sbvalues = new StringBuilder();
var sbwheres = new StringBuilder();
int count = 0;
foreach (SqlValue value in values)
{
sbvalues.Append(value.Name + "=" + value.Value);
if (count != values.Count - 1)
sbvalues.Append(",");
count++;
}
count = 0;
foreach (SqlValue where in wheres)
{
sbwheres.Append(where.Name + "=" + where.Value);
if (count != wheres.Count - 1)
sbwheres.Append(" AND ");
count++;
}
if (count != values.Count - 1)
sbnames.Append(", ");
count++;
}
count = 0;
foreach (SqlValue value in values)
{
sbvalues.Append(value.Value.ToString());
if (count != values.Count - 1)
sbvalues.Append(", ");
count++;
}
return "INSERT INTO '{0}' ({1}) VALUES ({2})".SFormat(table, sbnames.ToString(), sbvalues.ToString());
}
public string ReadColumn(string table, List<SqlValue> wheres)
{
var sbwheres = new StringBuilder();
int count = 0;
if (wheres.Count > 0)
return "UPDATE '{0}' SET {1} WHERE {2}".SFormat(table, sbvalues.ToString(), sbwheres.ToString());
else
return "UPDATE '{0}' SET {1}".SFormat(table, sbvalues.ToString());
}
foreach (SqlValue where in wheres)
{
sbwheres.Append(where.Name + "=" + where.Value);
if (count != wheres.Count - 1)
sbwheres.Append(" AND ");
count++;
}
public string InsertValues(string table, List<SqlValue> values)
{
var sbnames = new StringBuilder();
var sbvalues = new StringBuilder();
int count = 0;
if(wheres.Count > 0)
return "SELECT * FROM {0} WHERE {1}".SFormat(table, sbwheres.ToString());
else
return "SELECT * FROM {0}".SFormat(table);
}
foreach (SqlValue name in values)
{
sbnames.Append(name.Name);
static readonly Dictionary<MySqlDbType, string> TypesAsStrings = new Dictionary<MySqlDbType, string>
{
{MySqlDbType.VarChar, "TEXT"},
{MySqlDbType.String, "TEXT"},
{MySqlDbType.Text, "TEXT"},
{MySqlDbType.TinyText, "TEXT"},
{MySqlDbType.MediumText, "TEXT"},
{MySqlDbType.LongText, "TEXT"},
{MySqlDbType.Int32, "INTEGER"},
};
public string DbTypeToString(MySqlDbType type, int? length)
{
string ret;
if (TypesAsStrings.TryGetValue(type, out ret))
return ret;
throw new NotImplementedException(Enum.GetName(typeof(MySqlDbType), type));
}
}
public class MysqlQueryCreator : IQueryBuilder
{
public string CreateTable(SqlTable table)
{
var columns = table.Columns.Select(c => "{0} {1} {2} {3}".SFormat(c.Name, DbTypeToString(c.Type, c.Length), c.Primary ? "PRIMARY KEY" : "", c.AutoIncrement ? "AUTO_INCREMENT" : "", c.NotNull ? "NOT NULL" : ""));
var uniques = table.Columns.Where(c => c.Unique).Select(c => c.Name);
return "CREATE TABLE {0} ({1} {2})".SFormat(table.Name, string.Join(", ", columns), uniques.Count() > 0 ? ", UNIQUE({0})".SFormat(string.Join(", ", uniques)) : "");
}
static Random rand = new Random();
/// <summary>
/// Alter a table from source to destination
/// </summary>
/// <param name="from">Must have name and column names. Column types are not required</param>
/// <param name="to">Must have column names and column types.</param>
/// <returns></returns>
public string AlterTable(SqlTable from, SqlTable to)
{
var rstr = rand.NextString(20);
var alter = "RENAME TABLE {0} TO {1}_{0}".SFormat(from.Name, rstr);
var create = CreateTable(to);
//combine all columns in the 'from' variable excluding ones that aren't in the 'to' variable.
//exclude the ones that aren't in 'to' variable because if the column is deleted, why try to import the data?
var insert = "INSERT INTO {0} ({1}) SELECT {1} FROM {2}_{0}".SFormat(from.Name, string.Join(", ", from.Columns.Where(c => to.Columns.Any(c2 => c2.Name == c.Name)).Select(c => c.Name)), rstr);
var drop = "DROP TABLE {0}_{1}".SFormat(rstr, from.Name);
return "{0}; {1}; {2}; {3};".SFormat(alter, create, insert, drop);
}
public string DeleteRow(string table, List<SqlValue> wheres)
{
var sbwheres = new StringBuilder();
int count = 0;
foreach (SqlValue where in wheres)
{
sbwheres.Append(where.Name + "=" + where.Value);
if (count != wheres.Count - 1)
sbwheres.Append(" AND ");
count++;
}
if (wheres.Count > 0)
return "DELETE FROM {0} WHERE {1} ".SFormat(table, sbwheres.ToString());
else
return "DELETE FROM {0}".SFormat(table, sbwheres.ToString());
}
public string UpdateValue(string table, List<SqlValue> values, List<SqlValue> wheres)
{
var sbvalues = new StringBuilder();
var sbwheres = new StringBuilder();
int count = 0;
foreach (SqlValue value in values)
{
sbvalues.Append(value.Name + "=" + value.Value);
if (count != values.Count - 1)
sbvalues.Append("AND");
count++;
}
count = 0;
foreach (SqlValue where in wheres)
{
sbwheres.Append(where.Name + "=" + where.Value);
if (count != wheres.Count - 1)
sbwheres.Append(" AND ");
count++;
}
if (count != values.Count - 1)
sbnames.Append(", ");
count++;
}
count = 0;
foreach (SqlValue value in values)
{
sbvalues.Append(value.Value.ToString());
if (count != values.Count - 1)
sbvalues.Append(", ");
count++;
}
return "INSERT INTO '{0}' ({1}) VALUES ({2})".SFormat(table, sbnames.ToString(), sbvalues.ToString());
}
if (wheres.Count > 0)
return "UPDATE {0} SET {1} WHERE {2}".SFormat(table, sbvalues.ToString(), sbwheres.ToString());
else
return "UPDATE {0} SET {1}".SFormat(table, sbvalues.ToString());
}
public string InsertValues(string table, List<SqlValue> values)
{
var sbnames = new StringBuilder();
var sbvalues = new StringBuilder();
int count = 0;
public string ReadColumn(string table, List<SqlValue> wheres)
{
var sbwheres = new StringBuilder();
int count = 0;
foreach (SqlValue name in values)
{
sbnames.Append(name.Name);
foreach (SqlValue where in wheres)
{
sbwheres.Append(where.Name + "=" + where.Value);
if (count != wheres.Count - 1)
sbwheres.Append(" AND ");
count++;
}
if (count != values.Count - 1)
sbnames.Append(", ");
count++;
}
count = 0;
foreach (SqlValue value in values)
{
sbvalues.Append(value.Value.ToString());
if (count != values.Count - 1)
sbvalues.Append(", ");
count++;
}
if (wheres.Count > 0)
return "SELECT * FROM {0} WHERE {1}".SFormat(table, sbwheres.ToString());
else
return "SELECT * FROM {0}".SFormat(table);
}
return "INSERT INTO {0} ({1}) VALUES ({2})".SFormat(table, sbnames.ToString(), sbvalues.ToString());
}
public string ReadColumn(string table, List<SqlValue> wheres)
{
var sbwheres = new StringBuilder();
int count = 0;
private static readonly Dictionary<MySqlDbType, string> TypesAsStrings = new Dictionary<MySqlDbType, string>
{
{MySqlDbType.VarChar, "TEXT"},
{MySqlDbType.String, "TEXT"},
{MySqlDbType.Text, "TEXT"},
{MySqlDbType.TinyText, "TEXT"},
{MySqlDbType.MediumText, "TEXT"},
{MySqlDbType.LongText, "TEXT"},
{MySqlDbType.Int32, "INTEGER"},
};
foreach (SqlValue where in wheres)
{
sbwheres.Append(where.Name + "=" + where.Value);
if (count != wheres.Count - 1)
sbwheres.Append(" AND ");
count++;
}
public string DbTypeToString(MySqlDbType type, int? length)
{
string ret;
if (TypesAsStrings.TryGetValue(type, out ret))
return ret;
throw new NotImplementedException(Enum.GetName(typeof (MySqlDbType), type));
}
}
if (wheres.Count > 0)
return "SELECT * FROM {0} WHERE {1}".SFormat(table, sbwheres.ToString());
else
return "SELECT * FROM {0}".SFormat(table);
}
public class MysqlQueryCreator : IQueryBuilder
{
public string CreateTable(SqlTable table)
{
var columns =
table.Columns.Select(
c =>
"{0} {1} {2} {3}".SFormat(c.Name, DbTypeToString(c.Type, c.Length), c.Primary ? "PRIMARY KEY" : "",
c.AutoIncrement ? "AUTO_INCREMENT" : "", c.NotNull ? "NOT NULL" : ""));
var uniques = table.Columns.Where(c => c.Unique).Select(c => c.Name);
return "CREATE TABLE {0} ({1} {2})".SFormat(table.Name, string.Join(", ", columns),
uniques.Count() > 0
? ", UNIQUE({0})".SFormat(string.Join(", ", uniques))
: "");
}
static readonly Dictionary<MySqlDbType, string> TypesAsStrings = new Dictionary<MySqlDbType, string>
{
{MySqlDbType.VarChar, "VARCHAR"},
{MySqlDbType.String, "CHAR"},
{MySqlDbType.Text, "TEXT"},
{MySqlDbType.TinyText, "TINYTEXT"},
{MySqlDbType.MediumText, "MEDIUMTEXT"},
{MySqlDbType.LongText, "LONGTEXT"},
{MySqlDbType.Int32, "INT"},
};
public string DbTypeToString(MySqlDbType type, int? length)
{
string ret;
if (TypesAsStrings.TryGetValue(type, out ret))
return ret + (length != null ? "({0})".SFormat((int)length) : "");
throw new NotImplementedException(Enum.GetName(typeof(MySqlDbType), type));
}
}
}
private static Random rand = new Random();
/// <summary>
/// Alter a table from source to destination
/// </summary>
/// <param name="from">Must have name and column names. Column types are not required</param>
/// <param name="to">Must have column names and column types.</param>
/// <returns></returns>
public string AlterTable(SqlTable from, SqlTable to)
{
var rstr = rand.NextString(20);
var alter = "RENAME TABLE {0} TO {1}_{0}".SFormat(from.Name, rstr);
var create = CreateTable(to);
//combine all columns in the 'from' variable excluding ones that aren't in the 'to' variable.
//exclude the ones that aren't in 'to' variable because if the column is deleted, why try to import the data?
var insert = "INSERT INTO {0} ({1}) SELECT {1} FROM {2}_{0}".SFormat(from.Name,
string.Join(", ",
from.Columns.Where(
c =>
to.Columns.Any(
c2 => c2.Name == c.Name)).Select(
c => c.Name)), rstr);
var drop = "DROP TABLE {0}_{1}".SFormat(rstr, from.Name);
return "{0}; {1}; {2}; {3};".SFormat(alter, create, insert, drop);
}
public string DeleteRow(string table, List<SqlValue> wheres)
{
var sbwheres = new StringBuilder();
int count = 0;
foreach (SqlValue where in wheres)
{
sbwheres.Append(where.Name + "=" + where.Value);
if (count != wheres.Count - 1)
sbwheres.Append(" AND ");
count++;
}
if (wheres.Count > 0)
return "DELETE FROM {0} WHERE {1} ".SFormat(table, sbwheres.ToString());
else
return "DELETE FROM {0}".SFormat(table, sbwheres.ToString());
}
public string UpdateValue(string table, List<SqlValue> values, List<SqlValue> wheres)
{
var sbvalues = new StringBuilder();
var sbwheres = new StringBuilder();
int count = 0;
foreach (SqlValue value in values)
{
sbvalues.Append(value.Name + "=" + value.Value);
if (count != values.Count - 1)
sbvalues.Append("AND");
count++;
}
count = 0;
foreach (SqlValue where in wheres)
{
sbwheres.Append(where.Name + "=" + where.Value);
if (count != wheres.Count - 1)
sbwheres.Append(" AND ");
count++;
}
if (wheres.Count > 0)
return "UPDATE {0} SET {1} WHERE {2}".SFormat(table, sbvalues.ToString(), sbwheres.ToString());
else
return "UPDATE {0} SET {1}".SFormat(table, sbvalues.ToString());
}
public string InsertValues(string table, List<SqlValue> values)
{
var sbnames = new StringBuilder();
var sbvalues = new StringBuilder();
int count = 0;
foreach (SqlValue name in values)
{
sbnames.Append(name.Name);
if (count != values.Count - 1)
sbnames.Append(", ");
count++;
}
count = 0;
foreach (SqlValue value in values)
{
sbvalues.Append(value.Value.ToString());
if (count != values.Count - 1)
sbvalues.Append(", ");
count++;
}
return "INSERT INTO {0} ({1}) VALUES ({2})".SFormat(table, sbnames.ToString(), sbvalues.ToString());
}
public string ReadColumn(string table, List<SqlValue> wheres)
{
var sbwheres = new StringBuilder();
int count = 0;
foreach (SqlValue where in wheres)
{
sbwheres.Append(where.Name + "=" + where.Value);
if (count != wheres.Count - 1)
sbwheres.Append(" AND ");
count++;
}
if (wheres.Count > 0)
return "SELECT * FROM {0} WHERE {1}".SFormat(table, sbwheres.ToString());
else
return "SELECT * FROM {0}".SFormat(table);
}
private static readonly Dictionary<MySqlDbType, string> TypesAsStrings = new Dictionary<MySqlDbType, string>
{
{MySqlDbType.VarChar, "VARCHAR"},
{MySqlDbType.String, "CHAR"},
{MySqlDbType.Text, "TEXT"},
{MySqlDbType.TinyText, "TINYTEXT"},
{MySqlDbType.MediumText, "MEDIUMTEXT"},
{MySqlDbType.LongText, "LONGTEXT"},
{MySqlDbType.Int32, "INT"},
};
public string DbTypeToString(MySqlDbType type, int? length)
{
string ret;
if (TypesAsStrings.TryGetValue(type, out ret))
return ret + (length != null ? "({0})".SFormat((int) length) : "");
throw new NotImplementedException(Enum.GetName(typeof (MySqlDbType), type));
}
}
}

View file

@ -22,81 +22,86 @@ using MySql.Data.MySqlClient;
namespace TShockAPI.DB
{
public class InventoryManager
{
public IDbConnection database;
public class InventoryManager
{
public IDbConnection database;
public InventoryManager(IDbConnection db)
{
database = db;
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);
}
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);
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());
}
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;
}
return playerData;
}
public bool InsertPlayerData(TSPlayer player)
{
PlayerData playerData = player.PlayerData;
public bool InsertPlayerData(TSPlayer player)
{
PlayerData playerData = player.PlayerData;
if (!player.IsLoggedIn)
return false;
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;
}
}
}
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

@ -7,119 +7,122 @@ using MySql.Data.MySqlClient;
namespace TShockAPI.DB
{
public class ItemManager
{
private IDbConnection database;
public class ItemManager
{
private IDbConnection database;
public List<ItemBan> ItemBans = new List<ItemBan>();
public ItemManager(IDbConnection db)
{
database = db;
public ItemManager(IDbConnection db)
{
database = db;
var table = new SqlTable("ItemBans",
new SqlColumn("ItemName", MySqlDbType.VarChar, 50) { Primary = true },
new SqlColumn("AllowedGroups", MySqlDbType.Text )
);
var creator = new SqlTableCreator(db, db.GetSqlType() == SqlType.Sqlite ? (IQueryBuilder)new SqliteQueryCreator() : new MysqlQueryCreator());
creator.EnsureExists(table);
var table = new SqlTable("ItemBans",
new SqlColumn("ItemName", MySqlDbType.VarChar, 50) {Primary = true},
new SqlColumn("AllowedGroups", MySqlDbType.Text)
);
var creator = new SqlTableCreator(db,
db.GetSqlType() == SqlType.Sqlite
? (IQueryBuilder) new SqliteQueryCreator()
: new MysqlQueryCreator());
creator.EnsureExists(table);
String file = Path.Combine(TShock.SavePath, "itembans.txt");
if (File.Exists(file))
{
using (StreamReader sr = new StreamReader(file))
{
String line;
while ((line = sr.ReadLine()) != null)
{
if (!line.Equals("") && !line.Substring(0, 1).Equals("#"))
{
String file = Path.Combine(TShock.SavePath, "itembans.txt");
if (File.Exists(file))
{
using (StreamReader sr = new StreamReader(file))
{
String line;
while ((line = sr.ReadLine()) != null)
{
if (!line.Equals("") && !line.Substring(0, 1).Equals("#"))
{
string query = (TShock.Config.StorageType.ToLower() == "sqlite")
? "INSERT OR IGNORE INTO 'ItemBans' (ItemName, AllowedGroups) VALUES (@0, @1);"
: "INSERT IGNORE INTO ItemBans SET ItemName=@0,AllowedGroups=@1 ;";
string query = (TShock.Config.StorageType.ToLower() == "sqlite") ?
"INSERT OR IGNORE INTO 'ItemBans' (ItemName, AllowedGroups) VALUES (@0, @1);" :
"INSERT IGNORE INTO ItemBans SET ItemName=@0,AllowedGroups=@1 ;";
int id = 0;
int.TryParse(line, out id);
int id = 0;
int.TryParse(line, out id);
database.Query(query, TShock.Utils.GetItemById(id).name, "");
}
}
}
database.Query(query, TShock.Utils.GetItemById(id).name, "");
}
}
}
String path = Path.Combine(TShock.SavePath, "old_configs");
String file2 = Path.Combine(path, "itembans.txt");
if (!Directory.Exists(path))
Directory.CreateDirectory(path);
if (File.Exists(file2))
File.Delete(file2);
File.Move(file, file2);
}
String path = Path.Combine(TShock.SavePath, "old_configs");
String file2 = Path.Combine(path, "itembans.txt");
if (!Directory.Exists(path))
Directory.CreateDirectory(path);
if (File.Exists(file2))
File.Delete(file2);
File.Move(file, file2);
}
UpdateItemBans();
}
UpdateItemBans();
}
public void UpdateItemBans()
{
ItemBans.Clear();
public void UpdateItemBans()
{
ItemBans.Clear();
using (var reader = database.QueryReader("SELECT * FROM ItemBans"))
{
while (reader != null && reader.Read())
{
using (var reader = database.QueryReader("SELECT * FROM ItemBans"))
{
while (reader != null && reader.Read())
{
ItemBan ban = new ItemBan(reader.Get<string>("ItemName"));
ban.SetAllowedGroups( reader.Get<string>("AllowedGroups") );
ban.SetAllowedGroups(reader.Get<string>("AllowedGroups"));
ItemBans.Add(ban);
}
}
}
}
}
}
public void AddNewBan(string itemname = "")
{
try
{
database.Query("INSERT INTO ItemBans (ItemName, AllowedGroups) VALUES (@0, @1);", TShock.Utils.GetItemByName(itemname)[0].name, "");
if (!ItemIsBanned(itemname, null))
ItemBans.Add( new ItemBan(itemname) );
}
catch (Exception ex)
{
Log.Error(ex.ToString());
}
}
public void AddNewBan(string itemname = "")
{
try
{
database.Query("INSERT INTO ItemBans (ItemName, AllowedGroups) VALUES (@0, @1);",
TShock.Utils.GetItemByName(itemname)[0].name, "");
if (!ItemIsBanned(itemname, null))
ItemBans.Add(new ItemBan(itemname));
}
catch (Exception ex)
{
Log.Error(ex.ToString());
}
}
public void RemoveBan(string itemname)
{
if (!ItemIsBanned(itemname, null))
return;
try
{
database.Query("Delete FROM 'ItemBans' WHERE ItemName=@0;", TShock.Utils.GetItemByName(itemname)[0].name);
ItemBans.Remove( new ItemBan(itemname) );
}
catch (Exception ex)
{
Log.Error(ex.ToString());
}
}
public void RemoveBan(string itemname)
{
if (!ItemIsBanned(itemname, null))
return;
try
{
database.Query("Delete FROM 'ItemBans' WHERE ItemName=@0;", TShock.Utils.GetItemByName(itemname)[0].name);
ItemBans.Remove(new ItemBan(itemname));
}
catch (Exception ex)
{
Log.Error(ex.ToString());
}
}
public bool ItemIsBanned(string name)
{
if (ItemBans.Contains(new ItemBan(name)))
{
return true;
}
return false;
}
public bool ItemIsBanned(string name)
{
if (ItemBans.Contains(new ItemBan(name)))
{
return true;
}
return false;
}
public bool ItemIsBanned(string name, TSPlayer ply)
{
if (ItemBans.Contains( new ItemBan(name) ) )
public bool ItemIsBanned(string name, TSPlayer ply)
{
if (ItemBans.Contains(new ItemBan(name)))
{
ItemBan b = GetItemBanByName(name);
return !b.HasPermissionToUseItem(ply);
}
return false;
}
}
public bool AllowGroup(string item, string name)
{
@ -134,7 +137,7 @@ namespace TShockAPI.DB
b.SetAllowedGroups(groupsNew);
int q = database.Query("UPDATE ItemBans SET AllowedGroups=@0 WHERE ItemName=@1", groupsNew,
item);
item);
return q > 0;
}
@ -150,7 +153,7 @@ namespace TShockAPI.DB
b.RemoveGroup(group);
string groups = string.Join(",", b.AllowedGroups);
int q = database.Query("UPDATE ItemBans SET AllowedGroups=@0 WHERE ItemName=@1", groups,
item);
item);
if (q > 0)
return true;
}
@ -168,58 +171,58 @@ namespace TShockAPI.DB
}
return null;
}
}
}
public class ItemBan : IEquatable<ItemBan>
{
public string Name { get; set; }
{
public string Name { get; set; }
public List<string> AllowedGroups { get; set; }
public ItemBan(string name)
: this()
{
Name = name;
public ItemBan(string name)
: this()
{
Name = name;
AllowedGroups = new List<string>();
}
}
public ItemBan()
{
Name = "";
public ItemBan()
{
Name = "";
AllowedGroups = new List<string>();
}
}
public bool Equals(ItemBan other)
{
return Name == other.Name;
}
public bool HasPermissionToUseItem(TSPlayer ply)
{
public bool HasPermissionToUseItem(TSPlayer ply)
{
if (ply == null)
return false;
return AllowedGroups.Contains(ply.Group.Name); // could add in the other permissions in this class instead of a giant if switch.
}
public void SetAllowedGroups( String groups )
{
// prevent null pointer exceptions
if (!string.IsNullOrEmpty(groups))
{
List<String> groupArr = groups.Split(',').ToList();
for (int i = 0; i < groupArr.Count; i++)
{
groupArr[i] = groupArr[i].Trim();
Console.WriteLine(groupArr[i]);
}
AllowedGroups = groupArr;
}
return AllowedGroups.Contains(ply.Group.Name);
// could add in the other permissions in this class instead of a giant if switch.
}
public bool RemoveGroup(string groupName)
public void SetAllowedGroups(String groups)
{
// prevent null pointer exceptions
if (!string.IsNullOrEmpty(groups))
{
List<String> groupArr = groups.Split(',').ToList();
for (int i = 0; i < groupArr.Count; i++)
{
groupArr[i] = groupArr[i].Trim();
Console.WriteLine(groupArr[i]);
}
AllowedGroups = groupArr;
}
}
public bool RemoveGroup(string groupName)
{
return AllowedGroups.Remove(groupName);
}
}
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -23,69 +23,74 @@ using Terraria;
namespace TShockAPI.DB
{
public class RemeberedPosManager
{
public IDbConnection database;
public class RemeberedPosManager
{
public IDbConnection database;
public RemeberedPosManager(IDbConnection db)
{
database = db;
public RemeberedPosManager(IDbConnection db)
{
database = db;
var table = new SqlTable("RememberedPos",
new SqlColumn("Name", MySqlDbType.VarChar, 50) { Primary = true },
new SqlColumn("IP", MySqlDbType.Text),
new SqlColumn("X", MySqlDbType.Int32),
new SqlColumn("Y", MySqlDbType.Int32),
new SqlColumn("WorldID", MySqlDbType.Text)
);
var creator = new SqlTableCreator(db, db.GetSqlType() == SqlType.Sqlite ? (IQueryBuilder)new SqliteQueryCreator() : new MysqlQueryCreator());
creator.EnsureExists(table);
}
var table = new SqlTable("RememberedPos",
new SqlColumn("Name", MySqlDbType.VarChar, 50) {Primary = true},
new SqlColumn("IP", MySqlDbType.Text),
new SqlColumn("X", MySqlDbType.Int32),
new SqlColumn("Y", MySqlDbType.Int32),
new SqlColumn("WorldID", MySqlDbType.Text)
);
var creator = new SqlTableCreator(db,
db.GetSqlType() == SqlType.Sqlite
? (IQueryBuilder) new SqliteQueryCreator()
: new MysqlQueryCreator());
creator.EnsureExists(table);
}
public Vector2 GetLeavePos(string name, string IP)
{
try
{
using (var reader = database.QueryReader("SELECT * FROM RememberedPos WHERE Name=@0 AND IP=@1", name, IP))
{
if (reader.Read())
{
return new Vector2(reader.Get<int>("X"), reader.Get<int>("Y"));
}
}
}
catch (Exception ex)
{
Log.Error(ex.ToString());
}
public Vector2 GetLeavePos(string name, string IP)
{
try
{
using (var reader = database.QueryReader("SELECT * FROM RememberedPos WHERE Name=@0 AND IP=@1", name, IP))
{
if (reader.Read())
{
return new Vector2(reader.Get<int>("X"), reader.Get<int>("Y"));
}
}
}
catch (Exception ex)
{
Log.Error(ex.ToString());
}
return new Vector2();
}
return new Vector2();
}
public void InsertLeavePos(string name, string IP, int X, int Y)
{
if (GetLeavePos(name, IP) == Vector2.Zero)
{
try
{
database.Query("INSERT INTO RememberedPos (Name, IP, X, Y, WorldID) VALUES (@0, @1, @2, @3, @4);", name, IP, X, Y + 3, Main.worldID.ToString());
}
catch (Exception ex)
{
Log.Error(ex.ToString());
}
}
else
{
try
{
database.Query("UPDATE RememberedPos SET X = @0, Y = @1 WHERE Name = @2 AND IP = @3 AND WorldID = @4;", X, Y + 3, name, IP, Main.worldID.ToString());
}
catch (Exception ex)
{
Log.Error(ex.ToString());
}
}
}
}
}
public void InsertLeavePos(string name, string IP, int X, int Y)
{
if (GetLeavePos(name, IP) == Vector2.Zero)
{
try
{
database.Query("INSERT INTO RememberedPos (Name, IP, X, Y, WorldID) VALUES (@0, @1, @2, @3, @4);", name, IP, X,
Y + 3, Main.worldID.ToString());
}
catch (Exception ex)
{
Log.Error(ex.ToString());
}
}
else
{
try
{
database.Query("UPDATE RememberedPos SET X = @0, Y = @1 WHERE Name = @2 AND IP = @3 AND WorldID = @4;", X, Y + 3,
name, IP, Main.worldID.ToString());
}
catch (Exception ex)
{
Log.Error(ex.ToString());
}
}
}
}
}

View file

@ -2,34 +2,35 @@
namespace TShockAPI.DB
{
public class SqlColumn
{
//Required
public string Name { get; set; }
public MySqlDbType Type { get; set; }
public class SqlColumn
{
//Required
public string Name { get; set; }
public MySqlDbType Type { get; set; }
//Optional
public bool Unique { get; set; }
public bool Primary { get; set; }
public bool AutoIncrement { get; set; }
public bool NotNull { get; set; }
public string DefaultValue { get; set; }
//Optional
public bool Unique { get; set; }
public bool Primary { get; set; }
public bool AutoIncrement { get; set; }
public bool NotNull { get; set; }
public string DefaultValue { get; set; }
/// <summary>
/// Length of the data type, null = default
/// </summary>
public int? Length { get; set; }
/// <summary>
/// Length of the data type, null = default
/// </summary>
public int? Length { get; set; }
public SqlColumn(string name, MySqlDbType type)
: this(name, type, null)
{
}
public SqlColumn(string name, MySqlDbType type, int? length)
{
Name = name;
Type = type;
Length = length;
}
}
}
public SqlColumn(string name, MySqlDbType type)
: this(name, type, null)
{
}
public SqlColumn(string name, MySqlDbType type, int? length)
{
Name = name;
Type = type;
Length = length;
}
}
}

View file

@ -6,79 +6,86 @@ using MySql.Data.MySqlClient;
namespace TShockAPI.DB
{
public class SqlTable
{
public List<SqlColumn> Columns { get; protected set; }
public string Name { get; protected set; }
public SqlTable(string name, params SqlColumn[] columns)
: this(name, new List<SqlColumn>(columns))
{
}
public SqlTable(string name, List<SqlColumn> columns)
{
Name = name;
Columns = columns;
}
}
public class SqlTable
{
public List<SqlColumn> Columns { get; protected set; }
public string Name { get; protected set; }
public class SqlTableCreator
{
IDbConnection database;
IQueryBuilder creator;
public SqlTableCreator(IDbConnection db, IQueryBuilder provider)
{
database = db;
creator = provider;
}
public SqlTable(string name, params SqlColumn[] columns)
: this(name, new List<SqlColumn>(columns))
{
}
public void EnsureExists(SqlTable table)
{
var columns = GetColumns(table);
if (columns.Count > 0)
{
if (!table.Columns.All(c => columns.Contains(c.Name)) || !columns.All(c => table.Columns.Any(c2 => c2.Name == c)))
{
var from = new SqlTable(table.Name, columns.Select(s => new SqlColumn(s, MySqlDbType.String)).ToList());
database.Query(creator.AlterTable(from, table));
}
}
else
{
database.Query(creator.CreateTable(table));
}
}
public SqlTable(string name, List<SqlColumn> columns)
{
Name = name;
Columns = columns;
}
}
public List<string> GetColumns(SqlTable table)
{
var ret = new List<string>();
var name = database.GetSqlType();
if (name == SqlType.Sqlite)
{
using (var reader = database.QueryReader("PRAGMA table_info({0})".SFormat(table.Name)))
{
while (reader.Read())
ret.Add(reader.Get<string>("name"));
}
}
else if (name == SqlType.Mysql)
{
using (var reader = database.QueryReader("SELECT COLUMN_NAME FROM information_schema.COLUMNS WHERE TABLE_NAME=@0 AND TABLE_SCHEMA=@1", table.Name, database.Database))
{
while (reader.Read())
ret.Add(reader.Get<string>("COLUMN_NAME"));
}
}
else
{
throw new NotSupportedException();
}
public class SqlTableCreator
{
private IDbConnection database;
private IQueryBuilder creator;
return ret;
}
public SqlTableCreator(IDbConnection db, IQueryBuilder provider)
{
database = db;
creator = provider;
}
public void DeleteRow(string table, List<SqlValue> wheres)
{
database.Query(creator.DeleteRow(table, wheres));
}
}
}
public void EnsureExists(SqlTable table)
{
var columns = GetColumns(table);
if (columns.Count > 0)
{
if (!table.Columns.All(c => columns.Contains(c.Name)) || !columns.All(c => table.Columns.Any(c2 => c2.Name == c)))
{
var from = new SqlTable(table.Name, columns.Select(s => new SqlColumn(s, MySqlDbType.String)).ToList());
database.Query(creator.AlterTable(from, table));
}
}
else
{
database.Query(creator.CreateTable(table));
}
}
public List<string> GetColumns(SqlTable table)
{
var ret = new List<string>();
var name = database.GetSqlType();
if (name == SqlType.Sqlite)
{
using (var reader = database.QueryReader("PRAGMA table_info({0})".SFormat(table.Name)))
{
while (reader.Read())
ret.Add(reader.Get<string>("name"));
}
}
else if (name == SqlType.Mysql)
{
using (
var reader =
database.QueryReader(
"SELECT COLUMN_NAME FROM information_schema.COLUMNS WHERE TABLE_NAME=@0 AND TABLE_SCHEMA=@1", table.Name,
database.Database))
{
while (reader.Read())
ret.Add(reader.Get<string>("COLUMN_NAME"));
}
}
else
{
throw new NotSupportedException();
}
return ret;
}
public void DeleteRow(string table, List<SqlValue> wheres)
{
database.Query(creator.DeleteRow(table, wheres));
}
}
}

View file

@ -3,50 +3,50 @@ using System.Data;
namespace TShockAPI.DB
{
public class SqlValue
{
public string Name { get; set; }
public object Value { get; set; }
public class SqlValue
{
public string Name { get; set; }
public object Value { get; set; }
public SqlValue(string name, object value)
{
Name = name;
Value = value;
}
}
public SqlValue(string name, object value)
{
Name = name;
Value = value;
}
}
public class SqlTableEditor
{
IDbConnection database;
IQueryBuilder creator;
public class SqlTableEditor
{
private IDbConnection database;
private IQueryBuilder creator;
public SqlTableEditor(IDbConnection db, IQueryBuilder provider)
{
database = db;
creator = provider;
}
public SqlTableEditor(IDbConnection db, IQueryBuilder provider)
{
database = db;
creator = provider;
}
public void UpdateValues(string table, List<SqlValue> values, List<SqlValue> wheres)
{
database.Query(creator.UpdateValue(table, values, wheres));
}
public void UpdateValues(string table, List<SqlValue> values, List<SqlValue> wheres)
{
database.Query(creator.UpdateValue(table, values, wheres));
}
public void InsertValues(string table, List<SqlValue> values)
{
database.Query(creator.InsertValues(table, values));
}
public void InsertValues(string table, List<SqlValue> values)
{
database.Query(creator.InsertValues(table, values));
}
public List<object> ReadColumn(string table, string column, List<SqlValue> wheres)
{
List<object> values = new List<object>();
public List<object> ReadColumn(string table, string column, List<SqlValue> wheres)
{
List<object> values = new List<object>();
using (var reader = database.QueryReader(creator.ReadColumn(table, wheres)))
{
while (reader.Read())
values.Add(reader.Reader.Get<object>(column));
}
using (var reader = database.QueryReader(creator.ReadColumn(table, wheres)))
{
while (reader.Read())
values.Add(reader.Reader.Get<object>(column));
}
return values;
}
}
}
return values;
}
}
}

View file

@ -1,5 +1,4 @@

/*
/*
TShock, a server mod for Terraria
Copyright (C) 2011 The TShock Team
@ -24,354 +23,366 @@ using MySql.Data.MySqlClient;
namespace TShockAPI.DB
{
public class UserManager
{
private IDbConnection database;
public class UserManager
{
private IDbConnection database;
public UserManager(IDbConnection db)
{
database = db;
public UserManager(IDbConnection db)
{
database = db;
var table = new SqlTable("Users",
new SqlColumn("ID", MySqlDbType.Int32) { Primary = true, AutoIncrement = true },
new SqlColumn("Username", MySqlDbType.VarChar, 32) { Unique = true },
new SqlColumn("Password", MySqlDbType.VarChar, 128),
new SqlColumn("Usergroup", MySqlDbType.Text),
new SqlColumn("IP", MySqlDbType.VarChar, 16)
);
var creator = new SqlTableCreator(db, db.GetSqlType() == SqlType.Sqlite ? (IQueryBuilder)new SqliteQueryCreator() : new MysqlQueryCreator());
creator.EnsureExists(table);
var table = new SqlTable("Users",
new SqlColumn("ID", MySqlDbType.Int32) {Primary = true, AutoIncrement = true},
new SqlColumn("Username", MySqlDbType.VarChar, 32) {Unique = true},
new SqlColumn("Password", MySqlDbType.VarChar, 128),
new SqlColumn("Usergroup", MySqlDbType.Text),
new SqlColumn("IP", MySqlDbType.VarChar, 16)
);
var creator = new SqlTableCreator(db,
db.GetSqlType() == SqlType.Sqlite
? (IQueryBuilder) new SqliteQueryCreator()
: new MysqlQueryCreator());
creator.EnsureExists(table);
String file = Path.Combine(TShock.SavePath, "users.txt");
if (File.Exists(file))
{
using (StreamReader sr = new StreamReader(file))
{
String line;
while ((line = sr.ReadLine()) != null)
{
if (line.Equals("") || line.Substring(0, 1).Equals("#"))
continue;
String[] info = line.Split(' ');
String username = "";
String sha = "";
String group = "";
String ip = "";
String file = Path.Combine(TShock.SavePath, "users.txt");
if (File.Exists(file))
{
using (StreamReader sr = new StreamReader(file))
{
String line;
while ((line = sr.ReadLine()) != null)
{
if (line.Equals("") || line.Substring(0, 1).Equals("#"))
continue;
String[] info = line.Split(' ');
String username = "";
String sha = "";
String group = "";
String ip = "";
String[] nameSha = info[0].Split(':');
String[] nameSha = info[0].Split(':');
if (nameSha.Length < 2)
{
username = nameSha[0];
ip = nameSha[0];
group = info[1];
}
else
{
username = nameSha[0];
sha = nameSha[1];
group = info[1];
}
if (nameSha.Length < 2)
{
username = nameSha[0];
ip = nameSha[0];
group = info[1];
}
else
{
username = nameSha[0];
sha = nameSha[1];
group = info[1];
}
string query = (TShock.Config.StorageType.ToLower() == "sqlite") ?
"INSERT OR IGNORE INTO Users (Username, Password, Usergroup, IP) VALUES (@0, @1, @2, @3)" :
"INSERT IGNORE INTO Users SET Username=@0, Password=@1, Usergroup=@2, IP=@3";
string query = (TShock.Config.StorageType.ToLower() == "sqlite")
? "INSERT OR IGNORE INTO Users (Username, Password, Usergroup, IP) VALUES (@0, @1, @2, @3)"
: "INSERT IGNORE INTO Users SET Username=@0, Password=@1, Usergroup=@2, IP=@3";
database.Query(query, username.Trim(), sha.Trim(), group.Trim(), ip.Trim());
}
}
String path = Path.Combine(TShock.SavePath, "old_configs");
String file2 = Path.Combine(path, "users.txt");
if (!Directory.Exists(path))
Directory.CreateDirectory(path);
if (File.Exists(file2))
File.Delete(file2);
File.Move(file, file2);
}
database.Query(query, username.Trim(), sha.Trim(), group.Trim(), ip.Trim());
}
}
String path = Path.Combine(TShock.SavePath, "old_configs");
String file2 = Path.Combine(path, "users.txt");
if (!Directory.Exists(path))
Directory.CreateDirectory(path);
if (File.Exists(file2))
File.Delete(file2);
File.Move(file, file2);
}
}
}
/// <summary>
/// Adds a given username to the database
/// </summary>
/// <param name="user">User user</param>
public void AddUser(User user)
{
try
{
if (!TShock.Groups.GroupExists(user.Group))
throw new GroupNotExistsException(user.Group);
/// <summary>
/// Adds a given username to the database
/// </summary>
/// <param name="user">User user</param>
public void AddUser(User user)
{
try
{
if (!TShock.Groups.GroupExists(user.Group))
throw new GroupNotExistsException(user.Group);
if (
database.Query("INSERT INTO Users (Username, Password, UserGroup, IP) VALUES (@0, @1, @2, @3);", user.Name,
TShock.Utils.HashPassword(user.Password), user.Group, user.Address) < 1)
throw new UserExistsException(user.Name);
}
catch (Exception ex)
{
throw new UserManagerException("AddUser SQL returned an error", ex);
}
}
if (database.Query("INSERT INTO Users (Username, Password, UserGroup, IP) VALUES (@0, @1, @2, @3);", user.Name, TShock.Utils.HashPassword(user.Password), user.Group, user.Address) < 1)
throw new UserExistsException(user.Name);
}
catch (Exception ex)
{
throw new UserManagerException("AddUser SQL returned an error", ex);
}
}
/// <summary>
/// Removes a given username from the database
/// </summary>
/// <param name="user">User user</param>
public void RemoveUser(User user)
{
try
{
int affected = -1;
if (!string.IsNullOrEmpty(user.Address))
{
affected = database.Query("DELETE FROM Users WHERE IP=@0", user.Address);
}
else
{
affected = database.Query("DELETE FROM Users WHERE Username=@0", user.Name);
}
/// <summary>
/// Removes a given username from the database
/// </summary>
/// <param name="user">User user</param>
public void RemoveUser(User user)
{
try
{
int affected = -1;
if (!string.IsNullOrEmpty(user.Address))
{
affected = database.Query("DELETE FROM Users WHERE IP=@0", user.Address);
}
else
{
affected = database.Query("DELETE FROM Users WHERE Username=@0", user.Name);
}
if (affected < 1)
throw new UserNotExistException(string.IsNullOrEmpty(user.Address) ? user.Name : user.Address);
}
catch (Exception ex)
{
throw new UserManagerException("RemoveUser SQL returned an error", ex);
}
}
if (affected < 1)
throw new UserNotExistException(string.IsNullOrEmpty(user.Address) ? user.Name : user.Address);
}
catch (Exception ex)
{
throw new UserManagerException("RemoveUser SQL returned an error", ex);
}
}
/// <summary>
/// Sets the Hashed Password for a given username
/// </summary>
/// <param name="user">User user</param>
/// <param name="group">string password</param>
public void SetUserPassword(User user, string password)
{
try
{
if (database.Query("UPDATE Users SET Password = @0 WHERE Username = @1;", TShock.Utils.HashPassword(password), user.Name) == 0)
throw new UserNotExistException(user.Name);
}
catch (Exception ex)
{
throw new UserManagerException("SetUserPassword SQL returned an error", ex);
}
}
/// <summary>
/// Sets the Hashed Password for a given username
/// </summary>
/// <param name="user">User user</param>
/// <param name="group">string password</param>
public void SetUserPassword(User user, string password)
{
try
{
if (
database.Query("UPDATE Users SET Password = @0 WHERE Username = @1;", TShock.Utils.HashPassword(password),
user.Name) == 0)
throw new UserNotExistException(user.Name);
}
catch (Exception ex)
{
throw new UserManagerException("SetUserPassword SQL returned an error", ex);
}
}
/// <summary>
/// Sets the group for a given username
/// </summary>
/// <param name="user">User user</param>
/// <param name="group">string group</param>
public void SetUserGroup(User user, string group)
{
try
{
if (!TShock.Groups.GroupExists(group))
throw new GroupNotExistsException(group);
/// <summary>
/// Sets the group for a given username
/// </summary>
/// <param name="user">User user</param>
/// <param name="group">string group</param>
public void SetUserGroup(User user, string group)
{
try
{
if (!TShock.Groups.GroupExists(group))
throw new GroupNotExistsException(group);
if (database.Query("UPDATE Users SET UserGroup = @0 WHERE Username = @1;", group, user.Name) == 0)
throw new UserNotExistException(user.Name);
}
catch (Exception ex)
{
throw new UserManagerException("SetUserGroup SQL returned an error", ex);
}
}
if (database.Query("UPDATE Users SET UserGroup = @0 WHERE Username = @1;", group, user.Name) == 0)
throw new UserNotExistException(user.Name);
}
catch (Exception ex)
{
throw new UserManagerException("SetUserGroup SQL returned an error", ex);
}
}
public int GetUserID(string username)
{
try
{
using (var reader = database.QueryReader("SELECT * FROM Users WHERE Username=@0", username))
{
if (reader.Read())
{
return reader.Get<int>("ID");
}
}
}
catch (Exception ex)
{
Log.ConsoleError("FetchHashedPasswordAndGroup SQL returned an error: " + ex);
}
return -1;
}
public int GetUserID(string username)
{
try
{
using (var reader = database.QueryReader("SELECT * FROM Users WHERE Username=@0", username))
{
if (reader.Read())
{
return reader.Get<int>("ID");
}
}
}
catch (Exception ex)
{
Log.ConsoleError("FetchHashedPasswordAndGroup SQL returned an error: " + ex);
}
return -1;
}
/// <summary>
/// Returns a Group for a ip from the database
/// </summary>
/// <param name="ply">string ip</param>
public Group GetGroupForIP(string ip)
{
try
{
using (var reader = database.QueryReader("SELECT * FROM Users WHERE IP=@0", ip))
{
if (reader.Read())
{
string group = reader.Get<string>("UserGroup");
return TShock.Utils.GetGroup(group);
}
}
}
catch (Exception ex)
{
Log.ConsoleError("GetGroupForIP SQL returned an error: " + ex);
}
return TShock.Utils.GetGroup(TShock.Config.DefaultGuestGroupName);
}
/// <summary>
/// Returns a Group for a ip from the database
/// </summary>
/// <param name="ply">string ip</param>
public Group GetGroupForIP(string ip)
{
try
{
using (var reader = database.QueryReader("SELECT * FROM Users WHERE IP=@0", ip))
{
if (reader.Read())
{
string group = reader.Get<string>("UserGroup");
return TShock.Utils.GetGroup(group);
}
}
}
catch (Exception ex)
{
Log.ConsoleError("GetGroupForIP SQL returned an error: " + ex);
}
return TShock.Utils.GetGroup(TShock.Config.DefaultGuestGroupName);
}
public Group GetGroupForIPExpensive(string ip)
{
try
{
using (var reader = database.QueryReader("SELECT IP, UserGroup FROM Users"))
{
while (reader.Read())
{
if (TShock.Utils.GetIPv4Address(reader.Get<string>("IP")) == ip)
{
return TShock.Utils.GetGroup(reader.Get<string>("UserGroup"));
}
}
}
}
catch (Exception ex)
{
Log.ConsoleError("GetGroupForIP SQL returned an error: " + ex);
}
return TShock.Utils.GetGroup(TShock.Config.DefaultGuestGroupName);
}
public Group GetGroupForIPExpensive(string ip)
{
try
{
using (var reader = database.QueryReader("SELECT IP, UserGroup FROM Users"))
{
while (reader.Read())
{
if (TShock.Utils.GetIPv4Address(reader.Get<string>("IP")) == ip)
{
return TShock.Utils.GetGroup(reader.Get<string>("UserGroup"));
}
}
}
}
catch (Exception ex)
{
Log.ConsoleError("GetGroupForIP SQL returned an error: " + ex);
}
return TShock.Utils.GetGroup(TShock.Config.DefaultGuestGroupName);
}
public User GetUserByName(string name)
{
try
{
return GetUser(new User { Name = name });
}
catch (UserManagerException)
{
return null;
}
}
public User GetUserByID(int id)
{
try
{
return GetUser(new User { ID = id });
}
catch (UserManagerException)
{
return null;
}
}
public User GetUserByIP(string ip)
{
try
{
return GetUser(new User { Address = ip });
}
catch (UserManagerException)
{
return null;
}
}
public User GetUser(User user)
{
try
{
QueryResult result;
if (string.IsNullOrEmpty(user.Address))
{
result = database.QueryReader("SELECT * FROM Users WHERE Username=@0", user.Name);
}
else
{
result = database.QueryReader("SELECT * FROM Users WHERE IP=@0", user.Address);
}
public User GetUserByName(string name)
{
try
{
return GetUser(new User {Name = name});
}
catch (UserManagerException)
{
return null;
}
}
using (var reader = result)
{
if (reader.Read())
{
user.ID = reader.Get<int>("ID");
user.Group = reader.Get<string>("Usergroup");
user.Password = reader.Get<string>("Password");
user.Name = reader.Get<string>("Username");
user.Address = reader.Get<string>("IP");
return user;
}
}
}
catch (Exception ex)
{
throw new UserManagerException("GetUserID SQL returned an error", ex);
}
throw new UserNotExistException(string.IsNullOrEmpty(user.Address) ? user.Name : user.Address);
}
}
public User GetUserByID(int id)
{
try
{
return GetUser(new User {ID = id});
}
catch (UserManagerException)
{
return null;
}
}
public class User
{
public int ID { get; set; }
public string Name { get; set; }
public string Password { get; set; }
public string Group { get; set; }
public string Address { get; set; }
public User GetUserByIP(string ip)
{
try
{
return GetUser(new User {Address = ip});
}
catch (UserManagerException)
{
return null;
}
}
public User(string ip, string name, string pass, string group)
{
Address = ip;
Name = name;
Password = pass;
Group = group;
}
public User()
{
Address = "";
Name = "";
Password = "";
Group = "";
}
}
public User GetUser(User user)
{
try
{
QueryResult result;
if (string.IsNullOrEmpty(user.Address))
{
result = database.QueryReader("SELECT * FROM Users WHERE Username=@0", user.Name);
}
else
{
result = database.QueryReader("SELECT * FROM Users WHERE IP=@0", user.Address);
}
[Serializable]
public class UserManagerException : Exception
{
public UserManagerException(string message)
: base(message)
{
using (var reader = result)
{
if (reader.Read())
{
user.ID = reader.Get<int>("ID");
user.Group = reader.Get<string>("Usergroup");
user.Password = reader.Get<string>("Password");
user.Name = reader.Get<string>("Username");
user.Address = reader.Get<string>("IP");
return user;
}
}
}
catch (Exception ex)
{
throw new UserManagerException("GetUserID SQL returned an error", ex);
}
throw new UserNotExistException(string.IsNullOrEmpty(user.Address) ? user.Name : user.Address);
}
}
}
public UserManagerException(string message, Exception inner)
: base(message, inner)
{
public class User
{
public int ID { get; set; }
public string Name { get; set; }
public string Password { get; set; }
public string Group { get; set; }
public string Address { get; set; }
}
}
[Serializable]
public class UserExistsException : UserManagerException
{
public UserExistsException(string name)
: base("User '" + name + "' already exists")
{
}
}
[Serializable]
public class UserNotExistException : UserManagerException
{
public UserNotExistException(string name)
: base("User '" + name + "' does not exist")
{
}
}
[Serializable]
public class GroupNotExistsException : UserManagerException
{
public GroupNotExistsException(string group)
: base("Group '" + group + "' does not exist")
{
}
}
}
public User(string ip, string name, string pass, string group)
{
Address = ip;
Name = name;
Password = pass;
Group = group;
}
public User()
{
Address = "";
Name = "";
Password = "";
Group = "";
}
}
[Serializable]
public class UserManagerException : Exception
{
public UserManagerException(string message)
: base(message)
{
}
public UserManagerException(string message, Exception inner)
: base(message, inner)
{
}
}
[Serializable]
public class UserExistsException : UserManagerException
{
public UserExistsException(string name)
: base("User '" + name + "' already exists")
{
}
}
[Serializable]
public class UserNotExistException : UserManagerException
{
public UserNotExistException(string name)
: base("User '" + name + "' does not exist")
{
}
}
[Serializable]
public class GroupNotExistsException : UserManagerException
{
public GroupNotExistsException(string group)
: base("Group '" + group + "' does not exist")
{
}
}
}

View file

@ -27,245 +27,251 @@ using Terraria;
namespace TShockAPI.DB
{
public class WarpManager
{
private IDbConnection database;
public class WarpManager
{
private IDbConnection database;
[SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope")]
public WarpManager(IDbConnection db)
{
database = db;
[SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope")]
public WarpManager(IDbConnection db)
{
database = db;
var table = new SqlTable("Warps",
new SqlColumn("WarpName", MySqlDbType.VarChar, 50) { Primary = true },
new SqlColumn("X", MySqlDbType.Int32),
new SqlColumn("Y", MySqlDbType.Int32),
new SqlColumn("WorldID", MySqlDbType.Text),
new SqlColumn("Private", MySqlDbType.Text)
);
var creator = new SqlTableCreator(db, db.GetSqlType() == SqlType.Sqlite ? (IQueryBuilder)new SqliteQueryCreator() : new MysqlQueryCreator());
creator.EnsureExists(table);
var table = new SqlTable("Warps",
new SqlColumn("WarpName", MySqlDbType.VarChar, 50) {Primary = true},
new SqlColumn("X", MySqlDbType.Int32),
new SqlColumn("Y", MySqlDbType.Int32),
new SqlColumn("WorldID", MySqlDbType.Text),
new SqlColumn("Private", MySqlDbType.Text)
);
var creator = new SqlTableCreator(db,
db.GetSqlType() == SqlType.Sqlite
? (IQueryBuilder) new SqliteQueryCreator()
: new MysqlQueryCreator());
creator.EnsureExists(table);
String file = Path.Combine(TShock.SavePath, "warps.xml");
String name = "";
String world = "";
int x1 = 0;
int y1 = 0;
if (!File.Exists(file))
return;
String file = Path.Combine(TShock.SavePath, "warps.xml");
String name = "";
String world = "";
int x1 = 0;
int y1 = 0;
if (!File.Exists(file))
return;
using (var reader = XmlReader.Create(new StreamReader(file), new XmlReaderSettings { CloseInput = true }))
{
// Parse the file and display each of the nodes.
while (reader.Read())
{
switch (reader.NodeType)
{
case XmlNodeType.Element:
switch (reader.Name)
{
case "Warp":
name = "";
world = "";
x1 = 0;
y1 = 0;
break;
case "WarpName":
while (reader.NodeType != XmlNodeType.Text)
reader.Read();
name = reader.Value;
break;
case "X":
while (reader.NodeType != XmlNodeType.Text)
reader.Read();
int.TryParse(reader.Value, out x1);
break;
case "Y":
while (reader.NodeType != XmlNodeType.Text)
reader.Read();
int.TryParse(reader.Value, out y1);
break;
case "WorldName":
while (reader.NodeType != XmlNodeType.Text)
reader.Read();
world = reader.Value;
break;
}
break;
case XmlNodeType.Text:
using (var reader = XmlReader.Create(new StreamReader(file), new XmlReaderSettings {CloseInput = true}))
{
// Parse the file and display each of the nodes.
while (reader.Read())
{
switch (reader.NodeType)
{
case XmlNodeType.Element:
switch (reader.Name)
{
case "Warp":
name = "";
world = "";
x1 = 0;
y1 = 0;
break;
case "WarpName":
while (reader.NodeType != XmlNodeType.Text)
reader.Read();
name = reader.Value;
break;
case "X":
while (reader.NodeType != XmlNodeType.Text)
reader.Read();
int.TryParse(reader.Value, out x1);
break;
case "Y":
while (reader.NodeType != XmlNodeType.Text)
reader.Read();
int.TryParse(reader.Value, out y1);
break;
case "WorldName":
while (reader.NodeType != XmlNodeType.Text)
reader.Read();
world = reader.Value;
break;
}
break;
case XmlNodeType.Text:
break;
case XmlNodeType.XmlDeclaration:
case XmlNodeType.ProcessingInstruction:
break;
case XmlNodeType.Comment:
break;
case XmlNodeType.EndElement:
if (reader.Name.Equals("Warp"))
{
string query = (TShock.Config.StorageType.ToLower() == "sqlite")
? "INSERT OR IGNORE INTO Warps VALUES (@0, @1,@2, @3);"
: "INSERT IGNORE INTO Warps SET X=@0, Y=@1, WarpName=@2, WorldID=@3;";
database.Query(query, x1, y1, name, world);
}
break;
}
}
break;
case XmlNodeType.XmlDeclaration:
case XmlNodeType.ProcessingInstruction:
break;
case XmlNodeType.Comment:
break;
case XmlNodeType.EndElement:
if (reader.Name.Equals("Warp"))
{
string query = (TShock.Config.StorageType.ToLower() == "sqlite")
? "INSERT OR IGNORE INTO Warps VALUES (@0, @1,@2, @3);"
: "INSERT IGNORE INTO Warps SET X=@0, Y=@1, WarpName=@2, WorldID=@3;";
database.Query(query, x1, y1, name, world);
}
break;
}
}
}
}
String path = Path.Combine(TShock.SavePath, "old_configs");
String file2 = Path.Combine(path, "warps.xml");
if (!Directory.Exists(path))
Directory.CreateDirectory(path);
if (File.Exists(file2))
File.Delete(file2);
File.Move(file, file2);
}
String path = Path.Combine(TShock.SavePath, "old_configs");
String file2 = Path.Combine(path, "warps.xml");
if (!Directory.Exists(path))
Directory.CreateDirectory(path);
if (File.Exists(file2))
File.Delete(file2);
File.Move(file, file2);
}
public void ConvertDB()
{
try
{
database.Query("UPDATE Warps SET WorldID=@0", Main.worldID.ToString());
}
catch (Exception ex)
{
Log.Error(ex.ToString());
}
}
public void ConvertDB()
{
try
{
database.Query("UPDATE Warps SET WorldID=@0", Main.worldID.ToString());
}
catch (Exception ex)
{
Log.Error(ex.ToString());
}
}
public bool AddWarp(int x, int y, string name, string worldid)
{
try
{
database.Query("INSERT INTO Warps (X, Y, WarpName, WorldID) VALUES (@0, @1, @2, @3);", x, y, name, worldid);
return true;
}
catch (Exception ex)
{
Log.Error(ex.ToString());
}
return false;
}
public bool AddWarp(int x, int y, string name, string worldid)
{
try
{
database.Query("INSERT INTO Warps (X, Y, WarpName, WorldID) VALUES (@0, @1, @2, @3);", x, y, name, worldid);
return true;
}
catch (Exception ex)
{
Log.Error(ex.ToString());
}
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 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();
}
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>
/// Gets all the warps names from world
/// </summary>
/// <param name="worldid">World name to get warps from</param>
/// <returns>List of warps with only their names</returns>
public List<Warp> ListAllPublicWarps(string worldid)
{
var warps = new List<Warp>();
try
{
using (var reader = database.QueryReader("SELECT * FROM Warps WHERE WorldID=@0", worldid))
{
while (reader.Read())
{
try
{
if (reader.Get<String>("Private") == "0" || reader.Get<String>("Private") == null)
warps.Add(new Warp {WarpName = reader.Get<string>("WarpName")});
}
catch
{
warps.Add(new Warp {WarpName = reader.Get<string>("WarpName")});
}
}
}
}
catch (Exception ex)
{
Log.Error(ex.ToString());
}
return warps;
}
/// <summary>
/// Gets all the warps names from world
/// </summary>
/// <param name="worldid">World name to get warps from</param>
/// <returns>List of warps with only their names</returns>
public List<Warp> ListAllPublicWarps(string worldid)
{
var warps = new List<Warp>();
try
{
using (var reader = database.QueryReader("SELECT * FROM Warps WHERE WorldID=@0", worldid))
{
while (reader.Read())
{
try
{
if (reader.Get<String>("Private") == "0" || reader.Get<String>("Private") == null)
warps.Add(new Warp { WarpName = reader.Get<string>("WarpName") });
}
catch
{
warps.Add(new Warp { WarpName = reader.Get<string>("WarpName") });
}
}
}
}
catch (Exception ex)
{
Log.Error(ex.ToString());
}
return warps;
}
/// <summary>
/// Gets all the warps names from world
/// </summary>
/// <param name="worldid">World name to get warps from</param>
/// <returns>List of warps with only their names</returns>
public bool HideWarp(string warp, bool state)
{
try
{
string query = "UPDATE Warps SET Private=@0 WHERE WarpName=@1 AND WorldID=@2";
/// <summary>
/// Gets all the warps names from world
/// </summary>
/// <param name="worldid">World name to get warps from</param>
/// <returns>List of warps with only their names</returns>
public bool HideWarp(string warp, bool state)
{
try
{
string query = "UPDATE Warps SET Private=@0 WHERE WarpName=@1 AND WorldID=@2";
database.Query(query, state ? "1" : "0", warp, Main.worldID.ToString());
database.Query(query, state ? "1" : "0", warp, Main.worldID.ToString());
return true;
}
catch (Exception ex)
{
Log.Error(ex.ToString());
return false;
}
}
}
return true;
}
catch (Exception ex)
{
Log.Error(ex.ToString());
return false;
}
}
}
public class Warp
{
public Vector2 WarpPos { get; set; }
public string WarpName { get; set; }
public string WorldWarpID { get; set; }
public string Private { get; set; }
public class Warp
{
public Vector2 WarpPos { get; set; }
public string WarpName { get; set; }
public string WorldWarpID { get; set; }
public string Private { get; set; }
public Warp(Vector2 warppos, string name, string worldid, string hidden)
{
WarpPos = warppos;
WarpName = name;
WorldWarpID = worldid;
Private = hidden;
}
public Warp(Vector2 warppos, string name, string worldid, string hidden)
{
WarpPos = warppos;
WarpName = name;
WorldWarpID = worldid;
Private = hidden;
}
public Warp()
{
WarpPos = Vector2.Zero;
WarpName = null;
WorldWarpID = string.Empty;
Private = "0";
}
}
}
public Warp()
{
WarpPos = Vector2.Zero;
WarpName = null;
WorldWarpID = string.Empty;
Private = "0";
}
}
}

View file

@ -5,183 +5,214 @@ using System.Diagnostics.CodeAnalysis;
namespace TShockAPI.DB
{
public static class DbExt
{
public static class DbExt
{
/// <summary>
/// Executes a query on a database.
/// </summary>
/// <param name="olddb">Database to query</param>
/// <param name="query">Query string with parameters as @0, @1, etc.</param>
/// <param name="args">Parameters to be put in the query</param>
/// <returns>Rows affected by query</returns>
[SuppressMessage("Microsoft.Security", "CA2100:Review SQL queries for security vulnerabilities")]
public static int Query(this IDbConnection olddb, string query, params object[] args)
{
using (var db = olddb.CloneEx())
{
db.Open();
using (var com = db.CreateCommand())
{
com.CommandText = query;
for (int i = 0; i < args.Length; i++)
com.AddParameter("@" + i, args[i]);
/// <summary>
/// Executes a query on a database.
/// </summary>
/// <param name="olddb">Database to query</param>
/// <param name="query">Query string with parameters as @0, @1, etc.</param>
/// <param name="args">Parameters to be put in the query</param>
/// <returns>Rows affected by query</returns>
[SuppressMessage("Microsoft.Security", "CA2100:Review SQL queries for security vulnerabilities")]
public static int Query(this IDbConnection olddb, string query, params object[] args)
{
using (var db = olddb.CloneEx())
{
db.Open();
using (var com = db.CreateCommand())
{
com.CommandText = query;
for (int i = 0; i < args.Length; i++)
com.AddParameter("@" + i, args[i]);
return com.ExecuteNonQuery();
}
}
}
return com.ExecuteNonQuery();
}
}
}
/// <summary>
/// Executes a query on a database.
/// </summary>
/// <param name="olddb">Database to query</param>
/// <param name="query">Query string with parameters as @0, @1, etc.</param>
/// <param name="args">Parameters to be put in the query</param>
/// <returns>Query result as IDataReader</returns>
[SuppressMessage("Microsoft.Security", "CA2100:Review SQL queries for security vulnerabilities")]
public static QueryResult QueryReader(this IDbConnection olddb, string query, params object[] args)
{
var db = olddb.CloneEx();
db.Open();
using (var com = db.CreateCommand())
{
com.CommandText = query;
for (int i = 0; i < args.Length; i++)
com.AddParameter("@" + i, args[i]);
/// <summary>
/// Executes a query on a database.
/// </summary>
/// <param name="olddb">Database to query</param>
/// <param name="query">Query string with parameters as @0, @1, etc.</param>
/// <param name="args">Parameters to be put in the query</param>
/// <returns>Query result as IDataReader</returns>
[SuppressMessage("Microsoft.Security", "CA2100:Review SQL queries for security vulnerabilities")]
public static QueryResult QueryReader(this IDbConnection olddb, string query, params object[] args)
{
var db = olddb.CloneEx();
db.Open();
using (var com = db.CreateCommand())
{
com.CommandText = query;
for (int i = 0; i < args.Length; i++)
com.AddParameter("@" + i, args[i]);
return new QueryResult(db, com.ExecuteReader());
}
}
return new QueryResult(db, com.ExecuteReader());
}
}
public static QueryResult QueryReaderDict(this IDbConnection olddb, string query, Dictionary<string, object> values)
{
var db = olddb.CloneEx();
db.Open();
using (var com = db.CreateCommand())
{
com.CommandText = query;
foreach(var kv in values)
com.AddParameter("@" + kv.Key, kv.Value);
public static QueryResult QueryReaderDict(this IDbConnection olddb, string query, Dictionary<string, object> values)
{
var db = olddb.CloneEx();
db.Open();
using (var com = db.CreateCommand())
{
com.CommandText = query;
foreach (var kv in values)
com.AddParameter("@" + kv.Key, kv.Value);
return new QueryResult(db, com.ExecuteReader());
}
}
return new QueryResult(db, com.ExecuteReader());
}
}
public static IDbDataParameter AddParameter(this IDbCommand command, string name, object data)
{
var parm = command.CreateParameter();
parm.ParameterName = name;
parm.Value = data;
command.Parameters.Add(parm);
return parm;
}
public static IDbDataParameter AddParameter(this IDbCommand command, string name, object data)
{
var parm = command.CreateParameter();
parm.ParameterName = name;
parm.Value = data;
command.Parameters.Add(parm);
return parm;
}
public static IDbConnection CloneEx(this IDbConnection conn)
{
var clone = (IDbConnection)Activator.CreateInstance(conn.GetType());
clone.ConnectionString = conn.ConnectionString;
return clone;
}
public static IDbConnection CloneEx(this IDbConnection conn)
{
var clone = (IDbConnection) Activator.CreateInstance(conn.GetType());
clone.ConnectionString = conn.ConnectionString;
return clone;
}
public static SqlType GetSqlType(this IDbConnection conn)
{
var name = conn.GetType().Name;
if (name == "SqliteConnection")
return SqlType.Sqlite;
if (name == "MySqlConnection")
return SqlType.Mysql;
return SqlType.Unknown;
}
public static SqlType GetSqlType(this IDbConnection conn)
{
var name = conn.GetType().Name;
if (name == "SqliteConnection")
return SqlType.Sqlite;
if (name == "MySqlConnection")
return SqlType.Mysql;
return SqlType.Unknown;
}
static readonly Dictionary<Type, Func<IDataReader, int, object>> ReadFuncs = new Dictionary<Type, Func<IDataReader, int, object>>
{
{typeof(bool), (s, i) => s.GetBoolean(i)},
{typeof(byte), (s, i) => s.GetByte(i)},
{typeof(Int16), (s, i) => s.GetInt16(i)},
{typeof(Int32), (s, i) => s.GetInt32(i)},
{typeof(Int64), (s, i) => s.GetInt64(i)},
{typeof(string), (s, i) => s.GetString(i)},
{typeof(decimal), (s, i) => s.GetDecimal(i)},
{typeof(float), (s, i) => s.GetFloat(i)},
{typeof(double), (s, i) => s.GetDouble(i)},
{typeof(object), (s, i) => s.GetValue(i)},
};
private static readonly Dictionary<Type, Func<IDataReader, int, object>> ReadFuncs = new Dictionary
<Type, Func<IDataReader, int, object>>
{
{
typeof (bool),
(s, i) => s.GetBoolean(i)
},
{
typeof (byte),
(s, i) => s.GetByte(i)
},
{
typeof (Int16),
(s, i) => s.GetInt16(i)
},
{
typeof (Int32),
(s, i) => s.GetInt32(i)
},
{
typeof (Int64),
(s, i) => s.GetInt64(i)
},
{
typeof (string),
(s, i) => s.GetString(i)
},
{
typeof (decimal),
(s, i) => s.GetDecimal(i)
},
{
typeof (float),
(s, i) => s.GetFloat(i)
},
{
typeof (double),
(s, i) => s.GetDouble(i)
},
{
typeof (object),
(s, i) => s.GetValue(i)
},
};
public static T Get<T>(this IDataReader reader, string column)
{
return reader.Get<T>(reader.GetOrdinal(column));
}
public static T Get<T>(this IDataReader reader, string column)
{
return reader.Get<T>(reader.GetOrdinal(column));
}
public static T Get<T>(this IDataReader reader, int column)
{
if (reader.IsDBNull(column))
return default(T);
public static T Get<T>(this IDataReader reader, int column)
{
if (reader.IsDBNull(column))
return default(T);
if (ReadFuncs.ContainsKey(typeof(T)))
return (T)ReadFuncs[typeof(T)](reader, column);
if (ReadFuncs.ContainsKey(typeof (T)))
return (T) ReadFuncs[typeof (T)](reader, column);
throw new NotImplementedException();
}
}
throw new NotImplementedException();
}
}
public enum SqlType
{
Unknown,
Sqlite,
Mysql
}
public enum SqlType
{
Unknown,
Sqlite,
Mysql
}
public class QueryResult : IDisposable
{
public IDbConnection Connection { get; protected set; }
public IDataReader Reader { get; protected set; }
public class QueryResult : IDisposable
{
public IDbConnection Connection { get; protected set; }
public IDataReader Reader { get; protected set; }
public QueryResult(IDbConnection conn, IDataReader reader)
{
Connection = conn;
Reader = reader;
}
public QueryResult(IDbConnection conn, IDataReader reader)
{
Connection = conn;
Reader = reader;
}
~QueryResult()
{
Dispose(false);
}
~QueryResult()
{
Dispose(false);
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
if (Reader != null)
{
Reader.Dispose();
Reader = null;
}
if (Connection != null)
{
Connection.Dispose();
Connection = null;
}
}
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
if (Reader != null)
{
Reader.Dispose();
Reader = null;
}
if (Connection != null)
{
Connection.Dispose();
Connection = null;
}
}
}
public bool Read()
{
if (Reader == null)
return false;
return Reader.Read();
}
public T Get<T>(string column)
{
if (Reader == null)
return default(T);
return Reader.Get<T>(Reader.GetOrdinal(column));
}
}
public bool Read()
{
if (Reader == null)
return false;
return Reader.Read();
}
}
public T Get<T>(string column)
{
if (Reader == null)
return default(T);
return Reader.Get<T>(Reader.GetOrdinal(column));
}
}
}

View file

@ -3,15 +3,15 @@ using System.Collections.Generic;
namespace TShockAPI
{
public static class LinqExt
{
public static void ForEach<T>(this IEnumerable<T> source, Action<T> action)
{
if (source == null) throw new ArgumentNullException("source");
if (action == null) throw new ArgumentNullException("action");
public static class LinqExt
{
public static void ForEach<T>(this IEnumerable<T> source, Action<T> action)
{
if (source == null) throw new ArgumentNullException("source");
if (action == null) throw new ArgumentNullException("action");
foreach (T item in source)
action(item);
}
}
}
foreach (T item in source)
action(item);
}
}
}

View file

@ -3,27 +3,27 @@ using System.Text;
namespace TShockAPI.Extensions
{
public static class RandomExt
{
public static string NextString(this Random rand, int length)
{
var sb = new StringBuilder();
for (int i = 0; i < length; i++)
{
switch (rand.Next(0, 3))
{
case 0:
sb.Append((char)rand.Next('a', 'z' + 1));
break;
case 1:
sb.Append((char)rand.Next('A', 'Z' + 1));
break;
case 2:
sb.Append((char)rand.Next('0', '9' + 1));
break;
}
}
return sb.ToString();
}
}
}
public static class RandomExt
{
public static string NextString(this Random rand, int length)
{
var sb = new StringBuilder();
for (int i = 0; i < length; i++)
{
switch (rand.Next(0, 3))
{
case 0:
sb.Append((char) rand.Next('a', 'z' + 1));
break;
case 1:
sb.Append((char) rand.Next('A', 'Z' + 1));
break;
case 2:
sb.Append((char) rand.Next('0', '9' + 1));
break;
}
}
return sb.ToString();
}
}
}

View file

@ -2,12 +2,12 @@
namespace TShockAPI
{
public static class StringExt
{
//Can't name it Format :(
public static String SFormat(this String str, params object[] args)
{
return String.Format(str, args);
}
}
}
public static class StringExt
{
//Can't name it Format :(
public static String SFormat(this String str, params object[] args)
{
return String.Format(str, args);
}
}
}

View file

@ -20,93 +20,111 @@ using System.IO;
namespace TShockAPI
{
public class FileTools
{
internal static string RulesPath { get { return Path.Combine(TShock.SavePath, "rules.txt"); } }
internal static string MotdPath { get { return Path.Combine(TShock.SavePath, "motd.txt"); } }
internal static string WhitelistPath { get { return Path.Combine(TShock.SavePath, "whitelist.txt"); } }
internal static string RememberedPosPath { get { return Path.Combine(TShock.SavePath, "oldpos.xml"); } }
internal static string ConfigPath { get { return Path.Combine(TShock.SavePath, "config.json"); } }
public class FileTools
{
internal static string RulesPath
{
get { return Path.Combine(TShock.SavePath, "rules.txt"); }
}
public static void CreateFile(string file)
{
File.Create(file).Close();
}
internal static string MotdPath
{
get { return Path.Combine(TShock.SavePath, "motd.txt"); }
}
public static void CreateIfNot(string file, string data = "")
{
if (!File.Exists(file))
{
File.WriteAllText(file, data);
}
}
internal static string WhitelistPath
{
get { return Path.Combine(TShock.SavePath, "whitelist.txt"); }
}
/// <summary>
/// Sets up the configuration file for all variables, and creates any missing files.
/// </summary>
public static void SetupConfig()
{
if (!Directory.Exists(TShock.SavePath))
{
Directory.CreateDirectory(TShock.SavePath);
}
internal static string RememberedPosPath
{
get { return Path.Combine(TShock.SavePath, "oldpos.xml"); }
}
CreateIfNot(RulesPath, "Respect the admins!\nDon't use TNT!");
CreateIfNot(MotdPath, "This server is running TShock. Type /help for a list of commands.\n%255,000,000%Current map: %map%\nCurrent players: %players%");
CreateIfNot(WhitelistPath);
internal static string ConfigPath
{
get { return Path.Combine(TShock.SavePath, "config.json"); }
}
try
{
if (File.Exists(ConfigPath))
{
TShock.Config = ConfigFile.Read(ConfigPath);
// Add all the missing config properties in the json file
}
TShock.Config.Write(ConfigPath);
}
catch (Exception ex)
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine("Error in config file");
Console.ForegroundColor = ConsoleColor.Gray;
Log.Error("Config Exception");
Log.Error(ex.ToString());
}
public static void CreateFile(string file)
{
File.Create(file).Close();
}
public static void CreateIfNot(string file, string data = "")
{
if (!File.Exists(file))
{
File.WriteAllText(file, data);
}
}
}
/// <summary>
/// Sets up the configuration file for all variables, and creates any missing files.
/// </summary>
public static void SetupConfig()
{
if (!Directory.Exists(TShock.SavePath))
{
Directory.CreateDirectory(TShock.SavePath);
}
/// <summary>
/// Tells if a user is on the whitelist
/// </summary>
/// <param name="ip">string ip of the user</param>
/// <returns>true/false</returns>
public static bool OnWhitelist(string ip)
{
if (!TShock.Config.EnableWhitelist)
{
return true;
}
CreateIfNot(WhitelistPath, "127.0.0.1");
using (var tr = new StreamReader(WhitelistPath))
{
string whitelist = tr.ReadToEnd();
ip = TShock.Utils.GetRealIP(ip);
bool contains = whitelist.Contains(ip);
if (!contains)
{
foreach (var line in whitelist.Split(Environment.NewLine.ToCharArray()))
{
if (string.IsNullOrWhiteSpace(line))
continue;
contains = TShock.Utils.GetIPv4Address(line).Equals(ip);
if (contains)
return true;
}
return false;
}
return true;
}
}
}
CreateIfNot(RulesPath, "Respect the admins!\nDon't use TNT!");
CreateIfNot(MotdPath,
"This server is running TShock. Type /help for a list of commands.\n%255,000,000%Current map: %map%\nCurrent players: %players%");
CreateIfNot(WhitelistPath);
try
{
if (File.Exists(ConfigPath))
{
TShock.Config = ConfigFile.Read(ConfigPath);
// Add all the missing config properties in the json file
}
TShock.Config.Write(ConfigPath);
}
catch (Exception ex)
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine("Error in config file");
Console.ForegroundColor = ConsoleColor.Gray;
Log.Error("Config Exception");
Log.Error(ex.ToString());
}
}
/// <summary>
/// Tells if a user is on the whitelist
/// </summary>
/// <param name="ip">string ip of the user</param>
/// <returns>true/false</returns>
public static bool OnWhitelist(string ip)
{
if (!TShock.Config.EnableWhitelist)
{
return true;
}
CreateIfNot(WhitelistPath, "127.0.0.1");
using (var tr = new StreamReader(WhitelistPath))
{
string whitelist = tr.ReadToEnd();
ip = TShock.Utils.GetRealIP(ip);
bool contains = whitelist.Contains(ip);
if (!contains)
{
foreach (var line in whitelist.Split(Environment.NewLine.ToCharArray()))
{
if (string.IsNullOrWhiteSpace(line))
continue;
contains = TShock.Utils.GetIPv4Address(line).Equals(ip);
if (contains)
return true;
}
return false;
}
return true;
}
}
}
}

View file

@ -27,234 +27,290 @@ using System.Net.Sockets;
namespace MaxMind
{
/// <summary>
/// Allows for looking up a country based on an IP address. See www.maxmind.com for more details.
/// </summary>
/// <example>
/// static void Main(string[] args)
/// {
/// using(GeoIPCountry geo = new GeoIPCountry("GeoIP.dat"))
/// {
/// try
/// {
/// Console.WriteLine("Country code of IP address 67.15.94.80: " + geo.GetCountryCode("67.15.94.80"));
/// }
/// catch(Exception ex)
/// {
/// Console.WriteLine(ex.ToString());
/// }
/// }
/// }
/// </example>
public sealed class GeoIPCountry : IDisposable
{
Stream _geodata;
bool _close;
/// <summary>
/// Allows for looking up a country based on an IP address. See www.maxmind.com for more details.
/// </summary>
/// <example>
/// static void Main(string[] args)
/// {
/// using(GeoIPCountry geo = new GeoIPCountry("GeoIP.dat"))
/// {
/// try
/// {
/// Console.WriteLine("Country code of IP address 67.15.94.80: " + geo.GetCountryCode("67.15.94.80"));
/// }
/// catch(Exception ex)
/// {
/// Console.WriteLine(ex.ToString());
/// }
/// }
/// }
/// </example>
public sealed class GeoIPCountry : IDisposable
{
private Stream _geodata;
private bool _close;
// hard coded position of where country data starts in the data file.
const long COUNTRY_BEGIN = 16776960;
// hard coded position of where country data starts in the data file.
private const long COUNTRY_BEGIN = 16776960;
static readonly string[] CountryCodes = {
"--","AP","EU","AD","AE","AF","AG","AI","AL","AM","AN","AO","AQ","AR","AS",
"AT","AU","AW","AZ","BA","BB","BD","BE","BF","BG","BH","BI","BJ","BM","BN",
"BO","BR","BS","BT","BV","BW","BY","BZ","CA","CC","CD","CF","CG","CH","CI",
"CK","CL","CM","CN","CO","CR","CU","CV","CX","CY","CZ","DE","DJ","DK","DM",
"DO","DZ","EC","EE","EG","EH","ER","ES","ET","FI","FJ","FK","FM","FO","FR",
"FX","GA","GB","GD","GE","GF","GH","GI","GL","GM","GN","GP","GQ","GR","GS",
"GT","GU","GW","GY","HK","HM","HN","HR","HT","HU","ID","IE","IL","IN","IO",
"IQ","IR","IS","IT","JM","JO","JP","KE","KG","KH","KI","KM","KN","KP","KR",
"KW","KY","KZ","LA","LB","LC","LI","LK","LR","LS","LT","LU","LV","LY","MA",
"MC","MD","MG","MH","MK","ML","MM","MN","MO","MP","MQ","MR","MS","MT","MU",
"MV","MW","MX","MY","MZ","NA","NC","NE","NF","NG","NI","NL","NO","NP","NR",
"NU","NZ","OM","PA","PE","PF","PG","PH","PK","PL","PM","PN","PR","PS","PT",
"PW","PY","QA","RE","RO","RU","RW","SA","SB","SC","SD","SE","SG","SH","SI",
"SJ","SK","SL","SM","SN","SO","SR","ST","SV","SY","SZ","TC","TD","TF","TG",
"TH","TJ","TK","TM","TN","TO","TL","TR","TT","TV","TW","TZ","UA","UG","UM",
"US","UY","UZ","VA","VC","VE","VG","VI","VN","VU","WF","WS","YE","YT","RS",
"ZA","ZM","ME","ZW","A1","A2","O1","AX","GG","IM","JE","BL","MF"
};
private static readonly string[] CountryCodes = {
"--", "AP", "EU", "AD", "AE", "AF", "AG", "AI", "AL", "AM", "AN",
"AO", "AQ", "AR", "AS",
"AT", "AU", "AW", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH",
"BI", "BJ", "BM", "BN",
"BO", "BR", "BS", "BT", "BV", "BW", "BY", "BZ", "CA", "CC", "CD",
"CF", "CG", "CH", "CI",
"CK", "CL", "CM", "CN", "CO", "CR", "CU", "CV", "CX", "CY", "CZ",
"DE", "DJ", "DK", "DM",
"DO", "DZ", "EC", "EE", "EG", "EH", "ER", "ES", "ET", "FI", "FJ",
"FK", "FM", "FO", "FR",
"FX", "GA", "GB", "GD", "GE", "GF", "GH", "GI", "GL", "GM", "GN",
"GP", "GQ", "GR", "GS",
"GT", "GU", "GW", "GY", "HK", "HM", "HN", "HR", "HT", "HU", "ID",
"IE", "IL", "IN", "IO",
"IQ", "IR", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI",
"KM", "KN", "KP", "KR",
"KW", "KY", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT",
"LU", "LV", "LY", "MA",
"MC", "MD", "MG", "MH", "MK", "ML", "MM", "MN", "MO", "MP", "MQ",
"MR", "MS", "MT", "MU",
"MV", "MW", "MX", "MY", "MZ", "NA", "NC", "NE", "NF", "NG", "NI",
"NL", "NO", "NP", "NR",
"NU", "NZ", "OM", "PA", "PE", "PF", "PG", "PH", "PK", "PL", "PM",
"PN", "PR", "PS", "PT",
"PW", "PY", "QA", "RE", "RO", "RU", "RW", "SA", "SB", "SC", "SD",
"SE", "SG", "SH", "SI",
"SJ", "SK", "SL", "SM", "SN", "SO", "SR", "ST", "SV", "SY", "SZ",
"TC", "TD", "TF", "TG",
"TH", "TJ", "TK", "TM", "TN", "TO", "TL", "TR", "TT", "TV", "TW",
"TZ", "UA", "UG", "UM",
"US", "UY", "UZ", "VA", "VC", "VE", "VG", "VI", "VN", "VU", "WF",
"WS", "YE", "YT", "RS",
"ZA", "ZM", "ME", "ZW", "A1", "A2", "O1", "AX", "GG", "IM", "JE",
"BL", "MF"
};
static readonly string[] CountryNames = {
"N/A","Asia/Pacific Region","Europe","Andorra","United Arab Emirates","Afghanistan",
"Antigua and Barbuda","Anguilla","Albania","Armenia","Netherlands Antilles","Angola",
"Antarctica","Argentina","American Samoa","Austria","Australia","Aruba","Azerbaijan",
"Bosnia and Herzegovina","Barbados","Bangladesh","Belgium","Burkina Faso","Bulgaria",
"Bahrain","Burundi","Benin","Bermuda","Brunei Darussalam","Bolivia","Brazil","Bahamas",
"Bhutan","Bouvet Island","Botswana","Belarus","Belize","Canada","Cocos (Keeling) Islands",
"Congo, The Democratic Republic of the","Central African Republic","Congo","Switzerland",
"Cote D'Ivoire","Cook Islands","Chile","Cameroon","China","Colombia","Costa Rica","Cuba",
"Cape Verde","Christmas Island","Cyprus","Czech Republic","Germany","Djibouti","Denmark",
"Dominica","Dominican Republic","Algeria","Ecuador","Estonia","Egypt","Western Sahara",
"Eritrea","Spain","Ethiopia","Finland","Fiji","Falkland Islands (Malvinas)",
"Micronesia, Federated States of","Faroe Islands","France","France, Metropolitan","Gabon",
"United Kingdom","Grenada","Georgia","French Guiana","Ghana","Gibraltar","Greenland",
"Gambia","Guinea","Guadeloupe","Equatorial Guinea","Greece",
"South Georgia and the South Sandwich Islands","Guatemala","Guam","Guinea-Bissau","Guyana",
"Hong Kong","Heard Island and McDonald Islands","Honduras","Croatia","Haiti","Hungary",
"Indonesia","Ireland","Israel","India","British Indian Ocean Territory","Iraq",
"Iran, Islamic Republic of","Iceland","Italy","Jamaica","Jordan","Japan","Kenya",
"Kyrgyzstan","Cambodia","Kiribati","Comoros","Saint Kitts and Nevis",
"Korea, Democratic People's Republic of","Korea, Republic of","Kuwait","Cayman Islands",
"Kazakstan","Lao People's Democratic Republic","Lebanon","Saint Lucia","Liechtenstein",
"Sri Lanka","Liberia","Lesotho","Lithuania","Luxembourg","Latvia","Libyan Arab Jamahiriya",
"Morocco","Monaco","Moldova, Republic of","Madagascar","Marshall Islands","Macedonia",
"Mali","Myanmar","Mongolia","Macau","Northern Mariana Islands","Martinique","Mauritania",
"Montserrat","Malta","Mauritius","Maldives","Malawi","Mexico","Malaysia","Mozambique",
"Namibia","New Caledonia","Niger","Norfolk Island","Nigeria","Nicaragua","Netherlands",
"Norway","Nepal","Nauru","Niue","New Zealand","Oman","Panama","Peru","French Polynesia",
"Papua New Guinea","Philippines","Pakistan","Poland","Saint Pierre and Miquelon",
"Pitcairn Islands","Puerto Rico","Palestinian Territory","Portugal","Palau","Paraguay",
"Qatar","Reunion","Romania","Russian Federation","Rwanda","Saudi Arabia",
"Solomon Islands","Seychelles","Sudan","Sweden","Singapore","Saint Helena","Slovenia",
"Svalbard and Jan Mayen","Slovakia","Sierra Leone","San Marino","Senegal","Somalia",
"Suriname","Sao Tome and Principe","El Salvador","Syrian Arab Republic","Swaziland",
"Turks and Caicos Islands","Chad","French Southern Territories","Togo","Thailand",
"Tajikistan","Tokelau","Turkmenistan","Tunisia","Tonga","Timor-Leste","Turkey",
"Trinidad and Tobago","Tuvalu","Taiwan","Tanzania, United Republic of","Ukraine","Uganda",
"United States Minor Outlying Islands","United States","Uruguay","Uzbekistan",
"Holy See (Vatican City State)","Saint Vincent and the Grenadines","Venezuela",
"Virgin Islands, British","Virgin Islands, U.S.","Vietnam","Vanuatu","Wallis and Futuna",
"Samoa","Yemen","Mayotte","Serbia","South Africa","Zambia","Montenegro","Zimbabwe",
"Anonymous Proxy","Satellite Provider","Other","Aland Islands","Guernsey","Isle of Man",
"Jersey","Saint Barthelemy","Saint Martin"
};
private static readonly string[] CountryNames = {
"N/A", "Asia/Pacific Region", "Europe", "Andorra",
"United Arab Emirates", "Afghanistan",
"Antigua and Barbuda", "Anguilla", "Albania", "Armenia",
"Netherlands Antilles", "Angola",
"Antarctica", "Argentina", "American Samoa", "Austria", "Australia",
"Aruba", "Azerbaijan",
"Bosnia and Herzegovina", "Barbados", "Bangladesh", "Belgium",
"Burkina Faso", "Bulgaria",
"Bahrain", "Burundi", "Benin", "Bermuda", "Brunei Darussalam",
"Bolivia", "Brazil", "Bahamas",
"Bhutan", "Bouvet Island", "Botswana", "Belarus", "Belize", "Canada",
"Cocos (Keeling) Islands",
"Congo, The Democratic Republic of the", "Central African Republic",
"Congo", "Switzerland",
"Cote D'Ivoire", "Cook Islands", "Chile", "Cameroon", "China",
"Colombia", "Costa Rica", "Cuba",
"Cape Verde", "Christmas Island", "Cyprus", "Czech Republic",
"Germany", "Djibouti", "Denmark",
"Dominica", "Dominican Republic", "Algeria", "Ecuador", "Estonia",
"Egypt", "Western Sahara",
"Eritrea", "Spain", "Ethiopia", "Finland", "Fiji",
"Falkland Islands (Malvinas)",
"Micronesia, Federated States of", "Faroe Islands", "France",
"France, Metropolitan", "Gabon",
"United Kingdom", "Grenada", "Georgia", "French Guiana", "Ghana",
"Gibraltar", "Greenland",
"Gambia", "Guinea", "Guadeloupe", "Equatorial Guinea", "Greece",
"South Georgia and the South Sandwich Islands", "Guatemala", "Guam",
"Guinea-Bissau", "Guyana",
"Hong Kong", "Heard Island and McDonald Islands", "Honduras",
"Croatia", "Haiti", "Hungary",
"Indonesia", "Ireland", "Israel", "India",
"British Indian Ocean Territory", "Iraq",
"Iran, Islamic Republic of", "Iceland", "Italy", "Jamaica", "Jordan",
"Japan", "Kenya",
"Kyrgyzstan", "Cambodia", "Kiribati", "Comoros",
"Saint Kitts and Nevis",
"Korea, Democratic People's Republic of", "Korea, Republic of",
"Kuwait", "Cayman Islands",
"Kazakstan", "Lao People's Democratic Republic", "Lebanon",
"Saint Lucia", "Liechtenstein",
"Sri Lanka", "Liberia", "Lesotho", "Lithuania", "Luxembourg",
"Latvia", "Libyan Arab Jamahiriya",
"Morocco", "Monaco", "Moldova, Republic of", "Madagascar",
"Marshall Islands", "Macedonia",
"Mali", "Myanmar", "Mongolia", "Macau", "Northern Mariana Islands",
"Martinique", "Mauritania",
"Montserrat", "Malta", "Mauritius", "Maldives", "Malawi", "Mexico",
"Malaysia", "Mozambique",
"Namibia", "New Caledonia", "Niger", "Norfolk Island", "Nigeria",
"Nicaragua", "Netherlands",
"Norway", "Nepal", "Nauru", "Niue", "New Zealand", "Oman", "Panama",
"Peru", "French Polynesia",
"Papua New Guinea", "Philippines", "Pakistan", "Poland",
"Saint Pierre and Miquelon",
"Pitcairn Islands", "Puerto Rico", "Palestinian Territory",
"Portugal", "Palau", "Paraguay",
"Qatar", "Reunion", "Romania", "Russian Federation", "Rwanda",
"Saudi Arabia",
"Solomon Islands", "Seychelles", "Sudan", "Sweden", "Singapore",
"Saint Helena", "Slovenia",
"Svalbard and Jan Mayen", "Slovakia", "Sierra Leone", "San Marino",
"Senegal", "Somalia",
"Suriname", "Sao Tome and Principe", "El Salvador",
"Syrian Arab Republic", "Swaziland",
"Turks and Caicos Islands", "Chad", "French Southern Territories",
"Togo", "Thailand",
"Tajikistan", "Tokelau", "Turkmenistan", "Tunisia", "Tonga",
"Timor-Leste", "Turkey",
"Trinidad and Tobago", "Tuvalu", "Taiwan",
"Tanzania, United Republic of", "Ukraine", "Uganda",
"United States Minor Outlying Islands", "United States", "Uruguay",
"Uzbekistan",
"Holy See (Vatican City State)", "Saint Vincent and the Grenadines",
"Venezuela",
"Virgin Islands, British", "Virgin Islands, U.S.", "Vietnam",
"Vanuatu", "Wallis and Futuna",
"Samoa", "Yemen", "Mayotte", "Serbia", "South Africa", "Zambia",
"Montenegro", "Zimbabwe",
"Anonymous Proxy", "Satellite Provider", "Other", "Aland Islands",
"Guernsey", "Isle of Man",
"Jersey", "Saint Barthelemy", "Saint Martin"
};
//
// Constructor
//
//
// Constructor
//
/// <summary>
/// Initialises a new instance of this class.
/// </summary>
/// <param name="datafile">An already open stream pointing to the contents of a GeoIP.dat file.</param>
/// <remarks>The stream is not closed when this class is disposed. Be sure to clean up afterwards!</remarks>
public GeoIPCountry(Stream datafile)
{
_geodata = datafile;
_close = false;
}
/// <summary>
/// Initialises a new instance of this class.
/// </summary>
/// <param name="datafile">An already open stream pointing to the contents of a GeoIP.dat file.</param>
/// <remarks>The stream is not closed when this class is disposed. Be sure to clean up afterwards!</remarks>
public GeoIPCountry(Stream datafile)
{
_geodata = datafile;
_close = false;
}
/// <summary>
/// Initialises a new instance of this class, using an on-disk database.
/// </summary>
/// <param name="filename">Path to database file.</param>
/// <remarks>The file will be closed when this class is disposed.</remarks>
public GeoIPCountry(string filename)
{
FileStream fs = new FileStream(filename, FileMode.Open);
_geodata = fs;
_close = true;
}
/// <summary>
/// Initialises a new instance of this class, using an on-disk database.
/// </summary>
/// <param name="filename">Path to database file.</param>
/// <remarks>The file will be closed when this class is disposed.</remarks>
public GeoIPCountry(string filename)
{
FileStream fs = new FileStream(filename, FileMode.Open);
_geodata = fs;
_close = true;
}
/// <summary>
/// Retrieves a two-letter code, defined by MaxMind, which details the country the specified IP address is located.
/// </summary>
/// <param name="ip">IP address to query.</param>
/// <returns>A two-letter code string. Throws exceptions on failure.</returns>
/// <remarks>The IP address must be IPv4.</remarks>
public string GetCountryCode(IPAddress ip)
{
return CountryCodes[FindIndex(ip)];
}
/// <summary>
/// Retrieves a two-letter code, defined by MaxMind, which details the country the specified IP address is located.
/// </summary>
/// <param name="ip">IP address to query.</param>
/// <returns>A two-letter code string. Throws exceptions on failure.</returns>
/// <remarks>The IP address must be IPv4.</remarks>
public string GetCountryCode(IPAddress ip)
{
return CountryCodes[FindIndex(ip)];
}
/// <summary>
/// Retrieves a two-letter code, defined by MaxMind, which details the country the specified IP address is located. Does not throw exceptions on failure.
/// </summary>
/// <param name="ip">IP address to query.</param>
/// <returns>Two-letter country code or null on failure.</returns>
public string TryGetCountryCode(IPAddress ip)
{
try
{
return CountryCodes[FindIndex(ip)];
}
catch (Exception)
{
return null;
}
}
/// <summary>
/// Retrieves a two-letter code, defined by MaxMind, which details the country the specified IP address is located. Does not throw exceptions on failure.
/// </summary>
/// <param name="ip">IP address to query.</param>
/// <returns>Two-letter country code or null on failure.</returns>
public string TryGetCountryCode(IPAddress ip)
{
try
{
return CountryCodes[FindIndex(ip)];
}
catch (Exception)
{
return null;
}
}
/// <summary>
/// Gets the English name of a country, by a country code.
/// </summary>
/// <param name="countrycode">Country code to look up, returned by GetCountryCode or TryGetCountryCode.</param>
/// <returns>English name of the country, or null on failure.</returns>
public static string GetCountryNameByCode(string countrycode)
{
int index = Array.IndexOf(CountryCodes, countrycode);
return index == -1 ? null : CountryNames[index];
}
/// <summary>
/// Gets the English name of a country, by a country code.
/// </summary>
/// <param name="countrycode">Country code to look up, returned by GetCountryCode or TryGetCountryCode.</param>
/// <returns>English name of the country, or null on failure.</returns>
public static string GetCountryNameByCode(string countrycode)
{
int index = Array.IndexOf(CountryCodes, countrycode);
return index == -1 ? null : CountryNames[index];
}
int FindIndex(IPAddress ip)
{
return (int)FindCountryCode(0, AddressToLong(ip), 31);
}
private int FindIndex(IPAddress ip)
{
return (int) FindCountryCode(0, AddressToLong(ip), 31);
}
// Converts an IPv4 address into a long, for reading from geo database
long AddressToLong(IPAddress ip)
{
if (ip.AddressFamily != AddressFamily.InterNetwork)
throw new InvalidOperationException("IP address is not IPv4");
// Converts an IPv4 address into a long, for reading from geo database
private long AddressToLong(IPAddress ip)
{
if (ip.AddressFamily != AddressFamily.InterNetwork)
throw new InvalidOperationException("IP address is not IPv4");
long num = 0;
byte[] bytes = ip.GetAddressBytes();
for (int i = 0; i < 4; ++i)
{
long y = bytes[i];
if (y < 0)
y += 256;
num += y << ((3 - i) * 8);
}
long num = 0;
byte[] bytes = ip.GetAddressBytes();
for (int i = 0; i < 4; ++i)
{
long y = bytes[i];
if (y < 0)
y += 256;
num += y << ((3 - i)*8);
}
return num;
}
return num;
}
// Traverses the GeoIP binary data looking for a country code based
// on the IP address mask
long FindCountryCode(long offset, long ipnum, int depth)
{
byte[] buffer = new byte[6]; // 2 * MAX_RECORD_LENGTH
long[] x = new long[2];
if (depth < 0)
throw new IOException("Cannot seek GeoIP database");
// Traverses the GeoIP binary data looking for a country code based
// on the IP address mask
private long FindCountryCode(long offset, long ipnum, int depth)
{
byte[] buffer = new byte[6]; // 2 * MAX_RECORD_LENGTH
long[] x = new long[2];
if (depth < 0)
throw new IOException("Cannot seek GeoIP database");
_geodata.Seek(6 * offset, SeekOrigin.Begin);
_geodata.Read(buffer, 0, 6);
_geodata.Seek(6*offset, SeekOrigin.Begin);
_geodata.Read(buffer, 0, 6);
for (int i = 0; i < 2; i++)
{
x[i] = 0;
for (int j = 0; j < 3; j++)
{
int y = buffer[i * 3 + j];
if (y < 0)
y += 256;
x[i] += (y << (j * 8));
}
}
for (int i = 0; i < 2; i++)
{
x[i] = 0;
for (int j = 0; j < 3; j++)
{
int y = buffer[i*3 + j];
if (y < 0)
y += 256;
x[i] += (y << (j*8));
}
}
if ((ipnum & (1 << depth)) > 0)
{
if (x[1] >= COUNTRY_BEGIN)
return x[1] - COUNTRY_BEGIN;
return FindCountryCode(x[1], ipnum, depth - 1);
}
else
{
if (x[0] >= COUNTRY_BEGIN)
return x[0] - COUNTRY_BEGIN;
return FindCountryCode(x[0], ipnum, depth - 1);
}
}
public void Dispose()
{
if (_close && _geodata != null)
{
_geodata.Close();
_geodata = null;
}
}
}
}
if ((ipnum & (1 << depth)) > 0)
{
if (x[1] >= COUNTRY_BEGIN)
return x[1] - COUNTRY_BEGIN;
return FindCountryCode(x[1], ipnum, depth - 1);
}
else
{
if (x[0] >= COUNTRY_BEGIN)
return x[0] - COUNTRY_BEGIN;
return FindCountryCode(x[0], ipnum, depth - 1);
}
}
public void Dispose()
{
if (_close && _geodata != null)
{
_geodata.Close();
_geodata = null;
}
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -20,87 +20,87 @@ using System.Collections.Generic;
namespace TShockAPI
{
public class Group
{
public readonly List<string> permissions = new List<string>();
public readonly List<string> negatedpermissions = new List<string>();
public class Group
{
public readonly List<string> permissions = new List<string>();
public readonly List<string> negatedpermissions = new List<string>();
public string Name { get; set; }
public Group Parent { get; set; }
public int Order { get; set; }
public string Prefix { get; set; }
public string Suffix { get; set; }
public string Name { get; set; }
public Group Parent { get; set; }
public int Order { get; set; }
public string Prefix { get; set; }
public string Suffix { get; set; }
public byte R = 255;
public byte G = 255;
public byte B = 255;
public byte R = 255;
public byte G = 255;
public byte B = 255;
public Group(string groupname, Group parentgroup = null, string chatcolor = "255,255,255")
{
Name = groupname;
Parent = parentgroup;
byte.TryParse(chatcolor.Split(',')[0], out R);
byte.TryParse(chatcolor.Split(',')[1], out G);
byte.TryParse(chatcolor.Split(',')[2], out B);
}
public Group(string groupname, Group parentgroup = null, string chatcolor = "255,255,255")
{
Name = groupname;
Parent = parentgroup;
byte.TryParse(chatcolor.Split(',')[0], out R);
byte.TryParse(chatcolor.Split(',')[1], out G);
byte.TryParse(chatcolor.Split(',')[2], out B);
}
public virtual bool HasPermission(string permission)
{
var cur = this;
var traversed = new List<Group>();
while (cur != null)
{
if (string.IsNullOrEmpty(permission))
return true;
if (cur.negatedpermissions.Contains(permission))
return false;
if (cur.permissions.Contains(permission))
return true;
if (traversed.Contains(cur))
{
throw new Exception("Infinite group parenting ({0})".SFormat(cur.Name));
}
traversed.Add(cur);
cur = cur.Parent;
}
return false;
}
public virtual bool HasPermission(string permission)
{
var cur = this;
var traversed = new List<Group>();
while (cur != null)
{
if (string.IsNullOrEmpty(permission))
return true;
if (cur.negatedpermissions.Contains(permission))
return false;
if (cur.permissions.Contains(permission))
return true;
if (traversed.Contains(cur))
{
throw new Exception("Infinite group parenting ({0})".SFormat(cur.Name));
}
traversed.Add(cur);
cur = cur.Parent;
}
return false;
}
public void NegatePermission(string permission)
{
negatedpermissions.Add(permission);
}
public void NegatePermission(string permission)
{
negatedpermissions.Add(permission);
}
public void AddPermission(string permission)
{
permissions.Add(permission);
}
public void SetPermission( List<string> permission)
{
permissions.Clear();
foreach( string s in permission )
{
permissions.Add( s );
}
}
}
public void AddPermission(string permission)
{
permissions.Add(permission);
}
public class SuperAdminGroup : Group
{
public SuperAdminGroup()
: base("superadmin")
{
R = (byte)TShock.Config.SuperAdminChatRGB[0];
G = (byte)TShock.Config.SuperAdminChatRGB[1];
B = (byte)TShock.Config.SuperAdminChatRGB[2];
Prefix = TShock.Config.SuperAdminChatPrefix;
Suffix = TShock.Config.SuperAdminChatSuffix;
public void SetPermission(List<string> permission)
{
permissions.Clear();
foreach (string s in permission)
{
permissions.Add(s);
}
}
}
}
public class SuperAdminGroup : Group
{
public SuperAdminGroup()
: base("superadmin")
{
R = (byte) TShock.Config.SuperAdminChatRGB[0];
G = (byte) TShock.Config.SuperAdminChatRGB[1];
B = (byte) TShock.Config.SuperAdminChatRGB[2];
Prefix = TShock.Config.SuperAdminChatPrefix;
Suffix = TShock.Config.SuperAdminChatSuffix;
}
public override bool HasPermission(string permission)
{
return true;
}
}
public override bool HasPermission(string permission)
{
return true;
}
}
}

View file

@ -20,20 +20,21 @@ using System.IO;
namespace TShockAPI
{
/// <summary>
/// Derived objects can be written to and read from streams.
/// </summary>
public interface IPackable
{
/// <summary>
/// Writes object information to the stream
/// </summary>
/// <param name="stream">Stream to write to</param>
void Pack(Stream stream);
/// <summary>
/// Reads object information from the stream
/// </summary>
/// <param name="stream">Stream to read from</param>
void Unpack(Stream stream);
}
}
/// <summary>
/// Derived objects can be written to and read from streams.
/// </summary>
public interface IPackable
{
/// <summary>
/// Writes object information to the stream
/// </summary>
/// <param name="stream">Stream to write to</param>
void Pack(Stream stream);
/// <summary>
/// Reads object information from the stream
/// </summary>
/// <param name="stream">Stream to read from</param>
void Unpack(Stream stream);
}
}

View file

@ -22,147 +22,147 @@ using System.IO;
namespace TShockAPI
{
public enum LogLevel
{
None = 0,
Debug = 1,
Info = 2,
Warning = 4,
Error = 8,
Data = 16,
All = 31
}
public enum LogLevel
{
None = 0,
Debug = 1,
Info = 2,
Warning = 4,
Error = 8,
Data = 16,
All = 31
}
public static class Log
{
private static string _filename;
private static LogLevel _logLevel;
private static StreamWriter _logWriter;
public static class Log
{
private static string _filename;
private static LogLevel _logLevel;
private static StreamWriter _logWriter;
/// <summary>
/// Creates the log file stream and sets the initial log level.
/// </summary>
/// <param name="filename">The output filename. This file will be overwritten if 'clear' is set.</param>
/// <param name="logLevel">The <see cref="LogLevel" /> value which sets the type of messages to output.</param>
/// <param name="clear">Whether or not to clear the log file on initialization.</param>
public static void Initialize(string filename, LogLevel logLevel, bool clear)
{
_filename = filename;
_logLevel = logLevel;
/// <summary>
/// Creates the log file stream and sets the initial log level.
/// </summary>
/// <param name="filename">The output filename. This file will be overwritten if 'clear' is set.</param>
/// <param name="logLevel">The <see cref="LogLevel" /> value which sets the type of messages to output.</param>
/// <param name="clear">Whether or not to clear the log file on initialization.</param>
public static void Initialize(string filename, LogLevel logLevel, bool clear)
{
_filename = filename;
_logLevel = logLevel;
_logWriter = new StreamWriter(filename, !clear);
}
_logWriter = new StreamWriter(filename, !clear);
}
/// <summary>
/// Checks whether the log level contains the specified flag.
/// </summary>
/// <param name="type">The <see cref="LogLevel" /> value to check.</param>
private static bool MayWriteType(LogLevel type)
{
return ((_logLevel & type) == type);
}
/// <summary>
/// Checks whether the log level contains the specified flag.
/// </summary>
/// <param name="type">The <see cref="LogLevel" /> value to check.</param>
private static bool MayWriteType(LogLevel type)
{
return ((_logLevel & type) == type);
}
/// <summary>
/// Writes data to the log file.
/// </summary>
/// <param name="message">The message to be written.</param>
public static void Data(String message)
{
Write(message, LogLevel.Data);
}
/// <summary>
/// Writes data to the log file.
/// </summary>
/// <param name="message">The message to be written.</param>
public static void Data(String message)
{
Write(message, LogLevel.Data);
}
/// <summary>
/// Writes an error to the log file.
/// </summary>
/// <param name="message">The message to be written.</param>
public static void Error(String message)
{
Write(message, LogLevel.Error);
}
/// <summary>
/// Writes an error to the log file.
/// </summary>
/// <param name="message">The message to be written.</param>
public static void ConsoleError(String message)
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine(message);
Console.ForegroundColor = ConsoleColor.Gray;
Write(message, LogLevel.Error);
}
/// <summary>
/// Writes an error to the log file.
/// </summary>
/// <param name="message">The message to be written.</param>
public static void Error(String message)
{
Write(message, LogLevel.Error);
}
/// <summary>
/// Writes a warning to the log file.
/// </summary>
/// <param name="message">The message to be written.</param>
public static void Warn(String message)
{
Write(message, LogLevel.Warning);
}
/// <summary>
/// Writes an error to the log file.
/// </summary>
/// <param name="message">The message to be written.</param>
public static void ConsoleError(String message)
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine(message);
Console.ForegroundColor = ConsoleColor.Gray;
Write(message, LogLevel.Error);
}
/// <summary>
/// Writes an informative string to the log file.
/// </summary>
/// <param name="message">The message to be written.</param>
public static void Info(String message)
{
Write(message, LogLevel.Info);
}
/// <summary>
/// Writes a warning to the log file.
/// </summary>
/// <param name="message">The message to be written.</param>
public static void Warn(String message)
{
Write(message, LogLevel.Warning);
}
/// <summary>
/// Writes an informative string to the log file. Also outputs to the console.
/// </summary>
/// <param name="message">The message to be written.</param>
public static void ConsoleInfo(String message)
{
Console.ForegroundColor = ConsoleColor.Yellow;
Console.WriteLine(message);
Console.ForegroundColor = ConsoleColor.Gray;
Write(message, LogLevel.Info);
}
/// <summary>
/// Writes an informative string to the log file.
/// </summary>
/// <param name="message">The message to be written.</param>
public static void Info(String message)
{
Write(message, LogLevel.Info);
}
/// <summary>
/// Writes a debug string to the log file.
/// </summary>
/// <param name="message">The message to be written.</param>
public static void Debug(String message)
{
Write(message, LogLevel.Debug);
}
/// <summary>
/// Writes an informative string to the log file. Also outputs to the console.
/// </summary>
/// <param name="message">The message to be written.</param>
public static void ConsoleInfo(String message)
{
Console.ForegroundColor = ConsoleColor.Yellow;
Console.WriteLine(message);
Console.ForegroundColor = ConsoleColor.Gray;
Write(message, LogLevel.Info);
}
/// <summary>
/// Disposes objects that are being used.
/// </summary>
public static void Dispose()
{
_logWriter.Dispose();
}
/// <summary>
/// Writes a debug string to the log file.
/// </summary>
/// <param name="message">The message to be written.</param>
public static void Debug(String message)
{
Write(message, LogLevel.Debug);
}
/// <summary>
/// Internal method which writes a message directly to the log file.
/// </summary>
private static void Write(String message, LogLevel level)
{
if (!MayWriteType(level))
{
return;
}
/// <summary>
/// Disposes objects that are being used.
/// </summary>
public static void Dispose()
{
_logWriter.Dispose();
}
string caller = "TShock";
/// <summary>
/// Internal method which writes a message directly to the log file.
/// </summary>
private static void Write(String message, LogLevel level)
{
if (!MayWriteType(level))
{
return;
}
StackFrame frame = new StackTrace().GetFrame(2);
if (frame != null)
{
var meth = frame.GetMethod();
if (meth != null)
caller = meth.DeclaringType.Name;
}
string caller = "TShock";
_logWriter.WriteLine(string.Format("{0} - {1}: {2}: {3}",
DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture),
caller, level.ToString().ToUpper(), message));
_logWriter.Flush();
}
}
StackFrame frame = new StackTrace().GetFrame(2);
if (frame != null)
{
var meth = frame.GetMethod();
if (meth != null)
caller = meth.DeclaringType.Name;
}
_logWriter.WriteLine(string.Format("{0} - {1}: {2}: {3}",
DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture),
caller, level.ToString().ToUpper(), message));
_logWriter.Flush();
}
}
}

View file

@ -4,32 +4,33 @@ using System.IO.Streams;
namespace TShockAPI.Net
{
public class BaseMsg : IPackable
{
public virtual PacketTypes ID
{
get { throw new NotImplementedException("Msg ID not implemented"); }
}
public void PackFull(Stream stream)
{
long start = stream.Position;
stream.WriteInt32(1);
stream.WriteInt8((byte)ID);
Pack(stream);
long end = stream.Position;
stream.Position = start;
stream.WriteInt32((int)(end - start) - 4);
stream.Position = end;
}
public class BaseMsg : IPackable
{
public virtual PacketTypes ID
{
get { throw new NotImplementedException("Msg ID not implemented"); }
}
public virtual void Unpack(Stream stream)
{
throw new NotImplementedException();
}
public void PackFull(Stream stream)
{
long start = stream.Position;
stream.WriteInt32(1);
stream.WriteInt8((byte) ID);
Pack(stream);
long end = stream.Position;
stream.Position = start;
stream.WriteInt32((int) (end - start) - 4);
stream.Position = end;
}
public virtual void Pack(Stream stream)
{
throw new NotImplementedException();
}
}
}
public virtual void Unpack(Stream stream)
{
throw new NotImplementedException();
}
public virtual void Pack(Stream stream)
{
throw new NotImplementedException();
}
}
}

View file

@ -4,19 +4,18 @@ using System.Text;
namespace TShockAPI.Net
{
class DisconnectMsg : BaseMsg
{
public override PacketTypes ID
{
get
{
return PacketTypes.Disconnect;
}
}
public string Reason {get;set;}
public override void Pack(Stream stream)
{
stream.WriteBytes(Encoding.ASCII.GetBytes(Reason));
}
}
}
internal class DisconnectMsg : BaseMsg
{
public override PacketTypes ID
{
get { return PacketTypes.Disconnect; }
}
public string Reason { get; set; }
public override void Pack(Stream stream)
{
stream.WriteBytes(Encoding.ASCII.GetBytes(Reason));
}
}
}

View file

@ -23,116 +23,127 @@ using Terraria;
namespace TShockAPI.Net
{
public class NetTile : IPackable
{
public bool Active { get; set; }
public byte Type { get; set; }
public short FrameX { get; set; }
public short FrameY { get; set; }
public byte Wall { get; set; }
public byte Liquid { get; set; }
public bool Lava { get; set; }
public bool Wire { get; set; }
public class NetTile : IPackable
{
public bool Active { get; set; }
public byte Type { get; set; }
public short FrameX { get; set; }
public short FrameY { get; set; }
public byte Wall { get; set; }
public byte Liquid { get; set; }
public bool Lava { get; set; }
public bool Wire { get; set; }
public bool HasWall { get { return Wall > 0; } }
public bool HasLiquid { get { return Liquid > 0; } }
public bool FrameImportant { get { return Main.tileFrameImportant[Type]; } }
public bool HasWall
{
get { return Wall > 0; }
}
public NetTile()
{
Active = false;
Type = 0;
FrameX = -1;
FrameY = -1;
Wall = 0;
Liquid = 0;
Lava = false;
Wire = false;
}
public bool HasLiquid
{
get { return Liquid > 0; }
}
public NetTile(Stream stream)
: this()
{
Unpack(stream);
}
public bool FrameImportant
{
get { return Main.tileFrameImportant[Type]; }
}
public void Pack(Stream stream)
{
var flags = TileFlags.None;
public NetTile()
{
Active = false;
Type = 0;
FrameX = -1;
FrameY = -1;
Wall = 0;
Liquid = 0;
Lava = false;
Wire = false;
}
if (Active)
flags |= TileFlags.Active;
public NetTile(Stream stream)
: this()
{
Unpack(stream);
}
if (HasWall)
flags |= TileFlags.Wall;
public void Pack(Stream stream)
{
var flags = TileFlags.None;
if (HasLiquid)
flags |= TileFlags.Liquid;
if (Active)
flags |= TileFlags.Active;
if (Wire)
flags |= TileFlags.Wire;
if (HasWall)
flags |= TileFlags.Wall;
stream.WriteInt8((byte)flags);
if (HasLiquid)
flags |= TileFlags.Liquid;
if (Active)
{
stream.WriteInt8(Type);
if (FrameImportant)
{
stream.WriteInt16(FrameX);
stream.WriteInt16(FrameY);
}
}
if (Wire)
flags |= TileFlags.Wire;
if (HasWall)
stream.WriteInt8(Wall);
stream.WriteInt8((byte) flags);
if (HasLiquid)
{
stream.WriteInt8(Liquid);
stream.WriteBoolean(Lava);
}
}
if (Active)
{
stream.WriteInt8(Type);
if (FrameImportant)
{
stream.WriteInt16(FrameX);
stream.WriteInt16(FrameY);
}
}
public void Unpack(Stream stream)
{
var flags = (TileFlags)stream.ReadInt8();
if (HasWall)
stream.WriteInt8(Wall);
Active = flags.HasFlag(TileFlags.Active);
if (Active)
{
Type = stream.ReadInt8();
if (FrameImportant)
{
FrameX = stream.ReadInt16();
FrameY = stream.ReadInt16();
}
}
if (HasLiquid)
{
stream.WriteInt8(Liquid);
stream.WriteBoolean(Lava);
}
}
if (flags.HasFlag(TileFlags.Wall))
{
Wall = stream.ReadInt8();
}
public void Unpack(Stream stream)
{
var flags = (TileFlags) stream.ReadInt8();
if (flags.HasFlag(TileFlags.Liquid))
{
Liquid = stream.ReadInt8();
Lava = stream.ReadBoolean();
}
Active = flags.HasFlag(TileFlags.Active);
if (Active)
{
Type = stream.ReadInt8();
if (FrameImportant)
{
FrameX = stream.ReadInt16();
FrameY = stream.ReadInt16();
}
}
if (flags.HasFlag(TileFlags.Wire))
Wire = true;
}
}
if (flags.HasFlag(TileFlags.Wall))
{
Wall = stream.ReadInt8();
}
[Flags]
public enum TileFlags : byte
{
None = 0,
Active = 1,
Lighted = 2,
Wall = 4,
Liquid = 8,
Wire = 16
}
}
if (flags.HasFlag(TileFlags.Liquid))
{
Liquid = stream.ReadInt8();
Lava = stream.ReadBoolean();
}
if (flags.HasFlag(TileFlags.Wire))
Wire = true;
}
}
[Flags]
public enum TileFlags : byte
{
None = 0,
Active = 1,
Lighted = 2,
Wall = 4,
Liquid = 8,
Wire = 16
}
}

View file

@ -3,33 +3,30 @@ using System.IO.Streams;
namespace TShockAPI.Net
{
public class ProjectileRemoveMsg : BaseMsg
{
public override PacketTypes ID
{
get
{
return PacketTypes.ProjectileNew;
}
}
public class ProjectileRemoveMsg : BaseMsg
{
public override PacketTypes ID
{
get { return PacketTypes.ProjectileNew; }
}
public short Index { get; set; }
public byte Owner { get; set; }
public short Index { get; set; }
public byte Owner { get; set; }
public override void Pack(Stream stream)
{
stream.WriteInt16(Index);
stream.WriteSingle(-1);
stream.WriteSingle(-1);
stream.WriteSingle(0);
stream.WriteSingle(0);
stream.WriteSingle(0);
stream.WriteInt16(0);
stream.WriteByte(Owner);
stream.WriteByte(0);
stream.WriteSingle(0);
stream.WriteSingle(0);
stream.WriteSingle(0);
}
}
}
public override void Pack(Stream stream)
{
stream.WriteInt16(Index);
stream.WriteSingle(-1);
stream.WriteSingle(-1);
stream.WriteSingle(0);
stream.WriteSingle(0);
stream.WriteSingle(0);
stream.WriteInt16(0);
stream.WriteByte(Owner);
stream.WriteByte(0);
stream.WriteSingle(0);
stream.WriteSingle(0);
stream.WriteSingle(0);
}
}
}

View file

@ -3,25 +3,22 @@ using System.IO.Streams;
namespace TShockAPI.Net
{
public class SpawnMsg : BaseMsg
{
public override PacketTypes ID
{
get
{
return PacketTypes.PlayerSpawn;
}
}
public class SpawnMsg : BaseMsg
{
public override PacketTypes ID
{
get { return PacketTypes.PlayerSpawn; }
}
public int TileX { get; set; }
public int TileY {get;set;}
public byte PlayerIndex { get; set; }
public int TileX { get; set; }
public int TileY { get; set; }
public byte PlayerIndex { get; set; }
public override void Pack(Stream stream)
{
stream.WriteInt8(PlayerIndex);
stream.WriteInt32(TileX);
stream.WriteInt32(TileY);
}
}
}
public override void Pack(Stream stream)
{
stream.WriteInt8(PlayerIndex);
stream.WriteInt32(TileX);
stream.WriteInt32(TileY);
}
}
}

View file

@ -23,54 +23,54 @@ using System.Text;
namespace TShockAPI.Net
{
[Flags]
public enum WorldInfoFlag : byte
{
None = 0,
OrbSmashed = 1,
DownedBoss1 = 2,
DownedBoss2 = 4,
DownedBoss3 = 8,
HardMode = 16,
DownedClown = 32
}
public class WorldInfoMsg : BaseMsg
{
public int Time { get; set; }
public bool DayTime { get; set; }
public byte MoonPhase { get; set; }
public bool BloodMoon { get; set; }
public int MaxTilesX { get; set; }
public int MaxTilesY { get; set; }
public int SpawnX { get; set; }
public int SpawnY { get; set; }
public int WorldSurface { get; set; }
public int RockLayer { get; set; }
public int WorldID { get; set; }
public WorldInfoFlag WorldFlags { get; set; }
public string WorldName { get; set; }
public override PacketTypes ID
{
get
{
return PacketTypes.WorldInfo;
}
}
public override void Pack(Stream stream)
{
stream.WriteInt32(Time);
stream.WriteBoolean(DayTime);
stream.WriteInt8(MoonPhase);
stream.WriteBoolean(BloodMoon);
stream.WriteInt32(MaxTilesX);
stream.WriteInt32(MaxTilesY);
stream.WriteInt32(SpawnX);
stream.WriteInt32(SpawnY);
stream.WriteInt32(WorldSurface);
stream.WriteInt32(RockLayer);
stream.WriteInt32(WorldID);
stream.WriteInt8((byte)WorldFlags);
stream.WriteBytes(Encoding.ASCII.GetBytes(WorldName));
}
}
}
[Flags]
public enum WorldInfoFlag : byte
{
None = 0,
OrbSmashed = 1,
DownedBoss1 = 2,
DownedBoss2 = 4,
DownedBoss3 = 8,
HardMode = 16,
DownedClown = 32
}
public class WorldInfoMsg : BaseMsg
{
public int Time { get; set; }
public bool DayTime { get; set; }
public byte MoonPhase { get; set; }
public bool BloodMoon { get; set; }
public int MaxTilesX { get; set; }
public int MaxTilesY { get; set; }
public int SpawnX { get; set; }
public int SpawnY { get; set; }
public int WorldSurface { get; set; }
public int RockLayer { get; set; }
public int WorldID { get; set; }
public WorldInfoFlag WorldFlags { get; set; }
public string WorldName { get; set; }
public override PacketTypes ID
{
get { return PacketTypes.WorldInfo; }
}
public override void Pack(Stream stream)
{
stream.WriteInt32(Time);
stream.WriteBoolean(DayTime);
stream.WriteInt8(MoonPhase);
stream.WriteBoolean(BloodMoon);
stream.WriteInt32(MaxTilesX);
stream.WriteInt32(MaxTilesY);
stream.WriteInt32(SpawnX);
stream.WriteInt32(SpawnY);
stream.WriteInt32(WorldSurface);
stream.WriteInt32(RockLayer);
stream.WriteInt32(WorldID);
stream.WriteInt8((byte) WorldFlags);
stream.WriteBytes(Encoding.ASCII.GetBytes(WorldName));
}
}
}

View file

@ -9,29 +9,29 @@ using Terraria;
namespace TShockAPI
{
public class PacketBufferer : IDisposable
{
/// <summary>
/// Maximum number of bytes to send per update per socket
/// </summary>
public int BytesPerUpdate { get; set; }
public class PacketBufferer : IDisposable
{
/// <summary>
/// Maximum number of bytes to send per update per socket
/// </summary>
public int BytesPerUpdate { get; set; }
PacketBuffer[] buffers = new PacketBuffer[Netplay.serverSock.Length];
private PacketBuffer[] buffers = new PacketBuffer[Netplay.serverSock.Length];
int[] Bytes = new int[52];
int[] Packets = new int[52];
int[] Compressed = new int[52];
private int[] Bytes = new int[52];
private int[] Packets = new int[52];
private int[] Compressed = new int[52];
#if DEBUG_NET
Command dump;
Command flush;
#endif
public PacketBufferer()
{
BytesPerUpdate = 0xFFFF;
for (int i = 0; i < buffers.Length; i++)
buffers[i] = new PacketBuffer();
public PacketBufferer()
{
BytesPerUpdate = 0xFFFF;
for (int i = 0; i < buffers.Length; i++)
buffers[i] = new PacketBuffer();
#if DEBUG_NET
dump = new Command("superadmin", Dump, "netdump");
@ -40,113 +40,115 @@ namespace TShockAPI
Commands.ChatCommands.Add(flush);
#endif
NetHooks.SendBytes += ServerHooks_SendBytes;
ServerHooks.SocketReset += ServerHooks_SocketReset;
GameHooks.PostUpdate += GameHooks_Update;
}
NetHooks.SendBytes += ServerHooks_SendBytes;
ServerHooks.SocketReset += ServerHooks_SocketReset;
GameHooks.PostUpdate += GameHooks_Update;
}
~PacketBufferer()
{
Dispose(false);
}
~PacketBufferer()
{
Dispose(false);
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
#if DEBUG_NET
Commands.ChatCommands.Remove(dump);
Commands.ChatCommands.Remove(flush);
#endif
NetHooks.SendBytes -= ServerHooks_SendBytes;
ServerHooks.SocketReset -= ServerHooks_SocketReset;
GameHooks.PostUpdate -= GameHooks_Update;
}
}
NetHooks.SendBytes -= ServerHooks_SendBytes;
ServerHooks.SocketReset -= ServerHooks_SocketReset;
GameHooks.PostUpdate -= GameHooks_Update;
}
}
void Dump(CommandArgs args)
{
var sb = new StringBuilder();
sb.AppendLine("{0,-25}{1,-25}{2,-25}{3}".SFormat("Name:", "Packets", "Bytes", "Compression"));
for (int i = 1; i < Bytes.Length; i++)
{
sb.AppendLine("{0,-25}{1,-25}{2,-25}{3}".SFormat(Enum.GetName(typeof(PacketTypes), i) + ":", Packets[i], Bytes[i], Compressed[i]));
}
File.WriteAllText(Path.Combine(TShock.SavePath, "dmp.txt"), sb.ToString());
}
private void Dump(CommandArgs args)
{
var sb = new StringBuilder();
sb.AppendLine("{0,-25}{1,-25}{2,-25}{3}".SFormat("Name:", "Packets", "Bytes", "Compression"));
for (int i = 1; i < Bytes.Length; i++)
{
sb.AppendLine("{0,-25}{1,-25}{2,-25}{3}".SFormat(Enum.GetName(typeof (PacketTypes), i) + ":", Packets[i], Bytes[i],
Compressed[i]));
}
File.WriteAllText(Path.Combine(TShock.SavePath, "dmp.txt"), sb.ToString());
}
void Flush(CommandArgs args)
{
Bytes = new int[52];
Packets = new int[52];
Compressed = new int[52];
}
private void Flush(CommandArgs args)
{
Bytes = new int[52];
Packets = new int[52];
Compressed = new int[52];
}
void GameHooks_Update()
{
FlushAll();
}
private void GameHooks_Update()
{
FlushAll();
}
public void FlushAll()
{
for (int i = 0; i < Netplay.serverSock.Length; i++)
{
Flush(Netplay.serverSock[i]);
}
}
public void FlushAll()
{
for (int i = 0; i < Netplay.serverSock.Length; i++)
{
Flush(Netplay.serverSock[i]);
}
}
public bool Flush(ServerSock socket)
{
try
{
if (socket == null || !socket.active)
return false;
public bool Flush(ServerSock socket)
{
try
{
if (socket == null || !socket.active)
return false;
if (buffers[socket.whoAmI].Count < 1)
return false;
if (buffers[socket.whoAmI].Count < 1)
return false;
byte[] buff = buffers[socket.whoAmI].GetBytes(BytesPerUpdate);
if (buff == null)
return false;
byte[] buff = buffers[socket.whoAmI].GetBytes(BytesPerUpdate);
if (buff == null)
return false;
if (SendBytes(socket, buff))
{
buffers[socket.whoAmI].Pop(buff.Length);
return true;
}
}
catch (Exception e)
{
Log.ConsoleError(e.ToString());
}
return false;
}
if (SendBytes(socket, buff))
{
buffers[socket.whoAmI].Pop(buff.Length);
return true;
}
}
catch (Exception e)
{
Log.ConsoleError(e.ToString());
}
return false;
}
void ServerHooks_SocketReset(ServerSock socket)
{
buffers[socket.whoAmI] = new PacketBuffer();
}
private void ServerHooks_SocketReset(ServerSock socket)
{
buffers[socket.whoAmI] = new PacketBuffer();
}
public bool SendBytes(ServerSock socket, byte[] buffer)
{
return SendBytes(socket, buffer, 0, buffer.Length);
}
public void BufferBytes(ServerSock socket, byte[] buffer)
{
BufferBytes(socket, buffer, 0, buffer.Length);
}
public bool SendBytes(ServerSock socket, byte[] buffer)
{
return SendBytes(socket, buffer, 0, buffer.Length);
}
public void BufferBytes(ServerSock socket, byte[] buffer, int offset, int count)
{
lock (buffers[socket.whoAmI])
{
public void BufferBytes(ServerSock socket, byte[] buffer)
{
BufferBytes(socket, buffer, 0, buffer.Length);
}
public void BufferBytes(ServerSock socket, byte[] buffer, int offset, int count)
{
lock (buffers[socket.whoAmI])
{
#if DEBUG_NET
int size = (count - offset);
var pt = buffer[offset + 4];
@ -155,43 +157,44 @@ namespace TShockAPI
Bytes[pt] += size;
Compressed[pt] += Compress(buffer, offset, count);
#endif
using (var ms = new MemoryStream(buffer, offset, count))
{
buffers[socket.whoAmI].AddRange(ms.ToArray());
}
}
}
using (var ms = new MemoryStream(buffer, offset, count))
{
buffers[socket.whoAmI].AddRange(ms.ToArray());
}
}
}
public bool SendBytes(ServerSock socket, byte[] buffer, int offset, int count)
{
try
{
if (socket.tcpClient.Client != null && socket.tcpClient.Client.Poll(0, SelectMode.SelectWrite))
{
if (Main.runningMono)
socket.networkStream.Write(buffer, offset, count);
else
socket.tcpClient.Client.Send(buffer, offset, count, SocketFlags.None);
return true;
}
}
catch (ObjectDisposedException)
{
}
catch (SocketException)
{
}
catch (IOException)
{
}
return false;
}
public bool SendBytes(ServerSock socket, byte[] buffer, int offset, int count)
{
try
{
if (socket.tcpClient.Client != null && socket.tcpClient.Client.Poll(0, SelectMode.SelectWrite))
{
if (Main.runningMono)
socket.networkStream.Write(buffer, offset, count);
else
socket.tcpClient.Client.Send(buffer, offset, count, SocketFlags.None);
return true;
}
}
catch (ObjectDisposedException)
{
}
catch (SocketException)
{
}
catch (IOException)
{
}
return false;
}
private void ServerHooks_SendBytes(ServerSock socket, byte[] buffer, int offset, int count, HandledEventArgs e)
{
e.Handled = true;
BufferBytes(socket, buffer, offset, count);
}
void ServerHooks_SendBytes(ServerSock socket, byte[] buffer, int offset, int count, HandledEventArgs e)
{
e.Handled = true;
BufferBytes(socket, buffer, offset, count);
}
#if DEBUG_NET
static int Compress(byte[] buffer, int offset, int count)
{
@ -205,29 +208,29 @@ namespace TShockAPI
}
}
#endif
}
}
public class PacketBuffer : List<byte>
{
public byte[] GetBytes(int max)
{
lock (this)
{
if (this.Count < 1)
return null;
public class PacketBuffer : List<byte>
{
public byte[] GetBytes(int max)
{
lock (this)
{
if (this.Count < 1)
return null;
var ret = new byte[Math.Min(max, this.Count)];
this.CopyTo(0, ret, 0, ret.Length);
return ret;
}
}
var ret = new byte[Math.Min(max, this.Count)];
this.CopyTo(0, ret, 0, ret.Length);
return ret;
}
}
public void Pop(int count)
{
lock (this)
{
this.RemoveRange(0, count);
}
}
}
}
public void Pop(int count)
{
lock (this)
{
this.RemoveRange(0, count);
}
}
}
}

View file

@ -7,238 +7,193 @@ using System.Text;
namespace TShockAPI
{
public static class Permissions
{
//Permissions with blank descriptions basically means its described by the commands it gives access to.
public static class Permissions
{
//Permissions with blank descriptions basically means its described by the commands it gives access to.
[Description("")]
public static readonly string causeevents;
[Description("")] public static readonly string causeevents;
[Description("Required to be able to build (modify tiles and liquid)")]
public static readonly string canbuild;
[Description("Required to be able to build (modify tiles and liquid)")] public static readonly string canbuild;
[Description("")]
public static readonly string kill;
[Description("")] public static readonly string kill;
[Description("Allows you to use banned items")]
public static readonly string usebanneditem;
[Description("Allows you to use banned items")] public static readonly string usebanneditem;
[Description("Allows you to edit the spawn")]
public static readonly string editspawn;
[Description("Allows you to edit the spawn")] public static readonly string editspawn;
[Description("Prevents you from being kicked")]
public static readonly string immunetokick;
[Description("Prevents you from being kicked")] public static readonly string immunetokick;
[Description("Prevents you from being banned")]
public static readonly string immunetoban;
[Description("Prevents you from being banned")] public static readonly string immunetoban;
[Description("Prevents you from being reverted by kill tile abuse detection")]
public static readonly string ignorekilltiledetection;
[Description("Prevents you from being reverted by kill tile abuse detection")] public static readonly string
ignorekilltiledetection;
[Description("Prevents you from being reverted by place tile abuse detection")]
public static readonly string ignoreplacetiledetection;
[Description("Prevents you from being reverted by place tile abuse detection")] public static readonly string
ignoreplacetiledetection;
[Description("Prevents you from being disabled by liquid set abuse detection")]
public static readonly string ignoreliquidsetdetection;
[Description("Prevents you from being disabled by liquid set abuse detection")] public static readonly string
ignoreliquidsetdetection;
[Description("Prevents you from being disabled by liquid set abuse detection")]
public static readonly string ignoreprojectiledetection;
[Description("Prevents you from being disabled by liquid set abuse detection")] public static readonly string
ignoreprojectiledetection;
[Description("Prevents you from being reverted by no clip detection")]
public static readonly string ignorenoclipdetection;
[Description("Prevents you from being reverted by no clip detection")] public static readonly string
ignorenoclipdetection;
[Description("Prevents you from being disabled by stack hack detection")]
public static readonly string ignorestackhackdetection;
[Description("Prevents you from being disabled by stack hack detection")] public static readonly string
ignorestackhackdetection;
[Description("Prevents you from being kicked by hacked health detection")]
public static readonly string ignorestathackdetection;
[Description("Prevents you from being kicked by hacked health detection")] public static readonly string
ignorestathackdetection;
[Description("Specific log messages are sent to users with this permission")]
public static readonly string logs;
[Description("Specific log messages are sent to users with this permission")] public static readonly string logs;
[Description("Allows you to bypass the max slots for up to 5 slots above your max")]
public static readonly string reservedslot;
[Description("Allows you to bypass the max slots for up to 5 slots above your max")] public static readonly string
reservedslot;
[Description("User is notified when an update is available")]
public static readonly string maintenance;
[Description("User is notified when an update is available")] public static readonly string maintenance;
[Description("User can kick others")]
public static readonly string kick;
[Description("User can kick others")] public static readonly string kick;
[Description("User can ban others")]
public static readonly string ban;
[Description("User can ban others")] public static readonly string ban;
[Description("User can modify the whitelist")]
public static readonly string whitelist;
[Description("User can modify the whitelist")] public static readonly string whitelist;
[Description("User can spawn bosses")]
public static readonly string spawnboss;
[Description("User can spawn bosses")] public static readonly string spawnboss;
[Description("User can spawn npcs")]
public static readonly string spawnmob;
[Description("User can spawn npcs")] public static readonly string spawnmob;
[Description("User can teleport")]
public static readonly string tp;
[Description("User can teleport")] public static readonly string tp;
[Description("User can teleport people to them")]
public static readonly string tphere;
[Description("User can teleport people to them")] public static readonly string tphere;
[Description("User can use warps")]
public static readonly string warp;
[Description("User can use warps")] public static readonly string warp;
[Description("User can manage warps")]
public static readonly string managewarp;
[Description("User can manage warps")] public static readonly string managewarp;
[Description("User can manage item bans")]
public static readonly string manageitem;
[Description("User can manage item bans")] public static readonly string manageitem;
[Description("User can manage groups")]
public static readonly string managegroup;
[Description("User can manage groups")] public static readonly string managegroup;
[Description("User can edit sevrer configurations")]
public static readonly string cfg;
[Description("User can edit sevrer configurations")] public static readonly string cfg;
[Description("")]
public static readonly string time;
[Description("")] public static readonly string time;
[Description("")]
public static readonly string pvpfun;
[Description("")] public static readonly string pvpfun;
[Description("User can edit regions")]
public static readonly string manageregion;
[Description("User can edit regions")] public static readonly string manageregion;
[Description("Meant for super admins only")]
public static readonly string rootonly;
[Description("Meant for super admins only")] public static readonly string rootonly;
[Description("User can whisper to others")]
public static readonly string whisper;
[Description("User can whisper to others")] public static readonly string whisper;
[Description("")]
public static readonly string annoy;
[Description("")] public static readonly string annoy;
[Description("User can kill all enemy npcs")]
public static readonly string butcher;
[Description("User can kill all enemy npcs")] public static readonly string butcher;
[Description("User can spawn items")]
public static readonly string item;
[Description("User can spawn items")] public static readonly string item;
[Description("User can clear item drops.")]
public static readonly string clearitems;
[Description("User can clear item drops.")] public static readonly string clearitems;
[Description("")]
public static readonly string heal;
[Description("")] public static readonly string heal;
[Description("User can buff self")]
public static readonly string buff;
[Description("User can buff self")] public static readonly string buff;
[Description("User can buff other players")]
public static readonly string buffplayer;
[Description("User can buff other players")] public static readonly string buffplayer;
[Description("")]
public static readonly string grow;
[Description("")] public static readonly string grow;
[Description("User can change hardmode state.")]
public static readonly string hardmode;
[Description("User can change hardmode state.")] public static readonly string hardmode;
[Description("User can change the homes of NPCs.")]
public static readonly string movenpc;
[Description("User can change the homes of NPCs.")] public static readonly string movenpc;
[Description("Users can stop people from TPing to them")]
public static readonly string tpallow;
[Description("Users can stop people from TPing to them")] public static readonly string tpallow;
[Description("Users can tp to anyone")]
public static readonly string tpall;
[Description("Users can tp to anyone")] public static readonly string tpall;
[Description("Users can tp to people without showing a notice")]
public static readonly string tphide;
[Description("Users can tp to people without showing a notice")] public static readonly string tphide;
[Description("User can convert hallow into corruption and vice-versa")]
public static readonly string converthardmode;
[Description("User can convert hallow into corruption and vice-versa")] public static readonly string converthardmode;
[Description("User can mute and unmute users")]
public static readonly string mute;
[Description("User can register account in game")]
public static readonly string canregister;
[Description("User can login in game")]
public static readonly string canlogin;
[Description("User can change password in game")]
public static readonly string canchangepassword;
[Description("User can use party chat in game")]
public static readonly string canpartychat;
[Description("User can talk in third person")]
public static readonly string cantalkinthird;
[Description("User can mute and unmute users")] public static readonly string mute;
[Description("Bypass Server Side Inventory checks")]
public static readonly string bypassinventorychecks;
[Description("User can register account in game")] public static readonly string canregister;
[Description("Allow unrestricted Send Tile Square usage, for client side world editing")]
public static readonly string allowclientsideworldedit;
[Description("User can login in game")] public static readonly string canlogin;
static Permissions()
{
foreach (var field in typeof(Permissions).GetFields())
{
field.SetValue(null, field.Name);
}
}
[Description("User can change password in game")] public static readonly string canchangepassword;
static List<Command> GetCommands(string perm)
{
if (Commands.ChatCommands.Count < 1)
Commands.InitCommands();
return Commands.ChatCommands.Where(c => c.Permission == perm).ToList();
}
[Description("User can use party chat in game")] public static readonly string canpartychat;
static void DumpDescriptions()
{
var sb = new StringBuilder();
foreach (var field in typeof(Permissions).GetFields())
{
var name = field.Name;
[Description("User can talk in third person")] public static readonly string cantalkinthird;
var descattr = field.GetCustomAttributes(false).FirstOrDefault(o => o is DescriptionAttribute) as DescriptionAttribute;
var desc = descattr != null && !string.IsNullOrWhiteSpace(descattr.Description) ? descattr.Description : "None";
[Description("Bypass Server Side Inventory checks")] public static readonly string bypassinventorychecks;
var commands = GetCommands(name);
foreach (var c in commands)
{
for (var i = 0; i < c.Names.Count; i++)
{
c.Names[i] = "/" + c.Names[i];
}
}
var strs = commands.Select(c => c.Name + (c.Names.Count > 1 ? "({0})".SFormat(string.Join(" ", c.Names.ToArray(), 1, c.Names.Count - 1)) : ""));
[Description("Allow unrestricted Send Tile Square usage, for client side world editing")] public static readonly
string allowclientsideworldedit;
sb.AppendLine("## <a name=\"{0}\">{0} ".SFormat(name));
sb.AppendLine("**Description:** {0} ".SFormat(desc));
sb.AppendLine("**Commands:** {0} ".SFormat(strs.Count() > 0 ? string.Join(" ", strs) : "None"));
sb.AppendLine();
}
File.WriteAllText("PermissionsDescriptions.txt", sb.ToString());
}
}
static Permissions()
{
foreach (var field in typeof (Permissions).GetFields())
{
field.SetValue(null, field.Name);
}
}
[AttributeUsage(AttributeTargets.Field, Inherited = false, AllowMultiple = false)]
public sealed class TodoAttribute : Attribute
{
public string Info { get; private set; }
private static List<Command> GetCommands(string perm)
{
if (Commands.ChatCommands.Count < 1)
Commands.InitCommands();
return Commands.ChatCommands.Where(c => c.Permission == perm).ToList();
}
public TodoAttribute(string info)
{
Info = info;
private static void DumpDescriptions()
{
var sb = new StringBuilder();
foreach (var field in typeof (Permissions).GetFields())
{
var name = field.Name;
}
public TodoAttribute()
{
}
var descattr =
field.GetCustomAttributes(false).FirstOrDefault(o => o is DescriptionAttribute) as DescriptionAttribute;
var desc = descattr != null && !string.IsNullOrWhiteSpace(descattr.Description) ? descattr.Description : "None";
}
var commands = GetCommands(name);
foreach (var c in commands)
{
for (var i = 0; i < c.Names.Count; i++)
{
c.Names[i] = "/" + c.Names[i];
}
}
var strs =
commands.Select(
c =>
c.Name + (c.Names.Count > 1 ? "({0})".SFormat(string.Join(" ", c.Names.ToArray(), 1, c.Names.Count - 1)) : ""));
}
sb.AppendLine("## <a name=\"{0}\">{0} ".SFormat(name));
sb.AppendLine("**Description:** {0} ".SFormat(desc));
sb.AppendLine("**Commands:** {0} ".SFormat(strs.Count() > 0 ? string.Join(" ", strs) : "None"));
sb.AppendLine();
}
File.WriteAllText("PermissionsDescriptions.txt", sb.ToString());
}
}
[AttributeUsage(AttributeTargets.Field, Inherited = false, AllowMultiple = false)]
public sealed class TodoAttribute : Attribute
{
public string Info { get; private set; }
public TodoAttribute(string info)
{
Info = info;
}
public TodoAttribute()
{
}
}
}

View file

@ -28,420 +28,429 @@ using Terraria;
namespace TShockAPI
{
class RconHandler
{
public static string Password = "";
private static DateTime LastRequest;
private static DateTime LastHeartbeat;
public static int ListenPort;
public static bool ContinueServer = true;
public static string Response = "";
private static bool Started;
private static UdpClient listener;
private static Thread startThread;
private static Thread heartbeat;
private static Thread listen;
internal class RconHandler
{
public static string Password = "";
private static DateTime LastRequest;
private static DateTime LastHeartbeat;
public static int ListenPort;
public static bool ContinueServer = true;
public static string Response = "";
private static bool Started;
private static UdpClient listener;
private static Thread startThread;
private static Thread heartbeat;
private static Thread listen;
public static void ShutdownAllThreads()
{
if (Started)
{
startThread.Abort();
heartbeat.Abort();
listen.Abort();
Started = false;
}
}
public static void ShutdownAllThreads()
{
if (Started)
{
startThread.Abort();
heartbeat.Abort();
listen.Abort();
Started = false;
}
}
public static void StartThread()
{
if (!Started)
{
startThread = new Thread(Start);
startThread.Start();
public static void StartThread()
{
if (!Started)
{
startThread = new Thread(Start);
startThread.Start();
heartbeat = new Thread(SendHeartbeat);
heartbeat.Start();
}
Started = true;
}
heartbeat = new Thread(SendHeartbeat);
heartbeat.Start();
}
Started = true;
}
public static void Start()
{
Log.Info("Starting RconHandler.");
try
{
Console.WriteLine(string.Format("RconHandler is running at UDP port {0} and password is {1}",
ListenPort,
Password));
listen = new Thread(Listener);
listen.Start();
while (true)
{
if (listen.ThreadState != ThreadState.Running)
{
listen.Abort();
while (listen.ThreadState != ThreadState.Stopped)
continue;
listen.Start();
}
Thread.Sleep(3000);
}
}
catch (Exception e)
{
Log.Error(e.ToString());
}
}
public static void Start()
{
Log.Info("Starting RconHandler.");
try
{
Console.WriteLine(string.Format("RconHandler is running at UDP port {0} and password is {1}",
ListenPort,
Password));
listen = new Thread(Listener);
listen.Start();
while (true)
{
if (listen.ThreadState != ThreadState.Running)
{
listen.Abort();
while (listen.ThreadState != ThreadState.Stopped)
continue;
listen.Start();
}
Thread.Sleep(3000);
}
}
catch (Exception e)
{
Log.Error(e.ToString());
}
}
private static void Listener()
{
if (listener == null)
try
{
listener = new UdpClient(ListenPort);
}
catch (SocketException e)
{
if (e.SocketErrorCode == SocketError.AddressAlreadyInUse)
Log.ConsoleError("Could not bind to " + ListenPort + ". Are you sure you don't have another instance running?");
}
catch (Exception e)
{
Log.Error(e.ToString());
}
while (ContinueServer)
{
try
{
var listenEP = new IPEndPoint(IPAddress.Any, ListenPort);
LastRequest = DateTime.Now;
byte[] bytes = listener.Receive(ref listenEP);
var packet = ParsePacket(bytes, listenEP);
listener.Send(packet, packet.Length, listenEP);
}
catch (Exception e)
{
Log.Error(e.ToString());
}
}
private static void Listener()
{
if (listener == null)
try
{
listener = new UdpClient(ListenPort);
}
catch (SocketException e)
{
if (e.SocketErrorCode == SocketError.AddressAlreadyInUse)
Log.ConsoleError("Could not bind to " + ListenPort + ". Are you sure you don't have another instance running?");
}
catch (Exception e)
{
Log.Error(e.ToString());
}
while (ContinueServer)
{
try
{
var listenEP = new IPEndPoint(IPAddress.Any, ListenPort);
LastRequest = DateTime.Now;
byte[] bytes = listener.Receive(ref listenEP);
var packet = ParsePacket(bytes, listenEP);
listener.Send(packet, packet.Length, listenEP);
}
catch (Exception e)
{
Log.Error(e.ToString());
}
}
}
}
private static string SendPacket(byte[] bytes, string hostname, int port)
{
var response = Encoding.UTF8.GetString(new byte[] {0xFF, 0xFF, 0xFF, 0xFF}) + "disconnect";
try
{
var EP = new IPEndPoint(IPAddress.Any, port);
using (var client = new UdpClient())
{
client.Connect(hostname, port);
client.Client.ReceiveTimeout = 500;
client.Send(bytes, bytes.Length);
response = Encoding.UTF8.GetString(client.Receive(ref EP));
}
}
catch (Exception e)
{
Log.Error(e.ToString());
}
return response;
}
private static string SendPacket(byte[] bytes, string hostname, int port)
{
var response = Encoding.UTF8.GetString(new byte[] { 0xFF, 0xFF, 0xFF, 0xFF }) + "disconnect";
try
{
var EP = new IPEndPoint(IPAddress.Any, port);
using (var client = new UdpClient())
{
client.Connect(hostname, port);
client.Client.ReceiveTimeout = 500;
client.Send(bytes, bytes.Length);
response = Encoding.UTF8.GetString(client.Receive(ref EP));
}
}
catch (Exception e)
{
Log.Error(e.ToString());
}
return response;
}
private static byte[] ParsePacket(byte[] bytes, IPEndPoint EP)
{
string response = "";
var packetstring = Encoding.UTF8.GetString(PadPacket(bytes));
var redirect = false;
var print = true;
if ((DateTime.Now - LastRequest).Milliseconds >= 100)
{
if (packetstring.StartsWith("rcon") || packetstring.Substring(4).StartsWith("rcon") ||
packetstring.Substring(5).StartsWith("rcon"))
{
if (!string.IsNullOrEmpty(Password))
{
var args = ParseParameters(packetstring);
if (args.Count >= 3)
{
if (args[1] == Password)
{
args[1] = args[0] = "";
string command = string.Join(" ", args.ToArray());
command = command.TrimEnd(' ').TrimEnd('\0').TrimStart(' ');
Log.ConsoleInfo("Rcon from " + EP + ":" + command);
Response = "";
response = ExecuteCommand(command);
response += "\n" + Response;
Response = "";
response = response.TrimStart('\n');
}
else
{
response = "Bad rcon password.\n";
Log.ConsoleInfo("Bad rcon password from " + EP);
}
}
else
response = "";
}
else
{
response = "No rcon password set on the server.\n";
Log.Info("No password for rcon set");
}
}
else
redirect = true;
}
if (packetstring.StartsWith("getinfo")
|| packetstring.Substring(4).StartsWith("getinfo")
|| packetstring.Substring(5).StartsWith("getinfo"))
{
var challenge = "";
if (packetstring.Split(' ').Length == 2)
challenge = packetstring.Split(' ')[1];
response = "infoResponse\n";
var infostring =
string.Format(
@"\_TShock_ver\{6}\mapname\{1}\sv_maxclients\{2}\clients\{3}\sv_privateClients\{4}\hconly\{5}\gamename\TERRARIA\protocol\100\sv_hostname\{0}\g_needPass\{7}",
TShock.Config.ServerName, Main.worldName, Main.maxNetPlayers,
TShock.Utils.ActivePlayers(), Main.maxNetPlayers - TShock.Config.MaxSlots,
TShock.Config.HardcoreOnly ? 1 : 0, TShock.VersionNum,
Netplay.password != "" ? 1 : 0);
if (challenge != "")
infostring += @"\challenge\" + challenge;
response += infostring;
print = false;
redirect = false;
}
else if (packetstring.StartsWith("getstatus")
|| packetstring.Substring(4).StartsWith("getstatus")
|| packetstring.Substring(5).StartsWith("getstatus"))
{
var challenge = "";
if (packetstring.Split(' ').Length == 2)
challenge = packetstring.Split(' ')[1];
response = "statusResponse\n";
var statusstring = string.Format(
@"\_TShock_ver\{6}\mapname\{1}\sv_maxclients\{2}\clients\{3}\sv_privateClients\{4}\hconly\{5}\gamename\TERRARIA\protocol\100\sv_hostname\{0}\g_needPass\{7}",
TShock.Config.ServerName, Main.worldName, Main.maxNetPlayers,
TShock.Utils.ActivePlayers(), Main.maxNetPlayers - TShock.Config.MaxSlots,
TShock.Config.HardcoreOnly ? 1 : 0, TShock.VersionNum,
Netplay.password != "" ? 1 : 0) + "\n";
if (challenge != "")
statusstring += @"\challenge\" + challenge;
foreach (TSPlayer player in TShock.Players)
{
if (player != null && player.Active)
statusstring += (string.Format("0 0 {0}\n", player.Name));
}
response += statusstring;
print = false;
redirect = false;
}
if (!redirect)
return (ConstructPacket(response, print));
else
return (ConstructPacket("disconnect", false));
}
private static byte[] ParsePacket(byte[] bytes, IPEndPoint EP)
{
string response = "";
var packetstring = Encoding.UTF8.GetString(PadPacket(bytes));
var redirect = false;
var print = true;
if ((DateTime.Now - LastRequest).Milliseconds >= 100)
{
if (packetstring.StartsWith("rcon") || packetstring.Substring(4).StartsWith("rcon") || packetstring.Substring(5).StartsWith("rcon"))
{
if (!string.IsNullOrEmpty(Password))
{
var args = ParseParameters(packetstring);
if (args.Count >= 3)
{
if (args[1] == Password)
{
args[1] = args[0] = "";
string command = string.Join(" ", args.ToArray());
command = command.TrimEnd(' ').TrimEnd('\0').TrimStart(' ');
Log.ConsoleInfo("Rcon from " + EP + ":" + command);
Response = "";
response = ExecuteCommand(command);
response += "\n" + Response;
Response = "";
response = response.TrimStart('\n');
}
else
{
response = "Bad rcon password.\n";
Log.ConsoleInfo("Bad rcon password from " + EP);
}
}
else
response = "";
}
else
{
response = "No rcon password set on the server.\n";
Log.Info("No password for rcon set");
}
}
else
redirect = true;
}
if (packetstring.StartsWith("getinfo")
|| packetstring.Substring(4).StartsWith("getinfo")
|| packetstring.Substring(5).StartsWith("getinfo"))
{
var challenge = "";
if (packetstring.Split(' ').Length == 2)
challenge = packetstring.Split(' ')[1];
response = "infoResponse\n";
var infostring = string.Format(@"\_TShock_ver\{6}\mapname\{1}\sv_maxclients\{2}\clients\{3}\sv_privateClients\{4}\hconly\{5}\gamename\TERRARIA\protocol\100\sv_hostname\{0}\g_needPass\{7}",
TShock.Config.ServerName, Main.worldName, Main.maxNetPlayers,
TShock.Utils.ActivePlayers(), Main.maxNetPlayers - TShock.Config.MaxSlots,
TShock.Config.HardcoreOnly ? 1 : 0, TShock.VersionNum,
Netplay.password != "" ? 1 : 0);
if (challenge != "")
infostring += @"\challenge\" + challenge;
response += infostring;
print = false;
redirect = false;
}
else if (packetstring.StartsWith("getstatus")
|| packetstring.Substring(4).StartsWith("getstatus")
|| packetstring.Substring(5).StartsWith("getstatus"))
{
var challenge = "";
if (packetstring.Split(' ').Length == 2)
challenge = packetstring.Split(' ')[1];
response = "statusResponse\n";
var statusstring = string.Format(@"\_TShock_ver\{6}\mapname\{1}\sv_maxclients\{2}\clients\{3}\sv_privateClients\{4}\hconly\{5}\gamename\TERRARIA\protocol\100\sv_hostname\{0}\g_needPass\{7}",
TShock.Config.ServerName, Main.worldName, Main.maxNetPlayers,
TShock.Utils.ActivePlayers(), Main.maxNetPlayers - TShock.Config.MaxSlots,
TShock.Config.HardcoreOnly ? 1 : 0, TShock.VersionNum,
Netplay.password != "" ? 1 : 0) + "\n";
if (challenge != "")
statusstring += @"\challenge\" + challenge;
foreach (TSPlayer player in TShock.Players)
{
if (player != null && player.Active)
statusstring += (string.Format("0 0 {0}\n", player.Name));
}
response += statusstring;
print = false;
redirect = false;
}
if (!redirect)
return (ConstructPacket(response, print));
else
return (ConstructPacket("disconnect", false));
}
private static string ExecuteCommand(string text)
{
if (Main.rand == null)
Main.rand = new Random();
if (WorldGen.genRand == null)
WorldGen.genRand = new Random();
if (text.StartsWith("exit"))
{
TShock.Utils.ForceKickAll("Server shutting down!");
WorldGen.saveWorld(false);
Netplay.disconnect = true;
return "Server shutting down.";
}
else if (text.StartsWith("playing") || text.StartsWith("/playing"))
{
int count = 0;
foreach (TSPlayer player in TShock.Players)
{
if (player != null && player.Active)
{
count++;
TSPlayer.Server.SendMessage(string.Format("{0} ({1}) [{2}] <{3}>", player.Name, player.IP, player.Group.Name,
player.UserAccountName));
}
}
TSPlayer.Server.SendMessage(string.Format("{0} players connected.", count));
}
else if (text.StartsWith("status"))
{
Response += "map: " + Main.worldName + "\n";
Response += "num score ping name lastmsg address qport rate\n";
int count = 0;
foreach (TSPlayer player in TShock.Players)
{
if (player != null && player.Active)
{
count++;
Response +=
(string.Format("{0} 0 0 {1}({2}) {3} {4} 0 0", count, player.Name, player.Group.Name,
Netplay.serverSock[player.Index].tcpClient.Client.RemoteEndPoint, "")) + "\n";
}
}
}
else if (text.StartsWith("say "))
{
Log.Info(string.Format("Server said: {0}", text.Remove(0, 4)));
return string.Format("Server said: {0}", text.Remove(0, 4));
}
else if (text == "autosave")
{
Main.autoSave = TShock.Config.AutoSave = !TShock.Config.AutoSave;
Log.ConsoleInfo("AutoSave " + (TShock.Config.AutoSave ? "Enabled" : "Disabled"));
return "AutoSave " + (TShock.Config.AutoSave ? "Enabled" : "Disabled");
}
else if (text.StartsWith("/"))
{
if (!Commands.HandleCommand(TSPlayer.Server, text))
return "Invalid command.";
}
else if (!Commands.HandleCommand(TSPlayer.Server, "/" + text))
return "Invalid command.";
return "";
}
private static string ExecuteCommand(string text)
{
if (Main.rand == null)
Main.rand = new Random();
if (WorldGen.genRand == null)
WorldGen.genRand = new Random();
if (text.StartsWith("exit"))
{
TShock.Utils.ForceKickAll("Server shutting down!");
WorldGen.saveWorld(false);
Netplay.disconnect = true;
return "Server shutting down.";
}
else if (text.StartsWith("playing") || text.StartsWith("/playing"))
{
int count = 0;
foreach (TSPlayer player in TShock.Players)
{
if (player != null && player.Active)
{
count++;
TSPlayer.Server.SendMessage(string.Format("{0} ({1}) [{2}] <{3}>", player.Name, player.IP, player.Group.Name, player.UserAccountName));
}
}
TSPlayer.Server.SendMessage(string.Format("{0} players connected.", count));
}
else if (text.StartsWith("status"))
{
Response += "map: " + Main.worldName + "\n";
Response += "num score ping name lastmsg address qport rate\n";
int count = 0;
foreach (TSPlayer player in TShock.Players)
{
if (player != null && player.Active)
{
count++;
Response += (string.Format("{0} 0 0 {1}({2}) {3} {4} 0 0", count, player.Name, player.Group.Name, Netplay.serverSock[player.Index].tcpClient.Client.RemoteEndPoint, "")) + "\n";
}
}
}
else if (text.StartsWith("say "))
{
Log.Info(string.Format("Server said: {0}", text.Remove(0, 4)));
return string.Format("Server said: {0}", text.Remove(0, 4));
}
else if (text == "autosave")
{
Main.autoSave = TShock.Config.AutoSave = !TShock.Config.AutoSave;
Log.ConsoleInfo("AutoSave " + (TShock.Config.AutoSave ? "Enabled" : "Disabled"));
return "AutoSave " + (TShock.Config.AutoSave ? "Enabled" : "Disabled");
}
else if (text.StartsWith("/"))
{
if (!Commands.HandleCommand(TSPlayer.Server, text))
return "Invalid command.";
}
else
if (!Commands.HandleCommand(TSPlayer.Server, "/" + text))
return "Invalid command.";
return "";
}
private static byte[] ConstructPacket(string response, bool print)
{
var oob = new byte[] {0xFF, 0xFF, 0xFF, 0xFF};
using (var stream = new MemoryStream())
{
stream.WriteBytes(oob);
if (print)
stream.WriteBytes(Encoding.UTF8.GetBytes(string.Format("print\n{0}", response)));
else
stream.WriteBytes(Encoding.UTF8.GetBytes(response));
var trimmedpacket = new byte[(int) stream.Length];
var packet = stream.GetBuffer();
Array.Copy(packet, trimmedpacket, (int) stream.Length);
return trimmedpacket;
}
}
private static byte[] ConstructPacket(string response, bool print)
{
var oob = new byte[] { 0xFF, 0xFF, 0xFF, 0xFF };
using (var stream = new MemoryStream())
{
stream.WriteBytes(oob);
if (print)
stream.WriteBytes(Encoding.UTF8.GetBytes(string.Format("print\n{0}", response)));
else
stream.WriteBytes(Encoding.UTF8.GetBytes(response));
var trimmedpacket = new byte[(int)stream.Length];
var packet = stream.GetBuffer();
Array.Copy(packet, trimmedpacket, (int)stream.Length);
return trimmedpacket;
}
}
private static byte[] PadPacket(byte[] packet)
{
var returnpacket = new byte[(4 + packet.Length)];
int h = 0;
if (packet[0] != 0xFF)
{
for (int i = 0; i < 4; i++)
returnpacket[i] = 0xFF;
for (int i = 4; i < returnpacket.Length; i++)
returnpacket[i] = packet[h++];
}
else
returnpacket = packet;
return returnpacket;
}
private static byte[] PadPacket(byte[] packet)
{
var returnpacket = new byte[(4 + packet.Length)];
int h = 0;
if (packet[0] != 0xFF)
{
for (int i = 0; i < 4; i++)
returnpacket[i] = 0xFF;
for (int i = 4; i < returnpacket.Length; i++)
returnpacket[i] = packet[h++];
}
else
returnpacket = packet;
return returnpacket;
}
private static void SendHeartbeat()
{
LastHeartbeat = DateTime.UtcNow.Subtract(new TimeSpan(0, 0, 30));
while (true)
{
if ((DateTime.UtcNow - LastHeartbeat).Seconds >= 30)
{
var packet = ConstructPacket("heartbeat TerrariaShock", false);
if (listener == null)
try
{
listener = new UdpClient(ListenPort);
}
catch (SocketException e)
{
if (e.SocketErrorCode == SocketError.AddressAlreadyInUse)
Log.ConsoleError("Could not bind to " + ListenPort + ". Are you sure you don't have another instance running?");
}
catch (Exception e)
{
Log.Error(e.ToString());
}
listener.Send(packet, packet.Length, TShock.Config.MasterServer, 27950);
LastHeartbeat = DateTime.UtcNow;
}
Thread.Sleep(10000);
}
}
private static void SendHeartbeat()
{
LastHeartbeat = DateTime.UtcNow.Subtract(new TimeSpan(0, 0, 30));
while (true)
{
if ((DateTime.UtcNow - LastHeartbeat).Seconds >= 30)
{
var packet = ConstructPacket("heartbeat TerrariaShock", false);
if (listener == null)
try
{
listener = new UdpClient(ListenPort);
}
catch (SocketException e)
{
if (e.SocketErrorCode == SocketError.AddressAlreadyInUse)
Log.ConsoleError("Could not bind to " + ListenPort + ". Are you sure you don't have another instance running?");
}
catch (Exception e)
{
Log.Error(e.ToString());
}
listener.Send(packet, packet.Length, TShock.Config.MasterServer, 27950);
LastHeartbeat = DateTime.UtcNow;
}
Thread.Sleep(10000);
}
}
#region ParseParams
#region ParseParams
private static List<String> ParseParameters(string str)
{
var ret = new List<string>();
var sb = new StringBuilder();
bool instr = false;
for (int i = 0; i < str.Length; i++)
{
char c = str[i];
private static List<String> ParseParameters(string str)
{
var ret = new List<string>();
var sb = new StringBuilder();
bool instr = false;
for (int i = 0; i < str.Length; i++)
{
char c = str[i];
if (instr)
{
if (c == '\\')
{
if (i + 1 >= str.Length)
break;
c = GetEscape(str[++i]);
}
else if (c == '"')
{
ret.Add(sb.ToString());
sb.Clear();
instr = false;
continue;
}
sb.Append(c);
}
else
{
if (IsWhiteSpace(c))
{
if (sb.Length > 0)
{
ret.Add(sb.ToString());
sb.Clear();
}
}
else if (c == '"')
{
if (sb.Length > 0)
{
ret.Add(sb.ToString());
sb.Clear();
}
instr = true;
}
else
{
sb.Append(c);
}
}
}
if (sb.Length > 0)
ret.Add(sb.ToString());
if (instr)
{
if (c == '\\')
{
if (i + 1 >= str.Length)
break;
c = GetEscape(str[++i]);
}
else if (c == '"')
{
ret.Add(sb.ToString());
sb.Clear();
instr = false;
continue;
}
sb.Append(c);
}
else
{
if (IsWhiteSpace(c))
{
if (sb.Length > 0)
{
ret.Add(sb.ToString());
sb.Clear();
}
}
else if (c == '"')
{
if (sb.Length > 0)
{
ret.Add(sb.ToString());
sb.Clear();
}
instr = true;
}
else
{
sb.Append(c);
}
}
}
if (sb.Length > 0)
ret.Add(sb.ToString());
return ret;
}
private static char GetEscape(char c)
{
switch (c)
{
case '\\':
return '\\';
case '"':
return '"';
case 't':
return '\t';
default:
return c;
}
}
private static bool IsWhiteSpace(char c)
{
return c == ' ' || c == '\t' || c == '\n';
}
#endregion
}
}
return ret;
}
private static char GetEscape(char c)
{
switch (c)
{
case '\\':
return '\\';
case '"':
return '"';
case 't':
return '\t';
default:
return c;
}
}
private static bool IsWhiteSpace(char c)
{
return c == ' ' || c == '\t' || c == '\n';
}
#endregion
}
}

View file

@ -10,132 +10,142 @@ using HttpListener = HttpServer.HttpListener;
namespace Rests
{
/// <summary>
/// Rest command delegate
/// </summary>
/// <param name="parameters">Parameters in the url</param>
/// <param name="verbs">{x} in urltemplate</param>
/// <returns>Response object or null to not handle request</returns>
public delegate object RestCommandD(RestVerbs verbs, IParameterCollection parameters);
public class Rest : IDisposable
{
readonly List<RestCommand> commands = new List<RestCommand>();
HttpListener listener;
public IPAddress Ip { get; set; }
public int Port { get; set; }
/// <summary>
/// Rest command delegate
/// </summary>
/// <param name="parameters">Parameters in the url</param>
/// <param name="verbs">{x} in urltemplate</param>
/// <returns>Response object or null to not handle request</returns>
public delegate object RestCommandD(RestVerbs verbs, IParameterCollection parameters);
public Rest(IPAddress ip, int port)
{
Ip = ip;
Port = port;
}
public virtual void Start()
{
if (listener == null)
{
listener = HttpListener.Create(Ip, Port);
listener.RequestReceived += OnRequest;
listener.Start(int.MaxValue);
}
}
public void Start(IPAddress ip, int port)
{
Ip = ip;
Port = port;
Start();
}
public virtual void Stop()
{
listener.Stop();
}
public class Rest : IDisposable
{
private readonly List<RestCommand> commands = new List<RestCommand>();
private HttpListener listener;
public IPAddress Ip { get; set; }
public int Port { get; set; }
public void Register(string path, RestCommandD callback)
{
AddCommand(new RestCommand(path, callback));
}
public Rest(IPAddress ip, int port)
{
Ip = ip;
Port = port;
}
public void Register(RestCommand com)
{
AddCommand(com);
}
public virtual void Start()
{
if (listener == null)
{
listener = HttpListener.Create(Ip, Port);
listener.RequestReceived += OnRequest;
listener.Start(int.MaxValue);
}
}
protected void AddCommand(RestCommand com)
{
commands.Add(com);
}
public void Start(IPAddress ip, int port)
{
Ip = ip;
Port = port;
Start();
}
protected virtual void OnRequest(object sender, RequestEventArgs e)
{
var obj = ProcessRequest(sender, e);
if (obj == null)
throw new NullReferenceException("obj");
public virtual void Stop()
{
listener.Stop();
}
var str = JsonConvert.SerializeObject(obj, Formatting.Indented);
e.Response.Connection.Type = ConnectionType.Close;
e.Response.Body.Write(Encoding.ASCII.GetBytes(str), 0, str.Length);
e.Response.Status = HttpStatusCode.OK;
return;
}
public void Register(string path, RestCommandD callback)
{
AddCommand(new RestCommand(path, callback));
}
protected virtual object ProcessRequest(object sender, RequestEventArgs e)
{
var uri = e.Request.Uri.AbsolutePath;
uri = uri.TrimEnd('/');
public void Register(RestCommand com)
{
AddCommand(com);
}
foreach (var com in commands)
{
var verbs = new RestVerbs();
if (com.HasVerbs)
{
var match = Regex.Match(uri, com.UriVerbMatch);
if (!match.Success)
continue;
if ((match.Groups.Count - 1) != com.UriVerbs.Length)
continue;
protected void AddCommand(RestCommand com)
{
commands.Add(com);
}
for (int i = 0; i < com.UriVerbs.Length; i++)
verbs.Add(com.UriVerbs[i], match.Groups[i + 1].Value);
}
else if (com.UriTemplate.ToLower() != uri.ToLower())
{
continue;
}
protected virtual void OnRequest(object sender, RequestEventArgs e)
{
var obj = ProcessRequest(sender, e);
if (obj == null)
throw new NullReferenceException("obj");
var obj = ExecuteCommand(com, verbs, e.Request.Parameters);
if (obj != null)
return obj;
var str = JsonConvert.SerializeObject(obj, Formatting.Indented);
e.Response.Connection.Type = ConnectionType.Close;
e.Response.Body.Write(Encoding.ASCII.GetBytes(str), 0, str.Length);
e.Response.Status = HttpStatusCode.OK;
return;
}
}
return new Dictionary<string, string> { { "status", "404" }, { "error", "Specified API endpoint doesn't exist. Refer to the documentation for a list of valid endpoints." } };
}
protected virtual object ProcessRequest(object sender, RequestEventArgs e)
{
var uri = e.Request.Uri.AbsolutePath;
uri = uri.TrimEnd('/');
protected virtual object ExecuteCommand(RestCommand cmd, RestVerbs verbs, IParameterCollection parms)
{
return cmd.Callback(verbs, parms);
}
foreach (var com in commands)
{
var verbs = new RestVerbs();
if (com.HasVerbs)
{
var match = Regex.Match(uri, com.UriVerbMatch);
if (!match.Success)
continue;
if ((match.Groups.Count - 1) != com.UriVerbs.Length)
continue;
#region Dispose
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
if (listener != null)
{
listener.Stop();
listener = null;
}
}
}
~Rest()
{
Dispose(false);
}
for (int i = 0; i < com.UriVerbs.Length; i++)
verbs.Add(com.UriVerbs[i], match.Groups[i + 1].Value);
}
else if (com.UriTemplate.ToLower() != uri.ToLower())
{
continue;
}
#endregion
}
}
var obj = ExecuteCommand(com, verbs, e.Request.Parameters);
if (obj != null)
return obj;
}
return new Dictionary<string, string>
{
{"status", "404"},
{"error", "Specified API endpoint doesn't exist. Refer to the documentation for a list of valid endpoints."}
};
}
protected virtual object ExecuteCommand(RestCommand cmd, RestVerbs verbs, IParameterCollection parms)
{
return cmd.Callback(verbs, parms);
}
#region Dispose
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
if (listener != null)
{
listener.Stop();
listener = null;
}
}
}
~Rest()
{
Dispose(false);
}
#endregion
}
}

View file

@ -3,45 +3,45 @@ using System.Text.RegularExpressions;
namespace Rests
{
public class RestCommand
{
public string Name { get; protected set; }
public string UriTemplate { get; protected set; }
public string UriVerbMatch { get; protected set; }
public string[] UriVerbs { get; protected set; }
public RestCommandD Callback { get; protected set; }
public bool RequiresToken { get; set; }
public class RestCommand
{
public string Name { get; protected set; }
public string UriTemplate { get; protected set; }
public string UriVerbMatch { get; protected set; }
public string[] UriVerbs { get; protected set; }
public RestCommandD Callback { get; protected set; }
public bool RequiresToken { get; set; }
/// <summary>
///
/// </summary>
/// <param name="name">Used for identification</param>
/// <param name="uritemplate">Url template</param>
/// <param name="callback">Rest Command callback</param>
public RestCommand(string name, string uritemplate, RestCommandD callback)
{
Name = name;
UriTemplate = uritemplate;
UriVerbMatch = string.Format("^{0}$", string.Join("([^/]*)", Regex.Split(uritemplate, "\\{[^\\{\\}]*\\}")));
var matches = Regex.Matches(uritemplate, "\\{([^\\{\\}]*)\\}");
UriVerbs = (from Match match in matches select match.Groups[1].Value).ToArray();
Callback = callback;
RequiresToken = true;
}
/// <summary>
///
/// </summary>
/// <param name="uritemplate">Url template</param>
/// <param name="callback">Rest Command callback</param>
public RestCommand(string uritemplate, RestCommandD callback)
: this(string.Empty, uritemplate, callback)
{
/// <summary>
///
/// </summary>
/// <param name="name">Used for identification</param>
/// <param name="uritemplate">Url template</param>
/// <param name="callback">Rest Command callback</param>
public RestCommand(string name, string uritemplate, RestCommandD callback)
{
Name = name;
UriTemplate = uritemplate;
UriVerbMatch = string.Format("^{0}$", string.Join("([^/]*)", Regex.Split(uritemplate, "\\{[^\\{\\}]*\\}")));
var matches = Regex.Matches(uritemplate, "\\{([^\\{\\}]*)\\}");
UriVerbs = (from Match match in matches select match.Groups[1].Value).ToArray();
Callback = callback;
RequiresToken = true;
}
}
/// <summary>
///
/// </summary>
/// <param name="uritemplate">Url template</param>
/// <param name="callback">Rest Command callback</param>
public RestCommand(string uritemplate, RestCommandD callback)
: this(string.Empty, uritemplate, callback)
{
}
public bool HasVerbs
{
get { return UriVerbs.Length > 0; }
}
}
public bool HasVerbs
{
get { return UriVerbs.Length > 0; }
}
}
}

View file

@ -8,441 +8,451 @@ using TShockAPI.DB;
namespace TShockAPI
{
public class RestManager
{
private Rest Rest;
public class RestManager
{
private Rest Rest;
public RestManager(Rest rest)
{
Rest = rest;
}
public RestManager(Rest rest)
{
Rest = rest;
}
public void RegisterRestfulCommands()
{
Rest.Register(new RestCommand("/status", Status) { RequiresToken = false });
Rest.Register(new RestCommand("/tokentest", TokenTest) { RequiresToken = true });
public void RegisterRestfulCommands()
{
Rest.Register(new RestCommand("/status", Status) {RequiresToken = false});
Rest.Register(new RestCommand("/tokentest", TokenTest) {RequiresToken = true});
Rest.Register(new RestCommand("/users/read/{user}/info", UserInfo) { RequiresToken = true });
Rest.Register(new RestCommand("/users/destroy/{user}", UserDestroy) { RequiresToken = true });
Rest.Register(new RestCommand("/users/update/{user}", UserUpdate) { RequiresToken = true });
Rest.Register(new RestCommand("/users/read/{user}/info", UserInfo) {RequiresToken = true});
Rest.Register(new RestCommand("/users/destroy/{user}", UserDestroy) {RequiresToken = true});
Rest.Register(new RestCommand("/users/update/{user}", UserUpdate) {RequiresToken = true});
Rest.Register(new RestCommand("/bans/create", BanCreate) { RequiresToken = true });
Rest.Register(new RestCommand("/bans/read/{user}/info", BanInfo) { RequiresToken = true });
Rest.Register(new RestCommand("/bans/destroy/{user}", BanDestroy) { RequiresToken = true });
Rest.Register(new RestCommand("/bans/create", BanCreate) {RequiresToken = true});
Rest.Register(new RestCommand("/bans/read/{user}/info", BanInfo) {RequiresToken = true});
Rest.Register(new RestCommand("/bans/destroy/{user}", BanDestroy) {RequiresToken = true});
Rest.Register(new RestCommand("/lists/players", UserList) { RequiresToken = true });
Rest.Register(new RestCommand("/lists/players", UserList) {RequiresToken = true});
Rest.Register(new RestCommand("/world/read", WorldRead) { RequiresToken = true });
Rest.Register(new RestCommand("/world/meteor", WorldMeteor) { RequiresToken = true });
Rest.Register(new RestCommand("/world/bloodmoon/{bool}", WorldBloodmoon) { RequiresToken = true });
Rest.Register(new RestCommand("/world/read", WorldRead) {RequiresToken = true});
Rest.Register(new RestCommand("/world/meteor", WorldMeteor) {RequiresToken = true});
Rest.Register(new RestCommand("/world/bloodmoon/{bool}", WorldBloodmoon) {RequiresToken = true});
Rest.Register(new RestCommand("/players/read/{player}", PlayerRead) { RequiresToken = true });
Rest.Register(new RestCommand("/players/{player}/kick", PlayerKick) { RequiresToken = true });
Rest.Register(new RestCommand("/players/{player}/ban", PlayerBan) { RequiresToken = true });
//RegisterExamples();
}
Rest.Register(new RestCommand("/players/read/{player}", PlayerRead) {RequiresToken = true});
Rest.Register(new RestCommand("/players/{player}/kick", PlayerKick) {RequiresToken = true});
Rest.Register(new RestCommand("/players/{player}/ban", PlayerBan) {RequiresToken = true});
//RegisterExamples();
}
#region RestMethods
#region RestMethods
object TokenTest(RestVerbs verbs, IParameterCollection parameters)
{
return new Dictionary<string, string> { { "status", "200" }, { "response", "Token is valid and was passed through correctly." } };
}
private object TokenTest(RestVerbs verbs, IParameterCollection parameters)
{
return new Dictionary<string, string>
{{"status", "200"}, {"response", "Token is valid and was passed through correctly."}};
}
object Status(RestVerbs verbs, IParameterCollection parameters)
{
if (TShock.Config.EnableTokenEndpointAuthentication)
return new RestObject("403") { Error = "Server settings require a token for this API call." };
private object Status(RestVerbs verbs, IParameterCollection parameters)
{
if (TShock.Config.EnableTokenEndpointAuthentication)
return new RestObject("403") {Error = "Server settings require a token for this API call."};
var activeplayers = Main.player.Where(p => p != null && p.active).ToList();
string currentPlayers = string.Join(", ", activeplayers.Select(p => p.name));
var activeplayers = Main.player.Where(p => p != null && p.active).ToList();
string currentPlayers = string.Join(", ", activeplayers.Select(p => p.name));
var ret = new RestObject("200");
ret["name"] = TShock.Config.ServerNickname;
ret["port"] = Convert.ToString(TShock.Config.ServerPort);
ret["playercount"] = Convert.ToString(activeplayers.Count());
ret["players"] = currentPlayers;
var ret = new RestObject("200");
ret["name"] = TShock.Config.ServerNickname;
ret["port"] = Convert.ToString(TShock.Config.ServerPort);
ret["playercount"] = Convert.ToString(activeplayers.Count());
ret["players"] = currentPlayers;
return ret;
}
return ret;
}
#endregion
#endregion
#region RestUserMethods
#region RestUserMethods
object UserList(RestVerbs verbs, IParameterCollection parameters)
{
var activeplayers = Main.player.Where(p => p != null && p.active).ToList();
string currentPlayers = string.Join(", ", activeplayers.Select(p => p.name));
var ret = new RestObject("200");
ret["players"] = currentPlayers;
return ret;
}
private object UserList(RestVerbs verbs, IParameterCollection parameters)
{
var activeplayers = Main.player.Where(p => p != null && p.active).ToList();
string currentPlayers = string.Join(", ", activeplayers.Select(p => p.name));
var ret = new RestObject("200");
ret["players"] = currentPlayers;
return ret;
}
object UserUpdate(RestVerbs verbs, IParameterCollection parameters)
{
var returnBlock = new Dictionary<string, string>();
var password = parameters["password"];
var group = parameters["group"];
private object UserUpdate(RestVerbs verbs, IParameterCollection parameters)
{
var returnBlock = new Dictionary<string, string>();
var password = parameters["password"];
var group = parameters["group"];
if (group == null && password == null)
{
returnBlock.Add("status", "400");
returnBlock.Add("error", "No parameters were passed.");
return returnBlock;
}
if (group == null && password == null)
{
returnBlock.Add("status", "400");
returnBlock.Add("error", "No parameters were passed.");
return returnBlock;
}
var user = TShock.Users.GetUserByName(verbs["user"]);
if (user == null)
{
returnBlock.Add("status", "400");
returnBlock.Add("error", "The specefied user doesn't exist.");
return returnBlock;
}
var user = TShock.Users.GetUserByName(verbs["user"]);
if (user == null)
{
returnBlock.Add("status", "400");
returnBlock.Add("error", "The specefied user doesn't exist.");
return returnBlock;
}
if (password != null)
{
TShock.Users.SetUserPassword(user, password);
returnBlock.Add("password-response", "Password updated successfully.");
}
if (password != null)
{
TShock.Users.SetUserPassword(user, password);
returnBlock.Add("password-response", "Password updated successfully.");
}
if (group != null)
{
TShock.Users.SetUserGroup(user, group);
returnBlock.Add("group-response", "Group updated successfully.");
}
if (group != null)
{
TShock.Users.SetUserGroup(user, group);
returnBlock.Add("group-response", "Group updated successfully.");
}
returnBlock.Add("status", "200");
return returnBlock;
}
returnBlock.Add("status", "200");
return returnBlock;
}
object UserDestroy(RestVerbs verbs, IParameterCollection parameters)
{
var user = TShock.Users.GetUserByName(verbs["user"]);
if (user == null)
{
return new Dictionary<string, string> { { "status", "400" }, { "error", "The specified user account does not exist." } };
}
var returnBlock = new Dictionary<string, string>();
try
{
TShock.Users.RemoveUser(user);
}
catch (Exception)
{
returnBlock.Add("status", "400");
returnBlock.Add("error", "The specified user was unable to be removed.");
return returnBlock;
}
returnBlock.Add("status", "200");
returnBlock.Add("response", "User deleted successfully.");
return returnBlock;
}
private object UserDestroy(RestVerbs verbs, IParameterCollection parameters)
{
var user = TShock.Users.GetUserByName(verbs["user"]);
if (user == null)
{
return new Dictionary<string, string> {{"status", "400"}, {"error", "The specified user account does not exist."}};
}
var returnBlock = new Dictionary<string, string>();
try
{
TShock.Users.RemoveUser(user);
}
catch (Exception)
{
returnBlock.Add("status", "400");
returnBlock.Add("error", "The specified user was unable to be removed.");
return returnBlock;
}
returnBlock.Add("status", "200");
returnBlock.Add("response", "User deleted successfully.");
return returnBlock;
}
object UserInfo(RestVerbs verbs, IParameterCollection parameters)
{
var user = TShock.Users.GetUserByName(verbs["user"]);
if (user == null)
{
return new Dictionary<string, string> { { "status", "400" }, { "error", "The specified user account does not exist." } };
}
private object UserInfo(RestVerbs verbs, IParameterCollection parameters)
{
var user = TShock.Users.GetUserByName(verbs["user"]);
if (user == null)
{
return new Dictionary<string, string> {{"status", "400"}, {"error", "The specified user account does not exist."}};
}
var returnBlock = new Dictionary<string, string>();
returnBlock.Add("status", "200");
returnBlock.Add("group", user.Group);
returnBlock.Add("id", user.ID.ToString());
return returnBlock;
}
var returnBlock = new Dictionary<string, string>();
returnBlock.Add("status", "200");
returnBlock.Add("group", user.Group);
returnBlock.Add("id", user.ID.ToString());
return returnBlock;
}
#endregion
#endregion
#region RestBanMethods
#region RestBanMethods
object BanCreate(RestVerbs verbs, IParameterCollection parameters)
{
var returnBlock = new Dictionary<string, string>();
var ip = parameters["ip"];
var name = parameters["name"];
var reason = parameters["reason"];
private object BanCreate(RestVerbs verbs, IParameterCollection parameters)
{
var returnBlock = new Dictionary<string, string>();
var ip = parameters["ip"];
var name = parameters["name"];
var reason = parameters["reason"];
if (ip == null && name == null)
{
returnBlock.Add("status", "400");
returnBlock.Add("error", "Required parameters were missing from this API endpoint.");
return returnBlock;
}
if (ip == null && name == null)
{
returnBlock.Add("status", "400");
returnBlock.Add("error", "Required parameters were missing from this API endpoint.");
return returnBlock;
}
if (ip == null)
{
ip = "";
}
if (ip == null)
{
ip = "";
}
if (name == null)
{
name = "";
}
if (name == null)
{
name = "";
}
if (reason == null)
{
reason = "";
}
if (reason == null)
{
reason = "";
}
try
{
TShock.Bans.AddBan(ip, name, reason);
}
catch (Exception)
{
returnBlock.Add("status", "400");
returnBlock.Add("error", "The specified ban was unable to be created.");
return returnBlock;
}
returnBlock.Add("status", "200");
returnBlock.Add("response", "Ban created successfully.");
return returnBlock;
}
try
{
TShock.Bans.AddBan(ip, name, reason);
}
catch (Exception)
{
returnBlock.Add("status", "400");
returnBlock.Add("error", "The specified ban was unable to be created.");
return returnBlock;
}
returnBlock.Add("status", "200");
returnBlock.Add("response", "Ban created successfully.");
return returnBlock;
}
object BanDestroy(RestVerbs verbs, IParameterCollection parameters)
{
var returnBlock = new Dictionary<string, string>();
private object BanDestroy(RestVerbs verbs, IParameterCollection parameters)
{
var returnBlock = new Dictionary<string, string>();
var type = parameters["type"];
if (type == null)
{
returnBlock.Add("Error", "Invalid Type");
return returnBlock;
}
var type = parameters["type"];
if (type == null)
{
returnBlock.Add("Error", "Invalid Type");
return returnBlock;
}
var ban = new Ban();
if (type == "ip") ban = TShock.Bans.GetBanByIp(verbs["user"]);
else if (type == "name") ban = TShock.Bans.GetBanByName(verbs["user"]);
else
{
returnBlock.Add("Error", "Invalid Type");
return returnBlock;
}
var ban = new Ban();
if (type == "ip") ban = TShock.Bans.GetBanByIp(verbs["user"]);
else if (type == "name") ban = TShock.Bans.GetBanByName(verbs["user"]);
else
{
returnBlock.Add("Error", "Invalid Type");
return returnBlock;
}
if (ban == null)
{
return new Dictionary<string, string> { { "status", "400" }, { "error", "The specified ban does not exist." } };
}
if (ban == null)
{
return new Dictionary<string, string> {{"status", "400"}, {"error", "The specified ban does not exist."}};
}
try
{
TShock.Bans.RemoveBan(ban.IP);
}
catch (Exception)
{
returnBlock.Add("status", "400");
returnBlock.Add("error", "The specified ban was unable to be removed.");
return returnBlock;
}
returnBlock.Add("status", "200");
returnBlock.Add("response", "Ban deleted successfully.");
return returnBlock;
}
try
{
TShock.Bans.RemoveBan(ban.IP);
}
catch (Exception)
{
returnBlock.Add("status", "400");
returnBlock.Add("error", "The specified ban was unable to be removed.");
return returnBlock;
}
returnBlock.Add("status", "200");
returnBlock.Add("response", "Ban deleted successfully.");
return returnBlock;
}
object BanInfo(RestVerbs verbs, IParameterCollection parameters)
{
var returnBlock = new Dictionary<string, string>();
private object BanInfo(RestVerbs verbs, IParameterCollection parameters)
{
var returnBlock = new Dictionary<string, string>();
var type = parameters["type"];
if (type == null)
{
returnBlock.Add("Error", "Invalid Type");
return returnBlock;
}
var type = parameters["type"];
if (type == null)
{
returnBlock.Add("Error", "Invalid Type");
return returnBlock;
}
var ban = new Ban();
if (type == "ip") ban = TShock.Bans.GetBanByIp(verbs["user"]);
else if (type == "name") ban = TShock.Bans.GetBanByName(verbs["user"]);
else
{
returnBlock.Add("Error", "Invalid Type");
return returnBlock;
}
var ban = new Ban();
if (type == "ip") ban = TShock.Bans.GetBanByIp(verbs["user"]);
else if (type == "name") ban = TShock.Bans.GetBanByName(verbs["user"]);
else
{
returnBlock.Add("Error", "Invalid Type");
return returnBlock;
}
if (ban == null)
{
return new Dictionary<string, string> { { "status", "400" }, { "error", "The specified ban does not exist." } };
}
if (ban == null)
{
return new Dictionary<string, string> {{"status", "400"}, {"error", "The specified ban does not exist."}};
}
returnBlock.Add("status", "200");
returnBlock.Add("name", ban.Name);
returnBlock.Add("ip", ban.IP);
returnBlock.Add("reason", ban.Reason);
return returnBlock;
}
returnBlock.Add("status", "200");
returnBlock.Add("name", ban.Name);
returnBlock.Add("ip", ban.IP);
returnBlock.Add("reason", ban.Reason);
return returnBlock;
}
#endregion
#endregion
#region RestWorldMethods
object WorldRead(RestVerbs verbs, IParameterCollection parameters)
{
var returnBlock = new Dictionary<string, object>();
returnBlock.Add("status", "200");
returnBlock.Add("name", Main.worldName);
returnBlock.Add("size", Main.maxTilesX + "*" + Main.maxTilesY);
returnBlock.Add("time", Main.time);
returnBlock.Add("daytime", Main.dayTime);
returnBlock.Add("bloodmoon", Main.bloodMoon);
returnBlock.Add("invasionsize", Main.invasionSize);
return returnBlock;
}
#region RestWorldMethods
object WorldMeteor(RestVerbs verbs, IParameterCollection parameters)
{
WorldGen.dropMeteor();
var returnBlock = new Dictionary<string, string>();
returnBlock.Add("status", "200");
returnBlock.Add("response", "Meteor has been spawned.");
return returnBlock;
}
private object WorldRead(RestVerbs verbs, IParameterCollection parameters)
{
var returnBlock = new Dictionary<string, object>();
returnBlock.Add("status", "200");
returnBlock.Add("name", Main.worldName);
returnBlock.Add("size", Main.maxTilesX + "*" + Main.maxTilesY);
returnBlock.Add("time", Main.time);
returnBlock.Add("daytime", Main.dayTime);
returnBlock.Add("bloodmoon", Main.bloodMoon);
returnBlock.Add("invasionsize", Main.invasionSize);
return returnBlock;
}
object WorldBloodmoon(RestVerbs verbs, IParameterCollection parameters)
{
var returnBlock = new Dictionary<string, string>();
var bloodmoonVerb = verbs["bool"];
bool bloodmoon;
if (bloodmoonVerb == null)
{
returnBlock.Add("status", "400");
returnBlock.Add("error", "No parameter was passed.");
return returnBlock;
}
if (!bool.TryParse(bloodmoonVerb, out bloodmoon))
{
returnBlock.Add("status", "400");
returnBlock.Add("error", "Unable to parse parameter.");
return returnBlock;
}
Main.bloodMoon = bloodmoon;
returnBlock.Add("status", "200");
returnBlock.Add("response", "Blood Moon has been set to " + bloodmoon);
return returnBlock;
}
#endregion
private object WorldMeteor(RestVerbs verbs, IParameterCollection parameters)
{
WorldGen.dropMeteor();
var returnBlock = new Dictionary<string, string>();
returnBlock.Add("status", "200");
returnBlock.Add("response", "Meteor has been spawned.");
return returnBlock;
}
#region RestPlayerMethods
object PlayerRead(RestVerbs verbs, IParameterCollection parameters)
{
var returnBlock = new Dictionary<string, object>();
var playerParam = parameters["player"];
var found = TShock.Utils.FindPlayer(playerParam);
if (found.Count == 0)
{
returnBlock.Add("status", "400");
returnBlock.Add("error", "Name " + playerParam + " was not found");
}
else if (found.Count > 1)
{
returnBlock.Add("status", "400");
returnBlock.Add("error", "Name " + playerParam + " matches " + playerParam.Count() + " players");
}
else if (found.Count == 1)
{
var player = found[0];
returnBlock.Add("status", "200");
returnBlock.Add("nickname", player.Name);
returnBlock.Add("username", player.UserAccountName == null ? "" : player.UserAccountName);
returnBlock.Add("ip", player.IP);
returnBlock.Add("group", player.Group.Name);
returnBlock.Add("position", player.TileX + "," + player.TileY);
var activeItems = player.TPlayer.inventory.Where(p => p.active).ToList();
returnBlock.Add("inventory", string.Join(", ", activeItems.Select(p => p.name)));
returnBlock.Add("buffs", string.Join(", ", player.TPlayer.buffType));
}
return returnBlock;
}
object PlayerKick(RestVerbs verbs, IParameterCollection parameters)
{
var returnBlock = new Dictionary<string, object>();
var playerParam = parameters["player"];
var found = TShock.Utils.FindPlayer(playerParam);
var reason = verbs["reason"];
if (found.Count == 0)
{
returnBlock.Add("status", "400");
returnBlock.Add("error", "Name " + playerParam + " was not found");
}
else if (found.Count > 1)
{
returnBlock.Add("status", "400");
returnBlock.Add("error", "Name " + playerParam + " matches " + playerParam.Count() + " players");
}
else if (found.Count == 1)
{
var player = found[0];
TShock.Utils.ForceKick(player, reason == null ? "Kicked via web" : reason);
returnBlock.Add("status", "200");
returnBlock.Add("response", "Player " + player.Name + " was kicked");
}
return returnBlock;
}
object PlayerBan(RestVerbs verbs, IParameterCollection parameters)
{
var returnBlock = new Dictionary<string, object>();
var playerParam = parameters["player"];
var found = TShock.Utils.FindPlayer(playerParam);
var reason = verbs["reason"];
if (found.Count == 0)
{
returnBlock.Add("status", "400");
returnBlock.Add("error", "Name " + playerParam + " was not found");
}
else if (found.Count > 1)
{
returnBlock.Add("status", "400");
returnBlock.Add("error", "Name " + playerParam + " matches " + playerParam.Count() + " players");
}
else if (found.Count == 1)
{
var player = found[0];
TShock.Bans.AddBan(player.IP, player.Name, reason == null ? "Banned via web" : reason);
TShock.Utils.ForceKick(player, reason == null ? "Banned via web" : reason);
returnBlock.Add("status", "200");
returnBlock.Add("response", "Player " + player.Name + " was banned");
}
return returnBlock;
}
#endregion
private object WorldBloodmoon(RestVerbs verbs, IParameterCollection parameters)
{
var returnBlock = new Dictionary<string, string>();
var bloodmoonVerb = verbs["bool"];
bool bloodmoon;
if (bloodmoonVerb == null)
{
returnBlock.Add("status", "400");
returnBlock.Add("error", "No parameter was passed.");
return returnBlock;
}
if (!bool.TryParse(bloodmoonVerb, out bloodmoon))
{
returnBlock.Add("status", "400");
returnBlock.Add("error", "Unable to parse parameter.");
return returnBlock;
}
Main.bloodMoon = bloodmoon;
returnBlock.Add("status", "200");
returnBlock.Add("response", "Blood Moon has been set to " + bloodmoon);
return returnBlock;
}
#region RestExampleMethods
#endregion
public void RegisterExamples()
{
Rest.Register(new RestCommand("/HelloWorld/name/{username}", UserTest) { RequiresToken = false });
Rest.Register(new RestCommand("/wizard/{username}", Wizard) { RequiresToken = false });
}
#region RestPlayerMethods
//The Wizard example, for demonstrating the response convention:
object Wizard(RestVerbs verbs, IParameterCollection parameters)
{
var returnBack = new Dictionary<string, string>();
returnBack.Add("status", "200"); //Keep this in everything, 200 = ok, etc. Standard http status codes.
returnBack.Add("error", "(If this failed, you would have a different status code and provide the error object.)"); //And only include this if the status isn't 200 or a failure
returnBack.Add("Verified Wizard", "You're a wizard, " + verbs["username"]); //Outline any api calls and possible responses in some form of documentation somewhere
return returnBack;
}
private object PlayerRead(RestVerbs verbs, IParameterCollection parameters)
{
var returnBlock = new Dictionary<string, object>();
var playerParam = parameters["player"];
var found = TShock.Utils.FindPlayer(playerParam);
if (found.Count == 0)
{
returnBlock.Add("status", "400");
returnBlock.Add("error", "Name " + playerParam + " was not found");
}
else if (found.Count > 1)
{
returnBlock.Add("status", "400");
returnBlock.Add("error", "Name " + playerParam + " matches " + playerParam.Count() + " players");
}
else if (found.Count == 1)
{
var player = found[0];
returnBlock.Add("status", "200");
returnBlock.Add("nickname", player.Name);
returnBlock.Add("username", player.UserAccountName == null ? "" : player.UserAccountName);
returnBlock.Add("ip", player.IP);
returnBlock.Add("group", player.Group.Name);
returnBlock.Add("position", player.TileX + "," + player.TileY);
var activeItems = player.TPlayer.inventory.Where(p => p.active).ToList();
returnBlock.Add("inventory", string.Join(", ", activeItems.Select(p => p.name)));
returnBlock.Add("buffs", string.Join(", ", player.TPlayer.buffType));
}
return returnBlock;
}
//http://127.0.0.1:8080/HelloWorld/name/{username}?type=status
object UserTest(RestVerbs verbs, IParameterCollection parameters)
{
var ret = new Dictionary<string, string>();
var type = parameters["type"];
if (type == null)
{
ret.Add("Error", "Invalid Type");
return ret;
}
if (type == "status")
{
ret.Add("Users", "Info here");
return ret;
}
return null;
}
#endregion
}
}
private object PlayerKick(RestVerbs verbs, IParameterCollection parameters)
{
var returnBlock = new Dictionary<string, object>();
var playerParam = parameters["player"];
var found = TShock.Utils.FindPlayer(playerParam);
var reason = verbs["reason"];
if (found.Count == 0)
{
returnBlock.Add("status", "400");
returnBlock.Add("error", "Name " + playerParam + " was not found");
}
else if (found.Count > 1)
{
returnBlock.Add("status", "400");
returnBlock.Add("error", "Name " + playerParam + " matches " + playerParam.Count() + " players");
}
else if (found.Count == 1)
{
var player = found[0];
TShock.Utils.ForceKick(player, reason == null ? "Kicked via web" : reason);
returnBlock.Add("status", "200");
returnBlock.Add("response", "Player " + player.Name + " was kicked");
}
return returnBlock;
}
private object PlayerBan(RestVerbs verbs, IParameterCollection parameters)
{
var returnBlock = new Dictionary<string, object>();
var playerParam = parameters["player"];
var found = TShock.Utils.FindPlayer(playerParam);
var reason = verbs["reason"];
if (found.Count == 0)
{
returnBlock.Add("status", "400");
returnBlock.Add("error", "Name " + playerParam + " was not found");
}
else if (found.Count > 1)
{
returnBlock.Add("status", "400");
returnBlock.Add("error", "Name " + playerParam + " matches " + playerParam.Count() + " players");
}
else if (found.Count == 1)
{
var player = found[0];
TShock.Bans.AddBan(player.IP, player.Name, reason == null ? "Banned via web" : reason);
TShock.Utils.ForceKick(player, reason == null ? "Banned via web" : reason);
returnBlock.Add("status", "200");
returnBlock.Add("response", "Player " + player.Name + " was banned");
}
return returnBlock;
}
#endregion
#region RestExampleMethods
public void RegisterExamples()
{
Rest.Register(new RestCommand("/HelloWorld/name/{username}", UserTest) {RequiresToken = false});
Rest.Register(new RestCommand("/wizard/{username}", Wizard) {RequiresToken = false});
}
//The Wizard example, for demonstrating the response convention:
private object Wizard(RestVerbs verbs, IParameterCollection parameters)
{
var returnBack = new Dictionary<string, string>();
returnBack.Add("status", "200"); //Keep this in everything, 200 = ok, etc. Standard http status codes.
returnBack.Add("error", "(If this failed, you would have a different status code and provide the error object.)");
//And only include this if the status isn't 200 or a failure
returnBack.Add("Verified Wizard", "You're a wizard, " + verbs["username"]);
//Outline any api calls and possible responses in some form of documentation somewhere
return returnBack;
}
//http://127.0.0.1:8080/HelloWorld/name/{username}?type=status
private object UserTest(RestVerbs verbs, IParameterCollection parameters)
{
var ret = new Dictionary<string, string>();
var type = parameters["type"];
if (type == null)
{
ret.Add("Error", "Invalid Type");
return ret;
}
if (type == "status")
{
ret.Add("Users", "Info here");
return ret;
}
return null;
}
#endregion
}
}

View file

@ -3,61 +3,63 @@ using System.Collections.Generic;
namespace Rests
{
[Serializable]
public class RestObject : Dictionary<string, object>
{
public string Status
{
get { return this["status"] as string; }
set { this["status"] = value; }
}
public string Error
{
get { return this["error"] as string; }
set { this["error"] = value; }
}
public string Response
{
get { return this["response"] as string; }
set { this["response"] = value; }
}
[Serializable]
public class RestObject : Dictionary<string, object>
{
public string Status
{
get { return this["status"] as string; }
set { this["status"] = value; }
}
public RestObject(string status)
{
Status = status;
}
public string Error
{
get { return this["error"] as string; }
set { this["error"] = value; }
}
/// <summary>
/// Gets value safely, if it does not exist, return null. Sets/Adds value safely, if null it will remove.
/// </summary>
/// <param name="key"></param>
/// <param name="value"></param>
/// <returns>Returns null if key does not exist.</returns>
public new object this[string key]
{
get
{
object ret;
if (TryGetValue(key, out ret))
return ret;
return null;
}
set
{
if (!ContainsKey(key))
{
if (value == null)
return;
Add(key, value);
}
else
{
if (value != null)
base[key] = value;
else
Remove(key);
}
}
}
}
public string Response
{
get { return this["response"] as string; }
set { this["response"] = value; }
}
public RestObject(string status)
{
Status = status;
}
/// <summary>
/// Gets value safely, if it does not exist, return null. Sets/Adds value safely, if null it will remove.
/// </summary>
/// <param name="key"></param>
/// <param name="value"></param>
/// <returns>Returns null if key does not exist.</returns>
public new object this[string key]
{
get
{
object ret;
if (TryGetValue(key, out ret))
return ret;
return null;
}
set
{
if (!ContainsKey(key))
{
if (value == null)
return;
Add(key, value);
}
else
{
if (value != null)
base[key] = value;
else
Remove(key);
}
}
}
}
}

View file

@ -3,40 +3,40 @@ using System.Collections.Generic;
namespace Rests
{
[Serializable]
public class RestVerbs : Dictionary<string, string>
{
/// <summary>
/// Gets value safely, if it does not exist, return null. Sets/Adds value safely, if null it will remove.
/// </summary>
/// <param name="key"></param>
/// <param name="value"></param>
/// <returns>Returns null if key does not exist.</returns>
public new string this[string key]
{
get
{
string ret;
if (TryGetValue(key, out ret))
return ret;
return null;
}
set
{
if (!ContainsKey(key))
{
if (value == null)
return;
Add(key, value);
}
else
{
if (value != null)
base[key] = value;
else
Remove(key);
}
}
}
}
[Serializable]
public class RestVerbs : Dictionary<string, string>
{
/// <summary>
/// Gets value safely, if it does not exist, return null. Sets/Adds value safely, if null it will remove.
/// </summary>
/// <param name="key"></param>
/// <param name="value"></param>
/// <returns>Returns null if key does not exist.</returns>
public new string this[string key]
{
get
{
string ret;
if (TryGetValue(key, out ret))
return ret;
return null;
}
set
{
if (!ContainsKey(key))
{
if (value == null)
return;
Add(key, value);
}
else
{
if (value != null)
base[key] = value;
else
Remove(key);
}
}
}
}
}

View file

@ -6,84 +6,96 @@ using HttpServer;
namespace Rests
{
/// <summary>
///
/// </summary>
/// <param name="username">Username to verify</param>
/// <param name="password">Password to verify</param>
/// <returns>Returning a restobject with a null error means a successful verification.</returns>
public delegate RestObject VerifyD(string username, string password);
public class SecureRest : Rest
{
public Dictionary<string, object> Tokens { get; protected set; }
public event VerifyD Verify;
public SecureRest(IPAddress ip, int port)
: base(ip, port)
{
Tokens = new Dictionary<string, object>();
Register(new RestCommand("/token/create/{username}/{password}", NewToken) { RequiresToken = false });
Register(new RestCommand("/token/destroy/{token}", DestroyToken) { RequiresToken = true });
}
/// <summary>
///
/// </summary>
/// <param name="username">Username to verify</param>
/// <param name="password">Password to verify</param>
/// <returns>Returning a restobject with a null error means a successful verification.</returns>
public delegate RestObject VerifyD(string username, string password);
object DestroyToken(RestVerbs verbs, IParameterCollection parameters)
{
var token = verbs["token"];
try
{
Tokens.Remove(token);
}
catch (Exception)
{
return new Dictionary<string, string> { { "status", "400" }, { "error", "The specified token queued for destruction failed to be deleted." } };
}
return new Dictionary<string, string> { { "status", "200" }, { "response", "Requested token was successfully destroyed." } };
}
public class SecureRest : Rest
{
public Dictionary<string, object> Tokens { get; protected set; }
public event VerifyD Verify;
object NewToken(RestVerbs verbs, IParameterCollection parameters)
{
var user = verbs["username"];
var pass = verbs["password"];
public SecureRest(IPAddress ip, int port)
: base(ip, port)
{
Tokens = new Dictionary<string, object>();
Register(new RestCommand("/token/create/{username}/{password}", NewToken) {RequiresToken = false});
Register(new RestCommand("/token/destroy/{token}", DestroyToken) {RequiresToken = true});
}
RestObject obj = null;
if (Verify != null)
obj = Verify(user, pass);
private object DestroyToken(RestVerbs verbs, IParameterCollection parameters)
{
var token = verbs["token"];
try
{
Tokens.Remove(token);
}
catch (Exception)
{
return new Dictionary<string, string>
{{"status", "400"}, {"error", "The specified token queued for destruction failed to be deleted."}};
}
return new Dictionary<string, string>
{{"status", "200"}, {"response", "Requested token was successfully destroyed."}};
}
if (obj == null)
obj = new RestObject("401") { Error = "Invalid username/password combination provided. Please re-submit your query with a correct pair." };
private object NewToken(RestVerbs verbs, IParameterCollection parameters)
{
var user = verbs["username"];
var pass = verbs["password"];
if (obj.Error != null)
return obj;
RestObject obj = null;
if (Verify != null)
obj = Verify(user, pass);
string hash;
var rand = new Random();
var randbytes = new byte[32];
do
{
rand.NextBytes(randbytes);
hash = randbytes.Aggregate("", (s, b) => s + b.ToString("X2"));
} while (Tokens.ContainsKey(hash));
if (obj == null)
obj = new RestObject("401")
{Error = "Invalid username/password combination provided. Please re-submit your query with a correct pair."};
Tokens.Add(hash, user);
if (obj.Error != null)
return obj;
obj["token"] = hash;
return obj;
}
string hash;
var rand = new Random();
var randbytes = new byte[32];
do
{
rand.NextBytes(randbytes);
hash = randbytes.Aggregate("", (s, b) => s + b.ToString("X2"));
} while (Tokens.ContainsKey(hash));
Tokens.Add(hash, user);
obj["token"] = hash;
return obj;
}
protected override object ExecuteCommand(RestCommand cmd, RestVerbs verbs, IParameterCollection parms)
{
if (cmd.RequiresToken)
{
var strtoken = parms["token"];
if (strtoken == null)
return new Dictionary<string, string>
{{"status", "401"}, {"error", "Not authorized. The specified API endpoint requires a token."}};
protected override object ExecuteCommand(RestCommand cmd, RestVerbs verbs, IParameterCollection parms)
{
if (cmd.RequiresToken)
{
var strtoken = parms["token"];
if (strtoken == null)
return new Dictionary<string, string> { { "status", "401" }, { "error", "Not authorized. The specified API endpoint requires a token." } };
object token;
if (!Tokens.TryGetValue(strtoken, out token))
return new Dictionary<string, string> { { "status", "403" }, { "error", "Not authorized. The specified API endpoint requires a token, but the provided token was not valid." } };
}
return base.ExecuteCommand(cmd, verbs, parms);
}
}
}
object token;
if (!Tokens.TryGetValue(strtoken, out token))
return new Dictionary<string, string>
{
{"status", "403"},
{
"error",
"Not authorized. The specified API endpoint requires a token, but the provided token was not valid."
}
};
}
return base.ExecuteCommand(cmd, verbs, parms);
}
}
}

View file

@ -8,13 +8,13 @@ namespace TShockAPI
{
public class StatTracker
{
Utils Utils = TShock.Utils;
private Utils Utils = TShock.Utils;
public DateTime lastcheck = DateTime.MinValue;
readonly int checkinFrequency = 5;
private readonly int checkinFrequency = 5;
public void checkin()
{
if ((DateTime.Now - lastcheck).TotalMinutes >= checkinFrequency)
if ((DateTime.Now - lastcheck).TotalMinutes >= checkinFrequency)
{
ThreadPool.QueueUserWorkItem(callHome);
lastcheck = DateTime.Now;
@ -51,17 +51,23 @@ namespace TShockAPI
using (var client = new WebClient())
{
client.Headers.Add("user-agent",
"TShock (" + TShock.VersionNum + ")");
"TShock (" + TShock.VersionNum + ")");
try
{
string response;
if (TShock.Config.DisablePlayerCountReporting)
{
response = client.DownloadString("http://tshock.co/tickto.php?do=log&fp=" + fp + "&ver=" + TShock.VersionNum + "&os=" + Environment.OSVersion + "&mono=" + Main.runningMono + "&port=" + Netplay.serverPort + "&plcount=0");
response =
client.DownloadString("http://tshock.co/tickto.php?do=log&fp=" + fp + "&ver=" + TShock.VersionNum + "&os=" +
Environment.OSVersion + "&mono=" + Main.runningMono + "&port=" + Netplay.serverPort +
"&plcount=0");
}
else
{
response = client.DownloadString("http://tshock.co/tickto.php?do=log&fp=" + fp + "&ver=" + TShock.VersionNum + "&os=" + Environment.OSVersion + "&mono=" + Main.runningMono + "&port=" + Netplay.serverPort + "&plcount=" + TShock.Utils.ActivePlayers());
response =
client.DownloadString("http://tshock.co/tickto.php?do=log&fp=" + fp + "&ver=" + TShock.VersionNum + "&os=" +
Environment.OSVersion + "&mono=" + Main.runningMono + "&port=" + Netplay.serverPort +
"&plcount=" + TShock.Utils.ActivePlayers());
}
Log.ConsoleInfo("Stat Tracker: " + response + "\n");
}
@ -72,4 +78,4 @@ namespace TShockAPI
}
}
}
}
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -24,79 +24,80 @@ using Newtonsoft.Json;
namespace TShockAPI
{
class UpdateManager
{
static string updateUrl = "http://shankshock.com/tshock-update.json";
public static DateTime lastcheck = DateTime.MinValue;
/// <summary>
/// Check once every X minutes.
/// </summary>
static readonly int CheckXMinutes = 30;
internal class UpdateManager
{
private static string updateUrl = "http://shankshock.com/tshock-update.json";
public static DateTime lastcheck = DateTime.MinValue;
public static void UpdateProcedureCheck()
{
if ((DateTime.Now - lastcheck).TotalMinutes >= CheckXMinutes)
{
ThreadPool.QueueUserWorkItem(CheckUpdate);
lastcheck = DateTime.Now;
}
}
/// <summary>
/// Check once every X minutes.
/// </summary>
private static readonly int CheckXMinutes = 30;
public static void CheckUpdate(object o)
{
var updates = ServerIsOutOfDate();
if (updates != null)
{
NotifyAdministrators(updates);
}
}
public static void UpdateProcedureCheck()
{
if ((DateTime.Now - lastcheck).TotalMinutes >= CheckXMinutes)
{
ThreadPool.QueueUserWorkItem(CheckUpdate);
lastcheck = DateTime.Now;
}
}
/// <summary>
/// Checks to see if the server is out of date.
/// </summary>
/// <returns></returns>
private static Dictionary<string, string> ServerIsOutOfDate()
{
using (var client = new WebClient())
{
client.Headers.Add("user-agent",
"Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.0.3705;)");
try
{
string updatejson = client.DownloadString(updateUrl);
var update = JsonConvert.DeserializeObject<Dictionary<string, string>>(updatejson);
var version = new Version(update["version"]);
if (TShock.VersionNum.CompareTo(version) < 0)
return update;
}
catch (Exception e)
{
Log.Error(e.ToString());
}
return null;
}
}
public static void CheckUpdate(object o)
{
var updates = ServerIsOutOfDate();
if (updates != null)
{
NotifyAdministrators(updates);
}
}
private static void NotifyAdministrators(Dictionary<string, string> update)
{
var changes = update["changes"].Split(new[] { '\n' }, StringSplitOptions.RemoveEmptyEntries);
NotifyAdministrator(TSPlayer.Server, changes);
foreach (TSPlayer player in TShock.Players)
{
if (player != null && player.Active && player.Group.HasPermission(Permissions.maintenance))
{
NotifyAdministrator(player, changes);
}
}
}
/// <summary>
/// Checks to see if the server is out of date.
/// </summary>
/// <returns></returns>
private static Dictionary<string, string> ServerIsOutOfDate()
{
using (var client = new WebClient())
{
client.Headers.Add("user-agent",
"Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.0.3705;)");
try
{
string updatejson = client.DownloadString(updateUrl);
var update = JsonConvert.DeserializeObject<Dictionary<string, string>>(updatejson);
var version = new Version(update["version"]);
if (TShock.VersionNum.CompareTo(version) < 0)
return update;
}
catch (Exception e)
{
Log.Error(e.ToString());
}
return null;
}
}
private static void NotifyAdministrator(TSPlayer player, string[] changes)
{
player.SendMessage("The server is out of date.", Color.Red);
for (int j = 0; j < changes.Length; j++)
{
player.SendMessage(changes[j], Color.Red);
}
}
}
}
private static void NotifyAdministrators(Dictionary<string, string> update)
{
var changes = update["changes"].Split(new[] {'\n'}, StringSplitOptions.RemoveEmptyEntries);
NotifyAdministrator(TSPlayer.Server, changes);
foreach (TSPlayer player in TShock.Players)
{
if (player != null && player.Active && player.Group.HasPermission(Permissions.maintenance))
{
NotifyAdministrator(player, changes);
}
}
}
private static void NotifyAdministrator(TSPlayer player, string[] changes)
{
player.SendMessage("The server is out of date.", Color.Red);
for (int j = 0; j < changes.Length; j++)
{
player.SendMessage(changes[j], Color.Red);
}
}
}
}

File diff suppressed because it is too large Load diff