diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 00000000..598dd721 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,9 @@ +root = true + +[*] +end_of_line = crlf +insert_final_newline = true + +[*.cs] +indent_style = tab +trim_trailing_whitespace = true diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..026167bb --- /dev/null +++ b/.gitattributes @@ -0,0 +1,5 @@ +* text=auto +*.cs text eol=crlf +*.sln text eol=crlf +*.csproj text eol=crlf +*.vsmdi text eol=crlf diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 00000000..22e6ce9b --- /dev/null +++ b/.travis.yml @@ -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= \ No newline at end of file diff --git a/CONTRIBUTING b/CONTRIBUTING new file mode 100644 index 00000000..8f36fd52 --- /dev/null +++ b/CONTRIBUTING @@ -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. \ No newline at end of file diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000..095ad8ea --- /dev/null +++ b/CONTRIBUTING.md @@ -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. \ No newline at end of file diff --git a/DBEditor/.gitignore b/DBEditor/.gitignore deleted file mode 100644 index 4eddcb59..00000000 --- a/DBEditor/.gitignore +++ /dev/null @@ -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 \ No newline at end of file diff --git a/DBEditor/CommandList.cs b/DBEditor/CommandList.cs deleted file mode 100644 index c49c067c..00000000 --- a/DBEditor/CommandList.cs +++ /dev/null @@ -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 . -*/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace TShockDBEditor -{ - public class TShockCommandsList - { - public static void AddRemainingTShockCommands() - { - List CommandList = new List(); - - 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); - } - } - } -} diff --git a/DBEditor/DbExt.cs b/DBEditor/DbExt.cs deleted file mode 100644 index 226a8971..00000000 --- a/DBEditor/DbExt.cs +++ /dev/null @@ -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 . -*/ -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> ReadFuncs = new Dictionary>() - { - {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(this IDataReader reader, string column) - { - return reader.Get(reader.GetOrdinal(column)); - } - - public static T Get(this IDataReader reader, int column) - { - if (ReadFuncs.ContainsKey(typeof(T))) - return (T)ReadFuncs[typeof(T)](reader, column); - - throw new NotImplementedException(); - } - } -} diff --git a/DBEditor/Group.cs b/DBEditor/Group.cs deleted file mode 100644 index 581b90ca..00000000 --- a/DBEditor/Group.cs +++ /dev/null @@ -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 . -*/ -using System; -using System.Collections.Generic; - -namespace TShockDBEditor -{ - public class Group - { - public readonly List permissions = new List(); - private readonly List negatedpermissions = new List(); - - 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; - } - } -} \ No newline at end of file diff --git a/DBEditor/Itemlist.cs b/DBEditor/Itemlist.cs deleted file mode 100644 index e3372fd8..00000000 --- a/DBEditor/Itemlist.cs +++ /dev/null @@ -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 . -*/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace TShockDBEditor -{ - public class Itemlist - { - public static List ItemList = new List(); - - 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"); - } - } -} diff --git a/DBEditor/Main.Designer.cs b/DBEditor/Main.Designer.cs deleted file mode 100644 index a5824913..00000000 --- a/DBEditor/Main.Designer.cs +++ /dev/null @@ -1,1152 +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 . -*/ -namespace TShockDBEditor -{ - partial class TShockDBEditor - { - /// - /// Required designer variable. - /// - private System.ComponentModel.IContainer components = null; - - /// - /// Clean up any resources being used. - /// - /// true if managed resources should be disposed; otherwise, false. - protected override void Dispose(bool disposing) - { - if (disposing && (components != null)) - { - components.Dispose(); - } - base.Dispose(disposing); - } - - #region Windows Form Designer generated code - - /// - /// Required method for Designer support - do not modify - /// the contents of this method with the code editor. - /// - private void InitializeComponent() - { - this.itemListBanned = new System.Windows.Forms.ListBox(); - this.itemListAvailable = new System.Windows.Forms.ListBox(); - this.tabControl = new System.Windows.Forms.TabControl(); - this.tabPage1 = new System.Windows.Forms.TabPage(); - this.btn_moveAllLeft = new System.Windows.Forms.Button(); - this.btn_moveAllRight = new System.Windows.Forms.Button(); - this.btn_moveLeft = new System.Windows.Forms.Button(); - this.btn_moveRight = new System.Windows.Forms.Button(); - this.label2 = new System.Windows.Forms.Label(); - this.label1 = new System.Windows.Forms.Label(); - this.tabPage2 = new System.Windows.Forms.TabPage(); - this.groupBox2 = new System.Windows.Forms.GroupBox(); - this.label12 = new System.Windows.Forms.Label(); - this.btn_deletegroup = new System.Windows.Forms.Button(); - this.lbl_grpchild = new System.Windows.Forms.Label(); - this.groupBox1 = new System.Windows.Forms.GroupBox(); - this.label11 = new System.Windows.Forms.Label(); - this.btn_newgroup = new System.Windows.Forms.Button(); - this.txt_grpname = new System.Windows.Forms.TextBox(); - this.lst_inheritgrps = new System.Windows.Forms.ComboBox(); - this.label10 = new System.Windows.Forms.Label(); - this.label4 = new System.Windows.Forms.Label(); - this.label3 = new System.Windows.Forms.Label(); - this.btn_moveAllLeftCmd = new System.Windows.Forms.Button(); - this.btn_moveLeftCmd = new System.Windows.Forms.Button(); - this.btn_moveRightCmd = new System.Windows.Forms.Button(); - this.lst_AvailableCmds = new System.Windows.Forms.ListBox(); - this.btn_moveAllRightCmd = new System.Windows.Forms.Button(); - this.lst_bannedCmds = new System.Windows.Forms.ListBox(); - this.lst_groupList = new System.Windows.Forms.ListBox(); - this.tabPage5 = new System.Windows.Forms.TabPage(); - this.groupBox4 = new System.Windows.Forms.GroupBox(); - this.lbl_useraddstatus = new System.Windows.Forms.Label(); - this.btn_adduser = new System.Windows.Forms.Button(); - this.label20 = new System.Windows.Forms.Label(); - this.label22 = new System.Windows.Forms.Label(); - this.txt_newusername = new System.Windows.Forms.TextBox(); - this.txt_newuserpass = new System.Windows.Forms.TextBox(); - this.txt_newuserip = new System.Windows.Forms.TextBox(); - this.lst_newusergrplist = new System.Windows.Forms.ComboBox(); - this.label24 = new System.Windows.Forms.Label(); - this.label25 = new System.Windows.Forms.Label(); - this.groupBox3 = new System.Windows.Forms.GroupBox(); - this.label13 = new System.Windows.Forms.Label(); - this.btn_deluser = new System.Windows.Forms.Button(); - this.label23 = new System.Windows.Forms.Label(); - this.txt_username = new System.Windows.Forms.TextBox(); - this.txt_userpass = new System.Windows.Forms.TextBox(); - this.txt_userip = new System.Windows.Forms.TextBox(); - this.lst_usergrplist = new System.Windows.Forms.ComboBox(); - this.label21 = new System.Windows.Forms.Label(); - this.label14 = new System.Windows.Forms.Label(); - this.lst_userlist = new System.Windows.Forms.ListBox(); - this.tabPage6 = new System.Windows.Forms.TabPage(); - this.groupBox7 = new System.Windows.Forms.GroupBox(); - this.lst_bans = new System.Windows.Forms.ListBox(); - this.groupBox6 = new System.Windows.Forms.GroupBox(); - this.lbl_newbanstatus = new System.Windows.Forms.Label(); - this.label16 = new System.Windows.Forms.Label(); - this.btn_bannew = new System.Windows.Forms.Button(); - this.txt_newbanip = new System.Windows.Forms.TextBox(); - this.txt_newbanreason = new System.Windows.Forms.TextBox(); - this.txt_newbanname = new System.Windows.Forms.TextBox(); - this.label27 = new System.Windows.Forms.Label(); - this.label26 = new System.Windows.Forms.Label(); - this.groupBox5 = new System.Windows.Forms.GroupBox(); - this.label17 = new System.Windows.Forms.Label(); - this.txt_banip = new System.Windows.Forms.TextBox(); - this.btn_bandelete = new System.Windows.Forms.Button(); - this.txt_banname = new System.Windows.Forms.TextBox(); - this.label19 = new System.Windows.Forms.Label(); - this.txt_banreason = new System.Windows.Forms.TextBox(); - this.label18 = new System.Windows.Forms.Label(); - this.tabControl1 = new System.Windows.Forms.TabControl(); - this.tabPage3 = new System.Windows.Forms.TabPage(); - this.btn_OpenLocalDB = new System.Windows.Forms.Button(); - this.tabPage4 = new System.Windows.Forms.TabPage(); - this.btn_connect = new System.Windows.Forms.Button(); - this.label9 = new System.Windows.Forms.Label(); - this.txt_dbpassword = new System.Windows.Forms.TextBox(); - this.label8 = new System.Windows.Forms.Label(); - this.txt_dbusername = new System.Windows.Forms.TextBox(); - this.txt_port = new System.Windows.Forms.TextBox(); - this.txt_dbname = new System.Windows.Forms.TextBox(); - this.txt_hostname = new System.Windows.Forms.TextBox(); - this.label7 = new System.Windows.Forms.Label(); - this.label6 = new System.Windows.Forms.Label(); - this.label5 = new System.Windows.Forms.Label(); - this.tabControl.SuspendLayout(); - this.tabPage1.SuspendLayout(); - this.tabPage2.SuspendLayout(); - this.groupBox2.SuspendLayout(); - this.groupBox1.SuspendLayout(); - this.tabPage5.SuspendLayout(); - this.groupBox4.SuspendLayout(); - this.groupBox3.SuspendLayout(); - this.tabPage6.SuspendLayout(); - this.groupBox7.SuspendLayout(); - this.groupBox6.SuspendLayout(); - this.groupBox5.SuspendLayout(); - this.tabControl1.SuspendLayout(); - this.tabPage3.SuspendLayout(); - this.tabPage4.SuspendLayout(); - this.SuspendLayout(); - // - // itemListBanned - // - this.itemListBanned.FormattingEnabled = true; - this.itemListBanned.Location = new System.Drawing.Point(321, 19); - this.itemListBanned.Name = "itemListBanned"; - this.itemListBanned.Size = new System.Drawing.Size(275, 290); - this.itemListBanned.TabIndex = 1; - // - // itemListAvailable - // - this.itemListAvailable.FormattingEnabled = true; - this.itemListAvailable.Location = new System.Drawing.Point(7, 19); - this.itemListAvailable.Name = "itemListAvailable"; - this.itemListAvailable.Size = new System.Drawing.Size(275, 290); - this.itemListAvailable.TabIndex = 2; - // - // tabControl - // - this.tabControl.Controls.Add(this.tabPage1); - this.tabControl.Controls.Add(this.tabPage2); - this.tabControl.Controls.Add(this.tabPage5); - this.tabControl.Controls.Add(this.tabPage6); - this.tabControl.Location = new System.Drawing.Point(12, 143); - this.tabControl.Name = "tabControl"; - this.tabControl.SelectedIndex = 0; - this.tabControl.Size = new System.Drawing.Size(610, 407); - this.tabControl.TabIndex = 3; - this.tabControl.Visible = false; - // - // tabPage1 - // - this.tabPage1.Controls.Add(this.btn_moveAllLeft); - this.tabPage1.Controls.Add(this.btn_moveAllRight); - this.tabPage1.Controls.Add(this.btn_moveLeft); - this.tabPage1.Controls.Add(this.btn_moveRight); - this.tabPage1.Controls.Add(this.label2); - this.tabPage1.Controls.Add(this.label1); - this.tabPage1.Controls.Add(this.itemListAvailable); - this.tabPage1.Controls.Add(this.itemListBanned); - this.tabPage1.Location = new System.Drawing.Point(4, 22); - this.tabPage1.Name = "tabPage1"; - this.tabPage1.Padding = new System.Windows.Forms.Padding(3); - this.tabPage1.Size = new System.Drawing.Size(602, 381); - this.tabPage1.TabIndex = 0; - this.tabPage1.Text = "Item Bans"; - this.tabPage1.UseVisualStyleBackColor = true; - // - // btn_moveAllLeft - // - this.btn_moveAllLeft.Location = new System.Drawing.Point(288, 108); - this.btn_moveAllLeft.Name = "btn_moveAllLeft"; - this.btn_moveAllLeft.Size = new System.Drawing.Size(27, 23); - this.btn_moveAllLeft.TabIndex = 8; - this.btn_moveAllLeft.Text = "<<"; - this.btn_moveAllLeft.UseVisualStyleBackColor = true; - this.btn_moveAllLeft.Click += new System.EventHandler(this.btn_moveAllLeftItems_Click); - // - // btn_moveAllRight - // - this.btn_moveAllRight.Location = new System.Drawing.Point(288, 79); - this.btn_moveAllRight.Name = "btn_moveAllRight"; - this.btn_moveAllRight.Size = new System.Drawing.Size(27, 23); - this.btn_moveAllRight.TabIndex = 7; - this.btn_moveAllRight.Text = ">>"; - this.btn_moveAllRight.UseVisualStyleBackColor = true; - this.btn_moveAllRight.Click += new System.EventHandler(this.btn_moveAllRightItems_Click); - // - // btn_moveLeft - // - this.btn_moveLeft.Location = new System.Drawing.Point(288, 195); - this.btn_moveLeft.Name = "btn_moveLeft"; - this.btn_moveLeft.Size = new System.Drawing.Size(27, 23); - this.btn_moveLeft.TabIndex = 6; - this.btn_moveLeft.Text = "<"; - this.btn_moveLeft.UseVisualStyleBackColor = true; - this.btn_moveLeft.Click += new System.EventHandler(this.btn_moveLeftItems_Click); - // - // btn_moveRight - // - this.btn_moveRight.Location = new System.Drawing.Point(288, 166); - this.btn_moveRight.Name = "btn_moveRight"; - this.btn_moveRight.Size = new System.Drawing.Size(27, 23); - this.btn_moveRight.TabIndex = 5; - this.btn_moveRight.Text = ">"; - this.btn_moveRight.UseVisualStyleBackColor = true; - this.btn_moveRight.Click += new System.EventHandler(this.btn_moveRightItems_Click); - // - // label2 - // - this.label2.AutoSize = true; - this.label2.Location = new System.Drawing.Point(318, 3); - this.label2.Name = "label2"; - this.label2.Size = new System.Drawing.Size(86, 13); - this.label2.TabIndex = 4; - this.label2.Text = "Blacklisted Items"; - // - // label1 - // - this.label1.AutoSize = true; - this.label1.Location = new System.Drawing.Point(6, 3); - this.label1.Name = "label1"; - this.label1.Size = new System.Drawing.Size(87, 13); - this.label1.TabIndex = 3; - this.label1.Text = "Whitelisted Items"; - // - // tabPage2 - // - this.tabPage2.Controls.Add(this.groupBox2); - this.tabPage2.Controls.Add(this.groupBox1); - this.tabPage2.Controls.Add(this.label4); - this.tabPage2.Controls.Add(this.label3); - this.tabPage2.Controls.Add(this.btn_moveAllLeftCmd); - this.tabPage2.Controls.Add(this.btn_moveLeftCmd); - this.tabPage2.Controls.Add(this.btn_moveRightCmd); - this.tabPage2.Controls.Add(this.lst_AvailableCmds); - this.tabPage2.Controls.Add(this.btn_moveAllRightCmd); - this.tabPage2.Controls.Add(this.lst_bannedCmds); - this.tabPage2.Controls.Add(this.lst_groupList); - this.tabPage2.Location = new System.Drawing.Point(4, 22); - this.tabPage2.Name = "tabPage2"; - this.tabPage2.Padding = new System.Windows.Forms.Padding(3); - this.tabPage2.Size = new System.Drawing.Size(602, 381); - this.tabPage2.TabIndex = 1; - this.tabPage2.Text = "Group Manager"; - this.tabPage2.UseVisualStyleBackColor = true; - // - // groupBox2 - // - this.groupBox2.Controls.Add(this.label12); - this.groupBox2.Controls.Add(this.btn_deletegroup); - this.groupBox2.Controls.Add(this.lbl_grpchild); - this.groupBox2.Location = new System.Drawing.Point(222, 6); - this.groupBox2.Name = "groupBox2"; - this.groupBox2.Size = new System.Drawing.Size(374, 54); - this.groupBox2.TabIndex = 27; - this.groupBox2.TabStop = false; - this.groupBox2.Text = "Selected Group"; - // - // label12 - // - this.label12.AutoSize = true; - this.label12.Location = new System.Drawing.Point(6, 26); - this.label12.Name = "label12"; - this.label12.Size = new System.Drawing.Size(65, 13); - this.label12.TabIndex = 24; - this.label12.Text = "Group Child:"; - // - // btn_deletegroup - // - this.btn_deletegroup.Location = new System.Drawing.Point(183, 19); - this.btn_deletegroup.Name = "btn_deletegroup"; - this.btn_deletegroup.Size = new System.Drawing.Size(78, 23); - this.btn_deletegroup.TabIndex = 19; - this.btn_deletegroup.Text = "Delete Group"; - this.btn_deletegroup.UseVisualStyleBackColor = true; - this.btn_deletegroup.Click += new System.EventHandler(this.btn_deletegroup_Click); - // - // lbl_grpchild - // - this.lbl_grpchild.AutoSize = true; - this.lbl_grpchild.Location = new System.Drawing.Point(77, 26); - this.lbl_grpchild.Name = "lbl_grpchild"; - this.lbl_grpchild.Size = new System.Drawing.Size(31, 13); - this.lbl_grpchild.TabIndex = 25; - this.lbl_grpchild.Text = "none"; - // - // groupBox1 - // - this.groupBox1.Controls.Add(this.label11); - this.groupBox1.Controls.Add(this.btn_newgroup); - this.groupBox1.Controls.Add(this.txt_grpname); - this.groupBox1.Controls.Add(this.lst_inheritgrps); - this.groupBox1.Controls.Add(this.label10); - this.groupBox1.Location = new System.Drawing.Point(222, 66); - this.groupBox1.Name = "groupBox1"; - this.groupBox1.Size = new System.Drawing.Size(374, 76); - this.groupBox1.TabIndex = 26; - this.groupBox1.TabStop = false; - this.groupBox1.Text = "Create New Group"; - // - // label11 - // - this.label11.AutoSize = true; - this.label11.Location = new System.Drawing.Point(6, 25); - this.label11.Name = "label11"; - this.label11.Size = new System.Drawing.Size(65, 13); - this.label11.TabIndex = 22; - this.label11.Text = "Inherit From:"; - // - // btn_newgroup - // - this.btn_newgroup.Location = new System.Drawing.Point(183, 47); - this.btn_newgroup.Name = "btn_newgroup"; - this.btn_newgroup.Size = new System.Drawing.Size(78, 23); - this.btn_newgroup.TabIndex = 18; - this.btn_newgroup.Text = "New Group"; - this.btn_newgroup.UseVisualStyleBackColor = true; - this.btn_newgroup.Click += new System.EventHandler(this.btn_newgroup_Click); - // - // txt_grpname - // - this.txt_grpname.Location = new System.Drawing.Point(77, 49); - this.txt_grpname.Name = "txt_grpname"; - this.txt_grpname.Size = new System.Drawing.Size(100, 20); - this.txt_grpname.TabIndex = 21; - // - // lst_inheritgrps - // - this.lst_inheritgrps.FormattingEnabled = true; - this.lst_inheritgrps.Location = new System.Drawing.Point(77, 22); - this.lst_inheritgrps.Name = "lst_inheritgrps"; - this.lst_inheritgrps.Size = new System.Drawing.Size(100, 21); - this.lst_inheritgrps.TabIndex = 23; - // - // label10 - // - this.label10.AutoSize = true; - this.label10.Location = new System.Drawing.Point(1, 52); - this.label10.Name = "label10"; - this.label10.Size = new System.Drawing.Size(70, 13); - this.label10.TabIndex = 20; - this.label10.Text = "Group Name:"; - // - // label4 - // - this.label4.AutoSize = true; - this.label4.Location = new System.Drawing.Point(324, 144); - this.label4.Name = "label4"; - this.label4.Size = new System.Drawing.Size(114, 13); - this.label4.TabIndex = 17; - this.label4.Text = "Whitelisted Commands"; - // - // label3 - // - this.label3.AutoSize = true; - this.label3.Location = new System.Drawing.Point(6, 145); - this.label3.Name = "label3"; - this.label3.Size = new System.Drawing.Size(99, 13); - this.label3.TabIndex = 16; - this.label3.Text = "Banned Commands"; - // - // btn_moveAllLeftCmd - // - this.btn_moveAllLeftCmd.Location = new System.Drawing.Point(291, 225); - this.btn_moveAllLeftCmd.Name = "btn_moveAllLeftCmd"; - this.btn_moveAllLeftCmd.Size = new System.Drawing.Size(27, 23); - this.btn_moveAllLeftCmd.TabIndex = 15; - this.btn_moveAllLeftCmd.Text = "<<"; - this.btn_moveAllLeftCmd.UseVisualStyleBackColor = true; - this.btn_moveAllLeftCmd.Click += new System.EventHandler(this.btn_moveAllLeftCmd_Click); - // - // btn_moveLeftCmd - // - this.btn_moveLeftCmd.Location = new System.Drawing.Point(290, 313); - this.btn_moveLeftCmd.Name = "btn_moveLeftCmd"; - this.btn_moveLeftCmd.Size = new System.Drawing.Size(27, 23); - this.btn_moveLeftCmd.TabIndex = 14; - this.btn_moveLeftCmd.Text = "<"; - this.btn_moveLeftCmd.UseVisualStyleBackColor = true; - this.btn_moveLeftCmd.Click += new System.EventHandler(this.btn_moveLeftCmd_Click); - // - // btn_moveRightCmd - // - this.btn_moveRightCmd.Location = new System.Drawing.Point(290, 284); - this.btn_moveRightCmd.Name = "btn_moveRightCmd"; - this.btn_moveRightCmd.Size = new System.Drawing.Size(27, 23); - this.btn_moveRightCmd.TabIndex = 13; - this.btn_moveRightCmd.Text = ">"; - this.btn_moveRightCmd.UseVisualStyleBackColor = true; - this.btn_moveRightCmd.Click += new System.EventHandler(this.btn_moveRightCmd_Click); - // - // lst_AvailableCmds - // - this.lst_AvailableCmds.FormattingEnabled = true; - this.lst_AvailableCmds.Location = new System.Drawing.Point(324, 161); - this.lst_AvailableCmds.Name = "lst_AvailableCmds"; - this.lst_AvailableCmds.Size = new System.Drawing.Size(272, 212); - this.lst_AvailableCmds.TabIndex = 12; - // - // btn_moveAllRightCmd - // - this.btn_moveAllRightCmd.Location = new System.Drawing.Point(290, 196); - this.btn_moveAllRightCmd.Name = "btn_moveAllRightCmd"; - this.btn_moveAllRightCmd.Size = new System.Drawing.Size(27, 23); - this.btn_moveAllRightCmd.TabIndex = 11; - this.btn_moveAllRightCmd.Text = ">>"; - this.btn_moveAllRightCmd.UseVisualStyleBackColor = true; - this.btn_moveAllRightCmd.Click += new System.EventHandler(this.btn_moveAllRightCmd_Click); - // - // lst_bannedCmds - // - this.lst_bannedCmds.FormattingEnabled = true; - this.lst_bannedCmds.Location = new System.Drawing.Point(9, 161); - this.lst_bannedCmds.Name = "lst_bannedCmds"; - this.lst_bannedCmds.Size = new System.Drawing.Size(275, 212); - this.lst_bannedCmds.TabIndex = 10; - // - // lst_groupList - // - this.lst_groupList.FormattingEnabled = true; - this.lst_groupList.Location = new System.Drawing.Point(9, 8); - this.lst_groupList.Name = "lst_groupList"; - this.lst_groupList.Size = new System.Drawing.Size(200, 134); - this.lst_groupList.TabIndex = 0; - this.lst_groupList.SelectedIndexChanged += new System.EventHandler(this.lst_groupList_SelectedIndexChanged); - // - // tabPage5 - // - this.tabPage5.Controls.Add(this.groupBox4); - this.tabPage5.Controls.Add(this.groupBox3); - this.tabPage5.Controls.Add(this.lst_userlist); - this.tabPage5.Location = new System.Drawing.Point(4, 22); - this.tabPage5.Name = "tabPage5"; - this.tabPage5.Padding = new System.Windows.Forms.Padding(3); - this.tabPage5.Size = new System.Drawing.Size(602, 381); - this.tabPage5.TabIndex = 2; - this.tabPage5.Text = "User Manager"; - this.tabPage5.UseVisualStyleBackColor = true; - // - // groupBox4 - // - this.groupBox4.Controls.Add(this.lbl_useraddstatus); - this.groupBox4.Controls.Add(this.btn_adduser); - this.groupBox4.Controls.Add(this.label20); - this.groupBox4.Controls.Add(this.label22); - this.groupBox4.Controls.Add(this.txt_newusername); - this.groupBox4.Controls.Add(this.txt_newuserpass); - this.groupBox4.Controls.Add(this.txt_newuserip); - this.groupBox4.Controls.Add(this.lst_newusergrplist); - this.groupBox4.Controls.Add(this.label24); - this.groupBox4.Controls.Add(this.label25); - this.groupBox4.Location = new System.Drawing.Point(294, 173); - this.groupBox4.Name = "groupBox4"; - this.groupBox4.Size = new System.Drawing.Size(296, 161); - this.groupBox4.TabIndex = 15; - this.groupBox4.TabStop = false; - this.groupBox4.Text = "New User"; - // - // lbl_useraddstatus - // - this.lbl_useraddstatus.AutoSize = true; - this.lbl_useraddstatus.Location = new System.Drawing.Point(87, 135); - this.lbl_useraddstatus.Name = "lbl_useraddstatus"; - this.lbl_useraddstatus.Size = new System.Drawing.Size(146, 13); - this.lbl_useraddstatus.TabIndex = 23; - this.lbl_useraddstatus.Text = "Status messages display here"; - this.lbl_useraddstatus.Visible = false; - // - // btn_adduser - // - this.btn_adduser.Location = new System.Drawing.Point(6, 130); - this.btn_adduser.Name = "btn_adduser"; - this.btn_adduser.Size = new System.Drawing.Size(75, 23); - this.btn_adduser.TabIndex = 22; - this.btn_adduser.Text = "Add User"; - this.btn_adduser.UseVisualStyleBackColor = true; - this.btn_adduser.Click += new System.EventHandler(this.btn_adduser_Click); - // - // label20 - // - this.label20.AutoSize = true; - this.label20.Location = new System.Drawing.Point(6, 28); - this.label20.Name = "label20"; - this.label20.Size = new System.Drawing.Size(63, 13); - this.label20.TabIndex = 14; - this.label20.Text = "User Name:"; - // - // label22 - // - this.label22.AutoSize = true; - this.label22.Location = new System.Drawing.Point(13, 107); - this.label22.Name = "label22"; - this.label22.Size = new System.Drawing.Size(56, 13); - this.label22.TabIndex = 21; - this.label22.Text = "Password:"; - // - // txt_newusername - // - this.txt_newusername.Location = new System.Drawing.Point(75, 25); - this.txt_newusername.Name = "txt_newusername"; - this.txt_newusername.Size = new System.Drawing.Size(221, 20); - this.txt_newusername.TabIndex = 18; - // - // txt_newuserpass - // - this.txt_newuserpass.Location = new System.Drawing.Point(75, 104); - this.txt_newuserpass.Name = "txt_newuserpass"; - this.txt_newuserpass.Size = new System.Drawing.Size(221, 20); - this.txt_newuserpass.TabIndex = 19; - // - // txt_newuserip - // - this.txt_newuserip.Location = new System.Drawing.Point(75, 78); - this.txt_newuserip.Name = "txt_newuserip"; - this.txt_newuserip.Size = new System.Drawing.Size(221, 20); - this.txt_newuserip.TabIndex = 20; - // - // lst_newusergrplist - // - this.lst_newusergrplist.FormattingEnabled = true; - this.lst_newusergrplist.Location = new System.Drawing.Point(75, 51); - this.lst_newusergrplist.Name = "lst_newusergrplist"; - this.lst_newusergrplist.Size = new System.Drawing.Size(221, 21); - this.lst_newusergrplist.TabIndex = 16; - // - // label24 - // - this.label24.AutoSize = true; - this.label24.Location = new System.Drawing.Point(49, 81); - this.label24.Name = "label24"; - this.label24.Size = new System.Drawing.Size(20, 13); - this.label24.TabIndex = 17; - this.label24.Text = "IP:"; - // - // label25 - // - this.label25.AutoSize = true; - this.label25.Location = new System.Drawing.Point(30, 54); - this.label25.Name = "label25"; - this.label25.Size = new System.Drawing.Size(39, 13); - this.label25.TabIndex = 15; - this.label25.Text = "Group:"; - // - // groupBox3 - // - this.groupBox3.Controls.Add(this.label13); - this.groupBox3.Controls.Add(this.btn_deluser); - this.groupBox3.Controls.Add(this.label23); - this.groupBox3.Controls.Add(this.txt_username); - this.groupBox3.Controls.Add(this.txt_userpass); - this.groupBox3.Controls.Add(this.txt_userip); - this.groupBox3.Controls.Add(this.lst_usergrplist); - this.groupBox3.Controls.Add(this.label21); - this.groupBox3.Controls.Add(this.label14); - this.groupBox3.Location = new System.Drawing.Point(294, 7); - this.groupBox3.Name = "groupBox3"; - this.groupBox3.Size = new System.Drawing.Size(302, 159); - this.groupBox3.TabIndex = 14; - this.groupBox3.TabStop = false; - this.groupBox3.Text = "Current User"; - // - // label13 - // - this.label13.AutoSize = true; - this.label13.Location = new System.Drawing.Point(6, 26); - this.label13.Name = "label13"; - this.label13.Size = new System.Drawing.Size(63, 13); - this.label13.TabIndex = 1; - this.label13.Text = "User Name:"; - // - // btn_deluser - // - this.btn_deluser.Location = new System.Drawing.Point(6, 128); - this.btn_deluser.Name = "btn_deluser"; - this.btn_deluser.Size = new System.Drawing.Size(75, 23); - this.btn_deluser.TabIndex = 8; - this.btn_deluser.Text = "Delete User"; - this.btn_deluser.UseVisualStyleBackColor = true; - this.btn_deluser.Click += new System.EventHandler(this.btn_deluser_Click); - // - // label23 - // - this.label23.AutoSize = true; - this.label23.Location = new System.Drawing.Point(13, 105); - this.label23.Name = "label23"; - this.label23.Size = new System.Drawing.Size(56, 13); - this.label23.TabIndex = 13; - this.label23.Text = "Password:"; - // - // txt_username - // - this.txt_username.Location = new System.Drawing.Point(75, 23); - this.txt_username.Name = "txt_username"; - this.txt_username.ReadOnly = true; - this.txt_username.Size = new System.Drawing.Size(221, 20); - this.txt_username.TabIndex = 9; - // - // txt_userpass - // - this.txt_userpass.Location = new System.Drawing.Point(75, 102); - this.txt_userpass.Name = "txt_userpass"; - this.txt_userpass.ReadOnly = true; - this.txt_userpass.Size = new System.Drawing.Size(221, 20); - this.txt_userpass.TabIndex = 10; - // - // txt_userip - // - this.txt_userip.Location = new System.Drawing.Point(75, 76); - this.txt_userip.Name = "txt_userip"; - this.txt_userip.ReadOnly = true; - this.txt_userip.Size = new System.Drawing.Size(221, 20); - this.txt_userip.TabIndex = 12; - // - // lst_usergrplist - // - this.lst_usergrplist.FormattingEnabled = true; - this.lst_usergrplist.Location = new System.Drawing.Point(75, 49); - this.lst_usergrplist.Name = "lst_usergrplist"; - this.lst_usergrplist.Size = new System.Drawing.Size(221, 21); - this.lst_usergrplist.TabIndex = 4; - this.lst_usergrplist.SelectedIndexChanged += new System.EventHandler(this.lst_usergrplist_SelectedIndexChanged); - // - // label21 - // - this.label21.AutoSize = true; - this.label21.Location = new System.Drawing.Point(49, 79); - this.label21.Name = "label21"; - this.label21.Size = new System.Drawing.Size(20, 13); - this.label21.TabIndex = 6; - this.label21.Text = "IP:"; - // - // label14 - // - this.label14.AutoSize = true; - this.label14.Location = new System.Drawing.Point(30, 52); - this.label14.Name = "label14"; - this.label14.Size = new System.Drawing.Size(39, 13); - this.label14.TabIndex = 3; - this.label14.Text = "Group:"; - // - // lst_userlist - // - this.lst_userlist.FormattingEnabled = true; - this.lst_userlist.Location = new System.Drawing.Point(9, 7); - this.lst_userlist.Name = "lst_userlist"; - this.lst_userlist.Size = new System.Drawing.Size(275, 368); - this.lst_userlist.TabIndex = 0; - this.lst_userlist.SelectedIndexChanged += new System.EventHandler(this.lst_userlist_SelectedIndexChanged); - // - // tabPage6 - // - this.tabPage6.Controls.Add(this.groupBox7); - this.tabPage6.Controls.Add(this.groupBox6); - this.tabPage6.Controls.Add(this.groupBox5); - this.tabPage6.Location = new System.Drawing.Point(4, 22); - this.tabPage6.Name = "tabPage6"; - this.tabPage6.Padding = new System.Windows.Forms.Padding(3); - this.tabPage6.Size = new System.Drawing.Size(602, 381); - this.tabPage6.TabIndex = 3; - this.tabPage6.Text = "Ban Manager"; - this.tabPage6.UseVisualStyleBackColor = true; - // - // groupBox7 - // - this.groupBox7.Controls.Add(this.lst_bans); - this.groupBox7.Location = new System.Drawing.Point(6, 23); - this.groupBox7.Name = "groupBox7"; - this.groupBox7.Size = new System.Drawing.Size(284, 352); - this.groupBox7.TabIndex = 13; - this.groupBox7.TabStop = false; - this.groupBox7.Text = "Ban List"; - // - // lst_bans - // - this.lst_bans.FormattingEnabled = true; - this.lst_bans.Location = new System.Drawing.Point(6, 19); - this.lst_bans.Name = "lst_bans"; - this.lst_bans.Size = new System.Drawing.Size(272, 329); - this.lst_bans.TabIndex = 0; - this.lst_bans.SelectedIndexChanged += new System.EventHandler(this.lst_bans_SelectedIndexChanged); - // - // groupBox6 - // - this.groupBox6.Controls.Add(this.lbl_newbanstatus); - this.groupBox6.Controls.Add(this.label16); - this.groupBox6.Controls.Add(this.btn_bannew); - this.groupBox6.Controls.Add(this.txt_newbanip); - this.groupBox6.Controls.Add(this.txt_newbanreason); - this.groupBox6.Controls.Add(this.txt_newbanname); - this.groupBox6.Controls.Add(this.label27); - this.groupBox6.Controls.Add(this.label26); - this.groupBox6.Location = new System.Drawing.Point(296, 165); - this.groupBox6.Name = "groupBox6"; - this.groupBox6.Size = new System.Drawing.Size(300, 137); - this.groupBox6.TabIndex = 12; - this.groupBox6.TabStop = false; - this.groupBox6.Text = "New Ban"; - // - // lbl_newbanstatus - // - this.lbl_newbanstatus.AutoSize = true; - this.lbl_newbanstatus.Location = new System.Drawing.Point(90, 113); - this.lbl_newbanstatus.Name = "lbl_newbanstatus"; - this.lbl_newbanstatus.Size = new System.Drawing.Size(146, 13); - this.lbl_newbanstatus.TabIndex = 16; - this.lbl_newbanstatus.Text = "Status messages display here"; - this.lbl_newbanstatus.Visible = false; - // - // label16 - // - this.label16.AutoSize = true; - this.label16.Location = new System.Drawing.Point(2, 33); - this.label16.Name = "label16"; - this.label16.Size = new System.Drawing.Size(65, 13); - this.label16.TabIndex = 10; - this.label16.Text = "*IP Address:"; - // - // btn_bannew - // - this.btn_bannew.Location = new System.Drawing.Point(9, 108); - this.btn_bannew.Name = "btn_bannew"; - this.btn_bannew.Size = new System.Drawing.Size(75, 23); - this.btn_bannew.TabIndex = 10; - this.btn_bannew.Text = "New Ban"; - this.btn_bannew.UseVisualStyleBackColor = true; - this.btn_bannew.Click += new System.EventHandler(this.btn_bannew_Click); - // - // txt_newbanip - // - this.txt_newbanip.Location = new System.Drawing.Point(73, 30); - this.txt_newbanip.Name = "txt_newbanip"; - this.txt_newbanip.Size = new System.Drawing.Size(221, 20); - this.txt_newbanip.TabIndex = 13; - // - // txt_newbanreason - // - this.txt_newbanreason.Location = new System.Drawing.Point(74, 82); - this.txt_newbanreason.Multiline = true; - this.txt_newbanreason.Name = "txt_newbanreason"; - this.txt_newbanreason.Size = new System.Drawing.Size(220, 20); - this.txt_newbanreason.TabIndex = 15; - // - // txt_newbanname - // - this.txt_newbanname.Location = new System.Drawing.Point(74, 56); - this.txt_newbanname.Name = "txt_newbanname"; - this.txt_newbanname.Size = new System.Drawing.Size(220, 20); - this.txt_newbanname.TabIndex = 14; - // - // label27 - // - this.label27.AutoSize = true; - this.label27.Location = new System.Drawing.Point(25, 59); - this.label27.Name = "label27"; - this.label27.Size = new System.Drawing.Size(42, 13); - this.label27.TabIndex = 11; - this.label27.Text = "*Name:"; - // - // label26 - // - this.label26.AutoSize = true; - this.label26.Location = new System.Drawing.Point(21, 85); - this.label26.Name = "label26"; - this.label26.Size = new System.Drawing.Size(47, 13); - this.label26.TabIndex = 12; - this.label26.Text = "Reason:"; - // - // groupBox5 - // - this.groupBox5.Controls.Add(this.label17); - this.groupBox5.Controls.Add(this.txt_banip); - this.groupBox5.Controls.Add(this.btn_bandelete); - this.groupBox5.Controls.Add(this.txt_banname); - this.groupBox5.Controls.Add(this.label19); - this.groupBox5.Controls.Add(this.txt_banreason); - this.groupBox5.Controls.Add(this.label18); - this.groupBox5.Location = new System.Drawing.Point(296, 23); - this.groupBox5.Name = "groupBox5"; - this.groupBox5.Size = new System.Drawing.Size(300, 129); - this.groupBox5.TabIndex = 11; - this.groupBox5.TabStop = false; - this.groupBox5.Text = "Selected Ban"; - // - // label17 - // - this.label17.AutoSize = true; - this.label17.Location = new System.Drawing.Point(6, 26); - this.label17.Name = "label17"; - this.label17.Size = new System.Drawing.Size(61, 13); - this.label17.TabIndex = 3; - this.label17.Text = "IP Address:"; - // - // txt_banip - // - this.txt_banip.Location = new System.Drawing.Point(73, 23); - this.txt_banip.Name = "txt_banip"; - this.txt_banip.ReadOnly = true; - this.txt_banip.Size = new System.Drawing.Size(221, 20); - this.txt_banip.TabIndex = 6; - // - // btn_bandelete - // - this.btn_bandelete.Location = new System.Drawing.Point(9, 100); - this.btn_bandelete.Name = "btn_bandelete"; - this.btn_bandelete.Size = new System.Drawing.Size(75, 23); - this.btn_bandelete.TabIndex = 9; - this.btn_bandelete.Text = "Delete Ban"; - this.btn_bandelete.UseVisualStyleBackColor = true; - this.btn_bandelete.Click += new System.EventHandler(this.btn_bandelete_Click); - // - // txt_banname - // - this.txt_banname.Location = new System.Drawing.Point(74, 49); - this.txt_banname.Name = "txt_banname"; - this.txt_banname.ReadOnly = true; - this.txt_banname.Size = new System.Drawing.Size(220, 20); - this.txt_banname.TabIndex = 7; - // - // label19 - // - this.label19.AutoSize = true; - this.label19.Location = new System.Drawing.Point(21, 78); - this.label19.Name = "label19"; - this.label19.Size = new System.Drawing.Size(47, 13); - this.label19.TabIndex = 5; - this.label19.Text = "Reason:"; - // - // txt_banreason - // - this.txt_banreason.Location = new System.Drawing.Point(74, 75); - this.txt_banreason.Multiline = true; - this.txt_banreason.Name = "txt_banreason"; - this.txt_banreason.Size = new System.Drawing.Size(220, 20); - this.txt_banreason.TabIndex = 8; - this.txt_banreason.TextChanged += new System.EventHandler(this.txt_banreason_TextChanged); - // - // label18 - // - this.label18.AutoSize = true; - this.label18.Location = new System.Drawing.Point(30, 52); - this.label18.Name = "label18"; - this.label18.Size = new System.Drawing.Size(38, 13); - this.label18.TabIndex = 4; - this.label18.Text = "Name:"; - // - // tabControl1 - // - this.tabControl1.Controls.Add(this.tabPage3); - this.tabControl1.Controls.Add(this.tabPage4); - this.tabControl1.Location = new System.Drawing.Point(12, 12); - this.tabControl1.Name = "tabControl1"; - this.tabControl1.SelectedIndex = 0; - this.tabControl1.Size = new System.Drawing.Size(610, 125); - this.tabControl1.TabIndex = 6; - // - // tabPage3 - // - this.tabPage3.Controls.Add(this.btn_OpenLocalDB); - this.tabPage3.Location = new System.Drawing.Point(4, 22); - this.tabPage3.Name = "tabPage3"; - this.tabPage3.Padding = new System.Windows.Forms.Padding(3); - this.tabPage3.Size = new System.Drawing.Size(602, 99); - this.tabPage3.TabIndex = 0; - this.tabPage3.Text = "Local Database (SQLite)"; - this.tabPage3.UseVisualStyleBackColor = true; - // - // btn_OpenLocalDB - // - this.btn_OpenLocalDB.Location = new System.Drawing.Point(9, 6); - this.btn_OpenLocalDB.Name = "btn_OpenLocalDB"; - this.btn_OpenLocalDB.Size = new System.Drawing.Size(96, 23); - this.btn_OpenLocalDB.TabIndex = 0; - this.btn_OpenLocalDB.Text = "Open Database"; - this.btn_OpenLocalDB.UseVisualStyleBackColor = true; - this.btn_OpenLocalDB.Click += new System.EventHandler(this.btn_OpenLocalDB_Click); - // - // tabPage4 - // - this.tabPage4.Controls.Add(this.btn_connect); - this.tabPage4.Controls.Add(this.label9); - this.tabPage4.Controls.Add(this.txt_dbpassword); - this.tabPage4.Controls.Add(this.label8); - this.tabPage4.Controls.Add(this.txt_dbusername); - this.tabPage4.Controls.Add(this.txt_port); - this.tabPage4.Controls.Add(this.txt_dbname); - this.tabPage4.Controls.Add(this.txt_hostname); - this.tabPage4.Controls.Add(this.label7); - this.tabPage4.Controls.Add(this.label6); - this.tabPage4.Controls.Add(this.label5); - this.tabPage4.Location = new System.Drawing.Point(4, 22); - this.tabPage4.Name = "tabPage4"; - this.tabPage4.Padding = new System.Windows.Forms.Padding(3); - this.tabPage4.Size = new System.Drawing.Size(602, 99); - this.tabPage4.TabIndex = 1; - this.tabPage4.Text = "Remote Database (MySql)"; - this.tabPage4.UseVisualStyleBackColor = true; - // - // btn_connect - // - this.btn_connect.Location = new System.Drawing.Point(213, 63); - this.btn_connect.Name = "btn_connect"; - this.btn_connect.Size = new System.Drawing.Size(75, 23); - this.btn_connect.TabIndex = 10; - this.btn_connect.Text = "Connect"; - this.btn_connect.UseVisualStyleBackColor = true; - this.btn_connect.Click += new System.EventHandler(this.btn_connect_Click); - // - // label9 - // - this.label9.AutoSize = true; - this.label9.Location = new System.Drawing.Point(210, 36); - this.label9.Name = "label9"; - this.label9.Size = new System.Drawing.Size(56, 13); - this.label9.TabIndex = 9; - this.label9.Text = "Password:"; - // - // txt_dbpassword - // - this.txt_dbpassword.Location = new System.Drawing.Point(272, 33); - this.txt_dbpassword.Name = "txt_dbpassword"; - this.txt_dbpassword.Size = new System.Drawing.Size(100, 20); - this.txt_dbpassword.TabIndex = 8; - // - // label8 - // - this.label8.AutoSize = true; - this.label8.Location = new System.Drawing.Point(208, 10); - this.label8.Name = "label8"; - this.label8.Size = new System.Drawing.Size(58, 13); - this.label8.TabIndex = 7; - this.label8.Text = "Username:"; - // - // txt_dbusername - // - this.txt_dbusername.Location = new System.Drawing.Point(272, 7); - this.txt_dbusername.Name = "txt_dbusername"; - this.txt_dbusername.Size = new System.Drawing.Size(100, 20); - this.txt_dbusername.TabIndex = 6; - // - // txt_port - // - this.txt_port.Location = new System.Drawing.Point(102, 60); - this.txt_port.Name = "txt_port"; - this.txt_port.Size = new System.Drawing.Size(100, 20); - this.txt_port.TabIndex = 5; - this.txt_port.Text = "3306"; - // - // txt_dbname - // - this.txt_dbname.Location = new System.Drawing.Point(102, 33); - this.txt_dbname.Name = "txt_dbname"; - this.txt_dbname.Size = new System.Drawing.Size(100, 20); - this.txt_dbname.TabIndex = 4; - // - // txt_hostname - // - this.txt_hostname.Location = new System.Drawing.Point(102, 7); - this.txt_hostname.Name = "txt_hostname"; - this.txt_hostname.Size = new System.Drawing.Size(100, 20); - this.txt_hostname.TabIndex = 3; - this.txt_hostname.Text = "localhost"; - // - // label7 - // - this.label7.AutoSize = true; - this.label7.Location = new System.Drawing.Point(70, 63); - this.label7.Name = "label7"; - this.label7.Size = new System.Drawing.Size(26, 13); - this.label7.TabIndex = 2; - this.label7.Text = "Port"; - // - // label6 - // - this.label6.AutoSize = true; - this.label6.Location = new System.Drawing.Point(9, 36); - this.label6.Name = "label6"; - this.label6.Size = new System.Drawing.Size(87, 13); - this.label6.TabIndex = 1; - this.label6.Text = "Database Name:"; - // - // label5 - // - this.label5.AutoSize = true; - this.label5.Location = new System.Drawing.Point(38, 10); - this.label5.Name = "label5"; - this.label5.Size = new System.Drawing.Size(58, 13); - this.label5.TabIndex = 0; - this.label5.Text = "Hostname:"; - // - // TShockDBEditor - // - this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); - this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.ClientSize = new System.Drawing.Size(634, 562); - this.Controls.Add(this.tabControl1); - this.Controls.Add(this.tabControl); - this.Name = "TShockDBEditor"; - this.Text = "TShockDBEditor"; - this.Load += new System.EventHandler(this.TShockDBEditor_Load); - this.tabControl.ResumeLayout(false); - this.tabPage1.ResumeLayout(false); - this.tabPage1.PerformLayout(); - this.tabPage2.ResumeLayout(false); - this.tabPage2.PerformLayout(); - this.groupBox2.ResumeLayout(false); - this.groupBox2.PerformLayout(); - this.groupBox1.ResumeLayout(false); - this.groupBox1.PerformLayout(); - this.tabPage5.ResumeLayout(false); - this.groupBox4.ResumeLayout(false); - this.groupBox4.PerformLayout(); - this.groupBox3.ResumeLayout(false); - this.groupBox3.PerformLayout(); - this.tabPage6.ResumeLayout(false); - this.groupBox7.ResumeLayout(false); - this.groupBox6.ResumeLayout(false); - this.groupBox6.PerformLayout(); - this.groupBox5.ResumeLayout(false); - this.groupBox5.PerformLayout(); - this.tabControl1.ResumeLayout(false); - this.tabPage3.ResumeLayout(false); - this.tabPage4.ResumeLayout(false); - this.tabPage4.PerformLayout(); - this.ResumeLayout(false); - - } - - #endregion - - private System.Windows.Forms.ListBox itemListBanned; - private System.Windows.Forms.ListBox itemListAvailable; - private System.Windows.Forms.TabControl tabControl; - private System.Windows.Forms.TabPage tabPage1; - private System.Windows.Forms.TabPage tabPage2; - private System.Windows.Forms.Label label2; - private System.Windows.Forms.Label label1; - private System.Windows.Forms.Button btn_moveAllLeft; - private System.Windows.Forms.Button btn_moveAllRight; - private System.Windows.Forms.Button btn_moveLeft; - private System.Windows.Forms.Button btn_moveRight; - private System.Windows.Forms.TabControl tabControl1; - private System.Windows.Forms.TabPage tabPage3; - private System.Windows.Forms.TabPage tabPage4; - private System.Windows.Forms.Button btn_OpenLocalDB; - private System.Windows.Forms.Button btn_moveAllLeftCmd; - private System.Windows.Forms.Button btn_moveLeftCmd; - private System.Windows.Forms.Button btn_moveRightCmd; - private System.Windows.Forms.ListBox lst_AvailableCmds; - private System.Windows.Forms.Button btn_moveAllRightCmd; - private System.Windows.Forms.ListBox lst_bannedCmds; - private System.Windows.Forms.ListBox lst_groupList; - private System.Windows.Forms.Label label4; - private System.Windows.Forms.Label label3; - private System.Windows.Forms.Label label5; - private System.Windows.Forms.Button btn_connect; - private System.Windows.Forms.Label label9; - private System.Windows.Forms.TextBox txt_dbpassword; - private System.Windows.Forms.Label label8; - private System.Windows.Forms.TextBox txt_dbusername; - private System.Windows.Forms.TextBox txt_port; - private System.Windows.Forms.TextBox txt_dbname; - private System.Windows.Forms.TextBox txt_hostname; - private System.Windows.Forms.Label label7; - private System.Windows.Forms.Label label6; - private System.Windows.Forms.Button btn_deletegroup; - private System.Windows.Forms.Button btn_newgroup; - private System.Windows.Forms.ComboBox lst_inheritgrps; - private System.Windows.Forms.Label label11; - private System.Windows.Forms.TextBox txt_grpname; - private System.Windows.Forms.Label label10; - private System.Windows.Forms.Label lbl_grpchild; - private System.Windows.Forms.Label label12; - private System.Windows.Forms.TabPage tabPage5; - private System.Windows.Forms.Label label14; - private System.Windows.Forms.Label label13; - private System.Windows.Forms.ListBox lst_userlist; - private System.Windows.Forms.ComboBox lst_usergrplist; - private System.Windows.Forms.TabPage tabPage6; - private System.Windows.Forms.ListBox lst_bans; - private System.Windows.Forms.Label label18; - private System.Windows.Forms.Label label17; - private System.Windows.Forms.TextBox txt_banreason; - private System.Windows.Forms.TextBox txt_banname; - private System.Windows.Forms.TextBox txt_banip; - private System.Windows.Forms.Label label19; - private System.Windows.Forms.Button btn_bannew; - private System.Windows.Forms.Button btn_bandelete; - private System.Windows.Forms.Label label21; - private System.Windows.Forms.Button btn_deluser; - private System.Windows.Forms.Label label23; - private System.Windows.Forms.TextBox txt_userip; - private System.Windows.Forms.TextBox txt_userpass; - private System.Windows.Forms.TextBox txt_username; - private System.Windows.Forms.GroupBox groupBox2; - private System.Windows.Forms.GroupBox groupBox1; - private System.Windows.Forms.GroupBox groupBox3; - private System.Windows.Forms.GroupBox groupBox4; - private System.Windows.Forms.Button btn_adduser; - private System.Windows.Forms.Label label20; - private System.Windows.Forms.Label label22; - private System.Windows.Forms.TextBox txt_newusername; - private System.Windows.Forms.TextBox txt_newuserpass; - private System.Windows.Forms.TextBox txt_newuserip; - private System.Windows.Forms.ComboBox lst_newusergrplist; - private System.Windows.Forms.Label label24; - private System.Windows.Forms.Label label25; - private System.Windows.Forms.Label lbl_useraddstatus; - private System.Windows.Forms.GroupBox groupBox6; - private System.Windows.Forms.GroupBox groupBox5; - private System.Windows.Forms.Label label16; - private System.Windows.Forms.TextBox txt_newbanip; - private System.Windows.Forms.TextBox txt_newbanreason; - private System.Windows.Forms.TextBox txt_newbanname; - private System.Windows.Forms.Label label27; - private System.Windows.Forms.Label label26; - private System.Windows.Forms.Label lbl_newbanstatus; - private System.Windows.Forms.GroupBox groupBox7; - } -} - diff --git a/DBEditor/Main.cs b/DBEditor/Main.cs deleted file mode 100644 index 81d21f04..00000000 --- a/DBEditor/Main.cs +++ /dev/null @@ -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 . -*/ -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 groups = new List(); - public static List CommandList = new List(); - 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("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("GroupName")); - lst_inheritgrps.Items.Add(reader.Get("GroupName")); - lst_usergrplist.Items.Add(reader.Get("GroupName")); - lst_newusergrplist.Items.Add(reader.Get("GroupName")); - } - } - - using (var reader = com.ExecuteReader()) - { - while (reader.Read()) - { - foreach (string command in reader.Get("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("UserName") != "") - lst_userlist.Items.Add(reader.Get("UserName")); - else - lst_userlist.Items.Add(reader.Get("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("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("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("GroupName")); - lst_usergrplist.Items.Add(reader.Get("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("IP"); - txt_banname.Text = reader.Get("Name"); - txt_banreason.Text = reader.Get("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("Username"); - - if (reader.Get("IP") != "") - txt_userip.Text = reader.Get("IP"); - else - txt_userip.Text = "User does not have IP"; - - if (reader.Get("Password") != "") - txt_userpass.Text = reader.Get("Password"); - else - txt_userpass.Text = "User does not have Pasword"; - - foreach (string name in lst_usergrplist.Items) - { - if (name == reader.Get("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("Password") != "") - txt_userpass.Text = reader.Get("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("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) - { - - } - } -} \ No newline at end of file diff --git a/DBEditor/Main.resx b/DBEditor/Main.resx deleted file mode 100644 index 1af7de15..00000000 --- a/DBEditor/Main.resx +++ /dev/null @@ -1,120 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - \ No newline at end of file diff --git a/DBEditor/Properties/AssemblyInfo.cs b/DBEditor/Properties/AssemblyInfo.cs deleted file mode 100644 index 80567a20..00000000 --- a/DBEditor/Properties/AssemblyInfo.cs +++ /dev/null @@ -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 . -*/ -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")] diff --git a/DBEditor/Properties/Resources.Designer.cs b/DBEditor/Properties/Resources.Designer.cs deleted file mode 100644 index ef2100a0..00000000 --- a/DBEditor/Properties/Resources.Designer.cs +++ /dev/null @@ -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 . -*/ - -//------------------------------------------------------------------------------ -// -// 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. -// -//------------------------------------------------------------------------------ - -namespace TShockDBEditor.Properties { - using System; - - - /// - /// A strongly-typed resource class, for looking up localized strings, etc. - /// - // 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() { - } - - /// - /// Returns the cached ResourceManager instance used by this class. - /// - [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; - } - } - - /// - /// Overrides the current thread's CurrentUICulture property for all - /// resource lookups using this strongly typed resource class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Globalization.CultureInfo Culture { - get { - return resourceCulture; - } - set { - resourceCulture = value; - } - } - } -} diff --git a/DBEditor/Properties/Resources.resx b/DBEditor/Properties/Resources.resx deleted file mode 100644 index af7dbebb..00000000 --- a/DBEditor/Properties/Resources.resx +++ /dev/null @@ -1,117 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - \ No newline at end of file diff --git a/DBEditor/Properties/Settings.Designer.cs b/DBEditor/Properties/Settings.Designer.cs deleted file mode 100644 index 0288467b..00000000 --- a/DBEditor/Properties/Settings.Designer.cs +++ /dev/null @@ -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 . -*/ - -//------------------------------------------------------------------------------ -// -// 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. -// -//------------------------------------------------------------------------------ - -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; - } - } - } -} diff --git a/DBEditor/Properties/Settings.settings b/DBEditor/Properties/Settings.settings deleted file mode 100644 index 39645652..00000000 --- a/DBEditor/Properties/Settings.settings +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/DBEditor/TShockDBEditor.csproj b/DBEditor/TShockDBEditor.csproj deleted file mode 100644 index 25b8d7d8..00000000 --- a/DBEditor/TShockDBEditor.csproj +++ /dev/null @@ -1,148 +0,0 @@ - - - - Debug - x86 - 8.0.30703 - 2.0 - {F1AE395C-6B4D-40E0-8BF8-0D8A126488D3} - WinExe - Properties - TShockDBEditor - TShockDBEditor - v4.0 - - - 512 - false - publish\ - true - Disk - false - Foreground - 7 - Days - false - false - true - 0 - 1.0.0.%2a - false - true - - - x86 - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - x86 - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - - ..\SqlBins\Mono.Data.Sqlite.dll - - - False - ..\SqlBins\MySql.Data.dll - True - - - False - ..\SqlBins\MySql.Web.dll - True - - - - - - - - - - - - - - - - - - Form - - - Main.cs - - - - - - Main.cs - - - ResXFileCodeGenerator - Resources.Designer.cs - Designer - - - True - Resources.resx - True - - - - SettingsSingleFileGenerator - Settings.Designer.cs - - - True - Settings.settings - True - - - - - - - - - False - Microsoft .NET Framework 4 %28x86 and x64%29 - true - - - False - .NET Framework 3.5 SP1 Client Profile - false - - - False - .NET Framework 3.5 SP1 - false - - - False - Windows Installer 3.1 - true - - - - - \ No newline at end of file diff --git a/DBEditor/TShockDBEditor.licenseheader b/DBEditor/TShockDBEditor.licenseheader deleted file mode 100644 index 12ed0ea9..00000000 --- a/DBEditor/TShockDBEditor.licenseheader +++ /dev/null @@ -1,18 +0,0 @@ -extensions: .cs -/* -TShock, a server mod for Terraria -Copyright (C) 2011-2012 The TShock Team - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . -*/ \ No newline at end of file diff --git a/DBEditor/app.config b/DBEditor/app.config deleted file mode 100644 index e3656033..00000000 --- a/DBEditor/app.config +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/README.md b/README.md index 0eae0b9a..a993e427 100644 --- a/README.md +++ b/README.md @@ -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. \ No newline at end of file +* [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) diff --git a/TShock.sln b/TShock.sln index 7731de44..da320f87 100644 --- a/TShock.sln +++ b/TShock.sln @@ -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 diff --git a/TShockAPI/BackupManager.cs b/TShockAPI/BackupManager.cs index bb51336e..bc5cec6a 100644 --- a/TShockAPI/BackupManager.cs +++ b/TShockAPI/BackupManager.cs @@ -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 . */ + 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()); } } diff --git a/TShockAPI/Commands.cs b/TShockAPI/Commands.cs index 0dc8d053..d26ac5f6 100644 --- a/TShockAPI/Commands.cs +++ b/TShockAPI/Commands.cs @@ -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,18 +15,18 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ + using System; using System.Collections.Generic; +using System.Collections.ObjectModel; using System.Diagnostics; -using System.Diagnostics.CodeAnalysis; using System.IO; using System.Linq; -using System.Net; using System.Text; using System.Threading; +using TShockAPI.PluginUpdater; using Terraria; using TShockAPI.DB; -using System.Reflection; namespace TShockAPI { @@ -64,38 +64,60 @@ namespace TShockAPI } public List Names { get; protected set; } + public bool AllowServer { get; set; } public bool DoLog { get; set; } - public string Permission { get; protected set; } - private CommandDelegate command; + public List Permissions { get; protected set; } + + private CommandDelegate commandDelegate; + public CommandDelegate CommandDelegate + { + get { return commandDelegate; } + set + { + if (value == null) + throw new ArgumentNullException(); + + commandDelegate = value; + } + } + + public Command(List permissionsneeded, CommandDelegate cmd, params string[] names) + : this(cmd, names) + { + Permissions = permissionsneeded; + } public Command(string permissionneeded, CommandDelegate cmd, params string[] names) : this(cmd, names) { - Permission = permissionneeded; + Permissions = new List { permissionneeded }; } public Command(CommandDelegate cmd, params string[] names) { + if (cmd == null) + throw new ArgumentNullException("cmd"); if (names == null || names.Length < 1) - throw new NotSupportedException(); - Permission = null; + throw new ArgumentException("names"); + Permissions = new List(); Names = new List(names); - command = cmd; + CommandDelegate = cmd; + AllowServer = true; DoLog = true; } public bool Run(string msg, TSPlayer ply, List parms) { - if (!ply.Group.HasPermission(Permission)) + if (!CanRun(ply)) return false; try { - command(new CommandArgs(msg, ply, parms)); + CommandDelegate(new CommandArgs(msg, ply, parms)); } catch (Exception e) { - ply.SendMessage("Command failed, check logs for more details."); + ply.SendErrorMessage("Command failed, check logs for more details."); Log.Error(e.ToString()); } @@ -109,54 +131,80 @@ namespace TShockAPI public bool CanRun(TSPlayer ply) { - return ply.Group.HasPermission(Permission); + if (Permissions == null || Permissions.Count < 1) + return true; + foreach (var Permission in Permissions) + { + if (ply.Group.HasPermission(Permission)) + return true; + } + return false; } } public static class Commands { public static List ChatCommands = new List(); + public static ReadOnlyCollection TShockCommands = new ReadOnlyCollection(new List()); private delegate void AddChatCommand(string permission, CommandDelegate command, params string[] names); public static void InitCommands() { - AddChatCommand add = (p, c, n) => ChatCommands.Add(new Command(p, c, n)); - ChatCommands.Add(new Command(Permissions.canchangepassword, PasswordUser, "password") { DoLog = false }); - ChatCommands.Add(new Command(Permissions.canregister, RegisterUser, "register") { DoLog = false }); - ChatCommands.Add(new Command(Permissions.rootonly, ManageUsers, "user") { DoLog = false }); - ChatCommands.Add(new Command(Permissions.canlogin, AttemptLogin, "login") { DoLog = false }); + List tshockCommands = new List(100); + Action add2 = (cmd) => + { + tshockCommands.Add(cmd); + ChatCommands.Add(cmd); + }; + AddChatCommand add = (p, c, n) => add2(new Command(p, c, n)); + + add2(new Command(AuthToken, "auth") { AllowServer = false }); + add2(new Command(Permissions.canchangepassword, PasswordUser, "password") { AllowServer = false, DoLog = false }); + add2(new Command(Permissions.canregister, RegisterUser, "register") { AllowServer = false, DoLog = false }); + add2(new Command(Permissions.rootonly, ManageUsers, "user") { DoLog = false }); + add2(new Command(Permissions.canlogin, AttemptLogin, "login") { AllowServer = false, DoLog = false }); + add2(new Command(Permissions.buff, Buff, "buff") { AllowServer = false }); + add2(new Command(Permissions.cfg, SetSpawn, "setspawn") { AllowServer = false }); + add2(new Command(Permissions.grow, Grow, "grow") { AllowServer = false }); + add2(new Command(Permissions.item, Item, "item", "i") { AllowServer = false }); + add2(new Command(Permissions.home, Home, "home") { AllowServer = false }); + add2(new Command(Permissions.canpartychat, PartyChat, "p") { AllowServer = false }); + add2(new Command(Permissions.spawn, Spawn, "spawn") { AllowServer = false }); + add2(new Command(Permissions.tp, TP, "tp") { AllowServer = false }); + add2(new Command(Permissions.tphere, TPHere, "tphere") { AllowServer = false }); + add2(new Command(Permissions.tpallow, TPAllow, "tpallow") { AllowServer = false }); add(Permissions.kick, Kick, "kick"); - add(Permissions.ban, Ban, "ban", "banip", "listbans", "unban", "unbanip", "clearbans"); + add(Permissions.ban, Ban, "ban"); add(Permissions.whitelist, Whitelist, "whitelist"); add(Permissions.maintenance, Off, "off", "exit"); - add(Permissions.maintenance, Restart, "restart"); //Added restart command + add(Permissions.maintenance, Restart, "restart"); add(Permissions.maintenance, OffNoSave, "off-nosave", "exit-nosave"); add(Permissions.maintenance, CheckUpdates, "checkupdates"); + add(Permissions.updateplugins, UpdatePlugins, "updateplugins"); add(Permissions.causeevents, DropMeteor, "dropmeteor"); add(Permissions.causeevents, Star, "star"); add(Permissions.causeevents, Fullmoon, "fullmoon"); add(Permissions.causeevents, Bloodmoon, "bloodmoon"); add(Permissions.causeevents, Invade, "invade"); - add(Permissions.spawnboss, SpawnBoss, "boss", "eater", "king", "eye", "skeletron", "wof", "wallofflesh", "twins", - "destroyer", "prime", "skeletronp", "hardcore"); - add(Permissions.spawnmob, SpawnMob, "spawnmob", "sm"); - add(Permissions.tp, Home, "home"); - add(Permissions.tp, Spawn, "spawn"); - add(Permissions.tp, TP, "tp"); - add(Permissions.tphere, TPHere, "tphere"); - add(Permissions.tpallow, TPAllow, "tpallow"); - add(Permissions.warp, Warp, "warp", "setwarp", "delwarp", "sendwarp", "sw"); - add(Permissions.managegroup, AddGroup, "addgroup"); - add(Permissions.managegroup, DeleteGroup, "delgroup"); - add(Permissions.managegroup, ModifyGroup, "modgroup"); - add(Permissions.managegroup, ViewGroups, "group"); - add(Permissions.manageitem, AddItem, "additem", "banitem"); - add(Permissions.manageitem, DeleteItem, "delitem", "unbanitem"); - add(Permissions.manageitem, ListItems, "listitems", "listbanneditems"); - add(Permissions.manageitem, AddItemGroup, "additemgroup"); - add(Permissions.manageitem, DeleteItemGroup, "delitemgroup"); - add(Permissions.cfg, SetSpawn, "setspawn"); + add(Permissions.spawnboss, Eater, "eater"); + add(Permissions.spawnboss, Eye, "eye"); + add(Permissions.spawnboss, King, "king"); + add(Permissions.spawnboss, Skeletron, "skeletron"); + add(Permissions.spawnboss, WoF, "wof", "wallofflesh"); + add(Permissions.spawnboss, Twins, "twins"); + add(Permissions.spawnboss, Destroyer, "destroyer"); + add(Permissions.spawnboss, SkeletronPrime, "skeletronp", "prime"); + add(Permissions.spawnboss, Hardcore, "hardcore"); + add(Permissions.spawnmob, SpawnMob, "spawnmob", "sm"); + add(Permissions.warp, Warp, "warp"); + add(Permissions.managegroup, Group, "group"); + add(Permissions.managegroup, GroupDeprecated, "addgroup", "delgroup", "modgroup"); + add(Permissions.manageitem, ItemBan, "itemban"); + add(Permissions.manageitem, ItemBanDeprecated, + "additem", "additemgroup", "banitem", "delitem", "delitemgroup", "listitems", "listbanneditems", "unbanitem"); + add(Permissions.manageregion, Region, "region"); + add(Permissions.manageregion, DebugRegions, "debugreg"); add(Permissions.cfg, Reload, "reload"); add(Permissions.cfg, ServerPassword, "serverpassword"); add(Permissions.cfg, Save, "save"); @@ -167,16 +215,12 @@ namespace TShockAPI add(Permissions.pvpfun, Slap, "slap"); add(Permissions.editspawn, ToggleAntiBuild, "antibuild"); add(Permissions.editspawn, ProtectSpawn, "protectspawn"); - add(Permissions.manageregion, Region, "region"); - add(Permissions.manageregion, DebugRegions, "debgreg"); add(Permissions.maintenance, GetVersion, "version"); add(null, ListConnectedPlayers, "playing", "online", "who"); - add(null, AuthToken, "auth"); add(null, Motd, "motd"); add(null, Rules, "rules"); add(null, Help, "help"); add(Permissions.cantalkinthird, ThirdPerson, "me"); - add(Permissions.canpartychat, PartyChat, "p"); add(Permissions.mute, Mute, "mute", "unmute"); add(Permissions.logs, DisplayLogs, "displaylogs"); add(Permissions.userinfo, GrabUserUserInfo, "userinfo", "ui"); @@ -187,19 +231,23 @@ namespace TShockAPI add(Permissions.annoy, Annoy, "annoy"); add(Permissions.kill, Kill, "kill"); add(Permissions.butcher, Butcher, "butcher"); - add(Permissions.item, Item, "item", "i"); add(Permissions.item, Give, "give", "g"); add(Permissions.clearitems, ClearItems, "clear", "clearitems"); add(Permissions.heal, Heal, "heal"); - add(Permissions.buff, Buff, "buff"); add(Permissions.buffplayer, GBuff, "gbuff", "buffplayer"); - add(Permissions.grow, Grow, "grow"); add(Permissions.hardmode, StartHardMode, "hardmode"); add(Permissions.hardmode, DisableHardMode, "stophardmode", "disablehardmode"); add(Permissions.cfg, ServerInfo, "stats"); add(Permissions.cfg, WorldInfo, "world"); add(Permissions.savessi, SaveSSI, "savessi"); add(Permissions.savessi, OverrideSSI, "overridessi", "ossi"); + add(Permissions.xmas, ForceXmas, "forcexmas"); + add(Permissions.settempgroup, TempGroup, "tempgroup"); + add(null, Aliases, "aliases"); + add(Rests.RestPermissions.restmanage, ManageRest, "rest"); + //add(null, TestCallbackCommand, "test"); + + TShockCommands = new ReadOnlyCollection(tshockCommands); } public static bool HandleCommand(TSPlayer player, string text) @@ -213,26 +261,42 @@ namespace TShockAPI string cmdName = args[0].ToLower(); args.RemoveAt(0); - Command cmd = ChatCommands.FirstOrDefault(c => c.HasAlias(cmdName)); + if (Hooks.PlayerHooks.OnPlayerCommand(player, cmdName, cmdText, args)) + return true; - if (cmd == null) + IEnumerable cmds = ChatCommands.Where(c => c.HasAlias(cmdName)); + + if (cmds.Count() == 0) { - player.SendMessage("Invalid Command Entered. Type /help for a list of valid Commands.", Color.Red); + if (player.AwaitingResponse.ContainsKey(cmdName)) + { + Action call = player.AwaitingResponse[cmdName]; + player.AwaitingResponse.Remove(cmdName); + call(new CommandArgs(cmdText, player, args)); + return true; + } + player.SendErrorMessage("Invalid command entered. Type /help for a list of valid commands."); return true; } - - if (!cmd.CanRun(player)) - { - TShock.Utils.SendLogs(string.Format("{0} tried to execute {1}", player.Name, cmd.Name), Color.Red); - player.SendMessage("You do not have access to that command.", Color.Red); - } - else - { - if (cmd.DoLog) - TShock.Utils.SendLogs(string.Format("{0} executed: /{1}", player.Name, cmdText), Color.Red); - cmd.Run(cmdText, player, args); - } - return true; + foreach (Command cmd in cmds) + { + if (!cmd.CanRun(player)) + { + TShock.Utils.SendLogs(string.Format("{0} tried to execute /{1}.", player.Name, cmdText), Color.PaleVioletRed, player); + player.SendErrorMessage("You do not have access to that command."); + } + else if (!cmd.AllowServer && !player.RealPlayer) + { + player.SendErrorMessage("You must use this command in-game."); + } + else + { + if (cmd.DoLog) + TShock.Utils.SendLogs(string.Format("{0} executed: /{1}.", player.Name, cmdText), Color.PaleVioletRed, player); + cmd.Run(cmdText, player, args); + } + } + return true; } /// @@ -317,41 +381,59 @@ namespace TShockAPI return c == ' ' || c == '\t' || c == '\n'; } + //private static void TestCallbackCommand(CommandArgs args) + //{ + // Action a = (s) => { ((CommandArgs)s).Player.SendSuccessMessage("This is your callack"); }; + // args.Player.AddResponse( "yes", a); + // args.Player.SendInfoMessage( "Type /yes to get called back." ); + //} + #region Account commands - public static void AttemptLogin(CommandArgs args) + private static void AttemptLogin(CommandArgs args) { if (args.Player.LoginAttempts > TShock.Config.MaximumLoginAttempts && (TShock.Config.MaximumLoginAttempts != -1)) { - Log.Warn(args.Player.IP + "(" + args.Player.Name + ") had " + TShock.Config.MaximumLoginAttempts + - " or more invalid login attempts and was kicked automatically."); + Log.Warn(String.Format("{0} ({1}) had {2} or more invalid login attempts and was kicked automatically.", + args.Player.IP, args.Player.Name, TShock.Config.MaximumLoginAttempts)); TShock.Utils.Kick(args.Player, "Too many invalid login attempts."); + return; } - - var user = TShock.Users.GetUserByName(args.Player.Name); + + User user = TShock.Users.GetUserByName(args.Player.Name); string encrPass = ""; if (args.Parameters.Count == 1) { + if (Hooks.PlayerHooks.OnPlayerPreLogin(args.Player, args.Player.Name, args.Parameters[0])) + return; user = TShock.Users.GetUserByName(args.Player.Name); encrPass = TShock.Utils.HashPassword(args.Parameters[0]); } else if (args.Parameters.Count == 2 && TShock.Config.AllowLoginAnyUsername) { + if (Hooks.PlayerHooks.OnPlayerPreLogin(args.Player, args.Parameters[0], args.Parameters[1])) + return; + user = TShock.Users.GetUserByName(args.Parameters[0]); encrPass = TShock.Utils.HashPassword(args.Parameters[1]); + if (String.IsNullOrEmpty(args.Parameters[0])) + { + args.Player.SendErrorMessage("Bad login attempt."); + return; + } } else { - args.Player.SendMessage("Syntax: /login [password]"); - args.Player.SendMessage("If you forgot your password, there is no way to recover it."); + args.Player.SendErrorMessage(String.Format("Syntax: /login{0} ", TShock.Config.AllowLoginAnyUsername ? " [username]" : " ")); + args.Player.SendErrorMessage("If you forgot your password, there is no way to recover it."); return; } try { if (user == null) { - args.Player.SendMessage("User by that name does not exist"); + args.Player.SendErrorMessage("A user by that name does not exist."); } else if (user.Password.ToUpper() == encrPass.ToUpper()) { @@ -367,11 +449,13 @@ namespace TShockAPI } else if (!TShock.CheckInventory(args.Player)) { - args.Player.SendMessage("Login Failed, Please fix the above errors then /login again.", Color.Cyan); + args.Player.LoginFailsBySsi = true; + args.Player.SendErrorMessage("Login failed. Please fix the above errors then /login again."); args.Player.IgnoreActionsForClearingTrashCan = true; return; } } + args.Player.LoginFailsBySsi = false; if (group.HasPermission(Permissions.ignorestackhackdetection)) args.Player.IgnoreActionsForCheating = "none"; @@ -380,6 +464,7 @@ namespace TShockAPI args.Player.IgnoreActionsForDisabledArmor = "none"; args.Player.Group = group; + args.Player.tempGroup = null; args.Player.UserAccountName = user.Name; args.Player.UserID = TShock.Users.GetUserID(args.Player.UserAccountName); args.Player.IsLoggedIn = true; @@ -390,29 +475,32 @@ namespace TShockAPI args.Player.PlayerData.CopyInventory(args.Player); TShock.InventoryDB.InsertPlayerData(args.Player); } - args.Player.SendMessage("Authenticated as " + user.Name + " successfully.", Color.LimeGreen); + args.Player.SendSuccessMessage("Authenticated as " + user.Name + " successfully."); - Log.ConsoleInfo(args.Player.Name + " authenticated successfully as user: " + user.Name); - if ((args.Player.LoginHarassed) && (TShock.Config.RememberLeavePos)){ - if (TShock.RememberedPos.GetLeavePos(args.Player.Name, args.Player.IP) != Vector2.Zero) + Log.ConsoleInfo(args.Player.Name + " authenticated successfully as user: " + user.Name + "."); + if ((args.Player.LoginHarassed) && (TShock.Config.RememberLeavePos)) { - Vector2 pos = TShock.RememberedPos.GetLeavePos(args.Player.Name, args.Player.IP); + if (TShock.RememberedPos.GetLeavePos(args.Player.Name, args.Player.IP) != Vector2.Zero) + { + Vector2 pos = TShock.RememberedPos.GetLeavePos(args.Player.Name, args.Player.IP); + args.Player.Teleport((int)pos.X, (int)pos.Y + 3); + } + args.Player.LoginHarassed = false; - args.Player.Teleport((int) pos.X, (int) pos.Y + 3); } - args.Player.LoginHarassed = false; - - }} + + Hooks.PlayerHooks.OnPlayerPostLogin(args.Player); + } else { - args.Player.SendMessage("Incorrect password", Color.LimeGreen); - Log.Warn(args.Player.IP + " failed to authenticate as user: " + user.Name); + args.Player.SendErrorMessage("Incorrect password."); + Log.Warn(args.Player.IP + " failed to authenticate as user: " + user.Name + "."); args.Player.LoginAttempts++; } } catch (Exception ex) { - args.Player.SendMessage("There was an error processing your request.", Color.Red); + args.Player.SendErrorMessage("There was an error processing your request."); Log.Error(ex.ToString()); } } @@ -427,27 +515,26 @@ namespace TShockAPI string encrPass = TShock.Utils.HashPassword(args.Parameters[0]); if (user.Password.ToUpper() == encrPass.ToUpper()) { - args.Player.SendMessage("You changed your password!", Color.Green); + args.Player.SendSuccessMessage("You changed your password to " + args.Parameters[1] + "!"); TShock.Users.SetUserPassword(user, args.Parameters[1]); // SetUserPassword will hash it for you. - Log.ConsoleInfo(args.Player.IP + " named " + args.Player.Name + " changed the password of Account " + user.Name); + Log.ConsoleInfo(args.Player.IP + " named " + args.Player.Name + " changed the password of account " + user.Name + "."); } else { - args.Player.SendMessage("You failed to change your password!", Color.Red); - Log.ConsoleError(args.Player.IP + " named " + args.Player.Name + " failed to change password for Account: " + - user.Name); + args.Player.SendErrorMessage("You failed to change your password!"); + Log.ConsoleError(args.Player.IP + " named " + args.Player.Name + " failed to change password for account: " + + user.Name + "."); } } else { - args.Player.SendMessage("Not Logged in or Invalid syntax! Proper syntax: /password ", - Color.Red); + args.Player.SendErrorMessage("Not logged in or invalid syntax! Proper syntax: /password "); } } catch (UserManagerException ex) { - args.Player.SendMessage("Sorry, an error occured: " + ex.Message, Color.Green); - Log.ConsoleError("RegisterUser returned an error: " + ex); + args.Player.SendErrorMessage("Sorry, an error occured: " + ex.Message + "."); + Log.ConsoleError("PasswordUser returned an error: " + ex); } } @@ -469,7 +556,7 @@ namespace TShockAPI } else { - args.Player.SendMessage("Invalid syntax! Proper syntax: /register ", Color.Red); + args.Player.SendErrorMessage("Invalid syntax! Proper syntax: /register "); return; } @@ -477,32 +564,30 @@ namespace TShockAPI if (TShock.Users.GetUserByName(user.Name) == null) // Cheap way of checking for existance of a user { - args.Player.SendMessage("Account " + user.Name + " has been registered.", Color.Green); - args.Player.SendMessage("Your password is " + user.Password); + args.Player.SendSuccessMessage("Account " + user.Name + " has been registered."); + args.Player.SendSuccessMessage("Your password is " + user.Password); TShock.Users.AddUser(user); - Log.ConsoleInfo(args.Player.Name + " registered an Account: " + user.Name); + Log.ConsoleInfo(args.Player.Name + " registered an account: " + user.Name + "."); } else { - args.Player.SendMessage("Account " + user.Name + " has already been registered.", Color.Green); - Log.ConsoleInfo(args.Player.Name + " failed to register an existing Account: " + user.Name); + args.Player.SendErrorMessage("Account " + user.Name + " has already been registered."); + Log.ConsoleInfo(args.Player.Name + " failed to register an existing account: " + user.Name); } } catch (UserManagerException ex) { - args.Player.SendMessage("Sorry, an error occured: " + ex.Message, Color.Green); + args.Player.SendErrorMessage("Sorry, an error occured: " + ex.Message + "."); Log.ConsoleError("RegisterUser returned an error: " + ex); } } - //Todo: Add separate help text for '/user add' and '/user del'. Also add '/user addip' and '/user delip' - private static void ManageUsers(CommandArgs args) { // This guy needs to be here so that people don't get exceptions when they type /user if (args.Parameters.Count < 1) { - args.Player.SendMessage("Invalid user syntax. Try /user help.", Color.Red); + args.Player.SendErrorMessage("Invalid user syntax. Try /user help."); return; } @@ -532,26 +617,26 @@ namespace TShockAPI } if (!string.IsNullOrEmpty(user.Address)) { - args.Player.SendMessage("IP address admin added. If they're logged in, tell them to rejoin.", Color.Green); - args.Player.SendMessage("WARNING: This is insecure! It would be better to use a user account instead.", Color.Red); + args.Player.SendSuccessMessage("IP address admin added. If they're logged in, tell them to rejoin."); + args.Player.SendSuccessMessage("WARNING: This is insecure! It would be better to use a user account instead."); TShock.Users.AddUser(user); Log.ConsoleInfo(args.Player.Name + " added IP " + user.Address + " to group " + user.Group); } else { - args.Player.SendMessage("Account " + user.Name + " has been added to group " + user.Group + "!", Color.Green); + args.Player.SendSuccessMessage("Account " + user.Name + " has been added to group " + user.Group + "!"); TShock.Users.AddUser(user); Log.ConsoleInfo(args.Player.Name + " added Account " + user.Name + " to group " + user.Group); } } else { - args.Player.SendMessage("Invalid syntax. Try /user help.", Color.Red); + args.Player.SendErrorMessage("Invalid syntax. Try /user help."); } } catch (UserManagerException ex) { - args.Player.SendMessage(ex.Message, Color.Green); + args.Player.SendErrorMessage(ex.Message); Log.ConsoleError(ex.ToString()); } } @@ -570,8 +655,8 @@ namespace TShockAPI try { TShock.Users.RemoveUser(user); - args.Player.SendMessage("Account removed successfully.", Color.Green); - Log.ConsoleInfo(args.Player.Name + " successfully deleted account: " + args.Parameters[1]); + args.Player.SendSuccessMessage("Account removed successfully."); + Log.ConsoleInfo(args.Player.Name + " successfully deleted account: " + args.Parameters[1] + "."); } catch (UserManagerException ex) { @@ -589,18 +674,18 @@ namespace TShockAPI { if (args.Parameters.Count == 3) { - args.Player.SendMessage("Changed the password of " + user.Name + "!", Color.Green); + args.Player.SendSuccessMessage("Password change succeeded for " + user.Name + "."); TShock.Users.SetUserPassword(user, args.Parameters[2]); - Log.ConsoleInfo(args.Player.Name + " changed the password of Account " + user.Name); + Log.ConsoleInfo(args.Player.Name + " changed the password of account " + user.Name); } else { - args.Player.SendMessage("Invalid user password syntax. Try /user help.", Color.Red); + args.Player.SendErrorMessage("Invalid user password syntax. Try /user help."); } } catch (UserManagerException ex) { - args.Player.SendMessage(ex.Message, Color.Green); + args.Player.SendErrorMessage(ex.Message); Log.ConsoleError(ex.ToString()); } } @@ -623,22 +708,20 @@ namespace TShockAPI { if (!string.IsNullOrEmpty(user.Address)) { - args.Player.SendMessage("IP Address " + user.Address + " has been changed to group " + args.Parameters[2] + "!", - Color.Green); + args.Player.SendSuccessMessage("IP address " + user.Address + " has been changed to group " + args.Parameters[2] + "!"); TShock.Users.SetUserGroup(user, args.Parameters[2]); - Log.ConsoleInfo(args.Player.Name + " changed IP Address " + user.Address + " to group " + args.Parameters[2]); + Log.ConsoleInfo(args.Player.Name + " changed IP address " + user.Address + " to group " + args.Parameters[2] + "."); } else { - args.Player.SendMessage("Account " + user.Name + " has been changed to group " + args.Parameters[2] + "!", - Color.Green); + args.Player.SendSuccessMessage("Account " + user.Name + " has been changed to group " + args.Parameters[2] + "!"); TShock.Users.SetUserGroup(user, args.Parameters[2]); - Log.ConsoleInfo(args.Player.Name + " changed Account " + user.Name + " to group " + args.Parameters[2]); + Log.ConsoleInfo(args.Player.Name + " changed account " + user.Name + " to group " + args.Parameters[2] + "."); } } else { - args.Player.SendMessage("Invalid user group syntax. Try /user help.", Color.Red); + args.Player.SendErrorMessage("Invalid user group syntax. Try /user help."); } } catch (UserManagerException ex) @@ -649,15 +732,15 @@ namespace TShockAPI } else if (subcmd == "help") { - args.Player.SendMessage("Help for user subcommands:"); - args.Player.SendMessage("/user add username:password group -- Adds a specified user"); - args.Player.SendMessage("/user del username -- Removes a specified user"); - args.Player.SendMessage("/user password username newpassword -- Changes a user's password"); - args.Player.SendMessage("/user group username newgroup -- Changes a user's group"); + args.Player.SendInfoMessage("Use command help:"); + args.Player.SendInfoMessage("/user add username:password group -- Adds a specified user"); + args.Player.SendInfoMessage("/user del username -- Removes a specified user"); + args.Player.SendInfoMessage("/user password username newpassword -- Changes a user's password"); + args.Player.SendInfoMessage("/user group username newgroup -- Changes a user's group"); } else { - args.Player.SendMessage("Invalid user syntax. Try /user help.", Color.Red); + args.Player.SendErrorMessage("Invalid user syntax. Try /user help."); } } @@ -665,20 +748,21 @@ namespace TShockAPI #region Stupid commands - public static void ServerInfo(CommandArgs args) + private static void ServerInfo(CommandArgs args) { - args.Player.SendMessage("Memory usage: " + Process.GetCurrentProcess().WorkingSet64); - args.Player.SendMessage("Allocated memory: " + Process.GetCurrentProcess().VirtualMemorySize64); - args.Player.SendMessage("Total processor time: " + Process.GetCurrentProcess().TotalProcessorTime); - args.Player.SendMessage("Ver: " + Environment.OSVersion); - args.Player.SendMessage("Proc count: " + Environment.ProcessorCount); - args.Player.SendMessage("Machine name: " + Environment.MachineName); + args.Player.SendInfoMessage("Memory usage: " + Process.GetCurrentProcess().WorkingSet64); + args.Player.SendInfoMessage("Allocated memory: " + Process.GetCurrentProcess().VirtualMemorySize64); + args.Player.SendInfoMessage("Total processor time: " + Process.GetCurrentProcess().TotalProcessorTime); + args.Player.SendInfoMessage("WinVer: " + Environment.OSVersion); + args.Player.SendInfoMessage("Proc count: " + Environment.ProcessorCount); + args.Player.SendInfoMessage("Machine name: " + Environment.MachineName); } - public static void WorldInfo(CommandArgs args) + private static void WorldInfo(CommandArgs args) { - args.Player.SendMessage("World Name: " + Main.worldName); - args.Player.SendMessage("World ID: " + Main.worldID); + args.Player.SendInfoMessage("World name: " + Main.worldName); + args.Player.SendInfoMessage("World size: {0}x{1}", Main.maxTilesX, Main.maxTilesY); + args.Player.SendInfoMessage("World ID: " + Main.worldID); } #endregion @@ -689,7 +773,7 @@ namespace TShockAPI { if (args.Parameters.Count < 1) { - args.Player.SendMessage("Invalid syntax! Proper syntax: /userinfo ", Color.Red); + args.Player.SendErrorMessage("Invalid syntax! Proper syntax: /userinfo "); return; } @@ -708,16 +792,16 @@ namespace TShockAPI plrMatches += plr.Name; } } - args.Player.SendMessage("More than one player matched! Matches: " + plrMatches, Color.Red); + args.Player.SendErrorMessage("More than one player matched! Matches: " + plrMatches); return; } try { - args.Player.SendMessage("IP Address: " + players[0].IP + " Logged In As: " + players[0].UserAccountName + " Group: " + players[0].Group.Name, Color.Green); + args.Player.SendSuccessMessage("IP Address: " + players[0].IP + " Logged in as: " + players[0].UserAccountName + " group: " + players[0].Group.Name); } catch (Exception) { - args.Player.SendMessage("Invalid player.", Color.Red); + args.Player.SendErrorMessage("Invalid player."); } } @@ -725,12 +809,12 @@ namespace TShockAPI { if (args.Parameters.Count < 1) { - args.Player.SendMessage("Invalid syntax! Proper syntax: /kick [reason]", Color.Red); + args.Player.SendErrorMessage("Invalid syntax! Proper syntax: /kick [reason]"); return; } if (args.Parameters[0].Length == 0) { - args.Player.SendMessage("Missing player name", Color.Red); + args.Player.SendErrorMessage("Missing player name."); return; } @@ -738,7 +822,7 @@ namespace TShockAPI var players = TShock.Utils.FindPlayer(plStr); if (players.Count == 0) { - args.Player.SendMessage("Invalid player!", Color.Red); + args.Player.SendErrorMessage("Invalid player!"); } else if (players.Count > 1) { @@ -754,7 +838,7 @@ namespace TShockAPI plrMatches += plr.Name; } } - args.Player.SendMessage("More than one player matched! Matches: " + plrMatches, Color.Red); + args.Player.SendErrorMessage("More than one player matched! Matches: " + plrMatches); } else { @@ -763,21 +847,19 @@ namespace TShockAPI : "Misbehaviour."; if (!TShock.Utils.Kick(players[0], reason, !args.Player.RealPlayer, false, args.Player.Name)) { - args.Player.SendMessage("You can't kick another admin!", Color.Red); + args.Player.SendErrorMessage("You can't kick another admin!"); } } } private static void Ban(CommandArgs args) { - - if (args.Parameters[0].ToLower() == "help") + if (args.Parameters.Count == 0 || args.Parameters[0].ToLower() == "help") { - args.Player.SendMessage("All ban commands were merged into one in TShock 4.0.", Color.Yellow); - args.Player.SendMessage("Syntax: /ban [option] [arguments]", Color.Green); - args.Player.SendMessage("Options: list, listip, clear, add, addip, del, delip", Color.Green); - args.Player.SendMessage("Arguments: list, listip, clear [code], add [name], addip [ip], del [name], delip [name]", Color.Green); - args.Player.SendMessage("In addition, a reason may be provided for all new bans after the arguments.", Color.Green); + args.Player.SendInfoMessage("Syntax: /ban [option] [arguments]"); + args.Player.SendInfoMessage("Options: list, listip, clear, add, addip, del, delip"); + args.Player.SendInfoMessage("Arguments: list, listip, clear [code], add [name], addip [ip], del [name], delip [name]"); + args.Player.SendInfoMessage("In addition, a reason may be provided for all new bans after the arguments."); return; } if (args.Parameters[0].ToLower() == "list") @@ -785,7 +867,7 @@ namespace TShockAPI #region List bans if (TShock.Bans.GetBans().Count == 0) { - args.Player.SendMessage("There are currently no players banned."); + args.Player.SendErrorMessage("There are currently no players banned."); return; } @@ -824,20 +906,20 @@ namespace TShockAPI if (banStrings.Length == 0) { - args.Player.SendMessage("There are currently no players with valid names banned."); + args.Player.SendErrorMessage("There are currently no players with valid names banned."); return; } if (banStrings[0].Trim() == "") { - args.Player.SendMessage("There are currently no bans with valid names found."); + args.Player.SendErrorMessage("There are currently no bans with valid names found."); return; } - args.Player.SendMessage("List of banned players:"); + args.Player.SendInfoMessage("List of banned players:"); foreach (string s in banStrings) { - args.Player.SendMessage(s, Color.Yellow); + args.Player.SendInfoMessage(s); } return; #endregion List bans @@ -848,7 +930,7 @@ namespace TShockAPI #region List ip bans if (TShock.Bans.GetBans().Count == 0) { - args.Player.SendMessage("There are currently no players banned."); + args.Player.SendWarningMessage("There are currently no players banned."); return; } @@ -887,20 +969,20 @@ namespace TShockAPI if (banStrings.Length == 0) { - args.Player.SendMessage("There are currently no players with valid IPs banned."); + args.Player.SendErrorMessage("There are currently no players with valid IPs banned."); return; } if (banStrings[0].Trim() == "") { - args.Player.SendMessage("There are currently no bans with valid IPs found."); + args.Player.SendErrorMessage("There are currently no bans with valid IPs found."); return; } - args.Player.SendMessage("List of IP banned players:"); + args.Player.SendInfoMessage("List of IP banned players:"); foreach (string s in banStrings) { - args.Player.SendMessage(s, Color.Yellow); + args.Player.SendInfoMessage(s); } return; #endregion List ip bans @@ -915,7 +997,7 @@ namespace TShockAPI var players = TShock.Utils.FindPlayer(plStr); if (players.Count == 0) { - args.Player.SendMessage("Invalid player!", Color.Red); + args.Player.SendErrorMessage("Invalid player!"); } else if (players.Count > 1) { @@ -931,7 +1013,7 @@ namespace TShockAPI plrMatches += plr.Name; } } - args.Player.SendMessage("More than one player matched! Matches: " + plrMatches, Color.Red); + args.Player.SendErrorMessage("More than one player matched! Matches: " + plrMatches); } else { @@ -940,7 +1022,7 @@ namespace TShockAPI : "Misbehavior."; if (!TShock.Utils.Ban(players[0], reason, !args.Player.RealPlayer, args.Player.Name)) { - args.Player.SendMessage("You can't ban another admin!", Color.Red); + args.Player.SendErrorMessage("You can't ban another admin!"); } } return; @@ -954,7 +1036,7 @@ namespace TShockAPI ? String.Join(" ", args.Parameters.GetRange(2, args.Parameters.Count - 2)) : "Manually added IP address ban."; TShock.Bans.AddBan(ip, "", reason); - args.Player.SendMessage(ip + " banned.", Color.Green); + args.Player.SendSuccessMessage(ip + " banned."); return; #endregion Add ip ban } @@ -966,13 +1048,13 @@ namespace TShockAPI if (ban != null) { if (TShock.Bans.RemoveBan(ban.IP)) - args.Player.SendMessage(string.Format("Unbanned {0} ({1})!", ban.Name, ban.IP), Color.Red); + args.Player.SendSuccessMessage(string.Format("Unbanned {0} ({1})!", ban.Name, ban.IP)); else - args.Player.SendMessage(string.Format("Failed to unban {0} ({1})!", ban.Name, ban.IP), Color.Red); + args.Player.SendErrorMessage(string.Format("Failed to unban {0} ({1})!", ban.Name, ban.IP)); } else { - args.Player.SendMessage(string.Format("No bans for ip {0} exist", ip), Color.Red); + args.Player.SendErrorMessage(string.Format("No bans for ip {0} exist", ip)); } return; #endregion Delete ip ban @@ -985,13 +1067,13 @@ namespace TShockAPI if (ban != null) { if (TShock.Bans.RemoveBan(ban.Name, true)) - args.Player.SendMessage(string.Format("Unbanned {0} ({1})!", ban.Name, ban.IP), Color.Red); + args.Player.SendSuccessMessage(string.Format("Unbanned {0} ({1})!", ban.Name, ban.IP)); else - args.Player.SendMessage(string.Format("Failed to unban {0} ({1})!", ban.Name, ban.IP), Color.Red); + args.Player.SendErrorMessage(string.Format("Failed to unban {0} ({1})!", ban.Name, ban.IP)); } else { - args.Player.SendMessage(string.Format("No bans for player {0} exist", plStr), Color.Red); + args.Player.SendErrorMessage(string.Format("No bans for player {0} exist", plStr)); } return; #endregion Delete ban @@ -1003,19 +1085,19 @@ namespace TShockAPI if (args.Parameters.Count < 1 && ClearBansCode == -1) { ClearBansCode = new Random().Next(0, short.MaxValue); - args.Player.SendMessage("ClearBans Code: " + ClearBansCode, Color.Red); + args.Player.SendInfoMessage("ClearBans Code: " + ClearBansCode); return; } if (args.Parameters.Count < 1) { - args.Player.SendMessage("Invalid syntax! Proper syntax: /ban clear "); + args.Player.SendErrorMessage("Invalid syntax! Proper syntax: /ban clear "); return; } int num; if (!int.TryParse(args.Parameters[1], out num)) { - args.Player.SendMessage("Invalid syntax! Expecting number"); + args.Player.SendErrorMessage("Invalid syntax! Expected a number, didn't get one."); return; } @@ -1024,29 +1106,29 @@ namespace TShockAPI ClearBansCode = -1; if (TShock.Bans.ClearBans()) { - Log.ConsoleInfo("Bans cleared"); - args.Player.SendMessage("Bans cleared"); + Log.ConsoleInfo("Bans cleared."); + args.Player.SendSuccessMessage("Bans cleared."); } else { - args.Player.SendMessage("Failed to clear bans"); + args.Player.SendErrorMessage("Failed to clear bans."); } } else { - args.Player.SendMessage("Incorrect clear code"); + args.Player.SendErrorMessage("Incorrect clear code."); } } return; #endregion Clear bans } - args.Player.SendMessage("Invalid syntax or old command provided.", Color.Red); - args.Player.SendMessage("Type /ban help for more information.", Color.Red); + args.Player.SendErrorMessage("Invalid syntax or old command provided."); + args.Player.SendErrorMessage("Type /ban help for more information."); } private static int ClearBansCode = -1; - public static void Whitelist(CommandArgs args) + private static void Whitelist(CommandArgs args) { if (args.Parameters.Count == 1) { @@ -1054,21 +1136,21 @@ namespace TShockAPI { tw.WriteLine(args.Parameters[0]); } - args.Player.SendMessage("Added " + args.Parameters[0] + " to the whitelist."); + args.Player.SendSuccessMessage("Added " + args.Parameters[0] + " to the whitelist."); } } - public static void DisplayLogs(CommandArgs args) + private static void DisplayLogs(CommandArgs args) { args.Player.DisplayLogs = (!args.Player.DisplayLogs); - args.Player.SendMessage("You now " + (args.Player.DisplayLogs ? "receive" : "stopped receiving") + " logs"); + args.Player.SendSuccessMessage("You will " + (args.Player.DisplayLogs ? "now" : "no longer") + " receive logs."); } - public static void SaveSSI(CommandArgs args ) + private static void SaveSSI(CommandArgs args) { if (TShock.Config.ServerSideInventory) { - args.Player.SendMessage("SSI has been saved.", Color.Green); + args.Player.SendSuccessMessage("SSI has been saved."); foreach (TSPlayer player in TShock.Players) { if (player != null && player.IsLoggedIn && !player.IgnoreActionsForClearingTrashCan) @@ -1079,48 +1161,133 @@ namespace TShockAPI } } - public static void OverrideSSI( CommandArgs args ) + private static void OverrideSSI(CommandArgs args) { + if (!TShock.Config.ServerSideInventory) + { + args.Player.SendErrorMessage("Server Side Inventory is disabled."); + return; + } if( args.Parameters.Count < 1 ) { - args.Player.SendMessage("Correct usage: /overridessi(/ossi) ", Color.Red); + args.Player.SendErrorMessage("Correct usage: /overridessi|/ossi "); return; } - var players = TShock.Utils.FindPlayer(args.Parameters[0]); - if( players.Count < 1 ) + string playerNameToMatch = string.Join(" ", args.Parameters); + var matchedPlayers = TShock.Utils.FindPlayer(playerNameToMatch); + if( matchedPlayers.Count < 1 ) { - args.Player.SendMessage("No players match " + args.Parameters[0], Color.Red); + args.Player.SendErrorMessage("No players matched \"{0}\".", playerNameToMatch); + return; } - else if( players.Count > 1 ) + else if( matchedPlayers.Count > 1 ) { - args.Player.SendMessage( players.Count + " players matched " + args.Parameters[0], Color.Red); + args.Player.SendErrorMessage("{0} players matched \"{1}\".", matchedPlayers.Count, playerNameToMatch); + return; } - else if (TShock.Config.ServerSideInventory) + + TSPlayer matchedPlayer = matchedPlayers[0]; + if (matchedPlayer.IsLoggedIn) { - if( players[0] != null && players[0].IsLoggedIn && !players[0].IgnoreActionsForClearingTrashCan) - { - args.Player.SendMessage( players[0].Name + " has been exempted and updated.", Color.Green); - TShock.InventoryDB.InsertPlayerData(players[0]); - } + args.Player.SendErrorMessage("Player \"{0}\" is already logged in.", matchedPlayer.Name); + return; } + if (!matchedPlayer.LoginFailsBySsi) + { + args.Player.SendErrorMessage("Player \"{0}\" has to perform a /login attempt first.", matchedPlayer.Name); + return; + } + if (matchedPlayer.IgnoreActionsForClearingTrashCan) + { + args.Player.SendErrorMessage("Player \"{0}\" has to reconnect first.", matchedPlayer.Name); + return; + } + + TShock.InventoryDB.InsertPlayerData(matchedPlayer); + args.Player.SendSuccessMessage("SSI of player \"{0}\" has been overriden.", matchedPlayer.Name); } + private static void ForceXmas(CommandArgs args) + { + if(args.Parameters.Count == 0) + { + args.Player.SendErrorMessage("Usage: /forcexmas [true/false]"); + args.Player.SendInfoMessage( + String.Format("The server is currently {0} force Christmas mode.", + (TShock.Config.ForceXmas ? "in" : "not in"))); + return; + } + + if(args.Parameters[0].ToLower() == "true") + { + TShock.Config.ForceXmas = true; + Main.checkXMas(); + } + else if(args.Parameters[0].ToLower() == "false") + { + TShock.Config.ForceXmas = false; + Main.checkXMas(); + } + else + { + args.Player.SendErrorMessage("Usage: /forcexmas [true/false]"); + return; + } + + args.Player.SendInfoMessage( + String.Format("The server is currently {0} force Christmas mode.", + (TShock.Config.ForceXmas ? "in" : "not in"))); + } + + private static void TempGroup(CommandArgs args) + { + if (args.Parameters.Count < 2) + { + args.Player.SendInfoMessage("Invalid usage"); + args.Player.SendInfoMessage("Usage: /tempgroup "); + return; + } + + List ply = TShock.Utils.FindPlayer(args.Parameters[0]); + if(ply.Count < 1) + { + args.Player.SendErrorMessage(string.Format("Could not find player {0}.", args.Parameters[0])); + return; + } + + if (ply.Count > 1) + { + args.Player.SendErrorMessage(string.Format("Found more than one match for {0}.", args.Parameters[0])); + return; + } + + if(!TShock.Groups.GroupExists(args.Parameters[1])) + { + args.Player.SendErrorMessage(string.Format("Could not find group {0}", args.Parameters[1])); + return; + } + + Group g = TShock.Utils.GetGroup(args.Parameters[1]); + + ply[0].tempGroup = g; + + args.Player.SendSuccessMessage(string.Format("You have changed {0}'s group to {1}", ply[0].Name, g.Name)); + ply[0].SendSuccessMessage(string.Format("Your group has temporarily been changed to {0}", g.Name)); + } + #endregion Player Management Commands #region Server Maintenence Commands private static void Broadcast(CommandArgs args) { - string message = ""; + string message = string.Join(" ", args.Parameters); - for (int i = 0; i < args.Parameters.Count; i++) - { - message += " " + args.Parameters[i]; - } - - TShock.Utils.Broadcast("(Server Broadcast)" + message, Color.Red); - return; + TShock.Utils.Broadcast( + "(Server Broadcast) " + message, + Convert.ToByte(TShock.Config.BroadcastRGB[0]), Convert.ToByte(TShock.Config.BroadcastRGB[1]), + Convert.ToByte(TShock.Config.BroadcastRGB[2])); } private static void Off(CommandArgs args) @@ -1140,30 +1307,17 @@ namespace TShockAPI string reason = ((args.Parameters.Count > 0) ? "Server shutting down: " + String.Join(" ", args.Parameters) : "Server shutting down!"); TShock.Utils.StopServer(true, reason); } - //Added restart command + private static void Restart(CommandArgs args) { if (Main.runningMono) { - Log.ConsoleInfo("Sorry, this command has not yet been implemented in Mono"); + Log.ConsoleInfo("Sorry, this command has not yet been implemented in Mono."); } else { - if (TShock.Config.ServerSideInventory) - { - foreach (TSPlayer player in TShock.Players) - { - if (player != null && player.IsLoggedIn && !player.IgnoreActionsForClearingTrashCan) - { - TShock.InventoryDB.InsertPlayerData(player); - } - } - } - string reason = ((args.Parameters.Count > 0) ? "Server shutting down: " + String.Join(" ", args.Parameters) : "Server shutting down!"); - TShock.Utils.StopServer(true, reason); - System.Diagnostics.Process.Start(System.Reflection.Assembly.GetExecutingAssembly().GetName().CodeBase); - Environment.Exit(0); + TShock.Utils.RestartServer(true, reason); } } @@ -1175,17 +1329,78 @@ namespace TShockAPI private static void CheckUpdates(CommandArgs args) { + args.Player.SendInfoMessage("An update check has been queued."); ThreadPool.QueueUserWorkItem(UpdateManager.CheckUpdate); } + private static void UpdatePlugins(CommandArgs args) + { + args.Player.SendInfoMessage("Starting plugin update process:"); + args.Player.SendInfoMessage("This may take a while, do not turn off the server!"); + new PluginUpdaterThread(args.Player); + } + + private static void ManageRest(CommandArgs args) + { + string subCommand = "help"; + if (args.Parameters.Count > 0) + subCommand = args.Parameters[0]; + + switch(subCommand.ToLower()) + { + case "listusers": + { + int pageNumber; + if (!PaginationTools.TryParsePageNumber(args.Parameters, 1, args.Player, out pageNumber)) + return; + + Dictionary restUsersTokens = new Dictionary(); + foreach (Rests.SecureRest.TokenData tokenData in TShock.RestApi.Tokens.Values) + { + if (restUsersTokens.ContainsKey(tokenData.Username)) + restUsersTokens[tokenData.Username]++; + else + restUsersTokens.Add(tokenData.Username, 1); + } + + List restUsers = new List( + restUsersTokens.Select(ut => string.Format("{0} ({1} tokens)", ut.Key, ut.Value))); + + PaginationTools.SendPage( + args.Player, pageNumber, PaginationTools.BuildLinesFromTerms(restUsers), new PaginationTools.Settings { + NothingToDisplayString = "There are currently no active REST users.", + HeaderFormat = "Active REST Users ({0}/{1}):", + FooterFormat = "Type /rest listusers {0} for more." + } + ); + + break; + } + case "destroytokens": + { + TShock.RestApi.Tokens.Clear(); + args.Player.SendSuccessMessage("All REST tokens have been destroyed."); + break; + } + default: + { + args.Player.SendInfoMessage("Available REST Sub-Commands:"); + args.Player.SendMessage("listusers - Lists all REST users and their current active tokens.", Color.White); + args.Player.SendMessage("destroytokens - Destroys all current REST tokens.", Color.White); + break; + } + } + } + #endregion Server Maintenence Commands - #region Cause Events and Spawn Monsters Commands + #region Cause Events and Spawn Monsters Commands - private static void DropMeteor(CommandArgs args) + private static void DropMeteor(CommandArgs args) { WorldGen.spawnMeteor = false; WorldGen.dropMeteor(); + args.Player.SendInfoMessage("A meteor has been triggered."); } private static void Star(CommandArgs args) @@ -1202,145 +1417,241 @@ namespace TShockAPI speedX *= penis61; speedY *= penis61; Projectile.NewProjectile(vector.X, vector.Y, speedX, speedY, 12, 0x3e8, 10f, Main.myPlayer); + args.Player.SendInfoMessage("An attempt has been made to spawn a star."); } private static void Fullmoon(CommandArgs args) { TSPlayer.Server.SetFullMoon(true); - TShock.Utils.Broadcast(string.Format("{0} turned on full moon.", args.Player.Name)); + TShock.Utils.Broadcast(string.Format("{0} turned on the full moon.", args.Player.Name), Color.Green); } private static void Bloodmoon(CommandArgs args) { TSPlayer.Server.SetBloodMoon(true); - TShock.Utils.Broadcast(string.Format("{0} turned on blood moon.", args.Player.Name)); + TShock.Utils.Broadcast(string.Format("{0} turned on the blood moon.", args.Player.Name), Color.Green); } private static void Invade(CommandArgs args) { if (Main.invasionSize <= 0) { - TShock.Utils.Broadcast(string.Format("{0} has started an invasion.", args.Player.Name)); + TSPlayer.All.SendInfoMessage(string.Format("{0} has started a goblin army invasion.", args.Player.Name)); TShock.StartInvasion(); } else { - TShock.Utils.Broadcast(string.Format("{0} has ended an invasion.", args.Player.Name)); + TSPlayer.All.SendInfoMessage(string.Format("{0} has ended a goblin army invasion.", args.Player.Name)); Main.invasionSize = 0; } } - private static void SpawnBoss(CommandArgs args) + private static void StartHardMode(CommandArgs args) { - if (args.Parameters.Count == 0) - { - args.Player.SendMessage("As of TShock 4.0, all boss specific spawning commands are now in /boss.", Color.Yellow); - args.Player.SendMessage("Invalid syntax. Syntax: /boss [name] [count]", Color.Green); - args.Player.SendMessage("Bosses: eow, king, eye, skeletron, wof, twins, destroyer, prime, *", Color.Green); - return; - } - int numberOfEnemies = 0; - string boss = args.Parameters[0]; - int.TryParse(args.Parameters[1], out numberOfEnemies); - numberOfEnemies = Math.Min(numberOfEnemies, Main.maxNPCs); + if (!TShock.Config.DisableHardmode) + WorldGen.StartHardmode(); + else + args.Player.SendMessage("Hardmode is disabled via config.", Color.Red); + } - if (boss.ToLower() == "eow" || boss.ToLower() == "eater") - { - NPC eater = TShock.Utils.GetNPCById(13); - TSPlayer.Server.SpawnNPC(eater.type, eater.name, numberOfEnemies, args.Player.TileX, args.Player.TileY); - TShock.Utils.Broadcast(string.Format("{0} has spawned the eater of worlds {1} times!", args.Player.Name, numberOfEnemies)); - return; - } + private static void DisableHardMode(CommandArgs args) + { + Main.hardMode = false; + args.Player.SendMessage("Hardmode is now disabled.", Color.Green); + } - if (boss.ToLower() == "eye") + [Obsolete("This specific command for spawning mobs will replaced soon.")] + private static void Eater(CommandArgs args) + { + if (args.Parameters.Count > 1) { - NPC eye = TShock.Utils.GetNPCById(4); - TSPlayer.Server.SetTime(false, 0.0); - TSPlayer.Server.SpawnNPC(eye.type, eye.name, numberOfEnemies, args.Player.TileX, args.Player.TileY); - TShock.Utils.Broadcast(string.Format("{0} has spawned the eye of cthulhu {1} times!", args.Player.Name, numberOfEnemies)); + args.Player.SendMessage("Invalid syntax! Proper syntax: /eater [amount]", Color.Red); return; } + int amount = 1; + if (args.Parameters.Count == 1 && !int.TryParse(args.Parameters[0], out amount)) + { + args.Player.SendMessage("Invalid syntax! Proper syntax: /eater [amount]", Color.Red); + return; + } + amount = Math.Min(amount, Main.maxNPCs); + NPC eater = TShock.Utils.GetNPCById(13); + TSPlayer.Server.SpawnNPC(eater.type, eater.name, amount, args.Player.TileX, args.Player.TileY); + TShock.Utils.Broadcast(string.Format("{0} has spawned eater of worlds {1} times!", args.Player.Name, amount)); + } - if (boss.ToLower() == "king") + [Obsolete("This specific command for spawning mobs will replaced soon.")] + private static void Eye(CommandArgs args) + { + if (args.Parameters.Count > 1) { - NPC king = TShock.Utils.GetNPCById(50); - TSPlayer.Server.SpawnNPC(king.type, king.name, numberOfEnemies, args.Player.TileX, args.Player.TileY); - TShock.Utils.Broadcast(string.Format("{0} has spawned the king of slimes {1} times!", args.Player.Name, numberOfEnemies)); + args.Player.SendMessage("Invalid syntax! Proper syntax: /eye [amount]", Color.Red); return; } + int amount = 1; + if (args.Parameters.Count == 1 && !int.TryParse(args.Parameters[0], out amount)) + { + args.Player.SendMessage("Invalid syntax! Proper syntax: /eye [amount]", Color.Red); + return; + } + amount = Math.Min(amount, Main.maxNPCs); + NPC eye = TShock.Utils.GetNPCById(4); + TSPlayer.Server.SetTime(false, 0.0); + TSPlayer.Server.SpawnNPC(eye.type, eye.name, amount, args.Player.TileX, args.Player.TileY); + TShock.Utils.Broadcast(string.Format("{0} has spawned eye {1} times!", args.Player.Name, amount)); + } - if (boss.ToLower() == "skeleton") + [Obsolete("This specific command for spawning mobs will replaced soon.")] + private static void King(CommandArgs args) + { + if (args.Parameters.Count > 1) { - NPC skeletron = TShock.Utils.GetNPCById(35); - TSPlayer.Server.SetTime(false, 0.0); - TSPlayer.Server.SpawnNPC(skeletron.type, skeletron.name, numberOfEnemies, args.Player.TileX, args.Player.TileY); - TShock.Utils.Broadcast(string.Format("{0} has spawned skeletron {1} times!", args.Player.Name, numberOfEnemies)); + args.Player.SendMessage("Invalid syntax! Proper syntax: /king [amount]", Color.Red); return; } + int amount = 1; + if (args.Parameters.Count == 1 && !int.TryParse(args.Parameters[0], out amount)) + { + args.Player.SendMessage("Invalid syntax! Proper syntax: /king [amount]", Color.Red); + return; + } + amount = Math.Min(amount, Main.maxNPCs); + NPC king = TShock.Utils.GetNPCById(50); + TSPlayer.Server.SpawnNPC(king.type, king.name, amount, args.Player.TileX, args.Player.TileY); + TShock.Utils.Broadcast(string.Format("{0} has spawned king slime {1} times!", args.Player.Name, amount)); + } - if (boss.ToLower() == "wof" || boss.ToLower() == "flesh") + [Obsolete("This specific command for spawning mobs will replaced soon.")] + private static void Skeletron(CommandArgs args) + { + if (args.Parameters.Count > 1) { - if (Main.wof >= 0 || (args.Player.Y / 16f < (Main.maxTilesY - 205))) - { - args.Player.SendMessage("Can't spawn a Wall of Flesh!", Color.Red); - return; - } - NPC.SpawnWOF(new Vector2(args.Player.X, args.Player.Y)); - TShock.Utils.Broadcast(string.Format("{0} has spawned a Wall of Flesh!", args.Player.Name)); + args.Player.SendMessage("Invalid syntax! Proper syntax: /skeletron [amount]", Color.Red); return; } + int amount = 1; + if (args.Parameters.Count == 1 && !int.TryParse(args.Parameters[0], out amount)) + { + args.Player.SendMessage("Invalid syntax! Proper syntax: /skeletron [amount]", Color.Red); + return; + } + amount = Math.Min(amount, Main.maxNPCs); + NPC skeletron = TShock.Utils.GetNPCById(35); + TSPlayer.Server.SetTime(false, 0.0); + TSPlayer.Server.SpawnNPC(skeletron.type, skeletron.name, amount, args.Player.TileX, args.Player.TileY); + TShock.Utils.Broadcast(string.Format("{0} has spawned skeletron {1} times!", args.Player.Name, amount)); + } - if (boss.ToLower() == "twins") + [Obsolete("This specific command for spawning mobs will replaced soon.")] + private static void WoF(CommandArgs args) + { + if (Main.wof >= 0 || (args.Player.Y / 16f < (Main.maxTilesY - 205))) { - NPC retinazer = TShock.Utils.GetNPCById(125); - NPC spaz = TShock.Utils.GetNPCById(126); - TSPlayer.Server.SetTime(false, 0.0); - TSPlayer.Server.SpawnNPC(retinazer.type, retinazer.name, numberOfEnemies, args.Player.TileX, args.Player.TileY); - TSPlayer.Server.SpawnNPC(spaz.type, spaz.name, numberOfEnemies, args.Player.TileX, args.Player.TileY); - TShock.Utils.Broadcast(string.Format("{0} has spawned the twins {1} times!", args.Player.Name, numberOfEnemies)); + args.Player.SendMessage("Can't spawn Wall of Flesh!", Color.Red); return; } + NPC.SpawnWOF(new Vector2(args.Player.X, args.Player.Y)); + TShock.Utils.Broadcast(string.Format("{0} has spawned Wall of Flesh!", args.Player.Name)); + } - if (boss.ToLower() == "destroyer") + [Obsolete("This specific command for spawning mobs will replaced soon.")] + private static void Twins(CommandArgs args) + { + if (args.Parameters.Count > 1) { - NPC destroyer = TShock.Utils.GetNPCById(134); - TSPlayer.Server.SetTime(false, 0.0); - TSPlayer.Server.SpawnNPC(destroyer.type, destroyer.name, numberOfEnemies, args.Player.TileX, args.Player.TileY); - TShock.Utils.Broadcast(string.Format("{0} has spawned the destroyer {1} times!", args.Player.Name, numberOfEnemies)); + args.Player.SendMessage("Invalid syntax! Proper syntax: /twins [amount]", Color.Red); return; } + int amount = 1; + if (args.Parameters.Count == 1 && !int.TryParse(args.Parameters[0], out amount)) + { + args.Player.SendMessage("Invalid syntax! Proper syntax: /twins [amount]", Color.Red); + return; + } + amount = Math.Min(amount, Main.maxNPCs); + NPC retinazer = TShock.Utils.GetNPCById(125); + NPC spaz = TShock.Utils.GetNPCById(126); + TSPlayer.Server.SetTime(false, 0.0); + TSPlayer.Server.SpawnNPC(retinazer.type, retinazer.name, amount, args.Player.TileX, args.Player.TileY); + TSPlayer.Server.SpawnNPC(spaz.type, spaz.name, amount, args.Player.TileX, args.Player.TileY); + TShock.Utils.Broadcast(string.Format("{0} has spawned the twins {1} times!", args.Player.Name, amount)); + } - if (boss.ToLower() == "prime") + [Obsolete("This specific command for spawning mobs will replaced soon.")] + private static void Destroyer(CommandArgs args) + { + if (args.Parameters.Count > 1) { - NPC prime = TShock.Utils.GetNPCById(127); - TSPlayer.Server.SetTime(false, 0.0); - TSPlayer.Server.SpawnNPC(prime.type, prime.name, numberOfEnemies, args.Player.TileX, args.Player.TileY); - TShock.Utils.Broadcast(string.Format("{0} has spawned skeletron prime {1} times!", args.Player.Name, numberOfEnemies)); + args.Player.SendMessage("Invalid syntax! Proper syntax: /destroyer [amount]", Color.Red); return; } + int amount = 1; + if (args.Parameters.Count == 1 && !int.TryParse(args.Parameters[0], out amount)) + { + args.Player.SendMessage("Invalid syntax! Proper syntax: /destroyer [amount]", Color.Red); + return; + } + amount = Math.Min(amount, Main.maxNPCs); + NPC destroyer = TShock.Utils.GetNPCById(134); + TSPlayer.Server.SetTime(false, 0.0); + TSPlayer.Server.SpawnNPC(destroyer.type, destroyer.name, amount, args.Player.TileX, args.Player.TileY); + TShock.Utils.Broadcast(string.Format("{0} has spawned the destroyer {1} times!", args.Player.Name, amount)); + } - if (boss == "*") + [Obsolete("This specific command for spawning mobs will replaced soon.")] + private static void SkeletronPrime(CommandArgs args) + { + if (args.Parameters.Count > 1) { - NPC retinazer = TShock.Utils.GetNPCById(125); - NPC spaz = TShock.Utils.GetNPCById(126); - NPC destroyer = TShock.Utils.GetNPCById(134); - NPC prime = TShock.Utils.GetNPCById(127); - NPC eater = TShock.Utils.GetNPCById(13); - NPC eye = TShock.Utils.GetNPCById(4); - NPC king = TShock.Utils.GetNPCById(50); - NPC skeletron = TShock.Utils.GetNPCById(35); - TSPlayer.Server.SetTime(false, 0.0); - TSPlayer.Server.SpawnNPC(retinazer.type, retinazer.name, numberOfEnemies, args.Player.TileX, args.Player.TileY); - TSPlayer.Server.SpawnNPC(spaz.type, spaz.name, numberOfEnemies, args.Player.TileX, args.Player.TileY); - TSPlayer.Server.SpawnNPC(destroyer.type, destroyer.name, numberOfEnemies, args.Player.TileX, args.Player.TileY); - TSPlayer.Server.SpawnNPC(prime.type, prime.name, numberOfEnemies, args.Player.TileX, args.Player.TileY); - TSPlayer.Server.SpawnNPC(eater.type, eater.name, numberOfEnemies, args.Player.TileX, args.Player.TileY); - TSPlayer.Server.SpawnNPC(eye.type, eye.name, numberOfEnemies, args.Player.TileX, args.Player.TileY); - TSPlayer.Server.SpawnNPC(king.type, king.name, numberOfEnemies, args.Player.TileX, args.Player.TileY); - TSPlayer.Server.SpawnNPC(skeletron.type, skeletron.name, numberOfEnemies, args.Player.TileX, args.Player.TileY); - TShock.Utils.Broadcast(string.Format("{0} has spawned all bosses {1} times!", args.Player.Name, numberOfEnemies)); + args.Player.SendMessage("Invalid syntax! Proper syntax: /prime [amount]", Color.Red); return; } + int amount = 1; + if (args.Parameters.Count == 1 && !int.TryParse(args.Parameters[0], out amount)) + { + args.Player.SendMessage("Invalid syntax! Proper syntax: /prime [amount]", Color.Red); + return; + } + amount = Math.Min(amount, Main.maxNPCs); + NPC prime = TShock.Utils.GetNPCById(127); + TSPlayer.Server.SetTime(false, 0.0); + TSPlayer.Server.SpawnNPC(prime.type, prime.name, amount, args.Player.TileX, args.Player.TileY); + TShock.Utils.Broadcast(string.Format("{0} has spawned skeletron prime {1} times!", args.Player.Name, amount)); + } + + [Obsolete("This specific command for spawning mobs will replaced soon.")] + private static void Hardcore(CommandArgs args) // TODO: Add all 8 bosses + { + if (args.Parameters.Count > 1) + { + args.Player.SendMessage("Invalid syntax! Proper syntax: /hardcore [amount]", Color.Red); + return; + } + int amount = 1; + if (args.Parameters.Count == 1 && !int.TryParse(args.Parameters[0], out amount)) + { + args.Player.SendMessage("Invalid syntax! Proper syntax: /hardcore [amount]", Color.Red); + return; + } + amount = Math.Min(amount, Main.maxNPCs / 4); + NPC retinazer = TShock.Utils.GetNPCById(125); + NPC spaz = TShock.Utils.GetNPCById(126); + NPC destroyer = TShock.Utils.GetNPCById(134); + NPC prime = TShock.Utils.GetNPCById(127); + NPC eater = TShock.Utils.GetNPCById(13); + NPC eye = TShock.Utils.GetNPCById(4); + NPC king = TShock.Utils.GetNPCById(50); + NPC skeletron = TShock.Utils.GetNPCById(35); + TSPlayer.Server.SetTime(false, 0.0); + TSPlayer.Server.SpawnNPC(retinazer.type, retinazer.name, amount, args.Player.TileX, args.Player.TileY); + TSPlayer.Server.SpawnNPC(spaz.type, spaz.name, amount, args.Player.TileX, args.Player.TileY); + TSPlayer.Server.SpawnNPC(destroyer.type, destroyer.name, amount, args.Player.TileX, args.Player.TileY); + TSPlayer.Server.SpawnNPC(prime.type, prime.name, amount, args.Player.TileX, args.Player.TileY); + TSPlayer.Server.SpawnNPC(eater.type, eater.name, amount, args.Player.TileX, args.Player.TileY); + TSPlayer.Server.SpawnNPC(eye.type, eye.name, amount, args.Player.TileX, args.Player.TileY); + TSPlayer.Server.SpawnNPC(king.type, king.name, amount, args.Player.TileX, args.Player.TileY); + TSPlayer.Server.SpawnNPC(skeletron.type, skeletron.name, amount, args.Player.TileX, args.Player.TileY); + TShock.Utils.Broadcast(string.Format("{0} has spawned all bosses {1} times!", args.Player.Name, amount)); } private static void SpawnMob(CommandArgs args) @@ -1380,106 +1691,69 @@ namespace TShockAPI //Do not allow WoF to spawn, in certain conditions may cause loops in client { TSPlayer.Server.SpawnNPC(npc.type, npc.name, amount, args.Player.TileX, args.Player.TileY, 50, 20); - TShock.Utils.Broadcast(string.Format("{0} was spawned {1} time(s).", npc.name, amount)); + TSPlayer.All.SendSuccessMessage(string.Format("{0} was spawned {1} time(s).", npc.name, amount)); } else if (npc.type == 113) - args.Player.SendMessage("Sorry, you can't spawn Wall of Flesh! Try /wof instead."); + args.Player.SendErrorMessage("Sorry, you can't spawn Wall of Flesh! Try /wof instead."); // Maybe perhaps do something with WorldGen.SpawnWoF? else args.Player.SendMessage("Invalid mob type!", Color.Red); } } - private static void StartHardMode(CommandArgs args) - { - if (!TShock.Config.DisableHardmode) - WorldGen.StartHardmode(); - else - args.Player.SendMessage("Hardmode is disabled via config.", Color.Red); - } - - private static void DisableHardMode(CommandArgs args) - { - Main.hardMode = false; - args.Player.SendMessage("Hardmode is now disabled.", Color.Green); - } #endregion Cause Events and Spawn Monsters Commands #region Teleport Commands private static void Home(CommandArgs args) { - if (!args.Player.RealPlayer) - { - args.Player.SendMessage("You cannot use teleport commands!"); - return; - } - args.Player.Spawn(); - args.Player.SendMessage("Teleported to your spawnpoint."); + args.Player.SendSuccessMessage("Teleported to your spawnpoint."); } private static void Spawn(CommandArgs args) { - if (!args.Player.RealPlayer) - { - args.Player.SendMessage("You cannot use teleport commands!"); - return; - } - if (args.Player.Teleport(Main.spawnTileX, Main.spawnTileY)) - args.Player.SendMessage("Teleported to the map's spawnpoint."); + args.Player.SendSuccessMessage("Teleported to the map's spawnpoint."); } private static void TP(CommandArgs args) { - if (!args.Player.RealPlayer) - { - args.Player.SendMessage("You cannot use teleport commands!"); - return; - } - if (args.Parameters.Count < 1) { - args.Player.SendMessage("Invalid syntax! Proper syntax: /tp ", Color.Red); + args.Player.SendErrorMessage("Invalid syntax! Proper syntax: /tp "); return; } string plStr = String.Join(" ", args.Parameters); var players = TShock.Utils.FindPlayer(plStr); if (players.Count == 0) - args.Player.SendMessage("Invalid player!", Color.Red); + args.Player.SendErrorMessage("Invalid player!"); else if (players.Count > 1) - args.Player.SendMessage("More than one player matched!", Color.Red); + args.Player.SendErrorMessage("More than one player matched!"); else if (!players[0].TPAllow && !args.Player.Group.HasPermission(Permissions.tpall)) { var plr = players[0]; - args.Player.SendMessage(plr.Name + " Has Selected For Users Not To Teleport To Them"); - plr.SendMessage(args.Player.Name + " Attempted To Teleport To You"); + args.Player.SendErrorMessage(plr.Name + " has prevented users from teleporting to them."); + plr.SendInfoMessage(args.Player.Name + " attempted to teleport to you."); } else { var plr = players[0]; if (args.Player.Teleport(plr.TileX, plr.TileY + 3)) { - args.Player.SendMessage(string.Format("Teleported to {0}", plr.Name)); + args.Player.SendSuccessMessage(string.Format("Teleported to {0}.", plr.Name)); if (!args.Player.Group.HasPermission(Permissions.tphide)) - plr.SendMessage(args.Player.Name + " Teleported To You"); + plr.SendInfoMessage(args.Player.Name + " teleported to you."); } } } private static void TPHere(CommandArgs args) { - if (!args.Player.RealPlayer) - { - args.Player.SendMessage("You cannot use teleport commands!"); - return; - } - if (args.Parameters.Count < 1) { - args.Player.SendMessage("Invalid syntax! Proper syntax: /tphere ", Color.Red); + args.Player.SendErrorMessage("Invalid syntax! Proper syntax: /tphere "); return; } @@ -1487,13 +1761,13 @@ namespace TShockAPI if (plStr == "all" || plStr == "*") { - args.Player.SendMessage(string.Format("You brought all players here.")); + args.Player.SendInfoMessage(string.Format("You brought all players here.")); for (int i = 0; i < Main.maxPlayers; i++) { if (Main.player[i].active && (Main.player[i] != args.TPlayer)) { if (TShock.Players[i].Teleport(args.Player.TileX, args.Player.TileY + 3)) - TShock.Players[i].SendMessage(string.Format("You were teleported to {0}.", args.Player.Name)); + TShock.Players[i].SendSuccessMessage(string.Format("You were teleported to {0}.", args.Player.Name) + "."); } } return; @@ -1502,19 +1776,19 @@ namespace TShockAPI var players = TShock.Utils.FindPlayer(plStr); if (players.Count == 0) { - args.Player.SendMessage("Invalid player!", Color.Red); + args.Player.SendErrorMessage("Invalid player!"); } else if (players.Count > 1) { - args.Player.SendMessage("More than one player matched!", Color.Red); + args.Player.SendErrorMessage("More than one player matched!"); } else { var plr = players[0]; if (plr.Teleport(args.Player.TileX, args.Player.TileY + 3)) { - plr.SendMessage(string.Format("You were teleported to {0}.", args.Player.Name)); - args.Player.SendMessage(string.Format("You brought {0} here.", plr.Name)); + plr.SendInfoMessage(string.Format("You were teleported to {0}.", args.Player.Name)); + args.Player.SendSuccessMessage(string.Format("You brought {0} here.", plr.Name)); } } } @@ -1522,9 +1796,9 @@ namespace TShockAPI private static void TPAllow(CommandArgs args) { if (!args.Player.TPAllow) - args.Player.SendMessage("Other Players Can Now Teleport To You"); + args.Player.SendSuccessMessage("You have removed your teleportation protection."); if (args.Player.TPAllow) - args.Player.SendMessage("Other Players Can No Longer Teleport To You"); + args.Player.SendSuccessMessage("You have enabled teleportation protection."); args.Player.TPAllow = !args.Player.TPAllow; } @@ -1535,76 +1809,35 @@ namespace TShockAPI { if (hasManageWarpPermission) { - args.Player.SendMessage("All warp commands were merged into one in TShock 4.0.", Color.Yellow); - args.Player.SendMessage("Previous warps with spaces should be wrapped in single quotes.", Color.Red); - args.Player.SendMessage("Invalid syntax. Syntax: /warp [command] [arguments]", Color.Green); - args.Player.SendMessage("Commands: add, del, hide, list, send, [warpname]", Color.Green); - args.Player.SendMessage("Arguments: add [warp name], del [warp name], list [page]", Color.Green); - args.Player.SendMessage("Arguments: send [player] [warp name], hide [warp name] [Enable(true/false)]", Color.Green); - args.Player.SendMessage("Examples: /warp add foobar, /warp hide foobar true, /warp foobar", Color.Green); + args.Player.SendInfoMessage("Invalid syntax! Proper syntax: /warp [command] [arguments]"); + args.Player.SendInfoMessage("Commands: add, del, hide, list, send, [warpname]"); + args.Player.SendInfoMessage("Arguments: add [warp name], del [warp name], list [page]"); + args.Player.SendInfoMessage("Arguments: send [player] [warp name], hide [warp name] [Enable(true/false)]"); + args.Player.SendInfoMessage("Examples: /warp add foobar, /warp hide foobar true, /warp foobar"); return; } else { - args.Player.SendMessage("Invalid syntax. Syntax: /warp [name] or /warp list ", Color.Red); - args.Player.SendMessage("Previous warps with spaces should be wrapped in single quotes.", Color.Red); - + args.Player.SendErrorMessage("Invalid syntax! Proper syntax: /warp [name] or /warp list "); return; } } if (args.Parameters[0].Equals("list")) { - #region - //How many warps per page - const int pagelimit = 15; - //How many warps per line - const int perline = 5; - //Pages start at 0 but are displayed and parsed at 1 - int page = 0; - - - if (args.Parameters.Count > 1) - { - if (!int.TryParse(args.Parameters[1], out page) || page < 1) - { - args.Player.SendMessage(string.Format("Invalid page number ({0})", page), Color.Red); - return; - } - page--; //Substract 1 as pages are parsed starting at 1 and not 0 - } - - var warps = TShock.Warps.ListAllPublicWarps(Main.worldID.ToString()); - - //Check if they are trying to access a page that doesn't exist. - int pagecount = warps.Count/pagelimit; - if (page > pagecount) - { - args.Player.SendMessage(string.Format("Page number exceeds pages ({0}/{1})", page + 1, pagecount + 1), Color.Red); + #region List warps + int pageNumber; + if (!PaginationTools.TryParsePageNumber(args.Parameters, 1, args.Player, out pageNumber)) return; - } - - //Display the current page and the number of pages. - args.Player.SendMessage(string.Format("Current Warps ({0}/{1}):", page + 1, pagecount + 1), Color.Green); - - //Add up to pagelimit names to a list - var nameslist = new List(); - for (int i = (page*pagelimit); (i < ((page*pagelimit) + pagelimit)) && i < warps.Count; i++) - { - nameslist.Add(warps[i].WarpName); - } - - //convert the list to an array for joining - var names = nameslist.ToArray(); - for (int i = 0; i < names.Length; i += perline) - { - args.Player.SendMessage(string.Join(", ", names, i, Math.Min(names.Length - i, perline)), Color.Yellow); - } - - if (page < pagecount) - { - args.Player.SendMessage(string.Format("Type /warp list {0} for more warps.", (page + 2)), Color.Yellow); - } + IEnumerable warpNames = from warp in TShock.Warps.ListAllPublicWarps(Main.worldID.ToString()) + select warp.WarpName; + PaginationTools.SendPage(args.Player, pageNumber, PaginationTools.BuildLinesFromTerms(warpNames), + new PaginationTools.Settings + { + HeaderFormat = "Warps ({0}/{1}):", + FooterFormat = "Type /warp list {0} for more.", + NothingToDisplayString = "There are currently no warps defined." + }); #endregion } else if (args.Parameters[0].ToLower() == "add" && hasManageWarpPermission) @@ -1615,21 +1848,20 @@ namespace TShockAPI string warpName = args.Parameters[1]; if (warpName == "list" || warpName == "hide" || warpName == "del" || warpName == "add") { - args.Player.SendMessage("Name reserved, use a different name", Color.Red); + args.Player.SendErrorMessage("Name reserved, use a different name."); } else if (TShock.Warps.AddWarp(args.Player.TileX, args.Player.TileY, warpName, Main.worldID.ToString())) { - args.Player.SendMessage("Warp added: " + warpName, Color.Yellow); + args.Player.SendSuccessMessage("Warp added: " + warpName); } else { - args.Player.SendMessage("Warp " + warpName + " already exists", Color.Red); + args.Player.SendErrorMessage("Warp " + warpName + " already exists."); } } else - args.Player.SendMessage("Invalid syntax! Proper syntax: /warp add [name]", Color.Red); + args.Player.SendErrorMessage("Invalid syntax! Proper syntax: /warp add [name]"); #endregion - } else if (args.Parameters[0].ToLower() == "del" && hasManageWarpPermission) { @@ -1638,14 +1870,13 @@ namespace TShockAPI { string warpName = args.Parameters[1]; if (TShock.Warps.RemoveWarp(warpName)) - args.Player.SendMessage("Warp deleted: " + warpName, Color.Yellow); + args.Player.SendSuccessMessage("Warp deleted: " + warpName); else - args.Player.SendMessage("Could not find specified warp.", Color.Red); + args.Player.SendErrorMessage("Could not find the specified warp."); } else - args.Player.SendMessage("Invalid syntax! Proper syntax: /warp del [name]", Color.Red); + args.Player.SendErrorMessage("Invalid syntax! Proper syntax: /warp del [name]"); #endregion - } else if (args.Parameters[0].ToLower() == "hide" && hasManageWarpPermission) { @@ -1656,21 +1887,21 @@ namespace TShockAPI bool state = false; if (Boolean.TryParse(args.Parameters[2], out state)) { - if (TShock.Warps.HideWarp(args.Parameters[0], state)) + if (TShock.Warps.HideWarp(args.Parameters[1], state)) { if (state) - args.Player.SendMessage("Warp " + warpName + " is now private.", Color.Yellow); + args.Player.SendSuccessMessage("Warp " + warpName + " is now private."); else - args.Player.SendMessage("Warp " + warpName + " is now public.", Color.Yellow); + args.Player.SendSuccessMessage("Warp " + warpName + " is now public."); } else - args.Player.SendMessage("Could not find specified warp.", Color.Red); + args.Player.SendErrorMessage("Could not find specified warp."); } else - args.Player.SendMessage("Invalid syntax! Proper syntax: /warp hide [name] ", Color.Red); + args.Player.SendErrorMessage("Invalid syntax! Proper syntax: /warp hide [name] "); } else - args.Player.SendMessage("Invalid syntax! Proper syntax: /warp hide [name] ", Color.Red); + args.Player.SendErrorMessage("Invalid syntax! Proper syntax: /warp hide [name] "); #endregion } else if (args.Parameters[0].ToLower() == "send" && args.Player.Group.HasPermission(Permissions.tphere)) @@ -1678,19 +1909,19 @@ namespace TShockAPI #region Warp send if (args.Parameters.Count < 3) { - args.Player.SendMessage("Invalid syntax! Proper syntax: /warp send [player] [warpname]", Color.Red); + args.Player.SendErrorMessage("Invalid syntax! Proper syntax: /warp send [player] [warpname]"); return; } var foundplr = TShock.Utils.FindPlayer(args.Parameters[1]); if (foundplr.Count == 0) { - args.Player.SendMessage("Invalid player!", Color.Red); + args.Player.SendErrorMessage("Invalid player!"); return; } else if (foundplr.Count > 1) { - args.Player.SendMessage(string.Format("More than one ({0}) player matched!", args.Parameters.Count), Color.Red); + args.Player.SendErrorMessage(string.Format("More than one ({0}) player matched!", args.Parameters.Count)); return; } string warpName = args.Parameters[2]; @@ -1700,16 +1931,15 @@ namespace TShockAPI { if (plr.Teleport((int)warp.WarpPos.X, (int)warp.WarpPos.Y + 3)) { - plr.SendMessage(string.Format("{0} Warped you to {1}", args.Player.Name, warpName), Color.Yellow); - args.Player.SendMessage(string.Format("You warped {0} to {1}.", plr.Name, warpName), Color.Yellow); + plr.SendSuccessMessage(string.Format("{0} warped you to {1}.", args.Player.Name, warpName)); + args.Player.SendSuccessMessage(string.Format("You warped {0} to {1}.", plr.Name, warpName)); } } else { - args.Player.SendMessage("Specified warp not found.", Color.Red); + args.Player.SendErrorMessage("Specified warp not found."); } #endregion - } else { @@ -1718,11 +1948,11 @@ namespace TShockAPI if (warp.WarpPos != Vector2.Zero) { if (args.Player.Teleport((int)warp.WarpPos.X, (int)warp.WarpPos.Y + 3)) - args.Player.SendMessage("Warped to " + warpName, Color.Yellow); + args.Player.SendSuccessMessage("Warped to " + warpName + "."); } else { - args.Player.SendMessage("Specified warp not found", Color.Red); + args.Player.SendErrorMessage("The specified warp was not found."); } } } @@ -1731,341 +1961,442 @@ namespace TShockAPI #region Group Management - private static void AddGroup(CommandArgs args) + private static void GroupDeprecated(CommandArgs args) { - if (args.Parameters.Count > 0) - { - String groupname = args.Parameters[0]; - args.Parameters.RemoveAt(0); - String permissions = String.Join(",", args.Parameters); - - String response = TShock.Groups.AddGroup(groupname, permissions); - if (response.Length > 0) - args.Player.SendMessage(response, Color.Green); - } - else - { - args.Player.SendMessage("Incorrect format: /addGroup [optional permissions]", Color.Red); - } + args.Player.SendInfoMessage("The group commands were merged into /group in TShock 4.1; check /group help."); } - private static void DeleteGroup(CommandArgs args) + private static void Group(CommandArgs args) { - if (args.Parameters.Count > 0) + if (args.Parameters.Count == 0) { - String groupname = args.Parameters[0]; - - String response = TShock.Groups.DeleteGroup(groupname); - if (response.Length > 0) - args.Player.SendMessage(response, Color.Green); + args.Player.SendInfoMessage("Invalid syntax! Proper syntax: /group [arguments]"); + args.Player.SendInfoMessage("Commands: add, addperm, del, delperm, list, listperm"); + args.Player.SendInfoMessage("Arguments: add , addperm , del "); + args.Player.SendInfoMessage("Arguments: delperm , list [page], listperm [page]"); + return; } - else + + switch (args.Parameters[0].ToLower()) { - args.Player.SendMessage("Incorrect format: /delGroup ", Color.Red); - } - } - - private static void ModifyGroup(CommandArgs args) - { - if (args.Parameters.Count > 2) - { - String com = args.Parameters[0]; - args.Parameters.RemoveAt(0); - - String groupname = args.Parameters[0]; - args.Parameters.RemoveAt(0); - - string response = ""; - if (com.Equals("add")) - { - if( groupname == "*" ) + case "add": + #region Add group { - int count = 0; - foreach( Group g in TShock.Groups ) + if (args.Parameters.Count < 2) { - response = TShock.Groups.AddPermissions(g.Name, args.Parameters); - if (!response.StartsWith("Error:")) - count++; - } - args.Player.SendMessage(String.Format("{0} groups were modified.", count ), Color.Green ); - return; - } - response = TShock.Groups.AddPermissions(groupname, args.Parameters); - if (response.Length > 0) - args.Player.SendMessage(response, Color.Green); - return; - } - - if (com.Equals("del") || com.Equals("delete")) - { - if (groupname == "*") - { - int count = 0; - foreach (Group g in TShock.Groups) - { - response = TShock.Groups.DeletePermissions(g.Name, args.Parameters); - if (!response.StartsWith("Error:")) - count++; - } - args.Player.SendMessage(String.Format("{0} groups were modified.", count), Color.Green); - return; - } - response = TShock.Groups.DeletePermissions(groupname, args.Parameters); - if (response.Length > 0) - args.Player.SendMessage(response, Color.Green); - return; - } - } - args.Player.SendMessage("Incorrect format: /modGroup add|del ", Color.Red); - } - - private static void ViewGroups(CommandArgs args) - { - if (args.Parameters.Count > 0) - { - String com = args.Parameters[0]; - - if( com == "list" ) - { - string ret = "Groups: "; - foreach( Group g in TShock.Groups.groups ) - { - if (ret.Length > 50) - { - args.Player.SendMessage(ret, Color.Green); - ret = ""; - } - - if( ret != "" ) - { - ret += ", "; - } - - ret += g.Name; - } - - if (ret.Length > 0) - { - args.Player.SendMessage(ret, Color.Green); - } - return; - } - else if( com == "perm") - { - if (args.Parameters.Count > 1) - { - String groupname = args.Parameters[1]; - - if( TShock.Groups.GroupExists( groupname ) ) - { - string ret = String.Format("Permissions for {0}: ", groupname); - foreach (string p in TShock.Utils.GetGroup( groupname ).permissions) - { - if (ret.Length > 50) - { - args.Player.SendMessage(ret, Color.Green); - ret = ""; - } - - if (ret != "") - { - ret += ", "; - } - - ret += p; - } - if (ret.Length > 0) - { - args.Player.SendMessage(ret, Color.Green); - } - + args.Player.SendErrorMessage("Invalid syntax! Proper syntax: /group add [permissions]"); return; } + + string groupName = args.Parameters[1]; + args.Parameters.RemoveRange(0, 2); + string permissions = String.Join(",", args.Parameters); + + try + { + string response = TShock.Groups.AddGroup(groupName, permissions); + if (response.Length > 0) + { + args.Player.SendSuccessMessage(response); + } + } + catch (GroupManagerException ex) + { + args.Player.SendErrorMessage(ex.ToString()); + } + } + #endregion + return; + case "addperm": + #region Add permissions + { + if (args.Parameters.Count < 3) + { + args.Player.SendErrorMessage("Invalid syntax! Proper syntax: /group addperm "); + return; + } + + string groupName = args.Parameters[1]; + args.Parameters.RemoveRange(0, 2); + if (groupName == "*") + { + foreach (Group g in TShock.Groups) + { + TShock.Groups.AddPermissions(g.Name, args.Parameters); + } + args.Player.SendSuccessMessage("Modified all groups."); + return; + } + try + { + string response = TShock.Groups.AddPermissions(groupName, args.Parameters); + if (response.Length > 0) + { + args.Player.SendSuccessMessage(response); + } + return; + } + catch (GroupManagerException ex) + { + args.Player.SendErrorMessage(ex.ToString()); + } + } + #endregion + return; + + case "parent": + #region Parent + { + if (args.Parameters.Count < 2) + { + args.Player.SendErrorMessage("Invalid syntax! Proper syntax: /group parent [new parent group name]"); + return; + } + + string groupName = args.Parameters[1]; + Group group = TShock.Groups.GetGroupByName(groupName); + if (group == null) + { + args.Player.SendErrorMessage("No such group \"{0}\".", groupName); + return; + } + + if (args.Parameters.Count > 2) + { + string newParentGroupName = string.Join(" ", args.Parameters.Skip(2)); + if (!string.IsNullOrWhiteSpace(newParentGroupName) && !TShock.Groups.GroupExists(newParentGroupName)) + { + args.Player.SendErrorMessage("No such group \"{0}\".", newParentGroupName); + return; + } + + try + { + TShock.Groups.UpdateGroup(groupName, newParentGroupName, group.Permissions, group.ChatColor); + + if (!string.IsNullOrWhiteSpace(newParentGroupName)) + args.Player.SendSuccessMessage("Parent of group \"{0}\" set to \"{1}\".", groupName, newParentGroupName); + else + args.Player.SendSuccessMessage("Removed parent of group \"{0}\".", groupName); + } + catch (GroupManagerException ex) + { + args.Player.SendErrorMessage(ex.Message); + } + } else { - args.Player.SendMessage("Group does not exist.", Color.Red); - return; + if (group.Parent != null) + args.Player.SendSuccessMessage("Parent of \"{0}\" is \"{1}\".", group.Name, group.Parent.Name); + else + args.Player.SendSuccessMessage("Group \"{0}\" has no parent.", group.Name); } } - } - } - args.Player.SendMessage("Incorrect format: /group list", Color.Red); - args.Player.SendMessage(" /group perm ", Color.Red); - } + #endregion + return; + case "del": + #region Delete group + { + if (args.Parameters.Count != 2) + { + args.Player.SendErrorMessage("Invalid syntax! Proper syntax: /group del "); + return; + } + try + { + string response = TShock.Groups.DeleteGroup(args.Parameters[1]); + if (response.Length > 0) + { + args.Player.SendSuccessMessage(response); + } + } + catch (GroupManagerException ex) + { + args.Player.SendErrorMessage(ex.ToString()); + } + } + #endregion + return; + case "delperm": + #region Delete permissions + { + if (args.Parameters.Count < 3) + { + args.Player.SendErrorMessage("Invalid syntax! Proper syntax: /group delperm "); + return; + } + + string groupName = args.Parameters[1]; + args.Parameters.RemoveRange(0, 2); + if (groupName == "*") + { + foreach (Group g in TShock.Groups) + { + TShock.Groups.DeletePermissions(g.Name, args.Parameters); + } + args.Player.SendSuccessMessage("Modified all groups."); + return; + } + try + { + string response = TShock.Groups.DeletePermissions(groupName, args.Parameters); + if (response.Length > 0) + { + args.Player.SendSuccessMessage(response); + } + return; + } + catch (GroupManagerException ex) + { + args.Player.SendErrorMessage(ex.ToString()); + } + } + #endregion + return; + case "list": + #region List groups + { + int pageNumber; + if (!PaginationTools.TryParsePageNumber(args.Parameters, 1, args.Player, out pageNumber)) + return; + IEnumerable groupNames = from grp in TShock.Groups.groups + select grp.Name; + PaginationTools.SendPage(args.Player, pageNumber, PaginationTools.BuildLinesFromTerms(groupNames), + new PaginationTools.Settings + { + HeaderFormat = "Groups ({0}/{1}):", + FooterFormat = "Type /group list {0} for more." + }); + } + #endregion + return; + case "listperm": + #region List permissions + { + if (args.Parameters.Count == 1) + { + args.Player.SendErrorMessage("Invalid syntax! Proper syntax: /group listperm [page]"); + return; + } + int pageNumber; + if (!PaginationTools.TryParsePageNumber(args.Parameters, 2, args.Player, out pageNumber)) + return; + + if (!TShock.Groups.GroupExists(args.Parameters[1])) + { + args.Player.SendErrorMessage("Invalid group."); + return; + } + Group grp = TShock.Utils.GetGroup(args.Parameters[1]); + List permissions = grp.TotalPermissions; + + PaginationTools.SendPage(args.Player, pageNumber, PaginationTools.BuildLinesFromTerms(permissions), + new PaginationTools.Settings + { + HeaderFormat = "Permissions for " + grp.Name + " ({0}/{1}):", + FooterFormat = "Type /group permlist " + grp.Name + " {0} for more.", + NothingToDisplayString = "There are currently no permissions for " + grp.Name + "." + }); + } + #endregion + return; + case "help": + args.Player.SendInfoMessage("Syntax: /group [arguments]"); + args.Player.SendInfoMessage("Commands: add, addperm, parent, del, delperm, list, listperm"); + args.Player.SendInfoMessage("Arguments: add , addperm , del "); + args.Player.SendInfoMessage("Arguments: delperm , list [page], listperm [page]"); + return; + } + } #endregion Group Management #region Item Management - private static void AddItem(CommandArgs args) + private static void ItemBanDeprecated(CommandArgs args) { - if (args.Parameters.Count == 1) - { - var items = TShock.Utils.GetItemByIdOrName(args.Parameters[0]); - if (items.Count == 0) - { - args.Player.SendMessage("Invalid item type!", Color.Red); - } - else if (items.Count > 1) - { - args.Player.SendMessage(string.Format("More than one ({0}) item matched!", items.Count), Color.Red); - } - else - { - var item = items[0]; - if (item.type >= 1) - { - TShock.Itembans.AddNewBan(item.name); - args.Player.SendMessage(item.name + " has been banned.", Color.Green); - } - else - { - args.Player.SendMessage("Invalid item type!", Color.Red); - } - } - } - else - { - args.Player.SendMessage("Invalid use: /additem \"item name\" or /additem ##", Color.Red); - } + args.Player.SendInfoMessage("The item ban commands were merged into /itemban in TShock 4.1; check /itemban help."); } - private static void DeleteItem(CommandArgs args) + private static void ItemBan(CommandArgs args) { - if (args.Parameters.Count == 1) + if (args.Parameters.Count == 0) { - var items = TShock.Utils.GetItemByIdOrName(args.Parameters[0]); - if (items.Count == 0) - { - args.Player.SendMessage("Invalid item type!", Color.Red); - } - else if (items.Count > 1) - { - args.Player.SendMessage(string.Format("More than one ({0}) item matched!", items.Count), Color.Red); - } - else - { - var item = items[0]; - if (item.type >= 1) - { - TShock.Itembans.RemoveBan(item.name); - args.Player.SendMessage(item.name + " has been unbanned.", Color.Green); - } - else - { - args.Player.SendMessage("Invalid item type!", Color.Red); - } - } + args.Player.SendInfoMessage("Invalid syntax! Proper syntax: /itemban [arguments]"); + args.Player.SendInfoMessage("Commands: add, allow, del, disallow, list"); + args.Player.SendInfoMessage("Arguments: add , allow "); + args.Player.SendInfoMessage("Arguments: del , disallow , list [page]"); + return; } - else + + switch (args.Parameters[0].ToLower()) { - args.Player.SendMessage("Invalid use: /delitem \"item name\" or /delitem ##", Color.Red); - } - } - - private static void ListItems(CommandArgs args) - { - args.Player.SendMessage("The banned items are: " + String.Join(",", TShock.Itembans.ItemBans), Color.Yellow); - } - - private static void AddItemGroup(CommandArgs args) - { - if (args.Parameters.Count == 2) - { - var items = TShock.Utils.GetItemByIdOrName(args.Parameters[0]); - if (items.Count == 0) - { - args.Player.SendMessage("Invalid item type!", Color.Red); - } - else if (items.Count > 1) - { - args.Player.SendMessage(string.Format("More than one ({0}) item matched!", items.Count), Color.Red); - } - else - { - var item = items[0]; - if (item.type >= 1) + case "add": + #region Add item { - if(TShock.Groups.GroupExists(args.Parameters[1])) + if (args.Parameters.Count != 2) { - ItemBan ban = TShock.Itembans.GetItemBanByName(item.name); - - if(!ban.AllowedGroups.Contains(args.Parameters[1])) - { - TShock.Itembans.AllowGroup(item.name, args.Parameters[1]); - args.Player.SendMessage("Banned item " + item.name + " has been allowed for group " + args.Parameters[1] + ".", Color.Green); - } - else - { - args.Player.SendMessage("Banned item " + item.name + " is already allowed for group " + args.Parameters[1] + "!", Color.OrangeRed); - } + args.Player.SendErrorMessage("Invalid syntax! Proper syntax: /itemban add "); + return; + } + + List items = TShock.Utils.GetItemByIdOrName(args.Parameters[1]); + if (items.Count == 0) + { + args.Player.SendErrorMessage("Invalid item."); + } + else if (items.Count > 1) + { + args.Player.SendErrorMessage(string.Format("More than one ({0}) item matched.", items.Count)); } else { - args.Player.SendMessage("Group " + args.Parameters[1] + " not found!", Color.Red); + TShock.Itembans.AddNewBan(items[0].name); + args.Player.SendSuccessMessage("Banned " + items[0].name + "."); } } - else + #endregion + return; + case "allow": + #region Allow group to item { - args.Player.SendMessage("Invalid item type!", Color.Red); - } - } - } - else - { - args.Player.SendMessage("Invalid use: /additemgroup \"item name\" \"group name\"", Color.Red); - } - } - - private static void DeleteItemGroup(CommandArgs args) - { - if (args.Parameters.Count == 2) - { - var items = TShock.Utils.GetItemByIdOrName(args.Parameters[0]); - if (items.Count == 0) - { - args.Player.SendMessage("Invalid item type!", Color.Red); - } - else if (items.Count > 1) - { - args.Player.SendMessage(string.Format("More than one ({0}) item matched!", items.Count), Color.Red); - } - else - { - var item = items[0]; - if (item.type >= 1) - { - if(TShock.Groups.GroupExists(args.Parameters[1])) + if (args.Parameters.Count != 3) { - ItemBan ban = TShock.Itembans.GetItemBanByName(item.name); - - if(ban.AllowedGroups.Contains(args.Parameters[1])) - { - TShock.Itembans.RemoveGroup(item.name, args.Parameters[1]); - args.Player.SendMessage("Removed access for group " + args.Parameters[1] + " to banned item " + item.name + ".", Color.Green); - } - else - { - args.Player.SendMessage("Group " + args.Parameters[1] + " has not access to banned item " + item.name + "!", Color.Red); - } + args.Player.SendErrorMessage("Invalid syntax! Proper syntax: /itemban allow "); + return; + } + + List items = TShock.Utils.GetItemByIdOrName(args.Parameters[1]); + if (items.Count == 0) + { + args.Player.SendErrorMessage("Invalid item."); + } + else if (items.Count > 1) + { + args.Player.SendErrorMessage(string.Format("More than one ({0}) item matched.", items.Count)); } else { - args.Player.SendMessage("Group " + args.Parameters[1] + " not found!", Color.Red); + if (!TShock.Groups.GroupExists(args.Parameters[2])) + { + args.Player.SendErrorMessage("Invalid group."); + return; + } + + ItemBan ban = TShock.Itembans.GetItemBanByName(items[0].name); + if (ban == null) + { + args.Player.SendErrorMessage(items[0].name + " is not banned."); + return; + } + if (!ban.AllowedGroups.Contains(args.Parameters[2])) + { + TShock.Itembans.AllowGroup(items[0].name, args.Parameters[2]); + args.Player.SendSuccessMessage(String.Format("{0} has been allowed to use {1}.", args.Parameters[2], items[0].name)); + } + else + { + args.Player.SendWarningMessage(String.Format("{0} is already allowed to use {1}.", args.Parameters[2], items[0].name)); + } } } - else + #endregion + return; + case "del": + #region Delete item { - args.Player.SendMessage("Invalid item type!", Color.Red); + if (args.Parameters.Count != 2) + { + args.Player.SendErrorMessage("Invalid syntax! Proper syntax: /itemban del "); + return; + } + + List items = TShock.Utils.GetItemByIdOrName(args.Parameters[1]); + if (items.Count == 0) + { + args.Player.SendErrorMessage("Invalid item."); + } + else if (items.Count > 1) + { + args.Player.SendErrorMessage(string.Format("More than one ({0}) item matched.", items.Count)); + } + else + { + TShock.Itembans.RemoveBan(items[0].name); + args.Player.SendSuccessMessage("Unbanned " + items[0].name + "."); + } } - } - } - else - { - args.Player.SendMessage("Invalid use: /delitemgroup \"item name\" \"group name\"", Color.Red); + #endregion + return; + case "disallow": + #region Allow group to item + { + if (args.Parameters.Count != 3) + { + args.Player.SendErrorMessage("Invalid syntax! Proper syntax: /itemban disallow "); + return; + } + + List items = TShock.Utils.GetItemByIdOrName(args.Parameters[1]); + if (items.Count == 0) + { + args.Player.SendErrorMessage("Invalid item."); + } + else if (items.Count > 1) + { + args.Player.SendErrorMessage(string.Format("More than one ({0}) item matched.", items.Count)); + } + else + { + if (!TShock.Groups.GroupExists(args.Parameters[2])) + { + args.Player.SendErrorMessage("Invalid group."); + return; + } + + ItemBan ban = TShock.Itembans.GetItemBanByName(items[0].name); + if (ban == null) + { + args.Player.SendErrorMessage(items[0].name + " is not banned."); + return; + } + if (ban.AllowedGroups.Contains(args.Parameters[2])) + { + TShock.Itembans.RemoveGroup(items[0].name, args.Parameters[2]); + args.Player.SendSuccessMessage(String.Format("{0} has been disallowed to use {1}.", args.Parameters[2], items[0].name)); + } + else + { + args.Player.SendWarningMessage(String.Format("{0} is already disallowed to use {1}.", args.Parameters[2], items[0].name)); + } + } + } + #endregion + return; + case "help": + args.Player.SendInfoMessage("Syntax: /itemban [arguments]"); + args.Player.SendInfoMessage("Commands: add, allow, del, disallow, list"); + args.Player.SendInfoMessage("Arguments: add , allow "); + args.Player.SendInfoMessage("Arguments: del , disallow , list [page]"); + return; + case "list": + #region List items + int pageNumber; + if (!PaginationTools.TryParsePageNumber(args.Parameters, 1, args.Player, out pageNumber)) + return; + IEnumerable itemNames = from itemBan in TShock.Itembans.ItemBans + select itemBan.Name; + PaginationTools.SendPage(args.Player, pageNumber, PaginationTools.BuildLinesFromTerms(itemNames), + new PaginationTools.Settings + { + HeaderFormat = "Item bans ({0}/{1}):", + FooterFormat = "Type /itemban list {0} for more.", + NothingToDisplayString = "There are currently no banned items." + }); + #endregion + return; } } - #endregion Item Management #region Server Config Commands @@ -2075,29 +2406,27 @@ namespace TShockAPI Main.spawnTileX = args.Player.TileX + 1; Main.spawnTileY = args.Player.TileY + 3; SaveManager.Instance.SaveWorld(false); - args.Player.SendMessage( "Spawn has now been set at your location.", Color.Green); + args.Player.SendSuccessMessage("Spawn has now been set at your location."); } private static void Reload(CommandArgs args) { - FileTools.SetupConfig(); - TShock.HandleCommandLinePostConfigLoad(Environment.GetCommandLineArgs()); - TShock.Groups.LoadPermisions(); - TShock.Regions.ReloadAllRegions(); - args.Player.SendMessage( - "Configuration, Permissions, and Regions reload complete. Some changes may require server restart."); + TShock.Utils.Reload(args.Player); + + args.Player.SendSuccessMessage( + "Configuration, permissions, and regions reload complete. Some changes may require a server restart."); } private static void ServerPassword(CommandArgs args) { if (args.Parameters.Count != 1) { - args.Player.SendMessage("Invalid syntax! Proper syntax: /password \"\"", Color.Red); + args.Player.SendErrorMessage("Invalid syntax! Proper syntax: /password \"\""); return; } string passwd = args.Parameters[0]; TShock.Config.ServerPassword = passwd; - args.Player.SendMessage(string.Format("Server password changed to: {0}", passwd)); + args.Player.SendSuccessMessage(string.Format("Server password has been changed to: {0}.", passwd)); } private static void Save(CommandArgs args) @@ -2107,39 +2436,40 @@ namespace TShockAPI { tsply.SaveServerInventory(); } + args.Player.SendSuccessMessage("Save succeeded."); } private static void Settle(CommandArgs args) { if (Liquid.panicMode) { - args.Player.SendMessage("Liquid is already settling!", Color.Red); + args.Player.SendWarningMessage("Liquids are already settling!"); return; } Liquid.StartPanic(); - TShock.Utils.Broadcast("Settling all liquids..."); + args.Player.SendInfoMessage("Settling liquids."); } private static void MaxSpawns(CommandArgs args) { if (args.Parameters.Count != 1) { - args.Player.SendMessage("Invalid syntax! Proper syntax: /maxspawns ", Color.Red); - args.Player.SendMessage("Proper syntax: /maxspawns show", Color.Red); - args.Player.SendMessage("Proper syntax: /maxspawns default", Color.Red); + args.Player.SendErrorMessage("Invalid syntax! Proper syntax: /maxspawns "); + args.Player.SendErrorMessage("Proper syntax: /maxspawns show"); + args.Player.SendErrorMessage("Proper syntax: /maxspawns default"); return; } if (args.Parameters[0] == "show") { - args.Player.SendMessage("Current maximum spawns is: " + TShock.Config.DefaultMaximumSpawns); + args.Player.SendInfoMessage("Current maximum spawns is " + TShock.Config.DefaultMaximumSpawns + "."); return; } if(args.Parameters[0]=="default"){ TShock.Config.DefaultMaximumSpawns = 5; NPC.defaultMaxSpawns = 5; - TShock.Utils.Broadcast(string.Format("{0} changed the maximum spawns to: 5", args.Player.Name)); + TSPlayer.All.SendInfoMessage(string.Format("{0} changed the maximum spawns to 5.", args.Player.Name)); return; } @@ -2147,22 +2477,22 @@ namespace TShockAPI int.TryParse(args.Parameters[0], out amount); NPC.defaultMaxSpawns = amount; TShock.Config.DefaultMaximumSpawns = amount; - TShock.Utils.Broadcast(string.Format("{0} changed the maximum spawns to: {1}", args.Player.Name, amount)); + TSPlayer.All.SendInfoMessage(string.Format("{0} changed the maximum spawns to {1}.", args.Player.Name, amount)); } private static void SpawnRate(CommandArgs args) { if (args.Parameters.Count != 1) { - args.Player.SendMessage("Invalid syntax! Proper syntax: /spawnrate ", Color.Red); - args.Player.SendMessage("/spawnrate show", Color.Red); - args.Player.SendMessage("/spawnrate default", Color.Red); + args.Player.SendErrorMessage("Invalid syntax! Proper syntax: /spawnrate "); + args.Player.SendErrorMessage("/spawnrate show"); + args.Player.SendErrorMessage("/spawnrate default"); return; } if (args.Parameters[0] == "show") { - args.Player.SendMessage("Current spawn rate is: " + TShock.Config.DefaultSpawnRate); + args.Player.SendInfoMessage("Current spawn rate is " + TShock.Config.DefaultSpawnRate + "."); return; } @@ -2170,15 +2500,26 @@ namespace TShockAPI { TShock.Config.DefaultSpawnRate = 600; NPC.defaultSpawnRate = 600; - TShock.Utils.Broadcast(string.Format("{0} changed the spawn rate to: 600", args.Player.Name)); + TSPlayer.All.SendInfoMessage(string.Format("{0} changed the spawn rate to 600.", args.Player.Name)); + return; + } + + int amount = -1; + if (!int.TryParse(args.Parameters[0], out amount)) + { + args.Player.SendWarningMessage(string.Format("Invalid spawnrate ({0})", args.Parameters[0])); + return; + } + + if (amount < 0) + { + args.Player.SendWarningMessage("Spawnrate cannot be negative!"); return; } - int amount = Convert.ToInt32(args.Parameters[0]); - int.TryParse(args.Parameters[0], out amount); NPC.defaultSpawnRate = amount; TShock.Config.DefaultSpawnRate = amount; - TShock.Utils.Broadcast(string.Format("{0} changed the spawn rate to: {1}", args.Player.Name, amount)); + TSPlayer.All.SendInfoMessage(string.Format("{0} changed the spawn rate to {1}.", args.Player.Name, amount)); } #endregion Server Config Commands @@ -2189,7 +2530,7 @@ namespace TShockAPI { if (args.Parameters.Count != 1) { - args.Player.SendMessage("Invalid syntax! Proper syntax: /time ", Color.Red); + args.Player.SendErrorMessage("Invalid syntax! Proper syntax: /time "); return; } @@ -2197,40 +2538,42 @@ namespace TShockAPI { case "day": TSPlayer.Server.SetTime(true, 150.0); - TShock.Utils.Broadcast(string.Format("{0} set time to day.", args.Player.Name)); + TSPlayer.All.SendInfoMessage(string.Format("{0} set the time to day.", args.Player.Name)); break; case "night": TSPlayer.Server.SetTime(false, 0.0); - TShock.Utils.Broadcast(string.Format("{0} set time to night.", args.Player.Name)); + TSPlayer.All.SendInfoMessage(string.Format("{0} set the time to night.", args.Player.Name)); break; case "dusk": TSPlayer.Server.SetTime(false, 0.0); - TShock.Utils.Broadcast(string.Format("{0} set time to dusk.", args.Player.Name)); + TSPlayer.All.SendInfoMessage(string.Format("{0} set the time to dusk.", args.Player.Name)); break; case "noon": TSPlayer.Server.SetTime(true, 27000.0); - TShock.Utils.Broadcast(string.Format("{0} set time to noon.", args.Player.Name)); + TSPlayer.All.SendInfoMessage(string.Format("{0} set the time to noon.", args.Player.Name)); break; case "midnight": TSPlayer.Server.SetTime(false, 16200.0); - TShock.Utils.Broadcast(string.Format("{0} set time to midnight.", args.Player.Name)); + TSPlayer.All.SendInfoMessage(string.Format("{0} set the time to midnight.", args.Player.Name)); break; default: - args.Player.SendMessage("Invalid syntax! Proper syntax: /time ", Color.Red); + args.Player.SendErrorMessage("Invalid syntax! Proper syntax: /time "); break; } } + //TODO: Come back here + private static void Slap(CommandArgs args) { if (args.Parameters.Count < 1 || args.Parameters.Count > 2) { - args.Player.SendMessage("Invalid syntax! Proper syntax: /slap [dmg]", Color.Red); + args.Player.SendErrorMessage("Invalid syntax! Proper syntax: /slap [dmg]"); return; } if (args.Parameters[0].Length == 0) { - args.Player.SendMessage("Missing player name", Color.Red); + args.Player.SendErrorMessage("Missing player name."); return; } @@ -2238,11 +2581,11 @@ namespace TShockAPI var players = TShock.Utils.FindPlayer(plStr); if (players.Count == 0) { - args.Player.SendMessage("Invalid player!", Color.Red); + args.Player.SendErrorMessage("Invalid player!"); } else if (players.Count > 1) { - args.Player.SendMessage("More than one player matched!", Color.Red); + args.Player.SendErrorMessage("More than one player matched!"); } else { @@ -2257,475 +2600,571 @@ namespace TShockAPI damage = TShock.Utils.Clamp(damage, 15, 0); } plr.DamagePlayer(damage); - TShock.Utils.Broadcast(string.Format("{0} slapped {1} for {2} damage.", + TSPlayer.All.SendSuccessMessage(string.Format("{0} slapped {1} for {2} damage.", args.Player.Name, plr.Name, damage)); - Log.Info(args.Player.Name + " slapped " + plr.Name + " with " + damage + " damage."); + Log.Info(args.Player.Name + " slapped " + plr.Name + " for " + damage + " damage."); } } #endregion Time/PvpFun Commands - #region World Protection Commands + #region Region Commands - private static void ToggleAntiBuild(CommandArgs args) + private static void DebugRegions(CommandArgs args) + { + foreach (Region r in TShock.Regions.Regions) + { + args.Player.SendMessage(r.Name + ": P: " + r.DisableBuild + " X: " + r.Area.X + " Y: " + r.Area.Y + " W: " + + r.Area.Width + " H: " + r.Area.Height); + foreach (int s in r.AllowedIDs) + { + args.Player.SendMessage(r.Name + ": " + s); + } + } + } + + private static void Region(CommandArgs args) + { + string cmd = "help"; + if (args.Parameters.Count > 0) + { + cmd = args.Parameters[0].ToLower(); + } + switch (cmd) + { + case "name": + { + { + args.Player.SendMessage("Hit a block to get the name of the region", Color.Yellow); + args.Player.AwaitingName = true; + args.Player.AwaitingNameParameters = args.Parameters.Skip(1).ToArray(); + } + break; + } + case "set": + { + int choice = 0; + if (args.Parameters.Count == 2 && + int.TryParse(args.Parameters[1], out choice) && + choice >= 1 && choice <= 2) + { + args.Player.SendMessage("Hit a block to Set Point " + choice, Color.Yellow); + args.Player.AwaitingTempPoint = choice; + } + else + { + args.Player.SendMessage("Invalid syntax! Proper syntax: /region set <1/2>", Color.Red); + } + break; + } + case "define": + { + if (args.Parameters.Count > 1) + { + if (!args.Player.TempPoints.Any(p => p == Point.Zero)) + { + string regionName = String.Join(" ", args.Parameters.GetRange(1, args.Parameters.Count - 1)); + var x = Math.Min(args.Player.TempPoints[0].X, args.Player.TempPoints[1].X); + var y = Math.Min(args.Player.TempPoints[0].Y, args.Player.TempPoints[1].Y); + var width = Math.Abs(args.Player.TempPoints[0].X - args.Player.TempPoints[1].X); + var height = Math.Abs(args.Player.TempPoints[0].Y - args.Player.TempPoints[1].Y); + + if (TShock.Regions.AddRegion(x, y, width, height, regionName, args.Player.UserAccountName, + Main.worldID.ToString())) + { + args.Player.TempPoints[0] = Point.Zero; + args.Player.TempPoints[1] = Point.Zero; + args.Player.SendMessage("Set region " + regionName, Color.Yellow); + } + else + { + args.Player.SendMessage("Region " + regionName + " already exists", Color.Red); + } + } + else + { + args.Player.SendMessage("Points not set up yet", Color.Red); + } + } + else + args.Player.SendMessage("Invalid syntax! Proper syntax: /region define ", Color.Red); + break; + } + case "protect": + { + if (args.Parameters.Count == 3) + { + string regionName = args.Parameters[1]; + if (args.Parameters[2].ToLower() == "true") + { + if (TShock.Regions.SetRegionState(regionName, true)) + args.Player.SendMessage("Protected region " + regionName, Color.Yellow); + else + args.Player.SendMessage("Could not find specified region", Color.Red); + } + else if (args.Parameters[2].ToLower() == "false") + { + if (TShock.Regions.SetRegionState(regionName, false)) + args.Player.SendMessage("Unprotected region " + regionName, Color.Yellow); + else + args.Player.SendMessage("Could not find specified region", Color.Red); + } + else + args.Player.SendMessage("Invalid syntax! Proper syntax: /region protect ", Color.Red); + } + else + args.Player.SendMessage("Invalid syntax! Proper syntax: /region protect ", Color.Red); + break; + } + case "delete": + { + if (args.Parameters.Count > 1) + { + string regionName = String.Join(" ", args.Parameters.GetRange(1, args.Parameters.Count - 1)); + if (TShock.Regions.DeleteRegion(regionName)) + args.Player.SendMessage("Deleted region " + regionName, Color.Yellow); + else + args.Player.SendMessage("Could not find specified region", Color.Red); + } + else + args.Player.SendMessage("Invalid syntax! Proper syntax: /region delete ", Color.Red); + break; + } + case "clear": + { + args.Player.TempPoints[0] = Point.Zero; + args.Player.TempPoints[1] = Point.Zero; + args.Player.SendMessage("Cleared temp area", Color.Yellow); + args.Player.AwaitingTempPoint = 0; + break; + } + case "allow": + { + if (args.Parameters.Count > 2) + { + string playerName = args.Parameters[1]; + string regionName = ""; + + for (int i = 2; i < args.Parameters.Count; i++) + { + if (regionName == "") + { + regionName = args.Parameters[2]; + } + else + { + regionName = regionName + " " + args.Parameters[i]; + } + } + if (TShock.Users.GetUserByName(playerName) != null) + { + if (TShock.Regions.AddNewUser(regionName, playerName)) + { + args.Player.SendMessage("Added user " + playerName + " to " + regionName, Color.Yellow); + } + else + args.Player.SendMessage("Region " + regionName + " not found", Color.Red); + } + else + { + args.Player.SendMessage("Player " + playerName + " not found", Color.Red); + } + } + else + args.Player.SendMessage("Invalid syntax! Proper syntax: /region allow ", Color.Red); + break; + } + case "remove": + if (args.Parameters.Count > 2) + { + string playerName = args.Parameters[1]; + string regionName = ""; + + for (int i = 2; i < args.Parameters.Count; i++) + { + if (regionName == "") + { + regionName = args.Parameters[2]; + } + else + { + regionName = regionName + " " + args.Parameters[i]; + } + } + if (TShock.Users.GetUserByName(playerName) != null) + { + if (TShock.Regions.RemoveUser(regionName, playerName)) + { + args.Player.SendMessage("Removed user " + playerName + " from " + regionName, Color.Yellow); + } + else + args.Player.SendMessage("Region " + regionName + " not found", Color.Red); + } + else + { + args.Player.SendMessage("Player " + playerName + " not found", Color.Red); + } + } + else + args.Player.SendMessage("Invalid syntax! Proper syntax: /region remove ", Color.Red); + break; + case "allowg": + { + if (args.Parameters.Count > 2) + { + string group = args.Parameters[1]; + string regionName = ""; + + for (int i = 2; i < args.Parameters.Count; i++) + { + if (regionName == "") + { + regionName = args.Parameters[2]; + } + else + { + regionName = regionName + " " + args.Parameters[i]; + } + } + if (TShock.Groups.GroupExists(group)) + { + if (TShock.Regions.AllowGroup(regionName, group)) + { + args.Player.SendMessage("Added group " + group + " to " + regionName, Color.Yellow); + } + else + args.Player.SendMessage("Region " + regionName + " not found", Color.Red); + } + else + { + args.Player.SendMessage("Group " + group + " not found", Color.Red); + } + } + else + args.Player.SendMessage("Invalid syntax! Proper syntax: /region allowg ", Color.Red); + break; + } + case "removeg": + if (args.Parameters.Count > 2) + { + string group = args.Parameters[1]; + string regionName = ""; + + for (int i = 2; i < args.Parameters.Count; i++) + { + if (regionName == "") + { + regionName = args.Parameters[2]; + } + else + { + regionName = regionName + " " + args.Parameters[i]; + } + } + if (TShock.Groups.GroupExists(group)) + { + if (TShock.Regions.RemoveGroup(regionName, group)) + { + args.Player.SendMessage("Removed group " + group + " from " + regionName, Color.Yellow); + } + else + args.Player.SendMessage("Region " + regionName + " not found", Color.Red); + } + else + { + args.Player.SendMessage("Group " + group + " not found", Color.Red); + } + } + else + args.Player.SendMessage("Invalid syntax! Proper syntax: /region removeg ", Color.Red); + break; + case "list": + { + int pageNumber; + if (!PaginationTools.TryParsePageNumber(args.Parameters, 1, args.Player, out pageNumber)) + return; + + IEnumerable regionNames = from region in TShock.Regions.Regions + where region.WorldID == Main.worldID.ToString() + select region.Name; + PaginationTools.SendPage(args.Player, pageNumber, PaginationTools.BuildLinesFromTerms(regionNames), + new PaginationTools.Settings + { + HeaderFormat = "Regions ({0}/{1}):", + FooterFormat = "Type /region list {0} for more.", + NothingToDisplayString = "There are currently no regions defined." + }); + break; + } + case "info": + { + if (args.Parameters.Count == 1 || args.Parameters.Count > 4) + { + args.Player.SendErrorMessage("Invalid syntax! Proper syntax: /region info [-d] [page]"); + break; + } + + string regionName = args.Parameters[1]; + bool displayBoundaries = args.Parameters.Skip(2).Any( + p => p.Equals("-d", StringComparison.InvariantCultureIgnoreCase) + ); + + Region region = TShock.Regions.GetRegionByName(regionName); + if (region == null) + { + args.Player.SendErrorMessage("Region \"{0}\" does not exist.", regionName); + break; + } + + int pageNumberIndex = displayBoundaries ? 3 : 2; + int pageNumber; + if (!PaginationTools.TryParsePageNumber(args.Parameters, pageNumberIndex, args.Player, out pageNumber)) + break; + + List lines = new List + { + string.Format("X: {0}; Y: {1}; W: {2}; H: {3}, Z: {4}", region.Area.X, region.Area.Y, region.Area.Width, region.Area.Height, region.Z), + string.Concat("Owner: ", region.Owner), + string.Concat("Protected: ", region.DisableBuild.ToString()), + }; + + if (region.AllowedIDs.Count > 0) + { + IEnumerable sharedUsersSelector = region.AllowedIDs.Select(userId => + { + User user = TShock.Users.GetUserByID(userId); + if (user != null) + return user.Name; + else + return string.Concat("{ID: ", userId, "}"); + }); + List extraLines = PaginationTools.BuildLinesFromTerms(sharedUsersSelector.Distinct()); + extraLines[0] = "Shared with: " + extraLines[0]; + lines.AddRange(extraLines); + } + else + { + lines.Add("Region is not shared with any users."); + } + + if (region.AllowedGroups.Count > 0) + { + List extraLines = PaginationTools.BuildLinesFromTerms(region.AllowedGroups.Distinct()); + extraLines[0] = "Shared with groups: " + extraLines[0]; + lines.AddRange(extraLines); + } + else + { + lines.Add("Region is not shared with any groups."); + } + + PaginationTools.SendPage( + args.Player, pageNumber, lines, new PaginationTools.Settings + { + HeaderFormat = string.Format("Information About Region \"{0}\" ({{0}}/{{1}}):", region.Name), + FooterFormat = string.Format("Type /region info {0} {{0}} for more information.", regionName) + } + ); + + if (displayBoundaries) + { + Rectangle regionArea = region.Area; + foreach (Point boundaryPoint in Utils.Instance.EnumerateRegionBoundaries(regionArea)) + { + // Preferring dotted lines as those should easily be distinguishable from actual wires. + if ((boundaryPoint.X + boundaryPoint.Y & 1) == 0) + { + // Could be improved by sending raw tile data to the client instead but not really + // worth the effort as chances are very low that overwriting the wire for a few + // nanoseconds will cause much trouble. + Tile tile = Main.tile[boundaryPoint.X, boundaryPoint.Y]; + bool oldWireState = tile.wire; + tile.wire = true; + + try { + args.Player.SendTileSquare(boundaryPoint.X, boundaryPoint.Y, 1); + } finally { + tile.wire = oldWireState; + } + } + } + + Timer boundaryHideTimer = null; + boundaryHideTimer = new Timer((state) => { + foreach (Point boundaryPoint in Utils.Instance.EnumerateRegionBoundaries(regionArea)) + if ((boundaryPoint.X + boundaryPoint.Y & 1) == 0) + args.Player.SendTileSquare(boundaryPoint.X, boundaryPoint.Y, 1); + + // ReSharper disable AccessToModifiedClosure + Debug.Assert(boundaryHideTimer != null); + boundaryHideTimer.Dispose(); + // ReSharper restore AccessToModifiedClosure + }, + null, 5000, Timeout.Infinite + ); + } + + break; + } + case "z": + { + if (args.Parameters.Count == 3) + { + string regionName = args.Parameters[1]; + int z = 0; + if (int.TryParse(args.Parameters[2], out z)) + { + if (TShock.Regions.SetZ(regionName, z)) + args.Player.SendMessage("Region's z is now " + z, Color.Yellow); + else + args.Player.SendMessage("Could not find specified region", Color.Red); + } + else + args.Player.SendMessage("Invalid syntax! Proper syntax: /region z <#>", Color.Red); + } + else + args.Player.SendMessage("Invalid syntax! Proper syntax: /region z <#>", Color.Red); + break; + } + case "resize": + case "expand": + { + if (args.Parameters.Count == 4) + { + int direction; + switch (args.Parameters[2]) + { + case "u": + case "up": + { + direction = 0; + break; + } + case "r": + case "right": + { + direction = 1; + break; + } + case "d": + case "down": + { + direction = 2; + break; + } + case "l": + case "left": + { + direction = 3; + break; + } + default: + { + direction = -1; + break; + } + } + int addAmount; + int.TryParse(args.Parameters[3], out addAmount); + if (TShock.Regions.resizeRegion(args.Parameters[1], addAmount, direction)) + { + args.Player.SendMessage("Region Resized Successfully!", Color.Yellow); + TShock.Regions.ReloadAllRegions(); + } + else + { + args.Player.SendMessage("Invalid syntax! Proper syntax: /region resize ", + Color.Red); + } + } + else + { + args.Player.SendMessage("Invalid syntax! Proper syntax: /region resize ", + Color.Red); + } + break; + } + case "tp": + { + if (!args.Player.Group.HasPermission(Permissions.tp)) + { + args.Player.SendErrorMessage("You don't have the necessary permission to do that."); + break; + } + if (args.Parameters.Count <= 1) + { + args.Player.SendErrorMessage("Invalid syntax! Proper syntax: /region tp ."); + break; + } + + string regionName = string.Join(" ", args.Parameters.Skip(1)); + Region region = TShock.Regions.GetRegionByName(regionName); + if (region == null) + { + args.Player.SendErrorMessage("Region \"{0}\" does not exist.", regionName); + break; + } + + args.Player.Teleport(region.Area.Center.X, region.Area.Center.Y + 3); + + break; + } + case "help": + default: + { + int pageNumber; + int pageParamIndex = 0; + if (args.Parameters.Count > 1) + pageParamIndex = 1; + if (!PaginationTools.TryParsePageNumber(args.Parameters, pageParamIndex, args.Player, out pageNumber)) + return; + + List lines = new List { + "set <1/2> - Sets the temporary region points.", + "clear - Clears the temporary region points.", + "define - Defines the region with the given name.", + "delete - Deletes the given region.", + "name [-u][-z][-p] - Shows the name of the region at the given point.", + "list - Lists all regions.", + "resize - Resizes a region.", + "allow - Allows a user to a region.", + "remove - Removes a user from a region.", + "allowg - Allows a user group to a region.", + "removeg - Removes a user group from a region.", + "info [-d] - Displays several information about the given region.", + "protect - Sets whether the tiles inside the region are protected or not.", + "z <#> - Sets the z-order of the region.", + }; + if (args.Player.Group.HasPermission(Permissions.tp)) + lines.Add("tp - Teleports you to the given region's center."); + + PaginationTools.SendPage( + args.Player, pageNumber, lines, + new PaginationTools.Settings + { + HeaderFormat = "Available Region Sub-Commands ({0}/{1}):", + FooterFormat = "Type /region {0} for more sub-commands." + } + ); + break; + } + } + } + + #endregion Region Commands + + #region World Protection Commands + + private static void ToggleAntiBuild(CommandArgs args) { TShock.Config.DisableBuild = (TShock.Config.DisableBuild == false); - TShock.Utils.Broadcast(string.Format("Anti-build is now {0}.", (TShock.Config.DisableBuild ? "on" : "off"))); + TSPlayer.All.SendSuccessMessage(string.Format("Anti-build is now {0}.", (TShock.Config.DisableBuild ? "on" : "off"))); } private static void ProtectSpawn(CommandArgs args) { TShock.Config.SpawnProtection = (TShock.Config.SpawnProtection == false); - TShock.Utils.Broadcast(string.Format("Spawn is now {0}.", (TShock.Config.SpawnProtection ? "protected" : "open"))); - } - - private static void DebugRegions(CommandArgs args) - { - foreach (Region r in TShock.Regions.Regions) - { - args.Player.SendMessage(r.Name + ": P: " + r.DisableBuild + " X: " + r.Area.X + " Y: " + r.Area.Y + " W: " + - r.Area.Width + " H: " + r.Area.Height); - foreach (int s in r.AllowedIDs) - { - args.Player.SendMessage(r.Name + ": " + s); - } - } - } - - private static void Region(CommandArgs args) - { - string cmd = "help"; - if (args.Parameters.Count > 0) - { - cmd = args.Parameters[0].ToLower(); - } - switch (cmd) - { - case "name": - { - { - args.Player.SendMessage("Hit a block to get the name of the region", Color.Yellow); - args.Player.AwaitingName = true; - } - break; - } - case "set": - { - int choice = 0; - if (args.Parameters.Count == 2 && - int.TryParse(args.Parameters[1], out choice) && - choice >= 1 && choice <= 2) - { - args.Player.SendMessage("Hit a block to Set Point " + choice, Color.Yellow); - args.Player.AwaitingTempPoint = choice; - } - else - { - args.Player.SendMessage("Invalid syntax! Proper syntax: /region set [1/2]", Color.Red); - } - break; - } - case "define": - { - if (args.Parameters.Count > 1) - { - if (!args.Player.TempPoints.Any(p => p == Point.Zero)) - { - string regionName = String.Join(" ", args.Parameters.GetRange(1, args.Parameters.Count - 1)); - var x = Math.Min(args.Player.TempPoints[0].X, args.Player.TempPoints[1].X); - var y = Math.Min(args.Player.TempPoints[0].Y, args.Player.TempPoints[1].Y); - var width = Math.Abs(args.Player.TempPoints[0].X - args.Player.TempPoints[1].X); - var height = Math.Abs(args.Player.TempPoints[0].Y - args.Player.TempPoints[1].Y); - - if (TShock.Regions.AddRegion(x, y, width, height, regionName, args.Player.UserAccountName, - Main.worldID.ToString())) - { - args.Player.TempPoints[0] = Point.Zero; - args.Player.TempPoints[1] = Point.Zero; - args.Player.SendMessage("Set region " + regionName, Color.Yellow); - } - else - { - args.Player.SendMessage("Region " + regionName + " already exists", Color.Red); - } - } - else - { - args.Player.SendMessage("Points not set up yet", Color.Red); - } - } - else - args.Player.SendMessage("Invalid syntax! Proper syntax: /region define [name]", Color.Red); - break; - } - case "protect": - { - if (args.Parameters.Count == 3) - { - string regionName = args.Parameters[1]; - if (args.Parameters[2].ToLower() == "true") - { - if (TShock.Regions.SetRegionState(regionName, true)) - args.Player.SendMessage("Protected region " + regionName, Color.Yellow); - else - args.Player.SendMessage("Could not find specified region", Color.Red); - } - else if (args.Parameters[2].ToLower() == "false") - { - if (TShock.Regions.SetRegionState(regionName, false)) - args.Player.SendMessage("Unprotected region " + regionName, Color.Yellow); - else - args.Player.SendMessage("Could not find specified region", Color.Red); - } - else - args.Player.SendMessage("Invalid syntax! Proper syntax: /region protect [name] [true/false]", Color.Red); - } - else - args.Player.SendMessage("Invalid syntax! Proper syntax: /region protect [name] [true/false]", Color.Red); - break; - } - case "delete": - { - if (args.Parameters.Count > 1) - { - string regionName = String.Join(" ", args.Parameters.GetRange(1, args.Parameters.Count - 1)); - if (TShock.Regions.DeleteRegion(regionName)) - args.Player.SendMessage("Deleted region " + regionName, Color.Yellow); - else - args.Player.SendMessage("Could not find specified region", Color.Red); - } - else - args.Player.SendMessage("Invalid syntax! Proper syntax: /region delete [name]", Color.Red); - break; - } - case "clear": - { - args.Player.TempPoints[0] = Point.Zero; - args.Player.TempPoints[1] = Point.Zero; - args.Player.SendMessage("Cleared temp area", Color.Yellow); - args.Player.AwaitingTempPoint = 0; - break; - } - case "allow": - { - if (args.Parameters.Count > 2) - { - string playerName = args.Parameters[1]; - string regionName = ""; - - for (int i = 2; i < args.Parameters.Count; i++) - { - if (regionName == "") - { - regionName = args.Parameters[2]; - } - else - { - regionName = regionName + " " + args.Parameters[i]; - } - } - if (TShock.Users.GetUserByName(playerName) != null) - { - if (TShock.Regions.AddNewUser(regionName, playerName)) - { - args.Player.SendMessage("Added user " + playerName + " to " + regionName, Color.Yellow); - } - else - args.Player.SendMessage("Region " + regionName + " not found", Color.Red); - } - else - { - args.Player.SendMessage("Player " + playerName + " not found", Color.Red); - } - } - else - args.Player.SendMessage("Invalid syntax! Proper syntax: /region allow [name] [region]", Color.Red); - break; - } - case "remove": - if (args.Parameters.Count > 2) - { - string playerName = args.Parameters[1]; - string regionName = ""; - - for (int i = 2; i < args.Parameters.Count; i++) - { - if (regionName == "") - { - regionName = args.Parameters[2]; - } - else - { - regionName = regionName + " " + args.Parameters[i]; - } - } - if (TShock.Users.GetUserByName(playerName) != null) - { - if (TShock.Regions.RemoveUser(regionName, playerName)) - { - args.Player.SendMessage("Removed user " + playerName + " from " + regionName, Color.Yellow); - } - else - args.Player.SendMessage("Region " + regionName + " not found", Color.Red); - } - else - { - args.Player.SendMessage("Player " + playerName + " not found", Color.Red); - } - } - else - args.Player.SendMessage("Invalid syntax! Proper syntax: /region remove [name] [region]", Color.Red); - break; - case "allowg": - { - if (args.Parameters.Count > 2) - { - string group = args.Parameters[1]; - string regionName = ""; - - for (int i = 2; i < args.Parameters.Count; i++) - { - if (regionName == "") - { - regionName = args.Parameters[2]; - } - else - { - regionName = regionName + " " + args.Parameters[i]; - } - } - if (TShock.Groups.GroupExists(group)) - { - if (TShock.Regions.AllowGroup(regionName, group)) - { - args.Player.SendMessage("Added group " + group + " to " + regionName, Color.Yellow); - } - else - args.Player.SendMessage("Region " + regionName + " not found", Color.Red); - } - else - { - args.Player.SendMessage("Group " + group + " not found", Color.Red); - } - } - else - args.Player.SendMessage("Invalid syntax! Proper syntax: /region allow [group] [region]", Color.Red); - break; - } - case "removeg": - if (args.Parameters.Count > 2) - { - string group = args.Parameters[1]; - string regionName = ""; - - for (int i = 2; i < args.Parameters.Count; i++) - { - if (regionName == "") - { - regionName = args.Parameters[2]; - } - else - { - regionName = regionName + " " + args.Parameters[i]; - } - } - if (TShock.Groups.GroupExists(group)) - { - if (TShock.Regions.RemoveGroup(regionName, group)) - { - args.Player.SendMessage("Removed group " + group + " from " + regionName, Color.Yellow); - } - else - args.Player.SendMessage("Region " + regionName + " not found", Color.Red); - } - else - { - args.Player.SendMessage("Group " + group + " not found", Color.Red); - } - } - else - args.Player.SendMessage("Invalid syntax! Proper syntax: /region removeg [group] [region]", Color.Red); - break; - case "list": - { - //How many regions per page - const int pagelimit = 15; - //How many regions per line - const int perline = 5; - //Pages start at 0 but are displayed and parsed at 1 - int page = 0; - - - if (args.Parameters.Count > 1) - { - if (!int.TryParse(args.Parameters[1], out page) || page < 1) - { - args.Player.SendMessage(string.Format("Invalid page number ({0})", page), Color.Red); - return; - } - page--; //Substract 1 as pages are parsed starting at 1 and not 0 - } - - var regions = TShock.Regions.ListAllRegions(Main.worldID.ToString()); - - // Are there even any regions to display? - if (regions.Count == 0) - { - args.Player.SendMessage("There are currently no regions defined.", Color.Red); - return; - } - - //Check if they are trying to access a page that doesn't exist. - int pagecount = regions.Count/pagelimit; - if (page > pagecount) - { - args.Player.SendMessage(string.Format("Page number exceeds pages ({0}/{1})", page + 1, pagecount + 1), Color.Red); - return; - } - - //Display the current page and the number of pages. - args.Player.SendMessage(string.Format("Current Regions ({0}/{1}):", page + 1, pagecount + 1), Color.Green); - - //Add up to pagelimit names to a list - var nameslist = new List(); - for (int i = (page*pagelimit); (i < ((page*pagelimit) + pagelimit)) && i < regions.Count; i++) - { - nameslist.Add(regions[i].Name); - } - - //convert the list to an array for joining - var names = nameslist.ToArray(); - for (int i = 0; i < names.Length; i += perline) - { - args.Player.SendMessage(string.Join(", ", names, i, Math.Min(names.Length - i, perline)), Color.Yellow); - } - - if (page < pagecount) - { - args.Player.SendMessage(string.Format("Type /region list {0} for more regions.", (page + 2)), Color.Yellow); - } - - break; - } - case "info": - { - if (args.Parameters.Count > 1) - { - string regionName = String.Join(" ", args.Parameters.GetRange(1, args.Parameters.Count - 1)); - Region r = TShock.Regions.GetRegionByName(regionName); - - if (r == null) - { - args.Player.SendMessage("Region {0} does not exist"); - break; - } - - args.Player.SendMessage(r.Name + ": P: " + r.DisableBuild + " X: " + r.Area.X + " Y: " + r.Area.Y + " W: " + - r.Area.Width + " H: " + r.Area.Height); - foreach (int s in r.AllowedIDs) - { - var user = TShock.Users.GetUserByID(s); - args.Player.SendMessage(r.Name + ": " + (user != null ? user.Name : "Unknown")); - } - } - else - { - args.Player.SendMessage("Invalid syntax! Proper syntax: /region info [name]", Color.Red); - } - - break; - } - case "z": - { - if (args.Parameters.Count == 3) - { - string regionName = args.Parameters[1]; - int z = 0; - if (int.TryParse(args.Parameters[2], out z ) ) - { - if (TShock.Regions.SetZ(regionName, z)) - args.Player.SendMessage("Region's z is now " + z, Color.Yellow); - else - args.Player.SendMessage("Could not find specified region", Color.Red); - } - else - args.Player.SendMessage("Invalid syntax! Proper syntax: /region z [name] [#]", Color.Red); - } - else - args.Player.SendMessage("Invalid syntax! Proper syntax: /region z [name] [#]", Color.Red); - break; - } - case "resize": - case "expand": - { - if (args.Parameters.Count == 4) - { - int direction; - switch (args.Parameters[2]) - { - case "u": - case "up": - { - direction = 0; - break; - } - case "r": - case "right": - { - direction = 1; - break; - } - case "d": - case "down": - { - direction = 2; - break; - } - case "l": - case "left": - { - direction = 3; - break; - } - default: - { - direction = -1; - break; - } - } - int addAmount; - int.TryParse(args.Parameters[3], out addAmount); - if (TShock.Regions.resizeRegion(args.Parameters[1], addAmount, direction)) - { - args.Player.SendMessage("Region Resized Successfully!", Color.Yellow); - TShock.Regions.ReloadAllRegions(); - } - else - { - args.Player.SendMessage("Invalid syntax! Proper syntax: /region resize [regionname] [u/d/l/r] [amount]", - Color.Red); - } - } - else - { - args.Player.SendMessage("Invalid syntax! Proper syntax: /region resize [regionname] [u/d/l/r] [amount]1", - Color.Red); - } - break; - } - case "help": - default: - { - args.Player.SendMessage("Avialable region commands:", Color.Green); - args.Player.SendMessage("/region set [1/2] /region define [name] /region protect [name] [true/false]", - Color.Yellow); - args.Player.SendMessage("/region name (provides region name)", Color.Yellow); - args.Player.SendMessage("/region delete [name] /region clear (temporary region)", Color.Yellow); - args.Player.SendMessage("/region allow [name] [regionname]", Color.Yellow); - args.Player.SendMessage("/region resize [regionname] [u/d/l/r] [amount]", Color.Yellow); - break; - } - } + TSPlayer.All.SendSuccessMessage(string.Format("Spawn is now {0}.", (TShock.Config.SpawnProtection ? "protected" : "open"))); } #endregion World Protection Commands @@ -2734,112 +3173,76 @@ namespace TShockAPI private static void Help(CommandArgs args) { - args.Player.SendMessage("TShock Commands:"); - int page = 1; - if (args.Parameters.Count > 0) - int.TryParse(args.Parameters[0], out page); - var cmdlist = new List(); - for (int j = 0; j < ChatCommands.Count; j++) - { - if (ChatCommands[j].CanRun(args.Player)) + int pageNumber; + if (!PaginationTools.TryParsePageNumber(args.Parameters, 0, args.Player, out pageNumber)) + return; + IEnumerable cmdNames = from cmd in ChatCommands + where cmd.CanRun(args.Player) && (cmd.Name != "auth" || TShock.AuthToken != 0) + select "/" + cmd.Name; + PaginationTools.SendPage(args.Player, pageNumber, PaginationTools.BuildLinesFromTerms(cmdNames), + new PaginationTools.Settings { - cmdlist.Add(ChatCommands[j]); - } - } - var sb = new StringBuilder(); - if (cmdlist.Count > (15*(page - 1))) - { - for (int j = (15*(page - 1)); j < (15*page); j++) - { - if (sb.Length != 0) - sb.Append(", "); - sb.Append("/").Append(cmdlist[j].Name); - if (j == cmdlist.Count - 1) - { - args.Player.SendMessage(sb.ToString(), Color.Yellow); - break; - } - if ((j + 1)%5 == 0) - { - args.Player.SendMessage(sb.ToString(), Color.Yellow); - sb.Clear(); - } - } - } - if (cmdlist.Count > (15*page)) - { - args.Player.SendMessage(string.Format("Type /help {0} for more commands.", (page + 1)), Color.Yellow); - } + HeaderFormat = "Commands ({0}/{1}):", + FooterFormat = "Type /help {0} for more." + }); } - private static void GetVersion(CommandArgs args) - { - args.Player.SendMessage(string.Format("TShock: {0} ({1}): ({2}/{3})", TShock.VersionNum, TShock.VersionCodename, - TShock.Utils.ActivePlayers(), TShock.Config.MaxSlots)); - } + private static void GetVersion(CommandArgs args) + { + args.Player.SendInfoMessage(string.Format("TShock: {0} ({1}): ({2}/{3})", TShock.VersionNum, TShock.VersionCodename, + TShock.Utils.ActivePlayers(), TShock.Config.MaxSlots)); + } - private static void ListConnectedPlayers(CommandArgs args) - { - //How many players per page - const int pagelimit = 15; - //How many players per line - const int perline = 5; - //Pages start at 0 but are displayed and parsed at 1 - int page = 0; + private static void ListConnectedPlayers(CommandArgs args) + { + bool invalidUsage = (args.Parameters.Count > 2); + bool displayIdsRequested = false; + int pageNumber = 1; + if (!invalidUsage) + { + foreach (string parameter in args.Parameters) + { + if (parameter.Equals("-i", StringComparison.InvariantCultureIgnoreCase)) + { + displayIdsRequested = true; + continue; + } - if (args.Parameters.Count > 0) - { - if (!int.TryParse(args.Parameters[0], out page) || page < 1) - { - args.Player.SendMessage(string.Format("Invalid page number ({0})", page), Color.Red); - return; - } - page--; //Substract 1 as pages are parsed starting at 1 and not 0 - } + if (!int.TryParse(parameter, out pageNumber)) + { + invalidUsage = true; + break; + } + } + } + if (invalidUsage) + { + args.Player.SendErrorMessage("Invalid usage, proper usage: /who [-i] [pagenumber]"); + return; + } + if (displayIdsRequested && !args.Player.Group.HasPermission(Permissions.seeids)) + { + args.Player.SendErrorMessage("You don't have the required permission to list player ids."); + return; + } - var playerList = args.Player.Group.HasPermission(Permissions.seeids) - ? TShock.Utils.GetPlayers(true) - : TShock.Utils.GetPlayers(false); - - //Check if they are trying to access a page that doesn't exist. - int pagecount = playerList.Count / pagelimit; - if (page > pagecount) - { - args.Player.SendMessage(string.Format("Page number exceeds pages ({0}/{1})", page + 1, pagecount + 1), Color.Red); - return; - } - - //Display the current page and the number of pages. - args.Player.SendMessage(string.Format("Players: {0}/{1}", - TShock.Utils.ActivePlayers(), TShock.Config.MaxSlots)); - args.Player.SendMessage(string.Format("Current players page {0}/{1}:", page + 1, pagecount + 1), Color.Green); - - //Add up to pagelimit names to a list - var nameslist = new List(); - for (int i = (page * pagelimit); (i < ((page * pagelimit) + pagelimit)) && i < playerList.Count; i++) - { - nameslist.Add(playerList[i]); - } - - //convert the list to an array for joining - var names = nameslist.ToArray(); - for (int i = 0; i < names.Length; i += perline) - { - args.Player.SendMessage(string.Join(", ", names, i, Math.Min(names.Length - i, perline)), Color.Yellow); - } - - if (page < pagecount) - { - args.Player.SendMessage(string.Format("Type /who {0} for more players.", (page + 2)), Color.Yellow); - } - } + args.Player.SendSuccessMessage("Online Players ({0}/{1})", TShock.Utils.ActivePlayers(), TShock.Config.MaxSlots); + PaginationTools.SendPage( + args.Player, pageNumber, PaginationTools.BuildLinesFromTerms(TShock.Utils.GetPlayers(displayIdsRequested)), + new PaginationTools.Settings + { + IncludeHeader = false, + FooterFormat = string.Format("Type /who {0}{{0}} for more.", displayIdsRequested ? "-i " : string.Empty) + } + ); + } private static void AuthToken(CommandArgs args) { if (TShock.AuthToken == 0) { - args.Player.SendMessage("Auth is disabled. This incident has been logged.", Color.Red); + args.Player.SendWarningMessage("Auth is disabled. This incident has been logged."); Log.Warn(args.Player.IP + " attempted to use /auth even though it's disabled."); return; } @@ -2850,32 +3253,32 @@ namespace TShockAPI { TShock.Users.AddUser(new User(args.Player.IP, "", "", "superadmin")); args.Player.Group = TShock.Utils.GetGroup("superadmin"); - args.Player.SendMessage("This IP address is now superadmin. Please perform the following command:"); - args.Player.SendMessage("/user add : superadmin"); - args.Player.SendMessage("Creates: with the password as part of the superadmin group."); - args.Player.SendMessage("Please use /login to login from now on."); - args.Player.SendMessage("If you understand, please /login now, and type /auth-verify"); + args.Player.SendInfoMessage("This IP address is now superadmin. Please perform the following command:"); + args.Player.SendInfoMessage("/user add : superadmin"); + args.Player.SendInfoMessage("Creates: with the password as part of the superadmin group."); + args.Player.SendInfoMessage("Please use /login to login from now on."); + args.Player.SendInfoMessage("If you understand, please /login now, and type /auth-verify."); } catch (UserManagerException ex) { Log.ConsoleError(ex.ToString()); - args.Player.SendMessage(ex.Message); + args.Player.SendErrorMessage(ex.Message); } return; } if (args.Player.Group.Name == "superadmin") { - args.Player.SendMessage("Please disable the auth system! If you need help, consult the forums. http://tshock.co/"); - args.Player.SendMessage("This IP address is now superadmin. Please perform the following command:"); - args.Player.SendMessage("/user add : superadmin"); - args.Player.SendMessage("Creates: with the password as part of the superadmin group."); - args.Player.SendMessage("Please use /login to login from now on."); - args.Player.SendMessage("If you understand, please /login now, and type /auth-verify"); + args.Player.SendInfoMessage("Please disable the auth system! If you need help, consult the forums. http://tshock.co/"); + args.Player.SendInfoMessage("This IP address is now superadmin. Please perform the following command:"); + args.Player.SendInfoMessage("/user add : superadmin"); + args.Player.SendInfoMessage("Creates: with the password as part of the superadmin group."); + args.Player.SendInfoMessage("Please use /login to login from now on."); + args.Player.SendInfoMessage("If you understand, please /login now, and type /auth-verify."); return; } - args.Player.SendMessage("Incorrect auth code. This incident has been logged."); + args.Player.SendErrorMessage("Incorrect auth code. This incident has been logged."); Log.Warn(args.Player.IP + " attempted to use an incorrect auth code."); } @@ -2883,23 +3286,23 @@ namespace TShockAPI { if (TShock.AuthToken == 0) { - args.Player.SendMessage("It appears that you have already turned off the auth token."); - args.Player.SendMessage("If this is a mistake, delete auth.lck."); + args.Player.SendWarningMessage("It appears that you have already turned off the auth token."); + args.Player.SendWarningMessage("If this is a mistake, delete auth.lck."); return; } if (!args.Player.IsLoggedIn) { - args.Player.SendMessage("You must be logged in to disable the auth system."); - args.Player.SendMessage("This is a security measure designed to prevent insecure administration setups."); - args.Player.SendMessage("Please re-run /auth and read the instructions!"); - args.Player.SendMessage("If you're still confused, consult the forums. http://tshock.co/"); + args.Player.SendWarningMessage("You must be logged in to disable the auth system."); + args.Player.SendWarningMessage("This is a security measure designed to prevent insecure administration setups."); + args.Player.SendWarningMessage("Please re-run /auth and read the instructions!"); + args.Player.SendWarningMessage("If you're still confused, consult the forums: http://tshock.co/"); return; } - args.Player.SendMessage("Your new account has been verified, and the /auth system has been turned off."); - args.Player.SendMessage("You can always use the /user command to manage players. Don't just delete the auth.lck."); - args.Player.SendMessage("Thankyou for using TShock! http://tshock.co/ & http://github.com/TShock/TShock"); + args.Player.SendSuccessMessage("Your new account has been verified, and the /auth system has been turned off."); + args.Player.SendSuccessMessage("You can always use the /user command to manage players. Don't just delete the auth.lck."); + args.Player.SendSuccessMessage("Thank you for using TShock! http://tshock.co/ & http://github.com/TShock/TShock"); FileTools.CreateFile(Path.Combine(TShock.SavePath, "auth.lck")); File.Delete(Path.Combine(TShock.SavePath, "authcode.txt")); TShock.AuthToken = 0; @@ -2909,26 +3312,26 @@ namespace TShockAPI { if (args.Parameters.Count == 0) { - args.Player.SendMessage("Invalid syntax! Proper syntax: /me ", Color.Red); + args.Player.SendErrorMessage("Invalid syntax! Proper syntax: /me "); return; } if (args.Player.mute) - args.Player.SendMessage("You are muted."); + args.Player.SendErrorMessage("You are muted."); else - TShock.Utils.Broadcast(string.Format("*{0} {1}", args.Player.Name, String.Join(" ", args.Parameters)), 205, 133, 63); + TSPlayer.All.SendMessage(string.Format("*{0} {1}", args.Player.Name, String.Join(" ", args.Parameters)), 205, 133, 63); } private static void PartyChat(CommandArgs args) { if (args.Parameters.Count == 0) { - args.Player.SendMessage("Invalid syntax! Proper syntax: /p ", Color.Red); + args.Player.SendErrorMessage("Invalid syntax! Proper syntax: /p "); return; } int playerTeam = args.Player.Team; if (args.Player.mute) - args.Player.SendMessage("You are muted."); + args.Player.SendErrorMessage("You are muted."); else if (playerTeam != 0) { string msg = string.Format("<{0}> {1}", args.Player.Name, String.Join(" ", args.Parameters)); @@ -2939,39 +3342,41 @@ namespace TShockAPI } } else - args.Player.SendMessage("You are not in a party!", 255, 240, 20); + args.Player.SendErrorMessage("You are not in a party!"); } private static void Mute(CommandArgs args) { if (args.Parameters.Count < 1) { - args.Player.SendMessage("Invalid syntax! Proper syntax: /mute ", Color.Red); + args.Player.SendErrorMessage("Invalid syntax! Proper syntax: /mute [reason]"); return; } - string plStr = String.Join(" ", args.Parameters); - var players = TShock.Utils.FindPlayer(plStr); + var players = TShock.Utils.FindPlayer(args.Parameters[0]); if (players.Count == 0) - args.Player.SendMessage("Invalid player!", Color.Red); + args.Player.SendErrorMessage("Invalid player!"); else if (players.Count > 1) - args.Player.SendMessage("More than one player matched!", Color.Red); - else if (players[0].mute && !players[0].Group.HasPermission(Permissions.mute)) + args.Player.SendErrorMessage("More than one player matched!"); + else if (players[0].Group.HasPermission(Permissions.mute)) + { + args.Player.SendErrorMessage("You cannot mute this player."); + } + else if (players[0].mute) { var plr = players[0]; plr.mute = false; - plr.SendMessage("You have been unmuted."); - TShock.Utils.Broadcast(plr.Name + " has been unmuted by " + args.Player.Name, Color.Yellow); - } - else if (!players[0].Group.HasPermission(Permissions.mute)) - { - var plr = players[0]; - plr.mute = true; - plr.SendMessage("You have been muted."); - TShock.Utils.Broadcast(plr.Name + " has been muted by " + args.Player.Name, Color.Yellow); + TSPlayer.All.SendInfoMessage(String.Format("{0} has been unmuted by {1}.", plr.Name, args.Player.Name)); } else - args.Player.SendMessage("You cannot mute this player."); + { + string reason = "misbehavior"; + if (args.Parameters.Count > 1) + reason = String.Join(" ", args.Parameters.ToArray(), 1, args.Parameters.Count - 1); + var plr = players[0]; + plr.mute = true; + TSPlayer.All.SendInfoMessage(String.Format("{0} has been muted by {1} for {2}.", plr.Name, args.Player.Name, reason)); + } } private static void Motd(CommandArgs args) @@ -2988,21 +3393,21 @@ namespace TShockAPI { if (args.Parameters.Count < 2) { - args.Player.SendMessage("Invalid syntax! Proper syntax: /whisper ", Color.Red); + args.Player.SendErrorMessage("Invalid syntax! Proper syntax: /whisper "); return; } var players = TShock.Utils.FindPlayer(args.Parameters[0]); if (players.Count == 0) { - args.Player.SendMessage("Invalid player!", Color.Red); + args.Player.SendErrorMessage("Invalid player!"); } else if (players.Count > 1) { - args.Player.SendMessage("More than one player matched!", Color.Red); + args.Player.SendErrorMessage("More than one player matched!"); } else if (args.Player.mute) - args.Player.SendMessage("You are muted."); + args.Player.SendErrorMessage("You are muted."); else { var plr = players[0]; @@ -3017,7 +3422,7 @@ namespace TShockAPI private static void Reply(CommandArgs args) { if (args.Player.mute) - args.Player.SendMessage("You are muted."); + args.Player.SendErrorMessage("You are muted."); else if (args.Player.LastWhisper != null) { var msg = string.Join(" ", args.Parameters); @@ -3025,15 +3430,15 @@ namespace TShockAPI args.Player.SendMessage("(Whisper To)" + "<" + args.Player.LastWhisper.Name + ">" + msg, Color.MediumPurple); } else - args.Player.SendMessage( - "You haven't previously received any whispers. Please use /whisper to whisper to other people.", Color.Red); + args.Player.SendErrorMessage( + "You haven't previously received any whispers. Please use /whisper to whisper to other people."); } private static void Annoy(CommandArgs args) { if (args.Parameters.Count != 2) { - args.Player.SendMessage("Invalid syntax! Proper syntax: /annoy ", Color.Red); + args.Player.SendErrorMessage("Invalid syntax! Proper syntax: /annoy "); return; } int annoy = 5; @@ -3041,17 +3446,52 @@ namespace TShockAPI var players = TShock.Utils.FindPlayer(args.Parameters[0]); if (players.Count == 0) - args.Player.SendMessage("Invalid player!", Color.Red); + args.Player.SendErrorMessage("Invalid player!"); else if (players.Count > 1) - args.Player.SendMessage("More than one player matched!", Color.Red); + args.Player.SendErrorMessage("More than one player matched!"); else { var ply = players[0]; - args.Player.SendMessage("Annoying " + ply.Name + " for " + annoy + " seconds."); + args.Player.SendSuccessMessage("Annoying " + ply.Name + " for " + annoy + " seconds."); (new Thread(ply.Whoopie)).Start(annoy); } } + private static void Aliases(CommandArgs args) + { + if (args.Parameters.Count < 1) + { + args.Player.SendErrorMessage("Invalid syntax! Proper syntax: /aliases "); + return; + } + + string givenCommandName = string.Join(" ", args.Parameters); + if (string.IsNullOrWhiteSpace(givenCommandName)) { + args.Player.SendErrorMessage("Please enter a proper command name or alias."); + return; + } + + string commandName; + if (givenCommandName[0] == '/') + commandName = givenCommandName.Substring(1); + else + commandName = givenCommandName; + + bool didMatch = false; + foreach (Command matchingCommand in ChatCommands.Where(cmd => cmd.Names.IndexOf(commandName) != -1)) { + if (matchingCommand.Names.Count > 1) + args.Player.SendInfoMessage( + "Aliases of /{0}: /{1}", matchingCommand.Name, string.Join(", /", matchingCommand.Names.Skip(1))); + else + args.Player.SendInfoMessage("/{0} defines no aliases.", matchingCommand.Name); + + didMatch = true; + } + + if (!didMatch) + args.Player.SendErrorMessage("No command or command alias matching \"{0}\" found.", givenCommandName); + } + #endregion General Commands #region Cheat Commands @@ -3060,7 +3500,7 @@ namespace TShockAPI { if (args.Parameters.Count < 1) { - args.Player.SendMessage("Invalid syntax! Proper syntax: /kill ", Color.Red); + args.Player.SendErrorMessage("Invalid syntax! Proper syntax: /kill "); return; } @@ -3068,18 +3508,18 @@ namespace TShockAPI var players = TShock.Utils.FindPlayer(plStr); if (players.Count == 0) { - args.Player.SendMessage("Invalid player!", Color.Red); + args.Player.SendErrorMessage("Invalid player!"); } else if (players.Count > 1) { - args.Player.SendMessage("More than one player matched!", Color.Red); + args.Player.SendErrorMessage("More than one player matched!"); } else { var plr = players[0]; plr.DamagePlayer(999999); - args.Player.SendMessage(string.Format("You just killed {0}!", plr.Name)); - plr.SendMessage(string.Format("{0} just killed you!", args.Player.Name)); + args.Player.SendSuccessMessage(string.Format("You just killed {0}!", plr.Name)); + plr.SendErrorMessage(string.Format("{0} just killed you!", args.Player.Name)); } } @@ -3087,7 +3527,7 @@ namespace TShockAPI { if (args.Parameters.Count > 1) { - args.Player.SendMessage("Invalid syntax! Proper syntax: /butcher [killTownNPCs(true/false)]", Color.Red); + args.Player.SendErrorMessage("Invalid syntax! Proper syntax: /butcher [killTownNPCs(true/false)]"); return; } @@ -3104,88 +3544,115 @@ namespace TShockAPI killcount++; } } - TShock.Utils.Broadcast(string.Format("Killed {0} NPCs.", killcount)); + TSPlayer.All.SendSuccessMessage(string.Format("Killed {0} NPCs.", killcount)); } private static void Item(CommandArgs args) { if (args.Parameters.Count < 1) { - args.Player.SendMessage("Invalid syntax! Proper syntax: /item [item amount] [prefix id/name]", - Color.Red); - return; - } - if (args.Parameters[0].Length == 0) - { - args.Player.SendMessage("Missing item name/id", Color.Red); + args.Player.SendErrorMessage("Invalid syntax! Proper syntax: /item [item amount] [prefix id/name]"); return; } + + int amountParamIndex = -1; int itemAmount = 0; - int prefix = 0; - if (args.Parameters.Count == 2) - int.TryParse(args.Parameters[1], out itemAmount); - else if (args.Parameters.Count == 3) + for (int i = 1; i < args.Parameters.Count; i++) { - int.TryParse(args.Parameters[1], out itemAmount); - var found = TShock.Utils.GetPrefixByIdOrName(args.Parameters[2]); - if (found.Count == 1) - prefix = found[0]; + if (int.TryParse(args.Parameters[i], out itemAmount)) + { + amountParamIndex = i; + break; + } } - var items = TShock.Utils.GetItemByIdOrName(args.Parameters[0]); - if (items.Count == 0) + + string itemNameOrId; + if (amountParamIndex == -1) + itemNameOrId = string.Join(" ", args.Parameters); + else + itemNameOrId = string.Join(" ", args.Parameters.Take(amountParamIndex)); + + Item item; + List matchedItems = TShock.Utils.GetItemByIdOrName(itemNameOrId); + if (matchedItems.Count == 0) { - args.Player.SendMessage("Invalid item type!", Color.Red); + args.Player.SendErrorMessage("Invalid item type!"); + return; } - else if (items.Count > 1) + else if (matchedItems.Count > 1) { - args.Player.SendMessage(string.Format("More than one ({0}) item matched!", items.Count), Color.Red); + args.Player.SendErrorMessage("More than one item matched:"); + args.Player.SendErrorMessage(string.Join(", ", matchedItems.Select(i => i.name))); + return; } else { - var item = items[0]; - if (item.type >= 1 && item.type < Main.maxItemTypes) + item = matchedItems[0]; + } + if (item.type < 1 && item.type >= Main.maxItemTypes) + { + args.Player.SendErrorMessage("The item type {0} is invalid.", itemNameOrId); + return; + } + + int prefixId = 0; + if (amountParamIndex != -1 && args.Parameters.Count > amountParamIndex + 1) + { + string prefixidOrName = args.Parameters[amountParamIndex + 1]; + List matchedPrefixIds = TShock.Utils.GetPrefixByIdOrName(prefixidOrName); + if (matchedPrefixIds.Count > 1) { - if (args.Player.InventorySlotAvailable || item.name.Contains("Coin")) - { - if (itemAmount == 0 || itemAmount > item.maxStack) - itemAmount = item.maxStack; - if (args.Player.GiveItemCheck(item.type, item.name, item.width, item.height, itemAmount, prefix)) - { - args.Player.SendMessage(string.Format("Gave {0} {1}(s).", itemAmount, item.name)); - } - else - { - args.Player.SendMessage("The item is banned and the config prevents you from spawning banned items.", Color.Red); - } - } - else - { - args.Player.SendMessage("You don't have free slots!", Color.Red); - } + args.Player.SendErrorMessage("More than one ({0}) prefixes matched \"{1}\".", matchedPrefixIds.Count, prefixidOrName); + return; + } + else if (matchedPrefixIds.Count == 0) + { + args.Player.SendErrorMessage("No prefix matched \"{0}\".", prefixidOrName); + return; } else { - args.Player.SendMessage("Invalid item type!", Color.Red); + prefixId = matchedPrefixIds[0]; } } + + if (args.Player.InventorySlotAvailable || item.name.Contains("Coin")) + { + if (itemAmount == 0 || itemAmount > item.maxStack) + itemAmount = item.maxStack; + + if (args.Player.GiveItemCheck(item.type, item.name, item.width, item.height, itemAmount, prefixId)) + { + item.prefix = (byte)prefixId; + args.Player.SendSuccessMessage("Gave {0} {1}(s).", itemAmount, item.AffixName()); + } + else + { + args.Player.SendErrorMessage("The item is banned and the config prevents you from spawning banned items."); + } + } + else + { + args.Player.SendErrorMessage("Your inventory seems full."); + } } private static void Give(CommandArgs args) { if (args.Parameters.Count < 2) { - args.Player.SendMessage( - "Invalid syntax! Proper syntax: /give [item amount] [prefix id/name]", Color.Red); + args.Player.SendErrorMessage( + "Invalid syntax! Proper syntax: /give [item amount] [prefix id/name]"); return; } if (args.Parameters[0].Length == 0) { - args.Player.SendMessage("Missing item name/id", Color.Red); + args.Player.SendErrorMessage("Missing item name/id."); return; } if (args.Parameters[1].Length == 0) { - args.Player.SendMessage("Missing player name", Color.Red); + args.Player.SendErrorMessage("Missing player name."); return; } int itemAmount = 0; @@ -3206,11 +3673,11 @@ namespace TShockAPI if (items.Count == 0) { - args.Player.SendMessage("Invalid item type!", Color.Red); + args.Player.SendErrorMessage("Invalid item type!"); } else if (items.Count > 1) { - args.Player.SendMessage(string.Format("More than one ({0}) item matched!", items.Count), Color.Red); + args.Player.SendErrorMessage(string.Format("More than one ({0}) item matched!", items.Count)); } else { @@ -3220,11 +3687,11 @@ namespace TShockAPI var players = TShock.Utils.FindPlayer(plStr); if (players.Count == 0) { - args.Player.SendMessage("Invalid player!", Color.Red); + args.Player.SendErrorMessage("Invalid player!"); } else if (players.Count > 1) { - args.Player.SendMessage("More than one player matched!", Color.Red); + args.Player.SendErrorMessage("More than one player matched!"); } else { @@ -3235,29 +3702,29 @@ namespace TShockAPI itemAmount = item.maxStack; if (plr.GiveItemCheck(item.type, item.name, item.width, item.height, itemAmount, prefix)) { - args.Player.SendMessage(string.Format("Gave {0} {1} {2}(s).", plr.Name, itemAmount, item.name)); - plr.SendMessage(string.Format("{0} gave you {1} {2}(s).", args.Player.Name, itemAmount, item.name)); + args.Player.SendSuccessMessage(string.Format("Gave {0} {1} {2}(s).", plr.Name, itemAmount, item.name)); + plr.SendSuccessMessage(string.Format("{0} gave you {1} {2}(s).", args.Player.Name, itemAmount, item.name)); } else { - args.Player.SendMessage("The item is banned and the config prevents spawning banned items.", Color.Red); + args.Player.SendErrorMessage("The item is banned and the config prevents spawning banned items."); } } else { - args.Player.SendMessage("Player does not have free slots!", Color.Red); + args.Player.SendErrorMessage("Player does not have free slots!"); } } } else { - args.Player.SendMessage("Invalid item type!", Color.Red); + args.Player.SendErrorMessage("Invalid item type!"); } } } - public static void ClearItems(CommandArgs args) + private static void ClearItems(CommandArgs args) { int radius = 50; if (args.Parameters.Count > 0) @@ -3274,8 +3741,8 @@ namespace TShockAPI } catch (Exception) { - args.Player.SendMessage( - "Please either enter the keyword \"all\", or the block radius you wish to delete all items from.", Color.Red); + args.Player.SendErrorMessage( + "Please either enter the keyword \"all\", or the block radius you wish to delete all items from."); return; } } @@ -3292,7 +3759,7 @@ namespace TShockAPI count++; } } - args.Player.SendMessage("All " + count + " items within a radius of " + radius + " have been deleted."); + args.Player.SendSuccessMessage("All " + count + " items within a radius of " + radius + " have been deleted."); } private static void Heal(CommandArgs args) @@ -3304,12 +3771,12 @@ namespace TShockAPI var players = TShock.Utils.FindPlayer(plStr); if (players.Count == 0) { - args.Player.SendMessage("Invalid player!", Color.Red); + args.Player.SendErrorMessage("Invalid player!"); return; } else if (players.Count > 1) { - args.Player.SendMessage("More than one player matched!", Color.Red); + args.Player.SendErrorMessage("More than one player matched!"); return; } else @@ -3319,7 +3786,7 @@ namespace TShockAPI } else if (!args.Player.RealPlayer) { - args.Player.SendMessage("You cant heal yourself!"); + args.Player.SendErrorMessage("You cant heal yourself!"); return; } else @@ -3335,12 +3802,12 @@ namespace TShockAPI playerToHeal.GiveItem(star.type, star.name, star.width, star.height, star.maxStack); if (playerToHeal == args.Player) { - args.Player.SendMessage("You just got healed!"); + args.Player.SendSuccessMessage("You just got healed!"); } else { - args.Player.SendMessage(string.Format("You just healed {0}", playerToHeal.Name)); - playerToHeal.SendMessage(string.Format("{0} just healed you!", args.Player.Name)); + args.Player.SendSuccessMessage(string.Format("You just healed {0}", playerToHeal.Name)); + playerToHeal.SendSuccessMessage(string.Format("{0} just healed you!", args.Player.Name)); } } @@ -3348,7 +3815,7 @@ namespace TShockAPI { if (args.Parameters.Count < 1 || args.Parameters.Count > 2) { - args.Player.SendMessage("Invalid syntax! Proper syntax: /buff [time(seconds)]", Color.Red); + args.Player.SendErrorMessage("Invalid syntax! Proper syntax: /buff [time(seconds)]"); return; } int id = 0; @@ -3358,12 +3825,12 @@ namespace TShockAPI var found = TShock.Utils.GetBuffByName(args.Parameters[0]); if (found.Count == 0) { - args.Player.SendMessage("Invalid buff name!", Color.Red); + args.Player.SendErrorMessage("Invalid buff name!"); return; } else if (found.Count > 1) { - args.Player.SendMessage(string.Format("More than one ({0}) buff matched!", found.Count), Color.Red); + args.Player.SendErrorMessage(string.Format("More than one ({0}) buff matched!", found.Count)); return; } id = found[0]; @@ -3375,19 +3842,18 @@ namespace TShockAPI if (time < 0 || time > short.MaxValue) time = 60; args.Player.SetBuff(id, time*60); - args.Player.SendMessage(string.Format("You have buffed yourself with {0}({1}) for {2} seconds!", - TShock.Utils.GetBuffName(id), TShock.Utils.GetBuffDescription(id), (time)), - Color.Green); + args.Player.SendSuccessMessage(string.Format("You have buffed yourself with {0}({1}) for {2} seconds!", + TShock.Utils.GetBuffName(id), TShock.Utils.GetBuffDescription(id), (time))); } else - args.Player.SendMessage("Invalid buff ID!", Color.Red); + args.Player.SendErrorMessage("Invalid buff ID!"); } private static void GBuff(CommandArgs args) { if (args.Parameters.Count < 2 || args.Parameters.Count > 3) { - args.Player.SendMessage("Invalid syntax! Proper syntax: /gbuff [time(seconds)]", Color.Red); + args.Player.SendErrorMessage("Invalid syntax! Proper syntax: /gbuff [time(seconds)]"); return; } int id = 0; @@ -3395,12 +3861,12 @@ namespace TShockAPI var foundplr = TShock.Utils.FindPlayer(args.Parameters[0]); if (foundplr.Count == 0) { - args.Player.SendMessage("Invalid player!", Color.Red); + args.Player.SendErrorMessage("Invalid player!"); return; } else if (foundplr.Count > 1) { - args.Player.SendMessage(string.Format("More than one ({0}) player matched!", args.Parameters.Count), Color.Red); + args.Player.SendErrorMessage(string.Format("More than one ({0}) player matched!", args.Parameters.Count)); return; } else @@ -3410,12 +3876,12 @@ namespace TShockAPI var found = TShock.Utils.GetBuffByName(args.Parameters[1]); if (found.Count == 0) { - args.Player.SendMessage("Invalid buff name!", Color.Red); + args.Player.SendErrorMessage("Invalid buff name!"); return; } else if (found.Count > 1) { - args.Player.SendMessage(string.Format("More than one ({0}) buff matched!", found.Count), Color.Red); + args.Player.SendErrorMessage(string.Format("More than one ({0}) buff matched!", found.Count)); return; } id = found[0]; @@ -3427,15 +3893,15 @@ namespace TShockAPI if (time < 0 || time > short.MaxValue) time = 60; foundplr[0].SetBuff(id, time*60); - args.Player.SendMessage(string.Format("You have buffed {0} with {1}({2}) for {3} seconds!", + args.Player.SendSuccessMessage(string.Format("You have buffed {0} with {1}({2}) for {3} seconds!", foundplr[0].Name, TShock.Utils.GetBuffName(id), - TShock.Utils.GetBuffDescription(id), (time)), Color.Green); - foundplr[0].SendMessage(string.Format("{0} has buffed you with {1}({2}) for {3} seconds!", + TShock.Utils.GetBuffDescription(id), (time))); + foundplr[0].SendSuccessMessage(string.Format("{0} has buffed you with {1}({2}) for {3} seconds!", args.Player.Name, TShock.Utils.GetBuffName(id), - TShock.Utils.GetBuffDescription(id), (time)), Color.Green); + TShock.Utils.GetBuffDescription(id), (time))); } else - args.Player.SendMessage("Invalid buff ID!", Color.Red); + args.Player.SendErrorMessage("Invalid buff ID!"); } } @@ -3443,7 +3909,7 @@ namespace TShockAPI { if (args.Parameters.Count != 1) { - args.Player.SendMessage("Invalid syntax! Proper syntax: /grow [tree/epictree/mushroom/cactus/herb]", Color.Red); + args.Player.SendErrorMessage("Invalid syntax! Proper syntax: /grow [tree/epictree/mushroom/cactus/herb]"); return; } var name = "Fail"; @@ -3499,11 +3965,11 @@ namespace TShockAPI name = "Herb"; break; default: - args.Player.SendMessage("Unknown plant!", Color.Red); + args.Player.SendErrorMessage("Unknown plant!"); return; } args.Player.SendTileSquare(x, y); - args.Player.SendMessage("Tried to grow a " + name, Color.Green); + args.Player.SendSuccessMessage("Tried to grow a " + name + "."); } #endregion Cheat Comamnds diff --git a/TShockAPI/ConfigFile.cs b/TShockAPI/ConfigFile.cs index 03e74d1f..36d7e6ae 100644 --- a/TShockAPI/ConfigFile.cs +++ b/TShockAPI/ConfigFile.cs @@ -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 . */ + 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 ApplicationRestTokens = new Dictionary(); + + [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; /// /// Reads a configuration file from a given path diff --git a/TShockAPI/DB/BanManager.cs b/TShockAPI/DB/BanManager.cs index 7ace1584..ddcd4d8e 100644 --- a/TShockAPI/DB/BanManager.cs +++ b/TShockAPI/DB/BanManager.cs @@ -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 . */ + using System; using System.Collections.Generic; using System.Data; -using System.IO; using MySql.Data.MySqlClient; namespace TShockAPI.DB diff --git a/TShockAPI/DB/GroupManager.cs b/TShockAPI/DB/GroupManager.cs index de3f0db4..ab9fe61d 100644 --- a/TShockAPI/DB/GroupManager.cs +++ b/TShockAPI/DB/GroupManager.cs @@ -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 . */ + 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 /// chatcolor 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 groupChain = new List { 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 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 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(); - tempgroups.Add(new SuperAdminGroup()); - - if (groups == null || groups.Count < 2) - { - groups.Clear(); - groups.AddRange(tempgroups); - } - try { - var groupsparents = new List>(); + List newGroups = new List(groups.Count); + Dictionary newGroupParents = new Dictionary(groups.Count); using (var reader = database.QueryReader("SELECT * FROM GroupList")) { while (reader.Read()) { - var group = new Group(reader.Get("GroupName"), null, reader.Get("ChatColor"), reader.Get("Commands")); - group.Prefix = reader.Get("Prefix"); - group.Suffix = reader.Get("Suffix"); - groupsparents.Add(Tuple.Create(group, reader.Get("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("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("ChatColor"), reader.Get("Commands")) { + Prefix = reader.Get("Prefix"), + Suffix = reader.Get("Suffix"), + }); + + try + { + newGroupParents.Add(groupName, reader.Get("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 groupChain = new List { 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); } } } diff --git a/TShockAPI/DB/IQueryBuilder.cs b/TShockAPI/DB/IQueryBuilder.cs index 2d4a8662..d65af44a 100644 --- a/TShockAPI/DB/IQueryBuilder.cs +++ b/TShockAPI/DB/IQueryBuilder.cs @@ -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 . */ + using System; using System.Collections.Generic; using System.Linq; diff --git a/TShockAPI/DB/InventoryManager.cs b/TShockAPI/DB/InventoryManager.cs index 92f8a6bf..9cbff2f4 100644 --- a/TShockAPI/DB/InventoryManager.cs +++ b/TShockAPI/DB/InventoryManager.cs @@ -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 . */ + using System; using System.Data; using MySql.Data.MySqlClient; diff --git a/TShockAPI/DB/ItemManager.cs b/TShockAPI/DB/ItemManager.cs index 6ef11b6b..b95bd886 100644 --- a/TShockAPI/DB/ItemManager.cs +++ b/TShockAPI/DB/ItemManager.cs @@ -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 . */ + using System; using System.Collections.Generic; using System.Data; -using System.IO; using System.Linq; using MySql.Data.MySqlClient; diff --git a/TShockAPI/DB/RegionManager.cs b/TShockAPI/DB/RegionManager.cs index b3eef5fe..f9cce5c8 100644 --- a/TShockAPI/DB/RegionManager.cs +++ b/TShockAPI/DB/RegionManager.cs @@ -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 . */ + 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 InAreaRegionName(int x, int y) { List regions = new List() { }; - 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 InAreaRegion(int x, int y) + { + List regions = new List() { }; + foreach (Region region in Regions.ToList()) + { + if (x >= region.Area.Left && x <= region.Area.Right && + y >= region.Area.Top && y <= region.Area.Bottom && + region.DisableBuild) + { + regions.Add(region); + } + } + return regions; + } + public static List ListIDs(string MergedIDs) { 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("UserIds"); + mergedIDs = reader.Get("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("Groups"); + mergedGroups = reader.Get("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 { diff --git a/TShockAPI/DB/RememberPosManager.cs b/TShockAPI/DB/RememberedPosManager.cs similarity index 95% rename from TShockAPI/DB/RememberPosManager.cs rename to TShockAPI/DB/RememberedPosManager.cs index ee06db63..457bb028 100644 --- a/TShockAPI/DB/RememberPosManager.cs +++ b/TShockAPI/DB/RememberedPosManager.cs @@ -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 . */ + 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; diff --git a/TShockAPI/DB/SqlColumn.cs b/TShockAPI/DB/SqlColumn.cs index efc94649..9b59c89e 100644 --- a/TShockAPI/DB/SqlColumn.cs +++ b/TShockAPI/DB/SqlColumn.cs @@ -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 . */ + using MySql.Data.MySqlClient; namespace TShockAPI.DB diff --git a/TShockAPI/DB/SqlTable.cs b/TShockAPI/DB/SqlTable.cs index 0b4024c6..08275ef9 100644 --- a/TShockAPI/DB/SqlTable.cs +++ b/TShockAPI/DB/SqlTable.cs @@ -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 . */ + using System; using System.Collections.Generic; using System.Data; diff --git a/TShockAPI/DB/SqlValue.cs b/TShockAPI/DB/SqlValue.cs index 0efd78bf..04161e90 100644 --- a/TShockAPI/DB/SqlValue.cs +++ b/TShockAPI/DB/SqlValue.cs @@ -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 . */ + using System.Collections.Generic; using System.Data; diff --git a/TShockAPI/DB/UserManager.cs b/TShockAPI/DB/UserManager.cs index db360518..fdb3cdf5 100644 --- a/TShockAPI/DB/UserManager.cs +++ b/TShockAPI/DB/UserManager.cs @@ -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 . */ + using System; using System.Data; -using System.IO; using System.Collections.Generic; using System.Linq; using MySql.Data.MySqlClient; diff --git a/TShockAPI/DB/WarpsManager.cs b/TShockAPI/DB/WarpsManager.cs index 67d1afe8..9ece9591 100644 --- a/TShockAPI/DB/WarpsManager.cs +++ b/TShockAPI/DB/WarpsManager.cs @@ -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 . */ + using System; using System.Collections.Generic; using System.Data; diff --git a/TShockAPI/Extensions/DbExt.cs b/TShockAPI/Extensions/DbExt.cs index 42bcc6f1..3f1db5c7 100644 --- a/TShockAPI/Extensions/DbExt.cs +++ b/TShockAPI/Extensions/DbExt.cs @@ -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 . */ + using System; using System.Collections.Generic; using System.Data; diff --git a/TShockAPI/Extensions/LinqExt.cs b/TShockAPI/Extensions/LinqExt.cs index 25d06b7e..86b639bd 100644 --- a/TShockAPI/Extensions/LinqExt.cs +++ b/TShockAPI/Extensions/LinqExt.cs @@ -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 . */ + using System; using System.Collections.Generic; diff --git a/TShockAPI/Extensions/RandomExt.cs b/TShockAPI/Extensions/RandomExt.cs index 2e4d2681..e0a866bf 100644 --- a/TShockAPI/Extensions/RandomExt.cs +++ b/TShockAPI/Extensions/RandomExt.cs @@ -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 . */ + using System; using System.Text; diff --git a/TShockAPI/Extensions/StringExt.cs b/TShockAPI/Extensions/StringExt.cs index e70be35b..ea67e801 100644 --- a/TShockAPI/Extensions/StringExt.cs +++ b/TShockAPI/Extensions/StringExt.cs @@ -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 . */ + using System; namespace TShockAPI diff --git a/TShockAPI/FileTools.cs b/TShockAPI/FileTools.cs index b353bf9a..581fe393 100644 --- a/TShockAPI/FileTools.cs +++ b/TShockAPI/FileTools.cs @@ -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 . */ + using System; using System.IO; @@ -22,36 +23,52 @@ namespace TShockAPI { public class FileTools { + /// + /// Path to the file containing the rules. + /// internal static string RulesPath { get { return Path.Combine(TShock.SavePath, "rules.txt"); } } + /// + /// Path to the file containing the message of the day. + /// internal static string MotdPath { get { return Path.Combine(TShock.SavePath, "motd.txt"); } } + /// + /// Path to the file containing the whitelist. + /// internal static string WhitelistPath { get { return Path.Combine(TShock.SavePath, "whitelist.txt"); } } - internal static string RememberedPosPath - { - get { return Path.Combine(TShock.SavePath, "oldpos.xml"); } - } - + /// + /// Path to the file containing the config. + /// internal static string ConfigPath { get { return Path.Combine(TShock.SavePath, "config.json"); } } + /// + /// Creates an empty file at the given path. + /// + /// The path to the file. public static void CreateFile(string file) { File.Create(file).Close(); } + /// + /// Creates a file if the files doesn't already exist. + /// + /// The path to the files + /// The data to write to the file. public static void CreateIfNot(string file, string data = "") { if (!File.Exists(file)) diff --git a/TShockAPI/GeoIPCountry.cs b/TShockAPI/GeoIPCountry.cs index c09ccffc..4ca30777 100644 --- a/TShockAPI/GeoIPCountry.cs +++ b/TShockAPI/GeoIPCountry.cs @@ -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 . +*/ + +/* 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 . -*/ using System; using System.IO; using System.Net; diff --git a/TShockAPI/GetDataHandlers.cs b/TShockAPI/GetDataHandlers.cs index 800516a6..7a508474 100644 --- a/TShockAPI/GetDataHandlers.cs +++ b/TShockAPI/GetDataHandlers.cs @@ -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 . */ + 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) /// public byte EditType { get; set; } + + /// + /// Did the tile get destroyed successfully. + /// + public bool Fail { get; set; } + + /// + /// Used when a tile is placed to denote a subtype of tile. (e.g. for tile id 21: Chest = 0, Gold Chest = 1) + /// + public byte Style { get; set; } } /// /// TileEdit - called when a tile is placed or destroyed /// public static HandlerList 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 outputRegions = new List(); + 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; } } diff --git a/TShockAPI/Group.cs b/TShockAPI/Group.cs index f6d41630..50995b51 100644 --- a/TShockAPI/Group.cs +++ b/TShockAPI/Group.cs @@ -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 . */ + 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"; + /// + /// Default chat color. + /// + public const string defaultChatColor = "255,255,255"; + + /// + /// List of permissions available to the group. + /// public readonly List permissions = new List(); + + /// + /// List of permissions that the group is explicitly barred from. + /// public readonly List negatedpermissions = new List(); + /// + /// The group's name. + /// public string Name { get; set; } + + /// + /// The group that this group inherits permissions from. + /// public Group Parent { get; set; } - public int Order { get; set; } + + /// + /// The chat prefix for this group. + /// public string Prefix { get; set; } + + /// + /// The chat suffix for this group. + /// public string Suffix { get; set; } + + /// + /// 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. + /// public string ParentName { get { return (null == Parent) ? "" : Parent.Name; } } + + /// + /// The chat color of the group. + /// Returns "255255255", sets "255,255,255" + /// 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 } } + /// + /// The permissions of the user in string form. + /// public string Permissions { get @@ -75,6 +115,9 @@ namespace TShockAPI } } + /// + /// The permissions of this group and all that it inherits from. + /// public List TotalPermissions { get @@ -125,29 +168,55 @@ namespace TShockAPI Permissions = permissions; } + /// + /// Checks to see if a group has a specified permission. + /// + /// The permission to check. + /// Returns true if the user has that permission. public virtual bool HasPermission(string permission) { - if (string.IsNullOrEmpty(permission)) - return true; - - var cur = this; - var traversed = new List(); - 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(); + 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; + } + + /// + /// Adds a permission to the list of negated permissions. + /// + /// The permission to negate. public void NegatePermission(string permission) { // Avoid duplicates @@ -158,6 +227,10 @@ namespace TShockAPI } } + /// + /// Adds a permission to the list of permissions. + /// + /// The permission to add. public void AddPermission(string permission) { if (permission.StartsWith("!")) @@ -173,6 +246,11 @@ namespace TShockAPI } } + /// + /// Clears the permission list and sets it to the list provided, + /// will parse "!permssion" and add it to the negated permissions. + /// + /// public void SetPermission(List permission) { permissions.Clear(); @@ -180,6 +258,11 @@ namespace TShockAPI permission.ForEach(p => AddPermission(p)); } + /// + /// Will remove a permission from the respective list, + /// where "!permission" will remove a negated permission. + /// + /// public void RemovePermission(string permission) { if (permission.StartsWith("!")) @@ -189,8 +272,31 @@ namespace TShockAPI } permissions.Remove(permission); } + + /// + /// Assigns all fields of this instance to another. + /// + /// The other instance. + 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; + } } + /// + /// This class is the SuperAdminGroup, which has access to everything. + /// public class SuperAdminGroup : Group { public SuperAdminGroup() @@ -203,9 +309,14 @@ namespace TShockAPI Suffix = TShock.Config.SuperAdminChatSuffix; } + /// + /// Override to allow access to everything. + /// + /// The permission + /// True public override bool HasPermission(string permission) { return true; } } -} \ No newline at end of file +} diff --git a/TShockAPI/HandlerList.cs b/TShockAPI/HandlerList.cs index 12822962..128e6c5e 100644 --- a/TShockAPI/HandlerList.cs +++ b/TShockAPI/HandlerList.cs @@ -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 . */ + using System; using System.Collections.Generic; using System.ComponentModel; using System.Linq; -using System.Text; namespace TShockAPI { diff --git a/DBEditor/Program.cs b/TShockAPI/Hooks/GeneralHooks.cs similarity index 54% rename from DBEditor/Program.cs rename to TShockAPI/Hooks/GeneralHooks.cs index e0f7ef00..f84efabd 100644 --- a/DBEditor/Program.cs +++ b/TShockAPI/Hooks/GeneralHooks.cs @@ -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 . */ -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 { - /// - /// The main entry point for the application. - /// - [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)); } } } diff --git a/TShockAPI/Hooks/PlayerHooks.cs b/TShockAPI/Hooks/PlayerHooks.cs new file mode 100644 index 00000000..047fca50 --- /dev/null +++ b/TShockAPI/Hooks/PlayerHooks.cs @@ -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 . +*/ + +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 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 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; + } + } +} diff --git a/TShockAPI/IPackable.cs b/TShockAPI/IPackable.cs index 8523aeff..b44bedc8 100644 --- a/TShockAPI/IPackable.cs +++ b/TShockAPI/IPackable.cs @@ -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 . */ + using System.IO; namespace TShockAPI diff --git a/TShockAPI/Log.cs b/TShockAPI/Log.cs index 9e54c53a..1e286b09 100644 --- a/TShockAPI/Log.cs +++ b/TShockAPI/Log.cs @@ -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 . */ + using System; using System.Diagnostics; using System.Globalization; @@ -72,6 +73,16 @@ namespace TShockAPI Write(message, LogLevel.Data); } + /// + /// Writes data to the log file. + /// + /// The format of the message to be written. + /// The format arguments. + public static void Data(String format, params String[] args) + { + Data(String.Format(format, args)); + } + /// /// Writes an error to the log file. /// @@ -81,6 +92,16 @@ namespace TShockAPI Write(message, LogLevel.Error); } + /// + /// Writes an error to the log file. + /// + /// The format of the message to be written. + /// The format arguments. + public static void Error(String format, params String[] args) + { + Error(String.Format(format, args)); + } + /// /// Writes an error to the log file. /// @@ -93,6 +114,16 @@ namespace TShockAPI Write(message, LogLevel.Error); } + /// + /// Writes an error to the log file. + /// + /// The format of the message to be written. + /// The format arguments. + public static void ConsoleError(String format, params String[] args) + { + ConsoleError(String.Format(format, args)); + } + /// /// Writes a warning to the log file. /// @@ -102,6 +133,16 @@ namespace TShockAPI Write(message, LogLevel.Warning); } + /// + /// Writes a warning to the log file. + /// + /// The format of the message to be written. + /// The format arguments. + public static void Warn(String format, params String[] args) + { + Warn(String.Format(format, args)); + } + /// /// Writes an informative string to the log file. /// @@ -111,6 +152,16 @@ namespace TShockAPI Write(message, LogLevel.Info); } + /// + /// Writes an informative string to the log file. + /// + /// The format of the message to be written. + /// The format arguments. + public static void Info(String format, params String[] args) + { + Info(String.Format(format, args)); + } + /// /// Writes an informative string to the log file. Also outputs to the console. /// @@ -123,6 +174,16 @@ namespace TShockAPI Write(message, LogLevel.Info); } + /// + /// Writes an informative string to the log file. Also outputs to the console. + /// + /// The format of the message to be written. + /// The format arguments. + public static void ConsoleInfo(String format, params String[] args) + { + ConsoleInfo(String.Format(format, args)); + } + /// /// Writes a debug string to the log file. /// @@ -132,6 +193,16 @@ namespace TShockAPI Write(message, LogLevel.Debug); } + /// + /// Writes a debug string to the log file. + /// + /// The format of the message to be written. + /// The format arguments. + public static void Debug(String format, params String[] args) + { + Debug(String.Format(format, args)); + } + /// /// Disposes objects that are being used. /// diff --git a/TShockAPI/Net/BaseMsg.cs b/TShockAPI/Net/BaseMsg.cs index 8e0ce232..5db8814e 100644 --- a/TShockAPI/Net/BaseMsg.cs +++ b/TShockAPI/Net/BaseMsg.cs @@ -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 . */ + using System; using System.IO; using System.IO.Streams; diff --git a/TShockAPI/Net/DisconnectMsg.cs b/TShockAPI/Net/DisconnectMsg.cs index d62775a4..eaaa6df8 100644 --- a/TShockAPI/Net/DisconnectMsg.cs +++ b/TShockAPI/Net/DisconnectMsg.cs @@ -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 . */ + using System.IO; using System.IO.Streams; using System.Text; diff --git a/TShockAPI/Net/NetTile.cs b/TShockAPI/Net/NetTile.cs index 78d53be7..e3cc30f4 100644 --- a/TShockAPI/Net/NetTile.cs +++ b/TShockAPI/Net/NetTile.cs @@ -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 . */ + using System; using System.IO; using System.IO.Streams; diff --git a/TShockAPI/Net/ProjectileRemoveMsg.cs b/TShockAPI/Net/ProjectileRemoveMsg.cs index bc119dcc..d8775313 100644 --- a/TShockAPI/Net/ProjectileRemoveMsg.cs +++ b/TShockAPI/Net/ProjectileRemoveMsg.cs @@ -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 . */ + using System.IO; using System.IO.Streams; diff --git a/TShockAPI/Net/SpawnMsg.cs b/TShockAPI/Net/SpawnMsg.cs index 36258396..849e5627 100644 --- a/TShockAPI/Net/SpawnMsg.cs +++ b/TShockAPI/Net/SpawnMsg.cs @@ -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 . */ + using System.IO; using System.IO.Streams; diff --git a/TShockAPI/Net/WorldInfoMsg.cs b/TShockAPI/Net/WorldInfoMsg.cs index 7b64f2a8..d95a8bf9 100644 --- a/TShockAPI/Net/WorldInfoMsg.cs +++ b/TShockAPI/Net/WorldInfoMsg.cs @@ -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 . */ + using System; using System.IO; using System.IO.Streams; diff --git a/TShockAPI/PacketBufferer.cs b/TShockAPI/PacketBufferer.cs index e2ea8e94..d18ac47f 100644 --- a/TShockAPI/PacketBufferer.cs +++ b/TShockAPI/PacketBufferer.cs @@ -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 . */ + 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) { diff --git a/TShockAPI/PaginationTools.cs b/TShockAPI/PaginationTools.cs new file mode 100644 index 00000000..e64d3e2a --- /dev/null +++ b/TShockAPI/PaginationTools.cs @@ -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 . +*/ + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Text; + +namespace TShockAPI +{ + public static class PaginationTools + { + public delegate Tuple 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 / {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) + { + var lineFormat = (Tuple)lineData; + lineMessage = lineFormat.Item1; + lineColor = lineFormat.Item2; + } + else if (settings.LineFormatter != null) + { + try + { + Tuple 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 BuildLinesFromTerms( + IEnumerable terms, Func termFormatter = null, string separator = ", ", int maxCharsPerLine = 80) + { + List lines = new List(); + 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 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; + } + } +} \ No newline at end of file diff --git a/TShockAPI/Permissions.cs b/TShockAPI/Permissions.cs index c64b0489..bf56613c 100644 --- a/TShockAPI/Permissions.cs +++ b/TShockAPI/Permissions.cs @@ -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 . */ + 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"; } /// @@ -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(); } /// diff --git a/TShockAPI/PluginUpdater/PluginUpdaterThread.cs b/TShockAPI/PluginUpdater/PluginUpdaterThread.cs new file mode 100644 index 00000000..b77a1370 --- /dev/null +++ b/TShockAPI/PluginUpdater/PluginUpdaterThread.cs @@ -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 . +*/ +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."); + } + } + } +} diff --git a/TShockAPI/PluginUpdater/PluginVersionCheck.cs b/TShockAPI/PluginUpdater/PluginVersionCheck.cs new file mode 100644 index 00000000..61858af8 --- /dev/null +++ b/TShockAPI/PluginUpdater/PluginVersionCheck.cs @@ -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 . +*/ +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 files = new List(); + + 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(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(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; } + } +} diff --git a/TShockAPI/PluginUpdater/VersionInfo.cs b/TShockAPI/PluginUpdater/VersionInfo.cs new file mode 100644 index 00000000..4dd061b3 --- /dev/null +++ b/TShockAPI/PluginUpdater/VersionInfo.cs @@ -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 . +*/ +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 files; + } + + class PluginFile + { + public string url; + public string destination = ""; + } +} diff --git a/TShockAPI/Properties/AssemblyInfo.cs b/TShockAPI/Properties/AssemblyInfo.cs index 568320d9..7b0a99aa 100644 --- a/TShockAPI/Properties/AssemblyInfo.cs +++ b/TShockAPI/Properties/AssemblyInfo.cs @@ -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 . */ + 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")] diff --git a/TShockAPI/RconHandler.cs b/TShockAPI/RconHandler.cs index 3d314f24..3e83f856 100644 --- a/TShockAPI/RconHandler.cs +++ b/TShockAPI/RconHandler.cs @@ -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 . */ + using System; using System.Collections.Generic; using System.IO; diff --git a/TShockAPI/Resources.Designer.cs b/TShockAPI/Resources.Designer.cs index 99b8a890..d22d260b 100644 --- a/TShockAPI/Resources.Designer.cs +++ b/TShockAPI/Resources.Designer.cs @@ -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 . //------------------------------------------------------------------------------ namespace TShockAPI { - using System; - - /// /// A strongly-typed resource class, for looking up localized strings, etc. /// diff --git a/TShockAPI/Rest/Rest.cs b/TShockAPI/Rest/Rest.cs index 3f2ae2e2..1d827a35 100644 --- a/TShockAPI/Rest/Rest.cs +++ b/TShockAPI/Rest/Rest.cs @@ -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 . */ + using System; using System.Collections.Generic; using System.ComponentModel; @@ -38,6 +39,15 @@ namespace Rests /// Response object or null to not handle request public delegate object RestCommandD(RestVerbs verbs, IParameterCollection parameters); + /// + /// Secure Rest command delegate including token data. + /// + /// Parameters in the url + /// {x} in urltemplate + /// The data of stored for the provided token. + /// Response object or null to not handle request + public delegate object SecureRestCommandD(RestVerbs verbs, IParameterCollection parameters, SecureRest.TokenData tokenData); + public class Rest : IDisposable { private readonly List commands = new List(); @@ -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 + return new RestObject("500") { - {"status", "500"}, {"error", "Internal server error."}, {"errormsg", exception.Message}, {"stacktrace", exception.StackTrace}, }; } - return new Dictionary + 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 diff --git a/TShockAPI/Rest/RestCommand.cs b/TShockAPI/Rest/RestCommand.cs index 334752de..c0db0a9a 100644 --- a/TShockAPI/Rest/RestCommand.cs +++ b/TShockAPI/Rest/RestCommand.cs @@ -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 . */ + 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; /// /// @@ -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; } /// @@ -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); + } } } \ No newline at end of file diff --git a/TShockAPI/Rest/RestManager.cs b/TShockAPI/Rest/RestManager.cs index 160dad55..50c442cb 100644 --- a/TShockAPI/Rest/RestManager.cs +++ b/TShockAPI/Rest/RestManager.cs @@ -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 . */ + 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(){ {"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 { diff --git a/TShockAPI/Rest/RestObject.cs b/TShockAPI/Rest/RestObject.cs index 0133ff6f..4edfae9c 100644 --- a/TShockAPI/Rest/RestObject.cs +++ b/TShockAPI/Rest/RestObject.cs @@ -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 . */ + using System; using System.Collections.Generic; diff --git a/TShockAPI/Rest/RestPermissions.cs b/TShockAPI/Rest/RestPermissions.cs new file mode 100644 index 00000000..c602370f --- /dev/null +++ b/TShockAPI/Rest/RestPermissions.cs @@ -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 . +*/ + +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); + } + } + } +} diff --git a/TShockAPI/Rest/RestVerbs.cs b/TShockAPI/Rest/RestVerbs.cs index ea155fcb..c63642d4 100644 --- a/TShockAPI/Rest/RestVerbs.cs +++ b/TShockAPI/Rest/RestVerbs.cs @@ -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 . */ + using System; using System.Collections.Generic; diff --git a/TShockAPI/Rest/SecureRest.cs b/TShockAPI/Rest/SecureRest.cs index 987cd295..3443d56c 100644 --- a/TShockAPI/Rest/SecureRest.cs +++ b/TShockAPI/Rest/SecureRest.cs @@ -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 . */ + using System; using System.Collections.Generic; using System.Linq; using System.Net; using HttpServer; +using TShockAPI; +using TShockAPI.DB; namespace Rests { - /// - /// - /// - /// Username to verify - /// Password to verify - /// Returning a restobject with a null error means a successful verification. - public delegate RestObject VerifyD(string username, string password); - public class SecureRest : Rest { - public Dictionary 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 Tokens { get; protected set; } + public Dictionary AppTokens { get; protected set; } public SecureRest(IPAddress ip, int port) : base(ip, port) { - Tokens = new Dictionary(); - 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 t in TShockAPI.TShock.RESTStartupTokens) + Tokens = new Dictionary(); + AppTokens = new Dictionary(); + + 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 t in TShockAPI.TShock.RESTStartupTokens) { - Tokens.Add(t.Key, t.Value); + AppTokens.Add(t.Key, t.Value); + } + + foreach (KeyValuePair 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 - {{"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 - {{"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 - {{"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 - { - {"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; } } } \ No newline at end of file diff --git a/TShockAPI/SaveManager.cs b/TShockAPI/SaveManager.cs index f411a2ef..7e0b0b57 100644 --- a/TShockAPI/SaveManager.cs +++ b/TShockAPI/SaveManager.cs @@ -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 . +*/ +using System; using System.Collections.Generic; using System.ComponentModel; using System.Threading; -using System.Diagnostics; using Terraria; namespace TShockAPI diff --git a/TShockAPI/StatTracker.cs b/TShockAPI/StatTracker.cs deleted file mode 100644 index 99364eae..00000000 --- a/TShockAPI/StatTracker.cs +++ /dev/null @@ -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 . -*/ -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()); - } - } - } - } -} \ No newline at end of file diff --git a/TShockAPI/TSPlayer.cs b/TShockAPI/TSPlayer.cs index f118390b..824758dc 100644 --- a/TShockAPI/TSPlayer.cs +++ b/TShockAPI/TSPlayer.cs @@ -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 . */ + using System; using System.Collections.Generic; using System.Diagnostics; @@ -27,61 +28,258 @@ namespace TShockAPI { public class TSPlayer { + /// + /// This represents the server as a player. + /// public static readonly TSServerPlayer Server = new TSServerPlayer(); + + /// + /// This player represents all the players. + /// public static readonly TSPlayer All = new TSPlayer("All"); + + /// + /// The amount of tiles that the player has killed in the last second. + /// public int TileKillThreshold { get; set; } - public int TilePlaceThreshold { get; set; } + + /// + /// The amount of tiles the player has placed in the last second. + /// + public int TilePlaceThreshold { get; set; } + + /// + /// The amount of liquid( in tiles ) that the player has placed in the last second. + /// public int TileLiquidThreshold { get; set; } + + /// + /// The number of projectiles created by the player in the last second. + /// public int ProjectileThreshold { get; set; } + + /// + /// A queue of tiles destroyed by the player for reverting. + /// public Dictionary TilesDestroyed { get; protected set; } + + /// + /// A queue of tiles placed by the player for reverting. + /// public Dictionary TilesCreated { get; protected set; } + public int FirstMaxHP { get; set; } + public int FirstMaxMP { get; set; } - public Group Group { get; set; } + + /// + /// The player's group. + /// + public Group Group + { + get + { + if (tempGroup != null) + return tempGroup; + return group; + } + set { group = value; } + } + + /// + /// The player's temporary group. This overrides the user's actual group. + /// + public Group tempGroup = null; + + private Group group = null; + public bool ReceivedInfo { get; set; } + + /// + /// The players index in the player array( Main.players[] ). + /// public int Index { get; protected set; } + + /// + /// The last time the player changed their team or pvp status. + /// public DateTime LastPvpChange; + + /// + /// Temp points for use in regions and other plugins. + /// public Point[] TempPoints = new Point[2]; + + /// + /// Whether the player is waiting to place/break a tile to set as a temp point. + /// public int AwaitingTempPoint { get; set; } + + /// + /// A list of command callbacks indexed by the command they need to do. + /// + public Dictionary> AwaitingResponse; + public bool AwaitingName { get; set; } + + public string[] AwaitingNameParameters { get; set; } + + /// + /// The last time a player broke a grief check. + /// public DateTime LastThreat { get; set; } + + /// + /// Not used, can be removed. + /// public DateTime LastTileChangeNotify { get; set; } + public bool InitSpawn; + + /// + /// Whether the player should see logs. + /// public bool DisplayLogs = true; + public Vector2 oldSpawn = Vector2.Zero; + + /// + /// The last player that the player whispered with( to or from ). + /// public TSPlayer LastWhisper; + + /// + /// The number of unsuccessful login attempts. + /// public int LoginAttempts { get; set; } + public Vector2 TeleportCoords = new Vector2(-1, -1); + public Vector2 LastNetPosition = Vector2.Zero; + + /// + /// The player's login name. + /// public string UserAccountName { get; set; } - public bool HasBeenSpammedWithBuildMessage; + + /// + /// 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. + /// + public bool LoginFailsBySsi { get; set; } + + /// + /// Whether the player is logged in or not. + /// public bool IsLoggedIn; + + /// + /// Whether the player has sent their whole inventory to the server while connecting. + /// + public bool HasSentInventory { get; set; } + + /// + /// The player's user id( from the db ). + /// public int UserID = -1; + + /// + /// Whether the player has been nagged about logging in. + /// public bool HasBeenNaggedAboutLoggingIn; - public bool TPAllow = true; + + public bool TPAllow = true; + + /// + /// Whether the player is muted or not. + /// public bool mute; + public bool TpLock; + private Player FakePlayer; + public bool RequestedSection; + + /// + /// The last time the player died. + /// public DateTime LastDeath { get; set; } + + /// + /// Whether the player is dead or not. + /// public bool Dead; + public string Country = "??"; + + /// + /// The players difficulty( normal[softcore], mediumcore, hardcore ). + /// public int Difficulty; + private string CacheIP; + public string IgnoreActionsForInventory = "none"; + public string IgnoreActionsForCheating = "none"; + public string IgnoreActionsForDisabledArmor = "none"; + public bool IgnoreActionsForClearingTrashCan; + + /// + /// The player's server side inventory data. + /// public PlayerData PlayerData; + + /// + /// Whether the player needs to specify a password upon connection( either server or user account ). + /// public bool RequiresPassword; + public bool SilentKickInProgress; + + public bool SilentJoinInProgress; + + /// + /// A list of points where ice tiles have been placed. + /// public List IceTiles; - public long RPm = 1; - public long WPm = 1; - public long SPm = 1; - public long BPm = 1; + + /// + /// Unused, can be removed. + /// + public long RPm = 1; + + /// + /// World protection message cool down. + /// + public long WPm = 1; + + /// + /// Spawn protection message cool down. + /// + public long SPm = 1; + + /// + /// Permission to build message cool down. + /// + public long BPm = 1; + + /// + /// The time in ms when the player has logged in. + /// public long LoginMS; + + /// + /// Whether the player has been harrassed about logging in due to server side inventory or forced login. + /// public bool LoginHarassed = false; + + /// + /// Whether the player is a real, human, player on the server. + /// 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(); + AwaitingResponse = new Dictionary>(); } 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>(); } 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); } + + /// + /// Adds a command callback to a specified command string. + /// + /// The string representing the command i.e "yes" == /yes + /// The method that will be executed on confirmation ie user accepts + public void AddResponse( string name, Action callback) + { + if( AwaitingResponse.ContainsKey(name)) + { + AwaitingResponse.Remove(name); + } + + AwaitingResponse.Add(name, callback); + } } - public class TSRestPlayer : TSServerPlayer + public class TSRestPlayer : TSPlayer { - internal List CommandReturn = new List(); + internal List CommandOutput = new List(); - public TSRestPlayer() + public TSRestPlayer(string playerName, Group playerGroup): base(playerName) { - Group = new SuperAdminGroup(); + Group = playerGroup; + AwaitingResponse = new Dictionary>(); } 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 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); } diff --git a/TShockAPI/TShock.cs b/TShockAPI/TShock.cs index 4324c0a7..7786f535 100644 --- a/TShockAPI/TShock.cs +++ b/TShockAPI/TShock.cs @@ -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 . */ + 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(); /// /// Used for implementing REST Tokens prior to the REST system starting up. /// - public static Dictionary RESTStartupTokens = new Dictionary(); + public static Dictionary RESTStartupTokens = new Dictionary(); /// /// 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; + } + } /// /// Handles exceptions that we didn't catch or that Red fucked up /// @@ -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; } diff --git a/TShockAPI/TShockAPI.csproj b/TShockAPI/TShockAPI.csproj index de62800c..bba42947 100644 --- a/TShockAPI/TShockAPI.csproj +++ b/TShockAPI/TShockAPI.csproj @@ -61,30 +61,27 @@ ..\SqlBins\MySql.Data.dll True - - False - ..\SqlBins\MySql.Web.dll - True - .\Newtonsoft.Json.dll - - - - - - + False .exe ..\TerrariaServerBins\TerrariaServer.exe - False + + + + + + + + @@ -114,11 +111,10 @@ - - + True True @@ -130,7 +126,6 @@ - @@ -184,7 +179,8 @@ - "$(ProjectDir)postbuild.bat" + + @@ -198,4 +194,4 @@ --> - + \ No newline at end of file diff --git a/TShockAPI/TShockAPI.licenseheader b/TShockAPI/TShockAPI.licenseheader index 12ed0ea9..5326a2f0 100644 --- a/TShockAPI/TShockAPI.licenseheader +++ b/TShockAPI/TShockAPI.licenseheader @@ -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 diff --git a/TShockAPI/UpdateManager.cs b/TShockAPI/UpdateManager.cs index c518aa76..27563744 100644 --- a/TShockAPI/UpdateManager.cs +++ b/TShockAPI/UpdateManager.cs @@ -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 . */ + using System; using System.Collections.Generic; using System.Net; diff --git a/TShockAPI/Utils.cs b/TShockAPI/Utils.cs index 5510e677..5a7483a4 100644 --- a/TShockAPI/Utils.cs +++ b/TShockAPI/Utils.cs @@ -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 . */ + using System; using System.Collections.Generic; using System.IO; @@ -33,12 +34,12 @@ namespace TShockAPI public class Utils { /// - /// Document me + /// The lowest id for a prefix. /// private const int FirstItemPrefix = 1; /// - /// Document me + /// The highest id for a prefix. /// private const int LastItemPrefix = 83; @@ -183,6 +184,7 @@ namespace TShockAPI /// Broadcasts a message to all players /// /// string message + [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)); } /// - /// Sends message to all users with 'logs' permission. + /// Sends message to all players with 'logs' permission. /// /// Message to send /// Color of the message - public void SendLogs(string log, Color color) + /// The player to not send the message to. + 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 } /// - /// Finds a TSPlayer based on name or id + /// Finds a TSPlayer based on name or ID /// - /// Player name + /// Player name or ID /// - public List FindPlayer(string ply) + public List FindPlayer(string plr) { var found = new List(); // 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 { 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 { player }; - } - } -// ReSharper disable EmptyGeneralCatchClause - catch (Exception e) -// ReSharper restore EmptyGeneralCatchClause - { - // Conversion failed - } - - string name = player.Name.ToLower(); - if (name.Equals(ply)) - return new List {player}; - if (name.Contains(ply)) - found.Add(player); + if (player != null) + { + // Must be an EXACT match + if (player.Name == plr) + return new List { player }; + if (player.Name.ToLower().StartsWith(plrLower)) + found.Add(player); + } } return found; } @@ -315,13 +315,13 @@ namespace TShockAPI /// Location X /// Location Y /// If the tile is valid - 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; } /// - /// Clears a tile + /// Checks to see if the tile is clear. /// /// Location X /// Location Y @@ -341,6 +341,8 @@ namespace TShockAPI int type = -1; if (int.TryParse(idOrName, out type)) { + if (type >= Main.maxItemTypes) + return new List(); return new List {GetItemById(type)}; } return GetItemByName(idOrName); @@ -365,30 +367,16 @@ namespace TShockAPI /// List of Items public List 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}; - } - //Method #2 - allows impartial matching var found = new List(); + 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}; - if (item.name.ToLower().StartsWith(name.ToLower())) - found.Add(item); - } - catch - { - } + item.netDefaults(i); + if (item.name.ToLower() == nameLower) + return new List {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 {GetNPCById(type)}; + if (type >= Main.maxNPCTypes) + return new List(); + return new List { GetNPCById(type) }; } return GetNPCByName(idOrName); } @@ -427,24 +417,16 @@ namespace TShockAPI /// List of matching NPCs public List GetNPCByName(string name) { - //Method #1 - must be exact match, allows support for different coloured slimes + var found = new List(); + 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}; - } - //Method #2 - allows impartial matching - var found = new List(); - 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}; - if (npc.name.ToLower().StartsWith(name.ToLower())) - found.Add(npc); + if (npc.name.ToLower() == nameLower) + return new List { npc }; + if (npc.name.ToLower().StartsWith(nameLower)) + found.Add((NPC)npc.Clone()); } return found; } @@ -476,15 +458,16 @@ namespace TShockAPI /// Matching list of buff ids public List 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 {i}; } var found = new List(); 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(); 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() { i }; + else if (prefixName.StartsWith(lowerName)) // Partial match + found.Add(i); } return found; } @@ -599,6 +562,36 @@ namespace TShockAPI Netplay.disconnect = true; } + /// + /// Stops the server after kicking all players with a reason message, and optionally saving the world then attempts to + /// restart it. + /// + /// bool perform a world save before stop (default: true) + /// string reason (default: "Server shutting down!") + 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); + } + + /// + /// Reloads all configuration settings, groups, regions and raises the reload event. + /// + 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 ""; } + /// + /// Default hashing algorithm. + /// public string HashAlgo = "sha512"; + /// + /// A dictionary of hashing algortihms and an implementation object. + /// public readonly Dictionary> HashTypes = new Dictionary> { {"sha512", () => new SHA512Managed()}, @@ -874,5 +873,25 @@ namespace TShockAPI } return new string(returnstr); } + + /// + /// Enumerates boundary points of the given region's rectangle. + /// + /// The region's area to enumerate through. + /// The enumerated boundary points. + public IEnumerable 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); + } + } } } diff --git a/TerrariaServerBins/TerrariaServer.exe b/TerrariaServerBins/TerrariaServer.exe index f8814727..c9081b0e 100644 Binary files a/TerrariaServerBins/TerrariaServer.exe and b/TerrariaServerBins/TerrariaServer.exe differ