Merge branch 'general-devel' of github.com:TShock/TShock

Conflicts:
	DBEditor/Main.Designer.cs
	DBEditor/Main.cs
This commit is contained in:
high 2011-08-05 00:55:54 -04:00
commit 4cf35a3093
50 changed files with 2567 additions and 1506 deletions

3
.gitignore vendored
View file

@ -51,4 +51,5 @@ Thumbs.db
#Template Bat file# #Template Bat file#
################### ###################
myass.bat myass.bat
/TestResults

View file

@ -5,21 +5,23 @@ using System.Text;
namespace TShockDBEditor namespace TShockDBEditor
{ {
public class Commandlist public class TShockCommandsList
{ {
public static List<string> CommandList = new List<string>(); public static void AddRemainingTShockCommands()
public static void AddCommands()
{ {
List<string> CommandList = new List<string>();
CommandList.Add("reservedslot"); CommandList.Add("reservedslot");
CommandList.Add("canwater"); CommandList.Add("canwater");
CommandList.Add("canlava"); CommandList.Add("canlava");
CommandList.Add("canbuild");
CommandList.Add("adminchat");
CommandList.Add("warp"); CommandList.Add("warp");
CommandList.Add("kick"); CommandList.Add("kick");
CommandList.Add("ban"); CommandList.Add("ban");
CommandList.Add("unban"); CommandList.Add("unban");
CommandList.Add("whitelist"); CommandList.Add("whitelist");
CommandList.Add("maintenace"); CommandList.Add("maintenance");
CommandList.Add("causeevents"); CommandList.Add("causeevents");
CommandList.Add("spawnboss"); CommandList.Add("spawnboss");
CommandList.Add("spawnmob"); CommandList.Add("spawnmob");
@ -42,6 +44,12 @@ namespace TShockDBEditor
CommandList.Add("ignorecheatdetection"); CommandList.Add("ignorecheatdetection");
CommandList.Add("ignoregriefdetection"); CommandList.Add("ignoregriefdetection");
CommandList.Add("usebanneditem"); CommandList.Add("usebanneditem");
foreach (string command in CommandList)
{
if (!TShockDBEditor.CommandList.Contains(command))
TShockDBEditor.CommandList.Add(command);
}
} }
} }
} }

View file

@ -82,6 +82,8 @@
this.label14 = new System.Windows.Forms.Label(); this.label14 = new System.Windows.Forms.Label();
this.lst_userlist = new System.Windows.Forms.ListBox(); this.lst_userlist = new System.Windows.Forms.ListBox();
this.tabPage6 = new System.Windows.Forms.TabPage(); this.tabPage6 = new System.Windows.Forms.TabPage();
this.groupBox7 = new System.Windows.Forms.GroupBox();
this.lst_bans = new System.Windows.Forms.ListBox();
this.groupBox6 = new System.Windows.Forms.GroupBox(); this.groupBox6 = new System.Windows.Forms.GroupBox();
this.lbl_newbanstatus = new System.Windows.Forms.Label(); this.lbl_newbanstatus = new System.Windows.Forms.Label();
this.label16 = new System.Windows.Forms.Label(); this.label16 = new System.Windows.Forms.Label();
@ -99,7 +101,6 @@
this.label19 = new System.Windows.Forms.Label(); this.label19 = new System.Windows.Forms.Label();
this.txt_banreason = new System.Windows.Forms.TextBox(); this.txt_banreason = new System.Windows.Forms.TextBox();
this.label18 = new System.Windows.Forms.Label(); this.label18 = new System.Windows.Forms.Label();
this.lst_bans = new System.Windows.Forms.ListBox();
this.tabControl1 = new System.Windows.Forms.TabControl(); this.tabControl1 = new System.Windows.Forms.TabControl();
this.tabPage3 = new System.Windows.Forms.TabPage(); this.tabPage3 = new System.Windows.Forms.TabPage();
this.btn_OpenLocalDB = new System.Windows.Forms.Button(); this.btn_OpenLocalDB = new System.Windows.Forms.Button();
@ -115,7 +116,6 @@
this.label7 = new System.Windows.Forms.Label(); this.label7 = new System.Windows.Forms.Label();
this.label6 = new System.Windows.Forms.Label(); this.label6 = new System.Windows.Forms.Label();
this.label5 = new System.Windows.Forms.Label(); this.label5 = new System.Windows.Forms.Label();
this.groupBox7 = new System.Windows.Forms.GroupBox();
this.tabControl.SuspendLayout(); this.tabControl.SuspendLayout();
this.tabPage1.SuspendLayout(); this.tabPage1.SuspendLayout();
this.tabPage2.SuspendLayout(); this.tabPage2.SuspendLayout();
@ -125,12 +125,12 @@
this.groupBox4.SuspendLayout(); this.groupBox4.SuspendLayout();
this.groupBox3.SuspendLayout(); this.groupBox3.SuspendLayout();
this.tabPage6.SuspendLayout(); this.tabPage6.SuspendLayout();
this.groupBox7.SuspendLayout();
this.groupBox6.SuspendLayout(); this.groupBox6.SuspendLayout();
this.groupBox5.SuspendLayout(); this.groupBox5.SuspendLayout();
this.tabControl1.SuspendLayout(); this.tabControl1.SuspendLayout();
this.tabPage3.SuspendLayout(); this.tabPage3.SuspendLayout();
this.tabPage4.SuspendLayout(); this.tabPage4.SuspendLayout();
this.groupBox7.SuspendLayout();
this.SuspendLayout(); this.SuspendLayout();
// //
// itemListBanned // itemListBanned
@ -675,6 +675,25 @@
this.tabPage6.Text = "Ban Manager"; this.tabPage6.Text = "Ban Manager";
this.tabPage6.UseVisualStyleBackColor = true; this.tabPage6.UseVisualStyleBackColor = true;
// //
// groupBox7
//
this.groupBox7.Controls.Add(this.lst_bans);
this.groupBox7.Location = new System.Drawing.Point(6, 23);
this.groupBox7.Name = "groupBox7";
this.groupBox7.Size = new System.Drawing.Size(284, 352);
this.groupBox7.TabIndex = 13;
this.groupBox7.TabStop = false;
this.groupBox7.Text = "Ban List";
//
// lst_bans
//
this.lst_bans.FormattingEnabled = true;
this.lst_bans.Location = new System.Drawing.Point(6, 19);
this.lst_bans.Name = "lst_bans";
this.lst_bans.Size = new System.Drawing.Size(272, 329);
this.lst_bans.TabIndex = 0;
this.lst_bans.SelectedIndexChanged += new System.EventHandler(this.lst_bans_SelectedIndexChanged);
//
// groupBox6 // groupBox6
// //
this.groupBox6.Controls.Add(this.lbl_newbanstatus); this.groupBox6.Controls.Add(this.lbl_newbanstatus);
@ -839,15 +858,6 @@
this.label18.TabIndex = 4; this.label18.TabIndex = 4;
this.label18.Text = "Name:"; this.label18.Text = "Name:";
// //
// lst_bans
//
this.lst_bans.FormattingEnabled = true;
this.lst_bans.Location = new System.Drawing.Point(6, 19);
this.lst_bans.Name = "lst_bans";
this.lst_bans.Size = new System.Drawing.Size(272, 329);
this.lst_bans.TabIndex = 0;
this.lst_bans.SelectedIndexChanged += new System.EventHandler(this.lst_bans_SelectedIndexChanged);
//
// tabControl1 // tabControl1
// //
this.tabControl1.Controls.Add(this.tabPage3); this.tabControl1.Controls.Add(this.tabPage3);
@ -992,16 +1002,6 @@
this.label5.TabIndex = 0; this.label5.TabIndex = 0;
this.label5.Text = "Hostname:"; this.label5.Text = "Hostname:";
// //
// groupBox7
//
this.groupBox7.Controls.Add(this.lst_bans);
this.groupBox7.Location = new System.Drawing.Point(6, 23);
this.groupBox7.Name = "groupBox7";
this.groupBox7.Size = new System.Drawing.Size(284, 352);
this.groupBox7.TabIndex = 13;
this.groupBox7.TabStop = false;
this.groupBox7.Text = "Ban List";
//
// TShockDBEditor // TShockDBEditor
// //
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
@ -1011,6 +1011,7 @@
this.Controls.Add(this.tabControl); this.Controls.Add(this.tabControl);
this.Name = "TShockDBEditor"; this.Name = "TShockDBEditor";
this.Text = "TShockDBEditor"; this.Text = "TShockDBEditor";
this.Load += new System.EventHandler(this.TShockDBEditor_Load);
this.tabControl.ResumeLayout(false); this.tabControl.ResumeLayout(false);
this.tabPage1.ResumeLayout(false); this.tabPage1.ResumeLayout(false);
this.tabPage1.PerformLayout(); this.tabPage1.PerformLayout();
@ -1026,6 +1027,7 @@
this.groupBox3.ResumeLayout(false); this.groupBox3.ResumeLayout(false);
this.groupBox3.PerformLayout(); this.groupBox3.PerformLayout();
this.tabPage6.ResumeLayout(false); this.tabPage6.ResumeLayout(false);
this.groupBox7.ResumeLayout(false);
this.groupBox6.ResumeLayout(false); this.groupBox6.ResumeLayout(false);
this.groupBox6.PerformLayout(); this.groupBox6.PerformLayout();
this.groupBox5.ResumeLayout(false); this.groupBox5.ResumeLayout(false);
@ -1034,7 +1036,6 @@
this.tabPage3.ResumeLayout(false); this.tabPage3.ResumeLayout(false);
this.tabPage4.ResumeLayout(false); this.tabPage4.ResumeLayout(false);
this.tabPage4.PerformLayout(); this.tabPage4.PerformLayout();
this.groupBox7.ResumeLayout(false);
this.ResumeLayout(false); this.ResumeLayout(false);
} }

View file

@ -18,6 +18,7 @@ namespace TShockDBEditor
{ {
public OpenFileDialog dialog = new OpenFileDialog(); public OpenFileDialog dialog = new OpenFileDialog();
public List<Group> groups = new List<Group>(); public List<Group> groups = new List<Group>();
public static List<string> CommandList = new List<string>();
public IDbConnection DB; public IDbConnection DB;
public string dbtype = ""; public string dbtype = "";
@ -25,7 +26,6 @@ namespace TShockDBEditor
{ {
InitializeComponent(); InitializeComponent();
Itemlist.AddItems(); Itemlist.AddItems();
Commandlist.AddCommands();
dialog.FileOk += new CancelEventHandler(dialog_FileOk); dialog.FileOk += new CancelEventHandler(dialog_FileOk);
dialog.Filter = "SQLite Database (*.sqlite)|*.sqlite"; dialog.Filter = "SQLite Database (*.sqlite)|*.sqlite";
} }
@ -50,6 +50,7 @@ namespace TShockDBEditor
itemListBanned.Items.Add(reader.Get<string>("ItemName")); itemListBanned.Items.Add(reader.Get<string>("ItemName"));
} }
} }
using (var com = DB.CreateCommand()) using (var com = DB.CreateCommand())
{ {
com.CommandText = com.CommandText =
@ -68,6 +69,21 @@ namespace TShockDBEditor
lst_newusergrplist.Items.Add(reader.Get<string>("GroupName")); lst_newusergrplist.Items.Add(reader.Get<string>("GroupName"));
} }
} }
using (var reader = com.ExecuteReader())
{
while (reader.Read())
{
foreach (string command in reader.Get<string>("Commands").Split(','))
{
if (!lst_groupList.Items.Contains(command))
if (!CommandList.Contains(command))
CommandList.Add(command);
}
}
}
TShockCommandsList.AddRemainingTShockCommands();
} }
using (var com = DB.CreateCommand()) using (var com = DB.CreateCommand())
{ {
@ -203,7 +219,10 @@ namespace TShockDBEditor
private void lst_groupList_SelectedIndexChanged(object sender, EventArgs e) private void lst_groupList_SelectedIndexChanged(object sender, EventArgs e)
{ {
UpdateGroupIndex(lst_groupList.SelectedIndex); if ((string)lst_groupList.SelectedItem != "superadmin")
UpdateGroupIndex(lst_groupList.SelectedIndex);
else
lst_groupList.SelectedIndex = -1;
} }
private void UpdateGroupIndex(int index) private void UpdateGroupIndex(int index)
@ -238,10 +257,10 @@ namespace TShockDBEditor
if (lbl_grpchild.Text == "") if (lbl_grpchild.Text == "")
lbl_grpchild.Text = "none"; lbl_grpchild.Text = "none";
for (int i = 0; i < Commandlist.CommandList.Count; i++) for (int i = 0; i < CommandList.Count; i++)
{ {
if (!lst_AvailableCmds.Items.Contains(Commandlist.CommandList[i])) if (!lst_AvailableCmds.Items.Contains(CommandList[i]))
lst_bannedCmds.Items.Add(Commandlist.CommandList[i]); lst_bannedCmds.Items.Add(CommandList[i]);
} }
} }
} }
@ -535,6 +554,8 @@ namespace TShockDBEditor
#endregion #endregion
#region UserTab
private void lst_userlist_SelectedIndexChanged(object sender, EventArgs e) private void lst_userlist_SelectedIndexChanged(object sender, EventArgs e)
{ {
txt_username.Text = "None Selected"; txt_username.Text = "None Selected";
@ -728,5 +749,12 @@ namespace TShockDBEditor
return bytes.Aggregate("", (s, b) => s + b.ToString("X2")); return bytes.Aggregate("", (s, b) => s + b.ToString("X2"));
} }
} }
#endregion
private void TShockDBEditor_Load(object sender, EventArgs e)
{
}
} }
} }

View file

@ -26,7 +26,6 @@
<MapFileExtensions>true</MapFileExtensions> <MapFileExtensions>true</MapFileExtensions>
<ApplicationRevision>0</ApplicationRevision> <ApplicationRevision>0</ApplicationRevision>
<ApplicationVersion>1.0.0.%2a</ApplicationVersion> <ApplicationVersion>1.0.0.%2a</ApplicationVersion>
<IsWebBootstrapper>false</IsWebBootstrapper>
<UseApplicationTrust>false</UseApplicationTrust> <UseApplicationTrust>false</UseApplicationTrust>
<BootstrapperEnabled>true</BootstrapperEnabled> <BootstrapperEnabled>true</BootstrapperEnabled>
</PropertyGroup> </PropertyGroup>
@ -75,8 +74,8 @@
<Reference Include="System.Xml" /> <Reference Include="System.Xml" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="Group.cs" />
<Compile Include="CommandList.cs" /> <Compile Include="CommandList.cs" />
<Compile Include="Group.cs" />
<Compile Include="DbExt.cs" /> <Compile Include="DbExt.cs" />
<Compile Include="Main.cs"> <Compile Include="Main.cs">
<SubType>Form</SubType> <SubType>Form</SubType>

View file

@ -1,5 +1,3 @@
####Do not download the latest master!
TShock is a server modification based upon High6's mod API that allows for basic server administration commands. TShock is a server modification based upon High6's mod API that allows for basic server administration commands.
__Constant builds__: http://ci.tshock.co/ __Constant builds__: http://ci.tshock.co/

View file

@ -18,10 +18,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
using System; using System;
using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq;
using System.Text;
using System.Threading; using System.Threading;
using Terraria; using Terraria;

View file

@ -1,4 +1,4 @@
/* /*
TShock, a server mod for Terraria TShock, a server mod for Terraria
Copyright (C) 2011 The TShock Team Copyright (C) 2011 The TShock Team
@ -17,12 +17,11 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
using System.Linq;
using System.Diagnostics; using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net; using System.Net;
using System.Text;
using System.Threading; using System.Threading;
using Microsoft.Xna.Framework; using Microsoft.Xna.Framework;
using Terraria; using Terraria;
@ -138,13 +137,16 @@ namespace TShockAPI
ChatCommands.Add(new Command("warp", UseWarp, "warp")); ChatCommands.Add(new Command("warp", UseWarp, "warp"));
ChatCommands.Add(new Command("managewarp", SetWarp, "setwarp")); ChatCommands.Add(new Command("managewarp", SetWarp, "setwarp"));
ChatCommands.Add(new Command("managewarp", DeleteWarp, "delwarp")); ChatCommands.Add(new Command("managewarp", DeleteWarp, "delwarp"));
ChatCommands.Add(new Command("managegroup", AddGroup, "addGroup")); ChatCommands.Add(new Command("managewarp", HideWarp, "hidewarp"));
ChatCommands.Add(new Command("managegroup", DeleteGroup, "delGroup")); ChatCommands.Add(new Command("managegroup", AddGroup, "addgroup"));
ChatCommands.Add(new Command("managegroup", ModifyGroup, "modGroup")); ChatCommands.Add(new Command("managegroup", DeleteGroup, "delgroup"));
ChatCommands.Add(new Command("managegroup", ModifyGroup, "modgroup"));
ChatCommands.Add(new Command("manageitem", AddItem, "additem"));
ChatCommands.Add(new Command("manageitem", DeleteItem, "delitem"));
ChatCommands.Add(new Command("cfg", SetSpawn, "setspawn")); ChatCommands.Add(new Command("cfg", SetSpawn, "setspawn"));
ChatCommands.Add(new Command("cfg", Reload, "reload")); ChatCommands.Add(new Command("cfg", Reload, "reload"));
ChatCommands.Add(new Command("cfg", DebugConfiguration, "debug-config")); ChatCommands.Add(new Command("cfg", ShowConfiguration, "showconfig"));
ChatCommands.Add(new Command("cfg", Password, "password")); ChatCommands.Add(new Command("cfg", ServerPassword, "serverpassword"));
ChatCommands.Add(new Command("cfg", Save, "save")); ChatCommands.Add(new Command("cfg", Save, "save"));
ChatCommands.Add(new Command("cfg", MaxSpawns, "maxspawns")); ChatCommands.Add(new Command("cfg", MaxSpawns, "maxspawns"));
ChatCommands.Add(new Command("cfg", SpawnRate, "spawnrate")); ChatCommands.Add(new Command("cfg", SpawnRate, "spawnrate"));
@ -370,7 +372,7 @@ namespace TShockAPI
catch (UserManagerException ex) catch (UserManagerException ex)
{ {
args.Player.SendMessage("Sorry, an error occured: " + ex.Message, Color.Green); args.Player.SendMessage("Sorry, an error occured: " + ex.Message, Color.Green);
Log.ConsoleError("RegisterUser returned an error: " + ex.ToString()); Log.ConsoleError("RegisterUser returned an error: " + ex);
} }
} }
@ -383,7 +385,7 @@ namespace TShockAPI
var user = new User(); var user = new User();
user.Name = args.Parameters[0].ToLower(); user.Name = args.Parameters[0].ToLower();
user.Password = args.Parameters[1]; user.Password = args.Parameters[1];
user.Group = "default"; // FIXME -- we should get this from the DB. user.Group = TShock.Config.DefaultRegistrationGroupName; // FIXME -- we should get this from the DB.
if (TShock.Users.GetUserByName(user.Name) == null) // Cheap way of checking for existance of a user if (TShock.Users.GetUserByName(user.Name) == null) // Cheap way of checking for existance of a user
{ {
@ -406,7 +408,7 @@ namespace TShockAPI
catch (UserManagerException ex) catch (UserManagerException ex)
{ {
args.Player.SendMessage("Sorry, an error occured: " + ex.Message, Color.Green); args.Player.SendMessage("Sorry, an error occured: " + ex.Message, Color.Green);
Log.ConsoleError("RegisterUser returned an error: " + ex.ToString()); Log.ConsoleError("RegisterUser returned an error: " + ex);
} }
} }
@ -414,15 +416,18 @@ namespace TShockAPI
private static void ManageUsers(CommandArgs args) private static void ManageUsers(CommandArgs args)
{ {
if (args.Parameters.Count < 2) // This guy needs to go away for the help later on to take effect.
{
args.Player.SendMessage("Syntax: /user <add/del> <ip/user:pass> [group]"); //if (args.Parameters.Count < 2)
args.Player.SendMessage("Note: Passwords are stored with SHA512 hashing. To reset a user's password, remove and re-add them."); //{
return; // args.Player.SendMessage("Syntax: /user <add/del> <ip/user:pass> [group]");
} // args.Player.SendMessage("Note: Passwords are stored with SHA512 hashing. To reset a user's password, remove and re-add them.");
// return;
//}
string subcmd = args.Parameters[0]; string subcmd = args.Parameters[0];
// Add requires a username:password pair/ip address and a group specified.
if (subcmd == "add") if (subcmd == "add")
{ {
var namepass = args.Parameters[1].Split(':'); var namepass = args.Parameters[1].Split(':');
@ -469,6 +474,7 @@ namespace TShockAPI
Log.ConsoleError(ex.ToString()); Log.ConsoleError(ex.ToString());
} }
} }
// User deletion requires a username
else if (subcmd == "del" && args.Parameters.Count == 2) else if (subcmd == "del" && args.Parameters.Count == 2)
{ {
var user = new User(); var user = new User();
@ -489,13 +495,86 @@ namespace TShockAPI
Log.ConsoleError(ex.ToString()); Log.ConsoleError(ex.ToString());
} }
} }
// Password changing requires a username, and a new password to set
else if (subcmd == "password")
{
var user = new User();
user.Name = args.Parameters[1];
try
{
if (args.Parameters.Count == 3)
{
args.Player.SendMessage("Changed the password of " + user.Name + "!", Color.Green);
TShock.Users.SetUserPassword(user, args.Parameters[2]);
Log.ConsoleInfo(args.Player.Name + " changed the password of Account " + user.Name);
}
else
{
args.Player.SendMessage("Invalid user password syntax. Try /user help.", Color.Red);
}
}
catch (UserManagerException ex)
{
args.Player.SendMessage(ex.Message, Color.Green);
Log.ConsoleError(ex.ToString());
}
}
// Group changing requires a username or IP address, and a new group to set
else if (subcmd == "group")
{
var user = new User();
if (args.Parameters[1].Contains("."))
user.Address = args.Parameters[1];
else
user.Name = args.Parameters[1];
try
{
if (args.Parameters.Count == 3)
{
if (!string.IsNullOrEmpty(user.Address))
{
args.Player.SendMessage("IP Address " + user.Address + " has been changed to group " + args.Parameters[2] + "!", Color.Green);
TShock.Users.SetUserGroup(user, args.Parameters[2]);
Log.ConsoleInfo(args.Player.Name + " changed IP Address " + user.Address + " to group " + args.Parameters[2]);
}
else
{
args.Player.SendMessage("Account " + user.Name + " has been changed to group " + args.Parameters[2] + "!", Color.Green);
TShock.Users.SetUserGroup(user, args.Parameters[2]);
Log.ConsoleInfo(args.Player.Name + " changed Account " + user.Name + " to group " + args.Parameters[2]);
}
}
else
{
args.Player.SendMessage("Invalid user group syntax. Try /user help.", Color.Red);
}
}
catch (UserManagerException ex)
{
args.Player.SendMessage(ex.Message, Color.Green);
Log.ConsoleError(ex.ToString());
}
}
else if (subcmd == "help")
{
args.Player.SendMessage("Help for user subcommands:");
args.Player.SendMessage("/user add username:password group -- Adds a specified user");
args.Player.SendMessage("/user del username -- Removes a specified user");
args.Player.SendMessage("/user password username newpassword -- Changes a user's password");
args.Player.SendMessage("/user group username newgroup -- Changes a user's group");
}
else else
{ {
args.Player.SendMessage("Invalid syntax. Try /user help.", Color.Red); args.Player.SendMessage("Invalid user syntax. Try /user help.", Color.Red);
} }
} }
#endregion #endregion
#region Player Management Commands #region Player Management Commands
private static void GrabUserIP(CommandArgs args) private static void GrabUserIP(CommandArgs args)
@ -626,7 +705,18 @@ namespace TShockAPI
if (TShock.Bans.RemoveBan(ban.IP)) if (TShock.Bans.RemoveBan(ban.IP))
args.Player.SendMessage(string.Format("Unbanned {0} ({1})!", ban.Name, ban.IP), Color.Red); args.Player.SendMessage(string.Format("Unbanned {0} ({1})!", ban.Name, ban.IP), Color.Red);
else else
args.Player.SendMessage(string.Format("Failed to Unbanned {0} ({1})!", ban.Name, ban.IP), Color.Red); args.Player.SendMessage(string.Format("Failed to unban {0} ({1})!", ban.Name, ban.IP), Color.Red);
}
else if (!TShock.Config.EnableBanOnUsernames)
{
ban = TShock.Bans.GetBanByIp(plStr);
if (ban == null)
args.Player.SendMessage(string.Format("Failed to unban {0}, not found.", args.Parameters[0]), Color.Red);
else if (TShock.Bans.RemoveBan(ban.IP))
args.Player.SendMessage(string.Format("Unbanned {0} ({1})!", ban.Name, ban.IP), Color.Red);
else
args.Player.SendMessage(string.Format("Failed to unban {0} ({1})!", ban.Name, ban.IP), Color.Red);
} }
else else
{ {
@ -695,7 +785,7 @@ namespace TShockAPI
if (TShock.Bans.RemoveBan(ban.IP)) if (TShock.Bans.RemoveBan(ban.IP))
args.Player.SendMessage(string.Format("Unbanned {0} ({1})!", ban.Name, ban.IP), Color.Red); args.Player.SendMessage(string.Format("Unbanned {0} ({1})!", ban.Name, ban.IP), Color.Red);
else else
args.Player.SendMessage(string.Format("Failed to Unbanned {0} ({1})!", ban.Name, ban.IP), Color.Red); args.Player.SendMessage(string.Format("Failed to unban {0} ({1})!", ban.Name, ban.IP), Color.Red);
} }
else else
{ {
@ -859,7 +949,7 @@ namespace TShockAPI
return; return;
} }
NPC eater = Tools.GetNPCById(13); NPC eater = Tools.GetNPCById(13);
TSPlayer.Server.SpawnNPC(eater.type, eater.name, amount, (int)args.Player.TileX, (int)args.Player.TileY); TSPlayer.Server.SpawnNPC(eater.type, eater.name, amount, args.Player.TileX, args.Player.TileY);
Tools.Broadcast(string.Format("{0} has spawned eater of worlds {1} times!", args.Player.Name, amount)); Tools.Broadcast(string.Format("{0} has spawned eater of worlds {1} times!", args.Player.Name, amount));
} }
@ -878,7 +968,7 @@ namespace TShockAPI
} }
NPC eye = Tools.GetNPCById(4); NPC eye = Tools.GetNPCById(4);
TSPlayer.Server.SetTime(false, 0.0); TSPlayer.Server.SetTime(false, 0.0);
TSPlayer.Server.SpawnNPC(eye.type, eye.name, amount, (int)args.Player.TileX, (int)args.Player.TileY); TSPlayer.Server.SpawnNPC(eye.type, eye.name, amount, args.Player.TileX, args.Player.TileY);
Tools.Broadcast(string.Format("{0} has spawned eye {1} times!", args.Player.Name, amount)); Tools.Broadcast(string.Format("{0} has spawned eye {1} times!", args.Player.Name, amount));
} }
@ -896,7 +986,7 @@ namespace TShockAPI
return; return;
} }
NPC king = Tools.GetNPCById(50); NPC king = Tools.GetNPCById(50);
TSPlayer.Server.SpawnNPC(king.type, king.name, amount, (int)args.Player.TileX, (int)args.Player.TileY); TSPlayer.Server.SpawnNPC(king.type, king.name, amount, args.Player.TileX, args.Player.TileY);
Tools.Broadcast(string.Format("{0} has spawned king slime {1} times!", args.Player.Name, amount)); Tools.Broadcast(string.Format("{0} has spawned king slime {1} times!", args.Player.Name, amount));
} }
@ -915,7 +1005,7 @@ namespace TShockAPI
} }
NPC skeletron = Tools.GetNPCById(35); NPC skeletron = Tools.GetNPCById(35);
TSPlayer.Server.SetTime(false, 0.0); TSPlayer.Server.SetTime(false, 0.0);
TSPlayer.Server.SpawnNPC(skeletron.type, skeletron.name, amount, (int)args.Player.TileX, (int)args.Player.TileY); TSPlayer.Server.SpawnNPC(skeletron.type, skeletron.name, amount, args.Player.TileX, args.Player.TileY);
Tools.Broadcast(string.Format("{0} has spawned skeletron {1} times!", args.Player.Name, amount)); Tools.Broadcast(string.Format("{0} has spawned skeletron {1} times!", args.Player.Name, amount));
} }
@ -937,10 +1027,10 @@ namespace TShockAPI
NPC king = Tools.GetNPCById(50); NPC king = Tools.GetNPCById(50);
NPC skeletron = Tools.GetNPCById(35); NPC skeletron = Tools.GetNPCById(35);
TSPlayer.Server.SetTime(false, 0.0); TSPlayer.Server.SetTime(false, 0.0);
TSPlayer.Server.SpawnNPC(eater.type, eater.name, amount, (int)args.Player.TileX, (int)args.Player.TileY); TSPlayer.Server.SpawnNPC(eater.type, eater.name, amount, args.Player.TileX, args.Player.TileY);
TSPlayer.Server.SpawnNPC(eye.type, eye.name, amount, (int)args.Player.TileX, (int)args.Player.TileY); TSPlayer.Server.SpawnNPC(eye.type, eye.name, amount, args.Player.TileX, args.Player.TileY);
TSPlayer.Server.SpawnNPC(king.type, king.name, amount, (int)args.Player.TileX, (int)args.Player.TileY); TSPlayer.Server.SpawnNPC(king.type, king.name, amount, args.Player.TileX, args.Player.TileY);
TSPlayer.Server.SpawnNPC(skeletron.type, skeletron.name, amount, (int)args.Player.TileX, (int)args.Player.TileY); TSPlayer.Server.SpawnNPC(skeletron.type, skeletron.name, amount, args.Player.TileX, args.Player.TileY);
Tools.Broadcast(string.Format("{0} has spawned all bosses {1} times!", args.Player.Name, amount)); Tools.Broadcast(string.Format("{0} has spawned all bosses {1} times!", args.Player.Name, amount));
} }
@ -977,7 +1067,7 @@ namespace TShockAPI
var npc = npcs[0]; var npc = npcs[0];
if (npc.type >= 1 && npc.type < Main.maxNPCTypes) if (npc.type >= 1 && npc.type < Main.maxNPCTypes)
{ {
TSPlayer.Server.SpawnNPC(npc.type, npc.name, amount, (int)args.Player.TileX, (int)args.Player.TileY, 50, 20); TSPlayer.Server.SpawnNPC(npc.type, npc.name, amount, args.Player.TileX, args.Player.TileY, 50, 20);
Tools.Broadcast(string.Format("{0} was spawned {1} time(s).", npc.name, amount)); Tools.Broadcast(string.Format("{0} was spawned {1} time(s).", npc.name, amount));
} }
else else
@ -1128,6 +1218,31 @@ namespace TShockAPI
args.Player.SendMessage("Invalid syntax! Proper syntax: /delwarp [name]", Color.Red); args.Player.SendMessage("Invalid syntax! Proper syntax: /delwarp [name]", Color.Red);
} }
private static void HideWarp(CommandArgs args)
{
if (args.Parameters.Count > 1)
{
string warpName = String.Join(" ", args.Parameters);
bool state = false;
if (Boolean.TryParse(args.Parameters[1], out state))
{
if (TShock.Warps.HideWarp(args.Parameters[0], state))
{
if (state)
args.Player.SendMessage("Made warp " + warpName + " private", Color.Yellow);
else
args.Player.SendMessage("Made warp " + warpName + " public", Color.Yellow);
}
else
args.Player.SendMessage("Could not find specified warp", Color.Red);
}
else
args.Player.SendMessage("Invalid syntax! Proper syntax: /hidewarp [name] <true/false>", Color.Red);
}
else
args.Player.SendMessage("Invalid syntax! Proper syntax: /hidewarp [name] <true/false>", Color.Red);
}
private static void UseWarp(CommandArgs args) private static void UseWarp(CommandArgs args)
{ {
if (args.Parameters.Count < 1) if (args.Parameters.Count < 1)
@ -1156,7 +1271,7 @@ namespace TShockAPI
page--; //Substract 1 as pages are parsed starting at 1 and not 0 page--; //Substract 1 as pages are parsed starting at 1 and not 0
} }
var warps = TShock.Warps.ListAllWarps(Main.worldID.ToString()); var warps = TShock.Warps.ListAllPublicWarps(Main.worldID.ToString());
//Check if they are trying to access a page that doesn't exist. //Check if they are trying to access a page that doesn't exist.
int pagecount = warps.Count / pagelimit; int pagecount = warps.Count / pagelimit;
@ -1207,7 +1322,6 @@ namespace TShockAPI
#endregion Teleport Commands #endregion Teleport Commands
#region Group Management #region Group Management
private static void AddGroup(CommandArgs args) private static void AddGroup(CommandArgs args)
@ -1218,7 +1332,7 @@ namespace TShockAPI
args.Parameters.RemoveAt(0); args.Parameters.RemoveAt(0);
String permissions = String.Join(",", args.Parameters ); String permissions = String.Join(",", args.Parameters );
String response = TShock.Groups.addGroup(groupname, permissions); String response = TShock.Groups.AddGroup(groupname, permissions);
if( response.Length > 0 ) if( response.Length > 0 )
args.Player.SendMessage(response, Color.Green); args.Player.SendMessage(response, Color.Green);
} }
@ -1234,7 +1348,7 @@ namespace TShockAPI
{ {
String groupname = args.Parameters[0]; String groupname = args.Parameters[0];
String response = TShock.Groups.delGroup(groupname); String response = TShock.Groups.DeleteGroup(groupname);
if (response.Length > 0) if (response.Length > 0)
args.Player.SendMessage(response, Color.Green); args.Player.SendMessage(response, Color.Green);
} }
@ -1256,14 +1370,14 @@ namespace TShockAPI
if (com.Equals("add")) if (com.Equals("add"))
{ {
String response = TShock.Groups.addPermission(groupname, args.Parameters); String response = TShock.Groups.AddPermissions(groupname, args.Parameters);
if (response.Length > 0) if (response.Length > 0)
args.Player.SendMessage(response, Color.Green); args.Player.SendMessage(response, Color.Green);
return; return;
} }
else if (com.Equals("del") || com.Equals("delete")) else if (com.Equals("del") || com.Equals("delete"))
{ {
String response = TShock.Groups.delPermission(groupname, args.Parameters); String response = TShock.Groups.DeletePermissions(groupname, args.Parameters);
if (response.Length > 0) if (response.Length > 0)
args.Player.SendMessage(response, Color.Green); args.Player.SendMessage(response, Color.Green);
return; return;
@ -1273,6 +1387,77 @@ namespace TShockAPI
} }
#endregion Group Management #endregion Group Management
#region Item Management
private static void AddItem(CommandArgs args)
{
if (args.Parameters.Count > 0)
{
var items = Tools.GetItemByIdOrName(args.Parameters[0]);
if (items.Count == 0)
{
args.Player.SendMessage("Invalid item type!", Color.Red);
}
else if (items.Count > 1)
{
args.Player.SendMessage(string.Format("More than one ({0}) item matched!", items.Count), Color.Red);
}
else
{
var item = items[0];
if (item.type >= 1)
{
TShock.Itembans.AddNewBan(args.Parameters[0]);
args.Player.SendMessage(Tools.GetItemByIdOrName(args.Parameters[0])[0].name + " has been banned.", Color.Green);
}
else
{
args.Player.SendMessage("Invalid item type!", Color.Red);
}
}
}
else
{
args.Player.SendMessage("Invalid use: /addItem \"item name\" or /addItem ##", Color.Red);
}
}
private static void DeleteItem(CommandArgs args)
{
if (args.Parameters.Count > 0)
{
var items = Tools.GetItemByIdOrName(args.Parameters[0]);
if (items.Count == 0)
{
args.Player.SendMessage("Invalid item type!", Color.Red);
}
else if (items.Count > 1)
{
args.Player.SendMessage(string.Format("More than one ({0}) item matched!", items.Count), Color.Red);
}
else
{
var item = items[0];
if (item.type >= 1)
{
TShock.Itembans.RemoveBan(args.Parameters[0]);
args.Player.SendMessage(Tools.GetItemByIdOrName(args.Parameters[0])[0].name + " has been unbanned.", Color.Green);
}
else
{
args.Player.SendMessage("Invalid item type!", Color.Red);
}
}
}
else
{
args.Player.SendMessage("Invalid use: /delItem \"item name\" or /delItem ##", Color.Red);
}
}
#endregion Item Management
#region Server Config Commands #region Server Config Commands
private static void SetSpawn(CommandArgs args) private static void SetSpawn(CommandArgs args)
@ -1285,7 +1470,7 @@ namespace TShockAPI
SaveWorld.Start(); SaveWorld.Start();
} }
private static void DebugConfiguration(CommandArgs args) private static void ShowConfiguration(CommandArgs args)
{ {
args.Player.SendMessage("TShock Config:"); args.Player.SendMessage("TShock Config:");
string lineOne = string.Format("BanCheater : {0}, KickCheater : {1}, BanGriefer : {2}, KickGriefer : {3}", string lineOne = string.Format("BanCheater : {0}, KickCheater : {1}, BanGriefer : {2}, KickGriefer : {3}",
@ -1313,7 +1498,7 @@ namespace TShockAPI
args.Player.SendMessage("Configuration reload complete. Some changes may require server restart."); args.Player.SendMessage("Configuration reload complete. Some changes may require server restart.");
} }
private static void Password(CommandArgs args) private static void ServerPassword(CommandArgs args)
{ {
if (args.Parameters.Count != 1) if (args.Parameters.Count != 1)
{ {
@ -1465,10 +1650,10 @@ namespace TShockAPI
{ {
foreach (Region r in TShock.Regions.Regions) foreach (Region r in TShock.Regions.Regions)
{ {
args.Player.SendMessage(r.RegionName + ": P: " + r.DisableBuild + " X: " + r.RegionArea.X + " Y: " + r.RegionArea.Y + " W: " + r.RegionArea.Width + " H: " + r.RegionArea.Height); args.Player.SendMessage(r.Name + ": P: " + r.DisableBuild + " X: " + r.Area.X + " Y: " + r.Area.Y + " W: " + r.Area.Width + " H: " + r.Area.Height);
foreach (int s in r.RegionAllowedIDs) foreach (int s in r.AllowedIDs)
{ {
args.Player.SendMessage(r.RegionName + ": " + s); args.Player.SendMessage(r.Name + ": " + s);
} }
} }
} }
@ -1673,7 +1858,7 @@ namespace TShockAPI
var nameslist = new List<string>(); var nameslist = new List<string>();
for (int i = 0; i < pagelimit && i + (page * pagelimit) < regions.Count; i++) for (int i = 0; i < pagelimit && i + (page * pagelimit) < regions.Count; i++)
{ {
nameslist.Add(regions[i].RegionName); nameslist.Add(regions[i].Name);
} }
//convert the list to an array for joining //convert the list to an array for joining
@ -1918,8 +2103,8 @@ namespace TShockAPI
else else
{ {
var ply = players[0]; var ply = players[0];
args.Player.SendMessage("Annoying " + ply.Name + " for " + annoy.ToString() + " seconds."); args.Player.SendMessage("Annoying " + ply.Name + " for " + annoy + " seconds.");
(new Thread(new ParameterizedThreadStart(ply.Whoopie))).Start(annoy); (new Thread(ply.Whoopie)).Start(annoy);
} }
} }
#endregion General Commands #endregion General Commands
@ -2010,7 +2195,7 @@ namespace TShockAPI
if (itemAmount == 0 || itemAmount > item.maxStack) if (itemAmount == 0 || itemAmount > item.maxStack)
itemAmount = item.maxStack; itemAmount = item.maxStack;
args.Player.GiveItem(item.type, item.name, item.width, item.height, itemAmount); args.Player.GiveItem(item.type, item.name, item.width, item.height, itemAmount);
args.Player.SendMessage(string.Format("Gave {0} {1}(s).", itemAmount.ToString(), item.name)); args.Player.SendMessage(string.Format("Gave {0} {1}(s).", itemAmount, item.name));
} }
else else
{ {
@ -2080,8 +2265,8 @@ namespace TShockAPI
if (itemAmount == 0 || itemAmount > item.maxStack) if (itemAmount == 0 || itemAmount > item.maxStack)
itemAmount = item.maxStack; itemAmount = item.maxStack;
plr.GiveItem(item.type, item.name, item.width, item.height, itemAmount); plr.GiveItem(item.type, item.name, item.width, item.height, itemAmount);
args.Player.SendMessage(string.Format("Gave {0} {1} {2}(s).", plr.Name, itemAmount.ToString(), item.name)); args.Player.SendMessage(string.Format("Gave {0} {1} {2}(s).", plr.Name, itemAmount, item.name));
plr.SendMessage(string.Format("{0} gave you {1} {2}(s).", args.Player.Name, itemAmount.ToString(), item.name)); plr.SendMessage(string.Format("{0} gave you {1} {2}(s).", args.Player.Name, itemAmount, item.name));
} }
else else
{ {

View file

@ -27,9 +27,9 @@ namespace TShockAPI
public int DefaultMaximumSpawns = 4; public int DefaultMaximumSpawns = 4;
public int DefaultSpawnRate = 700; public int DefaultSpawnRate = 700;
public int ServerPort = 7777; public int ServerPort = 7777;
public bool EnableWhitelist = false; public bool EnableWhitelist;
public bool InfiniteInvasion = false; public bool InfiniteInvasion;
public bool AlwaysPvP = false; public bool AlwaysPvP;
public bool KickCheaters = true; public bool KickCheaters = true;
public bool BanCheaters = true; public bool BanCheaters = true;
public bool KickGriefers = true; public bool KickGriefers = true;
@ -44,24 +44,24 @@ namespace TShockAPI
public string DistributationAgent = "facepunch"; public string DistributationAgent = "facepunch";
public int MaxSlots = 8; public int MaxSlots = 8;
public bool RangeChecks = true; public bool RangeChecks = true;
public bool SpamChecks = false; public bool SpamChecks;
public bool DisableBuild = false; public bool DisableBuild;
public int TileThreshold = 60; public int TileThreshold = 60;
public float[] AdminChatRGB = { 255, 0, 0 }; public float[] SuperAdminChatRGB = { 255, 0, 0 };
public string AdminChatPrefix = "(Admin) "; public string AdminChatPrefix = "(Admin) ";
public bool AdminChatEnabled = true; public bool AdminChatEnabled = true;
public int PvpThrottle = 0; public int PvpThrottle;
public int BackupInterval = 0; public int BackupInterval;
public int BackupKeepFor = 60; public int BackupKeepFor = 60;
public bool RememberLeavePos = false; public bool RememberLeavePos;
public bool HardcoreOnly = false; public bool HardcoreOnly;
public bool KickOnHardcoreDeath = false; public bool KickOnHardcoreDeath;
public bool BanOnHardcoreDeath = false; public bool BanOnHardcoreDeath;
public bool AutoSave = true; public bool AutoSave = true;
@ -93,12 +93,25 @@ namespace TShockAPI
public string TileKillAbuseReason = "Tile Kill abuse ({0})"; public string TileKillAbuseReason = "Tile Kill abuse ({0})";
public string HardcoreBanReason = "Death results in a ban"; public string HardcoreBanReason = "Death results in a ban";
public string HardcoreKickReason = "Death results in a kick"; public string HardcoreKickReason = "Death results in a kick";
public string ProjectileAbuseReason = "Projectile abuse";
public bool EnableDNSHostResolution = false; public bool EnableDNSHostResolution;
public bool EnableBanOnUsernames = false; public bool EnableBanOnUsernames;
public bool EnableAntiLag = true; public bool EnableAntiLag = true;
public string DefaultRegistrationGroupName = "default";
public bool DisableSpewLogs = true;
/// <summary>
/// Valid types are "sha512", "sha256", "md5"
/// </summary>
public string HashAlgorithm = "sha512";
public bool BufferPackets = false;
public static ConfigFile Read(string path) public static ConfigFile Read(string path)
{ {
if (!File.Exists(path)) if (!File.Exists(path))

View file

@ -1,4 +1,4 @@
/* /*
TShock, a server mod for Terraria TShock, a server mod for Terraria
Copyright (C) 2011 The TShock Team Copyright (C) 2011 The TShock Team
@ -17,12 +17,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
using System; using System;
using System.Collections.Generic;
using System.Data; using System.Data;
using System.IO; using System.IO;
using System.Text; using MySql.Data.MySqlClient;
using Community.CsharpSqlite.SQLiteClient;
using TShockAPI.DB;
namespace TShockAPI.DB namespace TShockAPI.DB
{ {
@ -34,45 +31,38 @@ namespace TShockAPI.DB
{ {
database = db; database = db;
using (var com = database.CreateCommand()) 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))
{ {
if (TShock.Config.StorageType.ToLower() == "sqlite") using (StreamReader sr = new StreamReader(file))
com.CommandText =
"CREATE TABLE IF NOT EXISTS 'Bans' ('IP' TEXT PRIMARY KEY, 'Name' TEXT, 'Reason' TEXT);";
else if (TShock.Config.StorageType.ToLower() == "mysql")
com.CommandText =
"CREATE TABLE IF NOT EXISTS Bans (IP VARCHAR(255) PRIMARY, Name VARCHAR(255), Reason VARCHAR(255));";
com.ExecuteNonQuery();
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 line; String[] info = line.Split('|');
while ((line = sr.ReadLine()) != null) string query;
{ if (TShock.Config.StorageType.ToLower() == "sqlite")
String[] info = line.Split('|'); query = "INSERT OR IGNORE INTO Bans (IP, Name, Reason) VALUES (@0, @1, @2);";
if (TShock.Config.StorageType.ToLower() == "sqlite") else
com.CommandText = "INSERT OR IGNORE INTO Bans (IP, Name, Reason) VALUES (@ip, @name, @reason);"; query = "INSERT IGNORE INTO Bans SET IP=@0, Name=@1, Reason=@2;";
else if (TShock.Config.StorageType.ToLower() == "mysql") db.Query(query, info[0].Trim(), info[1].Trim(), info[2].Trim());
com.CommandText = "INSERT IGNORE INTO Bans SET IP=@ip, Name=@name, Reason=@reason;";
com.AddParameter("@ip", info[0].Trim());
com.AddParameter("@name", info[1].Trim());
com.AddParameter("@reason", info[2].Trim());
com.ExecuteNonQuery();
com.Parameters.Clear();
}
} }
String path = Path.Combine(TShock.SavePath, "old_configs");
String file2 = Path.Combine(path, "bans.txt");
if (!Directory.Exists(path))
System.IO.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, "bans.txt");
if (!Directory.Exists(path))
Directory.CreateDirectory(path);
if (File.Exists(file2))
File.Delete(file2);
File.Move(file, file2);
} }
} }
@ -80,17 +70,10 @@ namespace TShockAPI.DB
{ {
try try
{ {
using (var com = database.CreateCommand()) using (var reader = database.QueryReader("SELECT * FROM Bans WHERE IP=@0", ip))
{ {
com.CommandText = "SELECT * FROM Bans WHERE IP=@ip"; if (reader.Read())
com.AddParameter("@ip", ip); return new Ban(reader.Get<string>("IP"), reader.Get<string>("Name"), reader.Get<string>("Reason"));
using (var reader = com.ExecuteReader())
{
if (reader.Read())
return new Ban((string)reader["IP"], (string)reader["Name"], (string)reader["Reason"]);
reader.Close();
}
} }
} }
catch (Exception ex) catch (Exception ex)
@ -108,20 +91,14 @@ namespace TShockAPI.DB
} }
try try
{ {
using (var com = database.CreateCommand()) var namecol = casesensitive ? "Name" : "UPPER(Name)";
if (!casesensitive)
name = name.ToUpper();
using (var reader = database.QueryReader("SELECT * FROM Bans WHERE " + namecol + "=@0", name))
{ {
var namecol = casesensitive ? "Name" : "UPPER(Name)"; if (reader.Read())
if (!casesensitive) return new Ban(reader.Get<string>("IP"), reader.Get<string>("Name"), reader.Get<string>("Reason"));
name = name.ToUpper();
com.CommandText = "SELECT * FROM Bans WHERE " + namecol + "=@name";
com.AddParameter("@name", name);
using (var reader = com.ExecuteReader())
{
if (reader.Read())
return new Ban((string)reader["IP"], (string)reader["Name"], (string)reader["Reason"]);
reader.Close();
}
} }
} }
catch (Exception ex) catch (Exception ex)
@ -135,15 +112,7 @@ namespace TShockAPI.DB
{ {
try try
{ {
using (var com = database.CreateCommand()) return database.Query("INSERT INTO Bans (IP, Name, Reason) VALUES (@0, @1, @2);", ip, name, reason) != 0;
{
com.CommandText = "INSERT INTO Bans (IP, Name, Reason) VALUES (@ip, @name, @reason);";
com.AddParameter("@ip", ip);
com.AddParameter("@name", name);
com.AddParameter("@reason", reason);
com.ExecuteNonQuery();
}
return true;
} }
catch (Exception ex) catch (Exception ex)
{ {
@ -156,13 +125,7 @@ namespace TShockAPI.DB
{ {
try try
{ {
using (var com = database.CreateCommand()) return database.Query("DELETE FROM Bans WHERE IP=@0", ip) != 0;
{
com.CommandText = "DELETE FROM Bans WHERE IP=@ip";
com.AddParameter("@ip", ip);
com.ExecuteNonQuery();
return true;
}
} }
catch (Exception ex) catch (Exception ex)
{ {
@ -174,12 +137,7 @@ namespace TShockAPI.DB
{ {
try try
{ {
using (var com = database.CreateCommand()) return database.Query("DELETE FROM Bans") != 0;
{
com.CommandText = "DELETE FROM Bans";
com.ExecuteNonQuery();
return true;
}
} }
catch (Exception ex) catch (Exception ex)
{ {

View file

@ -1,46 +0,0 @@
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
namespace TShockAPI.DB
{
public static class DbExt
{
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;
}
static 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)},
};
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 (ReadFuncs.ContainsKey(typeof(T)))
return (T)ReadFuncs[typeof(T)](reader, column);
throw new NotImplementedException();
}
}
}

View file

@ -1,10 +1,9 @@
using System; using System;
using System.IO;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data; using System.Data;
using Community.CsharpSqlite.SQLiteClient; using System.IO;
using System.Linq;
using MySql.Data.MySqlClient;
namespace TShockAPI.DB namespace TShockAPI.DB
{ {
@ -18,17 +17,13 @@ namespace TShockAPI.DB
{ {
database = db; database = db;
using (var com = database.CreateCommand()) var table = new SqlTable("GroupList",
{ new SqlColumn("GroupName", MySqlDbType.VarChar, 32) { Primary = true },
if (TShock.Config.StorageType.ToLower() == "sqlite") new SqlColumn("Commands", MySqlDbType.Text),
com.CommandText = new SqlColumn("ChatColor", MySqlDbType.Text)
"CREATE TABLE IF NOT EXISTS 'GroupList' ('GroupName' TEXT PRIMARY KEY, 'Commands' TEXT, 'OrderBy' TEXT);"; );
else if (TShock.Config.StorageType.ToLower() == "mysql") var creator = new SqlTableCreator(db, db.GetSqlType() == SqlType.Sqlite ? (IQueryBuilder)new SqliteQueryCreator() : new MysqlQueryCreator());
com.CommandText = creator.EnsureExists(table);
"CREATE TABLE IF NOT EXISTS GroupList (GroupName VARCHAR(255) PRIMARY, Commands VARCHAR(255), OrderBy VARCHAR(255));";
com.ExecuteNonQuery();
}
//Add default groups //Add default groups
AddGroup("trustedadmin", "admin,maintenance,cfg,butcher,item,heal,immunetoban,ignorecheatdetection,ignoregriefdetection,usebanneditem,manageusers"); AddGroup("trustedadmin", "admin,maintenance,cfg,butcher,item,heal,immunetoban,ignorecheatdetection,ignoregriefdetection,usebanneditem,manageusers");
@ -50,35 +45,28 @@ namespace TShockAPI.DB
String[] info = line.Split(' '); String[] info = line.Split(' ');
String comms = ""; String comms = "";
int size = info.Length; int size = info.Length;
int test = 0;
bool hasOrder = int.TryParse(info[info.Length - 1], out test);
if (hasOrder)
size = info.Length - 1;
for (int i = 1; i < size; i++) for (int i = 1; i < size; i++)
{ {
if (!comms.Equals("")) if (!comms.Equals(""))
comms = comms + ","; comms = comms + ",";
comms = comms + info[i].Trim(); comms = comms + info[i].Trim();
} }
using (var com = database.CreateCommand())
{
if (TShock.Config.StorageType.ToLower() == "sqlite")
com.CommandText = "INSERT OR IGNORE INTO GroupList (GroupName, Commands, OrderBy) VALUES (@groupname, @commands, @order);";
else if (TShock.Config.StorageType.ToLower() == "mysql")
com.CommandText = "INSERT IGNORE INTO GroupList SET GroupName=@groupname, Commands=@commands, OrderBy=@order;";
com.AddParameter("@groupname", info[0].Trim()); string query = "";
com.AddParameter("@commands", comms); if (TShock.Config.StorageType.ToLower() == "sqlite")
com.AddParameter("@order", hasOrder ? info[info.Length - 1] : "0"); query = "INSERT OR IGNORE INTO GroupList (GroupName, Commands) VALUES (@0, @1);";
com.ExecuteNonQuery(); 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 path = Path.Combine(TShock.SavePath, "old_configs");
String file2 = Path.Combine(path, "groups.txt"); String file2 = Path.Combine(path, "groups.txt");
if (!Directory.Exists(path)) if (!Directory.Exists(path))
System.IO.Directory.CreateDirectory(path); Directory.CreateDirectory(path);
if (File.Exists(file2)) if (File.Exists(file2))
File.Delete(file2); File.Delete(file2);
File.Move(file, file2); File.Move(file, file2);
@ -86,27 +74,6 @@ namespace TShockAPI.DB
} }
/// <summary>
/// Adds group with name and permissions if it does not exist.
/// </summary>
/// <param name="name">name of group</param>
/// <param name="commands">permissions</param>
public void AddGroup(string name, string commands)
{
using (var com = database.CreateCommand())
{
if (TShock.Config.StorageType.ToLower() == "sqlite")
com.CommandText =
"INSERT OR IGNORE INTO GroupList (GroupName, Commands, OrderBy) VALUES (@groupname, @commands, @order);";
else if (TShock.Config.StorageType.ToLower() == "mysql")
com.CommandText =
"INSERT IGNORE INTO GroupList SET GroupName=@groupname, Commands=@commands, OrderBy=@order;";
com.AddParameter("@groupname", name);
com.AddParameter("@commands", commands);
com.AddParameter("@order", "0");
com.ExecuteNonQuery();
}
}
public bool GroupExists(string group) public bool GroupExists(string group)
{ {
@ -123,93 +90,72 @@ namespace TShockAPI.DB
return false; return false;
} }
public String addGroup(String name, String permissions) /// <summary>
/// Adds group with name and permissions if it does not exist.
/// </summary>
/// <param name="name">name of group</param>
/// <param name="permissions">permissions</param>
public String AddGroup(String name, String permissions, String ChatColor = "255,255,255")
{ {
String message = ""; String message = "";
if( GroupExists( name ) ) if (GroupExists(name))
return "Error: Group already exists. Use /modGroup to change permissions."; return "Error: Group already exists. Use /modGroup to change permissions.";
using (var com = database.CreateCommand())
{ string query = (TShock.Config.StorageType.ToLower() == "sqlite") ?
if (TShock.Config.StorageType.ToLower() == "sqlite") "INSERT OR IGNORE INTO GroupList (GroupName, Commands, ChatColor) VALUES (@0, @1, @2);" :
com.CommandText = "INSERT OR IGNORE INTO GroupList (GroupName, Commands, OrderBy) VALUES (@groupname, @commands, @order);"; "INSERT IGNORE INTO GroupList SET GroupName=@0, Commands=@1";
else if (TShock.Config.StorageType.ToLower() == "mysql") if (database.Query(query, name, permissions, ChatColor) == 1)
com.CommandText = "INSERT IGNORE INTO GroupList SET GroupName=@groupname, Commands=@commands, OrderBy=@order;"; message = "Group " + name + " has been created successfully.";
com.AddParameter("@groupname", name); Group g = new Group(name, null, ChatColor);
com.AddParameter("@commands", permissions); g.permissions.Add(permissions);
com.AddParameter("@order", "0"); groups.Add(g);
if (com.ExecuteNonQuery() == 1)
message = "Group " + name + " has been created successfully.";
Group g = new Group(name);
g.permissions.Add(permissions);
groups.Add(g);
}
return message; return message;
} }
public String delGroup(String name) public String DeleteGroup(String name)
{ {
String message = ""; String message = "";
if (!GroupExists(name)) if (!GroupExists(name))
return "Error: Group doesn't exists."; return "Error: Group doesn't exists.";
using (var com = database.CreateCommand())
{ if (database.Query("DELETE FROM GroupList WHERE GroupName=@0", name) == 1)
com.CommandText = "Delete FROM GroupList WHERE GroupName=@groupname;"; message = "Group " + name + " has been deleted successfully.";
com.AddParameter("@groupname", name); groups.Remove(Tools.GetGroup(name));
if (com.ExecuteNonQuery() == 1)
message = "Group " + name + " has been deleted successfully.";
groups.Remove(Tools.GetGroup(name));
}
return message; return message;
} }
public String addPermission(String name, List<String> permissions) public String AddPermissions(String name, List<String> permissions)
{ {
String message = ""; String message = "";
if (!GroupExists(name)) if (!GroupExists(name))
return "Error: Group doesn't exists."; return "Error: Group doesn't exists.";
using (var com = database.CreateCommand())
{ var group = Tools.GetGroup(name);
Group g = Tools.GetGroup(name); //Add existing permissions (without duplicating)
List<String> perm = g.permissions; permissions.AddRange(group.permissions.Where(s => !permissions.Contains(s)));
foreach (String p in permissions)
{ if (database.Query("UPDATE GroupList SET Commands=@0 WHERE GroupName=@1", String.Join(",", permissions), name) != 0)
if (!perm.Contains(p)) message = "Group " + name + " has been modified successfully.";
{
if (perm.Count > 0 && perm[0].Equals(""))
perm[0] = p;
else
g.permissions.Add(p);
}
}
com.CommandText = "UPDATE GroupList SET Commands=@perm WHERE GroupName=@name;";
com.AddParameter("@perm", String.Join(",", perm));
com.AddParameter("@name", name);
if (com.ExecuteNonQuery() == 1)
message = "Group " + name + " has been modified successfully.";
}
return message; return message;
} }
public String delPermission(String name, List<String> permissions) public String DeletePermissions(String name, List<String> permissions)
{ {
String message = ""; String message = "";
if (!GroupExists(name)) if (!GroupExists(name))
return "Error: Group doesn't exists."; return "Error: Group doesn't exists.";
using (var com = database.CreateCommand())
{ var group = Tools.GetGroup(name);
Group g = Tools.GetGroup(name);
List<String> perm = g.permissions; //Only get permissions that exist in the group.
foreach (String p in permissions) var newperms = permissions.Where(s => group.permissions.Contains(s));
{
if (perm.Contains(p)) if (database.Query("UPDATE GroupList SET Commands=@0 WHERE GroupName=@1", String.Join(",", newperms), name) != 0)
g.permissions.Remove(p); message = "Group " + name + " has been modified successfully.";
}
com.CommandText = "UPDATE GroupList SET Commands=@perm WHERE GroupName=@name;";
com.AddParameter("@perm", String.Join(",", perm));
com.AddParameter("@name", name);
if (com.ExecuteNonQuery() == 1)
message = "Group " + name + " has been modified successfully.";
}
return message; return message;
} }
@ -220,41 +166,29 @@ namespace TShockAPI.DB
try try
{ {
using (var com = database.CreateCommand()) using (var reader = database.QueryReader("SELECT * FROM Grouplist"))
{ {
com.CommandText = "SELECT * FROM Grouplist;"; while (reader.Read())
using (var reader = com.ExecuteReader())
{ {
while (reader.Read()) Group group = null;
{ string groupname = reader.Get<String>("GroupName");
Group group = null; group = new Group(groupname);
string groupname = reader.Get<String>("GroupName");
group = new Group(groupname);
//Inherit Given commands //Inherit Given commands
String[] commands = reader.Get<String>("Commands").Split(','); String[] commands = reader.Get<String>("Commands").Split(',');
for (int i = 0; i < commands.Length; i++) for (int i = 0; i < commands.Length; i++)
{
group.AddPermission(commands[i].Trim());
}
groups.Add(group);
}
}
/** ORDER BY IS DUMB
//Inherit all commands from group below in order, unless Order is 0 (unique groups anyone)
foreach (Group group in groups)
{
if (group.Order != 0 && group.Order < groups.Count)
{ {
for (int i = group.Order + 1; i < groups.Count; i++) group.AddPermission(commands[i].Trim());
{
for (int j = 0; j < groups[i].permissions.Count; j++)
{
group.AddPermission(groups[i].permissions[j]);
}
}
} }
}*/ 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);
}
groups.Add(group);
}
} }
} }
catch (Exception ex) catch (Exception ex)

View file

@ -0,0 +1,256 @@
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using MySql.Data.MySqlClient;
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);
}
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);
/*
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"
DROP TABLE "main"."oXHFcGcd04oXHFcGcd04_Bans"
*
* Twitchy - Oh. I get it!
*/
}
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.ToString());
if (count != values.Count - 1)
sbvalues.Append(",");
count++;
}
count = 0;
foreach (SqlValue where in wheres)
{
sbwheres.Append(where.Name + "=" + where.Value.ToString());
if (count != wheres.Count - 1)
sbvalues.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.ToString());
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);
}
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 ? "AUTOINCREMENT" : "", 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 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.ToString());
if (count != values.Count - 1)
sbvalues.Append("AND");
count++;
}
count = 0;
foreach (SqlValue where in wheres)
{
sbwheres.Append(where.Name + "=" + where.Value.ToString());
if (count != wheres.Count - 1)
sbvalues.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.ToString());
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);
}
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

@ -1,11 +1,8 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data; using System.Data;
using Community.CsharpSqlite.SQLiteClient;
using TShockAPI.DB;
using System.IO; using System.IO;
using MySql.Data.MySqlClient;
namespace TShockAPI.DB namespace TShockAPI.DB
{ {
@ -18,48 +15,42 @@ namespace TShockAPI.DB
{ {
database = db; database = db;
using (var com = database.CreateCommand()) var table = new SqlTable("ItemBans",
new SqlColumn("ItemName", MySqlDbType.VarChar, 50) { Primary = true }
);
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))
{ {
if (TShock.Config.StorageType.ToLower() == "sqlite") using (StreamReader sr = new StreamReader(file))
com.CommandText =
"CREATE TABLE IF NOT EXISTS 'ItemBans' ('ItemName' TEXT PRIMARY KEY);";
else if (TShock.Config.StorageType.ToLower() == "mysql")
com.CommandText =
"CREATE TABLE IF NOT EXISTS ItemBans (ItemName VARCHAR(255) PRIMARY);";
com.ExecuteNonQuery();
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)
{ {
String line; if (!line.Equals("") && !line.Substring(0, 1).Equals("#"))
while ((line = sr.ReadLine()) != null)
{ {
if (!line.Equals("") && !line.Substring(0, 1).Equals("#"))
{
if (TShock.Config.StorageType.ToLower() == "sqlite")
com.CommandText = "INSERT OR IGNORE INTO 'ItemBans' (ItemName) VALUES (@name);";
else if (TShock.Config.StorageType.ToLower() == "mysql")
com.CommandText = "INSERT IGNORE INTO ItemBans SET ItemName=@name;";
int id = 0; string query = (TShock.Config.StorageType.ToLower() == "sqlite") ?
int.TryParse(line, out id); "INSERT OR IGNORE INTO 'ItemBans' (ItemName) VALUES (@0);" :
com.AddParameter("@name", Tools.GetItemById(id).name); "INSERT IGNORE INTO ItemBans SET ItemName=@0;";
com.ExecuteNonQuery();
com.Parameters.Clear(); int id = 0;
} int.TryParse(line, out id);
database.Query(query, Tools.GetItemById(id).name);
} }
} }
String path = Path.Combine(TShock.SavePath, "old_configs");
String file2 = Path.Combine(path, "itembans.txt");
if (!Directory.Exists(path))
System.IO.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();
@ -68,29 +59,20 @@ namespace TShockAPI.DB
public void UpdateItemBans() public void UpdateItemBans()
{ {
ItemBans.Clear(); ItemBans.Clear();
using (var com = database.CreateCommand())
{
com.CommandText = "SELECT * FROM ItemBans";
using (var reader = com.ExecuteReader()) using (var reader = database.QueryReader("SELECT * FROM ItemBans"))
{ {
while (reader!=null&&reader.Read()) while (reader != null && reader.Read())
ItemBans.Add(reader.Get<string>("ItemName")); ItemBans.Add(reader.Get<string>("ItemName"));
}
} }
} }
public void AddNewBan(string itemname = "") public void AddNewBan(string itemname = "")
{ {
try try
{ {
using (var com = database.CreateCommand()) database.Query("INSERT INTO ItemBans (ItemName) VALUES (@0);", Tools.GetItemByName(itemname)[0].name);
{ if (!ItemIsBanned(itemname))
com.CommandText = "INSERT INTO ItemBans (ItemName) VALUES (@itemname);"; ItemBans.Add(itemname);
com.AddParameter("@itemname", Tools.GetItemByName(itemname)[0].name);
com.ExecuteNonQuery();
if( !ItemIsBanned( itemname ) )
ItemBans.Add(itemname);
}
} }
catch (Exception ex) catch (Exception ex)
{ {
@ -104,13 +86,8 @@ namespace TShockAPI.DB
return; return;
try try
{ {
using (var com = database.CreateCommand()) database.Query("Delete FROM 'ItemBans' WHERE ItemName=@0;", Tools.GetItemByName(itemname)[0].name);
{ ItemBans.Remove(itemname);
com.CommandText = "Delete FROM 'ItemBans' WHERE ItemName=@itemname;";
com.AddParameter("@itemname", Tools.GetItemByName(itemname)[0].name);
com.ExecuteNonQuery();
ItemBans.Remove(itemname);
}
} }
catch (Exception ex) catch (Exception ex)
{ {

View file

@ -1,4 +1,4 @@
/* /*
TShock, a server mod for Terraria TShock, a server mod for Terraria
Copyright (C) 2011 The TShock Team Copyright (C) 2011 The TShock Team
@ -18,17 +18,13 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.IO;
using System.Data; using System.Data;
using TShockAPI.DB; using System.IO;
using Community.CsharpSqlite.SQLiteClient; using System.Xml;
using Microsoft.Xna.Framework; using Microsoft.Xna.Framework;
using MySql.Data.MySqlClient;
using Terraria; using Terraria;
namespace TShockAPI.DB namespace TShockAPI.DB
{ {
public class RegionManager public class RegionManager
@ -41,186 +37,119 @@ namespace TShockAPI.DB
{ {
database = db; database = db;
using (var com = database.CreateCommand()) var table = new SqlTable("Regions",
new SqlColumn("X1", MySqlDbType.Int32),
new SqlColumn("Y1", MySqlDbType.Int32),
new SqlColumn("height", MySqlDbType.Int32),
new SqlColumn("width", MySqlDbType.Int32),
new SqlColumn("RegionName", MySqlDbType.VarChar, 50) { Primary = true },
new SqlColumn("WorldID", MySqlDbType.Text),
new SqlColumn("UserIds", MySqlDbType.Text),
new SqlColumn("Protected", MySqlDbType.Int32)
);
var creator = new SqlTableCreator(db, db.GetSqlType() == SqlType.Sqlite ? (IQueryBuilder)new SqliteQueryCreator() : new MysqlQueryCreator());
creator.EnsureExists(table);
ImportOld();
}
public void ImportOld()
{
String file = Path.Combine(TShock.SavePath, "regions.xml");
if (!File.Exists(file))
return;
Region region;
Rectangle rect;
using (var sr = new StreamReader(file))
{ {
if (TShock.Config.StorageType.ToLower() == "sqlite") using (var reader = XmlReader.Create(sr))
com.CommandText =
"CREATE TABLE IF NOT EXISTS 'Regions' ('X1' NUMERIC, 'Y1' NUMERIC, 'height' NUMERIC, 'width' NUMERIC, 'RegionName' TEXT PRIMARY KEY, 'WorldID' TEXT, 'UserIds' TEXT, 'Protected' NUMERIC);";
else if (TShock.Config.StorageType.ToLower() == "mysql")
com.CommandText =
"CREATE TABLE IF NOT EXISTS Regions (X1 INT(11), Y1 INT(11), height INT(11), width INT(11), RegionName VARCHAR(255) PRIMARY, WorldID VARCHAR(255), UserIds VARCHAR(255), Protected INT(1));";
com.ExecuteNonQuery();
String file = Path.Combine(TShock.SavePath, "regions.xml");
String name = "";
String world = "";
int x1 = 0;
int x2 = 0;
int y1 = 0;
int y2 = 0;
int prot = 0;
int users = 0;
String[] ips;
String ipstr = "";
int updates = 0;
if (File.Exists(file))
{ {
XmlReader reader;
reader = XmlReader.Create(new StreamReader(file));
// Parse the file and display each of the nodes. // Parse the file and display each of the nodes.
while (reader.Read()) while (reader.Read())
{ {
switch (reader.NodeType) if (reader.NodeType != XmlNodeType.Element || reader.Name != "ProtectedRegion")
continue;
region = new Region();
rect = new Rectangle();
bool endregion = false;
while (reader.Read() && !endregion)
{ {
case XmlNodeType.Element: if (reader.NodeType != XmlNodeType.Element)
switch (reader.Name) continue;
{
case "ProtectedRegion":
name = "";
world = "";
x1 = 0;
x2 = 0;
y1 = 0;
y2 = 0;
prot = 0;
users = 0;
ips = null;
ipstr = "";
break;
case "RegionName":
while (reader.NodeType != XmlNodeType.Text)
reader.Read();
name = reader.Value;
break;
case "Point1X":
while (reader.NodeType != XmlNodeType.Text)
reader.Read();
int.TryParse(reader.Value, out x1);
break;
case "Point1Y":
while (reader.NodeType != XmlNodeType.Text)
reader.Read();
int.TryParse(reader.Value, out y1);
break;
case "Point2X":
while (reader.NodeType != XmlNodeType.Text)
reader.Read();
int.TryParse(reader.Value, out x2);
break;
case "Point2Y":
while (reader.NodeType != XmlNodeType.Text)
reader.Read();
int.TryParse(reader.Value, out y2);
break;
case "Protected":
while (reader.NodeType != XmlNodeType.Text)
reader.Read();
if (reader.Value.Equals("True"))
{
prot = 0;
}
else
{
prot = 1;
}
break;
case "WorldName":
while (reader.NodeType != XmlNodeType.Text)
reader.Read();
world = reader.Value;
break;
case "AllowedUserCount":
while (reader.NodeType != XmlNodeType.Text)
reader.Read();
int.TryParse(reader.Value, out users);
if (users > 0)
{
ips = new String[users];
for (int i = 0; i < users; i++)
{
do
reader.Read();
while (reader.NodeType != XmlNodeType.Text);
ips[i] = reader.Value;
}
ipstr = "";
for (int i = 0; i < ips.Length; i++)
{
try
{
if (ipstr != "")
ipstr += ",";
ipstr += TShock.Users.GetUserID(ips[i]);
}
catch (Exception)
{
Log.Error("An IP address failed to import. It wasn't a user in the new user system.");
}
} string name = reader.Name;
} while (reader.Read() && reader.NodeType != XmlNodeType.Text) ;
if (TShock.Config.StorageType.ToLower() == "sqlite")
com.CommandText = "INSERT OR IGNORE INTO Regions VALUES (@tx, @ty, @height, @width, @name, @worldid, @userids, @protected);";
else if (TShock.Config.StorageType.ToLower() == "mysql")
com.CommandText = "INSERT IGNORE INTO Regions SET X1=@tx, Y1=@ty, height=@height, width=@width, RegionName=@name, WorldID=@world, UserIds=@userids, Protected=@protected;";
com.AddParameter("@tx", x1);
com.AddParameter("@ty", y1);
com.AddParameter("@width", x2);
com.AddParameter("@height", y2);
com.AddParameter("@name", name);
com.AddParameter("@worldid", world);
com.AddParameter("@userids", ipstr);
com.AddParameter("@protected", prot);
updates += com.ExecuteNonQuery();
com.Parameters.Clear();
break;
}
break;
case XmlNodeType.Text:
break; switch (name)
case XmlNodeType.XmlDeclaration: {
case XmlNodeType.ProcessingInstruction: case "RegionName":
break; region.Name = reader.Value;
case XmlNodeType.Comment: break;
break; case "Point1X":
case XmlNodeType.EndElement: int.TryParse(reader.Value, out rect.X);
break;
case "Point1Y":
int.TryParse(reader.Value, out rect.Y);
break;
case "Point2X":
int.TryParse(reader.Value, out rect.Width);
break;
case "Point2Y":
int.TryParse(reader.Value, out rect.Height);
break;
case "Protected":
region.DisableBuild = reader.Value.ToLower().Equals("true");
break;
case "WorldName":
region.WorldID = reader.Value;
break;
case "AllowedUserCount":
break;
case "IP":
region.AllowedIDs.Add(int.Parse(reader.Value));
break;
default:
endregion = true;
break;
}
}
break; region.Area = rect;
using (var com = database.CreateCommand())
{
string query = (TShock.Config.StorageType.ToLower() == "sqlite") ?
"INSERT OR IGNORE INTO Regions VALUES (@0, @1, @2, @3, @4, @5, @6, @7);" :
"INSERT IGNORE INTO Regions SET X1=@0, Y1=@1, height=@2, width=@3, RegionName=@4, WorldID=@5, UserIds=@6, Protected=@7;";
database.Query(query, region.Area.X, region.Area.Y, region.Area.Width, region.Area.Height, region.Name, region.WorldID, "", region.DisableBuild);
//Todo: What should this be? We don't really have a way to go from ips to userids
/*string.Join(",", region.AllowedIDs)*/
} }
} }
reader.Close();
reader = null;
String path = Path.Combine(TShock.SavePath, "old_configs");
String file2 = Path.Combine(path, "regions.xml");
if (!Directory.Exists(path))
System.IO.Directory.CreateDirectory(path);
if (File.Exists(file2))
File.Delete(file2);
//File.Move(file, file2);
} }
if (updates > 0)
ReloadAllRegions();
} }
String path = Path.Combine(TShock.SavePath, "old_configs");
String file2 = Path.Combine(path, "regions.xml");
if (!Directory.Exists(path))
Directory.CreateDirectory(path);
if (File.Exists(file2))
File.Delete(file2);
File.Move(file, file2);
ReloadAllRegions();
} }
public void ConvertDB() public void ConvertDB()
{ {
try try
{ {
using (var com = database.CreateCommand()) database.Query("UPDATE Regions SET WorldID=@0, UserIds=''", Main.worldID.ToString());
{ ReloadAllRegions();
com.CommandText = "UPDATE Regions SET WorldID=@worldid";
com.AddParameter("@worldid", Main.worldID.ToString());
com.ExecuteNonQuery();
com.Parameters.Clear();
com.CommandText = "UPDATE Regions SET UserIds=@UserIds";
com.AddParameter("@UserIds", "");
com.ExecuteNonQuery();
ReloadAllRegions();
}
} }
catch (Exception ex) catch (Exception ex)
{ {
@ -232,50 +161,45 @@ namespace TShockAPI.DB
{ {
try try
{ {
using (var com = database.CreateCommand()) using (var reader = database.QueryReader("SELECT * FROM Regions WHERE WorldID=@0", Main.worldID.ToString()))
{ {
com.CommandText = "SELECT * FROM Regions WHERE WorldID=@worldid"; Regions.Clear();
com.AddParameter("@worldid", Main.worldID.ToString()); while (reader.Read())
using (var reader = com.ExecuteReader())
{ {
Regions.Clear(); int X1 = reader.Get<int>("X1");
while (reader.Read()) int Y1 = reader.Get<int>("Y1");
int height = reader.Get<int>("height");
int width = reader.Get<int>("width");
int Protected = reader.Get<int>("Protected");
string MergedIDs = reader.Get<string>("UserIds");
string name = reader.Get<string>("RegionName");
string[] SplitIDs = MergedIDs.Split(',');
Region r = new Region(new Rectangle(X1, Y1, width, height), name, Protected != 0, Main.worldID.ToString());
try
{ {
int X1 = reader.Get<int>("X1"); for (int i = 0; i < SplitIDs.Length; i++)
int Y1 = reader.Get<int>("Y1");
int height = reader.Get<int>("height");
int width = reader.Get<int>("width");
int Protected = reader.Get<int>("Protected");
string MergedIDs = DbExt.Get<string>(reader, "UserIds");
string name = DbExt.Get<string>(reader, "RegionName");
System.Console.WriteLine(MergedIDs);
string[] SplitIDs = MergedIDs.Split(',');
Region r = new Region(new Rectangle(X1, Y1, width, height), name, Protected, Main.worldID.ToString());
r.RegionAllowedIDs = new int[SplitIDs.Length];
try
{ {
for (int i = 0; i < SplitIDs.Length; i++) int id;
{
if (SplitIDs.Length == 1 && SplitIDs[0].Equals(""))
{
break;
}
//System.Console.WriteLine(SplitIDs[i]);
r.RegionAllowedIDs[i] = Convert.ToInt32(SplitIDs[i]);
}
}
catch (Exception e)
{
Log.Error("Your database contains invalid UserIDs (they should be ints).");
Log.Error("A lot of things will fail because of this. You must manually delete and re-create the allowed field.");
Log.Error(e.Message);
Log.Error(e.StackTrace);
}
Regions.Add(r); if (Int32.TryParse(SplitIDs[i], out id)) // if unparsable, it's not an int, so silently skip
r.AllowedIDs.Add(id);
else if (SplitIDs[i] == "") // Split gotcha, can return an empty string with certain conditions
// but we only want to let the user know if it's really a nonparsable integer.
Log.Warn("One of your UserIDs is not a usable integer: " + SplitIDs[i]);
}
} }
reader.Close(); catch (Exception e)
{
Log.Error("Your database contains invalid UserIDs (they should be ints).");
Log.Error("A lot of things will fail because of this. You must manually delete and re-create the allowed field.");
Log.Error(e.Message);
Log.Error(e.StackTrace);
}
Regions.Add(r);
} }
} }
} }
@ -285,29 +209,58 @@ namespace TShockAPI.DB
} }
} }
public void ReloadForUnitTest(String n)
{
using (var reader = database.QueryReader("SELECT * FROM Regions WHERE WorldID=@0", n))
{
Regions.Clear();
while (reader.Read())
{
int X1 = reader.Get<int>("X1");
int Y1 = reader.Get<int>("Y1");
int height = reader.Get<int>("height");
int width = reader.Get<int>("width");
int Protected = reader.Get<int>("Protected");
string MergedIDs = reader.Get<string>("UserIds");
string name = reader.Get<string>("RegionName");
string[] SplitIDs = MergedIDs.Split(',');
Region r = new Region(new Rectangle(X1, Y1, width, height), name, Protected != 0, Main.worldID.ToString());
try
{
for (int i = 0; i < SplitIDs.Length; i++)
{
int id;
if (Int32.TryParse(SplitIDs[i], out id)) // if unparsable, it's not an int, so silently skip
r.AllowedIDs.Add(id);
else if (SplitIDs[i] == "") // Split gotcha, can return an empty string with certain conditions
// but we only want to let the user know if it's really a nonparsable integer.
Log.Warn("UnitTest: One of your UserIDs is not a usable integer: " + SplitIDs[i]);
}
}
catch (Exception e)
{
Log.Error("Your database contains invalid UserIDs (they should be ints).");
Log.Error("A lot of things will fail because of this. You must manually delete and re-create the allowed field.");
Log.Error(e.Message);
Log.Error(e.StackTrace);
}
Regions.Add(r);
}
}
}
public bool AddRegion(int tx, int ty, int width, int height, string regionname, string worldid) public bool AddRegion(int tx, int ty, int width, int height, string regionname, string worldid)
{ {
try try
{ {
using (var com = database.CreateCommand()) database.Query("INSERT INTO Regions VALUES (@0, @1, @2, @3, @4, @5, @6, @7);", tx, ty, width, height, regionname, worldid, "", 1);
{ Regions.Add(new Region(new Rectangle(tx, ty, width, height), regionname, true, worldid));
com.CommandText = return true;
"INSERT INTO Regions VALUES (@tx, @ty, @height, @width, @name, @worldid, @userids, @protected);";
com.AddParameter("@tx", tx);
com.AddParameter("@ty", ty);
com.AddParameter("@width", width);
com.AddParameter("@height", height);
com.AddParameter("@name", regionname.ToLower());
com.AddParameter("@worldid", worldid);
com.AddParameter("@userids", "");
com.AddParameter("@protected", 1);
if (com.ExecuteNonQuery() > 0)
{
Regions.Add(new Region(new Rectangle(tx, ty, width, height), regionname, 0, worldid));
return true;
}
}
} }
catch (Exception ex) catch (Exception ex)
{ {
@ -320,15 +273,9 @@ namespace TShockAPI.DB
{ {
try try
{ {
using (var com = database.CreateCommand()) database.Query("DELETE FROM Regions WHERE RegionName=@0 AND WorldID=@1", name, Main.worldID.ToString());
{ Regions.Remove(getRegion(name));
com.CommandText = "DELETE FROM Regions WHERE RegionName=@name AND WorldID=@worldid"; return true;
com.AddParameter("@name", name.ToLower());
com.AddParameter("@worldid", Main.worldID.ToString());
com.ExecuteNonQuery();
ReloadAllRegions();
return true;
}
} }
catch (Exception ex) catch (Exception ex)
{ {
@ -341,16 +288,24 @@ namespace TShockAPI.DB
{ {
try try
{ {
using (var com = database.CreateCommand()) database.Query("UPDATE Regions SET Protected=@0 WHERE RegionName=@1 AND WorldID=@2", state ? 1 : 0, name, Main.worldID.ToString());
{ getRegion(name).DisableBuild = state;
com.CommandText = "UPDATE Regions SET Protected=@bool WHERE RegionName=@name AND WorldID=@worldid"; return true;
com.AddParameter("@name", name); }
com.AddParameter("@bool", state ? 1 : 0); catch (Exception ex)
com.AddParameter("@worldid", Main.worldID.ToString()); {
int q = com.ExecuteNonQuery(); Log.Error(ex.ToString());
ReloadAllRegions(); return false;
return (q > 0); }
} }
public bool SetRegionStateTest(string name, string world, bool state)
{
try
{
database.Query("UPDATE Regions SET Protected=@0 WHERE RegionName=@1 AND WorldID=@2", state ? 1 : 0, name, world);
getRegion(name).DisableBuild = state;
return true;
} }
catch (Exception ex) catch (Exception ex)
{ {
@ -379,9 +334,9 @@ namespace TShockAPI.DB
{ {
foreach (Region region in Regions) foreach (Region region in Regions)
{ {
if (x >= region.RegionArea.Left && x <= region.RegionArea.Right && if (x >= region.Area.Left && x <= region.Area.Right &&
y >= region.RegionArea.Top && y <= region.RegionArea.Bottom && y >= region.Area.Top && y <= region.Area.Bottom &&
region.DisableBuild == 1) region.DisableBuild)
{ {
return true; return true;
} }
@ -392,7 +347,7 @@ namespace TShockAPI.DB
public static List<string> ListIDs(string MergedIDs) public static List<string> ListIDs(string MergedIDs)
{ {
List<string> SplitIDs = new List<string>(); List<string> SplitIDs = new List<string>();
var sb = new StringBuilder(); /*var sb = new StringBuilder();
for (int i = 0; i < MergedIDs.Length; i++) for (int i = 0; i < MergedIDs.Length; i++)
{ {
char c = MergedIDs[i]; char c = MergedIDs[i];
@ -406,53 +361,43 @@ namespace TShockAPI.DB
SplitIDs.Add(sb.ToString()); SplitIDs.Add(sb.ToString());
sb.Clear(); sb.Clear();
} }
}*/
String[] s = MergedIDs.Split(',');
for (int i = 0; i < s.Length; i++)
{
if (!s[i].Equals(""))
SplitIDs.Add(s[i]);
} }
return SplitIDs; return SplitIDs;
} }
public bool AddNewUser(string regionName, String userName) public bool AddNewUser(string regionName, String userName)
{ {
try try
{ {
using (var com = database.CreateCommand()) string MergedIDs = string.Empty;
using (var reader = database.QueryReader("SELECT * FROM Regions WHERE RegionName=@0 AND WorldID=@1", regionName, Main.worldID.ToString()))
{ {
com.CommandText = "SELECT * FROM Regions WHERE RegionName=@name AND WorldID=@worldid"; if (reader.Read())
com.AddParameter("@name", regionName); MergedIDs = reader.Get<string>("UserIds");
com.AddParameter("@worldid", Main.worldID.ToString()); }
string MergedIDs = string.Empty;
using (var reader = com.ExecuteReader())
{
if (reader.Read())
MergedIDs = reader.Get<string>("UserIds");
}
if (MergedIDs == string.Empty) if (MergedIDs == string.Empty)
MergedIDs = Convert.ToString(TShock.Users.GetUserID(userName)); MergedIDs = Convert.ToString(TShock.Users.GetUserID(userName));
else else
MergedIDs = MergedIDs + "," + Convert.ToString(TShock.Users.GetUserID(userName)); MergedIDs = MergedIDs + "," + Convert.ToString(TShock.Users.GetUserID(userName));
com.Parameters.Clear();
com.CommandText = "UPDATE Regions SET UserIds=@ids WHERE RegionName=@name AND WorldID=@worldid"; if (database.Query("UPDATE Regions SET UserIds=@0 WHERE RegionName=@1 AND WorldID=@2", MergedIDs, regionName, Main.worldID.ToString()) > 0)
com.AddParameter("@ids", MergedIDs); {
com.AddParameter("@name", regionName); ReloadAllRegions();
com.AddParameter("@worldid", Main.worldID.ToString()); return true;
if (com.ExecuteNonQuery() > 0)
{
ReloadAllRegions();
return true;
}
else
{
return false;
}
} }
} }
catch (Exception ex) catch (Exception ex)
{ {
Log.Error(ex.ToString()); Log.Error(ex.ToString());
return false;
} }
return false;
} }
/// <summary> /// <summary>
@ -465,15 +410,10 @@ namespace TShockAPI.DB
var regions = new List<Region>(); var regions = new List<Region>();
try try
{ {
using (var com = database.CreateCommand()) using (var reader = database.QueryReader("SELECT RegionName FROM Regions WHERE WorldID=@0", worldid))
{ {
com.CommandText = "SELECT RegionName FROM Regions WHERE WorldID=@worldid"; while (reader.Read())
com.AddParameter("@worldid", worldid); regions.Add(new Region { Name = reader.Get<string>("RegionName") });
using (var reader = com.ExecuteReader())
{
while (reader.Read())
regions.Add(new Region { RegionName = reader.Get<string>("RegionName") });
}
} }
} }
catch (Exception ex) catch (Exception ex)
@ -482,35 +422,47 @@ namespace TShockAPI.DB
} }
return regions; return regions;
} }
public Region getRegion(String name)
{
foreach (Region r in Regions)
{
if (r.Name.Equals(name))
return r;
}
return new Region();
}
} }
public class Region public class Region
{ {
public Rectangle RegionArea { get; set; } public Rectangle Area { get; set; }
public string RegionName { get; set; } public string Name { get; set; }
public int DisableBuild { get; set; } public bool DisableBuild { get; set; }
public string RegionWorldID { get; set; } public string WorldID { get; set; }
public int[] RegionAllowedIDs { get; set; } public List<int> AllowedIDs { get; set; }
public Region(Rectangle region, string name, int disablebuild, string RegionWorldIDz) public Region(Rectangle region, string name, bool disablebuild, string RegionWorldIDz)
: this()
{ {
RegionArea = region; Area = region;
RegionName = name; Name = name;
DisableBuild = disablebuild; DisableBuild = disablebuild;
RegionWorldID = RegionWorldIDz; WorldID = RegionWorldIDz;
} }
public Region() public Region()
{ {
RegionArea = Rectangle.Empty; Area = Rectangle.Empty;
RegionName = string.Empty; Name = string.Empty;
DisableBuild = 1; DisableBuild = true;
RegionWorldID = string.Empty; WorldID = string.Empty;
AllowedIDs = new List<int>();
} }
public bool InArea(Rectangle point) public bool InArea(Rectangle point)
{ {
if (RegionArea.Contains(point.X, point.Y)) if (Area.Contains(point.X, point.Y))
{ {
return true; return true;
} }
@ -528,14 +480,14 @@ namespace TShockAPI.DB
} }
return false; return false;
} }
if (DisableBuild == 0) if (!DisableBuild)
{ {
return true; return true;
} }
for (int i = 0; i < RegionAllowedIDs.Length; i++) for (int i = 0; i < AllowedIDs.Count; i++)
{ {
if (RegionAllowedIDs[i] == ply.UserID) if (AllowedIDs[i] == ply.UserID)
{ {
return true; return true;
} }

View file

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

35
TShockAPI/DB/SqlColumn.cs Normal file
View file

@ -0,0 +1,35 @@
using MySql.Data.MySqlClient;
namespace TShockAPI.DB
{
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; }
/// <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;
}
}
}

80
TShockAPI/DB/SqlTable.cs Normal file
View file

@ -0,0 +1,80 @@
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
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 SqlTableCreator
{
IDbConnection database;
IQueryBuilder creator;
public SqlTableCreator(IDbConnection db, IQueryBuilder provider)
{
database = db;
creator = provider;
}
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;
}
}
}

53
TShockAPI/DB/SqlValue.cs Normal file
View file

@ -0,0 +1,53 @@
using System.Data;
using MySql.Data.MySqlClient;
using System.Collections.Generic;
namespace TShockAPI.DB
{
public class SqlValue
{
public string Name { get; set; }
public object Value { get; set; }
public SqlValue(string name, object value)
{
Name = name;
Value = value;
}
}
public class SqlTableEditor
{
IDbConnection database;
IQueryBuilder creator;
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 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>();
using (var reader = database.QueryReader(creator.ReadColumn(table, wheres)))
{
while (reader.Read())
values.Add(reader.Reader.Get<object>(column));
}
return values;
}
}
}

View file

@ -18,12 +18,10 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
using System; using System;
using System.IO;
using System.Collections.Generic;
using System.Data; using System.Data;
using System.Linq; using System.IO;
using System.Text; using MySql.Data.MySqlClient;
using Community.CsharpSqlite.SQLiteClient;
namespace TShockAPI.DB namespace TShockAPI.DB
{ {
public class UserManager public class UserManager
@ -34,69 +32,63 @@ namespace TShockAPI.DB
{ {
database = db; database = db;
using (var com = database.CreateCommand()) 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, 64),
new SqlColumn("Usergroup", MySqlDbType.Text),
new SqlColumn("IP", MySqlDbType.VarChar, 32)
);
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))
{ {
if (TShock.Config.StorageType.ToLower() == "sqlite") using (StreamReader sr = new StreamReader(file))
com.CommandText =
"CREATE TABLE IF NOT EXISTS 'Users' ('ID' INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL UNIQUE, 'Username' VARCHAR(32) UNIQUE, 'Password' VARCHAR(64), 'Usergroup' TEXT, 'IP' VARCHAR(32));";
else if (TShock.Config.StorageType.ToLower() == "mysql")
com.CommandText =
"CREATE TABLE IF NOT EXISTS Users (ID INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, Username VARCHAR(32) UNIQUE, Password VARCHAR(64), Usergroup VARCHAR(255), IP VARCHAR(15));";
com.ExecuteNonQuery();
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)
{ {
String line; if (line.Equals("") || line.Substring(0, 1).Equals("#"))
while ((line = sr.ReadLine()) != null ) continue;
String[] info = line.Split(' ');
String username = "";
String sha = "";
String group = "";
String ip = "";
String[] nameSha = info[0].Split(':');
if (nameSha.Length < 2)
{ {
if (line.Equals("") || line.Substring(0, 1).Equals("#") ) username = nameSha[0];
continue; ip = nameSha[0];
String[] info = line.Split(' '); group = info[1];
if (TShock.Config.StorageType.ToLower() == "sqlite")
com.CommandText = "INSERT OR IGNORE INTO Users (Username, Password, Usergroup, IP) VALUES (@name, @pass, @group, @ip);";
else if (TShock.Config.StorageType.ToLower() == "mysql")
com.CommandText = "INSERT IGNORE INTO Users SET Username=@name, Password=@pass, Usergroup=@group, IP=@ip ;";
String username = "";
String sha = "";
String group = "";
String ip = "";
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];
}
com.AddParameter("@name", username.Trim());
com.AddParameter("@pass", sha.Trim());
com.AddParameter("@group", group.Trim());
com.AddParameter("@ip", ip.Trim());
com.ExecuteNonQuery();
com.Parameters.Clear();
} }
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";
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))
System.IO.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, "users.txt");
if (!Directory.Exists(path))
Directory.CreateDirectory(path);
if (File.Exists(file2))
File.Delete(file2);
File.Move(file, file2);
} }
} }
/// <summary> /// <summary>
@ -107,24 +99,11 @@ namespace TShockAPI.DB
{ {
try try
{ {
using (var com = database.CreateCommand()) if (!TShock.Groups.GroupExists(user.Group))
{ throw new GroupNotExistsException(user.Group);
com.CommandText = "INSERT INTO Users (Username, Password, UserGroup, IP) VALUES (@name, @password, @group, @ip);";
com.AddParameter("@name", user.Name);
com.AddParameter("@password", Tools.HashPassword(user.Password));
if (!TShock.Groups.GroupExists(user.Group)) if (database.Query("INSERT INTO Users (Username, Password, UserGroup, IP) VALUES (@0, @1, @2, @3);", user.Name, Tools.HashPassword(user.Password), user.Group, user.Address) < 1)
throw new GroupNotExistsException(user.Group); throw new UserExistsException(user.Name);
com.AddParameter("@group", user.Group);
com.AddParameter("@ip", user.Address);
using (var reader = com.ExecuteReader())
{
if (reader.RecordsAffected < 1)
throw new UserExistsException(user.Name);
}
}
} }
catch (Exception ex) catch (Exception ex)
{ {
@ -140,25 +119,18 @@ namespace TShockAPI.DB
{ {
try try
{ {
using (var com = database.CreateCommand()) int affected = -1;
if (!string.IsNullOrEmpty(user.Address))
{ {
if (!string.IsNullOrEmpty(user.Address)) affected = database.Query("DELETE FROM Users WHERE IP=@0", user.Address);
{
com.CommandText = "DELETE FROM Users WHERE IP=@ip";
com.AddParameter("@ip", user.Address);
}
else
{
com.CommandText = "DELETE FROM Users WHERE Username=@name";
com.AddParameter("@name", user.Name);
}
using (var reader = com.ExecuteReader())
{
if (reader.RecordsAffected < 1)
throw new UserNotExistException(string.IsNullOrEmpty(user.Address) ? user.Name : 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) catch (Exception ex)
{ {
@ -176,18 +148,8 @@ namespace TShockAPI.DB
{ {
try try
{ {
using (var com = database.CreateCommand()) if (database.Query("UPDATE Users SET Password = @0 WHERE Username = @1;", Tools.HashPassword(password), user.Name) == 0)
{ throw new UserNotExistException(user.Name);
com.CommandText = "UPDATE Users SET Password = @password WHERE Username = @name;";
com.AddParameter("@name", user.Name);
com.AddParameter("@password", Tools.HashPassword(password));
using (var reader = com.ExecuteReader())
{
if (reader.RecordsAffected < 1)
throw new UserExistsException(user.Name);
}
}
} }
catch (Exception ex) catch (Exception ex)
{ {
@ -204,22 +166,11 @@ namespace TShockAPI.DB
{ {
try try
{ {
using (var com = database.CreateCommand()) if (!TShock.Groups.GroupExists(group))
{ throw new GroupNotExistsException(group);
com.CommandText = "UPDATE Users SET UserGroup = @group WHERE Username = @name;";
com.AddParameter("@name", user.Name);
if (!TShock.Groups.GroupExists(group)) if (database.Query("UPDATE Users SET UserGroup = @0 WHERE Username = @1;", group, user.Name) == 0)
throw new GroupNotExistsException(group); throw new UserNotExistException(user.Name);
com.AddParameter("@group", group);
using (var reader = com.ExecuteReader())
{
if (reader.RecordsAffected < 1)
throw new UserExistsException(user.Name);
}
}
} }
catch (Exception ex) catch (Exception ex)
{ {
@ -238,26 +189,19 @@ namespace TShockAPI.DB
string[] returndata = new string[2]; string[] returndata = new string[2];
try try
{ {
using (var com = database.CreateCommand()) using (var reader = database.QueryReader("SELECT * FROM Users WHERE Username=@0", username))
{ {
com.CommandText = "SELECT * FROM Users WHERE Username=@name"; if (reader.Read())
com.AddParameter("@name", username.ToLower());
using (var reader = com.ExecuteReader())
{ {
if (reader.Read()) returndata[0] = reader.Get<string>("Password");
{ returndata[1] = reader.Get<string>("UserGroup");
returndata[0] = reader.Get<string>("Password"); return returndata;
returndata[1] = reader.Get<string>("UserGroup");
return returndata;
}
reader.Close();
} }
} }
} }
catch (Exception ex) catch (Exception ex)
{ {
Log.ConsoleError("FetchHashedPasswordAndGroup SQL returned an error: " + ex.ToString()); Log.ConsoleError("FetchHashedPasswordAndGroup SQL returned an error: " + ex);
} }
return returndata; return returndata;
} }
@ -266,24 +210,17 @@ namespace TShockAPI.DB
{ {
try try
{ {
using (var com = database.CreateCommand()) using (var reader = database.QueryReader("SELECT * FROM Users WHERE Username=@0", username))
{ {
com.CommandText = "SELECT * FROM Users WHERE Username=@name"; if (reader.Read())
com.AddParameter("@name", username.ToLower());
using (var reader = com.ExecuteReader())
{ {
if (reader.Read()) return reader.Get<int>("ID");
{
return reader.Get<int>("ID");
}
reader.Close();
} }
} }
} }
catch (Exception ex) catch (Exception ex)
{ {
Log.ConsoleError("FetchHashedPasswordAndGroup SQL returned an error: " + ex.ToString()); Log.ConsoleError("FetchHashedPasswordAndGroup SQL returned an error: " + ex);
} }
return -1; return -1;
} }
@ -296,24 +233,18 @@ namespace TShockAPI.DB
{ {
try try
{ {
using (var com = database.CreateCommand()) using (var reader = database.QueryReader("SELECT * FROM Users WHERE IP=@0", ip))
{ {
com.CommandText = "SELECT * FROM Users WHERE IP=@ip"; if (reader.Read())
com.AddParameter("@ip", ip);
using (var reader = com.ExecuteReader())
{ {
if (reader.Read()) string group = reader.Get<string>("UserGroup");
{ return Tools.GetGroup(group);
string group = reader.Get<string>("UserGroup");
return Tools.GetGroup(group);
}
} }
} }
} }
catch (Exception ex) catch (Exception ex)
{ {
Log.ConsoleError("GetGroupForIP SQL returned an error: " + ex.ToString()); Log.ConsoleError("GetGroupForIP SQL returned an error: " + ex);
} }
return Tools.GetGroup("default"); return Tools.GetGroup("default");
} }
@ -322,26 +253,20 @@ namespace TShockAPI.DB
{ {
try try
{ {
using (var com = database.CreateCommand()) using (var reader = database.QueryReader("SELECT IP, UserGroup FROM Users"))
{ {
com.CommandText = "SELECT * FROM Users"; while (reader.Read())
using (var reader = com.ExecuteReader())
{ {
while(reader.Read()) if (Tools.GetIPv4Address(reader.Get<string>("IP")) == ip)
{ {
if (Tools.GetIPv4Address(reader.Get<string>("IP")) == ip) return Tools.GetGroup(reader.Get<string>("UserGroup"));
{
string group = reader.Get<string>("UserGroup");
return Tools.GetGroup(group);
}
} }
} }
} }
} }
catch (Exception ex) catch (Exception ex)
{ {
Log.ConsoleError("GetGroupForIP SQL returned an error: " + ex.ToString()); Log.ConsoleError("GetGroupForIP SQL returned an error: " + ex);
} }
return Tools.GetGroup("default"); return Tools.GetGroup("default");
} }
@ -373,27 +298,23 @@ namespace TShockAPI.DB
{ {
try try
{ {
using (var com = database.CreateCommand()) QueryResult result;
if (string.IsNullOrEmpty(user.Address))
{ {
if (string.IsNullOrEmpty(user.Address)) result = database.QueryReader("SELECT * FROM Users WHERE Username=@0", user.Name);
{ }
com.CommandText = "SELECT * FROM Users WHERE Username=@name"; else
com.AddParameter("@name", user.Name); {
} result = database.QueryReader("SELECT * FROM Users WHERE IP=@0", user.Address);
else }
{
com.CommandText = "SELECT * FROM Users WHERE IP=@ip";
com.AddParameter("@ip", user.Address);
}
using (var reader = com.ExecuteReader()) using (var reader = result)
{
if (reader.Read())
{ {
if (reader.Read()) user.ID = reader.Get<int>("ID");
{ user.Group = reader.Get<string>("Usergroup");
user.ID = reader.Get<int>("ID"); return user;
user.Group = reader.Get<string>("Usergroup");
return user;
}
} }
} }
} }

View file

@ -20,8 +20,9 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Data; using System.Data;
using System.IO; using System.IO;
using Microsoft.Xna.Framework;
using System.Xml; using System.Xml;
using Microsoft.Xna.Framework;
using MySql.Data.MySqlClient;
using Terraria; using Terraria;
namespace TShockAPI.DB namespace TShockAPI.DB
@ -34,112 +35,100 @@ namespace TShockAPI.DB
{ {
database = db; database = db;
using (var com = database.CreateCommand()) 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))
{ {
if (TShock.Config.StorageType.ToLower() == "sqlite") XmlReader reader;
com.CommandText = using (reader = XmlReader.Create(new StreamReader(file)))
"CREATE TABLE IF NOT EXISTS 'Warps' ('X' NUMERIC, 'Y' NUMERIC, 'WarpName' TEXT PRIMARY KEY, 'WorldID' TEXT);";
else if (TShock.Config.StorageType.ToLower() == "mysql")
com.CommandText =
"CREATE TABLE IF NOT EXISTS Warps (X INT(11), Y INT(11), WarpName VARCHAR(255) PRIMARY, WorldID VARCHAR(255));";
com.ExecuteNonQuery();
String file = Path.Combine(TShock.SavePath, "warps.xml");
String name = "";
String world = "";
int x1 = 0;
int y1 = 0;
if (File.Exists(file))
{ {
XmlReader reader; // Parse the file and display each of the nodes.
using (reader = XmlReader.Create(new StreamReader(file))) while (reader.Read())
{ {
// Parse the file and display each of the nodes. switch (reader.NodeType)
while (reader.Read())
{ {
switch (reader.NodeType) case XmlNodeType.Element:
{ switch (reader.Name)
case XmlNodeType.Element: {
switch (reader.Name) case "Warp":
{ name = "";
case "Warp": world = "";
name = ""; x1 = 0;
world = ""; y1 = 0;
x1 = 0; break;
y1 = 0; case "WarpName":
break; while (reader.NodeType != XmlNodeType.Text)
case "WarpName": reader.Read();
while (reader.NodeType != XmlNodeType.Text) name = reader.Value;
reader.Read(); break;
name = reader.Value; case "X":
break; while (reader.NodeType != XmlNodeType.Text)
case "X": reader.Read();
while (reader.NodeType != XmlNodeType.Text) int.TryParse(reader.Value, out x1);
reader.Read(); break;
int.TryParse(reader.Value, out x1); case "Y":
break; while (reader.NodeType != XmlNodeType.Text)
case "Y": reader.Read();
while (reader.NodeType != XmlNodeType.Text) int.TryParse(reader.Value, out y1);
reader.Read(); break;
int.TryParse(reader.Value, out y1); case "WorldName":
break; while (reader.NodeType != XmlNodeType.Text)
case "WorldName": reader.Read();
while (reader.NodeType != XmlNodeType.Text) world = reader.Value;
reader.Read(); break;
world = reader.Value; }
break; break;
} case XmlNodeType.Text:
break;
case XmlNodeType.Text:
break; break;
case XmlNodeType.XmlDeclaration: case XmlNodeType.XmlDeclaration:
case XmlNodeType.ProcessingInstruction: case XmlNodeType.ProcessingInstruction:
break; break;
case XmlNodeType.Comment: case XmlNodeType.Comment:
break; break;
case XmlNodeType.EndElement: case XmlNodeType.EndElement:
if (reader.Name.Equals("Warp")) if (reader.Name.Equals("Warp"))
{ {
if (TShock.Config.StorageType.ToLower() == "sqlite") string query = (TShock.Config.StorageType.ToLower() == "sqlite") ?
com.CommandText = "INSERT OR IGNORE INTO Warps VALUES (@tx, @ty,@name, @worldid);"; "INSERT OR IGNORE INTO Warps VALUES (@0, @1,@2, @3);" :
else if (TShock.Config.StorageType.ToLower() == "mysql") "INSERT IGNORE INTO Warps SET X=@0, Y=@1, WarpName=@2, WorldID=@3;";
com.CommandText = "INSERT IGNORE INTO Warps SET X=@tx, Y=@ty, WarpName=@name, WorldID=@worldid;"; database.Query(query, x1, y1, name, world);
com.AddParameter("@tx", x1); }
com.AddParameter("@ty", y1); break;
com.AddParameter("@name", name);
com.AddParameter("@worldid", world);
com.ExecuteNonQuery();
com.Parameters.Clear();
}
break;
}
} }
} }
reader.Close();
String path = Path.Combine(TShock.SavePath, "old_configs");
String file2 = Path.Combine(path, "warps.xml");
if (!Directory.Exists(path))
System.IO.Directory.CreateDirectory(path);
if (File.Exists(file2))
File.Delete(file2);
//File.Move(file, file2);
} }
reader.Close();
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() public void ConvertDB()
{ {
try try
{ {
using (var com = database.CreateCommand()) database.Query("UPDATE Warps SET WorldID=@0", Main.worldID.ToString());
{
com.CommandText = "UPDATE Warps SET WorldID=@worldid";
com.AddParameter("@worldid", Main.worldID.ToString());
com.ExecuteNonQuery();
}
} }
catch (Exception ex) catch (Exception ex)
{ {
@ -151,16 +140,8 @@ namespace TShockAPI.DB
{ {
try try
{ {
using (var com = database.CreateCommand()) database.Query("INSERT INTO Warps (X, Y, WarpName, WorldID) VALUES (@0, @1, @2, @3);", x, y, name, worldid);
{ return true;
com.CommandText = "INSERT INTO Warps (X, Y, WarpName, WorldID) VALUES (@x, @y, @name, @worldid);";
com.AddParameter("@x", x);
com.AddParameter("@y", y);
com.AddParameter("@name", name.ToLower());
com.AddParameter("@worldid", worldid);
com.ExecuteNonQuery();
return true;
}
} }
catch (Exception ex) catch (Exception ex)
{ {
@ -173,14 +154,8 @@ namespace TShockAPI.DB
{ {
try try
{ {
using (var com = database.CreateCommand()) database.Query("DELETE FROM Warps WHERE WarpName=@0 AND WorldID=@1", name, Main.worldID.ToString());
{ return true;
com.CommandText = "DELETE FROM Warps WHERE WarpName=@name AND WorldID=@worldid";
com.AddParameter("@name", name.ToLower());
com.AddParameter("@worldid", Main.worldID.ToString());
com.ExecuteNonQuery();
return true;
}
} }
catch (Exception ex) catch (Exception ex)
{ {
@ -193,18 +168,18 @@ namespace TShockAPI.DB
{ {
try try
{ {
using (var com = database.CreateCommand()) using (var reader = database.QueryReader("SELECT * FROM Warps WHERE WarpName=@0 AND WorldID=@1", name, Main.worldID.ToString()))
{ {
com.CommandText = "SELECT * FROM Warps WHERE WarpName=@name AND WorldID=@worldid"; if (reader.Read())
com.AddParameter("@name", name);
com.AddParameter("@worldid", Main.worldID.ToString());
using (var reader = com.ExecuteReader())
{ {
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")); 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");
} }
reader.Close();
} }
} }
} }
@ -220,19 +195,24 @@ namespace TShockAPI.DB
/// </summary> /// </summary>
/// <param name="worldid">World name to get warps from</param> /// <param name="worldid">World name to get warps from</param>
/// <returns>List of warps with only their names</returns> /// <returns>List of warps with only their names</returns>
public List<Warp> ListAllWarps(string worldid) public List<Warp> ListAllPublicWarps(string worldid)
{ {
var warps = new List<Warp>(); var warps = new List<Warp>();
try try
{ {
using (var com = database.CreateCommand()) using (var reader = database.QueryReader("SELECT * FROM Warps WHERE WorldID=@0", worldid))
{ {
com.CommandText = "SELECT WarpName FROM Warps WHERE WorldID=@worldid"; while (reader.Read())
com.AddParameter("@worldid", worldid);
using (var reader = com.ExecuteReader())
{ {
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") }); warps.Add(new Warp { WarpName = reader.Get<string>("WarpName") });
}
} }
} }
} }
@ -242,6 +222,28 @@ namespace TShockAPI.DB
} }
return warps; 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";
database.Query(query, state ? "1" : "0", warp, Main.worldID.ToString());
return true;
}
catch (Exception ex)
{
Log.Error(ex.ToString());
return false;
}
}
} }
public class Warp public class Warp
@ -249,12 +251,14 @@ namespace TShockAPI.DB
public Vector2 WarpPos { get; set; } public Vector2 WarpPos { get; set; }
public string WarpName { get; set; } public string WarpName { get; set; }
public string WorldWarpID { get; set; } public string WorldWarpID { get; set; }
public string Private { get; set; }
public Warp(Vector2 warppos, string name, string worldname) public Warp(Vector2 warppos, string name, string worldid, string hidden)
{ {
WarpPos = warppos; WarpPos = warppos;
WarpName = name; WarpName = name;
WorldWarpID = worldname; WorldWarpID = worldid;
Private = hidden;
} }
public Warp() public Warp()
@ -262,6 +266,7 @@ namespace TShockAPI.DB
WarpPos = Vector2.Zero; WarpPos = Vector2.Zero;
WarpName = null; WarpName = null;
WorldWarpID = string.Empty; WorldWarpID = string.Empty;
Private = "0";
} }
} }
} }

317
TShockAPI/DBTools.cs Normal file
View file

@ -0,0 +1,317 @@
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using TShockAPI.DB;
namespace TShockAPI
{
public class DBTools
{
internal static IDbConnection database;
/// <summary>
/// Creates a Table, within the current open DB
/// </summary>
/// <param name="name">Name of the Table</param>
/// <param name="columns">The list of columns that the Table will have</param>
/// <param name="IfNotExists">Only try create Table if it does not exist</param>
public static void CreateTable(string name, List<Column> columns, bool IfNotExists =true)
{
//Build up Creation string :)
StringBuilder sb = new StringBuilder();
sb.Append("CREATE TABLE ");
if (IfNotExists)
sb.Append("IF NOT EXISTS ");
if (TShock.Config.StorageType.ToLower() == "sqlite")
sb.Append("'" + name + "' (");
else if (TShock.Config.StorageType.ToLower() == "mysql")
sb.Append(name + " (");
int count = 0;
foreach (Column column in columns)
{
count++;
if (column.Type.ToLower() == "int")
{
if (TShock.Config.StorageType.ToLower() == "sqlite")
sb.Append(column.Name + " NUMERIC ");
else if (TShock.Config.StorageType.ToLower() == "mysql")
sb.Append(column.Name + " INT(255) ");
}
else if (column.Type.ToLower() == "string")
{
if (TShock.Config.StorageType.ToLower() == "sqlite")
sb.Append(column.Name + " TEXT ");
else if (TShock.Config.StorageType.ToLower() == "mysql")
sb.Append(column.Name + " VARCHAR(255) ");
}
if (column.Unique)
sb.Append("UNIQUE");
if (columns.Count == count)
sb.Append(")");
else
sb.Append(", ");
}
database.Query(sb.ToString());
}
/// <summary>
/// Inserts a list of values into a Table, if conditions are met
/// </summary>
/// <param name="tablename">Name of the Table</param>
/// <param name="Ignore">Ignore insert if feild is unique and there is already a exact entry</param>
/// <param name="Values">The list of values to enter into the table</param>
/// <param name="WhereStatements">The list of where statements that must be met, can be an empty list</param>
public static int InsertTable(string tablename, bool Ignore, List<ColumnData> Values, List<ColumnData> WhereStatements)
{
StringBuilder sb = new StringBuilder();
sb.Append("INSERT ");
if (Ignore)
{
if (TShock.Config.StorageType.ToLower() == "sqlite")
sb.Append("OR IGNORE ");
else if (TShock.Config.StorageType.ToLower() == "mysql")
sb.Append("IGNORE ");
}
if (TShock.Config.StorageType.ToLower() == "sqlite")
sb.Append("INTO '" + tablename + "' (");
else if (TShock.Config.StorageType.ToLower() == "mysql")
sb.Append("INTO " + tablename + " ");
using (var com = database.CreateCommand())
{
//Values
if (TShock.Config.StorageType.ToLower() == "sqlite")
{
int count = 0;
foreach (ColumnData columnname in Values)
{
count++;
if (Values.Count != count)
sb.Append(columnname.Name + ", ");
else
sb.Append(columnname.Name + ") ");
}
sb.Append("VALUES (");
count = 0;
foreach (ColumnData columnname in Values)
{
count++;
if (Values.Count != count)
{
sb.Append("@" + columnname.Name.ToLower() + ", ");
com.AddParameter("@" + columnname.Name.ToLower(), columnname.Value);
}
else
{
sb.Append("@" + columnname.Name.ToLower() + ") ");
com.AddParameter("@" + columnname.Name.ToLower(), columnname.Value);
}
}
}
else if (TShock.Config.StorageType.ToLower() == "mysql")
{
sb.Append("SET ");
int count = 0;
foreach (ColumnData columnname in Values)
{
count++;
if (Values.Count != count)
{
sb.Append("@" + columnname.Name.ToLower() + "=" + columnname.Value + ", ");
com.AddParameter("@" + columnname.Name.ToLower(), columnname.Value);
}
else
{
sb.Append("@" + columnname.Name.ToLower() + "=" + columnname.Value + ") ");
com.AddParameter("@" + columnname.Name.ToLower(), columnname.Value);
}
}
}
//Where Statement (if any)
if (WhereStatements.Count > 0)
{
sb.Append("WHERE ");
int count = 0;
foreach (ColumnData columnname in WhereStatements)
{
count++;
if (Values.Count != count)
{
sb.Append("@" + columnname.Name.ToLower() + "-where" + "=" + columnname.Value + " AND ");
com.AddParameter("@" + columnname.Name.ToLower() + "-where", columnname.Value);
}
else
{
sb.Append("@" + columnname.Name.ToLower() + "-where" + "=" + columnname.Value + ";");
com.AddParameter("@" + columnname.Name.ToLower() + "-where", columnname.Value);
}
}
}
com.CommandText = sb.ToString();
using (var reader = com.ExecuteReader())
return reader.RecordsAffected;
}
}
/// <summary>
/// Returns a list of values from a given Table, where conditions are met
/// </summary>
/// <param name="tablename">Name of the Table</param>
/// <param name="getcolumn">The name of the column you are getting the values from</param>
/// <param name="WhereStatements">The list of where statements that must be met, can be an empty list</param>
public static List<object> ReadTable(string tablename, string getcolumn, List<ColumnData> WhereStatements)
{
StringBuilder sb = new StringBuilder();
List<object> ReturnedValues = new List<object>();
sb.Append("SELECT * FROM " + tablename + " ");
using (var com = database.CreateCommand())
{
//Where Statement (if any)
if (WhereStatements.Count > 0)
{
sb.Append("WHERE ");
int count = 0;
foreach (ColumnData columnname in WhereStatements)
{
count++;
if (WhereStatements.Count != count)
{
sb.Append(columnname.Name + " =" + columnname.Value + " AND ");
}
else
{
sb.Append(columnname.Name + " =" + columnname.Value);
}
}
}
com.CommandText = sb.ToString();
using (var reader = com.ExecuteReader())
{
while (reader.Read())
ReturnedValues.Add(reader.Get<object>(getcolumn));
}
}
return ReturnedValues;
}
/// <summary>
/// Sets values in a Table, where statements are met
/// </summary>
/// <param name="tablename">Name of the Table</param>
/// <param name="setcolumn">The column data you are setting</param>
/// <param name="WhereStatements">The list of where statements that must be met, can be an empty list</param>
public static int SetTable(string tablename, ColumnData setcolumn, List<ColumnData> WhereStatements)
{
StringBuilder sb = new StringBuilder();
sb.Append("UPDATE " + tablename + " SET " + setcolumn.Name + "=@setcolumn ");
using (var com = database.CreateCommand())
{
//Where Statement (if any)
if (WhereStatements.Count > 0)
{
sb.Append("WHERE ");
int count = 0;
foreach (ColumnData columnname in WhereStatements)
{
count++;
if (WhereStatements.Count != count)
{
sb.Append(columnname.Name + " =" + columnname.Value + " AND ");
}
else
{
sb.Append(columnname.Name + " =" + columnname.Value);
}
}
}
com.CommandText = sb.ToString();
com.AddParameter("@setcolumn", setcolumn.Value);
using (var reader = com.ExecuteReader())
return reader.RecordsAffected;
}
}
}
public class Column
{
public string Name { get; set; }
public string Type { get; set; }
public bool Unique { get; set; }
public string Parameters { get; set; }
/// <summary>
/// The class for creating a new column type
/// </summary>
/// <param name="name">Name of the column</param>
/// <param name="unique">Whether there can be more than one exact value in the column</param>
/// <param name="type">The type of column, currently the api only supports "string" or "int"</param>
/// <param name="parameters">Extra SQL parameters given, can cause errors cross different SQL (SQLite and MySql)</param>
public Column(string name, bool unique, string type, string parameters = "")
{
Name = name;
Type = type;
Unique = unique;
Parameters = parameters;
}
public Column()
{
Name = string.Empty;
Type = string.Empty;
Unique = false;
Parameters = string.Empty;
}
}
public class ColumnData
{
public string Name { get; set; }
public object Value { get; set; }
/// <summary>
/// The class for testing, inserting or setting column data
/// </summary>
/// <param name="name">Column Name</param>
/// <param name="value">Column Value</param>
public ColumnData(string name, object value)
{
Name = name;
Value = value;
}
public ColumnData()
{
Name = string.Empty;
Value = string.Empty;
}
}
}

View file

@ -0,0 +1,141 @@
using System;
using System.Collections.Generic;
using System.Data;
namespace TShockAPI.DB
{
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>
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();
}
}
}
/// <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>
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());
}
}
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 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)},
};
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 (ReadFuncs.ContainsKey(typeof(T)))
return (T)ReadFuncs[typeof(T)](reader, column);
throw new NotImplementedException();
}
}
public enum SqlType
{
Unknown,
Sqlite,
Mysql
}
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 void Dispose()
{
Reader.Dispose();
Connection.Dispose();
}
public bool Read()
{
return Reader.Read();
}
public T Get<T>(string column)
{
return Reader.Get<T>(Reader.GetOrdinal(column));
}
}
}

View file

@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
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");
foreach (T item in source)
action(item);
}
}
}

View file

@ -0,0 +1,31 @@
using System;
using System.Collections.Generic;
using System.Linq;
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();
}
}
}

View file

@ -0,0 +1,16 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
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);
}
}
}

View file

@ -17,17 +17,16 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
using System; using System;
using System.IO; using System.IO;
using Terraria;
namespace TShockAPI namespace TShockAPI
{ {
internal class FileTools public class FileTools
{ {
public static string RulesPath { get { return Path.Combine(TShock.SavePath, "rules.txt"); } } internal static string RulesPath { get { return Path.Combine(TShock.SavePath, "rules.txt"); } }
public static string MotdPath { get { return Path.Combine(TShock.SavePath, "motd.txt"); } } internal static string MotdPath { get { return Path.Combine(TShock.SavePath, "motd.txt"); } }
public static string WhitelistPath { get { return Path.Combine(TShock.SavePath, "whitelist.txt"); } } internal static string WhitelistPath { get { return Path.Combine(TShock.SavePath, "whitelist.txt"); } }
public static string RememberedPosPath { get { return Path.Combine(TShock.SavePath, "oldpos.xml"); } } internal static string RememberedPosPath { get { return Path.Combine(TShock.SavePath, "oldpos.xml"); } }
public static string ConfigPath { get { return Path.Combine(TShock.SavePath, "config.json"); } } internal static string ConfigPath { get { return Path.Combine(TShock.SavePath, "config.json"); } }
public static void CreateFile(string file) public static void CreateFile(string file)
{ {

View file

@ -340,7 +340,7 @@ namespace TShockAPI
if ((DateTime.UtcNow - args.Player.LastExplosive).TotalMilliseconds < 1000) if ((DateTime.UtcNow - args.Player.LastExplosive).TotalMilliseconds < 1000)
{ {
args.Player.SendMessage("Please wait another " + (1000 - (DateTime.UtcNow - args.Player.LastExplosive).TotalMilliseconds).ToString() + " milliseconds before placing/destroying tiles", Color.Red); args.Player.SendMessage("Please wait another " + (1000 - (DateTime.UtcNow - args.Player.LastExplosive).TotalMilliseconds) + " milliseconds before placing/destroying tiles", Color.Red);
args.Player.SendTileSquare(x, y); args.Player.SendTileSquare(x, y);
return true; return true;
} }
@ -414,6 +414,18 @@ namespace TShockAPI
byte owner = args.Data.ReadInt8(); byte owner = args.Data.ReadInt8();
byte type = args.Data.ReadInt8(); byte type = args.Data.ReadInt8();
if (ident > Main.maxProjectiles || ident < 0)
{
Tools.HandleGriefer(args.Player, TShock.Config.ExplosiveAbuseReason);
return true;
}
if ((vely == 0f || velx == 0f) && type == 23)
{
Tools.HandleGriefer(args.Player, TShock.Config.ProjectileAbuseReason);
return true;
}
if (type == 29 || type == 28 || type == 37) if (type == 29 || type == 28 || type == 37)
{ {
Log.Debug(string.Format("Explosive(PlyXY:{0}_{1}, Type:{2})", args.Player.TileX, args.Player.TileY, type)); Log.Debug(string.Format("Explosive(PlyXY:{0}_{1}, Type:{2})", args.Player.TileX, args.Player.TileY, type));

View file

@ -29,10 +29,17 @@ namespace TShockAPI
public Group Parent { get; protected set; } public Group Parent { get; protected set; }
public int Order { get; set; } public int Order { get; set; }
public Group(string groupname, Group parentgroup = null) 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; Name = groupname;
Parent = parentgroup; 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) public virtual bool HasPermission(string permission)
@ -100,6 +107,9 @@ namespace TShockAPI
public SuperAdminGroup() public SuperAdminGroup()
: base("superadmin") : base("superadmin")
{ {
R = (byte)TShock.Config.SuperAdminChatRGB[0];
G = (byte)TShock.Config.SuperAdminChatRGB[1];
B = (byte)TShock.Config.SuperAdminChatRGB[2];
} }
public override bool HasPermission(string permission) public override bool HasPermission(string permission)

View file

@ -16,11 +16,7 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
using System;
using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq;
using System.Text;
namespace TShockAPI namespace TShockAPI
{ {

View file

@ -17,10 +17,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
using System; using System;
using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq;
using System.Text;
using Terraria; using Terraria;
using XNAHelpers; using XNAHelpers;

View file

@ -17,11 +17,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
using System; using System;
using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq;
using System.Text; using System.Text;
using Terraria;
using TerrariaAPI; using TerrariaAPI;
using XNAHelpers; using XNAHelpers;

157
TShockAPI/PacketBufferer.cs Normal file
View file

@ -0,0 +1,157 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Net.Sockets;
using System.Text;
using Microsoft.Xna.Framework;
using Terraria;
using TerrariaAPI;
using TerrariaAPI.Hooks;
namespace TShockAPI
{
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];
int[] Bytes = new int[52];
int[] Packets = new int[52];
int[] Compressed = new int[52];
Command dump;
Command flush;
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");
flush = new Command("superadmin", Flush, "netflush");
Commands.ChatCommands.Add(dump);
Commands.ChatCommands.Add(flush);
#endif
ServerHooks.SendBytes += ServerHooks_SendBytes;
ServerHooks.SocketReset += ServerHooks_SocketReset;
GameHooks.PostUpdate += GameHooks_Update;
}
public void Dispose()
{
#if DEBUG_NET
Commands.ChatCommands.Remove(dump);
Commands.ChatCommands.Remove(flush);
#endif
ServerHooks.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());
}
void Flush(CommandArgs args)
{
Bytes = new int[52];
Packets = new int[52];
Compressed = new int[52];
}
void GameHooks_Update(GameTime obj)
{
for (int i = 0; i < Netplay.serverSock.Length; i++)
{
if (Netplay.serverSock[i] == null || !Netplay.serverSock[i].active)
continue;
if (!Netplay.serverSock[i].tcpClient.Client.Poll(0, SelectMode.SelectWrite))
continue;
byte[] buff = buffers[i].GetBytes(BytesPerUpdate);
if (buff == null)
continue;
try
{
Netplay.serverSock[i].tcpClient.Client.Send(buff);
}
catch (ObjectDisposedException)
{
}
catch (SocketException)
{
}
}
}
void ServerHooks_SocketReset(ServerSock socket)
{
buffers[socket.whoAmI] = new PacketBuffer();
}
void ServerHooks_SendBytes(ServerSock socket, byte[] buffer, int offset, int count, HandledEventArgs e)
{
e.Handled = true;
lock (buffers[socket.whoAmI])
{
#if DEBUG_NET
int size = (count - offset);
var pt = buffer[offset + 4];
Packets[pt]++;
Bytes[pt] += size;
Compressed[pt] += Compress(buffer, offset, count);
#endif
buffers[socket.whoAmI].AddRange(new MemoryStream(buffer, offset, count).ToArray());
}
}
#if DEBUG_NET
static int Compress(byte[] buffer, int offset, int count)
{
using (var ms = new MemoryStream())
{
using (var gzip = new GZipStream(ms, CompressionMode.Compress, true))
{
gzip.Write(buffer, offset, count);
}
return (int)ms.Length;
}
}
#endif
}
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);
this.RemoveRange(0, ret.Length);
return ret;
}
}
}
}

View file

@ -36,5 +36,5 @@ using System.Runtime.InteropServices;
// [assembly: AssemblyVersion("1.0.*")] // [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("3.1.3.0723")] [assembly: AssemblyVersion("3.2.0.0805")]
[assembly: AssemblyFileVersion("3.1.3.0723")] [assembly: AssemblyFileVersion("3.2.0.0805")]

View file

@ -18,12 +18,11 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.IO; using System.IO;
using System.Net; using System.Net;
using System.Net.Sockets; using System.Net.Sockets;
using System.Text;
using System.Threading;
using Terraria; using Terraria;
namespace TShockAPI namespace TShockAPI
@ -36,7 +35,7 @@ namespace TShockAPI
public static int ListenPort; public static int ListenPort;
public static bool ContinueServer = true; public static bool ContinueServer = true;
public static string Response = ""; public static string Response = "";
private static bool Started = false; private static bool Started;
private static UdpClient listener; private static UdpClient listener;
public static void StartThread() public static void StartThread()
@ -55,9 +54,9 @@ namespace TShockAPI
try try
{ {
Console.WriteLine(string.Format("RconHandler is running at UDP port {0} and password is {1}", Console.WriteLine(string.Format("RconHandler is running at UDP port {0} and password is {1}",
ListenPort.ToString(), ListenPort,
Password)); Password));
Thread listen = new Thread(new ThreadStart(Listener)); Thread listen = new Thread(Listener);
listen.Start(); listen.Start();
while (true) while (true)
{ {
@ -87,7 +86,7 @@ namespace TShockAPI
catch (SocketException e) catch (SocketException e)
{ {
if (e.SocketErrorCode == SocketError.AddressAlreadyInUse) if (e.SocketErrorCode == SocketError.AddressAlreadyInUse)
Log.ConsoleError("Could not bind to " + ListenPort.ToString() + ". Are you sure you don't have another instance running?"); Log.ConsoleError("Could not bind to " + ListenPort + ". Are you sure you don't have another instance running?");
} }
catch (Exception e) catch (Exception e)
{ {
@ -150,7 +149,7 @@ namespace TShockAPI
args[1] = args[0] = ""; args[1] = args[0] = "";
string command = string.Join(" ", args.ToArray()); string command = string.Join(" ", args.ToArray());
command = command.TrimEnd(' ').TrimEnd('\0').TrimStart(' '); command = command.TrimEnd(' ').TrimEnd('\0').TrimStart(' ');
Log.ConsoleInfo("Rcon from " + EP.ToString() + ":" + command); Log.ConsoleInfo("Rcon from " + EP + ":" + command);
Response = ""; Response = "";
response = ExecuteCommand(command); response = ExecuteCommand(command);
response += "\n" + Response; response += "\n" + Response;
@ -160,7 +159,7 @@ namespace TShockAPI
else else
{ {
response = "Bad rconpassword.\n"; response = "Bad rconpassword.\n";
Log.ConsoleInfo("Bad rconpassword from " + EP.ToString()); Log.ConsoleInfo("Bad rconpassword from " + EP);
} }
} }
else else
@ -186,7 +185,7 @@ namespace TShockAPI
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}", 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.Config.ServerName, Main.worldName, Main.maxNetPlayers,
Tools.ActivePlayers(), Main.maxNetPlayers - TShock.Config.MaxSlots, Tools.ActivePlayers(), Main.maxNetPlayers - TShock.Config.MaxSlots,
TShock.Config.HardcoreOnly ? 1 : 0, TShock.VersionNum.ToString(), TShock.Config.HardcoreOnly ? 1 : 0, TShock.VersionNum,
Netplay.password != "" ? 1 : 0); Netplay.password != "" ? 1 : 0);
if (challenge != "") if (challenge != "")
infostring += @"\challenge\" + challenge; infostring += @"\challenge\" + challenge;
@ -205,7 +204,7 @@ namespace TShockAPI
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}", 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.Config.ServerName, Main.worldName, Main.maxNetPlayers,
Tools.ActivePlayers(), Main.maxNetPlayers - TShock.Config.MaxSlots, Tools.ActivePlayers(), Main.maxNetPlayers - TShock.Config.MaxSlots,
TShock.Config.HardcoreOnly ? 1 : 0, TShock.VersionNum.ToString(), TShock.Config.HardcoreOnly ? 1 : 0, TShock.VersionNum,
Netplay.password != "" ? 1 : 0) + "\n"; Netplay.password != "" ? 1 : 0) + "\n";
if (challenge != "") if (challenge != "")
statusstring += @"\challenge\" + challenge; statusstring += @"\challenge\" + challenge;
@ -260,7 +259,7 @@ namespace TShockAPI
if (player != null && player.Active) if (player != null && player.Active)
{ {
count++; 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.ToString())) + "\n"; 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";
} }
} }
} }
@ -334,7 +333,7 @@ namespace TShockAPI
catch (SocketException e) catch (SocketException e)
{ {
if (e.SocketErrorCode == SocketError.AddressAlreadyInUse) if (e.SocketErrorCode == SocketError.AddressAlreadyInUse)
Log.ConsoleError("Could not bind to " + ListenPort.ToString() + ". Are you sure you don't have another instance running?"); Log.ConsoleError("Could not bind to " + ListenPort + ". Are you sure you don't have another instance running?");
} }
catch (Exception e) catch (Exception e)
{ {

View file

@ -1,154 +0,0 @@
/*
TShock, a server mod for Terraria
Copyright (C) 2011 The TShock Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using Terraria;
using Microsoft.Xna.Framework;
using System.Xml;
namespace TShockAPI
{
class RemeberedPosManager
{
public static List<RemeberedPos> RemeberedPosistions = new List<RemeberedPos>();
public static void LoadPos()
{
try
{
XmlReaderSettings xmlReaderSettings = new XmlReaderSettings();
xmlReaderSettings.IgnoreWhitespace = true;
using (XmlReader settingr = XmlReader.Create(FileTools.RememberedPosPath, xmlReaderSettings))
{
while (settingr.Read())
{
if (settingr.IsStartElement())
{
switch (settingr.Name)
{
case "Positions":
{
break;
}
case "Player":
{
if (settingr.Read())
{
string IP = null;
float X = 0;
float Y = 0;
settingr.Read();
if (settingr.Value != "" || settingr.Value != null)
IP = settingr.Value;
else
Log.Warn("IP is empty");
settingr.Read();
settingr.Read();
settingr.Read();
if (settingr.Value != "" || settingr.Value != null)
float.TryParse(settingr.Value, out X);
else
Log.Warn("X for IP " + IP + " is empty");
settingr.Read();
settingr.Read();
settingr.Read();
if (settingr.Value != "" || settingr.Value != null)
float.TryParse(settingr.Value, out Y);
else
Log.Warn("Y for IP " + IP + " is empty");
if (X != 0 && Y != 0)
RemeberedPosistions.Add(new RemeberedPos(IP, new Vector2(X, Y)));
}
break;
}
}
}
}
}
Log.Info("Read Remembered Positions");
}
catch
{
Log.Warn("Could not read Remembered Positions");
WriteSettings();
}
}
public static void WriteSettings()
{
try
{
XmlWriterSettings xmlWriterSettings = new XmlWriterSettings();
xmlWriterSettings.Indent = true;
xmlWriterSettings.NewLineChars = Environment.NewLine;
using (XmlWriter settingsw = XmlWriter.Create(FileTools.RememberedPosPath, xmlWriterSettings))
{
settingsw.WriteStartDocument();
settingsw.WriteStartElement("Positions");
foreach (RemeberedPos player in RemeberedPosistions)
{
settingsw.WriteStartElement("Player");
settingsw.WriteElementString("IP", player.IP);
settingsw.WriteElementString("X", player.Pos.X.ToString());
settingsw.WriteElementString("Y", player.Pos.Y.ToString());
settingsw.WriteEndElement();
}
settingsw.WriteEndElement();
settingsw.WriteEndDocument();
}
Log.Info("Wrote Remembered Positions");
}
catch
{
Log.Warn("Could not write Remembered Positions");
}
}
}
public class RemeberedPos
{
public string IP { get; set; }
public Vector2 Pos { get; set; }
public RemeberedPos(string ip, Vector2 pos)
{
IP = ip;
Pos = pos;
}
public RemeberedPos()
{
IP = string.Empty;
Pos = Vector2.Zero;
}
}
}

View file

@ -18,10 +18,10 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Threading;
using Microsoft.Xna.Framework; using Microsoft.Xna.Framework;
using Terraria; using Terraria;
using TerrariaAPI; using TerrariaAPI;
using TShockAPI.DB;
using TShockAPI.Net; using TShockAPI.Net;
namespace TShockAPI namespace TShockAPI
@ -38,21 +38,22 @@ namespace TShockAPI
public bool ReceivedInfo { get; set; } public bool ReceivedInfo { get; set; }
public int Index { get; protected set; } public int Index { get; protected set; }
public DateTime LastPvpChange { get; protected set; } public DateTime LastPvpChange { get; protected set; }
public Rectangle TempArea = new Rectangle(); public Rectangle TempArea;
public DateTime LastExplosive { get; set; } public DateTime LastExplosive { get; set; }
public DateTime LastTileChangeNotify { get; set; } public DateTime LastTileChangeNotify { get; set; }
public bool InitSpawn = false; public bool InitSpawn;
public bool DisplayLogs = true; public bool DisplayLogs = true;
public Vector2 oldSpawn = Vector2.Zero; public Vector2 oldSpawn = Vector2.Zero;
public TSPlayer LastWhisper; public TSPlayer LastWhisper;
public int LoginAttempts { get; set; } public int LoginAttempts { get; set; }
public Vector2 TeleportCoords = new Vector2(-1, -1); public Vector2 TeleportCoords = new Vector2(-1, -1);
public string UserAccountName { get; set; } public string UserAccountName { get; set; }
public bool HasBeenSpammedWithBuildMessage = false; public bool HasBeenSpammedWithBuildMessage;
public bool IsLoggedIn = false; public bool IsLoggedIn;
public int UserID = -1; public int UserID = -1;
public bool HasBeenNaggedAboutLoggingIn = false; public bool HasBeenNaggedAboutLoggingIn;
Player FakePlayer = null; public bool TpLock = false;
Player FakePlayer;
public bool RealPlayer public bool RealPlayer
{ {
@ -184,52 +185,29 @@ namespace TShockAPI
public bool Teleport(int tilex, int tiley) public bool Teleport(int tilex, int tiley)
{ {
InitSpawn = false; if (!TpLock)
SendTeleport(tilex, tiley);
//150 Should avoid all client crash errors
//The error occurs when a tile trys to update which the client hasnt load yet, Clients only update tiles withen 150 blocks
//Try 300 if it does not work (Higher number - Longer load times - Less chance of error)
if (!SendTileSquare(tilex, tiley, 150))
{ {
SendMessage("Warning, teleport failed due to being too close to the edge of the map.", Color.Red); InitSpawn = false;
return false;
} SendTeleport(tilex, tiley);
//150 Should avoid all client crash errors
//The error occurs when a tile trys to update which the client hasnt load yet, Clients only update tiles withen 150 blocks
//Try 300 if it does not work (Higher number - Longer load times - Less chance of error)
if (!SendTileSquare(tilex, tiley))
{
SendMessage("Warning, teleport failed due to being too close to the edge of the map.", Color.Red);
return false;
}
if (TPlayer.SpawnX > 0 && TPlayer.SpawnY > 0)
{
int spX = TPlayer.SpawnX;
int spY = TPlayer.SpawnY;
Main.tile[spX, spY].active = false;
SendTileSquare(spX, spY);
Spawn(); Spawn();
Main.tile[spX, spY].active = true;
SendTileSquare(spX, spY);
oldSpawn = new Vector2(spX, spY);
}
else
{
//Checks if Player has spawn point set (Server may think player does not have spawn)
if (oldSpawn != Vector2.Zero)
{
Main.tile[(int)oldSpawn.X, (int)oldSpawn.Y].active = false;
SendTileSquare((int)oldSpawn.X, (int)oldSpawn.Y);
Spawn();
Main.tile[(int)oldSpawn.X, (int)oldSpawn.Y].active = true;
SendTileSquare((int)oldSpawn.X, (int)oldSpawn.Y);
NetMessage.syncPlayers();
}
//Player has no spawn point set
else
{
Spawn();
}
}
SendTeleport(Main.spawnTileX, Main.spawnTileY); SendTeleport(Main.spawnTileX, Main.spawnTileY);
return true; return true;
}
SendMessage("Cannot teleport due to TP Lock", Color.Red);
return false;
} }
public void Spawn() public void Spawn()
@ -241,7 +219,7 @@ namespace TShockAPI
{ {
try try
{ {
SendData(PacketTypes.TileSendSquare, "", size, (float)(x - (size / 2)), (float)(y - (size / 2))); SendData(PacketTypes.TileSendSquare, "", size, (x - (size / 2)), (y - (size / 2)));
return true; return true;
} }
catch (Exception ex) catch (Exception ex)
@ -253,7 +231,7 @@ namespace TShockAPI
public virtual void GiveItem(int type, string name, int width, int height, int stack) public virtual void GiveItem(int type, string name, int width, int height, int stack)
{ {
int itemid = Terraria.Item.NewItem((int)X, (int)Y, width, height, type, stack, true); int itemid = Item.NewItem((int)X, (int)Y, width, height, type, stack, true);
// This is for special pickaxe/hammers/swords etc // This is for special pickaxe/hammers/swords etc
Main.item[itemid].SetDefaults(name); Main.item[itemid].SetDefaults(name);
// The set default overrides the wet and stack set by NewItem // The set default overrides the wet and stack set by NewItem
@ -296,6 +274,12 @@ namespace TShockAPI
NetMessage.SendData((int)PacketTypes.TogglePVP, -1, -1, "", Index); NetMessage.SendData((int)PacketTypes.TogglePVP, -1, -1, "", Index);
} }
public virtual void SetTeam(int team)
{
Main.player[Index].team = team;
SendData(PacketTypes.PlayerTeam, "", Index);
}
public virtual void Whoopie(object time) public virtual void Whoopie(object time)
{ {
var time2 = (int)time; var time2 = (int)time;
@ -310,18 +294,18 @@ namespace TShockAPI
{ {
Main.player[0].inventory[player].SetDefaults("Whoopie Cushion"); Main.player[0].inventory[player].SetDefaults("Whoopie Cushion");
Main.player[0].inventory[player].stack = 1; Main.player[0].inventory[player].stack = 1;
SendData(TerrariaAPI.PacketTypes.PlayerSlot, "Whoopie Cushion", player, 0f); SendData(PacketTypes.PlayerSlot, "Whoopie Cushion", player, 0f);
Main.player[player].position = TPlayer.position; Main.player[player].position = TPlayer.position;
Main.player[player].selectedItem = 0; Main.player[player].selectedItem = 0;
Main.player[player].controlUseItem = true; Main.player[player].controlUseItem = true;
SendData(TerrariaAPI.PacketTypes.PlayerUpdate, number: player); SendData(PacketTypes.PlayerUpdate, number: player);
System.Threading.Thread.Sleep(500); Thread.Sleep(500);
Main.player[player].controlUseItem = false; Main.player[player].controlUseItem = false;
SendData(TerrariaAPI.PacketTypes.PlayerUpdate, number: player); SendData(PacketTypes.PlayerUpdate, number: player);
System.Threading.Thread.Sleep(50); Thread.Sleep(50);
} }
Main.player[0].inventory[0] = oriinv; Main.player[0].inventory[0] = oriinv;
SendData(TerrariaAPI.PacketTypes.PlayerSlot, oriinv.name, player, 0f); SendData(PacketTypes.PlayerSlot, oriinv.name, player, 0f);
} }
//Todo: Separate this into a few functions. SendTo, SendToAll, etc //Todo: Separate this into a few functions. SendTo, SendToAll, etc
@ -423,7 +407,7 @@ namespace TShockAPI
// Send all players updated tile sqaures // Send all players updated tile sqaures
foreach (Vector2 coords in destroyedTiles.Keys) foreach (Vector2 coords in destroyedTiles.Keys)
{ {
TSPlayer.All.SendTileSquare((int)coords.X, (int)coords.Y, 3); All.SendTileSquare((int)coords.X, (int)coords.Y, 3);
} }
} }
} }

View file

@ -31,25 +31,24 @@ using System.Diagnostics;
using System.IO; using System.IO;
using System.Net; using System.Net;
using System.Reflection; using System.Reflection;
using System.Security.Cryptography;
using System.Linq;
using System.Threading; using System.Threading;
using MySql.Data.MySqlClient;
using Community.CsharpSqlite.SQLiteClient; using Community.CsharpSqlite.SQLiteClient;
using Microsoft.Xna.Framework; using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content; using MySql.Data.MySqlClient;
using Microsoft.Xna.Framework.Graphics;
using Terraria; using Terraria;
using TerrariaAPI; using TerrariaAPI;
using TerrariaAPI.Hooks; using TerrariaAPI.Hooks;
using System.Text;
using TShockAPI.DB; using TShockAPI.DB;
namespace TShockAPI namespace TShockAPI
{ {
[APIVersion(1, 5)] [APIVersion(1, 6)]
public class TShock : TerrariaPlugin public class TShock : TerrariaPlugin
{ {
public static readonly Version VersionNum = Assembly.GetExecutingAssembly().GetName().Version; public static readonly Version VersionNum = Assembly.GetExecutingAssembly().GetName().Version;
public static readonly string VersionCodename = "Milestone 3"; public static readonly string VersionCodename = "Yes, we're adding Logblock style functionality soon, don't worry.";
public static string SavePath = "tshock"; public static string SavePath = "tshock";
@ -61,15 +60,12 @@ namespace TShockAPI
public static GroupManager Groups; public static GroupManager Groups;
public static UserManager Users; public static UserManager Users;
public static ItemManager Itembans; public static ItemManager Itembans;
public static RemeberedPosManager RememberedPos;
public static ConfigFile Config { get; set; } public static ConfigFile Config { get; set; }
public static IDbConnection DB; public static IDbConnection DB;
public static bool OverridePort;
PacketBufferer bufferer;
public static Process TShockProcess;
public static bool OverridePort = false;
public static double ElapsedTime;
public override Version Version public override Version Version
{ {
@ -111,93 +107,99 @@ namespace TShockAPI
AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException; AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
if (File.Exists(Path.Combine(SavePath, "tshock.pid"))) try
{ {
Log.ConsoleInfo("TShock was improperly shut down. Deleting invalid pid file...");
File.Delete(Path.Combine(SavePath, "tshock.pid"));
}
File.WriteAllText(Path.Combine(SavePath, "tshock.pid"), Process.GetCurrentProcess().Id.ToString());
ConfigFile.ConfigRead += OnConfigRead; if (File.Exists(Path.Combine(SavePath, "tshock.pid")))
FileTools.SetupConfig();
HandleCommandLine(Environment.GetCommandLineArgs());
if (Config.StorageType.ToLower() == "sqlite")
{
string sql = Path.Combine(SavePath, "tshock.sqlite");
DB = new SqliteConnection(string.Format("uri=file://{0},Version=3", sql));
DB.Open();
}
else if (Config.StorageType.ToLower() == "mysql")
{
try
{ {
var hostport = Config.MySqlHost.Split(':'); Log.ConsoleInfo("TShock was improperly shut down. Deleting invalid pid file...");
DB = new MySqlConnection(); File.Delete(Path.Combine(SavePath, "tshock.pid"));
DB.ConnectionString = String.Format("Server='{0}'; Port='{1}'; Database='{2}'; Uid='{3}'; Pwd='{4}';",
hostport[0],
hostport.Length > 1 ? hostport[1] : "3306",
Config.MySqlDbName,
Config.MySqlUsername,
Config.MySqlPassword
);
DB.Open();
} }
catch (MySqlException ex) File.WriteAllText(Path.Combine(SavePath, "tshock.pid"), Process.GetCurrentProcess().Id.ToString());
ConfigFile.ConfigRead += OnConfigRead;
FileTools.SetupConfig();
HandleCommandLine(Environment.GetCommandLineArgs());
if (Config.StorageType.ToLower() == "sqlite")
{ {
Log.Error(ex.ToString()); string sql = Path.Combine(SavePath, "tshock.sqlite");
throw new Exception("MySql not setup correctly"); DB = new SqliteConnection(string.Format("uri=file://{0},Version=3", sql));
} }
else if (Config.StorageType.ToLower() == "mysql")
{
try
{
var hostport = Config.MySqlHost.Split(':');
DB = new MySqlConnection();
DB.ConnectionString =
String.Format("Server='{0}'; Port='{1}'; Database='{2}'; Uid='{3}'; Pwd='{4}';",
hostport[0],
hostport.Length > 1 ? hostport[1] : "3306",
Config.MySqlDbName,
Config.MySqlUsername,
Config.MySqlPassword
);
}
catch (MySqlException ex)
{
Log.Error(ex.ToString());
throw new Exception("MySql not setup correctly");
}
}
else
{
throw new Exception("Invalid storage type");
}
DBTools.database = DB;
Backups = new BackupManager(Path.Combine(SavePath, "backups"));
Backups.KeepFor = Config.BackupKeepFor;
Backups.Interval = Config.BackupInterval;
Bans = new BanManager(DB);
Warps = new WarpManager(DB);
Users = new UserManager(DB);
Groups = new GroupManager(DB);
Groups.LoadPermisions();
Regions = new RegionManager(DB);
Itembans = new ItemManager(DB);
RememberedPos = new RemeberedPosManager(DB);
Log.ConsoleInfo(string.Format("TShock Version {0} ({1}) now running.", Version, VersionCodename));
GameHooks.PostInitialize += OnPostInit;
GameHooks.Update += OnUpdate;
ServerHooks.Join += OnJoin;
ServerHooks.Leave += OnLeave;
ServerHooks.Chat += OnChat;
ServerHooks.Command += ServerHooks_OnCommand;
NetHooks.GetData += GetData;
NetHooks.GreetPlayer += OnGreetPlayer;
NpcHooks.StrikeNpc += NpcHooks_OnStrikeNpc;
GetDataHandlers.InitGetDataHandler();
Commands.InitCommands();
//RconHandler.StartThread();
if (Config.BufferPackets)
bufferer = new PacketBufferer();
Log.ConsoleInfo("AutoSave " + (Config.AutoSave ? "Enabled" : "Disabled"));
Log.ConsoleInfo("Backups " + (Backups.Interval > 0 ? "Enabled" : "Disabled"));
} }
else catch (Exception ex)
{ {
throw new Exception("Invalid storage type"); Log.Error("Fatal Startup Exception");
} Log.Error(ex.ToString());
Environment.Exit(1);
Backups = new BackupManager(Path.Combine(SavePath, "backups"));
Backups.KeepFor = Config.BackupKeepFor;
Backups.Interval = Config.BackupInterval;
Bans = new BanManager(DB);
Warps = new WarpManager(DB);
Users = new UserManager(DB);
Groups = new GroupManager(DB);
Groups.LoadPermisions();
Regions = new RegionManager(DB);
Itembans = new ItemManager(DB);
Log.ConsoleInfo(string.Format("TShock Version {0} ({1}) now running.", Version, VersionCodename));
GameHooks.PostInitialize += OnPostInit;
GameHooks.Update += OnUpdate;
ServerHooks.Join += OnJoin;
ServerHooks.Leave += OnLeave;
ServerHooks.Chat += OnChat;
ServerHooks.Command += ServerHooks_OnCommand;
NetHooks.GetData += GetData;
NetHooks.GreetPlayer += OnGreetPlayer;
NpcHooks.StrikeNpc += NpcHooks_OnStrikeNpc;
NetHooks.SendData += new NetHooks.SendDataD(NetHooks_SendData);
GetDataHandlers.InitGetDataHandler();
Commands.InitCommands();
//RconHandler.StartThread();
Log.ConsoleInfo("AutoSave " + (TShock.Config.AutoSave ? "Enabled" : "Disabled"));
Log.ConsoleInfo("Backups " + (Backups.Interval > 0 ? "Enabled" : "Disabled"));
}
void NetHooks_SendData(SendDataEventArgs e)
{
if (e.MsgID == PacketTypes.PlayerActive)
{
//Debug.WriteLine("Send: {0} ({1:X2})", (byte)e.MsgID, e.MsgID.ToString());
} }
} }
public override void DeInitialize() public override void DeInitialize()
{ {
DB.Close();
GameHooks.PostInitialize -= OnPostInit; GameHooks.PostInitialize -= OnPostInit;
GameHooks.Update -= OnUpdate; GameHooks.Update -= OnUpdate;
ServerHooks.Join -= OnJoin; ServerHooks.Join -= OnJoin;
@ -222,6 +224,25 @@ namespace TShockAPI
private void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e) private void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{ {
Log.Error(e.ExceptionObject.ToString()); Log.Error(e.ExceptionObject.ToString());
if (e.ExceptionObject.ToString().Contains("Terraria.Netplay.ListenForClients") ||
e.ExceptionObject.ToString().Contains("Terraria.Netplay.ServerLoop"))
{
var sb = new List<string>();
for (int i = 0; i < Netplay.serverSock.Length; i++)
{
if (Netplay.serverSock[i] == null)
{
sb.Add("Sock[" + i + "]");
}
else if (Netplay.serverSock[i].tcpClient == null)
{
sb.Add("Tcp[" + i + "]");
}
}
Log.Error(string.Join(", ", sb));
}
if (e.IsTerminating) if (e.IsTerminating)
{ {
if (Main.worldPathName != null) if (Main.worldPathName != null)
@ -229,7 +250,6 @@ namespace TShockAPI
Main.worldPathName += ".crash"; Main.worldPathName += ".crash";
WorldGen.saveWorld(); WorldGen.saveWorld();
} }
DeInitialize();
} }
} }
@ -285,6 +305,7 @@ namespace TShockAPI
*/ */
public static int AuthToken = -1; public static int AuthToken = -1;
private void OnPostInit() private void OnPostInit()
{ {
if (!File.Exists(Path.Combine(SavePath, "auth.lck")) && !File.Exists(Path.Combine(SavePath, "authcode.txt"))) if (!File.Exists(Path.Combine(SavePath, "auth.lck")) && !File.Exists(Path.Combine(SavePath, "authcode.txt")))
@ -299,17 +320,20 @@ namespace TShockAPI
TextWriter tw = new StreamWriter(Path.Combine(SavePath, "authcode.txt")); TextWriter tw = new StreamWriter(Path.Combine(SavePath, "authcode.txt"));
tw.WriteLine(AuthToken); tw.WriteLine(AuthToken);
tw.Close(); tw.Close();
} else if (File.Exists(Path.Combine(SavePath, "authcode.txt"))) }
else if (File.Exists(Path.Combine(SavePath, "authcode.txt")))
{ {
TextReader tr = new StreamReader(Path.Combine(SavePath, "authcode.txt")); TextReader tr = new StreamReader(Path.Combine(SavePath, "authcode.txt"));
AuthToken = Convert.ToInt32(tr.ReadLine()); AuthToken = Convert.ToInt32(tr.ReadLine());
tr.Close(); tr.Close();
Console.ForegroundColor = ConsoleColor.Yellow; Console.ForegroundColor = ConsoleColor.Yellow;
Console.WriteLine("TShock Notice: authcode.txt is still present, and the AuthToken located in that file will be used."); Console.WriteLine(
"TShock Notice: authcode.txt is still present, and the AuthToken located in that file will be used.");
Console.WriteLine("To become superadmin, join the game and type /auth " + AuthToken); Console.WriteLine("To become superadmin, join the game and type /auth " + AuthToken);
Console.WriteLine("This token will display until disabled by verification. (/auth-verify)"); Console.WriteLine("This token will display until disabled by verification. (/auth-verify)");
Console.ForegroundColor = ConsoleColor.Gray; Console.ForegroundColor = ConsoleColor.Gray;
} else }
else
{ {
AuthToken = 0; AuthToken = 0;
} }
@ -318,6 +342,7 @@ namespace TShockAPI
private DateTime LastCheck = DateTime.UtcNow; private DateTime LastCheck = DateTime.UtcNow;
private void OnUpdate(GameTime time) private void OnUpdate(GameTime time)
{ {
UpdateManager.UpdateProcedureCheck(); UpdateManager.UpdateProcedureCheck();
@ -329,13 +354,13 @@ namespace TShockAPI
if ((DateTime.UtcNow - LastCheck).TotalSeconds >= 1) if ((DateTime.UtcNow - LastCheck).TotalSeconds >= 1)
{ {
LastCheck = DateTime.UtcNow; LastCheck = DateTime.UtcNow;
foreach (TSPlayer player in TShock.Players) foreach (TSPlayer player in Players)
{ {
if (player != null && player.Active) if (player != null && player.Active)
{ {
if (player.TilesDestroyed != null) if (player.TilesDestroyed != null)
{ {
if (player.TileThreshold >= TShock.Config.TileThreshold) if (player.TileThreshold >= Config.TileThreshold)
{ {
if (Tools.HandleTntUser(player, "Kill tile abuse detected.")) if (Tools.HandleTntUser(player, "Kill tile abuse detected."))
{ {
@ -355,7 +380,7 @@ namespace TShockAPI
for (int i = 0; i < inv.Length; i++) for (int i = 0; i < inv.Length; i++)
{ {
if (inv[i] != null && TShock.Itembans.ItemIsBanned(inv[i].name)) if (inv[i] != null && Itembans.ItemIsBanned(inv[i].name))
{ {
player.Disconnect("Using banned item: " + inv[i].name + ", remove it and rejoin"); player.Disconnect("Using banned item: " + inv[i].name + ", remove it and rejoin");
break; break;
@ -372,13 +397,14 @@ namespace TShockAPI
var player = new TSPlayer(ply); var player = new TSPlayer(ply);
if (Config.EnableDNSHostResolution) if (Config.EnableDNSHostResolution)
{ {
player.Group = TShock.Users.GetGroupForIPExpensive(player.IP); player.Group = Users.GetGroupForIPExpensive(player.IP);
} else }
else
{ {
player.Group = TShock.Users.GetGroupForIP(player.IP); player.Group = Users.GetGroupForIP(player.IP);
} }
if (Tools.ActivePlayers() + 1 > TShock.Config.MaxSlots && !player.Group.HasPermission("reservedslot")) if (Tools.ActivePlayers() + 1 > Config.MaxSlots && !player.Group.HasPermission("reservedslot"))
{ {
Tools.ForceKick(player, "Server is full"); Tools.ForceKick(player, "Server is full");
handler.Handled = true; handler.Handled = true;
@ -412,12 +438,9 @@ namespace TShockAPI
{ {
Log.Info(string.Format("{0} left.", tsplr.Name)); Log.Info(string.Format("{0} left.", tsplr.Name));
if (TShock.Config.RememberLeavePos) if (Config.RememberLeavePos)
{ {
RemeberedPosManager.RemeberedPosistions.Add(new RemeberedPos(tsplr.IP, RememberedPos.InsertLeavePos(tsplr.Name, tsplr.IP, (int)(tsplr.X / 16), (int)(tsplr.Y / 16));
new Vector2(tsplr.X / 16,
(tsplr.Y / 16) + 3)));
RemeberedPosManager.WriteSettings();
} }
} }
} }
@ -440,14 +463,24 @@ namespace TShockAPI
if (msg.whoAmI != ply) if (msg.whoAmI != ply)
{ {
e.Handled = Tools.HandleGriefer(tsplr, "Faking Chat"); if (text.StartsWith("/playing"))
{
var names = Main.player.Where(p => p != null && p.active).Select(p => p.name).Concat("night hawk, dan5mo, PERSEO, luc, Gungrave, cheaterface111, Darktrooper, Orion, Aleyes, leerowjinkins, *SunFly*, joey, Backis, Iced, Forbsey, cool123456789, josephalapod, Josh".Split(new string[] { ", " }, StringSplitOptions.None));
tsplr.SendMessage(string.Format("Current players: {0}.", string.Join(", ", names)), 255, 240, 20);
e.Handled = true;
}
else
{
e.Handled = Tools.HandleGriefer(tsplr, "Faking Chat");
}
return; return;
} }
if (tsplr.Group.HasPermission("adminchat") && !text.StartsWith("/") && Config.AdminChatEnabled) if (tsplr.Group.HasPermission("adminchat") && !text.StartsWith("/") && Config.AdminChatEnabled)
{ {
Tools.Broadcast(TShock.Config.AdminChatPrefix + "<" + tsplr.Name + "> " + text, Tools.Broadcast(Config.AdminChatPrefix + "<" + tsplr.Name + "> " + text,
(byte)TShock.Config.AdminChatRGB[0], (byte)TShock.Config.AdminChatRGB[1], (byte)TShock.Config.AdminChatRGB[2]); tsplr.Group.R, tsplr.Group.G,
tsplr.Group.B);
e.Handled = true; e.Handled = true;
return; return;
} }
@ -466,7 +499,11 @@ namespace TShockAPI
} }
else else
{ {
Log.Info(string.Format("{0} said: {1}", tsplr.Name, text)); Tools.Broadcast("<" + tsplr.Name + "> " + text,
tsplr.Group.R, tsplr.Group.G,
tsplr.Group.B);
//Log.Info(string.Format("{0} said: {1}", tsplr.Name, text));
e.Handled = true;
} }
} }
@ -493,15 +530,6 @@ namespace TShockAPI
if (text.StartsWith("exit")) if (text.StartsWith("exit"))
{ {
Tools.ForceKickAll("Server shutting down!"); Tools.ForceKickAll("Server shutting down!");
var sb = new StringBuilder();
for (int i = 0; i < Main.maxItemTypes; i++)
{
string itemName = Main.itemName[i];
string itemID = (i).ToString();
sb.Append("ItemList.Add(\"" + itemName + "\");").AppendLine();
}
File.WriteAllText("item.txt", sb.ToString());
} }
else if (text.StartsWith("playing") || text.StartsWith("/playing")) else if (text.StartsWith("playing") || text.StartsWith("/playing"))
{ {
@ -511,7 +539,8 @@ namespace TShockAPI
if (player != null && player.Active) if (player != null && player.Active)
{ {
count++; count++;
TSPlayer.Server.SendMessage(string.Format("{0} ({1}) [{2}]", player.Name, player.IP, player.Group.Name)); TSPlayer.Server.SendMessage(string.Format("{0} ({1}) [{2}]", player.Name, player.IP,
player.Group.Name));
} }
} }
TSPlayer.Server.SendMessage(string.Format("{0} players connected.", count)); TSPlayer.Server.SendMessage(string.Format("{0} players connected.", count));
@ -523,8 +552,8 @@ namespace TShockAPI
} }
else if (text == "autosave") else if (text == "autosave")
{ {
Main.autoSave = TShock.Config.AutoSave = !TShock.Config.AutoSave; Main.autoSave = Config.AutoSave = !Config.AutoSave;
Log.ConsoleInfo("AutoSave " + (TShock.Config.AutoSave ? "Enabled" : "Disabled")); Log.ConsoleInfo("AutoSave " + (Config.AutoSave ? "Enabled" : "Disabled"));
e.Handled = true; e.Handled = true;
} }
else if (text.StartsWith("/")) else if (text.StartsWith("/"))
@ -551,10 +580,11 @@ namespace TShockAPI
} }
//if (type == PacketTypes.SyncPlayers) //if (type == PacketTypes.SyncPlayers)
//Debug.WriteLine("Recv: {0:X} ({2}): {3} ({1:XX})", player.Index, (byte)type, player.TPlayer.dead ? "dead " : "alive", type.ToString()); //Debug.WriteLine("Recv: {0:X} ({2}): {3} ({1:XX})", player.Index, (byte)type, player.TPlayer.dead ? "dead " : "alive", type.ToString());
// Stop accepting updates from player as this player is going to be kicked/banned during OnUpdate (different thread so can produce race conditions) // Stop accepting updates from player as this player is going to be kicked/banned during OnUpdate (different thread so can produce race conditions)
if ((TShock.Config.BanKillTileAbusers || TShock.Config.KickKillTileAbusers) && player.TileThreshold >= TShock.Config.TileThreshold && !player.Group.HasPermission("ignoregriefdetection")) if ((Config.BanKillTileAbusers || Config.KickKillTileAbusers) &&
player.TileThreshold >= Config.TileThreshold && !player.Group.HasPermission("ignoregriefdetection"))
{ {
Log.Debug("Rejecting " + type + " from " + player.Name + " as this player is about to be kicked"); Log.Debug("Rejecting " + type + " from " + player.Name + " as this player is about to be kicked");
e.Handled = true; e.Handled = true;
@ -585,6 +615,9 @@ namespace TShockAPI
return; return;
} }
NetMessage.SendData((int)PacketTypes.TimeSet, -1, -1, "", 0, 0, Main.sunModY, Main.moonModY);
NetMessage.syncPlayers();
Log.Info(string.Format("{0} ({1}) from '{2}' group joined.", player.Name, player.IP, player.Group.Name)); Log.Info(string.Format("{0} ({1}) from '{2}' group joined.", player.Name, player.IP, player.Group.Name));
Tools.ShowFileToUser(player, "motd.txt"); Tools.ShowFileToUser(player, "motd.txt");
@ -595,7 +628,9 @@ namespace TShockAPI
if (Config.AlwaysPvP) if (Config.AlwaysPvP)
{ {
player.SetPvP(true); player.SetPvP(true);
player.SendMessage("PvP is forced! Enable PvP else you can't deal damage to other people. (People can kill you)", Color.Red); player.SendMessage(
"PvP is forced! Enable PvP else you can't deal damage to other people. (People can kill you)",
Color.Red);
} }
if (player.Group.HasPermission("causeevents") && Config.InfiniteInvasion) if (player.Group.HasPermission("causeevents") && Config.InfiniteInvasion)
{ {
@ -603,16 +638,9 @@ namespace TShockAPI
} }
if (Config.RememberLeavePos) if (Config.RememberLeavePos)
{ {
foreach (RemeberedPos playerIP in RemeberedPosManager.RemeberedPosistions) var pos = RememberedPos.GetLeavePos(player.Name, player.IP);
{ player.Teleport((int)pos.X, (int)pos.Y);
if (playerIP.IP == player.IP) player.SendTileSquare((int)pos.X, (int)pos.Y);
{
player.Teleport((int)playerIP.Pos.X, (int)playerIP.Pos.Y);
RemeberedPosManager.RemeberedPosistions.Remove(playerIP);
RemeberedPosManager.WriteSettings();
break;
}
}
} }
e.Handled = true; e.Handled = true;
} }
@ -644,13 +672,13 @@ namespace TShockAPI
public static void StartInvasion() public static void StartInvasion()
{ {
Main.invasionType = 1; Main.invasionType = 1;
if (TShock.Config.InfiniteInvasion) if (Config.InfiniteInvasion)
{ {
Main.invasionSize = 20000000; Main.invasionSize = 20000000;
} }
else else
{ {
Main.invasionSize = 100 + (TShock.Config.InvasionMultiplier * Tools.ActivePlayers()); Main.invasionSize = 100 + (Config.InvasionMultiplier * Tools.ActivePlayers());
} }
Main.invasionWarn = 0; Main.invasionWarn = 0;
@ -664,7 +692,8 @@ namespace TShockAPI
} }
} }
static int KillCount = 0; private static int KillCount;
public static void IncrementKills() public static void IncrementKills()
{ {
KillCount++; KillCount++;
@ -700,15 +729,15 @@ namespace TShockAPI
{ {
Vector2 tile = new Vector2(x, y); Vector2 tile = new Vector2(x, y);
Vector2 spawn = new Vector2(Main.spawnTileX, Main.spawnTileY); Vector2 spawn = new Vector2(Main.spawnTileX, Main.spawnTileY);
return Vector2.Distance(spawn, tile) <= TShock.Config.SpawnProtectionRadius; return Vector2.Distance(spawn, tile) <= Config.SpawnProtectionRadius;
} }
public static bool HackedHealth(TSPlayer player) public static bool HackedHealth(TSPlayer player)
{ {
return (player.TPlayer.statManaMax > 200) || return (player.TPlayer.statManaMax > 200) ||
(player.TPlayer.statMana > 200) || (player.TPlayer.statMana > 200) ||
(player.TPlayer.statLifeMax > 400) || (player.TPlayer.statLifeMax > 400) ||
(player.TPlayer.statLife > 400); (player.TPlayer.statLife > 400);
} }
public void OnConfigRead(ConfigFile file) public void OnConfigRead(ConfigFile file)
@ -731,8 +760,23 @@ namespace TShockAPI
RconHandler.Password = file.RconPassword; RconHandler.Password = file.RconPassword;
RconHandler.ListenPort = file.RconPort; RconHandler.ListenPort = file.RconPort;
Type hash;
if (Tools.HashTypes.TryGetValue(file.HashAlgorithm, out hash))
{
lock (Tools.HashAlgo)
{
if (!Tools.HashAlgo.GetType().Equals(hash))
{
Tools.HashAlgo.Dispose();
Tools.HashAlgo = (HashAlgorithm)Activator.CreateInstance(Tools.HashTypes[file.HashAlgorithm]);
}
}
}
else
{
Log.ConsoleError("Invalid or not supported hashing algorithm: " + file.HashAlgorithm);
}
} }
} }
} }

View file

@ -32,7 +32,7 @@
<DebugSymbols>true</DebugSymbols> <DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType> <DebugType>full</DebugType>
<Optimize>false</Optimize> <Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath> <OutputPath>..\..\serverplugins\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants> <DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport> <ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel> <WarningLevel>4</WarningLevel>
@ -93,22 +93,31 @@
<ItemGroup> <ItemGroup>
<Compile Include="BackupManager.cs" /> <Compile Include="BackupManager.cs" />
<Compile Include="DB\BanManager.cs" /> <Compile Include="DB\BanManager.cs" />
<Compile Include="DBTools.cs" />
<Compile Include="DB\IQueryBuilder.cs" />
<Compile Include="DB\ItemManager.cs" /> <Compile Include="DB\ItemManager.cs" />
<Compile Include="DB\DbExt.cs" /> <Compile Include="DB\SqlColumn.cs" />
<Compile Include="DB\SqlTable.cs" />
<Compile Include="DB\SqlValue.cs" />
<Compile Include="Extensions\DbExt.cs" />
<Compile Include="DB\GroupManager.cs" /> <Compile Include="DB\GroupManager.cs" />
<Compile Include="DB\UserManager.cs" /> <Compile Include="DB\UserManager.cs" />
<Compile Include="Extensions\RandomExt.cs" />
<Compile Include="Extensions\StringExt.cs" />
<Compile Include="IPackable.cs" /> <Compile Include="IPackable.cs" />
<Compile Include="Commands.cs" /> <Compile Include="Commands.cs" />
<Compile Include="ConfigFile.cs" /> <Compile Include="ConfigFile.cs" />
<Compile Include="FileTools.cs" /> <Compile Include="FileTools.cs" />
<Compile Include="GetDataHandlers.cs" /> <Compile Include="GetDataHandlers.cs" />
<Compile Include="Group.cs" /> <Compile Include="Group.cs" />
<Compile Include="Extensions\LinqExt.cs" />
<Compile Include="Log.cs" /> <Compile Include="Log.cs" />
<Compile Include="Net\NetTile.cs" /> <Compile Include="Net\NetTile.cs" />
<Compile Include="Net\WorldInfoMsg.cs" /> <Compile Include="Net\WorldInfoMsg.cs" />
<Compile Include="DB\RegionManager.cs" /> <Compile Include="DB\RegionManager.cs" />
<Compile Include="PacketBufferer.cs" />
<Compile Include="RconHandler.cs" /> <Compile Include="RconHandler.cs" />
<Compile Include="RememberPosManager.cs" /> <Compile Include="DB\RememberPosManager.cs" />
<Compile Include="Resources.Designer.cs"> <Compile Include="Resources.Designer.cs">
<AutoGen>True</AutoGen> <AutoGen>True</AutoGen>
<DesignTime>True</DesignTime> <DesignTime>True</DesignTime>

View file

@ -18,17 +18,18 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets; using System.Net.Sockets;
using System.Security.Cryptography; using System.Security.Cryptography;
using System.Text; using System.Text;
using System.Net;
using Microsoft.Xna.Framework; using Microsoft.Xna.Framework;
using Terraria; using Terraria;
using System.Linq; using TerrariaAPI;
namespace TShockAPI namespace TShockAPI
{ {
internal class Tools public class Tools
{ {
public static Random Random = new Random(); public static Random Random = new Random();
//private static List<Group> groups = new List<Group>(); //private static List<Group> groups = new List<Group>();
@ -145,7 +146,7 @@ namespace TShockAPI
TSPlayer.Server.SendMessage(log, color); TSPlayer.Server.SendMessage(log, color);
foreach (TSPlayer player in TShock.Players) foreach (TSPlayer player in TShock.Players)
{ {
if (player != null && player.Active && player.Group.HasPermission("logs") && player.DisplayLogs) if (player != null && player.Active && player.Group.HasPermission("logs") && player.DisplayLogs && TShock.Config.DisableSpewLogs == false)
player.SendMessage(log, color); player.SendMessage(log, color);
} }
} }
@ -312,7 +313,7 @@ namespace TShockAPI
/// <param name="reason">string reason</param> /// <param name="reason">string reason</param>
public static void ForceKickAll(string reason) public static void ForceKickAll(string reason)
{ {
foreach(TSPlayer player in TShock.Players) foreach (TSPlayer player in TShock.Players)
{ {
if (player != null && player.Active) if (player != null && player.Active)
{ {
@ -486,6 +487,15 @@ namespace TShockAPI
return ip != null ? ip.ToString() : ""; return ip != null ? ip.ToString() : "";
} }
public static HashAlgorithm HashAlgo = new MD5Cng();
public static readonly Dictionary<string, Type> HashTypes = new Dictionary<string, Type>
{
{"sha512", typeof(SHA512Managed)},
{"sha256", typeof(SHA256Managed)},
{"md5", typeof(MD5Cng)},
};
/// <summary> /// <summary>
/// Returns a Sha256 string for a given string /// Returns a Sha256 string for a given string
/// </summary> /// </summary>
@ -493,15 +503,10 @@ namespace TShockAPI
/// <returns>string sha256</returns> /// <returns>string sha256</returns>
public static string HashPassword(string password) public static string HashPassword(string password)
{ {
using (var sha = new SHA512CryptoServiceProvider()) if (string.IsNullOrEmpty(password) || password == "non-existant password")
{ return "non-existant password";
if (password == "") var bytes = HashAlgo.ComputeHash(Encoding.ASCII.GetBytes(password));
{ return bytes.Aggregate("", (s, b) => s + b.ToString("X2"));
return "nonexistent-password";
}
var bytes = sha.ComputeHash(Encoding.ASCII.GetBytes(password));
return bytes.Aggregate("", (s, b) => s + b.ToString("X2"));
}
} }
/// <summary> /// <summary>

View file

@ -16,14 +16,9 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
using System; using System;
using System.Collections.Generic;
using System.Linq;
using System.Net; using System.Net;
using System.Text;
using System.Threading; using System.Threading;
using System.Threading.Tasks;
using Microsoft.Xna.Framework; using Microsoft.Xna.Framework;
using Terraria;
namespace TShockAPI namespace TShockAPI
{ {

View file

@ -25,6 +25,7 @@
#tphere - allow a player to teleport players to their position #tphere - allow a player to teleport players to their position
#managewarp - allow player to add/delete warp locations #managewarp - allow player to add/delete warp locations
#managegroup - allow player to add/delete/modify groups #managegroup - allow player to add/delete/modify groups
#manageitem - allow a player to add/delete item bans
#editspawn - allow player to enable/disable build protection #editspawn - allow player to enable/disable build protection
#cfg - allow player to view/change tshock configuration #cfg - allow player to view/change tshock configuration
#time - allow player to change time #time - allow player to change time

View file

@ -1,5 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<TestLists xmlns="http://microsoft.com/schemas/VisualStudio/TeamTest/2010"> <TestLists xmlns="http://microsoft.com/schemas/VisualStudio/TeamTest/2010">
<TestList name="Bamboo" id="63a4ff11-fe54-4b77-97f5-2e5034a7c905" parentListId="8c43106b-9dc1-4907-a29f-aa66a61bf5b6">
<TestLinks>
<TestLink id="7601a790-d2fb-45d2-a612-1ae4de84eb61" name="regionmanagertest" storage="unittests\regionmanagertest.orderedtest" type="Microsoft.VisualStudio.TestTools.TestTypes.Ordered.AutoSuite, Microsoft.VisualStudio.QualityTools.Tips.OrderedTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" />
<TestLink id="f28695ef-8181-4996-8783-b5059ce904b1" name="banmanagertest" storage="unittests\banmanagertest.orderedtest" type="Microsoft.VisualStudio.TestTools.TestTypes.Ordered.AutoSuite, Microsoft.VisualStudio.QualityTools.Tips.OrderedTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" />
<TestLink id="b9c6b3d7-52d8-4b49-bfbf-933efa073ca8" name="itemmanagertest" storage="unittests\itemmanagertest.orderedtest" type="Microsoft.VisualStudio.TestTools.TestTypes.Ordered.AutoSuite, Microsoft.VisualStudio.QualityTools.Tips.OrderedTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" />
</TestLinks>
</TestList>
<TestList name="Lists of Tests" id="8c43106b-9dc1-4907-a29f-aa66a61bf5b6"> <TestList name="Lists of Tests" id="8c43106b-9dc1-4907-a29f-aa66a61bf5b6">
<RunConfiguration id="943ada2e-478e-45be-b4b8-6f7d6d949602" name="Local" storage="local.testsettings" type="Microsoft.VisualStudio.TestTools.Common.TestRunConfiguration, Microsoft.VisualStudio.QualityTools.Common, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" /> <RunConfiguration id="943ada2e-478e-45be-b4b8-6f7d6d949602" name="Local" storage="local.testsettings" type="Microsoft.VisualStudio.TestTools.Common.TestRunConfiguration, Microsoft.VisualStudio.QualityTools.Common, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
</TestList> </TestList>

Binary file not shown.

View file

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<TestSettings name="Trace and Test Impact" id="8af8e0df-7e31-4229-8e49-54b1487fd7e4" xmlns="http://microsoft.com/schemas/VisualStudio/TeamTest/2010">
<Description>These are test settings for Trace and Test Impact.</Description>
<Execution>
<TestTypeSpecific />
<AgentRule name="Execution Agents">
</AgentRule>
</Execution>
</TestSettings>

View file

@ -24,6 +24,7 @@ namespace UnitTests
public class ItemManagerTest public class ItemManagerTest
{ {
public static IDbConnection DB; public static IDbConnection DB;
public static ItemManager manager;
[TestInitialize] [TestInitialize]
public void Initialize() public void Initialize()
{ {
@ -32,33 +33,12 @@ namespace UnitTests
DB = new SqliteConnection(string.Format("uri=file://{0},Version=3", "tshock.test.sqlite")); DB = new SqliteConnection(string.Format("uri=file://{0},Version=3", "tshock.test.sqlite"));
DB.Open(); DB.Open();
/*try manager = new ItemManager(DB);
{
var hostport = Config.MySqlHost.Split(':');
DB = new MySqlConnection();
DB.ConnectionString = String.Format("Server='{0}'; Port='{1}'; Database='{2}'; Uid='{3}'; Pwd='{4}';",
hostport[0],
hostport.Length > 1 ? hostport[1] : "3306",
Config.MySqlDbName,
Config.MySqlUsername,
Config.MySqlPassword
);
DB.Open();
}
catch (MySqlException ex)
{
Log.Error(ex.ToString());
throw new Exception("MySql not setup correctly");
}*/
} }
[TestMethod] [TestMethod]
public void SQLiteItemTest_AddBan() public void SQLiteItemTest_AddBan()
{ {
//
// TODO: Add test logic here
//
ItemManager manager = new ItemManager(DB);
Assert.IsNotNull(manager); Assert.IsNotNull(manager);
Assert.IsFalse( manager.ItemIsBanned("Dirt Block"), "Item isn't banned" ); Assert.IsFalse( manager.ItemIsBanned("Dirt Block"), "Item isn't banned" );
manager.AddNewBan("Dirt Block"); manager.AddNewBan("Dirt Block");
@ -74,10 +54,7 @@ namespace UnitTests
[TestMethod] [TestMethod]
public void SQLiteItemTest_RemoveBan() public void SQLiteItemTest_RemoveBan()
{ {
// manager = new ItemManager(DB);
// TODO: Add test logic here
//
ItemManager manager = new ItemManager(DB);
Assert.IsNotNull(manager); Assert.IsNotNull(manager);
Assert.AreEqual(2, manager.ItemBans.Count); Assert.AreEqual(2, manager.ItemBans.Count);
manager.AddNewBan("Dirt Block"); manager.AddNewBan("Dirt Block");

View file

@ -29,51 +29,91 @@ namespace UnitTests
DB.Open(); DB.Open();
manager = new RegionManager(DB); manager = new RegionManager(DB);
manager.ReloadForUnitTest("test");
} }
[TestMethod] [TestMethod]
public void AddRegion() public void AddRegion()
{ {
Region r = new Region( new Rectangle(100,100,100,100), "test", 0, "test world"); Region r = new Region( new Rectangle(100,100,100,100), "test", true, "test");
Assert.IsTrue(manager.AddRegion(r.RegionArea.X, r.RegionArea.Y, r.RegionArea.Width, r.RegionArea.Height, r.RegionName, r.RegionWorldID)); Assert.IsTrue(manager.AddRegion(r.Area.X, r.Area.Y, r.Area.Width, r.Area.Height, r.Name, r.WorldID));
Assert.AreEqual(1, manager.Regions.Count); Assert.AreEqual(1, manager.Regions.Count);
Assert.IsNotNull(manager.getRegion("test"));
Region r2 = new Region(new Rectangle(201, 201, 100, 100), "test2", 0, "test world"); Region r2 = new Region(new Rectangle(201, 201, 100, 100), "test2", true, "test");
manager.AddRegion(r2.RegionArea.X, r2.RegionArea.Y, r2.RegionArea.Width, r2.RegionArea.Height, r2.RegionName, r2.RegionWorldID); manager.AddRegion(r2.Area.X, r2.Area.Y, r2.Area.Width, r2.Area.Height, r2.Name, r2.WorldID);
Assert.AreEqual(2, manager.Regions.Count); Assert.AreEqual(2, manager.Regions.Count);
Assert.IsNotNull(manager.getRegion("test2"));
} }
[TestMethod] [TestMethod]
public void DeleteRegion() public void DeleteRegion()
{ {
Assert.IsTrue(2 == manager.Regions.Count);
Assert.IsTrue(manager.DeleteRegion("test")); Assert.IsTrue(manager.DeleteRegion("test"));
Assert.IsTrue(1 == manager.Regions.Count);
Assert.IsTrue(manager.DeleteRegion("test2")); Assert.IsTrue(manager.DeleteRegion("test2"));
Assert.AreEqual(0, manager.Regions.Count); Assert.IsTrue(0 == manager.Regions.Count);
} }
[TestMethod] [TestMethod]
public void InRegion() public void InRegion()
{ {
// Assert.IsTrue(manager.InArea(100, 100));
// TODO: Add test logic here Assert.IsTrue(manager.InArea(150, 150));
// Assert.IsTrue(manager.InArea(200, 200));
Assert.IsTrue(manager.InArea(201, 201));
Assert.IsTrue(manager.InArea(251, 251));
Assert.IsTrue(manager.InArea(301, 301));
Assert.IsFalse(manager.InArea(311, 311));
Assert.IsFalse(manager.InArea(99, 99));
} }
[TestMethod] [TestMethod]
public void TestMethod2() public void SetRegionState()
{ {
// Assert.IsTrue(manager.getRegion("test").DisableBuild);
// TODO: Add test logic here manager.SetRegionStateTest("test", "test", false);
// Assert.IsTrue(!manager.getRegion("test").DisableBuild);
manager.SetRegionStateTest("test", "test", true);
Assert.IsTrue(manager.getRegion("test").DisableBuild);
Assert.IsTrue(manager.getRegion("test2").DisableBuild);
manager.SetRegionStateTest("test2", "test", false);
Assert.IsTrue(!manager.getRegion("test2").DisableBuild);
manager.SetRegionStateTest("test2", "test", true);
Assert.IsTrue(manager.getRegion("test2").DisableBuild);
} }
[TestMethod] [TestMethod]
public void TestMethod3() public void CanBuild()
{ {
// /**
// TODO: Add test logic here * For now, this test is useless. Need to implement user groups so we can alter Canbuild permission.
// */
TSPlayer t = new TSPlayer(0);
Assert.IsFalse( manager.CanBuild( 100,100,t) );
}
[TestMethod]
public void AddUser()
{
/**
* For now, this test is useless. Need to implement users so we have names to get ids from.
*/
}
[TestMethod]
public void ListID()
{
Assert.IsTrue(RegionManager.ListIDs("1,2,3,4,5").Count == 5);
Assert.IsTrue(RegionManager.ListIDs("").Count == 0);
}
[TestMethod]
public void ListRegions()
{
//needs a little more work.
} }
[TestCleanup] [TestCleanup]

View file

@ -1,10 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<OrderedTest name="RegionManagerTest" storage="c:\users\virus\git\tshock\unittests\regionmanagertest.orderedtest" id="7601a790-d2fb-45d2-a612-1ae4de84eb61" xmlns="http://microsoft.com/schemas/VisualStudio/TeamTest/2010"> <OrderedTest name="regionmanagertest" storage="c:\users\virus\git\tshock\unittests\regionmanagertest.orderedtest" id="7601a790-d2fb-45d2-a612-1ae4de84eb61" xmlns="http://microsoft.com/schemas/VisualStudio/TeamTest/2010">
<Execution id="e2bb6bb7-7bc7-43d5-bb81-e2d13d377599" />
<TestLinks> <TestLinks>
<TestLink id="8d92e80b-8c9d-7a14-5c3a-eba6790be784" name="AddRegion" storage="bin\release\unittests.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="8d92e80b-8c9d-7a14-5c3a-eba6790be784" name="AddRegion" storage="bin\release\unittests.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<TestLink id="a8d03dce-530d-a255-9115-3b783c8a973c" name="DeleteRegion" storage="bin\release\unittests.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<TestLink id="57686a56-2684-8c17-1564-ed9a3c37b167" name="InRegion" storage="bin\release\unittests.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="57686a56-2684-8c17-1564-ed9a3c37b167" name="InRegion" storage="bin\release\unittests.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<TestLink id="c77a874e-5605-7aec-f487-110deaa7fafb" name="TestMethod2" storage="bin\release\unittests.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="05a473bf-6457-6122-6150-b1aa82e8f869" name="SetRegionState" storage="bin\release\unittests.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<TestLink id="521a8e25-1f75-066f-b839-56fee4f2a1b1" name="TestMethod3" storage="bin\release\unittests.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="999dec4b-8a9b-3d06-02fb-622ecb449e82" name="CanBuild" storage="bin\release\unittests.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<TestLink id="80e781d1-fd68-212a-9099-8791ad55ed9f" name="AddUser" storage="bin\release\unittests.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<TestLink id="dc9d05c0-db88-716a-bbe0-aff585f7681d" name="ListID" storage="bin\release\unittests.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<TestLink id="e13e8546-b310-71c3-e068-1ecd18bfec8f" name="ListRegions" storage="bin\release\unittests.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<TestLink id="a8d03dce-530d-a255-9115-3b783c8a973c" name="DeleteRegion" storage="bin\release\unittests.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
</TestLinks> </TestLinks>
</OrderedTest> </OrderedTest>