Merge remote branch 'upstream/general-devel' into general-devel

This commit is contained in:
k0rd 2013-09-21 16:41:25 -04:00
commit d36a549e1e
82 changed files with 4844 additions and 5602 deletions

9
.editorconfig Normal file
View file

@ -0,0 +1,9 @@
root = true
[*]
end_of_line = crlf
insert_final_newline = true
[*.cs]
indent_style = tab
trim_trailing_whitespace = true

5
.gitattributes vendored Normal file
View file

@ -0,0 +1,5 @@
* text=auto
*.cs text eol=crlf
*.sln text eol=crlf
*.csproj text eol=crlf
*.vsmdi text eol=crlf

9
.travis.yml Normal file
View file

@ -0,0 +1,9 @@
language: c
install:
- sudo apt-get install mono-devel mono-gmcs nunit-console
script:
- xbuild ./TShockAPI/TShockAPI.csproj
notifications:
irc: irc.rizon.net#tshock
hipchat:
secure: hpRLWiHF2j6O2qJOVs++aqAmryN6G5kY0SF26/rKCpQ7klhMlDZIgI1V1dbkKqlculFtW1neS0EBJyV9lmcV5b26H+KhlZYGN0j7q1VcOTM3rvtU6wW0Ap22uRLl2RrnA4kEsgDAsNouPOkyLZ19hlHAISlsId6G4+Rfqg6k+zQ=

36
CONTRIBUTING Normal file
View file

@ -0,0 +1,36 @@
### Issue Guidelines
Please follow these simple requirements before posting an issue:
1. TShock version number
2. Any stack traces that may have happened when the issue occurred
3. How to reproduce the issue
### Pull Request Dev Guidelines
These guidelines are for contributors. If you do not follow these guidelines your commits will be reverted.
Required:
- Follow the code style. We generally use microsofts except for m_ infront of private variables.
- Do not push unfinished features to the master branch, instead create a remote branch and push to that.
- Do not push untested code to the master branch, instead push to the test branch.
- Document all compatibility issues in the COMPATIBILITY file. (IE file formats changing)
- DO NOT MASS COMMIT. Commit changes as you go (without pushing). That way when you push we don't get a thousand changes with a 1-3 line commit message.
Optional:
- Build Version Increment (http://autobuildversion.codeplex.com/).
----
### Dev Team Guidelines
These guidelines are to be followed by all developers with commit level access to this repository:
- Do not, for any reason, submit code to the master branch before it hits the development branch first. If the development branch is far ahead, and a new bug fix is going out, branch master, then merge with master and remove your branch.
- If you are found to do this, you will be the person merging and rebasing your code to fit general-devel.
- Prior to posting any version on the website, you must tick the version in AssemblyInfo.cs. This is the versioning formula:
- Major.Minor.Revision.BuildDate (tick Revision if you're fixing prior to an actual planned release)
- Do not release any development builds on the forums without consulting another developer first.
- __Document code prior to marking it done in JIRA__
- Move any un-tested code to the "Needs Validation" section on JIRA prior to marking it as done.
- Do not push changes to any branch without a proper issue being assigned in JIRA. If a feature isn't planned for this release, __it shouldn't be in the repo about to be released__.
- Submit all pull requests to the general-devel branch prior to the master branch, or you will be ignored.

36
CONTRIBUTING.md Normal file
View file

@ -0,0 +1,36 @@
### Issue Guidelines
Please follow these simple requirements before posting an issue:
1. TShock version number
2. Any stack traces that may have happened when the issue occurred
3. How to reproduce the issue
### Pull Request Dev Guidelines
These guidelines are for contributors. If you do not follow these guidelines your commits will be reverted.
Required:
- Follow the code style. We generally use microsofts except for m_ infront of private variables.
- Do not push unfinished features to the master branch, instead create a remote branch and push to that.
- Do not push untested code to the master branch, instead push to the test branch.
- Document all compatibility issues in the COMPATIBILITY file. (IE file formats changing)
- DO NOT MASS COMMIT. Commit changes as you go (without pushing). That way when you push we don't get a thousand changes with a 1-3 line commit message.
Optional:
- Build Version Increment (http://autobuildversion.codeplex.com/).
----
### Dev Team Guidelines
These guidelines are to be followed by all developers with commit level access to this repository:
- Do not, for any reason, submit code to the master branch before it hits the development branch first. If the development branch is far ahead, and a new bug fix is going out, branch master, then merge with master and remove your branch.
- If you are found to do this, you will be the person merging and rebasing your code to fit general-devel.
- Prior to posting any version on the website, you must tick the version in AssemblyInfo.cs. This is the versioning formula:
- Major.Minor.Revision.BuildDate (tick Revision if you're fixing prior to an actual planned release)
- Do not release any development builds on the forums without consulting another developer first.
- __Document code prior to marking it done in JIRA__
- Move any un-tested code to the "Needs Validation" section on JIRA prior to marking it as done.
- Do not push changes to any branch without a proper issue being assigned in JIRA. If a feature isn't planned for this release, __it shouldn't be in the repo about to be released__.
- Submit all pull requests to the general-devel branch prior to the master branch, or you will be ignored.

55
DBEditor/.gitignore vendored
View file

@ -1,55 +0,0 @@
# Compiled source #
###################
*.com
*.class
*.dll
*.exe
*.o
*.so
*/bin/*
*/obj/*
bin/*
obj/*
# Packages #
############
# it's better to unpack these files and commit the raw source
# git has its own built in compression methods
*.7z
*.dmg
*.gz
*.iso
*.jar
*.rar
*.tar
*.zip
# Logs and databases #
######################
*.log
*.sql
*.sqlite
# OS generated files #
######################
.DS_Store?
ehthumbs.db
Icon?
Thumbs.db
# Visual Studio shit Motherfucka #
##################################
*.suo
*.sdf
*.opensdf
*.cache
*.pdb
*.csproj.user
*/_ReSharper*/*
*.user
#Template Bat file#
###################
myass.bat

View file

@ -1,78 +0,0 @@
/*
TShock, a server mod for Terraria
Copyright (C) 2011-2012 The TShock Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace TShockDBEditor
{
public class TShockCommandsList
{
public static void AddRemainingTShockCommands()
{
List<string> CommandList = new List<string>();
CommandList.Add("reservedslot");
CommandList.Add("canwater");
CommandList.Add("canlava");
CommandList.Add("canbuild");
CommandList.Add("adminchat");
CommandList.Add("warp");
CommandList.Add("kick");
CommandList.Add("ban");
CommandList.Add("unban");
CommandList.Add("whitelist");
CommandList.Add("maintenance");
CommandList.Add("causeevents");
CommandList.Add("spawnboss");
CommandList.Add("spawnmob");
CommandList.Add("tp");
CommandList.Add("tphere");
CommandList.Add("managewarp");
CommandList.Add("editspawn");
CommandList.Add("cfg");
CommandList.Add("time");
CommandList.Add("pvpfun");
CommandList.Add("logs");
CommandList.Add("kill");
CommandList.Add("butcher");
CommandList.Add("item");
CommandList.Add("clearitems");
CommandList.Add("heal");
CommandList.Add("whisper");
CommandList.Add("annoy");
CommandList.Add("immunetokick");
CommandList.Add("immunetoban");
CommandList.Add("usebanneditem");
CommandList.Add("canregister");
CommandList.Add("canlogin");
CommandList.Add("canchangepassword");
CommandList.Add("canpartychat");
CommandList.Add("cantalkinthird");
CommandList.Add("candisplayplaying");
foreach (string command in CommandList)
{
if (!TShockDBEditor.CommandList.Contains(command))
TShockDBEditor.CommandList.Add(command);
}
}
}
}

View file

@ -1,63 +0,0 @@
/*
TShock, a server mod for Terraria
Copyright (C) 2011-2012 The TShock Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
namespace TShockDBEditor
{
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,41 +0,0 @@
/*
TShock, a server mod for Terraria
Copyright (C) 2011-2012 The TShock Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
using System;
using System.Collections.Generic;
namespace TShockDBEditor
{
public class Group
{
public readonly List<string> permissions = new List<string>();
private readonly List<string> negatedpermissions = new List<string>();
public int ID { get; protected set; }
public string Name { get; set; }
public Group Parent { get; set; }
public int Order { get; set; }
public Group(int id, string groupname, int order, Group parentgroup = null)
{
Order = order;
ID = id;
Name = groupname;
Parent = parentgroup;
}
}
}

View file

@ -1,359 +0,0 @@
/*
TShock, a server mod for Terraria
Copyright (C) 2011-2012 The TShock Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace TShockDBEditor
{
public class Itemlist
{
public static List<string> ItemList = new List<string>();
public static void AddItems()
{
ItemList.Add("Iron Pickaxe");
ItemList.Add("Dirt Block");
ItemList.Add("Stone Block");
ItemList.Add("Iron Broadsword");
ItemList.Add("Mushroom");
ItemList.Add("Iron Shortsword");
ItemList.Add("Iron Hammer");
ItemList.Add("Torch");
ItemList.Add("Wood");
ItemList.Add("Iron Axe");
ItemList.Add("Iron Ore");
ItemList.Add("Copper Ore");
ItemList.Add("Gold Ore");
ItemList.Add("Silver Ore");
ItemList.Add("Copper Watch");
ItemList.Add("Silver Watch");
ItemList.Add("Gold Watch");
ItemList.Add("Depth Meter");
ItemList.Add("Gold Bar");
ItemList.Add("Copper Bar");
ItemList.Add("Silver Bar");
ItemList.Add("Iron Bar");
ItemList.Add("Gel");
ItemList.Add("Wooden Sword");
ItemList.Add("Wooden Door");
ItemList.Add("Stone Wall");
ItemList.Add("Acorn");
ItemList.Add("Lesser Healing Potion");
ItemList.Add("Life Crystal");
ItemList.Add("Dirt Wall");
ItemList.Add("Bottle");
ItemList.Add("Wooden Table");
ItemList.Add("Furnace");
ItemList.Add("Wooden Chair");
ItemList.Add("Iron Anvil");
ItemList.Add("Work Bench");
ItemList.Add("Goggles");
ItemList.Add("Lens");
ItemList.Add("Wooden Bow");
ItemList.Add("Wooden Arrow");
ItemList.Add("Flaming Arrow");
ItemList.Add("Shuriken");
ItemList.Add("Suspicious Looking Eye");
ItemList.Add("Demon Bow");
ItemList.Add("War Axe of the Night");
ItemList.Add("Light's Bane");
ItemList.Add("Unholy Arrow");
ItemList.Add("Chest");
ItemList.Add("Band of Regeneration");
ItemList.Add("Magic Mirror");
ItemList.Add("Jester's Arrow");
ItemList.Add("Angel Statue");
ItemList.Add("Cloud in a Bottle");
ItemList.Add("Hermes Boots");
ItemList.Add("Enchanted Boomerang");
ItemList.Add("Demonite Ore");
ItemList.Add("Demonite Bar");
ItemList.Add("Heart");
ItemList.Add("Corrupt Seeds");
ItemList.Add("Vile Mushroom");
ItemList.Add("Ebonstone Block");
ItemList.Add("Grass Seeds");
ItemList.Add("Sunflower");
ItemList.Add("Vilethorn");
ItemList.Add("Starfury");
ItemList.Add("Purification Powder");
ItemList.Add("Vile Powder");
ItemList.Add("Rotten Chunk");
ItemList.Add("Worm Tooth");
ItemList.Add("Worm Food");
ItemList.Add("Copper Coin");
ItemList.Add("Silver Coin");
ItemList.Add("Gold Coin");
ItemList.Add("Platinum Coin");
ItemList.Add("Fallen Star");
ItemList.Add("Copper Greaves");
ItemList.Add("Iron Greaves");
ItemList.Add("Silver Greaves");
ItemList.Add("Gold Greaves");
ItemList.Add("Copper Chainmail");
ItemList.Add("Iron Chainmail");
ItemList.Add("Silver Chainmail");
ItemList.Add("Gold Chainmail");
ItemList.Add("Grappling Hook");
ItemList.Add("Iron Chain");
ItemList.Add("Shadow Scale");
ItemList.Add("Piggy Bank");
ItemList.Add("Mining Helmet");
ItemList.Add("Copper Helmet");
ItemList.Add("Iron Helmet");
ItemList.Add("Silver Helmet");
ItemList.Add("Gold Helmet");
ItemList.Add("Wood Wall");
ItemList.Add("Wood Platform");
ItemList.Add("Flintlock Pistol");
ItemList.Add("Musket");
ItemList.Add("Musket Ball");
ItemList.Add("Minishark");
ItemList.Add("Iron Bow");
ItemList.Add("Shadow Greaves");
ItemList.Add("Shadow Scalemail");
ItemList.Add("Shadow Helmet");
ItemList.Add("Nightmare Pickaxe");
ItemList.Add("The Breaker");
ItemList.Add("Candle");
ItemList.Add("Copper Chandelier");
ItemList.Add("Silver Chandelier");
ItemList.Add("Gold Chandelier");
ItemList.Add("Mana Crystal");
ItemList.Add("Lesser Mana Potion");
ItemList.Add("Band of Starpower");
ItemList.Add("Flower of Fire");
ItemList.Add("Magic Missile");
ItemList.Add("Dirt Rod");
ItemList.Add("Orb of Light");
ItemList.Add("Meteorite");
ItemList.Add("Meteorite Bar");
ItemList.Add("Hook");
ItemList.Add("Flamarang");
ItemList.Add("Molten Fury");
ItemList.Add("Fiery Greatsword");
ItemList.Add("Molten Pickaxe");
ItemList.Add("Meteor Helmet");
ItemList.Add("Meteor Suit");
ItemList.Add("Meteor Leggings");
ItemList.Add("Bottled Water");
ItemList.Add("Space Gun");
ItemList.Add("Rocket Boots");
ItemList.Add("Gray Brick");
ItemList.Add("Gray Brick Wall");
ItemList.Add("Red Brick");
ItemList.Add("Red Brick Wall");
ItemList.Add("Clay Block");
ItemList.Add("Blue Brick");
ItemList.Add("Blue Brick Wall");
ItemList.Add("Chain Lantern");
ItemList.Add("Green Brick");
ItemList.Add("Green Brick Wall");
ItemList.Add("Pink Brick");
ItemList.Add("Pink Brick Wall");
ItemList.Add("Gold Brick");
ItemList.Add("Gold Brick Wall");
ItemList.Add("Silver Brick");
ItemList.Add("Silver Brick Wall");
ItemList.Add("Copper Brick");
ItemList.Add("Copper Brick Wall");
ItemList.Add("Spike");
ItemList.Add("Water Candle");
ItemList.Add("Book");
ItemList.Add("Cobweb");
ItemList.Add("Necro Helmet");
ItemList.Add("Necro Breastplate");
ItemList.Add("Necro Greaves");
ItemList.Add("Bone");
ItemList.Add("Muramasa");
ItemList.Add("Cobalt Shield");
ItemList.Add("Aqua Scepter");
ItemList.Add("Lucky Horseshoe");
ItemList.Add("Shiny Red Balloon");
ItemList.Add("Harpoon");
ItemList.Add("Spiky Ball");
ItemList.Add("Ball 'O Hurt");
ItemList.Add("Blue Moon");
ItemList.Add("Handgun");
ItemList.Add("Water Bolt");
ItemList.Add("Bomb");
ItemList.Add("Dynamite");
ItemList.Add("Grenade");
ItemList.Add("Sand Block");
ItemList.Add("Glass");
ItemList.Add("Sign");
ItemList.Add("Ash Block");
ItemList.Add("Obsidian");
ItemList.Add("Hellstone");
ItemList.Add("Hellstone Bar");
ItemList.Add("Mud Block");
ItemList.Add("Sapphire");
ItemList.Add("Ruby");
ItemList.Add("Emerald");
ItemList.Add("Topaz");
ItemList.Add("Amethyst");
ItemList.Add("Diamond");
ItemList.Add("Glowing Mushroom");
ItemList.Add("Star");
ItemList.Add("Ivy Whip");
ItemList.Add("Breathing Reed");
ItemList.Add("Flipper");
ItemList.Add("Healing Potion");
ItemList.Add("Mana Potion");
ItemList.Add("Blade of Grass");
ItemList.Add("Thorn Chakrum");
ItemList.Add("Obsidian Brick");
ItemList.Add("Obsidian Skull");
ItemList.Add("Mushroom Grass Seeds");
ItemList.Add("Jungle Grass Seeds");
ItemList.Add("Wooden Hammer");
ItemList.Add("Star Cannon");
ItemList.Add("Blue Phaseblade");
ItemList.Add("Red Phaseblade");
ItemList.Add("Green Phaseblade");
ItemList.Add("Purple Phaseblade");
ItemList.Add("White Phaseblade");
ItemList.Add("Yellow Phaseblade");
ItemList.Add("Meteor Hamaxe");
ItemList.Add("Empty Bucket");
ItemList.Add("Water Bucket");
ItemList.Add("Lava Bucket");
ItemList.Add("Jungle Rose");
ItemList.Add("Stinger");
ItemList.Add("Vine");
ItemList.Add("Feral Claws");
ItemList.Add("Anklet of the Wind");
ItemList.Add("Staff of Regrowth");
ItemList.Add("Hellstone Brick");
ItemList.Add("Whoopie Cushion");
ItemList.Add("Shackle");
ItemList.Add("Molten Hamaxe");
ItemList.Add("Flamelash");
ItemList.Add("Phoenix Blaster");
ItemList.Add("Sunfury");
ItemList.Add("Hellforge");
ItemList.Add("Clay Pot");
ItemList.Add("Nature's Gift");
ItemList.Add("Bed");
ItemList.Add("Silk");
ItemList.Add("Lesser Restoration Potion");
ItemList.Add("Restoration Potion");
ItemList.Add("Jungle Hat");
ItemList.Add("Jungle Shirt");
ItemList.Add("Jungle Pants");
ItemList.Add("Molten Helmet");
ItemList.Add("Molten Breastplate");
ItemList.Add("Molten Greaves");
ItemList.Add("Meteor Shot");
ItemList.Add("Sticky Bomb");
ItemList.Add("Black Lens");
ItemList.Add("Sunglasses");
ItemList.Add("Wizard Hat");
ItemList.Add("Top Hat");
ItemList.Add("Tuxedo Shirt");
ItemList.Add("Tuxedo Pants");
ItemList.Add("Summer Hat");
ItemList.Add("Bunny Hood");
ItemList.Add("Plumber's Hat");
ItemList.Add("Plumber's Shirt");
ItemList.Add("Plumber's Pants");
ItemList.Add("Hero's Hat");
ItemList.Add("Hero's Shirt");
ItemList.Add("Hero's Pants");
ItemList.Add("Fish Bowl");
ItemList.Add("Archaeologist's Hat");
ItemList.Add("Archaeologist's Jacket");
ItemList.Add("Archaeologist's Pants");
ItemList.Add("Black Dye");
ItemList.Add("Green Dye");
ItemList.Add("Ninja Hood");
ItemList.Add("Ninja Shirt");
ItemList.Add("Ninja Pants");
ItemList.Add("Leather");
ItemList.Add("Red Hat");
ItemList.Add("Goldfish");
ItemList.Add("Robe");
ItemList.Add("Robot Hat");
ItemList.Add("Gold Crown");
ItemList.Add("Hellfire Arrow");
ItemList.Add("Sandgun");
ItemList.Add("Guide Voodoo Doll");
ItemList.Add("Diving Helmet");
ItemList.Add("Familiar Shirt");
ItemList.Add("Familiar Pants");
ItemList.Add("Familiar Wig");
ItemList.Add("Demon Scythe");
ItemList.Add("Night's Edge");
ItemList.Add("Dark Lance");
ItemList.Add("Coral");
ItemList.Add("Cactus");
ItemList.Add("Trident");
ItemList.Add("Silver Bullet");
ItemList.Add("Throwing Knife");
ItemList.Add("Spear");
ItemList.Add("Blowpipe");
ItemList.Add("Glowstick");
ItemList.Add("Seed");
ItemList.Add("Wooden Boomerang");
ItemList.Add("Aglet");
ItemList.Add("Sticky Glowstick");
ItemList.Add("Poisoned Knife");
ItemList.Add("Obsidian Skin Potion");
ItemList.Add("Regeneration Potion");
ItemList.Add("Swiftness Potion");
ItemList.Add("Gills potion");
ItemList.Add("Ironskin Potion");
ItemList.Add("Mana Regeneration Potion");
ItemList.Add("Magic Power Potion");
ItemList.Add("Featherfall Potion");
ItemList.Add("Spelunker Potion");
ItemList.Add("Invisibility Potion");
ItemList.Add("Shine Potion");
ItemList.Add("Night Owl Potion");
ItemList.Add("Battle Potion");
ItemList.Add("Thorns Potion");
ItemList.Add("Water Walking Potion");
ItemList.Add("Archery Potion");
ItemList.Add("Hunter Potion");
ItemList.Add("Gravitation Potion");
ItemList.Add("Gold Chest");
ItemList.Add("Daybloom Seeds");
ItemList.Add("Moonglow Seeds");
ItemList.Add("Blinkroot Seeds");
ItemList.Add("Deathweed Seeds");
ItemList.Add("Waterleaf Seeds");
ItemList.Add("Fireblossom Seeds");
ItemList.Add("Daybloom");
ItemList.Add("Moonglow");
ItemList.Add("Blinkroot");
ItemList.Add("Deathweed");
ItemList.Add("Waterleaf");
ItemList.Add("Fireblossom");
ItemList.Add("Shark Fin");
ItemList.Add("Feather");
ItemList.Add("Tombstone");
ItemList.Add("Mime Mask");
ItemList.Add("Antlion Mandible");
ItemList.Add("Illegal Gun Parts");
ItemList.Add("The Doctor's Shirt");
ItemList.Add("The Doctor's Pants");
}
}
}

1152
DBEditor/Main.Designer.cs generated

File diff suppressed because it is too large Load diff

View file

@ -1,777 +0,0 @@
/*
TShock, a server mod for Terraria
Copyright (C) 2011-2012 The TShock Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.IO;
using System.Security.Cryptography;
using Mono.Data.Sqlite;
using MySql.Data.MySqlClient;
using System.Windows.Forms;
namespace TShockDBEditor
{
public partial class TShockDBEditor : Form
{
public OpenFileDialog dialog = new OpenFileDialog();
public List<Group> groups = new List<Group>();
public static List<string> CommandList = new List<string>();
public IDbConnection DB;
public string dbtype = "";
public TShockDBEditor()
{
InitializeComponent();
Itemlist.AddItems();
dialog.FileOk += new CancelEventHandler(dialog_FileOk);
dialog.Filter = "SQLite Database (*.sqlite)|*.sqlite";
}
public void LoadDB()
{
itemListBanned.Items.Clear();
lst_groupList.Items.Clear();
lst_AvailableCmds.Items.Clear();
lst_bannedCmds.Items.Clear();
itemListAvailable.Items.Clear();
using (var com = DB.CreateCommand())
{
com.CommandText =
"SELECT * FROM Itembans";
using (var reader = com.ExecuteReader())
{
while (reader.Read())
itemListBanned.Items.Add(reader.Get<string>("ItemName"));
}
}
using (var com = DB.CreateCommand())
{
com.CommandText =
"SELECT * FROM GroupList";
lst_groupList.Items.Add("superadmin");
lst_usergrplist.Items.Add("superadmin");
lst_newusergrplist.Items.Add("superadmin");
using (var reader = com.ExecuteReader())
{
while (reader.Read())
{
lst_groupList.Items.Add(reader.Get<string>("GroupName"));
lst_inheritgrps.Items.Add(reader.Get<string>("GroupName"));
lst_usergrplist.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())
{
com.CommandText =
"SELECT * FROM Users";
using (var reader = com.ExecuteReader())
{
while (reader.Read())
{
if (reader.Get<string>("UserName") != "")
lst_userlist.Items.Add(reader.Get<string>("UserName"));
else
lst_userlist.Items.Add(reader.Get<string>("IP"));
}
}
}
using (var com = DB.CreateCommand())
{
com.CommandText =
"SELECT * FROM Bans";
using (var reader = com.ExecuteReader())
{
while (reader.Read())
{
lst_bans.Items.Add(reader.Get<string>("Name"));
}
}
}
for (int i = 0; i < Itemlist.ItemList.Count; i++)
{
if (!itemListBanned.Items.Contains(Itemlist.ItemList[i]))
itemListAvailable.Items.Add(Itemlist.ItemList[i]);
}
}
public void LoadSqliteDatabase(string path)
{
string sql = dialog.FileName;
DB = new SqliteConnection(string.Format("uri=file://{0},Version=3", sql));
DB.Open();
dbtype = "sqlite";
LoadDB();
}
public void LoadMySqlDatabase(string hostname = "localhost", string port = "3306", string database = "", string dbusername = "", string dbpassword = "")
{
DB = new MySqlConnection();
DB.ConnectionString =
"Server='" + hostname +
"';Port='" + port +
"';Database='" + database +
"';Uid='" + dbusername +
"';Pwd='" + dbpassword + "';";
DB.Open();
dbtype = "mysql";
LoadDB();
}
#region BannedItemsTab
public void btn_moveAllRightItems_Click(object sender, EventArgs e)
{
foreach (object item in itemListAvailable.Items)
{
itemListBanned.Items.Add(item);
using (var com = DB.CreateCommand())
{
com.CommandText = "INSERT INTO ItemBans (ItemName) VALUES (@itemname);";
com.AddParameter("@itemname", item.ToString());
com.ExecuteNonQuery();
com.Parameters.Clear();
}
}
itemListAvailable.Items.Clear();
}
private void btn_moveAllLeftItems_Click(object sender, EventArgs e)
{
foreach (object item in itemListBanned.Items)
{
itemListAvailable.Items.Add(item);
using (var com = DB.CreateCommand())
{
com.CommandText = "DELETE FROM ItemBans WHERE ItemName=@itemname;";
com.AddParameter("@itemname", item.ToString());
com.ExecuteNonQuery();
com.Parameters.Clear();
}
}
itemListBanned.Items.Clear();
}
private void btn_moveRightItems_Click(object sender, EventArgs e)
{
if (itemListAvailable.SelectedItem != null)
{
itemListBanned.Items.Add(itemListAvailable.SelectedItem);
using (var com = DB.CreateCommand())
{
com.CommandText = "INSERT INTO ItemBans (ItemName) VALUES (@itemname);";
com.AddParameter("@itemname", itemListAvailable.SelectedItem.ToString());
com.ExecuteNonQuery();
}
itemListAvailable.Items.Remove(itemListAvailable.SelectedItem);
}
}
private void btn_moveLeftItems_Click(object sender, EventArgs e)
{
if (itemListBanned.SelectedItem != null)
{
itemListAvailable.Items.Add(itemListBanned.SelectedItem);
using (var com = DB.CreateCommand())
{
com.CommandText = "DELETE FROM ItemBans WHERE ItemName=@itemname;";
com.AddParameter("@itemname", itemListBanned.SelectedItem.ToString());
com.ExecuteNonQuery();
}
itemListBanned.Items.Remove(itemListBanned.SelectedItem);
}
}
#endregion
#region GroupTab
private void lst_groupList_SelectedIndexChanged(object sender, EventArgs e)
{
if ((string)lst_groupList.SelectedItem != "superadmin")
UpdateGroupIndex(lst_groupList.SelectedIndex);
else
lst_groupList.SelectedIndex = -1;
}
private void UpdateGroupIndex(int index)
{
try
{
using (var com = DB.CreateCommand())
{
lst_AvailableCmds.Items.Clear();
lst_bannedCmds.Items.Clear();
com.CommandText =
"SELECT * FROM GroupList WHERE GroupName=@groupname";
com.AddParameter("@groupname", lst_groupList.Items[index].ToString());
lbl_grpchild.Text = "";
using (var reader = com.ExecuteReader())
{
while (reader.Read())
{
foreach (string command in reader.Get<string>("Commands").Split(','))
{
if (lst_groupList.Items.Contains(command) || command == "")
lbl_grpchild.Text = command;
else
lst_AvailableCmds.Items.Add(command);
}
}
}
if (lbl_grpchild.Text == "")
lbl_grpchild.Text = "none";
for (int i = 0; i < CommandList.Count; i++)
{
if (!lst_AvailableCmds.Items.Contains(CommandList[i]))
lst_bannedCmds.Items.Add(CommandList[i]);
}
}
}
catch { }
}
private void btn_moveAllRightCmd_Click(object sender, EventArgs e)
{
try
{
var sb = new StringBuilder();
foreach (object cmd in lst_bannedCmds.Items)
{
lst_AvailableCmds.Items.Add(cmd);
if (string.IsNullOrEmpty(sb.ToString()))
sb.Append(cmd.ToString());
else
sb.Append(",").Append(cmd.ToString());
}
using (var com = DB.CreateCommand())
{
com.CommandText = "UPDATE GroupList SET Commands=@cmds WHERE GroupName=@name;";
com.AddParameter("@name", lst_groupList.Items[lst_groupList.SelectedIndex].ToString());
com.AddParameter("@cmds", sb.ToString());
com.ExecuteNonQuery();
}
lst_bannedCmds.Items.Clear();
}
catch { }
}
private void btn_moveRightCmd_Click(object sender, EventArgs e)
{
try
{
lst_AvailableCmds.Items.Add(lst_bannedCmds.Items[lst_bannedCmds.SelectedIndex]);
var sb = new StringBuilder();
foreach (object cmd in lst_AvailableCmds.Items)
{
if (string.IsNullOrEmpty(sb.ToString()))
sb.Append(cmd.ToString());
else
sb.Append(",").Append(cmd.ToString());
}
using (var com = DB.CreateCommand())
{
com.CommandText = "UPDATE GroupList SET Commands=@cmds WHERE GroupName=@name;";
com.AddParameter("@name", lst_groupList.Items[lst_groupList.SelectedIndex].ToString());
com.AddParameter("@cmds", sb.ToString());
com.ExecuteNonQuery();
}
lst_bannedCmds.Items.Remove(lst_bannedCmds.Items[lst_bannedCmds.SelectedIndex]);
}
catch { }
}
private void btn_moveLeftCmd_Click(object sender, EventArgs e)
{
try
{
lst_bannedCmds.Items.Add(lst_AvailableCmds.Items[lst_AvailableCmds.SelectedIndex]);
lst_AvailableCmds.Items.Remove(lst_AvailableCmds.Items[lst_AvailableCmds.SelectedIndex]);
var sb = new StringBuilder();
foreach (object cmd in lst_AvailableCmds.Items)
{
if (string.IsNullOrEmpty(sb.ToString()))
sb.Append(cmd.ToString());
else
sb.Append(",").Append(cmd.ToString());
}
using (var com = DB.CreateCommand())
{
com.CommandText = "UPDATE GroupList SET Commands=@cmds WHERE GroupName=@name;";
com.AddParameter("@name", lst_groupList.Items[lst_groupList.SelectedIndex].ToString());
com.AddParameter("@cmds", sb.ToString());
com.ExecuteNonQuery();
}
}
catch { }
}
private void btn_moveAllLeftCmd_Click(object sender, EventArgs e)
{
try
{
foreach (object cmd in lst_AvailableCmds.Items)
{
lst_bannedCmds.Items.Add(cmd);
}
using (var com = DB.CreateCommand())
{
com.CommandText = "UPDATE GroupList SET Commands=@cmds WHERE GroupName=@name;";
com.AddParameter("@name", lst_groupList.Items[lst_groupList.SelectedIndex].ToString());
com.AddParameter("@cmds", "");
com.ExecuteNonQuery();
}
lst_AvailableCmds.Items.Clear();
}
catch { }
}
private void btn_newgroup_Click(object sender, EventArgs e)
{
try
{
if (txt_grpname.Text != "")
{
using (var com = DB.CreateCommand())
{
if (dbtype == "sqlite")
com.CommandText = "INSERT OR IGNORE INTO GroupList (GroupName, Commands) VALUES (@groupname, @commands);";
else if (dbtype == "mysql")
com.CommandText = "INSERT IGNORE INTO GroupList SET GroupName=@groupname, Commands=@commands;";
com.AddParameter("@groupname", txt_grpname.Text);
if (lst_inheritgrps.SelectedIndex > -1)
com.AddParameter("@commands", lst_inheritgrps.Items[lst_inheritgrps.SelectedIndex]);
else
com.AddParameter("@commands", "");
using (var reader = com.ExecuteReader())
{
if (reader.RecordsAffected > 0)
{
lst_groupList.Items.Add(txt_grpname.Text);
lst_inheritgrps.Items.Add(txt_grpname.Text);
lst_usergrplist.Items.Add(txt_grpname.Text);
txt_grpname.Text = "";
}
}
com.Parameters.Clear();
}
}
}
catch { }
}
private void btn_deletegroup_Click(object sender, EventArgs e)
{
try
{
using (var com = DB.CreateCommand())
{
com.CommandText = "DELETE FROM Grouplist WHERE GroupName = @groupname";
com.AddParameter("@groupname", lst_groupList.Items[lst_groupList.SelectedIndex]);
com.ExecuteNonQuery();
lst_groupList.Items.Remove(lst_groupList.Items[lst_groupList.SelectedIndex]);
lst_inheritgrps.Items.Clear();
lst_usergrplist.Items.Clear();
com.CommandText =
"SELECT * FROM GroupList";
using (var reader = com.ExecuteReader())
{
while (reader.Read())
{
lst_inheritgrps.Items.Add(reader.Get<string>("GroupName"));
lst_usergrplist.Items.Add(reader.Get<string>("GroupName"));
}
}
}
}
catch { }
}
#endregion
#region FileOpenTabs
private void btn_OpenLocalDB_Click(object sender, EventArgs e)
{
dialog.ShowDialog();
}
void dialog_FileOk(object sender, CancelEventArgs e)
{
LoadSqliteDatabase(dialog.FileName);
tabControl.Visible = true;
}
private void btn_connect_Click(object sender, EventArgs e)
{
LoadMySqlDatabase(txt_hostname.Text, txt_port.Text, txt_dbname.Text, txt_dbusername.Text, txt_dbpassword.Text);
tabControl.Visible = true;
}
#endregion
#region BansTab
private void lst_bans_SelectedIndexChanged(object sender, EventArgs e)
{
using (var com = DB.CreateCommand())
{
if (lst_bans.SelectedIndex > -1)
{
com.CommandText =
"SELECT * FROM Bans WHERE Name=@name";
com.AddParameter("@name", lst_bans.Items[lst_bans.SelectedIndex]);
using (var reader = com.ExecuteReader())
{
if (reader.Read())
{
txt_banip.Text = reader.Get<string>("IP");
txt_banname.Text = reader.Get<string>("Name");
txt_banreason.Text = reader.Get<string>("Reason");
}
}
}
}
}
private void btn_bandelete_Click(object sender, EventArgs e)
{
using (var com = DB.CreateCommand())
{
com.CommandText =
"DELETE FROM Bans WHERE IP=@ip";
com.AddParameter("@ip", txt_banip.Text);
using (var reader = com.ExecuteReader())
{
if (reader.RecordsAffected > 0)
{
txt_banip.Text = "";
txt_banname.Text = "";
txt_banreason.Text = "";
lst_bans.Items.Remove(lst_bans.Items[lst_bans.SelectedIndex]);
}
}
}
}
private void btn_bannew_Click(object sender, EventArgs e)
{
using (var com = DB.CreateCommand())
{
if (dbtype == "sqlite")
com.CommandText = "INSERT INTO Bans (IP, Name, Reason) VALUES (@ip, @name, @reason);";
else if (dbtype == "mysql")
com.CommandText = "INSERT INTO Bans SET IP=@ip, Name=@name, Reason=@reason;";
if (txt_newbanip.Text != "" && txt_newbanname.Text != "")
{
com.AddParameter("@ip", txt_newbanip.Text);
com.AddParameter("@name", txt_newbanname.Text);
com.AddParameter("@reason", txt_newbanreason.Text);
com.ExecuteNonQuery();
lst_bans.Items.Add(txt_newbanname.Text);
txt_newbanip.Text = "";
txt_newbanname.Text = "";
txt_newbanreason.Text = "";
lbl_newbanstatus.Text = "Ban added successfully!";
}
else
lbl_newbanstatus.Text = "Required field('s) empty";
lst_bans.Items.Add(txt_newbanname.Text);
txt_newbanip.Text = "";
txt_newbanname.Text = "";
}
}
private void txt_banreason_TextChanged(object sender, EventArgs e)
{
if (txt_banip.Text != "")
{
using (var com = DB.CreateCommand())
{
com.CommandText =
"UPDATE Bans SET Reason=@reason WHERE IP=@ip";
com.AddParameter("@reason", txt_banreason.Text);
com.AddParameter("@ip", txt_banip.Text);
com.ExecuteNonQuery();
}
}
}
#endregion
#region UserTab
private void lst_userlist_SelectedIndexChanged(object sender, EventArgs e)
{
txt_username.Text = "None Selected";
txt_userip.Text = "None Selected";
lst_usergrplist.SelectedIndex = -1;
bool flag = false;
if (lst_userlist.SelectedIndex > -1)
{
using (var com = DB.CreateCommand())
{
com.CommandText =
"SELECT * FROM Users WHERE Username=@name";
com.AddParameter("@name", lst_userlist.Items[lst_userlist.SelectedIndex]);
using (var reader = com.ExecuteReader())
{
if (reader.Read())
{
txt_username.Text = reader.Get<string>("Username");
if (reader.Get<string>("IP") != "")
txt_userip.Text = reader.Get<string>("IP");
else
txt_userip.Text = "User does not have IP";
if (reader.Get<string>("Password") != "")
txt_userpass.Text = reader.Get<string>("Password");
else
txt_userpass.Text = "User does not have Pasword";
foreach (string name in lst_usergrplist.Items)
{
if (name == reader.Get<string>("Usergroup"))
{
lst_usergrplist.SelectedItem = name;
break;
}
}
}
else
flag = true;
}
}
if (flag)
{
using (var com = DB.CreateCommand())
{
com.CommandText =
"SELECT * FROM Users WHERE IP=@ip";
com.AddParameter("@ip", lst_userlist.Items[lst_userlist.SelectedIndex]);
using (var reader = com.ExecuteReader())
{
if (reader.Read())
{
if (reader.Get<string>("Password") != "")
txt_userpass.Text = reader.Get<string>("Password");
else
txt_userpass.Text = "User does not have Pasword";
txt_userip.Text = lst_userlist.Items[lst_userlist.SelectedIndex].ToString();
foreach (string name in lst_usergrplist.Items)
{
if (name == reader.Get<string>("Usergroup"))
{
lst_usergrplist.SelectedItem = name;
break;
}
}
}
}
}
}
}
}
private void lst_usergrplist_SelectedIndexChanged(object sender, EventArgs e)
{
if (lst_userlist.SelectedIndex > -1)
{
using (var com = DB.CreateCommand())
{
com.CommandText =
"UPDATE Users SET Usergroup=@group WHERE Username=@user OR IP=@ip";
com.AddParameter("@group", lst_usergrplist.SelectedItem);
com.AddParameter("@user", txt_username.Text);
com.AddParameter("@ip", txt_userip.Text);
com.ExecuteNonQuery();
}
}
}
private void btn_deluser_Click(object sender, EventArgs e)
{
if (lst_userlist.SelectedIndex > -1)
{
using (var com = DB.CreateCommand())
{
com.CommandText =
"DELETE FROM Users WHERE IP=@ip OR Username=@user";
com.AddParameter("@user", txt_username.Text);
com.AddParameter("@ip", txt_userip.Text);
com.ExecuteNonQuery();
lst_userlist.Items.Remove(lst_userlist.SelectedItem);
txt_userip.Text = "";
txt_username.Text = "";
txt_userpass.Text = "";
lst_usergrplist.SelectedIndex = -1;
lst_userlist.SelectedIndex = -1;
}
}
}
private void btn_adduser_Click(object sender, EventArgs e)
{
lbl_useraddstatus.Visible = true;
for (int i = 0; i == 0; i++)
{
if ((txt_newusername.Text == "" && txt_newuserpass.Text != ""))
{
lbl_useraddstatus.Text = "Username field cannot be empty";
break;
}
if ((txt_newusername.Text != "" && txt_newuserpass.Text == ""))
{
lbl_useraddstatus.Text = "Password field cannot be empty";
break;
}
if (txt_newuserip.Text == "" && (txt_newusername.Text == "" || txt_newuserpass.Text == ""))
{
lbl_useraddstatus.Text = "IP field cannot be empty";
break;
}
if (lst_newusergrplist.SelectedIndex == -1)
{
lbl_useraddstatus.Text = "Group must be selected";
break;
}
using (var com = DB.CreateCommand())
{
com.CommandText = "INSERT INTO Users (Username, Password, UserGroup, IP) VALUES (@name, @password, @group, @ip);";
com.AddParameter("@name", txt_newusername.Text);
com.AddParameter("@password", HashPassword(txt_newuserpass.Text));
com.AddParameter("@group", lst_newusergrplist.SelectedItem);
com.AddParameter("@ip", txt_newuserip.Text);
using (var reader = com.ExecuteReader())
{
if (reader.RecordsAffected > 0)
{
if (txt_newusername.Text != "")
lst_userlist.Items.Add(txt_newusername.Text);
else
lst_userlist.Items.Add(txt_newuserip.Text);
txt_newuserip.Text = "";
txt_newusername.Text = "";
txt_newuserpass.Text = "";
lst_newusergrplist.SelectedIndex = -1;
lbl_useraddstatus.Text = "User added successfully!";
}
else
lbl_useraddstatus.Text = "SQL error while adding user";
}
}
}
}
public static string HashPassword(string password)
{
using (var sha = new SHA512CryptoServiceProvider())
{
if (password == "")
{
return "nonexistent-password";
}
var bytes = sha.ComputeHash(Encoding.ASCII.GetBytes(password));
return bytes.Aggregate("", (s, b) => s + b.ToString("X2"));
}
}
#endregion
private void TShockDBEditor_Load(object sender, EventArgs e)
{
}
}
}

View file

@ -1,120 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

View file

@ -1,53 +0,0 @@
/*
TShock, a server mod for Terraria
Copyright (C) 2011-2012 The TShock Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("WindowsFormsApplication2")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Microsoft")]
[assembly: AssemblyProduct("WindowsFormsApplication2")]
[assembly: AssemblyCopyright("Copyright © Microsoft 2011")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("ffdb92d1-7f89-4f59-a671-22ea6cda680c")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

View file

@ -1,81 +0,0 @@
/*
TShock, a server mod for Terraria
Copyright (C) 2011-2012 The TShock Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.1
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace TShockDBEditor.Properties {
using System;
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
// This class was auto-generated by the StronglyTypedResourceBuilder
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resources {
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Resources() {
}
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("TShockDBEditor.Properties.Resources", typeof(Resources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
}
}

View file

@ -1,117 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

View file

@ -1,44 +0,0 @@
/*
TShock, a server mod for Terraria
Copyright (C) 2011-2012 The TShock Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.1
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace TShockDBEditor.Properties {
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "10.0.0.0")]
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
public static Settings Default {
get {
return defaultInstance;
}
}
}
}

View file

@ -1,7 +0,0 @@
<?xml version='1.0' encoding='utf-8'?>
<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)">
<Profiles>
<Profile Name="(Default)" />
</Profiles>
<Settings />
</SettingsFile>

View file

@ -1,148 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">x86</Platform>
<ProductVersion>8.0.30703</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{F1AE395C-6B4D-40E0-8BF8-0D8A126488D3}</ProjectGuid>
<OutputType>WinExe</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>TShockDBEditor</RootNamespace>
<AssemblyName>TShockDBEditor</AssemblyName>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<TargetFrameworkProfile>
</TargetFrameworkProfile>
<FileAlignment>512</FileAlignment>
<IsWebBootstrapper>false</IsWebBootstrapper>
<PublishUrl>publish\</PublishUrl>
<Install>true</Install>
<InstallFrom>Disk</InstallFrom>
<UpdateEnabled>false</UpdateEnabled>
<UpdateMode>Foreground</UpdateMode>
<UpdateInterval>7</UpdateInterval>
<UpdateIntervalUnits>Days</UpdateIntervalUnits>
<UpdatePeriodically>false</UpdatePeriodically>
<UpdateRequired>false</UpdateRequired>
<MapFileExtensions>true</MapFileExtensions>
<ApplicationRevision>0</ApplicationRevision>
<ApplicationVersion>1.0.0.%2a</ApplicationVersion>
<UseApplicationTrust>false</UseApplicationTrust>
<BootstrapperEnabled>true</BootstrapperEnabled>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
<PlatformTarget>x86</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
<PlatformTarget>x86</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="Mono.Data.Sqlite">
<HintPath>..\SqlBins\Mono.Data.Sqlite.dll</HintPath>
</Reference>
<Reference Include="MySql.Data, Version=6.3.6.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\SqlBins\MySql.Data.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="MySql.Web, Version=6.3.6.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\SqlBins\MySql.Web.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Deployment" />
<Reference Include="System.Drawing" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="CommandList.cs" />
<Compile Include="Group.cs" />
<Compile Include="DbExt.cs" />
<Compile Include="Main.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="Main.Designer.cs">
<DependentUpon>Main.cs</DependentUpon>
</Compile>
<Compile Include="Itemlist.cs" />
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<EmbeddedResource Include="Main.resx">
<DependentUpon>Main.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
<SubType>Designer</SubType>
</EmbeddedResource>
<Compile Include="Properties\Resources.Designer.cs">
<AutoGen>True</AutoGen>
<DependentUpon>Resources.resx</DependentUpon>
<DesignTime>True</DesignTime>
</Compile>
<None Include="app.config" />
<None Include="Properties\Settings.settings">
<Generator>SettingsSingleFileGenerator</Generator>
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
</None>
<Compile Include="Properties\Settings.Designer.cs">
<AutoGen>True</AutoGen>
<DependentUpon>Settings.settings</DependentUpon>
<DesignTimeSharedInput>True</DesignTimeSharedInput>
</Compile>
<None Include="TShockDBEditor.licenseheader" />
</ItemGroup>
<ItemGroup>
<WCFMetadata Include="Service References\" />
</ItemGroup>
<ItemGroup>
<BootstrapperPackage Include=".NETFramework,Version=v4.0">
<Visible>False</Visible>
<ProductName>Microsoft .NET Framework 4 %28x86 and x64%29</ProductName>
<Install>true</Install>
</BootstrapperPackage>
<BootstrapperPackage Include="Microsoft.Net.Client.3.5">
<Visible>False</Visible>
<ProductName>.NET Framework 3.5 SP1 Client Profile</ProductName>
<Install>false</Install>
</BootstrapperPackage>
<BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
<Visible>False</Visible>
<ProductName>.NET Framework 3.5 SP1</ProductName>
<Install>false</Install>
</BootstrapperPackage>
<BootstrapperPackage Include="Microsoft.Windows.Installer.3.1">
<Visible>False</Visible>
<ProductName>Windows Installer 3.1</ProductName>
<Install>true</Install>
</BootstrapperPackage>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

View file

@ -1,18 +0,0 @@
extensions: .cs
/*
TShock, a server mod for Terraria
Copyright (C) 2011-2012 The TShock Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

View file

@ -1,3 +0,0 @@
<?xml version="1.0"?>
<configuration>
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/></startup></configuration>

View file

@ -1,63 +1,27 @@
TShock is a server modification for Terraria.
# TShock [![Build Status](https://travis-ci.org/NyxStudios/TShock.png?branch=general-devel)](https://travis-ci.org/NyxStudios/TShock)
__Continuous Integration__: http://ci.tshock.co/
TShock is a server modification for Terraria, written in C#, and based upon the [Terraria Server API](https://github.com/Deathmax/TerrariaAPI-Server). It uses JSON for configuration management, and offers several features not present in the Terraria Server normally.
__Support Forums__: http://tshock.co/
## Features
__Wiki__: http://ci.tshock.co:8080/
* MySQL support
* Permissions
* Multiple administrators
* Anti-cheat
* User registration
* Reserved slots
* User punishment (kicking, banning, muting)
----
## Community
### Helping out
Feeling like helping out? Want to find an awesome server? Some awesome plugins?
If you'd like to help out, the best thing you can do is to fork this repository, add changes, and request a pull back in. Try to make your changes on the latest code possible so that merging doesn't take ages, but other than that we accept any improvements or changes.
* [Website & Forums](http://tshock.co/xf/)
* [Wiki](https://tshock.atlassian.net/wiki/display/TSHOCKPLUGINS/Home)
* [IRC: #tshock @ irc.rizon.net](http://tshock.co/xf/index.php?ezirc/)
----
## Download
### Teamspeak
We communicate on the ShankShock Temspeak server whilst programming.
__IP__: ts3.shankshock.com
__Port__: 9987
### IRC
We love IRC (although a little less than Teamspeak). If you need support, or just want to hang around, feel free to join.
__IP__: irc.shankshock.com
__Channel__: #terraria-dev or #terraria
----
### Pull Request Dev Guidelines
These guidelines are for contributors. If you do not follow these guidelines your commits will be reverted.
Required:
- Follow the code style. We generally use microsofts except for m_ infront of private variables.
- Do not push unfinished features to the master branch, instead create a remote branch and push to that.
- Do not push untested code to the master branch, instead push to the test branch.
- Document all compatibility issues in the COMPATIBILITY file. (IE file formats changing)
- DO NOT MASS COMMIT. Commit changes as you go (without pushing). That way when you push we don't get a thousand changes with a 1-3 line commit message.
Optional:
- Build Version Increment (http://autobuildversion.codeplex.com/).
----
### Dev Team Guidelines
These guidelines are to be followed by all developers with commit level access to this repository:
- Do not, for any reason, submit code to the master branch before it hits the development branch first. If the development branch is far ahead, and a new bug fix is going out, branch master, then merge with master and remove your branch.
- If you are found to do this, you will be the person merging and rebasing your code to fit general-devel.
- Prior to posting any version on the website, you must tick the version in AssemblyInfo.cs. This is the versioning formula:
- Major.Minor.Revision.BuildDate (tick Revision if you're fixing prior to an actual planned release)
- Do not release any development builds on the forums without consulting another developer first.
- __Document code prior to marking it done in JIRA__
- Move any un-tested code to the "Needs Validation" section on JIRA prior to marking it as done.
- Do not push changes to any branch without a proper issue being assigned in JIRA. If a feature isn't planned for this release, __it shouldn't be in the repo about to be released__.
- Submit all pull requests to the general-devel branch prior to the master branch, or you will be ignored.
* [Github Releases](https://github.com/TShock/TShock/releases)
* [Download Archive](https://github.com/TShock/TShock/downloads)
* [Latest Version (4.0.5)](https://s3.amazonaws.com/tshock/TShock+4.0.5.zip)

View file

@ -1,6 +1,6 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 11
# Visual Studio 2010
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{755F5B05-0924-47E9-9563-26EB20FE3F67}"
ProjectSection(SolutionItems) = preProject
Local.testsettings = Local.testsettings
@ -9,8 +9,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TShockAPI", "TShockAPI\TShockAPI.csproj", "{49606449-072B-4CF5-8088-AA49DA586694}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TShockDBEditor", "DBEditor\TShockDBEditor.csproj", "{F1AE395C-6B4D-40E0-8BF8-0D8A126488D3}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UnitTests", "UnitTests\UnitTests.csproj", "{F3742F51-D7BF-4754-A68A-CD944D2A21FF}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TShockRestTestPlugin", "TShockRestTestPlugin\TShockRestTestPlugin.csproj", "{F2FEDAFB-58DE-4611-9168-A86112C346C7}"
@ -38,16 +36,12 @@ Global
{49606449-072B-4CF5-8088-AA49DA586694}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{49606449-072B-4CF5-8088-AA49DA586694}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{49606449-072B-4CF5-8088-AA49DA586694}.Release|x86.ActiveCfg = Release|Any CPU
{F1AE395C-6B4D-40E0-8BF8-0D8A126488D3}.Debug|Any CPU.ActiveCfg = Debug|x86
{F1AE395C-6B4D-40E0-8BF8-0D8A126488D3}.Debug|Mixed Platforms.ActiveCfg = Debug|x86
{F1AE395C-6B4D-40E0-8BF8-0D8A126488D3}.Debug|Mixed Platforms.Build.0 = Debug|x86
{F1AE395C-6B4D-40E0-8BF8-0D8A126488D3}.Debug|x86.ActiveCfg = Debug|x86
{F1AE395C-6B4D-40E0-8BF8-0D8A126488D3}.Debug|x86.Build.0 = Debug|x86
{F1AE395C-6B4D-40E0-8BF8-0D8A126488D3}.Release|Any CPU.ActiveCfg = Release|x86
{F1AE395C-6B4D-40E0-8BF8-0D8A126488D3}.Release|Mixed Platforms.ActiveCfg = Release|x86
{F1AE395C-6B4D-40E0-8BF8-0D8A126488D3}.Release|Mixed Platforms.Build.0 = Release|x86
{F1AE395C-6B4D-40E0-8BF8-0D8A126488D3}.Release|x86.ActiveCfg = Release|x86
{F1AE395C-6B4D-40E0-8BF8-0D8A126488D3}.Release|x86.Build.0 = Release|x86
{F3742F51-D7BF-4754-A68A-CD944D2A21FF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F3742F51-D7BF-4754-A68A-CD944D2A21FF}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{F3742F51-D7BF-4754-A68A-CD944D2A21FF}.Debug|x86.ActiveCfg = Debug|Any CPU
{F3742F51-D7BF-4754-A68A-CD944D2A21FF}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F3742F51-D7BF-4754-A68A-CD944D2A21FF}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{F3742F51-D7BF-4754-A68A-CD944D2A21FF}.Release|x86.ActiveCfg = Release|Any CPU
{F2FEDAFB-58DE-4611-9168-A86112C346C7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F2FEDAFB-58DE-4611-9168-A86112C346C7}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F2FEDAFB-58DE-4611-9168-A86112C346C7}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
@ -58,12 +52,6 @@ Global
{F2FEDAFB-58DE-4611-9168-A86112C346C7}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{F2FEDAFB-58DE-4611-9168-A86112C346C7}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{F2FEDAFB-58DE-4611-9168-A86112C346C7}.Release|x86.ActiveCfg = Release|Any CPU
{F3742F51-D7BF-4754-A68A-CD944D2A21FF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F3742F51-D7BF-4754-A68A-CD944D2A21FF}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{F3742F51-D7BF-4754-A68A-CD944D2A21FF}.Debug|x86.ActiveCfg = Debug|Any CPU
{F3742F51-D7BF-4754-A68A-CD944D2A21FF}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F3742F51-D7BF-4754-A68A-CD944D2A21FF}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{F3742F51-D7BF-4754-A68A-CD944D2A21FF}.Release|x86.ActiveCfg = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

View file

@ -1,6 +1,6 @@
/*
TShock, a server mod for Terraria
Copyright (C) 2011-2012 The TShock Team
Copyright (C) 2011-2013 Nyx Studios (fka. The TShock Team)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -15,6 +15,7 @@ GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
using System;
using System.IO;
using System.Threading;
@ -60,22 +61,22 @@ namespace TShockAPI
if (worldpath != null && !Directory.Exists(worldpath))
Directory.CreateDirectory(worldpath);
TShock.Utils.Broadcast("Server map saving, potential lag spike");
TShock.Utils.Broadcast("Server map saving, potential lag spike.");
Console.WriteLine("Backing up world...");
SaveManager.Instance.SaveWorld();
Console.WriteLine("World backed up");
Console.WriteLine("World backed up.");
Console.ForegroundColor = ConsoleColor.Gray;
Log.Info(string.Format("World backed up ({0})", Main.worldPathName));
Log.Info(string.Format("World backed up ({0}).", Main.worldPathName));
Main.worldPathName = worldname;
}
catch (Exception ex)
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine("Backup failed");
Console.WriteLine("Backup failed!");
Console.ForegroundColor = ConsoleColor.Gray;
Log.Error("Backup failed");
Log.Error("Backup failed!");
Log.Error(ex.ToString());
}
}

File diff suppressed because it is too large Load diff

View file

@ -1,6 +1,6 @@
/*
TShock, a server mod for Terraria
Copyright (C) 2011-2012 The TShock Team
Copyright (C) 2011-2013 Nyx Studios (fka. The TShock Team)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -15,33 +15,36 @@ GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Text;
using Newtonsoft.Json;
using Rests;
namespace TShockAPI
{
public class ConfigFile
{
[Description(
"The equation for calculating invasion size is 100 + (multiplier * (number of active players with greater than 200 health))"
"The equation for calculating invasion size is 100 + (multiplier * (number of active players with greater than 200 health))."
)] public int InvasionMultiplier = 1;
[Description("The default maximum mobs that will spawn per wave. Higher means more mobs in that wave.")] public int
DefaultMaximumSpawns = 5;
[Description("The delay between waves. Shorter values lead to less mobs.")] public int DefaultSpawnRate = 600;
[Description("The delay between waves. Lower values lead to more mobs.")] public int DefaultSpawnRate = 600;
[Description("The port the server runs on.")] public int ServerPort = 7777;
[Description("Enable or disable the whitelist based on IP addresses in whitelist.txt")] public bool EnableWhitelist;
[Description(
"Enable the ability for invaison size to never decrease. Make sure to run /invade, and note that this adds 2 million+ goblins to the spawn que for the map."
"Enable the ability for invasion size to never decrease. Make sure to run /invade, and note that this adds 2 million+ goblins to the spawn queue for the map."
)] public bool InfiniteInvasion;
[Description("Set the server pvp mode. Vaild types are, \"normal\", \"always\", \"disabled\"")] public string PvPMode
[Description("Set the server pvp mode. Valid types are, \"normal\", \"always\", and \"disabled.\"")] public string PvPMode
= "normal";
[Description("Prevents tiles from being placed within SpawnProtectionRadius of the default spawn.")] public bool
@ -73,48 +76,48 @@ namespace TShockAPI
[Description("Hardcore players ONLY. This means softcore players cannot join.")] public bool HardcoreOnly;
[Description("Mediumcore players ONLY. This means softcore players cannot join.")] public bool MediumcoreOnly;
[Description("Kicks a Hardcore player on death.")] public bool KickOnMediumcoreDeath;
[Description("Bans a Hardcore player on death.")] public bool BanOnMediumcoreDeath;
[Description("Kicks a hardcore player on death.")] public bool KickOnMediumcoreDeath;
[Description("Bans a hardcore player on death.")] public bool BanOnMediumcoreDeath;
[Description("Enable/Disable Terrarias built in auto save")] public bool AutoSave = true;
[Description("Enable/disable Terraria's built in auto save.")] public bool AutoSave = true;
[Description("Number of failed login attempts before kicking the player.")] public int MaximumLoginAttempts = 3;
[Description("Not implemented")] public string RconPassword = "";
[Description("Not implemented")] public int RconPort = 7777;
[Description("Not implemented.")] public string RconPassword = "";
[Description("Not implemented.")] public int RconPort = 7777;
[Description("Used when replying to a rest /status request or sent to the client when UseServerName is true.")] public string ServerName = "";
[Description("Sends ServerName in place of the world name to clients.")] public bool UseServerName = false;
[Description("Not implemented")] public string MasterServer = "127.0.0.1";
[Description("Not implemented.")] public string MasterServer = "127.0.0.1";
[Description("Valid types are \"sqlite\" and \"mysql\"")] public string StorageType = "sqlite";
[Description("The MySQL Hostname and port to direct connections to")] public string MySqlHost = "localhost:3306";
[Description("The MySQL hostname and port to direct connections to")] public string MySqlHost = "localhost:3306";
[Description("Database name to connect to")] public string MySqlDbName = "";
[Description("Database username to connect with")] public string MySqlUsername = "";
[Description("Database password to connect with")] public string MySqlPassword = "";
[Description("Bans a Mediumcore player on death.")] public string MediumcoreBanReason = "Death results in a ban";
[Description("Kicks a Mediumcore player on death.")] public string MediumcoreKickReason = "Death results in a kick";
[Description("Bans a mediumcore player on death.")] public string MediumcoreBanReason = "Death results in a ban";
[Description("Kicks a mediumcore player on death.")] public string MediumcoreKickReason = "Death results in a kick";
[Description("Enables DNS resolution of incoming connections with GetGroupForIPExpensive.")] public bool
EnableDNSHostResolution;
[Description("Enables kicking of banned users by matching their IP Address")] public bool EnableIPBans = true;
[Description("Enables kicking of banned users by matching their IP Address.")] public bool EnableIPBans = true;
[Description("Enables kicking of banned users by matching their Character Name")] public bool EnableBanOnUsernames;
[Description("Enables kicking of banned users by matching their Character Name.")] public bool EnableBanOnUsernames;
[Description("Selects the default group name to place new registrants under")] public string
[Description("Selects the default group name to place new registrants under.")] public string
DefaultRegistrationGroupName = "default";
[Description("Selects the default group name to place non registered users under")] public string
DefaultGuestGroupName = "guest";
[Description("Force-Disable printing logs to players with the log permission")] public bool DisableSpewLogs = true;
[Description("Force-disable printing logs to players with the log permission.")] public bool DisableSpewLogs = true;
[Description("Valid types are \"sha512\", \"sha256\", \"md5\", append with \"-xp\" for the xp supported algorithms")] public string HashAlgorithm = "sha512";
[Description("Valid types are \"sha512\", \"sha256\", \"md5\", append with \"-xp\" for the xp supported algorithms.")] public string HashAlgorithm = "sha512";
[Description("Buffers up the packets and sends them out at the end of each frame")] public bool BufferPackets = true;
[Description("Buffers up the packets and sends them out at the end of each frame.")] public bool BufferPackets = true;
[Description("String that is used when kicking people when the server is full.")] public string ServerFullReason =
"Server is full";
@ -129,95 +132,95 @@ namespace TShockAPI
[Description("This will announce a player's location on join")] public bool EnableGeoIP;
[Description("This will turn on a token requirement for the /status API endpoint.")] public bool
[Description("This will turn on token requirement for the public REST API endpoints.")] public bool
EnableTokenEndpointAuthentication;
[Description("Deprecated. Use ServerName instead.")] public string ServerNickname = "TShock Server";
[Description("Enable/Disable the rest api.")] public bool RestApiEnabled;
[Description("Enable/disable the rest api.")] public bool RestApiEnabled;
[Description("This is the port which the rest api will listen on.")] public int RestApiPort = 7878;
[Description("Disable tombstones for all players.")] public bool DisableTombstones = true;
[Description("Displays a player's IP on join to everyone who has the log permission")] public bool DisplayIPToAdmins;
[Description("Displays a player's IP on join to everyone who has the log permission.")] public bool DisplayIPToAdmins;
[Description(
"Some tiles are 'fixed' by not letting TShock handle them. Disabling this may break certain asthetic tiles.")] public
"Some tiles are 'fixed' by not letting TShock handle them. Disabling this may break certain aesthetic tiles.")] public
bool EnableInsecureTileFixes = true;
[Description("Kicks users using a proxy as identified with the GeoIP database")] public bool KickProxyUsers = true;
[Description("Kicks users using a proxy as identified with the GeoIP database.")] public bool KickProxyUsers = true;
[Description("Disables hardmode, can't never be activated. Overrides /starthardmode")] public bool DisableHardmode;
[Description("Disables hardmode, can't never be activated. Overrides /starthardmode.")] public bool DisableHardmode;
[Description("Disables Dungeon Guardian from being spawned by player packets, this will instead force a respawn")] public bool DisableDungeonGuardian;
[Description("Disables the dungeon guardian from being spawned by player packets, this will instead force a respawn.")] public bool DisableDungeonGuardian;
[Description("Enable Server Side Inventory checks, EXPERIMENTAL")] public bool ServerSideInventory;
[Description("Enable server side inventory checks, EXPERIMENTAL")] public bool ServerSideInventory;
[Description("How often SSI should save, in minutes")] public int ServerSideInventorySave = 15;
[Description("How often SSI should save, in minutes.")] public int ServerSideInventorySave = 15;
[Description("Time, in milliseconds, to disallow discarding items after logging in when ServerSideInventory is ON")] public int LogonDiscardThreshold=250;
[Description("Time, in milliseconds, to disallow discarding items after logging in when ServerSideInventory is ON.")] public int LogonDiscardThreshold=250;
[Description("Disables reporting of playercount to the stat system.")] public bool DisablePlayerCountReporting;
[Description("Disables clown bomb projectiles from spawning.")] public bool DisableClownBombs;
[Description("Disables clown bomb projectiles from spawning")] public bool DisableClownBombs;
[Description("Disables snow ball projectiles from spawning")] public bool DisableSnowBalls;
[Description("Disables snow ball projectiles from spawning.")] public bool DisableSnowBalls;
[Description(
"Change ingame chat format, {0} = Group Name, {1} = Group Prefix, {2} = Player Name, {3} = Group Suffix, {4} = Chat Message"
"Changes ingame chat format: {0} = Group Name, {1} = Group Prefix, {2} = Player Name, {3} = Group Suffix, {4} = Chat Message"
)] public string ChatFormat = "{1}{2}{3}: {4}";
[Description("Change the chat format when using chat above heads. This begins with a player name wrapped in brackets, as per Terraria's formatting. Same formatting as ChatFormat.")] public string ChatAboveHeadsFormat = "{4}";
[Description("Force the world time to be normal, day, or night")] public string ForceTime = "normal";
[Description("Force the world time to be normal, day, or night.")] public string ForceTime = "normal";
[Description("Disable/Revert a player if they exceed this number of tile kills within 1 second.")] public int
[Description("Disables/reverts a player if this number of tile kills is exceeded within 1 second.")] public int
TileKillThreshold = 60;
[Description("Disable/Revert a player if they exceed this number of tile places within 1 second.")] public int
[Description("Disables/reverts a player if this number of tile places is exceeded within 1 second.")]
public int
TilePlaceThreshold = 20;
[Description("Disable a player if they exceed this number of liquid sets within 1 second.")] public int
[Description("Disables a player if this number of liquid sets is exceeded within 1 second.")] public int
TileLiquidThreshold = 15;
[Description("Disable a player if they exceed this number of projectile new within 1 second.")] public int
[Description("Disable a player if this number of projectiles is created within 1 second.")]
public int
ProjectileThreshold = 50;
[Description("Ignore shrapnel from crystal bullets for Projectile Threshold.")] public bool
[Description("Ignore shrapnel from crystal bullets for projectile threshold.")] public bool
ProjIgnoreShrapnel = true;
[Description("Require all players to register or login before being allowed to play.")] public bool RequireLogin;
[Description("Requires all players to register or login before being allowed to play.")] public bool RequireLogin;
[Description(
"Disables Invisibility potions from being used in PvP (Note, they can use them on the client, but the effect isn't sent to the rest of the server)"
"Disables invisibility potions from being used in PvP (Note, can be used in the client, but the effect isn't sent to the rest of the server)."
)] public bool DisableInvisPvP;
[Description("The maximum distance players disabled for various reasons can move from")] public int
[Description("The maximum distance players disabled for various reasons can move from.")] public int
MaxRangeForDisabled = 10;
[Description("Server password required to join server")] public string ServerPassword = "";
[Description("Server password required to join the server.")] public string ServerPassword = "";
[Description("Protect chests with region and build permissions")] public bool RegionProtectChests;
[Description("Protect chests with region and build permissions.")] public bool RegionProtectChests;
[Description("Disable users from being able to login with account password when joining")] public bool
[Description("Disable users from being able to login with account password when joining.")] public bool
DisableLoginBeforeJoin;
[Description("Allows users to register any username with /register")] public bool AllowRegisterAnyUsername;
[Description("Allows users to register any username with /register.")] public bool AllowRegisterAnyUsername;
[Description("Allows users to login with any username with /login")] public bool AllowLoginAnyUsername = true;
[Description("Allows users to login with any username with /login.")] public bool AllowLoginAnyUsername = true;
[Description("The maximum damage a player/npc can inflict")] public int MaxDamage = 175;
[Description("The maximum damage a player/npc can inflict.")] public int MaxDamage = 175;
[Description("The maximum damage a projectile can inflict")] public int MaxProjDamage = 175;
[Description("The maximum damage a projectile can inflict.")] public int MaxProjDamage = 175;
[Description("Ignores checking to see if player 'can' update a projectile")] public bool IgnoreProjUpdate = false;
[Description("Ignores checking to see if player 'can' update a projectile.")] public bool IgnoreProjUpdate = false;
[Description("Ignores checking to see if player 'can' kill a projectile")] public bool IgnoreProjKill = false;
[Description("Ignores checking to see if player 'can' kill a projectile.")] public bool IgnoreProjKill = false;
[Description("Ignores all no clip checks for players")] public bool IgnoreNoClip = false;
[Description("Ignores all no clip checks for players.")] public bool IgnoreNoClip = false;
[Description("Allow Ice placement even when user does not have canbuild")] public bool AllowIce = false;
[Description("Allow ice placement even when user does not have canbuild.")] public bool AllowIce = false;
[Description("Allows corrutption to spread when a world is hardmode.")] public bool AllowCorruptionCreep = true;
@ -229,17 +232,40 @@ namespace TShockAPI
[Description("How many things a statue spawns can exist in the world before it stops spawning. Default = 10")] public int StatueSpawnWorld = 10;
[Description("Prevent banned items from being /i or /give")] public bool PreventBannedItemSpawn = false;
[Description("Prevent banned items from being /i or /give.")] public bool PreventBannedItemSpawn = false;
[Description("Prevent banks on SSI")] public bool DisablePiggybanksOnSSI = false;
[Description("Prevent banks on SSI.")] public bool DisablePiggybanksOnSSI = false;
[Description("Prevent players from interacting with the world if dead")] public bool PreventDeadModification =
false;
[Description("Prevent players from interacting with the world if dead.")] public bool PreventDeadModification =
true;
[Description("Displays chat messages above players' heads, but will disable chat prefixes to compensate.")] public
bool EnableChatAboveHeads = false;
[Description("Hide stat tracker console messages.")] public bool HideStatTrackerDebugMessages = true;
[Description("Force Christmas only events to occur all year.")] public bool ForceXmas = false;
[Description("Allows groups on the banned item allowed list to spawn banned items.")] public bool AllowAllowedGroupsToSpawnBannedItems = false;
[Description("Allows stacks in chests to be beyond the stack limit")] public bool IgnoreChestStacksOnLoad = false;
[Description("The path of the directory where logs should be written into.")] public string LogPath = "tshock";
[Description("Prevents players from placing tiles with an invalid style.")] public bool PreventInvalidPlaceStyle = true;
[Description("#.#.#. = Red/Blue/Green - RGB Colors for broadcasts. Max value: 255.")] public float[] BroadcastRGB =
{127,255,212};
// TODO: Get rid of this when the old REST permission model is removed.
[Description(
"Whether the REST API should use the new permission model. Note: The old permission model will become depracted in the future."
)] public bool RestUseNewPermissionModel = true;
[Description("A dictionary of REST tokens that external applications may use to make queries to your server.")]
public Dictionary<string, SecureRest.TokenData> ApplicationRestTokens = new Dictionary<string, SecureRest.TokenData>();
[Description("The maximum value that a character may have for health.")] public int MaxHealth = 400;
[Description("The maximum value that a character may have for health.")] public int MaxMana = 400;
/// <summary>
/// Reads a configuration file from a given path

View file

@ -1,6 +1,6 @@
/*
TShock, a server mod for Terraria
Copyright (C) 2011-2012 The TShock Team
Copyright (C) 2011-2013 Nyx Studios (fka. The TShock Team)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -15,10 +15,10 @@ 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.Data;
using System.IO;
using MySql.Data.MySqlClient;
namespace TShockAPI.DB

View file

@ -1,6 +1,6 @@
/*
TShock, a server mod for Terraria
Copyright (C) 2011-2012 The TShock Team
Copyright (C) 2011-2013 Nyx Studios (fka. The TShock Team)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -15,11 +15,12 @@ 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;
using System.Collections.Generic;
using System.Data;
using System.IO;
using System.Diagnostics;
using System.Linq;
using MySql.Data.MySqlClient;
@ -106,7 +107,7 @@ namespace TShockAPI.DB
{
if (exceptions)
throw new GroupExistsException(name);
return "Error: Group already exists. Use /modGroup to change permissions.";
return "Error: Group already exists. Use /modgroup to change permissions.";
}
var group = new Group(name, null, chatcolor);
@ -114,7 +115,7 @@ namespace TShockAPI.DB
if (!string.IsNullOrWhiteSpace(parentname))
{
var parent = groups.FirstOrDefault(gp => gp.Name == parentname);
if (parent == null)
if (parent == null || name == parentname)
{
var error = "Invalid parent {0} for group {1}".SFormat(parentname, group.Name);
if (exceptions)
@ -126,15 +127,15 @@ namespace TShockAPI.DB
}
string query = (TShock.Config.StorageType.ToLower() == "sqlite")
? "INSERT OR IGNORE INTO GroupList (GroupName, Parent, Commands, ChatColor) VALUES (@0, @1, @2, @3);"
: "INSERT IGNORE INTO GroupList SET GroupName=@0, Parent=@1, Commands=@2, ChatColor=@3";
? "INSERT OR IGNORE INTO GroupList (GroupName, Parent, Commands, ChatColor) VALUES (@0, @1, @2, @3);"
: "INSERT IGNORE INTO GroupList SET GroupName=@0, Parent=@1, Commands=@2, ChatColor=@3";
if (database.Query(query, name, parentname, permissions, chatcolor) == 1)
{
groups.Add(group);
return "Group " + name + " has been created successfully.";
}
else if (exceptions)
throw new GroupManagerException("Failed to add group '" + name + "'");
throw new GroupManagerException("Failed to add group '" + name + ".'");
return "";
}
@ -166,25 +167,40 @@ namespace TShockAPI.DB
/// <param name="chatcolor">chatcolor</param>
public void UpdateGroup(string name, string parentname, string permissions, string chatcolor)
{
if (!GroupExists(name))
Group group = GetGroupByName(name);
if (group == null)
throw new GroupNotExistException(name);
Group parent = null;
if (!string.IsNullOrWhiteSpace(parentname))
{
parent = groups.FirstOrDefault(gp => gp.Name == parentname);
if (null == parent)
throw new GroupManagerException("Invalid parent {0} for group {1}".SFormat(parentname, name));
parent = GetGroupByName(parentname);
if (parent == null || parent == group)
throw new GroupManagerException("Invalid parent \"{0}\" for group \"{1}\".".SFormat(parentname, name));
// Check if the new parent would cause loops.
List<Group> groupChain = new List<Group> { group, parent };
Group checkingGroup = parent.Parent;
while (checkingGroup != null)
{
if (groupChain.Contains(checkingGroup))
throw new GroupManagerException(
string.Format("Invalid parent \"{0}\" for group \"{1}\" would cause loops in the parent chain.", parentname, name));
groupChain.Add(checkingGroup);
checkingGroup = checkingGroup.Parent;
}
}
// NOTE: we use newgroup.XYZ to ensure any validation is also persisted to the DB
var newgroup = new Group(name, parent, chatcolor, permissions);
// Ensure any group validation is also persisted to the DB.
var newGroup = new Group(name, parent, chatcolor, permissions);
string query = "UPDATE GroupList SET Parent=@0, Commands=@1, ChatColor=@2 WHERE GroupName=@3";
if (database.Query(query, parentname, newgroup.Permissions, newgroup.ChatColor, name) != 1)
throw new GroupManagerException("Failed to update group '" + name + "'");
if (database.Query(query, parentname, newGroup.Permissions, string.Format("{0},{1},{2}", newGroup.R, newGroup.G, newGroup.B), name) != 1)
throw new GroupManagerException(string.Format("Failed to update group \"{0}\".", name));
groups.Remove(TShock.Utils.GetGroup(name));
groups.Add(newgroup);
group.ChatColor = chatcolor;
group.Permissions = permissions;
group.Parent = parent;
}
#if COMPAT_SIGS
@ -200,7 +216,7 @@ namespace TShockAPI.DB
{
if (exceptions)
throw new GroupNotExistException(name);
return "Error: Group doesn't exists.";
return "Error: Group doesn't exist.";
}
if (database.Query("DELETE FROM GroupList WHERE GroupName=@0", name) == 1)
@ -209,7 +225,7 @@ namespace TShockAPI.DB
return "Group " + name + " has been deleted successfully.";
}
else if (exceptions)
throw new GroupManagerException("Failed to delete group '" + name + "'");
throw new GroupManagerException("Failed to delete group '" + name + ".'");
return "";
}
@ -217,7 +233,7 @@ namespace TShockAPI.DB
public String AddPermissions(String name, List<String> permissions)
{
if (!GroupExists(name))
return "Error: Group doesn't exists.";
return "Error: Group doesn't exist.";
var group = TShock.Utils.GetGroup(name);
var oldperms = group.Permissions; // Store old permissions in case of error
@ -234,7 +250,7 @@ namespace TShockAPI.DB
public String DeletePermissions(String name, List<String> permissions)
{
if (!GroupExists(name))
return "Error: Group doesn't exists.";
return "Error: Group doesn't exist.";
var group = TShock.Utils.GetGroup(name);
var oldperms = group.Permissions; // Store old permissions in case of error
@ -250,53 +266,106 @@ namespace TShockAPI.DB
public void LoadPermisions()
{
// Create a temporary list so if there is an error it doesn't override the currently loaded groups with broken groups.
var tempgroups = new List<Group>();
tempgroups.Add(new SuperAdminGroup());
if (groups == null || groups.Count < 2)
{
groups.Clear();
groups.AddRange(tempgroups);
}
try
{
var groupsparents = new List<Tuple<Group, string>>();
List<Group> newGroups = new List<Group>(groups.Count);
Dictionary<string,string> newGroupParents = new Dictionary<string, string>(groups.Count);
using (var reader = database.QueryReader("SELECT * FROM GroupList"))
{
while (reader.Read())
{
var group = new Group(reader.Get<String>("GroupName"), null, reader.Get<String>("ChatColor"), reader.Get<String>("Commands"));
group.Prefix = reader.Get<String>("Prefix");
group.Suffix = reader.Get<String>("Suffix");
groupsparents.Add(Tuple.Create(group, reader.Get<string>("Parent")));
}
}
foreach (var t in groupsparents)
{
var group = t.Item1;
var parentname = t.Item2;
if (!string.IsNullOrWhiteSpace(parentname))
{
var parent = groupsparents.FirstOrDefault(gp => gp.Item1.Name == parentname);
if (parent == null)
string groupName = reader.Get<string>("GroupName");
if (groupName == "superadmin")
{
Log.ConsoleError("Invalid parent {0} for group {1}".SFormat(parentname, group.Name));
Log.ConsoleInfo("WARNING: Group \"superadmin\" is defined in the database even though it's a reserved group name.");
continue;
}
newGroups.Add(new Group(groupName, null, reader.Get<string>("ChatColor"), reader.Get<string>("Commands")) {
Prefix = reader.Get<string>("Prefix"),
Suffix = reader.Get<string>("Suffix"),
});
try
{
newGroupParents.Add(groupName, reader.Get<string>("Parent"));
}
catch (ArgumentException)
{
// Just in case somebody messed with the unique primary key.
Log.ConsoleError("ERROR: Group name \"{0}\" occurs more than once. Keeping current group settings.");
return;
}
group.Parent = parent.Item1;
}
tempgroups.Add(group);
}
groups.Clear();
groups.AddRange(tempgroups);
try
{
// Get rid of deleted groups.
for (int i = 0; i < groups.Count; i++)
if (newGroups.All(g => g.Name != groups[i].Name))
groups.RemoveAt(i--);
// Apply changed group settings while keeping the current instances and add new groups.
foreach (Group newGroup in newGroups)
{
Group currentGroup = groups.FirstOrDefault(g => g.Name == newGroup.Name);
if (currentGroup != null)
newGroup.AssignTo(currentGroup);
else
groups.Add(newGroup);
}
// Resolve parent groups.
Debug.Assert(newGroups.Count == newGroupParents.Count);
for (int i = 0; i < groups.Count; i++)
{
Group group = groups[i];
string parentGroupName;
if (!newGroupParents.TryGetValue(group.Name, out parentGroupName) || string.IsNullOrEmpty(parentGroupName))
continue;
group.Parent = groups.FirstOrDefault(g => g.Name == parentGroupName);
if (group.Parent == null)
{
Log.ConsoleError(
"ERROR: Group \"{0}\" is referencing non existent parent group \"{1}\", parent reference was removed.",
group.Name, parentGroupName);
}
else
{
if (group.Parent == group)
Log.ConsoleInfo(
"WARNING: Group \"{0}\" is referencing itself as parent group, parent reference was removed.", group.Name);
List<Group> groupChain = new List<Group> { group };
Group checkingGroup = group;
while (checkingGroup.Parent != null)
{
if (groupChain.Contains(checkingGroup.Parent))
{
Log.ConsoleError(
"ERROR: Group \"{0}\" is referencing parent group \"{1}\" which is already part of the parent chain. Parent reference removed.",
checkingGroup.Name, checkingGroup.Parent.Name);
checkingGroup.Parent = null;
break;
}
groupChain.Add(checkingGroup);
checkingGroup = checkingGroup.Parent;
}
}
}
}
finally
{
if (!groups.Any(g => g is SuperAdminGroup))
groups.Add(new SuperAdminGroup());
}
}
catch (Exception ex)
{
Log.Error(ex.ToString());
Log.ConsoleError("Error on reloading groups: " + ex);
}
}
}

View file

@ -1,6 +1,6 @@
/*
TShock, a server mod for Terraria
Copyright (C) 2011-2012 The TShock Team
Copyright (C) 2011-2013 Nyx Studios (fka. The TShock Team)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -15,6 +15,7 @@ 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;

View file

@ -1,6 +1,6 @@
/*
TShock, a server mod for Terraria
Copyright (C) 2011-2012 The TShock Team
Copyright (C) 2011-2013 Nyx Studios (fka. The TShock Team)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -15,6 +15,7 @@ GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
using System;
using System.Data;
using MySql.Data.MySqlClient;

View file

@ -1,6 +1,6 @@
/*
TShock, a server mod for Terraria
Copyright (C) 2011-2012 The TShock Team
Copyright (C) 2011-2013 Nyx Studios (fka. The TShock Team)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -15,10 +15,10 @@ 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.Data;
using System.IO;
using System.Linq;
using MySql.Data.MySqlClient;

View file

@ -1,6 +1,6 @@
/*
TShock, a server mod for Terraria
Copyright (C) 2011-2012 The TShock Team
Copyright (C) 2011-2013 Nyx Studios (fka. The TShock Team)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -15,13 +15,11 @@ 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.Data;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;
using System.Xml;
using MySql.Data.MySqlClient;
using Terraria;
@ -238,25 +236,21 @@ namespace TShockAPI.DB
return false;
}
Region top = null;
for (int i = 0; i < Regions.Count; i++)
{
if (Regions[i].InArea(x,y) )
{
if (top == null)
top = Regions[i];
else
{
if (Regions[i].Z > top.Z)
top = Regions[i];
}
}
}
foreach (Region region in Regions.ToList())
{
if (region.InArea(x, y))
{
if (top == null || region.Z > top.Z)
top = region;
}
}
return top == null || top.HasPermissionToBuildInRegion(ply);
}
public bool InArea(int x, int y)
{
foreach (Region region in Regions)
foreach (Region region in Regions.ToList())
{
if (x >= region.Area.Left && x <= region.Area.Right &&
y >= region.Area.Top && y <= region.Area.Bottom &&
@ -271,7 +265,7 @@ namespace TShockAPI.DB
public List<string> InAreaRegionName(int x, int y)
{
List<string> regions = new List<string>() { };
foreach (Region region in Regions)
foreach (Region region in Regions.ToList())
{
if (x >= region.Area.Left && x <= region.Area.Right &&
y >= region.Area.Top && y <= region.Area.Bottom &&
@ -283,6 +277,21 @@ namespace TShockAPI.DB
return regions;
}
public List<Region> InAreaRegion(int x, int y)
{
List<Region> regions = new List<Region>() { };
foreach (Region region in Regions.ToList())
{
if (x >= region.Area.Left && x <= region.Area.Right &&
y >= region.Area.Top && y <= region.Area.Bottom &&
region.DisableBuild)
{
regions.Add(region);
}
}
return regions;
}
public static List<string> ListIDs(string MergedIDs)
{
return MergedIDs.Split(new[] {','}, StringSplitOptions.RemoveEmptyEntries).ToList();
@ -370,30 +379,36 @@ namespace TShockAPI.DB
return false;
}
public bool AddNewUser(string regionName, String userName)
public bool AddNewUser(string regionName, string userName)
{
try
{
string MergedIDs = string.Empty;
string mergedIDs = string.Empty;
using (
var reader = database.QueryReader("SELECT * FROM Regions WHERE RegionName=@0 AND WorldID=@1", regionName,
var reader = database.QueryReader("SELECT UserIds FROM Regions WHERE RegionName=@0 AND WorldID=@1", regionName,
Main.worldID.ToString()))
{
if (reader.Read())
MergedIDs = reader.Get<string>("UserIds");
mergedIDs = reader.Get<string>("UserIds");
}
if (string.IsNullOrEmpty(MergedIDs))
MergedIDs = Convert.ToString(TShock.Users.GetUserID(userName));
else
MergedIDs = MergedIDs + "," + Convert.ToString(TShock.Users.GetUserID(userName));
string userIdToAdd = Convert.ToString(TShock.Users.GetUserID(userName));
string[] ids = mergedIDs.Split(',');
// Is the user already allowed to the region?
if (ids.Contains(userIdToAdd))
return true;
int q = database.Query("UPDATE Regions SET UserIds=@0 WHERE RegionName=@1 AND WorldID=@2", MergedIDs,
if (string.IsNullOrEmpty(mergedIDs))
mergedIDs = userIdToAdd;
else
mergedIDs = string.Concat(mergedIDs, ",", userIdToAdd);
int q = database.Query("UPDATE Regions SET UserIds=@0 WHERE RegionName=@1 AND WorldID=@2", mergedIDs,
regionName, Main.worldID.ToString());
foreach (var r in Regions)
{
if (r.Name == regionName && r.WorldID == Main.worldID.ToString())
r.setAllowedIDs(MergedIDs);
r.setAllowedIDs(mergedIDs);
}
return q != 0;
}
@ -456,27 +471,33 @@ namespace TShockAPI.DB
return false;
}
public bool AllowGroup(string regionName, string groups)
public bool AllowGroup(string regionName, string groupName)
{
string groupsNew = "";
string mergedGroups = "";
using (
var reader = database.QueryReader("SELECT * FROM Regions WHERE RegionName=@0 AND WorldID=@1", regionName,
var reader = database.QueryReader("SELECT Groups FROM Regions WHERE RegionName=@0 AND WorldID=@1", regionName,
Main.worldID.ToString()))
{
if (reader.Read())
groupsNew = reader.Get<string>("Groups");
mergedGroups = reader.Get<string>("Groups");
}
if (groupsNew != "")
groupsNew += ",";
groupsNew += groups;
int q = database.Query("UPDATE Regions SET Groups=@0 WHERE RegionName=@1 AND WorldID=@2", groupsNew,
string[] groups = mergedGroups.Split(',');
// Is the group already allowed to the region?
if (groups.Contains(groupName))
return true;
if (mergedGroups != "")
mergedGroups += ",";
mergedGroups += groupName;
int q = database.Query("UPDATE Regions SET Groups=@0 WHERE RegionName=@1 AND WorldID=@2", mergedGroups,
regionName, Main.worldID.ToString());
Region r = GetRegionByName(regionName);
if (r != null)
{
r.SetAllowedGroups(groupsNew);
r.SetAllowedGroups(mergedGroups);
}
else
{

View file

@ -1,6 +1,6 @@
/*
TShock, a server mod for Terraria
Copyright (C) 2011-2012 The TShock Team
Copyright (C) 2011-2013 Nyx Studios (fka. The TShock Team)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -15,6 +15,7 @@ GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
using System;
using System.Data;
using MySql.Data.MySqlClient;
@ -22,11 +23,11 @@ using Terraria;
namespace TShockAPI.DB
{
public class RemeberedPosManager
public class RememberedPosManager
{
public IDbConnection database;
public RemeberedPosManager(IDbConnection db)
public RememberedPosManager(IDbConnection db)
{
database = db;

View file

@ -1,6 +1,6 @@
/*
TShock, a server mod for Terraria
Copyright (C) 2011-2012 The TShock Team
Copyright (C) 2011-2013 Nyx Studios (fka. The TShock Team)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -15,6 +15,7 @@ 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 MySql.Data.MySqlClient;
namespace TShockAPI.DB

View file

@ -1,6 +1,6 @@
/*
TShock, a server mod for Terraria
Copyright (C) 2011-2012 The TShock Team
Copyright (C) 2011-2013 Nyx Studios (fka. The TShock Team)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -15,6 +15,7 @@ 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.Data;

View file

@ -1,6 +1,6 @@
/*
TShock, a server mod for Terraria
Copyright (C) 2011-2012 The TShock Team
Copyright (C) 2011-2013 Nyx Studios (fka. The TShock Team)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -15,6 +15,7 @@ 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.Collections.Generic;
using System.Data;

View file

@ -1,6 +1,6 @@
/*
TShock, a server mod for Terraria
Copyright (C) 2011-2012 The TShock Team
Copyright (C) 2011-2013 Nyx Studios (fka. The TShock Team)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -15,9 +15,9 @@ GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
using System;
using System.Data;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using MySql.Data.MySqlClient;

View file

@ -1,6 +1,6 @@
/*
TShock, a server mod for Terraria
Copyright (C) 2011-2012 The TShock Team
Copyright (C) 2011-2013 Nyx Studios (fka. The TShock Team)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -15,6 +15,7 @@ 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.Data;

View file

@ -1,6 +1,6 @@
/*
TShock, a server mod for Terraria
Copyright (C) 2011-2012 The TShock Team
Copyright (C) 2011-2013 Nyx Studios (fka. The TShock Team)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -15,6 +15,7 @@ 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.Data;

View file

@ -1,6 +1,6 @@
/*
TShock, a server mod for Terraria
Copyright (C) 2011-2012 The TShock Team
Copyright (C) 2011-2013 Nyx Studios (fka. The TShock Team)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -15,6 +15,7 @@ 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;

View file

@ -1,6 +1,6 @@
/*
TShock, a server mod for Terraria
Copyright (C) 2011-2012 The TShock Team
Copyright (C) 2011-2013 Nyx Studios (fka. The TShock Team)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -15,6 +15,7 @@ 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.Text;

View file

@ -1,6 +1,6 @@
/*
TShock, a server mod for Terraria
Copyright (C) 2011-2012 The TShock Team
Copyright (C) 2011-2013 Nyx Studios (fka. The TShock Team)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -15,6 +15,7 @@ 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;
namespace TShockAPI

View file

@ -1,6 +1,6 @@
/*
TShock, a server mod for Terraria
Copyright (C) 2011-2012 The TShock Team
Copyright (C) 2011-2013 Nyx Studios (fka. The TShock Team)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -15,6 +15,7 @@ GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
using System;
using System.IO;
@ -22,36 +23,52 @@ namespace TShockAPI
{
public class FileTools
{
/// <summary>
/// Path to the file containing the rules.
/// </summary>
internal static string RulesPath
{
get { return Path.Combine(TShock.SavePath, "rules.txt"); }
}
/// <summary>
/// Path to the file containing the message of the day.
/// </summary>
internal static string MotdPath
{
get { return Path.Combine(TShock.SavePath, "motd.txt"); }
}
/// <summary>
/// Path to the file containing the whitelist.
/// </summary>
internal static string WhitelistPath
{
get { return Path.Combine(TShock.SavePath, "whitelist.txt"); }
}
internal static string RememberedPosPath
{
get { return Path.Combine(TShock.SavePath, "oldpos.xml"); }
}
/// <summary>
/// Path to the file containing the config.
/// </summary>
internal static string ConfigPath
{
get { return Path.Combine(TShock.SavePath, "config.json"); }
}
/// <summary>
/// Creates an empty file at the given path.
/// </summary>
/// <param name="file">The path to the file.</param>
public static void CreateFile(string file)
{
File.Create(file).Close();
}
/// <summary>
/// Creates a file if the files doesn't already exist.
/// </summary>
/// <param name="file">The path to the files</param>
/// <param name="data">The data to write to the file.</param>
public static void CreateIfNot(string file, string data = "")
{
if (!File.Exists(file))

View file

@ -1,4 +1,22 @@
/* GeoIPCountry.cs
/*
TShock, a server mod for Terraria
Copyright (C) 2011-2013 Nyx Studios (fka. The TShock Team)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* GeoIPCountry.cs
*
* Copyright (C) 2008 MaxMind, Inc. All Rights Reserved.
*
@ -16,24 +34,6 @@
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
TShock, a server mod for Terraria
Copyright (C) 2011-2012 The TShock Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
using System;
using System.IO;
using System.Net;

View file

@ -1,6 +1,6 @@
/*
TShock, a server mod for Terraria
Copyright (C) 2011-2012 The TShock Team
Copyright (C) 2011-2013 Nyx Studios (fka. The TShock Team)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -15,13 +15,16 @@ GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.IO.Streams;
using System.Linq;
using System.Text;
using TShockAPI.DB;
using Terraria;
using TShockAPI.Net;
@ -81,13 +84,23 @@ namespace TShockAPI
/// (KillTile = 0, PlaceTile = 1, KillWall = 2, PlaceWall = 3, KillTileNoItem = 4, PlaceWire = 5, KillWire = 6)
/// </summary>
public byte EditType { get; set; }
/// <summary>
/// Did the tile get destroyed successfully.
/// </summary>
public bool Fail { get; set; }
/// <summary>
/// Used when a tile is placed to denote a subtype of tile. (e.g. for tile id 21: Chest = 0, Gold Chest = 1)
/// </summary>
public byte Style { get; set; }
}
/// <summary>
/// TileEdit - called when a tile is placed or destroyed
/// </summary>
public static HandlerList<TileEditEventArgs> TileEdit;
private static bool OnTileEdit(TSPlayer ply, int x, int y, byte type, byte editType)
private static bool OnTileEdit(TSPlayer ply, int x, int y, byte type, byte editType, bool fail, byte style)
{
if (TileEdit == null)
return false;
@ -98,7 +111,9 @@ namespace TShockAPI
X = x,
Y = y,
Type = type,
EditType = editType
EditType = editType,
Fail = fail,
Style = style
};
TileEdit.Invoke(null, args);
return args.Handled;
@ -1183,6 +1198,14 @@ namespace TShockAPI
byte prefix = args.Data.ReadInt8();
short type = args.Data.ReadInt16();
// Players send a slot update packet for each inventory slot right after they've joined.
bool bypassTrashCanCheck = false;
if (plr == args.Player.Index && !args.Player.HasSentInventory && slot == NetItem.maxNetInventory)
{
args.Player.HasSentInventory = true;
bypassTrashCanCheck = true;
}
if (OnPlayerSlot(plr, slot, stack, prefix, type))
return true;
@ -1196,6 +1219,7 @@ namespace TShockAPI
return true;
}
// Garabage? Or will it cause some internal initialization or whatever?
var item = new Item();
item.netDefaults(type);
item.Prefix(prefix);
@ -1204,6 +1228,13 @@ namespace TShockAPI
{
args.Player.PlayerData.StoreSlot(slot, type, prefix, stack);
}
else if (
TShock.Config.ServerSideInventory && TShock.Config.DisableLoginBeforeJoin && !bypassTrashCanCheck &&
args.Player.HasSentInventory && !args.Player.Group.HasPermission(Permissions.bypassinventorychecks)
) {
// The player might have moved an item to their trash can before they performed a single login attempt yet.
args.Player.IgnoreActionsForClearingTrashCan = true;
}
return false;
}
@ -1220,7 +1251,7 @@ namespace TShockAPI
if (args.Player.FirstMaxHP == 0)
args.Player.FirstMaxHP = max;
if (max > 400 && max > args.Player.FirstMaxHP)
if (max > TShock.Config.MaxHealth && max > args.Player.FirstMaxHP)
{
TShock.Utils.ForceKick(args.Player, "Hacked Client Detected.", true);
return false;
@ -1246,7 +1277,7 @@ namespace TShockAPI
if (args.Player.FirstMaxMP == 0)
args.Player.FirstMaxMP = max;
if (max > 400 && max > args.Player.FirstMaxMP)
if (max > TShock.Config.MaxMana && max > args.Player.FirstMaxMP)
{
TShock.Utils.ForceKick(args.Player, "Hacked Client Detected.", true);
return false;
@ -1330,6 +1361,10 @@ namespace TShockAPI
return true;
string password = Encoding.UTF8.GetString(args.Data.ReadBytes((int) (args.Data.Length - args.Data.Position - 1)));
if (Hooks.PlayerHooks.OnPlayerPreLogin(args.Player, args.Player.Name, password))
return true;
var user = TShock.Users.GetUserByName(args.Player.Name);
if (user != null && !TShock.Config.DisableLoginBeforeJoin)
{
@ -1353,11 +1388,13 @@ namespace TShockAPI
}
else if (!TShock.CheckInventory(args.Player))
{
args.Player.LoginFailsBySsi = true;
args.Player.SendMessage("Login Failed, Please fix the above errors then /login again.", Color.Cyan);
args.Player.IgnoreActionsForClearingTrashCan = true;
return true;
}
}
args.Player.LoginFailsBySsi = false;
if (group.HasPermission(Permissions.ignorestackhackdetection))
args.Player.IgnoreActionsForCheating = "none";
@ -1366,6 +1403,7 @@ namespace TShockAPI
args.Player.IgnoreActionsForDisabledArmor = "none";
args.Player.Group = group;
args.Player.tempGroup = null;
args.Player.UserAccountName = args.Player.Name;
args.Player.UserID = TShock.Users.GetUserID(args.Player.UserAccountName);
args.Player.IsLoggedIn = true;
@ -1377,7 +1415,8 @@ namespace TShockAPI
TShock.InventoryDB.InsertPlayerData(args.Player);
}
args.Player.SendMessage("Authenticated as " + args.Player.Name + " successfully.", Color.LimeGreen);
Log.ConsoleInfo(args.Player.Name + " authenticated successfully as user: " + args.Player.Name);
Log.ConsoleInfo(args.Player.Name + " authenticated successfully as user " + args.Player.Name + ".");
Hooks.PlayerHooks.OnPlayerPostLogin(args.Player);
return true;
}
TShock.Utils.ForceKick(args.Player, "Invalid user account password.", true);
@ -1393,11 +1432,11 @@ namespace TShockAPI
NetMessage.SendData((int) PacketTypes.WorldInfo, args.Player.Index);
return true;
}
TShock.Utils.ForceKick(args.Player, "Incorrect Server Password", true);
TShock.Utils.ForceKick(args.Player, "Incorrect server password", true);
return true;
}
TShock.Utils.ForceKick(args.Player, "Bad Password Attempt", true);
TShock.Utils.ForceKick(args.Player, "Bad password attempt", true);
return true;
}
@ -1406,9 +1445,15 @@ namespace TShockAPI
if (args.Player.RequestedSection)
return true;
args.Player.RequestedSection = true;
if (TShock.HackedHealth(args.Player) && !args.Player.Group.HasPermission(Permissions.ignorestathackdetection))
if (String.IsNullOrEmpty(args.Player.Name))
{
TShock.Utils.ForceKick(args.Player, "You have Hacked Health/Mana, Please use a different character.", true);
TShock.Utils.ForceKick(args.Player, "Blank name.", true);
return true;
}
if (TShock.HackedStats(args.Player) && !args.Player.Group.HasPermission(Permissions.ignorestathackdetection))
{
TShock.Utils.ForceKick(args.Player, "You have hacked health/mana, please use a different character.", true);
return true;
}
if (!args.Player.Group.HasPermission(Permissions.ignorestackhackdetection))
@ -1430,13 +1475,15 @@ namespace TShockAPI
Log.Info(string.Format("{0} ({1}) from '{2}' group from '{3}' joined. ({4}/{5})", args.Player.Name, args.Player.IP,
args.Player.Group.Name, args.Player.Country, TShock.Utils.ActivePlayers(),
TShock.Config.MaxSlots));
TShock.Utils.Broadcast(args.Player.Name + " has joined from the " + args.Player.Country, Color.Yellow);
if (!args.Player.SilentJoinInProgress)
TShock.Utils.Broadcast(string.Format("{0} ({1}) has joined.", args.Player.Name, args.Player.Country), Color.Yellow);
}
else
{
Log.Info(string.Format("{0} ({1}) from '{2}' group joined. ({3}/{4})", args.Player.Name, args.Player.IP,
args.Player.Group.Name, TShock.Utils.ActivePlayers(), TShock.Config.MaxSlots));
TShock.Utils.Broadcast(args.Player.Name + " has joined", Color.Yellow);
if (!args.Player.SilentJoinInProgress)
TShock.Utils.Broadcast(args.Player.Name + " has joined.", Color.Yellow);
}
if (TShock.Config.DisplayIPToAdmins)
@ -1638,30 +1685,77 @@ namespace TShockAPI
var tileX = args.Data.ReadInt32();
var tileY = args.Data.ReadInt32();
var tiletype = args.Data.ReadInt8();
if (OnTileEdit(args.Player, tileX, tileY, tiletype, type))
var fail = tiletype == 1;
var style = args.Data.ReadInt8();
if (OnTileEdit(args.Player, tileX, tileY, tiletype, type, fail, style))
return true;
if (tileX < 0 || tileX >= Main.maxTilesX || tileY < 0 || tileY >= Main.maxTilesY)
if (!TShock.Utils.TileValid(tileX, tileY))
return false;
if (args.Player.Dead && TShock.Config.PreventDeadModification)
return true;
if (args.Player.AwaitingName)
{
var protectedregions = TShock.Regions.InAreaRegionName(tileX, tileY);
if (protectedregions.Count == 0)
{
args.Player.SendMessage("Region is not protected", Color.Yellow);
}
else
{
string regionlist = string.Join(",", protectedregions.ToArray());
args.Player.SendMessage("Region Name(s): " + regionlist, Color.Yellow);
}
args.Player.SendTileSquare(tileX, tileY);
args.Player.AwaitingName = false;
return true;
}
if (args.Player.AwaitingName)
{
Debug.Assert(args.Player.AwaitingNameParameters != null);
bool includeUnprotected = false;
bool includeZIndexes = false;
bool persistentMode = false;
foreach (string parameter in args.Player.AwaitingNameParameters)
{
if (parameter.Equals("-u", StringComparison.InvariantCultureIgnoreCase))
includeUnprotected = true;
if (parameter.Equals("-z", StringComparison.InvariantCultureIgnoreCase))
includeZIndexes = true;
if (parameter.Equals("-p", StringComparison.InvariantCultureIgnoreCase))
persistentMode = true;
}
List<string> outputRegions = new List<string>();
foreach (Region region in TShock.Regions.Regions.OrderBy(r => r.Z).Reverse())
{
if (!includeUnprotected && !region.DisableBuild)
continue;
if (tileX < region.Area.Left || tileX > region.Area.Right)
continue;
if (tileY < region.Area.Top || tileY > region.Area.Bottom)
continue;
string format = "{1}";
if (includeZIndexes)
format = "{1} (z:{0})";
outputRegions.Add(string.Format(format, region.Z, region.Name));
}
if (outputRegions.Count == 0)
{
if (includeUnprotected)
args.Player.SendMessage("There are no regions at this point.", Color.Yellow);
else
args.Player.SendMessage("There are no regions at this point or they are not protected.", Color.Yellow);
}
else
{
if (includeUnprotected)
args.Player.SendSuccessMessage("Regions at this point:");
else
args.Player.SendSuccessMessage("Protected regions at this point:");
foreach (string line in PaginationTools.BuildLinesFromTerms(outputRegions))
args.Player.SendMessage(line, Color.White);
}
if (!persistentMode)
{
args.Player.AwaitingName = false;
args.Player.AwaitingNameParameters = null;
}
args.Player.SendTileSquare(tileX, tileY);
return true;
}
if (args.Player.AwaitingTempPoint > 0)
{
@ -1673,35 +1767,96 @@ namespace TShockAPI
return true;
}
if (type == 1 || type == 3)
byte[] rightClickKill = new byte[] { 4, 13, 33, 49, 50, 128};
Item selectedItem = args.TPlayer.inventory[args.TPlayer.selectedItem];
if (type == 0 && Main.tile[tileX, tileY].type != 127 && !Main.tileCut[Main.tile[tileX, tileY].type] && !rightClickKill.Contains(Main.tile[tileX, tileY].type))
{
if (tiletype >= ((type == 1) ? Main.maxTileSets : Main.maxWallTypes))
// If the tile is an axe tile and they aren't selecting an axe, they're hacking.
if (Main.tileAxe[Main.tile[tileX, tileY].type] && selectedItem.axe == 0)
{
return true;
}
if ((tiletype == 29 || tiletype == 97) && TShock.Config.ServerSideInventory && TShock.Config.DisablePiggybanksOnSSI)
{
args.Player.SendMessage("You cannot place this tile, server side inventory is enabled.", Color.Red);
args.Player.SendTileSquare(tileX, tileY);
return true;
}
if (tiletype == 48 && !args.Player.Group.HasPermission(Permissions.usebanneditem) &&
TShock.Itembans.ItemIsBanned("Spike", args.Player))
// If the tile is a hammer tile and they aren't selecting an hammer, they're hacking.
else if (Main.tileHammer[Main.tile[tileX, tileY].type] && selectedItem.hammer == 0)
{
args.Player.Disable("Used banned spikes without permission.");
args.Player.SendTileSquare(tileX, tileY);
return true;
}
if (type == 1 && tiletype == 21 && TShock.Utils.MaxChests())
// If the tile is a pickaxe tile and they aren't selecting an pickaxe, they're hacking.
else if ((!Main.tileAxe[Main.tile[tileX, tileY].type] && !Main.tileHammer[Main.tile[tileX, tileY].type]) && selectedItem.pick == 0)
{
args.Player.SendMessage("Reached the world's max chest limit, unable to place more.", Color.Red);
args.Player.SendTileSquare(tileX, tileY);
return true;
}
if (tiletype == 141 && !args.Player.Group.HasPermission(Permissions.usebanneditem) &&
TShock.Itembans.ItemIsBanned("Explosives", args.Player))
}
else if (type == 2)
{
// If they aren't selecting an hammer, they're hacking.
if (selectedItem.hammer == 0)
{
args.Player.SendTileSquare(tileX, tileY);
return true;
}
}
else if (type == 1 || type == 3)
{
if (type == 1 && TShock.Config.PreventInvalidPlaceStyle && ((tiletype == 4 && style > 8) ||
(tiletype == 13 && style > 4) || (tiletype == 15 && style > 1) || (tiletype == 21 && style > 6) ||
(tiletype == 82 && style > 5) || (tiletype == 91 && style > 3) || (tiletype == 105 && style > 42) ||
(tiletype == 135 && style > 3) || (tiletype == 139 && style > 12) || (tiletype == 144 && style > 2) ||
(tiletype == 149 && style > 2)))
{
args.Player.SendTileSquare(tileX, tileY);
return true;
}
// If they aren't selecting the item which creates the tile or wall, they're hacking.
if (tiletype != 127 && tiletype != (type == 1 ? selectedItem.createTile : selectedItem.createWall))
{
args.Player.SendTileSquare(tileX, tileY);
return true;
}
if (TShock.Itembans.ItemIsBanned(selectedItem.name, args.Player) || tiletype >= (type == 1 ? Main.maxTileSets : Main.maxWallTypes))
{
args.Player.SendTileSquare(tileX, tileY);
return true;
}
if (type == 1 && (tiletype == 29 || tiletype == 97) && TShock.Config.ServerSideInventory && TShock.Config.DisablePiggybanksOnSSI)
{
args.Player.SendMessage("You cannot place this tile because server side inventory is enabled.", Color.Red);
args.Player.SendTileSquare(tileX, tileY);
return true;
}
if (type == 1 && tiletype == 21)
{
if (TShock.Utils.MaxChests())
{
args.Player.SendMessage("The world's chest limit has been reached - unable to place more.", Color.Red);
args.Player.SendTileSquare(tileX, tileY);
return true;
}
if ((TShock.Utils.TileValid(tileX, tileY + 1) && Main.tile[tileX, tileY + 1].type == 138) ||
(TShock.Utils.TileValid(tileX + 1, tileY + 1) && Main.tile[tileX + 1, tileY + 1].type == 138))
{
args.Player.SendTileSquare(tileX, tileY);
return true;
}
}
}
else if (type == 5)
{
// If they aren't selecting the wrench, they're hacking.
if (args.TPlayer.inventory[args.TPlayer.selectedItem].type != 509)
{
args.Player.SendTileSquare(tileX, tileY);
return true;
}
}
else if (type == 6)
{
// If they aren't selecting the wire cutter, they're hacking.
if (args.TPlayer.inventory[args.TPlayer.selectedItem].type != 510)
{
args.Player.Disable("Used banned explosives tile without permission.");
args.Player.SendTileSquare(tileX, tileY);
return true;
}
@ -1750,7 +1905,7 @@ namespace TShockAPI
return true;
}
if (type == 1 && !args.Player.Group.HasPermission(Permissions.ignoreplacetiledetection))
if ( ( type == 1 || type == 3 ) && !args.Player.Group.HasPermission(Permissions.ignoreplacetiledetection))
{
args.Player.TilePlaceThreshold++;
var coords = new Vector2(tileX, tileY);
@ -1758,7 +1913,7 @@ namespace TShockAPI
args.Player.TilesCreated.Add(coords, Main.tile[tileX, tileY].Data);
}
if ((type == 0 || type == 4) && Main.tileSolid[Main.tile[tileX, tileY].type] &&
if ((type == 0 || type == 4 || type == 2) && Main.tileSolid[Main.tile[tileX, tileY].type] &&
!args.Player.Group.HasPermission(Permissions.ignorekilltiledetection))
{
args.Player.TileKillThreshold++;
@ -1883,7 +2038,7 @@ namespace TShockAPI
}
else if (TShock.Config.PvPMode == "always" && !args.TPlayer.hostile)
{
args.Player.SendMessage("PvP is forced! Enable PvP else you can't move or do anything!",
args.Player.SendMessage("PvP is forced! Enable PvP or else you can't do anything!",
Color.Red);
}
int lastTileX = (int) (args.Player.LastNetPosition.X/16f);
@ -1903,13 +2058,14 @@ namespace TShockAPI
}
if (!args.Player.Group.HasPermission(Permissions.ignorenoclipdetection) &&
TSCheckNoclip(pos, args.TPlayer.width, args.TPlayer.height) && !TShock.Config.IgnoreNoClip)
TSCheckNoclip(pos, args.TPlayer.width, args.TPlayer.height) && !TShock.Config.IgnoreNoClip
&& !args.TPlayer.tongued)
{
int lastTileX = (int) (args.Player.LastNetPosition.X/16f);
int lastTileY = (int) (args.Player.LastNetPosition.Y/16f);
int lastTileX = (int)(args.Player.LastNetPosition.X / 16f);
int lastTileY = (int)(args.Player.LastNetPosition.Y / 16f);
if (!args.Player.Teleport(lastTileX, lastTileY + 3))
{
args.Player.SendMessage("You got stuck in a solid object, Sent to spawn point.");
args.Player.SendErrorMessage("You got stuck in a solid object, Sent to spawn point.");
args.Player.Spawn();
}
return true;
@ -2005,7 +2161,7 @@ namespace TShockAPI
if (dmg > TShock.Config.MaxProjDamage && !args.Player.Group.HasPermission(Permissions.ignoredamagecap))
{
args.Player.Disable(String.Format("Projectile damage is higher than {0}", TShock.Config.MaxProjDamage));
args.Player.Disable(String.Format("Projectile damage is higher than {0}.", TShock.Config.MaxProjDamage));
args.Player.RemoveProjectile(ident, owner);
return true;
}
@ -2016,23 +2172,24 @@ namespace TShockAPI
return true;
}
if (!TShock.Config.IgnoreProjUpdate && TShock.CheckProjectilePermission(args.Player, index, type))
bool hasPermission = !TShock.CheckProjectilePermission(args.Player, index, type);
if (!TShock.Config.IgnoreProjUpdate && !hasPermission)
{
if (type == 100)
{ //fix for skele prime
Log.Debug("Skeletron Prime's death laser ignored for cheat detection..");
}
else
{
args.Player.Disable("Does not have projectile permission to update projectile.");
args.Player.RemoveProjectile(ident, owner);
}
if (type == 100)
{ //fix for skele prime
Log.Debug("Skeletron Prime's death laser ignored for cheat detection..");
}
else
{
args.Player.Disable("Does not have projectile permission to update projectile.");
args.Player.RemoveProjectile(ident, owner);
}
return true;
}
if (args.Player.ProjectileThreshold >= TShock.Config.ProjectileThreshold)
{
args.Player.Disable("Reached projectile update threshold");
args.Player.Disable("Reached projectile update threshold.");
args.Player.RemoveProjectile(ident, owner);
return true;
}
@ -2045,14 +2202,22 @@ namespace TShockAPI
if (!args.Player.Group.HasPermission(Permissions.ignoreprojectiledetection))
{
if ((type ==90) && (TShock.Config.ProjIgnoreShrapnel))// ignore shrapnel
{
Log.Debug("Ignoring shrapnel per config..");
}
else
{
args.Player.ProjectileThreshold++;
}
if ((type == 90) && (TShock.Config.ProjIgnoreShrapnel))// ignore shrapnel
{
Log.Debug("Ignoring shrapnel per config..");
}
else
{
args.Player.ProjectileThreshold++;
}
}
// force all explosives server-side.
if (hasPermission && (type == 28 || type == 29 || type == 37))
{
args.Player.RemoveProjectile(ident, owner);
Projectile.NewProjectile(pos.X, pos.Y, vel.X, vel.Y, type, dmg, knockback);
return true;
}
return false;
@ -2088,7 +2253,7 @@ namespace TShockAPI
if (TShock.CheckProjectilePermission(args.Player, index, type) && type != 102 && type != 100 && !TShock.Config.IgnoreProjKill)
{
args.Player.Disable("Does not have projectile permission to kill projectile");
args.Player.Disable("Does not have projectile permission to kill projectile.");
args.Player.RemoveProjectile(ident, owner);
return true;
}
@ -2136,11 +2301,6 @@ namespace TShockAPI
if (OnLiquidSet(tileX, tileY, liquid, lava))
return true;
//The liquid was picked up.
if (liquid == 0)
return false;
if (tileX < 0 || tileX >= Main.maxTilesX || tileY < 0 || tileY >= Main.maxTilesY)
return false;
@ -2152,7 +2312,7 @@ namespace TShockAPI
if (args.Player.TileLiquidThreshold >= TShock.Config.TileLiquidThreshold)
{
args.Player.Disable("Reached TileLiquid threshold");
args.Player.Disable("Reached TileLiquid threshold.");
args.Player.SendTileSquare(tileX, tileY);
return true;
}
@ -2161,31 +2321,51 @@ namespace TShockAPI
{
args.Player.TileLiquidThreshold++;
}
if (liquid != 0)
{
int bucket = 0;
if (args.TPlayer.inventory[args.TPlayer.selectedItem].type == 206)
{
bucket = 1;
}
else if (args.TPlayer.inventory[args.TPlayer.selectedItem].type == 207)
{
bucket = 2;
}
int bucket = 0;
if (args.TPlayer.inventory[args.TPlayer.selectedItem].type == 206)
{
bucket = 1;
}
else if (args.TPlayer.inventory[args.TPlayer.selectedItem].type == 207)
{
bucket = 2;
}
if(lava && bucket != 2)
{
args.Player.SendErrorMessage("You do not have permission to perform this action.");
args.Player.Disable("Spreading lava without holding a lava bucket");
args.Player.SendTileSquare(tileX, tileY);
return true;
}
if(lava && (!args.Player.Group.HasPermission(Permissions.usebanneditem) &&
TShock.Itembans.ItemIsBanned("Lava Bucket", args.Player)))
{
args.Player.SendErrorMessage("You do not have permission to perform this action.");
args.Player.Disable("Using banned lava bucket without permissions");
args.Player.SendTileSquare(tileX, tileY);
return true;
}
if (lava && bucket != 2 && !args.Player.Group.HasPermission(Permissions.usebanneditem) &&
TShock.Itembans.ItemIsBanned("Lava Bucket", args.Player))
{
args.Player.Disable("Using banned lava bucket without permissions");
args.Player.SendTileSquare(tileX, tileY);
return true;
}
if (!lava && bucket != 1)
{
args.Player.SendErrorMessage("You do not have permission to perform this action.");
args.Player.Disable("Spreading water without holding a water bucket");
args.Player.SendTileSquare(tileX, tileY);
return true;
}
if (!lava && bucket != 1 && !args.Player.Group.HasPermission(Permissions.usebanneditem) &&
TShock.Itembans.ItemIsBanned("Water Bucket", args.Player))
{
args.Player.Disable("Using banned water bucket without permissions");
args.Player.SendTileSquare(tileX, tileY);
return true;
if (!lava && (!args.Player.Group.HasPermission(Permissions.usebanneditem) &&
TShock.Itembans.ItemIsBanned("Water Bucket", args.Player)))
{
args.Player.SendErrorMessage("You do not have permission to perform this action.");
args.Player.Disable("Using banned water bucket without permissions");
args.Player.SendTileSquare(tileX, tileY);
return true;
}
}
if (TShock.CheckTilePermission(args.Player, tileX, tileY))
@ -2461,6 +2641,11 @@ namespace TShockAPI
if (OnItemDrop(id, pos, vel, stacks, prefix, type))
return true;
// player is attempting to crash clients
if (type < -24 || type >= Main.maxItemTypes)
{
return true;
}
if (type == 0) //Item removed, let client do this to prevent item duplication client side
{
return false;
@ -2521,9 +2706,9 @@ namespace TShockAPI
if (TShock.Players[id] == null)
return true;
if (dmg > TShock.Config.MaxDamage && !args.Player.Group.HasPermission(Permissions.ignoredamagecap))
if (dmg > TShock.Config.MaxDamage && !args.Player.Group.HasPermission(Permissions.ignoredamagecap) && id != args.Player.Index)
{
args.Player.Disable(String.Format("Player damage exceeded {0}", TShock.Config.MaxDamage ) );
args.Player.Disable(String.Format("Player damage exceeded {0}.", TShock.Config.MaxDamage));
args.Player.SendData(PacketTypes.PlayerHp, "", id);
args.Player.SendData(PacketTypes.PlayerUpdate, "", id);
return true;
@ -2576,7 +2761,7 @@ namespace TShockAPI
if (dmg > TShock.Config.MaxDamage && !args.Player.Group.HasPermission(Permissions.ignoredamagecap))
{
args.Player.Disable(String.Format("NPC damage exceeded {0}", TShock.Config.MaxDamage ) );
args.Player.Disable(String.Format("NPC damage exceeded {0}.", TShock.Config.MaxDamage ) );
args.Player.SendData(PacketTypes.NpcUpdate, "", id);
return true;
}
@ -2589,7 +2774,7 @@ namespace TShockAPI
if (Main.npc[id].townNPC && !args.Player.Group.HasPermission(Permissions.movenpc))
{
args.Player.SendMessage( "You don't have permission to move the NPC", Color.Yellow);
args.Player.SendMessage( "You don't have permission to move this NPC.", Color.Yellow);
args.Player.SendData(PacketTypes.NpcUpdate, "", id);
return true;
}
@ -2756,7 +2941,7 @@ namespace TShockAPI
break;
}
TShock.Utils.SendLogs(string.Format("{0} summoned {1}", args.Player.Name, boss), Color.Red);
TShock.Utils.SendLogs(string.Format("{0} summoned {1}", args.Player.Name, boss), Color.PaleVioletRed, args.Player);
return false;
}
}

View file

@ -1,6 +1,6 @@
/*
TShock, a server mod for Terraria
Copyright (C) 2011-2012 The TShock Team
Copyright (C) 2011-2013 Nyx Studios (fka. The TShock Team)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -15,6 +15,7 @@ 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.Linq;
using System.Collections.Generic;
@ -25,16 +26,52 @@ namespace TShockAPI
{
// NOTE: Using a const still suffers from needing to recompile to change the default
// ideally we would use a static but this means it can't be used for the default parameter :(
public const string defaultChatColor = "255.255.255";
/// <summary>
/// Default chat color.
/// </summary>
public const string defaultChatColor = "255,255,255";
/// <summary>
/// List of permissions available to the group.
/// </summary>
public readonly List<string> permissions = new List<string>();
/// <summary>
/// List of permissions that the group is explicitly barred from.
/// </summary>
public readonly List<string> negatedpermissions = new List<string>();
/// <summary>
/// The group's name.
/// </summary>
public string Name { get; set; }
/// <summary>
/// The group that this group inherits permissions from.
/// </summary>
public Group Parent { get; set; }
public int Order { get; set; }
/// <summary>
/// The chat prefix for this group.
/// </summary>
public string Prefix { get; set; }
/// <summary>
/// The chat suffix for this group.
/// </summary>
public string Suffix { get; set; }
/// <summary>
/// The name of the parent, not particularly sure why this is here.
/// We can use group.Parent.Name and not have this second reference.
/// This was added for rest, so a discussion with Shank is necessary.
/// </summary>
public string ParentName { get { return (null == Parent) ? "" : Parent.Name; } }
/// <summary>
/// The chat color of the group.
/// Returns "255255255", sets "255,255,255"
/// </summary>
public string ChatColor
{
get { return string.Format("{0}{1}{2}", R.ToString("X2"), G.ToString("X2"), B.ToString("X2")); }
@ -58,6 +95,9 @@ namespace TShockAPI
}
}
/// <summary>
/// The permissions of the user in string form.
/// </summary>
public string Permissions
{
get
@ -75,6 +115,9 @@ namespace TShockAPI
}
}
/// <summary>
/// The permissions of this group and all that it inherits from.
/// </summary>
public List<string> TotalPermissions
{
get
@ -125,29 +168,55 @@ namespace TShockAPI
Permissions = permissions;
}
/// <summary>
/// Checks to see if a group has a specified permission.
/// </summary>
/// <param name="permission">The permission to check.</param>
/// <returns>Returns true if the user has that permission.</returns>
public virtual bool HasPermission(string permission)
{
if (string.IsNullOrEmpty(permission))
return true;
var cur = this;
var traversed = new List<Group>();
while (cur != null)
if (String.IsNullOrEmpty(permission) || RealHasPermission(permission))
{
if (cur.negatedpermissions.Contains(permission))
return false;
if (cur.permissions.Contains(permission))
return true;
if (traversed.Contains(cur))
return true;
}
string[] nodes = permission.Split('.');
for (int i = nodes.Length - 1; i >= 0; i--)
{
nodes[i] = "*";
if (RealHasPermission(String.Join(".", nodes, 0, i + 1)))
{
throw new Exception("Infinite group parenting ({0})".SFormat(cur.Name));
return true;
}
traversed.Add(cur);
cur = cur.Parent;
}
return false;
}
private bool RealHasPermission(string permission)
{
if (string.IsNullOrEmpty(permission))
return true;
var cur = this;
var traversed = new List<Group>();
while (cur != null)
{
if (cur.negatedpermissions.Contains(permission))
return false;
if (cur.permissions.Contains(permission))
return true;
if (traversed.Contains(cur))
{
throw new InvalidOperationException("Infinite group parenting ({0})".SFormat(cur.Name));
}
traversed.Add(cur);
cur = cur.Parent;
}
return false;
}
/// <summary>
/// Adds a permission to the list of negated permissions.
/// </summary>
/// <param name="permission">The permission to negate.</param>
public void NegatePermission(string permission)
{
// Avoid duplicates
@ -158,6 +227,10 @@ namespace TShockAPI
}
}
/// <summary>
/// Adds a permission to the list of permissions.
/// </summary>
/// <param name="permission">The permission to add.</param>
public void AddPermission(string permission)
{
if (permission.StartsWith("!"))
@ -173,6 +246,11 @@ namespace TShockAPI
}
}
/// <summary>
/// Clears the permission list and sets it to the list provided,
/// will parse "!permssion" and add it to the negated permissions.
/// </summary>
/// <param name="permission"></param>
public void SetPermission(List<string> permission)
{
permissions.Clear();
@ -180,6 +258,11 @@ namespace TShockAPI
permission.ForEach(p => AddPermission(p));
}
/// <summary>
/// Will remove a permission from the respective list,
/// where "!permission" will remove a negated permission.
/// </summary>
/// <param name="permission"></param>
public void RemovePermission(string permission)
{
if (permission.StartsWith("!"))
@ -189,8 +272,31 @@ namespace TShockAPI
}
permissions.Remove(permission);
}
/// <summary>
/// Assigns all fields of this instance to another.
/// </summary>
/// <param name="otherGroup">The other instance.</param>
public void AssignTo(Group otherGroup)
{
otherGroup.Name = Name;
otherGroup.Parent = Parent;
otherGroup.Prefix = Prefix;
otherGroup.Suffix = Suffix;
otherGroup.R = R;
otherGroup.G = G;
otherGroup.B = B;
otherGroup.Permissions = Permissions;
}
public override string ToString() {
return this.Name;
}
}
/// <summary>
/// This class is the SuperAdminGroup, which has access to everything.
/// </summary>
public class SuperAdminGroup : Group
{
public SuperAdminGroup()
@ -203,9 +309,14 @@ namespace TShockAPI
Suffix = TShock.Config.SuperAdminChatSuffix;
}
/// <summary>
/// Override to allow access to everything.
/// </summary>
/// <param name="permission">The permission</param>
/// <returns>True</returns>
public override bool HasPermission(string permission)
{
return true;
}
}
}
}

View file

@ -1,6 +1,6 @@
/*
TShock, a server mod for Terraria
Copyright (C) 2011-2012 The TShock Team
Copyright (C) 2011-2013 Nyx Studios (fka. The TShock Team)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -15,11 +15,11 @@ GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
namespace TShockAPI
{

View file

@ -1,6 +1,6 @@
/*
TShock, a server mod for Terraria
Copyright (C) 2011-2012 The TShock Team
Copyright (C) 2011-2013 Nyx Studios (fka. The TShock Team)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -15,25 +15,29 @@ 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.Windows.Forms;
using TShockDBEditor;
namespace TShockDBEditor
namespace TShockAPI.Hooks
{
static class Program
public class ReloadEventArgs
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
public TSPlayer Player { get; set; }
public ReloadEventArgs(TSPlayer ply)
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new TShockDBEditor());
Player = ply;
}
}
public class GeneralHooks
{
public delegate void ReloadEventD(ReloadEventArgs e);
public static event ReloadEventD ReloadEvent;
public static void OnReloadEvent(TSPlayer ply)
{
if(ReloadEvent == null)
return;
ReloadEvent(new ReloadEventArgs(ply));
}
}
}

View file

@ -0,0 +1,98 @@
/*
TShock, a server mod for Terraria
Copyright (C) 2011-2013 Nyx Studios (fka. The TShock Team)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
using System.Collections.Generic;
using System.ComponentModel;
namespace TShockAPI.Hooks
{
public class PlayerPostLoginEventArgs
{
public TSPlayer Player { get; set; }
public PlayerPostLoginEventArgs(TSPlayer ply)
{
Player = ply;
}
}
public class PlayerPreLoginEventArgs : HandledEventArgs
{
public TSPlayer Player { get; set; }
public string LoginName { get; set; }
public string Password { get; set; }
}
public class PlayerCommandEventArgs : HandledEventArgs
{
public TSPlayer Player { get; set; }
public string CommandName { get; set; }
public string CommandText { get; set; }
public List<string> Parameters { get; set; }
}
public static class PlayerHooks
{
public delegate void PlayerPostLoginD(PlayerPostLoginEventArgs e);
public static event PlayerPostLoginD PlayerPostLogin;
public delegate void PlayerPreLoginD(PlayerPreLoginEventArgs e);
public static event PlayerPreLoginD PlayerPreLogin;
public delegate void PlayerCommandD(PlayerCommandEventArgs e);
public static event PlayerCommandD PlayerCommand;
public static void OnPlayerPostLogin(TSPlayer ply)
{
if(PlayerPostLogin == null)
{
return;
}
PlayerPostLoginEventArgs args = new PlayerPostLoginEventArgs(ply);
PlayerPostLogin(args);
}
public static bool OnPlayerCommand(TSPlayer player, string cmdName, string cmdText, List<string> args)
{
if (PlayerCommand == null)
{
return false;
}
PlayerCommandEventArgs playerCommandEventArgs = new PlayerCommandEventArgs()
{
Player = player,
CommandName = cmdName,
CommandText = cmdText,
Parameters = args
};
PlayerCommand(playerCommandEventArgs);
return playerCommandEventArgs.Handled;
}
public static bool OnPlayerPreLogin(TSPlayer ply, string name, string pass)
{
if (PlayerPreLogin == null)
return false;
var args = new PlayerPreLoginEventArgs {Player = ply, LoginName = name, Password = pass};
PlayerPreLogin(args);
return args.Handled;
}
}
}

View file

@ -1,6 +1,6 @@
/*
TShock, a server mod for Terraria
Copyright (C) 2011-2012 The TShock Team
Copyright (C) 2011-2013 Nyx Studios (fka. The TShock Team)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -15,6 +15,7 @@ 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.IO;
namespace TShockAPI

View file

@ -1,6 +1,6 @@
/*
TShock, a server mod for Terraria
Copyright (C) 2011-2012 The TShock Team
Copyright (C) 2011-2013 Nyx Studios (fka. The TShock Team)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -15,6 +15,7 @@ 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.Diagnostics;
using System.Globalization;
@ -72,6 +73,16 @@ namespace TShockAPI
Write(message, LogLevel.Data);
}
/// <summary>
/// Writes data to the log file.
/// </summary>
/// <param name="format">The format of the message to be written.</param>
/// <param name="args">The format arguments.</param>
public static void Data(String format, params String[] args)
{
Data(String.Format(format, args));
}
/// <summary>
/// Writes an error to the log file.
/// </summary>
@ -81,6 +92,16 @@ namespace TShockAPI
Write(message, LogLevel.Error);
}
/// <summary>
/// Writes an error to the log file.
/// </summary>
/// <param name="format">The format of the message to be written.</param>
/// <param name="args">The format arguments.</param>
public static void Error(String format, params String[] args)
{
Error(String.Format(format, args));
}
/// <summary>
/// Writes an error to the log file.
/// </summary>
@ -93,6 +114,16 @@ namespace TShockAPI
Write(message, LogLevel.Error);
}
/// <summary>
/// Writes an error to the log file.
/// </summary>
/// <param name="format">The format of the message to be written.</param>
/// <param name="args">The format arguments.</param>
public static void ConsoleError(String format, params String[] args)
{
ConsoleError(String.Format(format, args));
}
/// <summary>
/// Writes a warning to the log file.
/// </summary>
@ -102,6 +133,16 @@ namespace TShockAPI
Write(message, LogLevel.Warning);
}
/// <summary>
/// Writes a warning to the log file.
/// </summary>
/// <param name="format">The format of the message to be written.</param>
/// <param name="args">The format arguments.</param>
public static void Warn(String format, params String[] args)
{
Warn(String.Format(format, args));
}
/// <summary>
/// Writes an informative string to the log file.
/// </summary>
@ -111,6 +152,16 @@ namespace TShockAPI
Write(message, LogLevel.Info);
}
/// <summary>
/// Writes an informative string to the log file.
/// </summary>
/// <param name="format">The format of the message to be written.</param>
/// <param name="args">The format arguments.</param>
public static void Info(String format, params String[] args)
{
Info(String.Format(format, args));
}
/// <summary>
/// Writes an informative string to the log file. Also outputs to the console.
/// </summary>
@ -123,6 +174,16 @@ namespace TShockAPI
Write(message, LogLevel.Info);
}
/// <summary>
/// Writes an informative string to the log file. Also outputs to the console.
/// </summary>
/// <param name="format">The format of the message to be written.</param>
/// <param name="args">The format arguments.</param>
public static void ConsoleInfo(String format, params String[] args)
{
ConsoleInfo(String.Format(format, args));
}
/// <summary>
/// Writes a debug string to the log file.
/// </summary>
@ -132,6 +193,16 @@ namespace TShockAPI
Write(message, LogLevel.Debug);
}
/// <summary>
/// Writes a debug string to the log file.
/// </summary>
/// <param name="format">The format of the message to be written.</param>
/// <param name="args">The format arguments.</param>
public static void Debug(String format, params String[] args)
{
Debug(String.Format(format, args));
}
/// <summary>
/// Disposes objects that are being used.
/// </summary>

View file

@ -1,6 +1,6 @@
/*
TShock, a server mod for Terraria
Copyright (C) 2011-2012 The TShock Team
Copyright (C) 2011-2013 Nyx Studios (fka. The TShock Team)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -15,6 +15,7 @@ GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
using System;
using System.IO;
using System.IO.Streams;

View file

@ -1,6 +1,6 @@
/*
TShock, a server mod for Terraria
Copyright (C) 2011-2012 The TShock Team
Copyright (C) 2011-2013 Nyx Studios (fka. The TShock Team)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -15,6 +15,7 @@ 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.IO;
using System.IO.Streams;
using System.Text;

View file

@ -1,6 +1,6 @@
/*
TShock, a server mod for Terraria
Copyright (C) 2011-2012 The TShock Team
Copyright (C) 2011-2013 Nyx Studios (fka. The TShock Team)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -15,6 +15,7 @@ GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
using System;
using System.IO;
using System.IO.Streams;

View file

@ -1,6 +1,6 @@
/*
TShock, a server mod for Terraria
Copyright (C) 2011-2012 The TShock Team
Copyright (C) 2011-2013 Nyx Studios (fka. The TShock Team)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -15,6 +15,7 @@ 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.IO;
using System.IO.Streams;

View file

@ -1,6 +1,6 @@
/*
TShock, a server mod for Terraria
Copyright (C) 2011-2012 The TShock Team
Copyright (C) 2011-2013 Nyx Studios (fka. The TShock Team)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -15,6 +15,7 @@ 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.IO;
using System.IO.Streams;

View file

@ -1,6 +1,6 @@
/*
TShock, a server mod for Terraria
Copyright (C) 2011-2012 The TShock Team
Copyright (C) 2011-2013 Nyx Studios (fka. The TShock Team)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -15,6 +15,7 @@ GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
using System;
using System.IO;
using System.IO.Streams;

View file

@ -1,6 +1,6 @@
/*
TShock, a server mod for Terraria
Copyright (C) 2011-2012 The TShock Team
Copyright (C) 2011-2013 Nyx Studios (fka. The TShock Team)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -15,6 +15,7 @@ GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
using System;
using System.Collections.Generic;
using System.ComponentModel;
@ -121,24 +122,24 @@ namespace TShockAPI
public bool Flush(ServerSock socket)
{
try
{
if (socket == null || !socket.active)
return false;
try
{
if (socket == null || !socket.active)
return false;
if (buffers[socket.whoAmI].Count < 1)
return false;
if (buffers[socket.whoAmI].Count < 1)
return false;
byte[] buff = buffers[socket.whoAmI].GetBytes(BytesPerUpdate);
if (buff == null)
return false;
byte[] buff = buffers[socket.whoAmI].GetBytes(BytesPerUpdate);
if (buff == null)
return false;
if (SendBytes(socket, buff))
{
buffers[socket.whoAmI].Pop(buff.Length);
return true;
}
}
if (SendBytes(socket, buff))
{
buffers[socket.whoAmI].Pop(buff.Length);
return true;
}
}
catch (Exception e)
{
Log.ConsoleError(e.ToString());
@ -200,7 +201,14 @@ namespace TShockAPI
}
catch (SocketException e)
{
Log.Warn(e.ToString());
switch ((uint)e.ErrorCode)
{
case 0x80004005:
break;
default:
Log.Warn(e.ToString());
break;
}
}
catch (IOException e)
{

View file

@ -0,0 +1,316 @@
/*
TShock, a server mod for Terraria
Copyright (C) 2011-2013 Nyx Studios (fka. The TShock Team)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
namespace TShockAPI
{
public static class PaginationTools
{
public delegate Tuple<string, Color> LineFormatterDelegate(object lineData, int lineIndex, int pageNumber);
#region [Nested: Settings Class]
public class Settings
{
public bool IncludeHeader { get; set; }
private string headerFormat;
public string HeaderFormat
{
get { return this.headerFormat; }
set
{
if (value == null)
throw new ArgumentNullException();
this.headerFormat = value;
}
}
public Color HeaderTextColor { get; set; }
public bool IncludeFooter { get; set; }
private string footerFormat;
public string FooterFormat
{
get { return this.footerFormat; }
set
{
if (value == null)
throw new ArgumentNullException();
this.footerFormat = value;
}
}
public Color FooterTextColor { get; set; }
public string NothingToDisplayString { get; set; }
public LineFormatterDelegate LineFormatter { get; set; }
public Color LineTextColor { get; set; }
private int maxLinesPerPage;
public int MaxLinesPerPage
{
get { return this.maxLinesPerPage; }
set
{
if (value <= 0)
throw new ArgumentException("The value has to be greater than zero.");
this.maxLinesPerPage = value;
}
}
private int pageLimit;
public int PageLimit
{
get { return this.pageLimit; }
set
{
if (value < 0)
throw new ArgumentException("The value has to be greater than or equal to zero.");
this.pageLimit = value;
}
}
public Settings()
{
this.IncludeHeader = true;
this.headerFormat = "Page {0} of {1}";
this.HeaderTextColor = Color.Green;
this.IncludeFooter = true;
this.footerFormat = "Type /<command> {0} for more.";
this.FooterTextColor = Color.Yellow;
this.NothingToDisplayString = null;
this.LineFormatter = null;
this.LineTextColor = Color.White;
this.maxLinesPerPage = 4;
this.pageLimit = 0;
}
}
#endregion
public static void SendPage(
TSPlayer player, int pageNumber, IEnumerable dataToPaginate, int dataToPaginateCount, Settings settings = null)
{
if (settings == null)
settings = new Settings();
if (dataToPaginateCount == 0)
{
if (settings.NothingToDisplayString != null)
{
if (player is TSServerPlayer)
{
player.SendSuccessMessage(settings.NothingToDisplayString);
}
else
{
player.SendMessage(settings.NothingToDisplayString, settings.HeaderTextColor);
}
}
return;
}
int pageCount = ((dataToPaginateCount - 1) / settings.MaxLinesPerPage) + 1;
if (settings.PageLimit > 0 && pageCount > settings.PageLimit)
pageCount = settings.PageLimit;
if (pageNumber > pageCount)
pageNumber = pageCount;
if (settings.IncludeHeader)
{
if (player is TSServerPlayer)
{
player.SendSuccessMessage(string.Format(settings.HeaderFormat, pageNumber, pageCount));
}
else
{
player.SendMessage(string.Format(settings.HeaderFormat, pageNumber, pageCount), settings.HeaderTextColor);
}
}
int listOffset = (pageNumber - 1) * settings.MaxLinesPerPage;
int offsetCounter = 0;
int lineCounter = 0;
foreach (object lineData in dataToPaginate)
{
if (lineData == null)
continue;
if (offsetCounter++ < listOffset)
continue;
if (lineCounter++ == settings.MaxLinesPerPage)
break;
string lineMessage;
Color lineColor = settings.LineTextColor;
if (lineData is Tuple<string, Color>)
{
var lineFormat = (Tuple<string, Color>)lineData;
lineMessage = lineFormat.Item1;
lineColor = lineFormat.Item2;
}
else if (settings.LineFormatter != null)
{
try
{
Tuple<string, Color> lineFormat = settings.LineFormatter(lineData, offsetCounter, pageNumber);
if (lineFormat == null)
continue;
lineMessage = lineFormat.Item1;
lineColor = lineFormat.Item2;
}
catch (Exception ex)
{
throw new InvalidOperationException(
"The method referenced by LineFormatter has thrown an exception. See inner exception for details.", ex);
}
}
else
{
lineMessage = lineData.ToString();
}
if (lineMessage != null)
{
if (player is TSServerPlayer)
{
Console.WriteLine(lineMessage);
}
else
{
player.SendMessage(lineMessage, lineColor);
}
}
}
if (lineCounter == 0)
{
if (settings.NothingToDisplayString != null)
{
if (player is TSServerPlayer)
{
player.SendSuccessMessage(settings.NothingToDisplayString);
}
else
{
player.SendMessage(settings.NothingToDisplayString, settings.HeaderTextColor);
}
}
}
else if (settings.IncludeFooter && pageNumber + 1 <= pageCount)
{
if (player is TSServerPlayer)
{
player.SendInfoMessage(string.Format(settings.FooterFormat, pageNumber + 1, pageNumber, pageCount));
}
else
{
player.SendMessage(string.Format(settings.FooterFormat, pageNumber + 1, pageNumber, pageCount), settings.FooterTextColor);
}
}
}
public static void SendPage(TSPlayer player, int pageNumber, IList dataToPaginate, Settings settings = null)
{
PaginationTools.SendPage(player, pageNumber, dataToPaginate, dataToPaginate.Count, settings);
}
public static List<string> BuildLinesFromTerms(
IEnumerable terms, Func<object, string> termFormatter = null, string separator = ", ", int maxCharsPerLine = 80)
{
List<string> lines = new List<string>();
StringBuilder lineBuilder = new StringBuilder();
foreach (object term in terms)
{
if (term == null && termFormatter == null)
continue;
string termString;
if (termFormatter != null)
{
try
{
termString = termFormatter(term);
if (termString == null)
continue;
}
catch (Exception ex)
{
throw new ArgumentException(
"The method represented by termFormatter has thrown an exception. See inner exception for details.", ex);
}
}
else
{
termString = term.ToString();
}
bool goesOnNextLine = (lineBuilder.Length + termString.Length > maxCharsPerLine);
if (!goesOnNextLine)
{
if (lineBuilder.Length > 0)
lineBuilder.Append(separator);
lineBuilder.Append(termString);
}
else
{
// A separator should always be at the end of a line as we know it is followed by another line.
lineBuilder.Append(separator);
lines.Add(lineBuilder.ToString());
lineBuilder.Clear();
lineBuilder.Append(termString);
}
}
if (lineBuilder.Length > 0)
lines.Add(lineBuilder.ToString());
return lines;
}
public static bool TryParsePageNumber(
List<string> commandParameters, int expectedParamterIndex, TSPlayer errorMessageReceiver, out int pageNumber)
{
pageNumber = 1;
if (commandParameters.Count <= expectedParamterIndex)
return true;
string pageNumberRaw = commandParameters[expectedParamterIndex];
if (!int.TryParse(pageNumberRaw, out pageNumber) || pageNumber < 1)
{
if (errorMessageReceiver != null)
errorMessageReceiver.SendErrorMessage(string.Format("\"{0}\" is not a valid page number.", pageNumberRaw));
pageNumber = 1;
return false;
}
return true;
}
}
}

View file

@ -1,6 +1,6 @@
/*
TShock, a server mod for Terraria
Copyright (C) 2011-2012 The TShock Team
Copyright (C) 2011-2013 Nyx Studios (fka. The TShock Team)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -15,6 +15,7 @@ GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
using System;
using System.Collections.Generic;
using System.ComponentModel;
@ -73,7 +74,7 @@ namespace TShockAPI
[Description("Allows you to bypass the max slots for up to 5 slots above your max")] public static readonly string
reservedslot;
[Description("User is notified when an update is available")] public static readonly string maintenance;
[Description("User is notified when an update is available, user can turn off / restart the server.")] public static readonly string maintenance;
[Description("User can kick others")] public static readonly string kick;
@ -129,7 +130,7 @@ namespace TShockAPI
[Description("User can change the homes of NPCs.")] public static readonly string movenpc;
[Description("Users can stop people from TPing to them")] public static readonly string tpallow;
[Description("Users can stop people from teleporting to them")] public static readonly string tpallow;
[Description("Users can tp to anyone")] public static readonly string tpall;
@ -149,9 +150,9 @@ namespace TShockAPI
[Description("User can talk in third person")] public static readonly string cantalkinthird;
[Description("Bypass Server Side Inventory checks")] public static readonly string bypassinventorychecks;
[Description("Bypass server side inventory checks")] public static readonly string bypassinventorychecks;
[Description("Allow unrestricted Send Tile Square usage, for client side world editing")] public static readonly
[Description("Allow unrestricted SendTileSquare usage, for client side world editing.")] public static readonly
string allowclientsideworldedit;
[Description("User can summon bosses using items")]
@ -166,18 +167,22 @@ namespace TShockAPI
[Description("User can save all the players SSI state.")]
public static readonly string savessi;
[Description("User can use rest api calls.")]
public static readonly string restapi;
[Description("User can force the server to Christmas mode.")] public static readonly string xmas;
static Permissions()
[Description("User can use /home.")] public static readonly string home;
[Description("User can use /spawn.")] public static readonly string spawn;
[Description("User can elevate other users' groups temporarily.")] public static readonly string settempgroup;
[Description("User can download updates to plugins that are currently running.")] public static readonly string updateplugins;
static Permissions()
{
foreach (var field in typeof (Permissions).GetFields())
{
field.SetValue(null, field.Name);
}
//Backwards compatability.
restapi = "api";
}
/// <summary>
@ -189,7 +194,7 @@ namespace TShockAPI
{
if (Commands.ChatCommands.Count < 1)
Commands.InitCommands();
return Commands.ChatCommands.Where(c => c.Permission == perm).ToList();
return Commands.ChatCommands.Where(c => c.Permissions.Contains(perm)).ToList();
}
/// <summary>

View file

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

View file

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

View file

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

View file

@ -1,6 +1,6 @@
/*
TShock, a server mod for Terraria
Copyright (C) 2011-2012 The TShock Team
Copyright (C) 2011-2013 Nyx Studios (fka. The TShock Team)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -15,6 +15,7 @@ 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.Reflection;
using System.Runtime.InteropServices;
@ -27,7 +28,7 @@ using System.Runtime.InteropServices;
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Nyx Team")]
[assembly: AssemblyProduct("TShockAPI")]
[assembly: AssemblyCopyright("Copyright © Nyx Team 2012")]
[assembly: AssemblyCopyright("Copyright © Nyx Team 2013")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
@ -48,5 +49,5 @@ using System.Runtime.InteropServices;
// Build Number
// MMdd of the build
[assembly: AssemblyVersion("3.9.1.0526")]
[assembly: AssemblyFileVersion("3.9.1.0526")]
[assembly: AssemblyVersion("4.1.0.0419")]
[assembly: AssemblyFileVersion("4.1.0.0419")]

View file

@ -1,6 +1,6 @@
/*
TShock, a server mod for Terraria
Copyright (C) 2011-2012 The TShock Team
Copyright (C) 2011-2013 Nyx Studios (fka. The TShock Team)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -15,6 +15,7 @@ GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
using System;
using System.Collections.Generic;
using System.IO;

View file

@ -1,6 +1,6 @@
/*
TShock, a server mod for Terraria
Copyright (C) 2011-2012 The TShock Team
Copyright (C) 2011-2013 Nyx Studios (fka. The TShock Team)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -27,9 +27,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
//------------------------------------------------------------------------------
namespace TShockAPI {
using System;
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>

View file

@ -1,6 +1,6 @@
/*
TShock, a server mod for Terraria
Copyright (C) 2011-2012 The TShock Team
Copyright (C) 2011-2013 Nyx Studios (fka. The TShock Team)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -15,6 +15,7 @@ GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
using System;
using System.Collections.Generic;
using System.ComponentModel;
@ -38,6 +39,15 @@ namespace Rests
/// <returns>Response object or null to not handle request</returns>
public delegate object RestCommandD(RestVerbs verbs, IParameterCollection parameters);
/// <summary>
/// Secure Rest command delegate including token data.
/// </summary>
/// <param name="parameters">Parameters in the url</param>
/// <param name="verbs">{x} in urltemplate</param>
/// <param name="tokenData">The data of stored for the provided token.</param>
/// <returns>Response object or null to not handle request</returns>
public delegate object SecureRestCommandD(RestVerbs verbs, IParameterCollection parameters, SecureRest.TokenData tokenData);
public class Rest : IDisposable
{
private readonly List<RestCommand> commands = new List<RestCommand>();
@ -125,6 +135,11 @@ namespace Rests
return;
var str = JsonConvert.SerializeObject(obj, Formatting.Indented);
var jsonp = e.Request.Parameters["jsonp"];
if (!string.IsNullOrWhiteSpace(jsonp))
{
str = string.Format("{0}({1});", jsonp, str);
}
e.Response.Connection.Type = ConnectionType.Close;
e.Response.ContentType = new ContentTypeHeader("application/json");
e.Response.Add(serverHeader);
@ -165,24 +180,47 @@ namespace Rests
}
catch (Exception exception)
{
return new Dictionary<string, string>
return new RestObject("500")
{
{"status", "500"},
{"error", "Internal server error."},
{"errormsg", exception.Message},
{"stacktrace", exception.StackTrace},
};
}
return new Dictionary<string, string>
return new RestObject("404")
{
{"status", "404"},
{"error", "Specified API endpoint doesn't exist. Refer to the documentation for a list of valid endpoints."}
};
}
protected virtual object ExecuteCommand(RestCommand cmd, RestVerbs verbs, IParameterCollection parms)
{
return cmd.Callback(verbs, parms);
object result = cmd.Execute(verbs, parms);
if (cmd.DoLog)
Log.ConsoleInfo("Anonymous requested REST endpoint: " + BuildRequestUri(cmd, verbs, parms, false));
return result;
}
protected virtual string BuildRequestUri(
RestCommand cmd, RestVerbs verbs, IParameterCollection parms, bool includeToken = true
) {
StringBuilder requestBuilder = new StringBuilder(cmd.UriTemplate);
char separator = '?';
foreach (IParameter paramImpl in parms)
{
Parameter param = (paramImpl as Parameter);
if (param == null || (!includeToken && param.Name.Equals("token", StringComparison.InvariantCultureIgnoreCase)))
continue;
requestBuilder.Append(separator);
requestBuilder.Append(param.Name);
requestBuilder.Append('=');
requestBuilder.Append(param.Value);
separator = '&';
}
return requestBuilder.ToString();
}
#region Dispose

View file

@ -1,6 +1,6 @@
/*
TShock, a server mod for Terraria
Copyright (C) 2011-2012 The TShock Team
Copyright (C) 2011-2013 Nyx Studios (fka. The TShock Team)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -15,8 +15,10 @@ 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.Linq;
using System.Text.RegularExpressions;
using HttpServer;
namespace Rests
{
@ -26,8 +28,10 @@ namespace Rests
public string UriTemplate { get; protected set; }
public string UriVerbMatch { get; protected set; }
public string[] UriVerbs { get; protected set; }
public RestCommandD Callback { get; protected set; }
public bool RequiresToken { get; set; }
public virtual bool RequiresToken { get { return false; } }
public bool DoLog { get; set; }
private RestCommandD callback;
/// <summary>
///
@ -42,8 +46,8 @@ namespace Rests
UriVerbMatch = string.Format("^{0}$", string.Join("([^/]*)", Regex.Split(uritemplate, "\\{[^\\{\\}]*\\}")));
var matches = Regex.Matches(uritemplate, "\\{([^\\{\\}]*)\\}");
UriVerbs = (from Match match in matches select match.Groups[1].Value).ToArray();
Callback = callback;
RequiresToken = true;
this.callback = callback;
DoLog = true;
}
/// <summary>
@ -60,5 +64,43 @@ namespace Rests
{
get { return UriVerbs.Length > 0; }
}
public virtual object Execute(RestVerbs verbs, IParameterCollection parameters)
{
return callback(verbs, parameters);
}
}
public class SecureRestCommand: RestCommand
{
public override bool RequiresToken { get { return true; } }
public string[] Permissions { get; set; }
private SecureRestCommandD callback;
public SecureRestCommand(string name, string uritemplate, SecureRestCommandD callback, params string[] permissions)
: base(name, uritemplate, null)
{
this.callback = callback;
Permissions = permissions;
}
public SecureRestCommand(string uritemplate, SecureRestCommandD callback, params string[] permissions)
: this(string.Empty, uritemplate, callback, permissions)
{
}
public override object Execute(RestVerbs verbs, IParameterCollection parameters)
{
return new RestObject("401") { Error = "Not authorized. The specified API endpoint requires a token." };
}
public object Execute(RestVerbs verbs, IParameterCollection parameters, SecureRest.TokenData tokenData)
{
if (tokenData.Equals(SecureRest.TokenData.None))
return new RestObject("401") { Error = "Not authorized. The specified API endpoint requires a token." };
return callback(verbs, parameters, tokenData);
}
}
}

View file

@ -1,6 +1,6 @@
/*
TShock, a server mod for Terraria
Copyright (C) 2011-2012 The TShock Team
Copyright (C) 2011-2013 Nyx Studios (fka. The TShock Team)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -15,9 +15,11 @@ 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;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using HttpServer;
using Rests;
@ -38,78 +40,140 @@ namespace TShockAPI
public void RegisterRestfulCommands()
{
// Server Commands
Rest.Register(new RestCommand("/v2/server/broadcast", ServerBroadcast));
Rest.Register(new RestCommand("/v2/server/off", ServerOff));
Rest.Register(new RestCommand("/v2/server/rawcmd", ServerCommand));
Rest.Register(new RestCommand("/v2/server/status", ServerStatusV2) { RequiresToken = false });
Rest.Register(new RestCommand("/tokentest", ServerTokenTest));
Rest.Register(new RestCommand("/status", ServerStatus) { RequiresToken = false });
if (TShock.Config.EnableTokenEndpointAuthentication)
{
Rest.Register(new SecureRestCommand("/v2/server/status", ServerStatusV2));
Rest.Register(new SecureRestCommand("/status", ServerStatus));
Rest.Register(new SecureRestCommand("/v3/server/motd", ServerMotd));
Rest.Register(new SecureRestCommand("/v3/server/rules", ServerRules));
}
else
{
Rest.Register(new RestCommand("/v2/server/status", (a, b) => this.ServerStatusV2(a, b, SecureRest.TokenData.None)));
Rest.Register(new RestCommand("/status", (a, b) => this.ServerStatusV2(a, b, SecureRest.TokenData.None)));
Rest.Register(new RestCommand("/v3/server/motd", (a, b) => this.ServerMotd(a, b, SecureRest.TokenData.None)));
Rest.Register(new RestCommand("/v3/server/rules", (a, b) => this.ServerRules(a, b, SecureRest.TokenData.None)));
}
Rest.Register(new SecureRestCommand("/v2/server/broadcast", ServerBroadcast));
Rest.Register(new SecureRestCommand("/v3/server/reload", ServerReload, RestPermissions.restcfg));
Rest.Register(new SecureRestCommand("/v2/server/off", ServerOff, RestPermissions.restmaintenance));
Rest.Register(new SecureRestCommand("/v3/server/restart", ServerRestart, RestPermissions.restmaintenance));
Rest.Register(new SecureRestCommand("/v2/server/rawcmd", ServerCommand, RestPermissions.restrawcommand));
Rest.Register(new SecureRestCommand("/v3/server/rawcmd", ServerCommandV3, RestPermissions.restrawcommand));
Rest.Register(new SecureRestCommand("/tokentest", ServerTokenTest));
// User Commands
Rest.Register(new RestCommand("/v2/users/activelist", UserActiveListV2));
Rest.Register(new RestCommand("/v2/users/create", UserCreateV2));
Rest.Register(new RestCommand("/v2/users/list", UserListV2));
Rest.Register(new RestCommand("/v2/users/read", UserInfoV2));
Rest.Register(new RestCommand("/v2/users/destroy", UserDestroyV2));
Rest.Register(new RestCommand("/v2/users/update", UserUpdateV2));
Rest.Register(new SecureRestCommand("/v2/users/activelist", UserActiveListV2, RestPermissions.restviewusers));
Rest.Register(new SecureRestCommand("/v2/users/create", UserCreateV2, RestPermissions.restmanageusers) { DoLog = false });
Rest.Register(new SecureRestCommand("/v2/users/list", UserListV2, RestPermissions.restviewusers));
Rest.Register(new SecureRestCommand("/v2/users/read", UserInfoV2, RestPermissions.restviewusers));
Rest.Register(new SecureRestCommand("/v2/users/destroy", UserDestroyV2, RestPermissions.restmanageusers));
Rest.Register(new SecureRestCommand("/v2/users/update", UserUpdateV2, RestPermissions.restmanageusers) { DoLog = false });
// Ban Commands
Rest.Register(new RestCommand("/bans/create", BanCreate));
Rest.Register(new RestCommand("/v2/bans/list", BanListV2));
Rest.Register(new RestCommand("/v2/bans/read", BanInfoV2));
Rest.Register(new RestCommand("/v2/bans/destroy", BanDestroyV2));
Rest.Register(new SecureRestCommand("/bans/create", BanCreate, RestPermissions.restmanagebans));
Rest.Register(new SecureRestCommand("/v2/bans/list", BanListV2, RestPermissions.restviewbans));
Rest.Register(new SecureRestCommand("/v2/bans/read", BanInfoV2, RestPermissions.restviewbans));
Rest.Register(new SecureRestCommand("/v2/bans/destroy", BanDestroyV2, RestPermissions.restmanagebans));
// World Commands
Rest.Register(new RestCommand("/world/read", WorldRead));
Rest.Register(new RestCommand("/world/meteor", WorldMeteor));
Rest.Register(new RestCommand("/world/bloodmoon/{bool}", WorldBloodmoon));
Rest.Register(new RestCommand("/v2/world/save", WorldSave));
Rest.Register(new RestCommand("/v2/world/autosave/state/{bool}", WorldChangeSaveSettings));
Rest.Register(new RestCommand("/v2/world/butcher", WorldButcher));
Rest.Register(new SecureRestCommand("/world/read", WorldRead));
Rest.Register(new SecureRestCommand("/world/meteor", WorldMeteor, RestPermissions.restcauseevents));
Rest.Register(new SecureRestCommand("/world/bloodmoon/{bool}", WorldBloodmoon, RestPermissions.restcauseevents));
Rest.Register(new SecureRestCommand("/v2/world/save", WorldSave, RestPermissions.restcfg));
Rest.Register(new SecureRestCommand("/v2/world/autosave/state/{bool}", WorldChangeSaveSettings, RestPermissions.restcfg));
Rest.Register(new SecureRestCommand("/v2/world/butcher", WorldButcher, RestPermissions.restbutcher));
// Player Commands
Rest.Register(new RestCommand("/lists/players", PlayerList));
Rest.Register(new RestCommand("/v2/players/list", PlayerListV2));
Rest.Register(new RestCommand("/v2/players/read", PlayerReadV2));
Rest.Register(new RestCommand("/v2/players/kick", PlayerKickV2));
Rest.Register(new RestCommand("/v2/players/ban", PlayerBanV2));
Rest.Register(new RestCommand("/v2/players/kill", PlayerKill));
Rest.Register(new RestCommand("/v2/players/mute", PlayerMute));
Rest.Register(new RestCommand("/v2/players/unmute", PlayerUnMute));
Rest.Register(new SecureRestCommand("/lists/players", PlayerList));
Rest.Register(new SecureRestCommand("/v2/players/list", PlayerListV2));
Rest.Register(new SecureRestCommand("/v2/players/read", PlayerReadV2, RestPermissions.restuserinfo));
Rest.Register(new SecureRestCommand("/v2/players/kick", PlayerKickV2, RestPermissions.restkick));
Rest.Register(new SecureRestCommand("/v2/players/ban", PlayerBanV2, RestPermissions.restban, RestPermissions.restmanagebans));
Rest.Register(new SecureRestCommand("/v2/players/kill", PlayerKill, RestPermissions.restkill));
Rest.Register(new SecureRestCommand("/v2/players/mute", PlayerMute, RestPermissions.restmute));
Rest.Register(new SecureRestCommand("/v2/players/unmute", PlayerUnMute, RestPermissions.restmute));
// Group Commands
Rest.Register(new RestCommand("/v2/groups/list", GroupList));
Rest.Register(new RestCommand("/v2/groups/read", GroupInfo));
Rest.Register(new RestCommand("/v2/groups/destroy", GroupDestroy));
Rest.Register(new RestCommand("/v2/groups/create", GroupCreate));
Rest.Register(new RestCommand("/v2/groups/update", GroupUpdate));
Rest.Register(new SecureRestCommand("/v2/groups/list", GroupList, RestPermissions.restviewgroups));
Rest.Register(new SecureRestCommand("/v2/groups/read", GroupInfo, RestPermissions.restviewgroups));
Rest.Register(new SecureRestCommand("/v2/groups/destroy", GroupDestroy, RestPermissions.restmanagegroups));
Rest.Register(new SecureRestCommand("/v2/groups/create", GroupCreate, RestPermissions.restmanagegroups));
Rest.Register(new SecureRestCommand("/v2/groups/update", GroupUpdate, RestPermissions.restmanagegroups));
}
#region RestServerMethods
private object ServerCommand(RestVerbs verbs, IParameterCollection parameters)
private object ServerCommand(RestVerbs verbs, IParameterCollection parameters, SecureRest.TokenData tokenData)
{
if (string.IsNullOrWhiteSpace(parameters["cmd"]))
return RestMissingParam("cmd");
TSRestPlayer tr = new TSRestPlayer();
Group restPlayerGroup;
// TODO: Get rid of this when the old REST permission model is removed.
if (TShock.Config.RestUseNewPermissionModel)
restPlayerGroup = TShock.Groups.GetGroupByName(tokenData.UserGroupName);
else
restPlayerGroup = new SuperAdminGroup();
TSRestPlayer tr = new TSRestPlayer(tokenData.Username, restPlayerGroup);
Commands.HandleCommand(tr, parameters["cmd"]);
return RestResponse(string.Join("\n", tr.GetCommandOutput()));
}
private object ServerOff(RestVerbs verbs, IParameterCollection parameters)
private object ServerCommandV3(RestVerbs verbs, IParameterCollection parameters, SecureRest.TokenData tokenData)
{
if (string.IsNullOrWhiteSpace(parameters["cmd"]))
return RestMissingParam("cmd");
Group restPlayerGroup;
// TODO: Get rid of this when the old REST permission model is removed.
if (TShock.Config.RestUseNewPermissionModel)
restPlayerGroup = TShock.Groups.GetGroupByName(tokenData.UserGroupName);
else
restPlayerGroup = new SuperAdminGroup();
TSRestPlayer tr = new TSRestPlayer(tokenData.Username, restPlayerGroup);
Commands.HandleCommand(tr, parameters["cmd"]);
return new RestObject()
{
{"response", tr.GetCommandOutput()}
};
}
private object ServerOff(RestVerbs verbs, IParameterCollection parameters, SecureRest.TokenData tokenData)
{
if (!GetBool(parameters["confirm"], false))
return RestInvalidParam("confirm");
// Inform players the server is shutting down
var msg = string.IsNullOrWhiteSpace(parameters["message"]) ? "Server is shutting down" : parameters["message"];
TShock.Utils.StopServer(!GetBool(parameters["nosave"], false), msg);
var reason = string.IsNullOrWhiteSpace(parameters["message"]) ? "Server is shutting down" : parameters["message"];
TShock.Utils.StopServer(!GetBool(parameters["nosave"], false), reason);
return RestResponse("The server is shutting down");
}
private object ServerBroadcast(RestVerbs verbs, IParameterCollection parameters)
private object ServerRestart(RestVerbs verbs, IParameterCollection parameters, SecureRest.TokenData tokenData)
{
if (!GetBool(parameters["confirm"], false))
return RestInvalidParam("confirm");
// Inform players the server is shutting down
var reason = string.IsNullOrWhiteSpace(parameters["message"]) ? "Server is restarting" : parameters["message"];
TShock.Utils.RestartServer(!GetBool(parameters["nosave"], false), reason);
return RestResponse("The server is shutting down and will attempt to restart");
}
private object ServerReload(RestVerbs verbs, IParameterCollection parameters, SecureRest.TokenData tokenData)
{
TShock.Utils.Reload(new TSRestPlayer(tokenData.Username, TShock.Groups.GetGroupByName(tokenData.UserGroupName)));
return RestResponse("Configuration, permissions, and regions reload complete. Some changes may require a server restart.");
}
private object ServerBroadcast(RestVerbs verbs, IParameterCollection parameters, SecureRest.TokenData tokenData)
{
var msg = parameters["msg"];
if (string.IsNullOrWhiteSpace(msg))
@ -118,11 +182,32 @@ namespace TShockAPI
return RestResponse("The message was broadcasted successfully");
}
private object ServerStatus(RestVerbs verbs, IParameterCollection parameters)
private object ServerMotd(RestVerbs verbs, IParameterCollection parameters, SecureRest.TokenData tokenData)
{
if (TShock.Config.EnableTokenEndpointAuthentication)
return RestError("Server settings require a token for this API call");
string motdFilePath = Path.Combine(TShock.SavePath, "motd.txt");
if (!File.Exists(motdFilePath))
return this.RestError("The motd.txt was not found.", "500");
return new RestObject()
{
{"motd", File.ReadAllLines(motdFilePath)}
};
}
private object ServerRules(RestVerbs verbs, IParameterCollection parameters, SecureRest.TokenData tokenData)
{
string rulesFilePath = Path.Combine(TShock.SavePath, "rules.txt");
if (!File.Exists(rulesFilePath))
return this.RestError("The rules.txt was not found.", "500");
return new RestObject()
{
{"rules", File.ReadAllLines(rulesFilePath)}
};
}
private object ServerStatus(RestVerbs verbs, IParameterCollection parameters, SecureRest.TokenData tokenData)
{
var activeplayers = Main.player.Where(p => null != p && p.active).ToList();
return new RestObject()
{
@ -133,18 +218,17 @@ namespace TShockAPI
};
}
private object ServerStatusV2(RestVerbs verbs, IParameterCollection parameters)
private object ServerStatusV2(RestVerbs verbs, IParameterCollection parameters, SecureRest.TokenData tokenData)
{
if (TShock.Config.EnableTokenEndpointAuthentication)
return RestError("Server settings require a token for this API call");
var ret = new RestObject()
{
{"name", TShock.Config.ServerName},
{"port", TShock.Config.ServerPort},
{"playercount", Main.player.Where(p => null != p && p.active).Count()},
{"maxplayers", TShock.Config.MaxSlots},
{"world", Main.worldName}
{"world", Main.worldName},
{"uptime", (DateTime.Now - System.Diagnostics.Process.GetCurrentProcess().StartTime).ToString(@"d'.'hh':'mm':'ss")},
{"serverpassword", !string.IsNullOrEmpty(TShock.Config.ServerPassword)}
};
if (GetBool(parameters["players"], false))
@ -174,27 +258,32 @@ namespace TShockAPI
rules.Add("PvPMode", TShock.Config.PvPMode);
rules.Add("SpawnProtection", TShock.Config.SpawnProtection);
rules.Add("SpawnProtectionRadius", TShock.Config.SpawnProtectionRadius);
rules.Add("ServerSideInventory", TShock.Config.ServerSideInventory);
ret.Add("rules", rules);
}
return ret;
}
private object ServerTokenTest(RestVerbs verbs, IParameterCollection parameters)
private object ServerTokenTest(RestVerbs verbs, IParameterCollection parameters, SecureRest.TokenData tokenData)
{
return RestResponse("Token is valid and was passed through correctly");
return new RestObject()
{
{"response", "Token is valid and was passed through correctly."},
{"associateduser", tokenData.Username}
};
}
#endregion
#region RestUserMethods
private object UserActiveListV2(RestVerbs verbs, IParameterCollection parameters)
private object UserActiveListV2(RestVerbs verbs, IParameterCollection parameters, SecureRest.TokenData tokenData)
{
return new RestObject() { { "activeusers", string.Join("\t", TShock.Players.Where(p => null != p && null != p.UserAccountName && p.Active).Select(p => p.UserAccountName)) } };
}
private object UserListV2(RestVerbs verbs, IParameterCollection parameters)
private object UserListV2(RestVerbs verbs, IParameterCollection parameters, SecureRest.TokenData tokenData)
{
return new RestObject() { { "users", TShock.Users.GetUsers().Select(p => new Dictionary<string,object>(){
{"name", p.Name},
@ -204,15 +293,15 @@ namespace TShockAPI
}) } };
}
private object UserCreateV2(RestVerbs verbs, IParameterCollection parameters)
private object UserCreateV2(RestVerbs verbs, IParameterCollection parameters, SecureRest.TokenData tokenData)
{
var username = parameters["user"];
if (string.IsNullOrWhiteSpace(username))
return RestMissingParam("user");
var group = parameters["group"];
if (string.IsNullOrWhiteSpace(group))
return RestMissingParam("group");
if (string.IsNullOrWhiteSpace(group))
group = TShock.Config.DefaultRegistrationGroupName;
var password = parameters["password"];
if (string.IsNullOrWhiteSpace(password))
@ -232,7 +321,7 @@ namespace TShockAPI
return RestResponse("User was successfully created");
}
private object UserUpdateV2(RestVerbs verbs, IParameterCollection parameters)
private object UserUpdateV2(RestVerbs verbs, IParameterCollection parameters, SecureRest.TokenData tokenData)
{
var ret = UserFind(parameters);
if (ret is RestObject)
@ -274,7 +363,7 @@ namespace TShockAPI
return response;
}
private object UserDestroyV2(RestVerbs verbs, IParameterCollection parameters)
private object UserDestroyV2(RestVerbs verbs, IParameterCollection parameters, SecureRest.TokenData tokenData)
{
var ret = UserFind(parameters);
if (ret is RestObject)
@ -292,7 +381,7 @@ namespace TShockAPI
return RestResponse("User deleted successfully");
}
private object UserInfoV2(RestVerbs verbs, IParameterCollection parameters)
private object UserInfoV2(RestVerbs verbs, IParameterCollection parameters, SecureRest.TokenData tokenData)
{
var ret = UserFind(parameters);
if (ret is RestObject)
@ -306,7 +395,7 @@ namespace TShockAPI
#region RestBanMethods
private object BanCreate(RestVerbs verbs, IParameterCollection parameters)
private object BanCreate(RestVerbs verbs, IParameterCollection parameters, SecureRest.TokenData tokenData)
{
var ip = parameters["ip"];
var name = parameters["name"];
@ -325,7 +414,7 @@ namespace TShockAPI
return RestResponse("Ban created successfully");
}
private object BanDestroyV2(RestVerbs verbs, IParameterCollection parameters)
private object BanDestroyV2(RestVerbs verbs, IParameterCollection parameters, SecureRest.TokenData tokenData)
{
var ret = BanFind(parameters);
if (ret is RestObject)
@ -357,7 +446,7 @@ namespace TShockAPI
return RestResponse("Ban deleted successfully");
}
private object BanInfoV2(RestVerbs verbs, IParameterCollection parameters)
private object BanInfoV2(RestVerbs verbs, IParameterCollection parameters, SecureRest.TokenData tokenData)
{
var ret = BanFind(parameters);
if (ret is RestObject)
@ -371,7 +460,7 @@ namespace TShockAPI
};
}
private object BanListV2(RestVerbs verbs, IParameterCollection parameters)
private object BanListV2(RestVerbs verbs, IParameterCollection parameters, SecureRest.TokenData tokenData)
{
var banList = new ArrayList();
foreach (var ban in TShock.Bans.GetBans())
@ -393,7 +482,7 @@ namespace TShockAPI
#region RestWorldMethods
private object WorldChangeSaveSettings(RestVerbs verbs, IParameterCollection parameters)
private object WorldChangeSaveSettings(RestVerbs verbs, IParameterCollection parameters, SecureRest.TokenData tokenData)
{
bool autoSave;
if (!bool.TryParse(verbs["bool"], out autoSave))
@ -403,14 +492,14 @@ namespace TShockAPI
return RestResponse("AutoSave has been set to " + autoSave);
}
private object WorldSave(RestVerbs verbs, IParameterCollection parameters)
private object WorldSave(RestVerbs verbs, IParameterCollection parameters, SecureRest.TokenData tokenData)
{
SaveManager.Instance.SaveWorld();
return RestResponse("World saved");
}
private object WorldButcher(RestVerbs verbs, IParameterCollection parameters)
private object WorldButcher(RestVerbs verbs, IParameterCollection parameters, SecureRest.TokenData tokenData)
{
bool killFriendly;
if (!bool.TryParse(parameters["killfriendly"], out killFriendly))
@ -432,7 +521,7 @@ namespace TShockAPI
return RestResponse(killcount + " NPCs have been killed");
}
private object WorldRead(RestVerbs verbs, IParameterCollection parameters)
private object WorldRead(RestVerbs verbs, IParameterCollection parameters, SecureRest.TokenData tokenData)
{
return new RestObject()
{
@ -445,7 +534,7 @@ namespace TShockAPI
};
}
private object WorldMeteor(RestVerbs verbs, IParameterCollection parameters)
private object WorldMeteor(RestVerbs verbs, IParameterCollection parameters, SecureRest.TokenData tokenData)
{
if (null == WorldGen.genRand)
WorldGen.genRand = new Random();
@ -453,7 +542,7 @@ namespace TShockAPI
return RestResponse("Meteor has been spawned");
}
private object WorldBloodmoon(RestVerbs verbs, IParameterCollection parameters)
private object WorldBloodmoon(RestVerbs verbs, IParameterCollection parameters, SecureRest.TokenData tokenData)
{
bool bloodmoon;
if (!bool.TryParse(verbs["bool"], out bloodmoon))
@ -467,23 +556,23 @@ namespace TShockAPI
#region RestPlayerMethods
private object PlayerUnMute(RestVerbs verbs, IParameterCollection parameters)
private object PlayerUnMute(RestVerbs verbs, IParameterCollection parameters, SecureRest.TokenData tokenData)
{
return PlayerSetMute(parameters, false);
}
private object PlayerMute(RestVerbs verbs, IParameterCollection parameters)
private object PlayerMute(RestVerbs verbs, IParameterCollection parameters, SecureRest.TokenData tokenData)
{
return PlayerSetMute(parameters, true);
}
private object PlayerList(RestVerbs verbs, IParameterCollection parameters)
private object PlayerList(RestVerbs verbs, IParameterCollection parameters, SecureRest.TokenData tokenData)
{
var activeplayers = Main.player.Where(p => null != p && p.active).ToList();
return new RestObject() { { "players", string.Join(", ", activeplayers.Select(p => p.name)) } };
}
private object PlayerListV2(RestVerbs verbs, IParameterCollection parameters)
private object PlayerListV2(RestVerbs verbs, IParameterCollection parameters, SecureRest.TokenData tokenData)
{
var playerList = new ArrayList();
foreach (TSPlayer tsPlayer in TShock.Players.Where(p => null != p))
@ -495,7 +584,7 @@ namespace TShockAPI
return new RestObject() { { "players", playerList } };
}
private object PlayerReadV2(RestVerbs verbs, IParameterCollection parameters)
private object PlayerReadV2(RestVerbs verbs, IParameterCollection parameters, SecureRest.TokenData tokenData)
{
var ret = PlayerFind(parameters);
if (ret is RestObject)
@ -515,7 +604,7 @@ namespace TShockAPI
};
}
private object PlayerKickV2(RestVerbs verbs, IParameterCollection parameters)
private object PlayerKickV2(RestVerbs verbs, IParameterCollection parameters, SecureRest.TokenData tokenData)
{
var ret = PlayerFind(parameters);
if (ret is RestObject)
@ -526,7 +615,7 @@ namespace TShockAPI
return RestResponse("Player " + player.Name + " was kicked");
}
private object PlayerBanV2(RestVerbs verbs, IParameterCollection parameters)
private object PlayerBanV2(RestVerbs verbs, IParameterCollection parameters, SecureRest.TokenData tokenData)
{
var ret = PlayerFind(parameters);
if (ret is RestObject)
@ -539,7 +628,7 @@ namespace TShockAPI
return RestResponse("Player " + player.Name + " was banned");
}
private object PlayerKill(RestVerbs verbs, IParameterCollection parameters)
private object PlayerKill(RestVerbs verbs, IParameterCollection parameters, SecureRest.TokenData tokenData)
{
var ret = PlayerFind(parameters);
if (ret is RestObject)
@ -556,7 +645,7 @@ namespace TShockAPI
#region RestGroupMethods
private object GroupList(RestVerbs verbs, IParameterCollection parameters)
private object GroupList(RestVerbs verbs, IParameterCollection parameters, SecureRest.TokenData tokenData)
{
var groups = new ArrayList();
foreach (Group group in TShock.Groups)
@ -566,7 +655,7 @@ namespace TShockAPI
return new RestObject() { { "groups", groups } };
}
private object GroupInfo(RestVerbs verbs, IParameterCollection parameters)
private object GroupInfo(RestVerbs verbs, IParameterCollection parameters, SecureRest.TokenData tokenData)
{
var ret = GroupFind(parameters);
if (ret is RestObject)
@ -576,14 +665,14 @@ namespace TShockAPI
return new RestObject() {
{"name", group.Name},
{"parent", group.ParentName},
{"chatcolor", group.ChatColor},
{"chatcolor", string.Format("{0},{1},{2}", group.R, group.G, group.B)},
{"permissions", group.permissions},
{"negatedpermissions", group.negatedpermissions},
{"totalpermissions", group.TotalPermissions}
};
}
private object GroupDestroy(RestVerbs verbs, IParameterCollection parameters)
private object GroupDestroy(RestVerbs verbs, IParameterCollection parameters, SecureRest.TokenData tokenData)
{
var ret = GroupFind(parameters);
if (ret is RestObject)
@ -602,7 +691,7 @@ namespace TShockAPI
return RestResponse("Group '" + group.Name + "' deleted successfully");
}
private object GroupCreate(RestVerbs verbs, IParameterCollection parameters)
private object GroupCreate(RestVerbs verbs, IParameterCollection parameters, SecureRest.TokenData tokenData)
{
var name = parameters["group"];
if (string.IsNullOrWhiteSpace(name))
@ -619,7 +708,7 @@ namespace TShockAPI
return RestResponse("Group '" + name + "' created successfully");
}
private object GroupUpdate(RestVerbs verbs, IParameterCollection parameters)
private object GroupUpdate(RestVerbs verbs, IParameterCollection parameters, SecureRest.TokenData tokenData)
{
var ret = GroupFind(parameters);
if (ret is RestObject)
@ -627,7 +716,7 @@ namespace TShockAPI
Group group = (Group)ret;
var parent = (null == parameters["parent"]) ? group.ParentName : parameters["parent"];
var chatcolor = (null == parameters["chatcolor"]) ? group.ChatColor : parameters["chatcolor"];
var chatcolor = (null == parameters["chatcolor"]) ? string.Format("{0}.{1}.{2}", group.R, group.G, group.B) : parameters["chatcolor"];
var permissions = (null == parameters["permissions"]) ? group.Permissions : parameters["permissions"];
try
{

View file

@ -1,6 +1,6 @@
/*
TShock, a server mod for Terraria
Copyright (C) 2011-2012 The TShock Team
Copyright (C) 2011-2013 Nyx Studios (fka. The TShock Team)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -15,6 +15,7 @@ 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;

View file

@ -0,0 +1,92 @@
/*
TShock, a server mod for Terraria
Copyright (C) 2011-2013 Nyx Studios (fka. The TShock Team)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
using System.ComponentModel;
namespace Rests
{
public static class RestPermissions
{
[Description("User can create REST tokens.")]
public static readonly string restapi;
[Description("User or REST user can destroy all REST tokens.")]
public static readonly string restmanage;
[Description("REST user can turn off / restart the server.")]
public static readonly string restmaintenance;
[Description("REST user can reload configurations, save the world and set auto save settings.")]
public static readonly string restcfg;
[Description("REST user can list and get detailed information about users.")]
public static readonly string restviewusers;
[Description("REST user can alter users.")]
public static readonly string restmanageusers;
[Description("REST user can list and get detailed information about bans.")]
public static readonly string restviewbans;
[Description("REST user can alter bans.")]
public static readonly string restmanagebans;
[Description("REST user can list and get detailed information about groups.")]
public static readonly string restviewgroups;
[Description("REST user can alter groups.")]
public static readonly string restmanagegroups;
[Description("REST user can get user information.")]
public static readonly string restuserinfo;
[Description("REST user can kick players.")]
public static readonly string restkick;
[Description("REST user can ban players.")]
public static readonly string restban;
[Description("REST user can mute and unmute players.")]
public static readonly string restmute;
[Description("REST user can kill players.")]
public static readonly string restkill;
[Description("REST user can drop meteors or change bloodmoon.")]
public static readonly string restcauseevents;
[Description("REST user can butcher npcs.")]
public static readonly string restbutcher;
[Description("REST user can run raw TShock commands (the raw command permissions are also checked though).")]
public static readonly string restrawcommand;
static RestPermissions()
{
foreach (var field in typeof (RestPermissions).GetFields())
{
field.SetValue(null, field.Name);
}
}
}
}

View file

@ -1,6 +1,6 @@
/*
TShock, a server mod for Terraria
Copyright (C) 2011-2012 The TShock Team
Copyright (C) 2011-2013 Nyx Studios (fka. The TShock Team)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -15,6 +15,7 @@ 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;

View file

@ -1,6 +1,6 @@
/*
TShock, a server mod for Terraria
Copyright (C) 2011-2012 The TShock Team
Copyright (C) 2011-2013 Nyx Studios (fka. The TShock Team)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -15,41 +15,76 @@ 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.Net;
using HttpServer;
using TShockAPI;
using TShockAPI.DB;
namespace Rests
{
/// <summary>
///
/// </summary>
/// <param name="username">Username to verify</param>
/// <param name="password">Password to verify</param>
/// <returns>Returning a restobject with a null error means a successful verification.</returns>
public delegate RestObject VerifyD(string username, string password);
public class SecureRest : Rest
{
public Dictionary<string, object> Tokens { get; protected set; }
public event VerifyD Verify;
public struct TokenData
{
public static readonly TokenData None = default(TokenData);
public string Username { get; set; }
public string UserGroupName { get; set; }
}
public Dictionary<string,TokenData> Tokens { get; protected set; }
public Dictionary<string, TokenData> AppTokens { get; protected set; }
public SecureRest(IPAddress ip, int port)
: base(ip, port)
{
Tokens = new Dictionary<string, object>();
Register(new RestCommand("/token/create/{username}/{password}", NewToken) {RequiresToken = false});
Register(new RestCommand("/v2/token/create/{password}", NewTokenV2) { RequiresToken = false });
Register(new RestCommand("/token/destroy/{token}", DestroyToken) {RequiresToken = true});
foreach (KeyValuePair<string, string> t in TShockAPI.TShock.RESTStartupTokens)
Tokens = new Dictionary<string, TokenData>();
AppTokens = new Dictionary<string, TokenData>();
Register(new RestCommand("/token/create/{username}/{password}", NewToken) { DoLog = false });
Register(new RestCommand("/v2/token/create/{password}", NewTokenV2) { DoLog = false });
Register(new SecureRestCommand("/token/destroy/{token}", DestroyToken));
Register(new SecureRestCommand("/v3/token/destroy/all", DestroyAllTokens, RestPermissions.restmanage));
foreach (KeyValuePair<string, TokenData> t in TShockAPI.TShock.RESTStartupTokens)
{
Tokens.Add(t.Key, t.Value);
AppTokens.Add(t.Key, t.Value);
}
foreach (KeyValuePair<string, TokenData> t in TShock.Config.ApplicationRestTokens)
{
AppTokens.Add(t.Key, t.Value);
}
// TODO: Get rid of this when the old REST permission model is removed.
if (TShock.Config.RestApiEnabled && !TShock.Config.RestUseNewPermissionModel)
{
string warningMessage = string.Concat(
"You're using the old REST permission model which is highly vulnerable in matter of security. ",
"The old model will be removed with the next maintenance release of TShock. In order to switch to the new model, ",
"change the config setting \"RestUseNewPermissionModel\" to true."
);
Log.Warn(warningMessage);
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine(warningMessage);
Console.ForegroundColor = ConsoleColor.Gray;
}
else if (TShock.Config.RestApiEnabled)
{
string warningMessage = string.Concat(
"You're using the new more secure REST permission model which can lead to compatibility problems ",
"with existing REST services. If compatibility problems occur, you can switch back to the unsecure permission ",
"model by changing the config setting \"RestUseNewPermissionModel\" to false, which is not recommended."
);
Log.ConsoleInfo(warningMessage);
}
}
private object DestroyToken(RestVerbs verbs, IParameterCollection parameters)
private object DestroyToken(RestVerbs verbs, IParameterCollection parameters, SecureRest.TokenData tokenData)
{
var token = verbs["token"];
try
@ -58,11 +93,19 @@ namespace Rests
}
catch (Exception)
{
return new Dictionary<string, string>
{{"status", "400"}, {"error", "The specified token queued for destruction failed to be deleted."}};
return new RestObject("400")
{ Error = "The specified token queued for destruction failed to be deleted." };
}
return new Dictionary<string, string>
{{"status", "200"}, {"response", "Requested token was successfully destroyed."}};
return new RestObject()
{ Response = "Requested token was successfully destroyed." };
}
private object DestroyAllTokens(RestVerbs verbs, IParameterCollection parameters, SecureRest.TokenData tokenData)
{
Tokens.Clear();
return new RestObject()
{ Response = "All tokens were successfully destroyed." };
}
private object NewTokenV2(RestVerbs verbs, IParameterCollection parameters)
@ -70,29 +113,7 @@ namespace Rests
var user = parameters["username"];
var pass = verbs["password"];
RestObject obj = null;
if (Verify != null)
obj = Verify(user, pass);
if (obj == null)
obj = new RestObject("401") { Error = "Invalid username/password combination provided. Please re-submit your query with a correct pair." };
if (obj.Error != null)
return obj;
string hash;
var rand = new Random();
var randbytes = new byte[32];
do
{
rand.NextBytes(randbytes);
hash = randbytes.Aggregate("", (s, b) => s + b.ToString("X2"));
} while (Tokens.ContainsKey(hash));
Tokens.Add(hash, user);
obj["token"] = hash;
return obj;
return this.NewTokenInternal(user, pass);
}
private object NewToken(RestVerbs verbs, IParameterCollection parameters)
@ -100,55 +121,84 @@ namespace Rests
var user = verbs["username"];
var pass = verbs["password"];
RestObject obj = null;
if (Verify != null)
obj = Verify(user, pass);
RestObject response = this.NewTokenInternal(user, pass);
response["deprecated"] = "This endpoint is depracted and will be removed in the future.";
return response;
}
if (obj == null)
obj = new RestObject("401")
{Error = "Invalid username/password combination provided. Please re-submit your query with a correct pair."};
private RestObject NewTokenInternal(string username, string password)
{
User userAccount = TShock.Users.GetUserByName(username);
if (userAccount == null || !string.IsNullOrWhiteSpace(userAccount.Address))
return new RestObject("401")
{ Error = "Invalid username/password combination provided. Please re-submit your query with a correct pair." };
if (!TShock.Utils.HashPassword(password).Equals(userAccount.Password, StringComparison.InvariantCultureIgnoreCase))
return new RestObject("401")
{ Error = "Invalid username/password combination provided. Please re-submit your query with a correct pair." };
if (obj.Error != null)
return obj;
string hash;
Group userGroup = TShock.Utils.GetGroup(userAccount.Group);
if (!userGroup.HasPermission(RestPermissions.restapi) && userAccount.Group != "superadmin")
return new RestObject("403")
{ Error = "Although your account was successfully found and identified, your account lacks the permission required to use the API. (restapi)" };
string tokenHash;
var rand = new Random();
var randbytes = new byte[32];
do
{
rand.NextBytes(randbytes);
hash = randbytes.Aggregate("", (s, b) => s + b.ToString("X2"));
} while (Tokens.ContainsKey(hash));
tokenHash = randbytes.Aggregate("", (s, b) => s + b.ToString("X2"));
} while (Tokens.ContainsKey(tokenHash));
Tokens.Add(hash, user);
Tokens.Add(tokenHash, new TokenData { Username = userAccount.Name, UserGroupName = userGroup.Name });
obj["token"] = hash;
obj["deprecated"] = "This method will be removed from TShock in 3.6.";
return obj;
RestObject response = new RestObject() { Response = "Successful login" };
response["token"] = tokenHash;
return response;
}
protected override object ExecuteCommand(RestCommand cmd, RestVerbs verbs, IParameterCollection parms)
{
if (cmd.RequiresToken)
{
var strtoken = parms["token"];
if (strtoken == null)
return new Dictionary<string, string>
{{"status", "401"}, {"error", "Not authorized. The specified API endpoint requires a token."}};
if (!cmd.RequiresToken)
return base.ExecuteCommand(cmd, verbs, parms);
var token = parms["token"];
if (token == null)
return new RestObject("401")
{ Error = "Not authorized. The specified API endpoint requires a token." };
object token;
if (!Tokens.TryGetValue(strtoken, out token))
return new Dictionary<string, string>
{
{"status", "403"},
{
"error",
"Not authorized. The specified API endpoint requires a token, but the provided token was not valid."
}
};
SecureRestCommand secureCmd = (SecureRestCommand)cmd;
TokenData tokenData;
if (!Tokens.TryGetValue(token, out tokenData) && !AppTokens.TryGetValue(token, out tokenData))
return new RestObject("403")
{ Error = "Not authorized. The specified API endpoint requires a token, but the provided token was not valid." };
// TODO: Get rid of this when the old REST permission model is removed.
if (TShock.Config.RestUseNewPermissionModel) {
Group userGroup = TShock.Groups.GetGroupByName(tokenData.UserGroupName);
if (userGroup == null)
{
Tokens.Remove(token);
return new RestObject("403")
{ Error = "Not authorized. The provided token became invalid due to group changes, please create a new token." };
}
if (secureCmd.Permissions.Length > 0 && secureCmd.Permissions.All(perm => !userGroup.HasPermission(perm)))
{
return new RestObject("403")
{ Error = string.Format("Not authorized. User \"{0}\" has no access to use the specified API endpoint.", tokenData.Username) };
}
}
return base.ExecuteCommand(cmd, verbs, parms);
object result = secureCmd.Execute(verbs, parms, tokenData);
if (cmd.DoLog)
TShock.Utils.SendLogs(string.Format(
"\"{0}\" requested REST endpoint: {1}", tokenData.Username, this.BuildRequestUri(cmd, verbs, parms, false)),
Color.PaleVioletRed);
return result;
}
}
}

View file

@ -1,8 +1,24 @@
using System;
/*
TShock, a server mod for Terraria
Copyright (C) 2011-2013 Nyx Studios (fka. The TShock Team)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Threading;
using System.Diagnostics;
using Terraria;
namespace TShockAPI

View file

@ -1,99 +0,0 @@
/*
TShock, a server mod for Terraria
Copyright (C) 2011-2012 The TShock Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
using System;
using System.IO;
using System.Net;
using System.Threading;
using Terraria;
namespace TShockAPI
{
public class StatTracker
{
private Utils Utils = TShock.Utils;
public DateTime lastcheck = DateTime.MinValue;
private readonly int checkinFrequency = 5;
public void CheckIn()
{
if ((DateTime.Now - lastcheck).TotalMinutes >= checkinFrequency)
{
ThreadPool.QueueUserWorkItem(CallHome);
lastcheck = DateTime.Now;
}
}
private void CallHome(object state)
{
string fp;
string lolpath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "/.tshock/";
if (!Directory.Exists(lolpath))
{
Directory.CreateDirectory(lolpath);
}
if (!File.Exists(Path.Combine(lolpath, Netplay.serverPort + ".fingerprint")))
{
fp = "";
int random = Utils.Random.Next(500000, 1000000);
fp += random;
fp = Utils.HashPassword(Netplay.serverIP + fp + Netplay.serverPort + Netplay.serverListenIP);
TextWriter tw = new StreamWriter(Path.Combine(lolpath, Netplay.serverPort + ".fingerprint"));
tw.Write(fp);
tw.Close();
}
else
{
fp = "";
TextReader tr = new StreamReader(Path.Combine(lolpath, Netplay.serverPort + ".fingerprint"));
fp = tr.ReadToEnd();
tr.Close();
}
using (var client = new WebClient())
{
client.Headers.Add("user-agent",
"TShock (" + TShock.VersionNum + ")");
try
{
string response;
if (TShock.Config.DisablePlayerCountReporting)
{
response =
client.DownloadString("http://tshock.co/tickto.php?do=log&fp=" + fp + "&ver=" + TShock.VersionNum + "&os=" +
Environment.OSVersion + "&mono=" + Main.runningMono + "&port=" + Netplay.serverPort +
"&plcount=0");
}
else
{
response =
client.DownloadString("http://tshock.co/tickto.php?do=log&fp=" + fp + "&ver=" + TShock.VersionNum + "&os=" +
Environment.OSVersion + "&mono=" + Main.runningMono + "&port=" + Netplay.serverPort +
"&plcount=" + TShock.Utils.ActivePlayers());
}
if (!TShock.Config.HideStatTrackerDebugMessages)
Log.ConsoleInfo("Stat Tracker: " + response);
}
catch (Exception e)
{
Log.Error(e.ToString());
}
}
}
}
}

View file

@ -1,6 +1,6 @@
/*
TShock, a server mod for Terraria
Copyright (C) 2011-2012 The TShock Team
Copyright (C) 2011-2013 Nyx Studios (fka. The TShock Team)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -15,6 +15,7 @@ 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.Diagnostics;
@ -27,61 +28,258 @@ namespace TShockAPI
{
public class TSPlayer
{
/// <summary>
/// This represents the server as a player.
/// </summary>
public static readonly TSServerPlayer Server = new TSServerPlayer();
/// <summary>
/// This player represents all the players.
/// </summary>
public static readonly TSPlayer All = new TSPlayer("All");
/// <summary>
/// The amount of tiles that the player has killed in the last second.
/// </summary>
public int TileKillThreshold { get; set; }
public int TilePlaceThreshold { get; set; }
/// <summary>
/// The amount of tiles the player has placed in the last second.
/// </summary>
public int TilePlaceThreshold { get; set; }
/// <summary>
/// The amount of liquid( in tiles ) that the player has placed in the last second.
/// </summary>
public int TileLiquidThreshold { get; set; }
/// <summary>
/// The number of projectiles created by the player in the last second.
/// </summary>
public int ProjectileThreshold { get; set; }
/// <summary>
/// A queue of tiles destroyed by the player for reverting.
/// </summary>
public Dictionary<Vector2, TileData> TilesDestroyed { get; protected set; }
/// <summary>
/// A queue of tiles placed by the player for reverting.
/// </summary>
public Dictionary<Vector2, TileData> TilesCreated { get; protected set; }
public int FirstMaxHP { get; set; }
public int FirstMaxMP { get; set; }
public Group Group { get; set; }
/// <summary>
/// The player's group.
/// </summary>
public Group Group
{
get
{
if (tempGroup != null)
return tempGroup;
return group;
}
set { group = value; }
}
/// <summary>
/// The player's temporary group. This overrides the user's actual group.
/// </summary>
public Group tempGroup = null;
private Group group = null;
public bool ReceivedInfo { get; set; }
/// <summary>
/// The players index in the player array( Main.players[] ).
/// </summary>
public int Index { get; protected set; }
/// <summary>
/// The last time the player changed their team or pvp status.
/// </summary>
public DateTime LastPvpChange;
/// <summary>
/// Temp points for use in regions and other plugins.
/// </summary>
public Point[] TempPoints = new Point[2];
/// <summary>
/// Whether the player is waiting to place/break a tile to set as a temp point.
/// </summary>
public int AwaitingTempPoint { get; set; }
/// <summary>
/// A list of command callbacks indexed by the command they need to do.
/// </summary>
public Dictionary<string, Action<object>> AwaitingResponse;
public bool AwaitingName { get; set; }
public string[] AwaitingNameParameters { get; set; }
/// <summary>
/// The last time a player broke a grief check.
/// </summary>
public DateTime LastThreat { get; set; }
/// <summary>
/// Not used, can be removed.
/// </summary>
public DateTime LastTileChangeNotify { get; set; }
public bool InitSpawn;
/// <summary>
/// Whether the player should see logs.
/// </summary>
public bool DisplayLogs = true;
public Vector2 oldSpawn = Vector2.Zero;
/// <summary>
/// The last player that the player whispered with( to or from ).
/// </summary>
public TSPlayer LastWhisper;
/// <summary>
/// The number of unsuccessful login attempts.
/// </summary>
public int LoginAttempts { get; set; }
public Vector2 TeleportCoords = new Vector2(-1, -1);
public Vector2 LastNetPosition = Vector2.Zero;
/// <summary>
/// The player's login name.
/// </summary>
public string UserAccountName { get; set; }
public bool HasBeenSpammedWithBuildMessage;
/// <summary>
/// Whether the player performed a valid login attempt (i.e. entered valid user name and password) but is still blocked
/// from logging in because of SSI.
/// </summary>
public bool LoginFailsBySsi { get; set; }
/// <summary>
/// Whether the player is logged in or not.
/// </summary>
public bool IsLoggedIn;
/// <summary>
/// Whether the player has sent their whole inventory to the server while connecting.
/// </summary>
public bool HasSentInventory { get; set; }
/// <summary>
/// The player's user id( from the db ).
/// </summary>
public int UserID = -1;
/// <summary>
/// Whether the player has been nagged about logging in.
/// </summary>
public bool HasBeenNaggedAboutLoggingIn;
public bool TPAllow = true;
public bool TPAllow = true;
/// <summary>
/// Whether the player is muted or not.
/// </summary>
public bool mute;
public bool TpLock;
private Player FakePlayer;
public bool RequestedSection;
/// <summary>
/// The last time the player died.
/// </summary>
public DateTime LastDeath { get; set; }
/// <summary>
/// Whether the player is dead or not.
/// </summary>
public bool Dead;
public string Country = "??";
/// <summary>
/// The players difficulty( normal[softcore], mediumcore, hardcore ).
/// </summary>
public int Difficulty;
private string CacheIP;
public string IgnoreActionsForInventory = "none";
public string IgnoreActionsForCheating = "none";
public string IgnoreActionsForDisabledArmor = "none";
public bool IgnoreActionsForClearingTrashCan;
/// <summary>
/// The player's server side inventory data.
/// </summary>
public PlayerData PlayerData;
/// <summary>
/// Whether the player needs to specify a password upon connection( either server or user account ).
/// </summary>
public bool RequiresPassword;
public bool SilentKickInProgress;
public bool SilentJoinInProgress;
/// <summary>
/// A list of points where ice tiles have been placed.
/// </summary>
public List<Point> IceTiles;
public long RPm = 1;
public long WPm = 1;
public long SPm = 1;
public long BPm = 1;
/// <summary>
/// Unused, can be removed.
/// </summary>
public long RPm = 1;
/// <summary>
/// World protection message cool down.
/// </summary>
public long WPm = 1;
/// <summary>
/// Spawn protection message cool down.
/// </summary>
public long SPm = 1;
/// <summary>
/// Permission to build message cool down.
/// </summary>
public long BPm = 1;
/// <summary>
/// The time in ms when the player has logged in.
/// </summary>
public long LoginMS;
/// <summary>
/// Whether the player has been harrassed about logging in due to server side inventory or forced login.
/// </summary>
public bool LoginHarassed = false;
/// <summary>
/// Whether the player is a real, human, player on the server.
/// </summary>
public bool RealPlayer
{
get { return Index >= 0 && Index < Main.maxNetPlayers && Main.player[Index] != null; }
@ -212,6 +410,7 @@ namespace TShockAPI
Index = index;
Group = new Group(TShock.Config.DefaultGuestGroupName);
IceTiles = new List<Point>();
AwaitingResponse = new Dictionary<string, Action<object>>();
}
protected TSPlayer(String playerName)
@ -221,6 +420,7 @@ namespace TShockAPI
Index = -1;
FakePlayer = new Player {name = playerName, whoAmi = -1};
Group = new Group(TShock.Config.DefaultGuestGroupName);
AwaitingResponse = new Dictionary<string, Action<object>>();
}
public virtual void Disconnect(string reason)
@ -384,7 +584,8 @@ namespace TShockAPI
public bool GiveItemCheck(int type, string name, int width, int height, int stack, int prefix = 0)
{
if (TShock.Itembans.ItemIsBanned(name) && TShock.Config.PreventBannedItemSpawn)
if ((TShock.Itembans.ItemIsBanned(name) && TShock.Config.PreventBannedItemSpawn) &&
(TShock.Itembans.ItemIsBanned(name, this) || !TShock.Config.AllowAllowedGroupsToSpawnBannedItems))
return false;
GiveItem(type,name,width,height,stack,prefix);
@ -407,9 +608,14 @@ namespace TShockAPI
NetMessage.SendData((int) PacketTypes.ItemOwner, -1, -1, "", itemid, 0f, 0f, 0f);
}
public virtual void SendInformationalMessage(string msg)
public virtual void SendInfoMessage(string msg)
{
SendMessage(msg, Color.Indigo);
SendMessage(msg, Color.Yellow);
}
public void SendInfoMessage(string format, params object[] args)
{
SendInfoMessage(string.Format(format, args));
}
public virtual void SendSuccessMessage(string msg)
@ -417,9 +623,19 @@ namespace TShockAPI
SendMessage(msg, Color.Green);
}
public void SendSuccessMessage(string format, params object[] args)
{
SendSuccessMessage(string.Format(format, args));
}
public virtual void SendWarningMessage(string msg)
{
SendMessage(msg, Color.Yellow);
SendMessage(msg, Color.OrangeRed);
}
public void SendWarningMessage(string format, params object[] args)
{
SendWarningMessage(string.Format(format, args));
}
public virtual void SendErrorMessage(string msg)
@ -427,6 +643,12 @@ namespace TShockAPI
SendMessage(msg, Color.Red);
}
public void SendErrorMessage(string format, params object[] args)
{
SendErrorMessage(string.Format(format, args));
}
[Obsolete("Use SendErrorMessage, SendInfoMessage, or SendWarningMessage, or a custom color instead.")]
public virtual void SendMessage(string msg)
{
SendMessage(msg, 0, 255, 0);
@ -466,13 +688,13 @@ namespace TShockAPI
SetBuff(32, 330, true); //Slow
SetBuff(23, 330, true); //Cursed
if (!string.IsNullOrEmpty(reason))
Log.ConsoleInfo(string.Format("Player {0} has been disabled for {1}", Name, reason));
Log.ConsoleInfo(string.Format("Player {0} has been disabled for {1}.", Name, reason));
var trace = new StackTrace();
StackFrame frame = null;
frame = trace.GetFrame(1);
if (frame != null && frame.GetMethod().DeclaringType != null)
Log.Debug(frame.GetMethod().DeclaringType.Name + " called Disable()");
Log.Debug(frame.GetMethod().DeclaringType.Name + " called Disable().");
}
public virtual void Whoopie(object time)
@ -521,15 +743,31 @@ namespace TShockAPI
return TShock.SendBytes(Netplay.serverSock[Index], data);
}
/// <summary>
/// Adds a command callback to a specified command string.
/// </summary>
/// <param name="name">The string representing the command i.e "yes" == /yes</param>
/// <param name="callback">The method that will be executed on confirmation ie user accepts</param>
public void AddResponse( string name, Action<object> callback)
{
if( AwaitingResponse.ContainsKey(name))
{
AwaitingResponse.Remove(name);
}
AwaitingResponse.Add(name, callback);
}
}
public class TSRestPlayer : TSServerPlayer
public class TSRestPlayer : TSPlayer
{
internal List<string> CommandReturn = new List<string>();
internal List<string> CommandOutput = new List<string>();
public TSRestPlayer()
public TSRestPlayer(string playerName, Group playerGroup): base(playerName)
{
Group = new SuperAdminGroup();
Group = playerGroup;
AwaitingResponse = new Dictionary<string, Action<object>>();
}
public override void SendMessage(string msg)
@ -544,12 +782,32 @@ namespace TShockAPI
public override void SendMessage(string msg, byte red, byte green, byte blue)
{
CommandReturn.Add(msg);
this.CommandOutput.Add(msg);
}
public override void SendInfoMessage(string msg)
{
SendMessage(msg, Color.Yellow);
}
public override void SendSuccessMessage(string msg)
{
SendMessage(msg, Color.Green);
}
public override void SendWarningMessage(string msg)
{
SendMessage(msg, Color.OrangeRed);
}
public override void SendErrorMessage(string msg)
{
SendMessage(msg, Color.Red);
}
public List<string> GetCommandOutput()
{
return CommandReturn;
return this.CommandOutput;
}
}
@ -561,6 +819,34 @@ namespace TShockAPI
Group = new SuperAdminGroup();
}
public override void SendErrorMessage(string msg)
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine(msg);
Console.ResetColor();
}
public override void SendInfoMessage(string msg)
{
Console.ForegroundColor = ConsoleColor.Yellow;
Console.WriteLine(msg);
Console.ResetColor();
}
public override void SendSuccessMessage(string msg)
{
Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine(msg);
Console.ResetColor();
}
public override void SendWarningMessage(string msg)
{
Console.ForegroundColor = ConsoleColor.DarkRed;
Console.WriteLine(msg);
Console.ResetColor();
}
public override void SendMessage(string msg)
{
SendMessage(msg, 0, 255, 0);
@ -614,6 +900,10 @@ namespace TShockAPI
public void StrikeNPC(int npcid, int damage, float knockBack, int hitDirection)
{
// Main.rand is thread static.
if (Main.rand == null)
Main.rand = new Random();
Main.npc[npcid].StrikeNPC(damage, knockBack, hitDirection);
NetMessage.SendData((int) PacketTypes.NpcStrike, -1, -1, "", npcid, damage, knockBack, hitDirection);
}

View file

@ -1,6 +1,6 @@
/*
TShock, a server mod for Terraria
Copyright (C) 2011-2012 The TShock Team
Copyright (C) 2011-2013 Nyx Studios (fka. The TShock Team)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -15,6 +15,7 @@ GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
using System;
using System.Collections.Generic;
using System.ComponentModel;
@ -25,7 +26,6 @@ using System.Globalization;
using System.IO;
using System.Net;
using System.Reflection;
using System.Threading;
using Hooks;
using MaxMind;
using Mono.Data.Sqlite;
@ -37,26 +37,28 @@ using TShockAPI.Net;
namespace TShockAPI
{
[APIVersion(1, 12)]
[APIVersion(1, 13)]
public class TShock : TerrariaPlugin
{
private const string LogFormatDefault = "yyyyMMddHHmmss";
private static string LogFormat = LogFormatDefault;
private static bool LogClear = false;
public static readonly Version VersionNum = Assembly.GetExecutingAssembly().GetName().Version;
public static readonly string VersionCodename = "4.x & 50,000th download milestone";
public static readonly string VersionCodename = "Welcome to the future.";
public static string SavePath = "tshock";
private const string LogFormatDefault = "yyyy-MM-dd_HH-mm-ss";
private static string LogFormat = LogFormatDefault;
private const string LogPathDefault = "tshock";
private static string LogPath = LogPathDefault;
private static bool LogClear = false;
public static TSPlayer[] Players = new TSPlayer[Main.maxPlayers];
public static BanManager Bans;
public static WarpManager Warps;
public static RegionManager Regions;
public static RegionManager Regions;
public static BackupManager Backups;
public static GroupManager Groups;
public static UserManager Users;
public static ItemManager Itembans;
public static RemeberedPosManager RememberedPos;
public static RememberedPosManager RememberedPos;
public static InventoryManager InventoryDB;
public static ConfigFile Config { get; set; }
public static IDbConnection DB;
@ -66,11 +68,10 @@ namespace TShockAPI
public static SecureRest RestApi;
public static RestManager RestManager;
public static Utils Utils = Utils.Instance;
public static StatTracker StatTracker = new StatTracker();
/// <summary>
/// Used for implementing REST Tokens prior to the REST system starting up.
/// </summary>
public static Dictionary<string, string> RESTStartupTokens = new Dictionary<string, string>();
public static Dictionary<string, SecureRest.TokenData> RESTStartupTokens = new Dictionary<string, SecureRest.TokenData>();
/// <summary>
/// Called after TShock is initialized. Useful for plugins that needs hooks before tshock but also depend on tshock being loaded.
@ -97,6 +98,10 @@ namespace TShockAPI
get { return "The administration modification of the future."; }
}
public override string UpdateURL
{
get { return ""; }
}
public TShock(Main game)
: base(game)
{
@ -108,35 +113,57 @@ namespace TShockAPI
[SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands")]
public override void Initialize()
{
HandleCommandLine(Environment.GetCommandLineArgs());
if (!Directory.Exists(SavePath))
Directory.CreateDirectory(SavePath);
DateTime now = DateTime.Now;
string logFilename;
try
{
logFilename = Path.Combine(SavePath, now.ToString(LogFormat)+".log");
}
catch(Exception)
{
// Problem with the log format use the default
logFilename = Path.Combine(SavePath, now.ToString(LogFormatDefault) + ".log");
}
HandleCommandLine(Environment.GetCommandLineArgs());
if (Version.Major >= 4)
getTShockAscii();
if (!Directory.Exists(SavePath))
Directory.CreateDirectory(SavePath);
ConfigFile.ConfigRead += OnConfigRead;
FileTools.SetupConfig();
DateTime now = DateTime.Now;
string logFilename;
string logPathSetupWarning = null;
// Log path was not already set by the command line parameter?
if (LogPath == LogPathDefault)
LogPath = Config.LogPath;
try
{
logFilename = Path.Combine(LogPath, now.ToString(LogFormat)+".log");
if (!Directory.Exists(LogPath))
Directory.CreateDirectory(LogPath);
}
catch(Exception ex)
{
logPathSetupWarning = "Could not apply the given log path / log format, defaults will be used. Exception details:\n" + ex;
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine(logPathSetupWarning);
Console.ForegroundColor = ConsoleColor.Gray;
// Problem with the log path or format use the default
logFilename = Path.Combine(LogPathDefault, now.ToString(LogFormatDefault) + ".log");
}
#if DEBUG
Log.Initialize(logFilename, LogLevel.All, false);
Log.Initialize(logFilename, LogLevel.All, false);
#else
Log.Initialize(logFilename, LogLevel.All & ~LogLevel.Debug, LogClear);
Log.Initialize(logFilename, LogLevel.All & ~LogLevel.Debug, LogClear);
#endif
AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
if (Version.Major >= 4)
{
getTShockAscii();
}
if (logPathSetupWarning != null)
Log.Warn(logPathSetupWarning);
AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
}
catch(Exception ex)
{
// Will be handled by the server api and written to its crashlog.txt.
throw new Exception("Fatal TShock initialization exception. See inner exception for details.", ex);
}
// Further exceptions are written to TShock's log from now on.
try
{
if (File.Exists(Path.Combine(SavePath, "tshock.pid")))
@ -147,9 +174,6 @@ namespace TShockAPI
}
File.WriteAllText(Path.Combine(SavePath, "tshock.pid"), Process.GetCurrentProcess().Id.ToString(CultureInfo.InvariantCulture));
ConfigFile.ConfigRead += OnConfigRead;
FileTools.SetupConfig();
HandleCommandLinePostConfigLoad(Environment.GetCommandLineArgs());
if (Config.StorageType.ToLower() == "sqlite")
@ -188,14 +212,13 @@ namespace TShockAPI
Backups.Interval = Config.BackupInterval;
Bans = new BanManager(DB);
Warps = new WarpManager(DB);
Regions = new RegionManager(DB);
Users = new UserManager(DB);
Groups = new GroupManager(DB);
Regions = new RegionManager(DB);
Itembans = new ItemManager(DB);
RememberedPos = new RemeberedPosManager(DB);
RememberedPos = new RememberedPosManager(DB);
InventoryDB = new InventoryManager(DB);
RestApi = new SecureRest(Netplay.serverListenIP, Config.RestApiPort);
RestApi.Verify += RestApi_Verify;
RestApi.Port = Config.RestApiPort;
RestManager = new RestManager(RestApi);
RestManager.RegisterRestfulCommands();
@ -223,6 +246,8 @@ namespace TShockAPI
ProjectileHooks.SetDefaults += OnProjectileSetDefaults;
WorldHooks.StartHardMode += OnStartHardMode;
WorldHooks.SaveWorld += SaveManager.Instance.OnSaveWorld;
WorldHooks.ChristmasCheck += OnXmasCheck;
NetHooks.NameCollision += NetHooks_NameCollision;
GetDataHandlers.InitGetDataHandler();
Commands.InitCommands();
@ -267,33 +292,6 @@ namespace TShockAPI
// ReSharper restore LocalizableElement
}
private RestObject RestApi_Verify(string username, string password)
{
var userAccount = Users.GetUserByName(username);
if (userAccount == null)
{
return new RestObject("401")
{Error = "Invalid username/password combination provided. Please re-submit your query with a correct pair."};
}
if (Utils.HashPassword(password).ToUpper() != userAccount.Password.ToUpper())
{
return new RestObject("401")
{Error = "Invalid username/password combination provided. Please re-submit your query with a correct pair."};
}
if (!Utils.GetGroup(userAccount.Group).HasPermission(Permissions.restapi) && userAccount.Group != "superadmin")
{
return new RestObject("403")
{
Error =
"Although your account was successfully found and identified, your account lacks the permission required to use the API. (api)"
};
}
return new RestObject("200") {Response = "Successful login"}; //Maybe return some user info too?
}
protected override void Dispose(bool disposing)
{
if (disposing)
@ -322,6 +320,8 @@ namespace TShockAPI
ProjectileHooks.SetDefaults -= OnProjectileSetDefaults;
WorldHooks.StartHardMode -= OnStartHardMode;
WorldHooks.SaveWorld -= SaveManager.Instance.OnSaveWorld;
WorldHooks.ChristmasCheck -= OnXmasCheck;
NetHooks.NameCollision -= NetHooks_NameCollision;
if (File.Exists(Path.Combine(SavePath, "tshock.pid")))
{
@ -334,6 +334,48 @@ namespace TShockAPI
base.Dispose(disposing);
}
void NetHooks_NameCollision(int who, string name, HandledEventArgs e)
{
string ip = TShock.Utils.GetRealIP(Netplay.serverSock[who].tcpClient.Client.RemoteEndPoint.ToString());
foreach (TSPlayer ply in TShock.Players)
{
if (ply == null)
{
continue;
}
if (ply.Name == name && ply.Index != who)
{
if (ply.IP == ip)
{
if (ply.State < 2)
{
Utils.ForceKick(ply, "Name collision and this client has no world data.", true, false);
e.Handled = true;
return;
}
else
{
e.Handled = false;
return;
}
}
}
}
e.Handled = false;
return;
}
void OnXmasCheck(ChristmasCheckEventArgs args)
{
if (args.Handled)
return;
if(Config.ForceXmas)
{
args.Xmas = true;
args.Handled = true;
}
}
/// <summary>
/// Handles exceptions that we didn't catch or that Red fucked up
/// </summary>
@ -396,9 +438,13 @@ namespace TShockAPI
}
break;
case "-dump":
ConfigFile.DumpDescriptions();
Permissions.DumpDescriptions();
case "-logpath":
path = parms[++i];
if (path.IndexOfAny(Path.GetInvalidPathChars()) == -1)
{
LogPath = path;
Log.ConsoleInfo("Log path has been set to " + path);
}
break;
case "-logformat":
@ -408,6 +454,11 @@ namespace TShockAPI
case "-logclear":
bool.TryParse(parms[++i], out LogClear);
break;
case "-dump":
ConfigFile.DumpDescriptions();
Permissions.DumpDescriptions();
break;
}
}
}
@ -427,7 +478,7 @@ namespace TShockAPI
break;
case "-rest-token":
string token = Convert.ToString(parms[++i]);
RESTStartupTokens.Add(token, "null");
RESTStartupTokens.Add(token, new SecureRest.TokenData { Username = "null", UserGroupName = "superadmin" });
Console.WriteLine("Startup parameter overrode REST token.");
break;
case "-rest-enabled":
@ -488,14 +539,20 @@ namespace TShockAPI
{
AuthToken = 0;
}
Regions.ReloadAllRegions();
StatTracker.CheckIn();
Regions.ReloadAllRegions();
Lighting.lightMode = 2;
FixChestStacks();
}
private void FixChestStacks()
{
if (Config.IgnoreChestStacksOnLoad)
return;
foreach (Chest chest in Main.chest)
{
if (chest != null)
@ -515,7 +572,6 @@ namespace TShockAPI
private void OnUpdate()
{
UpdateManager.UpdateProcedureCheck();
StatTracker.CheckIn();
if (Backups.IsBackupTime)
Backups.Backup();
//call these every second, not every update
@ -564,7 +620,7 @@ namespace TShockAPI
{
if (player.TileKillThreshold >= Config.TileKillThreshold)
{
player.Disable("Reached TileKill threshold");
player.Disable("Reached TileKill threshold.");
TSPlayer.Server.RevertTiles(player.TilesDestroyed);
player.TilesDestroyed.Clear();
}
@ -579,7 +635,7 @@ namespace TShockAPI
{
if (player.TilePlaceThreshold >= Config.TilePlaceThreshold)
{
player.Disable("Reached TilePlace threshold");
player.Disable("Reached TilePlace threshold.");
TSPlayer.Server.RevertTiles(player.TilesCreated);
player.TilesCreated.Clear();
}
@ -590,7 +646,7 @@ namespace TShockAPI
}
if (player.TileLiquidThreshold >= Config.TileLiquidThreshold)
{
player.Disable("Reached TileLiquid threshold");
player.Disable("Reached TileLiquid threshold.");
}
if (player.TileLiquidThreshold > 0)
{
@ -598,7 +654,7 @@ namespace TShockAPI
}
if (player.ProjectileThreshold >= Config.ProjectileThreshold)
{
player.Disable("Reached Projectile threshold");
player.Disable("Reached projectile threshold.");
}
if (player.ProjectileThreshold > 0)
{
@ -614,7 +670,7 @@ namespace TShockAPI
if (!player.Group.HasPermission(Permissions.ignorestackhackdetection) && item.stack > item.maxStack &&
item.type != 0)
{
check = "Remove Item " + item.name + " (" + item.stack + ") exceeds max stack of " + item.maxStack;
check = "Remove item " + item.name + " (" + item.stack + ") exceeds max stack of " + item.maxStack;
}
}
player.IgnoreActionsForCheating = check;
@ -625,7 +681,7 @@ namespace TShockAPI
{
player.SetBuff(30, 120); //Bleeding
player.SetBuff(36, 120); //Broken Armor
check = "Remove Armor/Accessory " + item.name;
check = "Remove armor/accessory " + item.name;
}
}
player.IgnoreActionsForDisabledArmor = check;
@ -776,12 +832,9 @@ namespace TShockAPI
if (tsplr != null && tsplr.ReceivedInfo)
{
if (!tsplr.SilentKickInProgress || tsplr.State > 1)
if (!tsplr.SilentKickInProgress && tsplr.State >= 3)
{
if (tsplr.State >= 2)
{
Utils.Broadcast(tsplr.Name + " left", Color.Yellow);
}
Utils.Broadcast(tsplr.Name + " left", Color.Yellow);
}
Log.Info(string.Format("{0} disconnected.", tsplr.Name));
@ -841,7 +894,7 @@ namespace TShockAPI
}
else if (tsplr.mute)
{
tsplr.SendMessage("You are muted!");
tsplr.SendErrorMessage("You are muted!");
e.Handled = true;
}
}
@ -874,11 +927,11 @@ namespace TShockAPI
if (player != null && player.Active)
{
count++;
TSPlayer.Server.SendMessage(string.Format("{0} ({1}) [{2}] <{3}>", player.Name, player.IP,
TSPlayer.Server.SendInfoMessage(string.Format("{0} ({1}) [{2}] <{3}>", player.Name, player.IP,
player.Group.Name, player.UserAccountName));
}
}
TSPlayer.Server.SendMessage(string.Format("{0} players connected.", count));
TSPlayer.Server.SendInfoMessage(string.Format("{0} players connected.", count));
}
else if (text == "autosave")
{
@ -959,7 +1012,7 @@ namespace TShockAPI
if (Config.PvPMode == "always" && !player.TPlayer.hostile)
{
player.SendMessage("PvP is forced! Enable PvP else you can't move or do anything!", Color.Red);
player.SendMessage("PvP is forced! Enable PvP else you can't do anything!", Color.Red);
}
if (!player.IsLoggedIn)
@ -967,7 +1020,7 @@ namespace TShockAPI
if (Config.ServerSideInventory)
{
player.SendMessage(
player.IgnoreActionsForInventory = "Server Side Inventory is enabled! Please /register or /login to play!",
player.IgnoreActionsForInventory = "Server side inventory is enabled! Please /register or /login to play!",
Color.Red);
player.LoginHarassed = true;
}
@ -1184,22 +1237,22 @@ namespace TShockAPI
switch (random)
{
case 0:
Utils.Broadcast(string.Format("You call that a lot? {0} goblins killed!", KillCount));
Utils.Broadcast(string.Format("You call that a lot? {0} goblins killed!", KillCount), Color.Green);
break;
case 1:
Utils.Broadcast(string.Format("Fatality! {0} goblins killed!", KillCount));
Utils.Broadcast(string.Format("Fatality! {0} goblins killed!", KillCount), Color.Green);
break;
case 2:
Utils.Broadcast(string.Format("Number of 'noobs' killed to date: {0}", KillCount));
Utils.Broadcast(string.Format("Number of 'noobs' killed to date: {0}", KillCount), Color.Green);
break;
case 3:
Utils.Broadcast(string.Format("Duke Nukem would be proud. {0} goblins killed.", KillCount));
Utils.Broadcast(string.Format("Duke Nukem would be proud. {0} goblins killed.", KillCount), Color.Green);
break;
case 4:
Utils.Broadcast(string.Format("You call that a lot? {0} goblins killed!", KillCount));
Utils.Broadcast(string.Format("You call that a lot? {0} goblins killed!", KillCount), Color.Green);
break;
case 5:
Utils.Broadcast(string.Format("{0} copies of Call of Duty smashed.", KillCount));
Utils.Broadcast(string.Format("{0} copies of Call of Duty smashed.", KillCount), Color.Green);
break;
}
}
@ -1256,6 +1309,7 @@ namespace TShockAPI
{
if (TShock.Config.AllowIce && actionType != 1)
{
foreach (Point p in player.IceTiles)
{
if (p.X == tileX && p.Y == tileY && (Main.tile[p.X, p.Y].type == 0 || Main.tile[p.X, p.Y].type == 127))
@ -1264,11 +1318,12 @@ namespace TShockAPI
return false;
}
}
if (((DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond) - player.BPm) > 2000){
player.SendMessage("You do not have permission to build!", Color.Red);
player.BPm=DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond;
}
if (((DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond) - player.BPm) > 2000){
player.SendMessage("You do not have permission to build!", Color.Red);
player.BPm=DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond;
}
return true;
}
@ -1278,30 +1333,33 @@ namespace TShockAPI
return false;
}
if (((DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond) - player.BPm) > 2000){
if (((DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond) - player.BPm) > 2000){
player.SendMessage("You do not have permission to build!", Color.Red);
player.BPm=DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond;
player.BPm=DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond;
}
}
return true;
}
if (!player.Group.HasPermission(Permissions.editspawn) && !Regions.CanBuild(tileX, tileY, player) &&
Regions.InArea(tileX, tileY))
{
if (((DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond) - player.RPm) > 2000){
player.SendMessage("Region protected from changes.", Color.Red);
player.RPm=DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond;
if (((DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond) - player.RPm) > 2000)
{
player.SendMessage("This region is protected from changes.", Color.Red);
player.RPm = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond;
}
}
return true;
}
if (Config.DisableBuild)
{
if (!player.Group.HasPermission(Permissions.editspawn))
{
if (((DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond) - player.WPm) > 2000){
player.SendMessage("World protected from changes.", Color.Red);
player.SendMessage("The world is protected from changes.", Color.Red);
player.WPm=DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond;
}
@ -1316,7 +1374,7 @@ namespace TShockAPI
if (flag)
{
if (((DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond) - player.SPm) > 2000){
player.SendMessage("Spawn protected from changes.", Color.Red);
player.SendMessage("Spawn is protected from changes.", Color.Red);
player.SPm=DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond;
}
return true;
@ -1337,25 +1395,26 @@ namespace TShockAPI
}
return true;
}
if (!player.Group.HasPermission(Permissions.editspawn) && !Regions.CanBuild(tileX, tileY, player) &&
Regions.InArea(tileX, tileY))
{
if (!player.Group.HasPermission(Permissions.editspawn) && !Regions.CanBuild(tileX, tileY, player) &&
Regions.InArea(tileX, tileY))
{
if (((DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond) - player.RPm) > 2000){
player.SendMessage("Region protected from changes.", Color.Red);
player.RPm=DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond;
}
return true;
}
if (((DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond) - player.RPm) > 2000)
{
player.SendMessage("This region is protected from changes.", Color.Red);
player.RPm = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond;
}
return true;
}
if (Config.DisableBuild)
{
if (!player.Group.HasPermission(Permissions.editspawn))
{
if (((DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond) - player.WPm) > 2000){
player.SendMessage("World protected from changes.", Color.Red);
player.SendMessage("The world is protected from changes.", Color.Red);
player.WPm=DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond;
}
return true;
@ -1369,7 +1428,7 @@ namespace TShockAPI
if (flag)
{
if (((DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond) - player.SPm) > 1000){
player.SendMessage("Spawn protected from changes.", Color.Red);
player.SendMessage("Spawn is protected from changes.", Color.Red);
player.SPm=DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond;
}
@ -1396,12 +1455,12 @@ namespace TShockAPI
return (float) Math.Sqrt(num3);
}
public static bool HackedHealth(TSPlayer player)
public static bool HackedStats(TSPlayer player)
{
return (player.TPlayer.statManaMax > 400) ||
(player.TPlayer.statMana > 400) ||
(player.TPlayer.statLifeMax > 400) ||
(player.TPlayer.statLife > 400);
return (player.TPlayer.statManaMax > TShock.Config.MaxMana) ||
(player.TPlayer.statMana > TShock.Config.MaxMana) ||
(player.TPlayer.statLifeMax > TShock.Config.MaxHealth) ||
(player.TPlayer.statLife > TShock.Config.MaxHealth);
}
public static bool HackedInventory(TSPlayer player)
@ -1458,7 +1517,7 @@ namespace TShockAPI
if (player.TPlayer.statLifeMax > playerData.maxHealth)
{
player.SendMessage("Error: Your max health exceeded (" + playerData.maxHealth + ") which is stored on server",
player.SendMessage("Error: Your max health exceeded (" + playerData.maxHealth + ") which is stored on server.",
Color.Cyan);
check = false;
}
@ -1498,7 +1557,7 @@ namespace TShockAPI
item.AffixName();
player.SendMessage(
player.IgnoreActionsForInventory =
"Your item (" + item.name + ") (" + inventory[i].stack + ") needs to have it's stack decreased to (" +
"Your item (" + item.name + ") (" + inventory[i].stack + ") needs to have its stack size decreased to (" +
playerData.inventory[i].stack + ").", Color.Cyan);
check = false;
}
@ -1535,7 +1594,7 @@ namespace TShockAPI
item.AffixName();
player.SendMessage(
player.IgnoreActionsForInventory =
"Your armor (" + item.name + ") (" + inventory[i].stack + ") needs to have it's stack decreased to (" +
"Your armor (" + item.name + ") (" + inventory[i].stack + ") needs to have its stack size decreased to (" +
playerData.inventory[i].stack + ").", Color.Cyan);
check = false;
}

View file

@ -61,30 +61,27 @@
<HintPath>..\SqlBins\MySql.Data.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="MySql.Web, Version=6.3.6.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\SqlBins\MySql.Web.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Newtonsoft.Json">
<HintPath>.\Newtonsoft.Json.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
<Reference Include="TerrariaServer, Version=1.0.4.0, Culture=neutral, processorArchitecture=x86">
<Reference Include="TerrariaServer, Version=0.0.0.0, Culture=neutral, processorArchitecture=x86">
<SpecificVersion>False</SpecificVersion>
<ExecutableExtension>.exe</ExecutableExtension>
<HintPath>..\TerrariaServerBins\TerrariaServer.exe</HintPath>
<Private>False</Private>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="BackupManager.cs" />
<Compile Include="DB\RegionManager.cs" />
<Compile Include="Hooks\GeneralHooks.cs" />
<Compile Include="Hooks\PlayerHooks.cs" />
<Compile Include="PaginationTools.cs" />
<Compile Include="PluginUpdater\PluginUpdaterThread.cs" />
<Compile Include="PluginUpdater\PluginVersionCheck.cs" />
<Compile Include="PluginUpdater\VersionInfo.cs" />
<Compile Include="Rest\RestPermissions.cs" />
<Compile Include="SaveManager.cs" />
<Compile Include="DB\BanManager.cs" />
<Compile Include="DB\InventoryManager.cs" />
@ -114,11 +111,10 @@
<Compile Include="Net\ProjectileRemoveMsg.cs" />
<Compile Include="Net\SpawnMsg.cs" />
<Compile Include="Net\WorldInfoMsg.cs" />
<Compile Include="DB\RegionManager.cs" />
<Compile Include="PacketBufferer.cs" />
<Compile Include="Permissions.cs" />
<Compile Include="RconHandler.cs" />
<Compile Include="DB\RememberPosManager.cs" />
<Compile Include="DB\RememberedPosManager.cs" />
<Compile Include="Resources.Designer.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
@ -130,7 +126,6 @@
<Compile Include="Rest\RestObject.cs" />
<Compile Include="Rest\RestVerbs.cs" />
<Compile Include="Rest\SecureRest.cs" />
<Compile Include="StatTracker.cs" />
<Compile Include="Utils.cs" />
<Compile Include="TShock.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
@ -184,7 +179,8 @@
</PreBuildEvent>
</PropertyGroup>
<PropertyGroup>
<PostBuildEvent>"$(ProjectDir)postbuild.bat"</PostBuildEvent>
<PostBuildEvent>
</PostBuildEvent>
</PropertyGroup>
<ProjectExtensions>
<VisualStudio>
@ -198,4 +194,4 @@
<Target Name="AfterBuild">
</Target>
-->
</Project>
</Project>

View file

@ -1,7 +1,7 @@
extensions: .cs
/*
TShock, a server mod for Terraria
Copyright (C) 2011-2012 The TShock Team
Copyright (C) 2011-2013 Nyx Studios (fka. The TShock Team)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by

View file

@ -1,6 +1,6 @@
/*
TShock, a server mod for Terraria
Copyright (C) 2011-2012 The TShock Team
Copyright (C) 2011-2013 Nyx Studios (fka. The TShock Team)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -15,6 +15,7 @@ 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.Net;

View file

@ -1,6 +1,6 @@
/*
TShock, a server mod for Terraria
Copyright (C) 2011-2012 The TShock Team
Copyright (C) 2011-2013 Nyx Studios (fka. The TShock Team)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -15,6 +15,7 @@ GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
using System;
using System.Collections.Generic;
using System.IO;
@ -33,12 +34,12 @@ namespace TShockAPI
public class Utils
{
/// <summary>
/// Document me
/// The lowest id for a prefix.
/// </summary>
private const int FirstItemPrefix = 1;
/// <summary>
/// Document me
/// The highest id for a prefix.
/// </summary>
private const int LastItemPrefix = 83;
@ -183,6 +184,7 @@ namespace TShockAPI
/// Broadcasts a message to all players
/// </summary>
/// <param name="msg">string message</param>
[Obsolete("Use TSPlayer.All and send a message via that method rather than using Broadcast.")]
public void Broadcast(string msg)
{
Broadcast(msg, Color.Green);
@ -211,23 +213,24 @@ namespace TShockAPI
public void Broadcast(int ply, string msg, byte red, byte green, byte blue)
{
TSPlayer.All.SendMessageFromPlayer(msg, red, green, blue, ply);
TSPlayer.Server.SendMessage(msg, red, green, blue);
Log.Info(string.Format("Broadcast: {0}", msg));
TSPlayer.Server.SendMessage(Main.player[ply].name + ": " + msg, red, green, blue);
Log.Info(string.Format("Broadcast: {0}", Main.player[ply].name + ": " + msg));
}
/// <summary>
/// Sends message to all users with 'logs' permission.
/// Sends message to all players with 'logs' permission.
/// </summary>
/// <param name="log">Message to send</param>
/// <param name="color">Color of the message</param>
public void SendLogs(string log, Color color)
/// <param name="excludedPlayer">The player to not send the message to.</param>
public void SendLogs(string log, Color color, TSPlayer excludedPlayer = null)
{
Log.Info(log);
TSPlayer.Server.SendMessage(log, color);
foreach (TSPlayer player in TShock.Players)
{
if (player != null && player.Active && player.Group.HasPermission(Permissions.logs) && player.DisplayLogs &&
TShock.Config.DisableSpewLogs == false)
if (player != null && player != excludedPlayer && player.Active && player.Group.HasPermission(Permissions.logs) &&
player.DisplayLogs && TShock.Config.DisableSpewLogs == false)
player.SendMessage(log, color);
}
}
@ -242,41 +245,38 @@ namespace TShockAPI
}
/// <summary>
/// Finds a TSPlayer based on name or id
/// Finds a TSPlayer based on name or ID
/// </summary>
/// <param name="ply">Player name</param>
/// <param name="plr">Player name or ID</param>
/// <returns></returns>
public List<TSPlayer> FindPlayer(string ply)
public List<TSPlayer> FindPlayer(string plr)
{
var found = new List<TSPlayer>();
// Avoid errors caused by null search
if (null == ply)
if (plr == null)
return found;
ply = ply.ToLower();
byte plrID;
if (byte.TryParse(plr, out plrID))
{
TSPlayer player = TShock.Players[plrID];
if (player != null && player.Active)
{
return new List<TSPlayer> { player };
}
}
string plrLower = plr.ToLower();
foreach (TSPlayer player in TShock.Players)
{
if (player == null)
continue;
try
{
if (Convert.ToInt32(ply) == player.Index && player.Active)
{
return new List<TSPlayer> { player };
}
}
// ReSharper disable EmptyGeneralCatchClause
catch (Exception e)
// ReSharper restore EmptyGeneralCatchClause
{
// Conversion failed
}
string name = player.Name.ToLower();
if (name.Equals(ply))
return new List<TSPlayer> {player};
if (name.Contains(ply))
found.Add(player);
if (player != null)
{
// Must be an EXACT match
if (player.Name == plr)
return new List<TSPlayer> { player };
if (player.Name.ToLower().StartsWith(plrLower))
found.Add(player);
}
}
return found;
}
@ -315,13 +315,13 @@ namespace TShockAPI
/// <param name="tileX">Location X</param>
/// <param name="tileY">Location Y</param>
/// <returns>If the tile is valid</returns>
private bool TileValid(int tileX, int tileY)
public bool TileValid(int tileX, int tileY)
{
return tileX >= 0 && tileX <= Main.maxTilesX && tileY >= 0 && tileY <= Main.maxTilesY;
return tileX >= 0 && tileX < Main.maxTilesX && tileY >= 0 && tileY < Main.maxTilesY;
}
/// <summary>
/// Clears a tile
/// Checks to see if the tile is clear.
/// </summary>
/// <param name="tileX">Location X</param>
/// <param name="tileY">Location Y</param>
@ -341,6 +341,8 @@ namespace TShockAPI
int type = -1;
if (int.TryParse(idOrName, out type))
{
if (type >= Main.maxItemTypes)
return new List<Item>();
return new List<Item> {GetItemById(type)};
}
return GetItemByName(idOrName);
@ -365,30 +367,16 @@ namespace TShockAPI
/// <returns>List of Items</returns>
public List<Item> GetItemByName(string name)
{
//Method #1 - must be exact match, allows support for different pickaxes/hammers/swords etc
for (int i = 1; i < Main.maxItemTypes; i++)
{
Item item = new Item();
item.SetDefaults(name);
if (item.name == name)
return new List<Item> {item};
}
//Method #2 - allows impartial matching
var found = new List<Item>();
Item item = new Item();
string nameLower = name.ToLower();
for (int i = -24; i < Main.maxItemTypes; i++)
{
try
{
Item item = new Item();
item.netDefaults(i);
if (item.name.ToLower() == name.ToLower())
return new List<Item> {item};
if (item.name.ToLower().StartsWith(name.ToLower()))
found.Add(item);
}
catch
{
}
item.netDefaults(i);
if (item.name.ToLower() == nameLower)
return new List<Item> {item};
if (item.name.ToLower().StartsWith(nameLower))
found.Add((Item)item.Clone());
}
return found;
}
@ -403,7 +391,9 @@ namespace TShockAPI
int type = -1;
if (int.TryParse(idOrName, out type))
{
return new List<NPC> {GetNPCById(type)};
if (type >= Main.maxNPCTypes)
return new List<NPC>();
return new List<NPC> { GetNPCById(type) };
}
return GetNPCByName(idOrName);
}
@ -427,24 +417,16 @@ namespace TShockAPI
/// <returns>List of matching NPCs</returns>
public List<NPC> GetNPCByName(string name)
{
//Method #1 - must be exact match, allows support for different coloured slimes
var found = new List<NPC>();
NPC npc = new NPC();
string nameLower = name.ToLower();
for (int i = -17; i < Main.maxNPCTypes; i++)
{
NPC npc = new NPC();
npc.SetDefaults(name);
if (npc.name == name)
return new List<NPC> {npc};
}
//Method #2 - allows impartial matching
var found = new List<NPC>();
for (int i = 1; i < Main.maxNPCTypes; i++)
{
NPC npc = new NPC();
npc.netDefaults(i);
if (npc.name.ToLower() == name.ToLower())
return new List<NPC> {npc};
if (npc.name.ToLower().StartsWith(name.ToLower()))
found.Add(npc);
if (npc.name.ToLower() == nameLower)
return new List<NPC> { npc };
if (npc.name.ToLower().StartsWith(nameLower))
found.Add((NPC)npc.Clone());
}
return found;
}
@ -476,15 +458,16 @@ namespace TShockAPI
/// <returns>Matching list of buff ids</returns>
public List<int> GetBuffByName(string name)
{
string nameLower = name.ToLower();
for (int i = 1; i < Main.maxBuffs; i++)
{
if (Main.buffName[i].ToLower() == name)
if (Main.buffName[i].ToLower() == nameLower)
return new List<int> {i};
}
var found = new List<int>();
for (int i = 1; i < Main.maxBuffs; i++)
{
if (Main.buffName[i].ToLower().StartsWith(name.ToLower()))
if (Main.buffName[i].ToLower().StartsWith(nameLower))
found.Add(i);
}
return found;
@ -517,32 +500,12 @@ namespace TShockAPI
var found = new List<int>();
for (int i = FirstItemPrefix; i <= LastItemPrefix; i++)
{
try
{
item.prefix = (byte)i;
string trimmed = item.AffixName().Trim();
if (trimmed == name)
{
// Exact match
found.Add(i);
return found;
}
else
{
string trimmedLower = trimmed.ToLower();
if (trimmedLower == lowerName)
{
// Exact match (caseinsensitive)
found.Add(i);
return found;
}
else if (trimmedLower.StartsWith(lowerName)) // Partial match
found.Add(i);
}
}
catch
{
}
item.prefix = (byte)i;
string prefixName = item.AffixName().Trim().ToLower();
if (prefixName == lowerName)
return new List<int>() { i };
else if (prefixName.StartsWith(lowerName)) // Partial match
found.Add(i);
}
return found;
}
@ -599,6 +562,36 @@ namespace TShockAPI
Netplay.disconnect = true;
}
/// <summary>
/// Stops the server after kicking all players with a reason message, and optionally saving the world then attempts to
/// restart it.
/// </summary>
/// <param name="save">bool perform a world save before stop (default: true)</param>
/// <param name="reason">string reason (default: "Server shutting down!")</param>
public void RestartServer(bool save = true, string reason = "Server shutting down!")
{
if (TShock.Config.ServerSideInventory)
foreach (TSPlayer player in TShock.Players)
if (player != null && player.IsLoggedIn && !player.IgnoreActionsForClearingTrashCan)
TShock.InventoryDB.InsertPlayerData(player);
StopServer(true, reason);
System.Diagnostics.Process.Start(System.Reflection.Assembly.GetExecutingAssembly().GetName().CodeBase);
Environment.Exit(0);
}
/// <summary>
/// Reloads all configuration settings, groups, regions and raises the reload event.
/// </summary>
public void Reload(TSPlayer player)
{
FileTools.SetupConfig();
TShock.HandleCommandLinePostConfigLoad(Environment.GetCommandLineArgs());
TShock.Groups.LoadPermisions();
TShock.Regions.ReloadAllRegions();
Hooks.GeneralHooks.OnReloadEvent(player);
}
#if COMPAT_SIGS
[Obsolete("This method is for signature compatibility for external code only")]
public void ForceKick(TSPlayer player, string reason)
@ -649,9 +642,9 @@ namespace TShockAPI
if (!silent)
{
if (string.IsNullOrWhiteSpace(adminUserName))
Broadcast(string.Format("{0} was {1}kicked for {2}", playerName, verb, reason.ToLower()));
Broadcast(string.Format("{0} was {1}kicked for {2}", playerName, verb, reason.ToLower()), Color.Green);
else
Broadcast(string.Format("{0} {1}kicked {2} for {3}", adminUserName, verb, playerName, reason.ToLower()));
Broadcast(string.Format("{0} {1}kicked {2} for {3}", adminUserName, verb, playerName, reason.ToLower()), Color.Green);
}
return true;
}
@ -685,9 +678,9 @@ namespace TShockAPI
Log.ConsoleInfo(string.Format("Banned {0} for : {1}", playerName, reason));
string verb = force ? "force " : "";
if (string.IsNullOrWhiteSpace(adminUserName))
Broadcast(string.Format("{0} was {1}banned for {1}", playerName, verb, reason.ToLower()));
Broadcast(string.Format("{0} was {1}banned for {2}", playerName, verb, reason.ToLower()));
else
Broadcast(string.Format("{0} {1}banned {1} for {2}", adminUserName, verb, playerName, reason.ToLower()));
Broadcast(string.Format("{0} {1}banned {2} for {3}", adminUserName, verb, playerName, reason.ToLower()));
return true;
}
return false;
@ -770,8 +763,14 @@ namespace TShockAPI
return "";
}
/// <summary>
/// Default hashing algorithm.
/// </summary>
public string HashAlgo = "sha512";
/// <summary>
/// A dictionary of hashing algortihms and an implementation object.
/// </summary>
public readonly Dictionary<string, Func<HashAlgorithm>> HashTypes = new Dictionary<string, Func<HashAlgorithm>>
{
{"sha512", () => new SHA512Managed()},
@ -874,5 +873,25 @@ namespace TShockAPI
}
return new string(returnstr);
}
/// <summary>
/// Enumerates boundary points of the given region's rectangle.
/// </summary>
/// <param name="regionArea">The region's area to enumerate through.</param>
/// <returns>The enumerated boundary points.</returns>
public IEnumerable<Point> EnumerateRegionBoundaries(Rectangle regionArea)
{
for (int x = 0; x < regionArea.Width + 1; x++)
{
yield return new Point(regionArea.Left + x, regionArea.Top);
yield return new Point(regionArea.Left + x, regionArea.Bottom);
}
for (int y = 1; y < regionArea.Height; y++)
{
yield return new Point(regionArea.Left, regionArea.Top + y);
yield return new Point(regionArea.Right, regionArea.Top + y);
}
}
}
}