Merge branch 'general-devel'

This commit is contained in:
Lucas Nicodemus 2015-03-07 19:21:31 -07:00
commit 0622350653
41 changed files with 2138 additions and 1735 deletions

View file

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

View file

@ -1,36 +1,40 @@
### Issue Guidelines ### Issue Guidelines
Please follow these simple requirements before posting an issue: Please follow these simple requirements before posting an issue:
1. TShock version number - TShock version number
2. Any stack traces that may have happened when the issue occurred - Any stack traces that may have happened when the issue occurred
3. How to reproduce the issue - How to reproduce the issue
- Screenshots of the issue (if applicable)
### TShock Additions
If something is better suited to be a plugin for TShock, rather than a TShock core feature, it should not be added!
### Pull Request Dev Guidelines ### Pull Request Dev Guidelines
These guidelines are for contributors. If you do not follow these guidelines your commits will be reverted. These guidelines are for all contributors.
Required: Required:
- Follow the code style. We generally use microsofts except for m_ infront of private variables. - Push code to the general-devel branch. Do not push it anywhere else.
- Do not push unfinished features to the master branch, instead create a remote branch and push to that. - Use tabs, not spaces.
- Do not push untested code to the master branch, instead push to the test branch. - Use UpperCamelCase for public function names.
- Document all compatibility issues in the COMPATIBILITY file. (IE file formats changing) - Prior to developing, make sure your clone is up to date with general-devel. This means that we don't get merge commits in your pull request.
- 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 ### Dev Team Guidelines
These guidelines are to be followed by all developers with commit level access to this repository: 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: - 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) - Major.Minor.Revision
- Do not release any development builds on the forums without consulting another developer first. - Do not release any development builds on the forums without consulting another developer first.
- __Document code prior to marking it done in JIRA__ - This is not a professional software product. Your results may vary with code quality, buginess, etc. Do not complain about something -- just fix it and move on.
- Move any un-tested code to the "Needs Validation" section on JIRA prior to marking it as done. - __Do not force push the repo__, or you will be removed.
- 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__. - __Do not revert commits__, unless you have sign-off from one other developer (the two-man rule), or you will be removed.
- Submit all pull requests to the general-devel branch prior to the master branch, or you will be ignored. - __This is not a meritocracy.__
#### Pull Request Acceptance Guidelines
- Don't ruin someone's first time sending a pull request. They feel demotivated, and then they won't want to push any more code for us.
- Don't accept untested pull requests from the outside world. Bamboo and Travis will at least make sure that something compiles, but actual code and execution tests are required.
- Pull request acceptance from internal contributors (anyone with write access) requires only one other approval to merge.
- Pull request acceptance from external contributors (anyone without write access) requires the [two-man rule](https://en.wikipedia.org/wiki/Two-man_rule) to be followed. If another man/woman/child in the two-man rule cannot be found within seven days, then this requirement is exempted.

View file

@ -1,8 +1,3 @@
# Current Status
This project is in maintenance mode. This means that the core team of developers' time is very limited, and only extremely game breaking bugs will be fixed. Improvements, new features, and minor issues will not be resolved by direct development until this time restriction has passed. Issues created reflecting these requests will not be worked on until this notice is removed.
Thanks for your continued support of TShock for Terraria.
# TShock [![Build Status](https://travis-ci.org/NyxStudios/TShock.png?branch=general-devel)](https://travis-ci.org/NyxStudios/TShock) # TShock [![Build Status](https://travis-ci.org/NyxStudios/TShock.png?branch=general-devel)](https://travis-ci.org/NyxStudios/TShock)
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. 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.
@ -21,11 +16,11 @@ TShock is a server modification for Terraria, written in C#, and based upon the
Feeling like helping out? Want to find an awesome server? Some awesome plugins? Feeling like helping out? Want to find an awesome server? Some awesome plugins?
* [Website & Forums](http://tshock.co/xf/) * [Website & Forums](https://tshock.co/xf/)
* [Wiki](https://tshock.atlassian.net/wiki/display/TSHOCKPLUGINS/Home) * [Wiki](https://tshock.atlassian.net/wiki/display/TSHOCKPLUGINS/Home)
* [IRC: #tshock @ irc.rizon.net](http://tshock.co/xf/index.php?ezirc/)
## Download ## Download
* [Github Releases](https://github.com/TShock/TShock/releases) * [Github Releases](https://github.com/TShock/TShock/releases)
* [Download Archive](https://github.com/TShock/TShock/downloads) * [Plugins](https://tshock.co/xf/index.php?resources/)
* [Very, very old versions of TShock](https://github.com/TShock/TShock/downloads)

View file

@ -61,13 +61,13 @@ namespace TShockAPI
if (worldpath != null && !Directory.Exists(worldpath)) if (worldpath != null && !Directory.Exists(worldpath))
Directory.CreateDirectory(worldpath); Directory.CreateDirectory(worldpath);
TShock.Utils.Broadcast("Server map saving, potential lag spike."); TSPlayer.All.SendInfoMessage("Server map saving, potential lag spike.");
Console.WriteLine("Backing up world..."); Console.WriteLine("Backing up world...");
SaveManager.Instance.SaveWorld(); SaveManager.Instance.SaveWorld();
Console.WriteLine("World backed up."); Console.WriteLine("World backed up.");
Console.ForegroundColor = ConsoleColor.Gray; Console.ForegroundColor = ConsoleColor.Gray;
Log.Info(string.Format("World backed up ({0}).", Main.worldPathName)); TShock.Log.Info(string.Format("World backed up ({0}).", Main.worldPathName));
Main.worldPathName = worldname; Main.worldPathName = worldname;
} }
@ -76,8 +76,8 @@ namespace TShockAPI
Console.ForegroundColor = ConsoleColor.Red; Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine("Backup failed!"); Console.WriteLine("Backup failed!");
Console.ForegroundColor = ConsoleColor.Gray; Console.ForegroundColor = ConsoleColor.Gray;
Log.Error("Backup failed!"); TShock.Log.Error("Backup failed!");
Log.Error(ex.ToString()); TShock.Log.Error(ex.ToString());
} }
} }

File diff suppressed because it is too large Load diff

View file

@ -106,11 +106,6 @@ namespace TShockAPI
[Description("Number of failed login attempts before kicking the player.")] [Description("Number of failed login attempts before kicking the player.")]
public int MaximumLoginAttempts = 3; public int MaximumLoginAttempts = 3;
[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.")] [Description("Used when replying to a rest /status request or sent to the client when UseServerName is true.")]
public string ServerName = ""; public string ServerName = "";
[Description("Sends ServerName in place of the world name to clients.")] [Description("Sends ServerName in place of the world name to clients.")]
@ -325,6 +320,12 @@ namespace TShockAPI
[Description("The path of the directory where logs should be written into.")] [Description("The path of the directory where logs should be written into.")]
public string LogPath = "tshock"; public string LogPath = "tshock";
[Description("Save logs to an SQL database instead of a text file. Default = false")]
public bool UseSqlLogs = false;
[Description("Number of times the SQL log must fail to insert logs before falling back to the text log")]
public int RevertToTextLogsOnSqlFailures = 10;
[Description("Prevents players from placing tiles with an invalid style.")] [Description("Prevents players from placing tiles with an invalid style.")]
public bool PreventInvalidPlaceStyle = true; public bool PreventInvalidPlaceStyle = true;
@ -367,9 +368,12 @@ namespace TShockAPI
[Description("Allows anyone to break grass, pots, etc.")] [Description("Allows anyone to break grass, pots, etc.")]
public bool AllowCutTilesAndBreakables = false; public bool AllowCutTilesAndBreakables = false;
[Description("Specifies which string starts a command")] [Description("Specifies which string starts a command.")]
public string CommandSpecifier = "/"; public string CommandSpecifier = "/";
[Description("Specifies which string starts a command silently.")]
public string CommandSilentSpecifier = ".";
[Description("Kicks a hardcore player on death.")] [Description("Kicks a hardcore player on death.")]
public bool KickOnHardcoreDeath; public bool KickOnHardcoreDeath;
@ -391,6 +395,9 @@ namespace TShockAPI
[Description("The maximum allowable MP, before equipment buffs.")] [Description("The maximum allowable MP, before equipment buffs.")]
public int MaxMP = 200; public int MaxMP = 200;
[Description("Determines if the server should save the world if the last player exits.")]
public bool SaveWorldOnLastPlayerExit = true;
/// <summary> /// <summary>
/// Reads a configuration file from a given path /// Reads a configuration file from a given path
/// </summary> /// </summary>

View file

@ -72,7 +72,7 @@ namespace TShockAPI.DB
} }
catch (Exception ex) catch (Exception ex)
{ {
Log.Error(ex.ToString()); TShock.Log.Error(ex.ToString());
} }
return null; return null;
} }
@ -96,7 +96,7 @@ namespace TShockAPI.DB
} }
catch (Exception ex) catch (Exception ex)
{ {
Log.Error(ex.ToString()); TShock.Log.Error(ex.ToString());
Console.WriteLine(ex.StackTrace); Console.WriteLine(ex.StackTrace);
} }
return null; return null;
@ -123,7 +123,7 @@ namespace TShockAPI.DB
} }
catch (Exception ex) catch (Exception ex)
{ {
Log.Error(ex.ToString()); TShock.Log.Error(ex.ToString());
} }
return null; return null;
} }
@ -145,18 +145,11 @@ namespace TShockAPI.DB
} }
catch (Exception ex) catch (Exception ex)
{ {
Log.Error(ex.ToString()); TShock.Log.Error(ex.ToString());
} }
return null; return null;
} }
#if COMPAT_SIGS
[Obsolete("This method is for signature compatibility for external code only")]
public bool AddBan(string ip, string name, string reason)
{
return AddBan(ip, name, "", reason, false, "", "");
}
#endif
public bool AddBan(string ip, string name = "", string uuid = "", string reason = "", bool exceptions = false, string banner = "", string expiration = "") public bool AddBan(string ip, string name = "", string uuid = "", string reason = "", bool exceptions = false, string banner = "", string expiration = "")
{ {
try try
@ -167,18 +160,11 @@ namespace TShockAPI.DB
{ {
if (exceptions) if (exceptions)
throw ex; throw ex;
Log.Error(ex.ToString()); TShock.Log.Error(ex.ToString());
} }
return false; return false;
} }
#if COMPAT_SIGS
[Obsolete("This method is for signature compatibility for external code only")]
public bool RemoveBan(string ip)
{
return RemoveBan(ip, false, true, false);
}
#endif
public bool RemoveBan(string match, bool byName = false, bool casesensitive = true, bool exceptions = false) public bool RemoveBan(string match, bool byName = false, bool casesensitive = true, bool exceptions = false)
{ {
try try
@ -193,7 +179,7 @@ namespace TShockAPI.DB
{ {
if (exceptions) if (exceptions)
throw ex; throw ex;
Log.Error(ex.ToString()); TShock.Log.Error(ex.ToString());
} }
return false; return false;
} }
@ -206,7 +192,7 @@ namespace TShockAPI.DB
} }
catch (Exception ex) catch (Exception ex)
{ {
Log.Error(ex.ToString()); TShock.Log.Error(ex.ToString());
} }
return false; return false;
} }

View file

@ -95,7 +95,7 @@ namespace TShockAPI.DB
} }
catch (Exception ex) catch (Exception ex)
{ {
Log.Error(ex.ToString()); TShock.Log.Error(ex.ToString());
} }
return playerData; return playerData;
@ -104,7 +104,7 @@ namespace TShockAPI.DB
public bool SeedInitialData(User user) public bool SeedInitialData(User user)
{ {
var inventory = new StringBuilder(); var inventory = new StringBuilder();
for (int i = 0; i < Terraria.Main.maxInventory; i++) for (int i = 0; i < NetItem.maxNetInventory; i++)
{ {
if (i > 0) if (i > 0)
{ {
@ -137,7 +137,7 @@ namespace TShockAPI.DB
} }
catch (Exception ex) catch (Exception ex)
{ {
Log.Error(ex.ToString()); TShock.Log.Error(ex.ToString());
} }
return false; return false;
@ -162,7 +162,7 @@ namespace TShockAPI.DB
} }
catch (Exception ex) catch (Exception ex)
{ {
Log.Error(ex.ToString()); TShock.Log.Error(ex.ToString());
} }
} }
else else
@ -176,7 +176,7 @@ namespace TShockAPI.DB
} }
catch (Exception ex) catch (Exception ex)
{ {
Log.Error(ex.ToString()); TShock.Log.Error(ex.ToString());
} }
} }
return false; return false;
@ -191,7 +191,7 @@ namespace TShockAPI.DB
} }
catch (Exception ex) catch (Exception ex)
{ {
Log.Error(ex.ToString()); TShock.Log.Error(ex.ToString());
} }
return false; return false;

View file

@ -137,7 +137,7 @@ namespace TShockAPI.DB
var error = "Invalid parent {0} for group {1}".SFormat(parentname, group.Name); var error = "Invalid parent {0} for group {1}".SFormat(parentname, group.Name);
if (exceptions) if (exceptions)
throw new GroupManagerException(error); throw new GroupManagerException(error);
Log.ConsoleError(error); TShock.Log.ConsoleError(error);
return error; return error;
} }
group.Parent = parent; group.Parent = parent;
@ -162,19 +162,6 @@ namespace TShockAPI.DB
return AddGroup(name, null, permissions, Group.defaultChatColor, false); return AddGroup(name, null, permissions, Group.defaultChatColor, false);
} }
#if COMPAT_SIGS
[Obsolete("This method is for signature compatibility for external code only")]
public String AddGroup(String name, string parentname, String permissions)
{
return AddGroup(name, parentname, permissions, Group.defaultChatColor, false);
}
[Obsolete("This method is for signature compatibility for external code only")]
public String AddGroup(String name, string parentname, String permissions, String chatcolor)
{
return AddGroup(name, parentname, permissions, chatcolor, false);
}
#endif
/// <summary> /// <summary>
/// Updates a group including permissions /// Updates a group including permissions
/// </summary> /// </summary>
@ -224,13 +211,6 @@ namespace TShockAPI.DB
group.Suffix = suffix; group.Suffix = suffix;
} }
#if COMPAT_SIGS
[Obsolete("This method is for signature compatibility for external code only")]
public String DeleteGroup(String name)
{
return DeleteGroup(name, false);
}
#endif
public String DeleteGroup(String name, bool exceptions = false) public String DeleteGroup(String name, bool exceptions = false)
{ {
if (!GroupExists(name)) if (!GroupExists(name))
@ -298,7 +278,7 @@ namespace TShockAPI.DB
string groupName = reader.Get<string>("GroupName"); string groupName = reader.Get<string>("GroupName");
if (groupName == "superadmin") if (groupName == "superadmin")
{ {
Log.ConsoleInfo("WARNING: Group \"superadmin\" is defined in the database even though it's a reserved group name."); TShock.Log.ConsoleInfo("WARNING: Group \"superadmin\" is defined in the database even though it's a reserved group name.");
continue; continue;
} }
@ -314,7 +294,7 @@ namespace TShockAPI.DB
catch (ArgumentException) catch (ArgumentException)
{ {
// Just in case somebody messed with the unique primary key. // Just in case somebody messed with the unique primary key.
Log.ConsoleError("ERROR: Group name \"{0}\" occurs more than once. Keeping current group settings."); TShock.Log.ConsoleError("ERROR: Group name \"{0}\" occurs more than once. Keeping current group settings.");
return; return;
} }
} }
@ -349,14 +329,14 @@ namespace TShockAPI.DB
group.Parent = groups.FirstOrDefault(g => g.Name == parentGroupName); group.Parent = groups.FirstOrDefault(g => g.Name == parentGroupName);
if (group.Parent == null) if (group.Parent == null)
{ {
Log.ConsoleError( TShock.Log.ConsoleError(
"ERROR: Group \"{0}\" is referencing non existent parent group \"{1}\", parent reference was removed.", "ERROR: Group \"{0}\" is referencing non existent parent group \"{1}\", parent reference was removed.",
group.Name, parentGroupName); group.Name, parentGroupName);
} }
else else
{ {
if (group.Parent == group) if (group.Parent == group)
Log.ConsoleInfo( TShock.Log.ConsoleInfo(
"WARNING: Group \"{0}\" is referencing itself as parent group, parent reference was removed.", group.Name); "WARNING: Group \"{0}\" is referencing itself as parent group, parent reference was removed.", group.Name);
List<Group> groupChain = new List<Group> { group }; List<Group> groupChain = new List<Group> { group };
@ -365,7 +345,7 @@ namespace TShockAPI.DB
{ {
if (groupChain.Contains(checkingGroup.Parent)) if (groupChain.Contains(checkingGroup.Parent))
{ {
Log.ConsoleError( TShock.Log.ConsoleError(
"ERROR: Group \"{0}\" is referencing parent group \"{1}\" which is already part of the parent chain. Parent reference removed.", "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.Name, checkingGroup.Parent.Name);
@ -386,7 +366,7 @@ namespace TShockAPI.DB
} }
catch (Exception ex) catch (Exception ex)
{ {
Log.ConsoleError("Error on reloading groups: " + ex); TShock.Log.ConsoleError("Error on reloading groups: " + ex);
} }
} }
} }

View file

@ -71,7 +71,7 @@ namespace TShockAPI.DB
} }
catch (Exception ex) catch (Exception ex)
{ {
Log.Error(ex.ToString()); TShock.Log.Error(ex.ToString());
} }
} }
@ -86,7 +86,7 @@ namespace TShockAPI.DB
} }
catch (Exception ex) catch (Exception ex)
{ {
Log.Error(ex.ToString()); TShock.Log.Error(ex.ToString());
} }
} }
@ -126,7 +126,7 @@ namespace TShockAPI.DB
} }
catch (Exception ex) catch (Exception ex)
{ {
Log.Error(ex.ToString()); TShock.Log.Error(ex.ToString());
} }
} }
@ -150,7 +150,7 @@ namespace TShockAPI.DB
} }
catch (Exception ex) catch (Exception ex)
{ {
Log.Error(ex.ToString()); TShock.Log.Error(ex.ToString());
} }
} }
return false; return false;

View file

@ -72,7 +72,7 @@ namespace TShockAPI.DB
} }
catch (Exception ex) catch (Exception ex)
{ {
Log.Error(ex.ToString()); TShock.Log.Error(ex.ToString());
} }
} }
@ -87,7 +87,7 @@ namespace TShockAPI.DB
} }
catch (Exception ex) catch (Exception ex)
{ {
Log.Error(ex.ToString()); TShock.Log.Error(ex.ToString());
} }
} }
@ -131,7 +131,7 @@ namespace TShockAPI.DB
} }
catch (Exception ex) catch (Exception ex)
{ {
Log.Error(ex.ToString()); TShock.Log.Error(ex.ToString());
} }
} }
@ -155,7 +155,7 @@ namespace TShockAPI.DB
} }
catch (Exception ex) catch (Exception ex)
{ {
Log.Error(ex.ToString()); TShock.Log.Error(ex.ToString());
} }
} }
return false; return false;

View file

@ -94,15 +94,15 @@ namespace TShockAPI.DB
if (Int32.TryParse(splitids[i], out id)) // if unparsable, it's not an int, so silently skip if (Int32.TryParse(splitids[i], out id)) // if unparsable, it's not an int, so silently skip
r.AllowedIDs.Add(id); r.AllowedIDs.Add(id);
else else
Log.Warn("One of your UserIDs is not a usable integer: " + splitids[i]); TShock.Log.Warn("One of your UserIDs is not a usable integer: " + splitids[i]);
} }
} }
catch (Exception e) catch (Exception e)
{ {
Log.Error("Your database contains invalid UserIDs (they should be ints)."); TShock.Log.Error("Your database contains invalid UserIDs (they should be ints).");
Log.Error("A lot of things will fail because of this. You must manually delete and re-create the allowed field."); TShock.Log.Error("A lot of things will fail because of this. You must manually delete and re-create the allowed field.");
Log.Error(e.ToString()); TShock.Log.Error(e.ToString());
Log.Error(e.StackTrace); TShock.Log.Error(e.StackTrace);
} }
Regions.Add(r); Regions.Add(r);
@ -111,10 +111,22 @@ namespace TShockAPI.DB
} }
catch (Exception ex) catch (Exception ex)
{ {
Log.Error(ex.ToString()); TShock.Log.Error(ex.ToString());
} }
} }
/// <summary>
/// Adds a region to the database.
/// </summary>
/// <param name="tx">TileX of the top left corner.</param>
/// <param name="ty">TileY of the top left corner.</param>
/// <param name="width">Width of the region in tiles.</param>
/// <param name="height">Height of the region in tiles.</param>
/// <param name="regionname">The name of the region.</param>
/// <param name="owner">The User Account Name of the person who created this region.</param>
/// <param name="worldid">The world id that this region is in.</param>
/// <param name="z">The Z index of the region.</param>
/// <returns>Whether the region was created and added successfully.</returns>
public bool AddRegion(int tx, int ty, int width, int height, string regionname, string owner, string worldid, int z = 0) public bool AddRegion(int tx, int ty, int width, int height, string regionname, string owner, string worldid, int z = 0)
{ {
if (GetRegionByName(regionname) != null) if (GetRegionByName(regionname) != null)
@ -126,28 +138,37 @@ namespace TShockAPI.DB
database.Query( database.Query(
"INSERT INTO Regions (X1, Y1, width, height, RegionName, WorldID, UserIds, Protected, Groups, Owner, Z) VALUES (@0, @1, @2, @3, @4, @5, @6, @7, @8, @9, @10);", "INSERT INTO Regions (X1, Y1, width, height, RegionName, WorldID, UserIds, Protected, Groups, Owner, Z) VALUES (@0, @1, @2, @3, @4, @5, @6, @7, @8, @9, @10);",
tx, ty, width, height, regionname, worldid, "", 1, "", owner, z); tx, ty, width, height, regionname, worldid, "", 1, "", owner, z);
Regions.Add(new Region(new Rectangle(tx, ty, width, height), regionname, owner, true, worldid, z)); var region = new Region(new Rectangle(tx, ty, width, height), regionname, owner, true, worldid, z);
Regions.Add(region);
Hooks.RegionHooks.OnRegionCreated(region);
return true; return true;
} }
catch (Exception ex) catch (Exception ex)
{ {
Log.Error(ex.ToString()); TShock.Log.Error(ex.ToString());
} }
return false; return false;
} }
/// <summary>
/// Deletes the region from this world with a given name.
/// </summary>
/// <param name="name">The name of the region to delete.</param>
/// <returns>Whether the region was successfully deleted.</returns>
public bool DeleteRegion(string name) public bool DeleteRegion(string name)
{ {
try try
{ {
database.Query("DELETE FROM Regions WHERE RegionName=@0 AND WorldID=@1", name, Main.worldID.ToString()); database.Query("DELETE FROM Regions WHERE RegionName=@0 AND WorldID=@1", name, Main.worldID.ToString());
var worldid = Main.worldID.ToString(); var worldid = Main.worldID.ToString();
var region = Regions.FirstOrDefault(r => r.Name == name && r.WorldID == worldid);
Regions.RemoveAll(r => r.Name == name && r.WorldID == worldid); Regions.RemoveAll(r => r.Name == name && r.WorldID == worldid);
Hooks.RegionHooks.OnRegionDeleted(region);
return true; return true;
} }
catch (Exception ex) catch (Exception ex)
{ {
Log.Error(ex.ToString()); TShock.Log.Error(ex.ToString());
} }
return false; return false;
} }
@ -165,7 +186,7 @@ namespace TShockAPI.DB
} }
catch (Exception ex) catch (Exception ex)
{ {
Log.Error(ex.ToString()); TShock.Log.Error(ex.ToString());
return false; return false;
} }
} }
@ -182,7 +203,7 @@ namespace TShockAPI.DB
} }
catch (Exception ex) catch (Exception ex)
{ {
Log.Error(ex.ToString()); TShock.Log.Error(ex.ToString());
return false; return false;
} }
} }
@ -308,7 +329,7 @@ namespace TShockAPI.DB
} }
catch (Exception ex) catch (Exception ex)
{ {
Log.Error(ex.ToString()); TShock.Log.Error(ex.ToString());
} }
return false; return false;
} }
@ -363,7 +384,7 @@ namespace TShockAPI.DB
} }
catch (Exception ex) catch (Exception ex)
{ {
Log.Error(ex.ToString()); TShock.Log.Error(ex.ToString());
} }
return false; return false;
} }
@ -390,7 +411,7 @@ namespace TShockAPI.DB
} }
catch (Exception ex) catch (Exception ex)
{ {
Log.Error(ex.ToString()); TShock.Log.Error(ex.ToString());
} }
return false; return false;
} }
@ -413,7 +434,7 @@ namespace TShockAPI.DB
} }
catch (Exception ex) catch (Exception ex)
{ {
Log.Error(ex.ToString()); TShock.Log.Error(ex.ToString());
} }
return regions; return regions;
} }
@ -518,7 +539,7 @@ namespace TShockAPI.DB
} }
catch (Exception ex) catch (Exception ex)
{ {
Log.Error(ex.ToString()); TShock.Log.Error(ex.ToString());
return false; return false;
} }
} }

View file

@ -66,7 +66,7 @@ namespace TShockAPI.DB
} }
catch (Exception ex) catch (Exception ex)
{ {
Log.Error(ex.ToString()); TShock.Log.Error(ex.ToString());
} }
return new Vector2(); return new Vector2();
@ -88,7 +88,7 @@ namespace TShockAPI.DB
} }
catch (Exception ex) catch (Exception ex)
{ {
Log.Error(ex.ToString()); TShock.Log.Error(ex.ToString());
} }
return new Vector2(); return new Vector2();
@ -105,7 +105,7 @@ namespace TShockAPI.DB
} }
catch (Exception ex) catch (Exception ex)
{ {
Log.Error(ex.ToString()); TShock.Log.Error(ex.ToString());
} }
} }
else else
@ -117,7 +117,7 @@ namespace TShockAPI.DB
} }
catch (Exception ex) catch (Exception ex)
{ {
Log.Error(ex.ToString()); TShock.Log.Error(ex.ToString());
} }
} }
} }

View file

@ -79,19 +79,7 @@ namespace TShockAPI.DB
[Obsolete("This method will be replaced by EnsureTableExists.")] [Obsolete("This method will be replaced by EnsureTableExists.")]
public void EnsureExists(SqlTable table) public void EnsureExists(SqlTable table)
{ {
var columns = GetColumns(table); EnsureTableStructure(table);
if (columns.Count > 0)
{
if (!table.Columns.All(c => columns.Contains(c.Name)) || !columns.All(c => table.Columns.Any(c2 => c2.Name == c)))
{
var from = new SqlTable(table.Name, columns.Select(s => new SqlColumn(s, MySqlDbType.String)).ToList());
database.Query(creator.AlterTable(from, table));
}
}
else
{
database.Query(creator.CreateTable(table));
}
} }
public List<string> GetColumns(SqlTable table) public List<string> GetColumns(SqlTable table)

View file

@ -72,7 +72,7 @@ namespace TShockAPI.DB
} }
catch (Exception ex) catch (Exception ex)
{ {
Log.Error(ex.ToString()); TShock.Log.Error(ex.ToString());
} }
} }
@ -87,7 +87,7 @@ namespace TShockAPI.DB
} }
catch (Exception ex) catch (Exception ex)
{ {
Log.Error(ex.ToString()); TShock.Log.Error(ex.ToString());
} }
} }
@ -131,7 +131,7 @@ namespace TShockAPI.DB
} }
catch (Exception ex) catch (Exception ex)
{ {
Log.Error(ex.ToString()); TShock.Log.Error(ex.ToString());
} }
} }
@ -155,7 +155,7 @@ namespace TShockAPI.DB
} }
catch (Exception ex) catch (Exception ex)
{ {
Log.Error(ex.ToString()); TShock.Log.Error(ex.ToString());
} }
} }
return false; return false;

View file

@ -197,7 +197,7 @@ namespace TShockAPI.DB
} }
catch (Exception ex) catch (Exception ex)
{ {
Log.ConsoleError("FetchHashedPasswordAndGroup SQL returned an error: " + ex); TShock.Log.ConsoleError("FetchHashedPasswordAndGroup SQL returned an error: " + ex);
} }
return -1; return -1;
} }
@ -285,7 +285,7 @@ namespace TShockAPI.DB
} }
catch (Exception ex) catch (Exception ex)
{ {
Log.Error(ex.ToString()); TShock.Log.Error(ex.ToString());
} }
return null; return null;
} }

View file

@ -74,7 +74,7 @@ namespace TShockAPI.DB
} }
catch (Exception ex) catch (Exception ex)
{ {
Log.Error(ex.ToString()); TShock.Log.Error(ex.ToString());
} }
return false; return false;
} }
@ -117,7 +117,7 @@ namespace TShockAPI.DB
} }
catch (Exception ex) catch (Exception ex)
{ {
Log.Error(ex.ToString()); TShock.Log.Error(ex.ToString());
} }
return false; return false;
} }
@ -162,7 +162,7 @@ namespace TShockAPI.DB
} }
catch (Exception ex) catch (Exception ex)
{ {
Log.Error(ex.ToString()); TShock.Log.Error(ex.ToString());
} }
return false; return false;
} }
@ -186,7 +186,7 @@ namespace TShockAPI.DB
} }
catch (Exception ex) catch (Exception ex)
{ {
Log.Error(ex.ToString()); TShock.Log.Error(ex.ToString());
} }
return false; return false;
} }

View file

@ -62,10 +62,10 @@ namespace TShockAPI
/// </summary> /// </summary>
public class TileEditEventArgs : HandledEventArgs public class TileEditEventArgs : HandledEventArgs
{ {
/// <summary> /// <summary>
/// The TSPlayer who made the tile edit /// The TSPlayer who made the tile edit
/// </summary> /// </summary>
public TSPlayer Player { get; set; } public TSPlayer Player { get; set; }
/// <summary> /// <summary>
/// The tile coordinate on the X plane /// The tile coordinate on the X plane
@ -87,10 +87,10 @@ namespace TShockAPI
/// </summary> /// </summary>
public EditAction Action { get; set; } public EditAction Action { get; set; }
/// <summary> /// <summary>
/// Did the tile get destroyed successfully. /// Did the tile get destroyed successfully.
/// </summary> /// </summary>
public EditType editDetail { get; set; } public EditType editDetail { get; set; }
/// <summary> /// <summary>
/// Used when a tile is placed to denote a subtype of tile. (e.g. for tile id 21: Chest = 0, Gold Chest = 1) /// Used when a tile is placed to denote a subtype of tile. (e.g. for tile id 21: Chest = 0, Gold Chest = 1)
@ -109,12 +109,12 @@ namespace TShockAPI
var args = new TileEditEventArgs var args = new TileEditEventArgs
{ {
Player = ply, Player = ply,
X = x, X = x,
Y = y, Y = y,
Action = action, Action = action,
EditData = editData, EditData = editData,
editDetail = editDetail, editDetail = editDetail,
Style = style Style = style
}; };
TileEdit.Invoke(null, args); TileEdit.Invoke(null, args);
@ -152,37 +152,37 @@ namespace TShockAPI
return args.Handled; return args.Handled;
} }
/// <summary> /// <summary>
/// For use in a PlayerTeam event /// For use in a PlayerTeam event
/// </summary> /// </summary>
public class PlayerTeamEventArgs : HandledEventArgs public class PlayerTeamEventArgs : HandledEventArgs
{ {
/// <summary> /// <summary>
/// The Terraria player ID of the player /// The Terraria player ID of the player
/// </summary> /// </summary>
public byte PlayerId { get; set; } public byte PlayerId { get; set; }
/// <summary> /// <summary>
/// Enable/disable pvp? /// Enable/disable pvp?
/// </summary> /// </summary>
public byte Team { get; set; } public byte Team { get; set; }
} }
/// <summary> /// <summary>
/// TogglePvp - called when a player toggles pvp /// TogglePvp - called when a player toggles pvp
/// </summary> /// </summary>
public static HandlerList<PlayerTeamEventArgs> PlayerTeam; public static HandlerList<PlayerTeamEventArgs> PlayerTeam;
private static bool OnPlayerTeam(byte _id, byte _team) private static bool OnPlayerTeam(byte _id, byte _team)
{ {
if (PlayerTeam == null) if (PlayerTeam == null)
return false; return false;
var args = new PlayerTeamEventArgs var args = new PlayerTeamEventArgs
{ {
PlayerId = _id, PlayerId = _id,
Team = _team, Team = _team,
}; };
PlayerTeam.Invoke(null, args); PlayerTeam.Invoke(null, args);
return args.Handled; return args.Handled;
} }
/// <summary> /// <summary>
/// For use in a PlayerSlot event /// For use in a PlayerSlot event
@ -1261,7 +1261,7 @@ namespace TShockAPI
} }
catch (Exception ex) catch (Exception ex)
{ {
Log.Error(ex.ToString()); TShock.Log.Error(ex.ToString());
return true; return true;
} }
} }
@ -1469,7 +1469,7 @@ namespace TShockAPI
TShock.CharacterDB.InsertPlayerData(args.Player); TShock.CharacterDB.InsertPlayerData(args.Player);
} }
args.Player.SendMessage("Authenticated as " + args.Player.Name + " successfully.", Color.LimeGreen); args.Player.SendMessage("Authenticated as " + args.Player.Name + " successfully.", Color.LimeGreen);
Log.ConsoleInfo(args.Player.Name + " authenticated successfully as user " + args.Player.Name + "."); TShock.Log.ConsoleInfo(args.Player.Name + " authenticated successfully as user " + args.Player.Name + ".");
Hooks.PlayerHooks.OnPlayerPostLogin(args.Player); Hooks.PlayerHooks.OnPlayerPostLogin(args.Player);
return true; return true;
} }
@ -1500,56 +1500,56 @@ namespace TShockAPI
string password = args.Data.ReadString(); string password = args.Data.ReadString();
if (Hooks.PlayerHooks.OnPlayerPreLogin(args.Player, args.Player.Name, password)) if (Hooks.PlayerHooks.OnPlayerPreLogin(args.Player, args.Player.Name, password))
return true; return true;
var user = TShock.Users.GetUserByName(args.Player.Name); var user = TShock.Users.GetUserByName(args.Player.Name);
if (user != null && !TShock.Config.DisableLoginBeforeJoin) if (user != null && !TShock.Config.DisableLoginBeforeJoin)
{ {
string encrPass = TShock.Utils.HashPassword(password); string encrPass = TShock.Utils.HashPassword(password);
if (user.Password.ToUpper() == encrPass.ToUpper()) if (user.Password.ToUpper() == encrPass.ToUpper())
{ {
args.Player.RequiresPassword = false; args.Player.RequiresPassword = false;
args.Player.PlayerData = TShock.CharacterDB.GetPlayerData(args.Player, TShock.Users.GetUserID(args.Player.Name)); args.Player.PlayerData = TShock.CharacterDB.GetPlayerData(args.Player, TShock.Users.GetUserID(args.Player.Name));
if (args.Player.State == 1) if (args.Player.State == 1)
args.Player.State = 2; args.Player.State = 2;
NetMessage.SendData((int) PacketTypes.WorldInfo, args.Player.Index); NetMessage.SendData((int) PacketTypes.WorldInfo, args.Player.Index);
var group = TShock.Utils.GetGroup(user.Group); var group = TShock.Utils.GetGroup(user.Group);
if (Main.ServerSideCharacter) if (Main.ServerSideCharacter)
{ {
if (group.HasPermission(Permissions.bypassssc)) if (group.HasPermission(Permissions.bypassssc))
{ {
args.Player.IgnoreActionsForClearingTrashCan = false; args.Player.IgnoreActionsForClearingTrashCan = false;
} }
args.Player.PlayerData.RestoreCharacter(args.Player); args.Player.PlayerData.RestoreCharacter(args.Player);
} }
args.Player.LoginFailsBySsi = false; args.Player.LoginFailsBySsi = false;
if (group.HasPermission(Permissions.ignorestackhackdetection)) if (group.HasPermission(Permissions.ignorestackhackdetection))
args.Player.IgnoreActionsForCheating = "none"; args.Player.IgnoreActionsForCheating = "none";
if (group.HasPermission(Permissions.usebanneditem)) if (group.HasPermission(Permissions.usebanneditem))
args.Player.IgnoreActionsForDisabledArmor = "none"; args.Player.IgnoreActionsForDisabledArmor = "none";
args.Player.Group = group; args.Player.Group = group;
args.Player.tempGroup = null; args.Player.tempGroup = null;
args.Player.UserAccountName = args.Player.Name; args.Player.UserAccountName = args.Player.Name;
args.Player.UserID = TShock.Users.GetUserID(args.Player.UserAccountName); args.Player.UserID = TShock.Users.GetUserID(args.Player.UserAccountName);
args.Player.IsLoggedIn = true; args.Player.IsLoggedIn = true;
args.Player.IgnoreActionsForInventory = "none"; args.Player.IgnoreActionsForInventory = "none";
if (!args.Player.IgnoreActionsForClearingTrashCan && Main.ServerSideCharacter) if (!args.Player.IgnoreActionsForClearingTrashCan && Main.ServerSideCharacter)
{ {
args.Player.PlayerData.CopyCharacter(args.Player); args.Player.PlayerData.CopyCharacter(args.Player);
TShock.CharacterDB.InsertPlayerData(args.Player); TShock.CharacterDB.InsertPlayerData(args.Player);
} }
args.Player.SendMessage("Authenticated as " + args.Player.Name + " successfully.", Color.LimeGreen); args.Player.SendMessage("Authenticated as " + args.Player.Name + " successfully.", Color.LimeGreen);
Log.ConsoleInfo(args.Player.Name + " authenticated successfully as user " + args.Player.Name + "."); TShock.Log.ConsoleInfo(args.Player.Name + " authenticated successfully as user " + args.Player.Name + ".");
TShock.Users.SetUserUUID(user, args.Player.UUID); TShock.Users.SetUserUUID(user, args.Player.UUID);
Hooks.PlayerHooks.OnPlayerPostLogin(args.Player); Hooks.PlayerHooks.OnPlayerPostLogin(args.Player);
return true; return true;
} }
TShock.Utils.ForceKick(args.Player, "Invalid user account password.", true); TShock.Utils.ForceKick(args.Player, "Invalid user account password.", true);
@ -1577,7 +1577,7 @@ namespace TShockAPI
{ {
if (args.Player.RequestedSection) if (args.Player.RequestedSection)
return true; return true;
args.Player.RequestedSection = true; args.Player.RequestedSection = true;
if (String.IsNullOrEmpty(args.Player.Name)) if (String.IsNullOrEmpty(args.Player.Name))
{ {
TShock.Utils.ForceKick(args.Player, "Blank name.", true); TShock.Utils.ForceKick(args.Player, "Blank name.", true);
@ -2180,15 +2180,15 @@ namespace TShockAPI
return false; return false;
} }
private static bool HandlePlayerTeam(GetDataHandlerArgs args) private static bool HandlePlayerTeam(GetDataHandlerArgs args)
{ {
byte id = args.Data.ReadInt8(); byte id = args.Data.ReadInt8();
byte team = args.Data.ReadInt8(); byte team = args.Data.ReadInt8();
if (OnPlayerTeam(id, team)) if (OnPlayerTeam(id, team))
return true; return true;
if (id != args.Player.Index) if (id != args.Player.Index)
return true; return true;
if ((DateTime.UtcNow - args.Player.LastPvPTeamChange).TotalSeconds < 5) if ((DateTime.UtcNow - args.Player.LastPvPTeamChange).TotalSeconds < 5)
{ {
@ -2197,8 +2197,8 @@ namespace TShockAPI
} }
args.Player.LastPvPTeamChange = DateTime.UtcNow; args.Player.LastPvPTeamChange = DateTime.UtcNow;
return false; return false;
} }
private static bool HandlePlayerUpdate(GetDataHandlerArgs args) private static bool HandlePlayerUpdate(GetDataHandlerArgs args)
{ {
@ -2232,34 +2232,30 @@ namespace TShockAPI
if (!pos.Equals(args.Player.LastNetPosition)) if (!pos.Equals(args.Player.LastNetPosition))
{ {
float distance = Vector2.Distance(new Vector2(pos.X/16f, pos.Y/16f), float distance = Vector2.Distance(new Vector2(pos.X/16f, pos.Y/16f),
new Vector2(args.Player.LastNetPosition.X/16f, args.Player.LastNetPosition.Y/16f)); new Vector2(args.Player.LastNetPosition.X/16f, args.Player.LastNetPosition.Y/16f));
if (TShock.CheckIgnores(args.Player)) if (TShock.CheckIgnores(args.Player))
{ {
if (distance > TShock.Config.MaxRangeForDisabled) if (distance > TShock.Config.MaxRangeForDisabled)
{ {
if (args.Player.IgnoreActionsForCheating != "none") if (args.Player.IgnoreActionsForCheating != "none")
{ {
args.Player.SendMessage("Disabled for cheating: " + args.Player.IgnoreActionsForCheating, args.Player.SendErrorMessage("Disabled for cheating: " + args.Player.IgnoreActionsForCheating);
Color.Red);
} }
else if (args.Player.IgnoreActionsForDisabledArmor != "none") else if (args.Player.IgnoreActionsForDisabledArmor != "none")
{ {
args.Player.SendMessage( args.Player.SendErrorMessage("Disabled for banned armor: " + args.Player.IgnoreActionsForDisabledArmor);
"Disabled for banned armor: " + args.Player.IgnoreActionsForDisabledArmor, Color.Red);
} }
else if (args.Player.IgnoreActionsForInventory != "none") else if (args.Player.IgnoreActionsForInventory != "none")
{ {
args.Player.SendMessage( args.Player.SendErrorMessage("Disabled for Server Side Inventory: " + args.Player.IgnoreActionsForInventory);
"Disabled for Server Side Inventory: " + args.Player.IgnoreActionsForInventory,
Color.Red);
} }
else if (TShock.Config.RequireLogin && !args.Player.IsLoggedIn) else if (TShock.Config.RequireLogin && !args.Player.IsLoggedIn)
{ {
args.Player.SendMessage("Please /register or /login to play!", Color.Red); args.Player.SendErrorMessage("Please /register or /login to play!");
} }
else if (args.Player.IgnoreActionsForClearingTrashCan) else if (args.Player.IgnoreActionsForClearingTrashCan)
{ {
args.Player.SendMessage("You need to rejoin to ensure your trash can is cleared!", Color.Red); args.Player.SendErrorMessage("You need to rejoin to ensure your trash can is cleared!");
} }
var lastTileX = args.Player.LastNetPosition.X; var lastTileX = args.Player.LastNetPosition.X;
var lastTileY = args.Player.LastNetPosition.Y - 48; var lastTileY = args.Player.LastNetPosition.Y - 48;
@ -2299,9 +2295,8 @@ namespace TShockAPI
{ {
control[5] = false; control[5] = false;
args.Player.Disable("Using banned item"); args.Player.Disable("Using banned item");
args.Player.SendMessage( args.Player.SendErrorMessage("You cannot use {0} on this server. Your actions are being ignored.",
string.Format("You cannot use {0} on this server. Your actions are being ignored.", args.TPlayer.inventory[item].name);
args.TPlayer.inventory[item].name), Color.Red);
} }
if (args.TPlayer.inventory[item].name == "Mana Crystal" && args.Player.TPlayer.statManaMax <= 180) if (args.TPlayer.inventory[item].name == "Mana Crystal" && args.Player.TPlayer.statManaMax <= 180)
@ -2419,7 +2414,7 @@ namespace TShockAPI
var owner = args.Data.ReadInt8(); var owner = args.Data.ReadInt8();
var type = args.Data.ReadInt16(); var type = args.Data.ReadInt16();
var bits = (BitsByte) args.Data.ReadInt8(); var bits = (BitsByte) args.Data.ReadInt8();
owner = (byte)args.Player.Index; owner = (byte)args.Player.Index;
float[] ai = new float[Projectile.maxAI]; float[] ai = new float[Projectile.maxAI];
for (int i = 0; i < Projectile.maxAI; i++) for (int i = 0; i < Projectile.maxAI; i++)
@ -2449,15 +2444,8 @@ namespace TShockAPI
args.Player.RemoveProjectile(ident, owner); args.Player.RemoveProjectile(ident, owner);
return true; return true;
} }
// Server now checks owner + ident, if owner is different, server will create new projectile.
/*if (args.Player.Index != owner)
{
args.Player.Disable(String.Format("Owner ({0}) and player ID ({1}) does not match to update projectile", owner, args.Player.Index));
args.Player.RemoveProjectile(ident, owner);
return true;
}*/
if (dmg > TShock.Config.MaxProjDamage && !args.Player.Group.HasPermission(Permissions.ignoredamagecap)) 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); args.Player.RemoveProjectile(ident, owner);
@ -2475,7 +2463,7 @@ namespace TShockAPI
{ {
if (type == 100 || type == 164 || type == 180 || type == 261 || (type > 289 && type < 298) || (type >= 325 && type <= 328) || (type >= 345 && type <= 352)) if (type == 100 || type == 164 || type == 180 || type == 261 || (type > 289 && type < 298) || (type >= 325 && type <= 328) || (type >= 345 && type <= 352))
{ {
Log.Debug("Certain projectiles have been ignored for cheat detection."); TShock.Log.Debug("Certain projectiles have been ignored for cheat detection.");
} }
else else
{ {
@ -2502,7 +2490,7 @@ namespace TShockAPI
{ {
if (type == 90 && TShock.Config.ProjIgnoreShrapnel) // Ignore crystal shards if (type == 90 && TShock.Config.ProjIgnoreShrapnel) // Ignore crystal shards
{ {
Log.Debug("Ignoring shrapnel per config.."); TShock.Log.Debug("Ignoring shrapnel per config..");
} }
else if (!Main.projectile[index].active) else if (!Main.projectile[index].active)
{ {
@ -2527,7 +2515,7 @@ namespace TShockAPI
{ {
var ident = args.Data.ReadInt16(); var ident = args.Data.ReadInt16();
var owner = args.Data.ReadInt8(); var owner = args.Data.ReadInt8();
owner = (byte)args.Player.Index; owner = (byte)args.Player.Index;
var index = TShock.Utils.SearchProjectile(ident, owner); var index = TShock.Utils.SearchProjectile(ident, owner);
if (index > Main.maxProjectiles || index < 0) if (index > Main.maxProjectiles || index < 0)
@ -2537,7 +2525,7 @@ namespace TShockAPI
var type = Main.projectile[index].type; var type = Main.projectile[index].type;
// Players can no longer destroy projectiles that are not theirs as of 1.1.2 // Players can no longer destroy projectiles that are not theirs as of 1.1.2
/*if (args.Player.Index != Main.projectile[index].owner && type != 102 && type != 100 && !TShock.Config.IgnoreProjKill) // workaround for skeletron prime projectiles /*if (args.Player.Index != Main.projectile[index].owner && type != 102 && type != 100 && !TShock.Config.IgnoreProjKill) // workaround for skeletron prime projectiles
{ {
args.Player.Disable(String.Format("Owner ({0}) and player ID ({1}) does not match to kill projectile of type: {3}", Main.projectile[index].owner, args.Player.Index, type)); args.Player.Disable(String.Format("Owner ({0}) and player ID ({1}) does not match to kill projectile of type: {3}", Main.projectile[index].owner, args.Player.Index, type));
@ -2551,7 +2539,7 @@ namespace TShockAPI
return true; return true;
} }
if (TShock.CheckProjectilePermission(args.Player, index, type) && type != 102 && type != 100 && !TShock.Config.IgnoreProjKill) 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); args.Player.RemoveProjectile(ident, owner);
@ -2579,7 +2567,7 @@ namespace TShockAPI
if (dmg > 20000) //Abnormal values have the potential to cause infinite loops in the server. if (dmg > 20000) //Abnormal values have the potential to cause infinite loops in the server.
{ {
TShock.Utils.ForceKick(args.Player, "Crash Exploit Attempt", true); TShock.Utils.ForceKick(args.Player, "Crash Exploit Attempt", true);
Log.ConsoleError("Death Exploit Attempt: Damage {0}", dmg); TShock.Log.ConsoleError("Death Exploit Attempt: Damage {0}", dmg);
return false; return false;
} }
@ -2610,18 +2598,18 @@ namespace TShockAPI
} }
} }
if (args.TPlayer.difficulty == 2 && (TShock.Config.KickOnHardcoreDeath || TShock.Config.BanOnHardcoreDeath)) if (args.TPlayer.difficulty == 2 && (TShock.Config.KickOnHardcoreDeath || TShock.Config.BanOnHardcoreDeath))
{ {
if (TShock.Config.BanOnHardcoreDeath) if (TShock.Config.BanOnHardcoreDeath)
{ {
if (!TShock.Utils.Ban(args.Player, TShock.Config.HardcoreBanReason, false, "hardcore-death")) if (!TShock.Utils.Ban(args.Player, TShock.Config.HardcoreBanReason, false, "hardcore-death"))
TShock.Utils.ForceKick(args.Player, "Death results in a ban, but can't ban you.", true); TShock.Utils.ForceKick(args.Player, "Death results in a ban, but can't ban you.", true);
} }
else else
{ {
TShock.Utils.ForceKick(args.Player, TShock.Config.HardcoreKickReason, true, false); TShock.Utils.ForceKick(args.Player, TShock.Config.HardcoreKickReason, true, false);
} }
} }
if (args.TPlayer.difficulty == 2 && Main.ServerSideCharacter && args.Player.IsLoggedIn) if (args.TPlayer.difficulty == 2 && Main.ServerSideCharacter && args.Player.IsLoggedIn)
{ {
@ -2686,32 +2674,32 @@ namespace TShockAPI
} }
if (type == 1 && !(bucket == 2 || bucket == 0)) if (type == 1 && !(bucket == 2 || bucket == 0))
{ {
args.Player.SendErrorMessage("You do not have permission to perform this action."); args.Player.SendErrorMessage("You do not have permission to perform this action.");
args.Player.Disable("Spreading lava without holding a lava bucket"); args.Player.Disable("Spreading lava without holding a lava bucket");
args.Player.SendTileSquare(tileX, tileY, 1); args.Player.SendTileSquare(tileX, tileY, 1);
return true; return true;
} }
if(type == 1 && TShock.Itembans.ItemIsBanned("Lava Bucket", args.Player)) if(type == 1 && TShock.Itembans.ItemIsBanned("Lava Bucket", args.Player))
{ {
args.Player.SendErrorMessage("You do not have permission to perform this action."); args.Player.SendErrorMessage("You do not have permission to perform this action.");
args.Player.Disable("Using banned lava bucket without permissions"); args.Player.Disable("Using banned lava bucket without permissions");
args.Player.SendTileSquare(tileX, tileY, 1); args.Player.SendTileSquare(tileX, tileY, 1);
return true; return true;
} }
if (type == 0 && !(bucket == 1 || bucket == 0)) if (type == 0 && !(bucket == 1 || bucket == 0))
{ {
args.Player.SendErrorMessage("You do not have permission to perform this action."); args.Player.SendErrorMessage("You do not have permission to perform this action.");
args.Player.Disable("Spreading water without holding a water bucket"); args.Player.Disable("Spreading water without holding a water bucket");
args.Player.SendTileSquare(tileX, tileY, 1); args.Player.SendTileSquare(tileX, tileY, 1);
return true; return true;
} }
if (type == 0 && TShock.Itembans.ItemIsBanned("Water Bucket", args.Player)) if (type == 0 && TShock.Itembans.ItemIsBanned("Water Bucket", args.Player))
{ {
args.Player.SendErrorMessage("You do not have permission to perform this action."); args.Player.SendErrorMessage("You do not have permission to perform this action.");
args.Player.Disable("Using banned water bucket without permissions"); args.Player.Disable("Using banned water bucket without permissions");
args.Player.SendTileSquare(tileX, tileY, 1); args.Player.SendTileSquare(tileX, tileY, 1);
return true; return true;
@ -2825,20 +2813,20 @@ namespace TShockAPI
args.Player.InitSpawn = true; args.Player.InitSpawn = true;
if ((Main.ServerSideCharacter) && (args.Player.sX > 0) && (args.Player.sY > 0) && (args.TPlayer.SpawnX > 0) && ((args.TPlayer.SpawnX != args.Player.sX) && (args.TPlayer.SpawnY != args.Player.sY))) if ((Main.ServerSideCharacter) && (args.Player.sX > 0) && (args.Player.sY > 0) && (args.TPlayer.SpawnX > 0) && ((args.TPlayer.SpawnX != args.Player.sX) && (args.TPlayer.SpawnY != args.Player.sY)))
{ {
args.Player.sX=args.TPlayer.SpawnX; args.Player.sX=args.TPlayer.SpawnX;
args.Player.sY=args.TPlayer.SpawnY; args.Player.sY=args.TPlayer.SpawnY;
if (((Main.tile[args.Player.sX, args.Player.sY - 1].active() && Main.tile[args.Player.sX, args.Player.sY - 1].type == 79)) && (WorldGen.StartRoomCheck(args.Player.sX, args.Player.sY -1))) if (((Main.tile[args.Player.sX, args.Player.sY - 1].active() && Main.tile[args.Player.sX, args.Player.sY - 1].type == 79)) && (WorldGen.StartRoomCheck(args.Player.sX, args.Player.sY -1)))
args.Player.Teleport(args.Player.sX * 16, (args.Player.sY * 16) -48); args.Player.Teleport(args.Player.sX * 16, (args.Player.sY * 16) -48);
} }
else if ((Main.ServerSideCharacter) && (args.Player.sX > 0) && (args.Player.sY > 0)) else if ((Main.ServerSideCharacter) && (args.Player.sX > 0) && (args.Player.sY > 0))
{ {
if (((Main.tile[args.Player.sX, args.Player.sY - 1].active() && Main.tile[args.Player.sX, args.Player.sY - 1].type == 79)) && (WorldGen.StartRoomCheck(args.Player.sX, args.Player.sY -1))) if (((Main.tile[args.Player.sX, args.Player.sY - 1].active() && Main.tile[args.Player.sX, args.Player.sY - 1].type == 79)) && (WorldGen.StartRoomCheck(args.Player.sX, args.Player.sY -1)))
args.Player.Teleport(args.Player.sX * 16, (args.Player.sY * 16) -48); args.Player.Teleport(args.Player.sX * 16, (args.Player.sY * 16) -48);
} }
args.Player.Dead = false; args.Player.Dead = false;
return false; return false;
@ -2970,7 +2958,7 @@ namespace TShockAPI
if (!args.Player.Group.HasPermission(Permissions.movenpc)) if (!args.Player.Group.HasPermission(Permissions.movenpc))
{ {
args.Player.SendMessage("You do not have permission to relocate NPCs.", Color.Red); args.Player.SendErrorMessage("You do not have permission to relocate NPCs.");
args.Player.SendData(PacketTypes.UpdateNPCHome, "", id, Main.npc[id].homeTileX, Main.npc[id].homeTileY, args.Player.SendData(PacketTypes.UpdateNPCHome, "", id, Main.npc[id].homeTileX, Main.npc[id].homeTileY,
Convert.ToByte(Main.npc[id].homeless)); Convert.ToByte(Main.npc[id].homeless));
return true; return true;
@ -2978,13 +2966,13 @@ namespace TShockAPI
if (TShock.CheckTilePermission(args.Player, x, y)) if (TShock.CheckTilePermission(args.Player, x, y))
{ {
args.Player.SendMessage( "You do not have access to modify this area.", Color.Red); args.Player.SendErrorMessage( "You do not have access to modify this area.");
args.Player.SendData(PacketTypes.UpdateNPCHome, "", id, Main.npc[id].homeTileX, Main.npc[id].homeTileY, args.Player.SendData(PacketTypes.UpdateNPCHome, "", id, Main.npc[id].homeTileX, Main.npc[id].homeTileY,
Convert.ToByte(Main.npc[id].homeless)); Convert.ToByte(Main.npc[id].homeless));
return true; return true;
} }
//removed until NPC Home packet actually sends their home coords. //removed until NPC Home packet actually sends their home coords.
/*if (TShock.CheckRangePermission(args.Player, x, y)) /*if (TShock.CheckRangePermission(args.Player, x, y))
{ {
args.Player.SendData(PacketTypes.UpdateNPCHome, "", id, Main.npc[id].homeTileX, Main.npc[id].homeTileY, args.Player.SendData(PacketTypes.UpdateNPCHome, "", id, Main.npc[id].homeTileX, Main.npc[id].homeTileY,
@ -3099,7 +3087,7 @@ namespace TShockAPI
if ((Main.ServerSideCharacter) && (DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond - args.Player.LoginMS < TShock.ServerSideCharacterConfig.LogonDiscardThreshold)) if ((Main.ServerSideCharacter) && (DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond - args.Player.LoginMS < TShock.ServerSideCharacterConfig.LogonDiscardThreshold))
{ {
//Player is probably trying to sneak items onto the server in their hands!!! //Player is probably trying to sneak items onto the server in their hands!!!
Log.ConsoleInfo(string.Format("Player {0} tried to sneak {1} onto the server!", args.Player.Name, item.name)); TShock.Log.ConsoleInfo("Player {0} tried to sneak {1} onto the server!", args.Player.Name, item.name);
args.Player.SendData(PacketTypes.ItemDrop, "", id); args.Player.SendData(PacketTypes.ItemDrop, "", id);
return true; return true;
@ -3214,7 +3202,7 @@ namespace TShockAPI
if (Main.npc[id] == null) if (Main.npc[id] == null)
return true; return true;
if (dmg > TShock.Config.MaxDamage && !args.Player.Group.HasPermission(Permissions.ignoredamagecap)) if (dmg > TShock.Config.MaxDamage && !args.Player.Group.HasPermission(Permissions.ignoredamagecap))
{ {
if (TShock.Config.KickOnDamageThresholdBroken) if (TShock.Config.KickOnDamageThresholdBroken)
{ {
@ -3382,12 +3370,12 @@ namespace TShockAPI
} }
if (spawnboss && !args.Player.Group.HasPermission(Permissions.summonboss)) if (spawnboss && !args.Player.Group.HasPermission(Permissions.summonboss))
{ {
args.Player.SendMessage("You don't have permission to summon a boss.", Color.Red); args.Player.SendErrorMessage("You don't have permission to summon a boss.");
return true; return true;
} }
if (invasion && !args.Player.Group.HasPermission(Permissions.startinvasion)) if (invasion && !args.Player.Group.HasPermission(Permissions.startinvasion))
{ {
args.Player.SendMessage("You don't have permission to start an invasion.", Color.Red); args.Player.SendErrorMessage("You don't have permission to start an invasion.");
return true; return true;
} }
if (!spawnboss && !invasion) if (!spawnboss && !invasion)

View file

@ -153,13 +153,6 @@ namespace TShockAPI
public byte B = 255; public byte B = 255;
public static Group DefaultGroup = null; public static Group DefaultGroup = null;
#if COMPAT_SIGS
[Obsolete("This constructor is for signature compatibility for external code only")]
public Group(string groupname, Group parentgroup, string chatcolor)
: this(groupname, parentgroup, chatcolor, null)
{
}
#endif
public Group(string groupname, Group parentgroup = null, string chatcolor = "255,255,255", string permissions = null) public Group(string groupname, Group parentgroup = null, string chatcolor = "255,255,255", string permissions = null)
{ {

View file

@ -21,7 +21,7 @@ namespace TShockAPI.Hooks
{ {
public class AccountDeleteEventArgs public class AccountDeleteEventArgs
{ {
public User User { get; set; } public User User { get; private set; }
public AccountDeleteEventArgs(User user) public AccountDeleteEventArgs(User user)
{ {
@ -31,7 +31,7 @@ namespace TShockAPI.Hooks
public class AccountCreateEventArgs public class AccountCreateEventArgs
{ {
public User User { get; set; } public User User { get; private set; }
public AccountCreateEventArgs(User user) public AccountCreateEventArgs(User user)
{ {

View file

@ -0,0 +1,111 @@
/*
TShock, a server mod for Terraria
Copyright (C) 2011-2015 Nyx Studios (fka. The TShock Team)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
using TShockAPI.DB;
namespace TShockAPI.Hooks
{
public class RegionHooks
{
public class RegionEnteredEventArgs
{
public TSPlayer Player { get; private set; }
public RegionEnteredEventArgs(TSPlayer ply)
{
Player = ply;
}
}
public delegate void RegionEnteredD(RegionEnteredEventArgs args);
public static event RegionEnteredD RegionEntered;
public static void OnRegionEntered(TSPlayer player)
{
if (RegionEntered == null)
{
return;
}
RegionEntered(new RegionEnteredEventArgs(player));
}
public class RegionLeftEventArgs
{
public TSPlayer Player { get; private set; }
public Region Region { get; private set; }
public RegionLeftEventArgs(TSPlayer ply, Region region)
{
Player = ply;
Region = region;
}
}
public delegate void RegionLeftD(RegionLeftEventArgs args);
public static event RegionLeftD RegionLeft;
public static void OnRegionLeft(TSPlayer player, Region region)
{
if (RegionLeft == null)
{
return;
}
RegionLeft(new RegionLeftEventArgs(player, region));
}
public class RegionCreatedEventArgs
{
public Region Region { get; private set; }
public RegionCreatedEventArgs(Region region)
{
Region = region;
}
}
public delegate void RegionCreatedD(RegionCreatedEventArgs args);
public static event RegionCreatedD RegionCreated;
public static void OnRegionCreated(Region region)
{
if (RegionCreated == null)
return;
RegionCreated(new RegionCreatedEventArgs(region));
}
public class RegionDeletedEventArgs
{
public Region Region { get; private set; }
public RegionDeletedEventArgs(Region region)
{
Region = region;
}
}
public delegate void RegionDeletedD(RegionDeletedEventArgs args);
public static event RegionDeletedD RegionDeleted;
public static void OnRegionDeleted(Region region)
{
if (RegionDeleted == null)
return;
RegionDeleted(new RegionDeletedEventArgs(region));
}
}
}

153
TShockAPI/ILog.cs Normal file
View file

@ -0,0 +1,153 @@
/*
TShock, a server mod for Terraria
Copyright (C) 2011-2015 Nyx Studios (fka. The TShock Team)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
using System;
namespace TShockAPI
{
[Flags]
public enum LogLevel
{
None = 0,
Debug = 1,
Info = 2,
Warning = 4,
Error = 8,
Data = 16,
All = 31
}
/// <summary>
/// Logging interface
/// </summary>
public interface ILog
{
/// <summary>
/// Log name
/// </summary>
string Name { get; }
/// <summary>
/// Checks whether the log level contains the specified flag.
/// </summary>
/// <param name="type">The <see cref="LogLevel" /> value to check.</param>
bool MayWriteType(LogLevel type);
/// <summary>
/// Writes an informative string to the log and to the console.
/// </summary>
/// <param name="message">The message to be written.</param>
void ConsoleInfo(string message);
/// <summary>
/// Writes an informative string to the log and to the console.
/// </summary>
/// <param name="message">The format of the message to be written.</param>
/// <param name="args">The format arguments.</param>
void ConsoleInfo(string format, params object[] args);
/// <summary>
/// Writes an error message to the log and to the console.
/// </summary>
/// <param name="message">The message to be written.</param>
void ConsoleError(string message);
/// <summary>
/// Writes an error message to the log and to the console.
/// </summary>
/// <param name="format">The format of the message to be written.</param>
/// <param name="args">The format arguments.</param>
void ConsoleError(string format, params object[] args);
/// <summary>
/// Writes a warning to the log.
/// </summary>
/// <param name="message">The message to be written.</param>
void Warn(string message);
/// <summary>
/// Writes a warning to the log.
/// </summary>
/// <param name="format">The format of the message to be written.</param>
/// <param name="args">The format arguments.</param>
void Warn(string format, params object[] args);
/// <summary>
/// Writes an error to the log.
/// </summary>
/// <param name="message">The message to be written.</param>
void Error(string message);
/// <summary>
/// Writes an error to the log.
/// </summary>
/// <param name="format">The format of the message to be written.</param>
/// <param name="args">The format arguments.</param>
void Error(string format, params object[] args);
/// <summary>
/// Writes an informative string to the log.
/// </summary>
/// <param name="message">The message to be written.</param>
void Info(string message);
/// <summary>
/// Writes an informative string to the log.
/// </summary>
/// <param name="format">The format of the message to be written.</param>
/// <param name="args">The format arguments.</param>
void Info(string format, params object[] args);
/// <summary>
/// Writes data to the log.
/// </summary>
/// <param name="message">The message to be written.</param>
void Data(string message);
/// <summary>
/// Writes data to the log.
/// </summary>
/// <param name="format">The format of the message to be written.</param>
/// <param name="args">The format arguments.</param>
void Data(string format, params object[] args);
/// <summary>
/// Writes a message to the log
/// </summary>
/// <param name="message">Message to write</param>
/// <param name="level">LogLevel assosciated with the message</param>
void Write(string message, LogLevel level);
/// <summary>
/// Writes a debug string to the log file.
/// </summary>
/// <param name="message">The message to be written.</param>
void Debug(String message);
/// <summary>
/// Writes a debug string to the log file.
/// </summary>
/// <param name="format">The format of the message to be written.</param>
/// <param name="args">The format arguments.</param>
void Debug(string format, params object[] args);
/// <summary>
/// Dispose the Log
/// </summary>
void Dispose();
}
}

View file

@ -17,57 +17,16 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
using System; using System;
using System.Diagnostics;
using System.Globalization;
using System.IO;
namespace TShockAPI namespace TShockAPI
{ {
[Flags]
public enum LogLevel
{
None = 0,
Debug = 1,
Info = 2,
Warning = 4,
Error = 8,
Data = 16,
All = 31
}
public static class Log public static class Log
{ {
private static string _filename;
private static LogLevel _logLevel;
private static StreamWriter _logWriter;
/// <summary>
/// Creates the log file stream and sets the initial log level.
/// </summary>
/// <param name="filename">The output filename. This file will be overwritten if 'clear' is set.</param>
/// <param name="logLevel">The <see cref="LogLevel" /> value which sets the type of messages to output.</param>
/// <param name="clear">Whether or not to clear the log file on initialization.</param>
public static void Initialize(string filename, LogLevel logLevel, bool clear)
{
_filename = filename;
_logLevel = logLevel;
_logWriter = new StreamWriter(filename, !clear);
}
/// <summary>
/// Checks whether the log level contains the specified flag.
/// </summary>
/// <param name="type">The <see cref="LogLevel" /> value to check.</param>
private static bool MayWriteType(LogLevel type)
{
return ((_logLevel & type) == type);
}
/// <summary> /// <summary>
/// Writes data to the log file. /// Writes data to the log file.
/// </summary> /// </summary>
/// <param name="message">The message to be written.</param> /// <param name="message">The message to be written.</param>
[Obsolete("Please use TShock.Log.Data")]
public static void Data(String message) public static void Data(String message)
{ {
Write(message, LogLevel.Data); Write(message, LogLevel.Data);
@ -78,6 +37,7 @@ namespace TShockAPI
/// </summary> /// </summary>
/// <param name="format">The format of the message to be written.</param> /// <param name="format">The format of the message to be written.</param>
/// <param name="args">The format arguments.</param> /// <param name="args">The format arguments.</param>
[Obsolete("Please use TShock.Log.Data")]
public static void Data(string format, params object[] args) public static void Data(string format, params object[] args)
{ {
Data(String.Format(format, args)); Data(String.Format(format, args));
@ -87,6 +47,7 @@ namespace TShockAPI
/// Writes an error to the log file. /// Writes an error to the log file.
/// </summary> /// </summary>
/// <param name="message">The message to be written.</param> /// <param name="message">The message to be written.</param>
[Obsolete("Please use TShock.Log.Error")]
public static void Error(String message) public static void Error(String message)
{ {
Write(message, LogLevel.Error); Write(message, LogLevel.Error);
@ -97,6 +58,7 @@ namespace TShockAPI
/// </summary> /// </summary>
/// <param name="format">The format of the message to be written.</param> /// <param name="format">The format of the message to be written.</param>
/// <param name="args">The format arguments.</param> /// <param name="args">The format arguments.</param>
[Obsolete("Please use TShock.Log.Error")]
public static void Error(string format, params object[] args) public static void Error(string format, params object[] args)
{ {
Error(String.Format(format, args)); Error(String.Format(format, args));
@ -106,6 +68,7 @@ namespace TShockAPI
/// Writes an error to the log file. /// Writes an error to the log file.
/// </summary> /// </summary>
/// <param name="message">The message to be written.</param> /// <param name="message">The message to be written.</param>
[Obsolete("Please use TShock.Log.ConsoleError")]
public static void ConsoleError(String message) public static void ConsoleError(String message)
{ {
Console.ForegroundColor = ConsoleColor.Red; Console.ForegroundColor = ConsoleColor.Red;
@ -119,6 +82,7 @@ namespace TShockAPI
/// </summary> /// </summary>
/// <param name="format">The format of the message to be written.</param> /// <param name="format">The format of the message to be written.</param>
/// <param name="args">The format arguments.</param> /// <param name="args">The format arguments.</param>
[Obsolete("Please use TShock.Log.ConsoleError")]
public static void ConsoleError(string format, params object[] args) public static void ConsoleError(string format, params object[] args)
{ {
ConsoleError(String.Format(format, args)); ConsoleError(String.Format(format, args));
@ -128,6 +92,7 @@ namespace TShockAPI
/// Writes a warning to the log file. /// Writes a warning to the log file.
/// </summary> /// </summary>
/// <param name="message">The message to be written.</param> /// <param name="message">The message to be written.</param>
[Obsolete("Please use TShock.Log.Warn")]
public static void Warn(String message) public static void Warn(String message)
{ {
Write(message, LogLevel.Warning); Write(message, LogLevel.Warning);
@ -138,6 +103,7 @@ namespace TShockAPI
/// </summary> /// </summary>
/// <param name="format">The format of the message to be written.</param> /// <param name="format">The format of the message to be written.</param>
/// <param name="args">The format arguments.</param> /// <param name="args">The format arguments.</param>
[Obsolete("Please use TShock.Log.Warn")]
public static void Warn(string format, params object[] args) public static void Warn(string format, params object[] args)
{ {
Warn(String.Format(format, args)); Warn(String.Format(format, args));
@ -147,6 +113,7 @@ namespace TShockAPI
/// Writes an informative string to the log file. /// Writes an informative string to the log file.
/// </summary> /// </summary>
/// <param name="message">The message to be written.</param> /// <param name="message">The message to be written.</param>
[Obsolete("Please use TShock.Log.Info")]
public static void Info(String message) public static void Info(String message)
{ {
Write(message, LogLevel.Info); Write(message, LogLevel.Info);
@ -157,6 +124,7 @@ namespace TShockAPI
/// </summary> /// </summary>
/// <param name="format">The format of the message to be written.</param> /// <param name="format">The format of the message to be written.</param>
/// <param name="args">The format arguments.</param> /// <param name="args">The format arguments.</param>
[Obsolete("Please use TShock.Log.Info")]
public static void Info(string format, params object[] args) public static void Info(string format, params object[] args)
{ {
Info(String.Format(format, args)); Info(String.Format(format, args));
@ -166,6 +134,7 @@ namespace TShockAPI
/// Writes an informative string to the log file. Also outputs to the console. /// Writes an informative string to the log file. Also outputs to the console.
/// </summary> /// </summary>
/// <param name="message">The message to be written.</param> /// <param name="message">The message to be written.</param>
[Obsolete("Please use TShock.Log.ConsoleInfo")]
public static void ConsoleInfo(String message) public static void ConsoleInfo(String message)
{ {
Console.ForegroundColor = ConsoleColor.Yellow; Console.ForegroundColor = ConsoleColor.Yellow;
@ -179,6 +148,7 @@ namespace TShockAPI
/// </summary> /// </summary>
/// <param name="format">The format of the message to be written.</param> /// <param name="format">The format of the message to be written.</param>
/// <param name="args">The format arguments.</param> /// <param name="args">The format arguments.</param>
[Obsolete("Please use TShock.Log.ConsoleInfo")]
public static void ConsoleInfo(string format, params object[] args) public static void ConsoleInfo(string format, params object[] args)
{ {
ConsoleInfo(String.Format(format, args)); ConsoleInfo(String.Format(format, args));
@ -188,6 +158,7 @@ namespace TShockAPI
/// Writes a debug string to the log file. /// Writes a debug string to the log file.
/// </summary> /// </summary>
/// <param name="message">The message to be written.</param> /// <param name="message">The message to be written.</param>
[Obsolete("Please use TShock.Log.Debug")]
public static void Debug(String message) public static void Debug(String message)
{ {
Write(message, LogLevel.Debug); Write(message, LogLevel.Debug);
@ -198,53 +169,18 @@ namespace TShockAPI
/// </summary> /// </summary>
/// <param name="format">The format of the message to be written.</param> /// <param name="format">The format of the message to be written.</param>
/// <param name="args">The format arguments.</param> /// <param name="args">The format arguments.</param>
[Obsolete("Please use TShock.Log.Debug")]
public static void Debug(string format, params object[] args) public static void Debug(string format, params object[] args)
{ {
Debug(String.Format(format, args)); Debug(String.Format(format, args));
} }
/// <summary>
/// Disposes objects that are being used.
/// </summary>
public static void Dispose()
{
_logWriter.Dispose();
}
/// <summary> /// <summary>
/// Internal method which writes a message directly to the log file. /// Internal method which writes a message directly to the log file.
/// </summary> /// </summary>
private static void Write(String message, LogLevel level) private static void Write(String message, LogLevel level)
{ {
if (!MayWriteType(level)) TShock.Log.Write(message, level);
{
return;
}
string caller = "TShock";
StackFrame frame = new StackTrace().GetFrame(2);
if (frame != null)
{
var meth = frame.GetMethod();
if (meth != null)
caller = meth.DeclaringType.Name;
}
try
{
_logWriter.WriteLine(string.Format("{0} - {1}: {2}: {3}",
DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture),
caller, level.ToString().ToUpper(), message));
_logWriter.Flush();
}
catch (ObjectDisposedException)
{
Console.WriteLine("Unable to write to log as log has been disposed.");
Console.WriteLine("{0} - {1}: {2}: {3}",
DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture),
caller, level.ToString().ToUpper(), message);
}
} }
} }
} }

View file

@ -145,7 +145,7 @@ namespace TShockAPI
} }
catch (Exception e) catch (Exception e)
{ {
Log.ConsoleError(e.ToString()); TShock.Log.ConsoleError(e.ToString());
} }
return false; return false;
} }
@ -206,7 +206,7 @@ namespace TShockAPI
} }
catch (ObjectDisposedException e) catch (ObjectDisposedException e)
{ {
Log.Warn(e.ToString()); TShock.Log.Warn(e.ToString());
} }
catch (SocketException e) catch (SocketException e)
{ {
@ -216,7 +216,7 @@ namespace TShockAPI
case 10053: case 10053:
break; break;
default: default:
Log.Warn(e.ToString()); TShock.Log.Warn(e.ToString());
break; break;
} }
} }
@ -230,12 +230,12 @@ namespace TShockAPI
case SocketError.ConnectionReset: case SocketError.ConnectionReset:
break; break;
default: default:
Log.Warn(e.ToString()); TShock.Log.Warn(e.ToString());
break; break;
} }
} }
else else
Log.Warn(e.ToString()); TShock.Log.Warn(e.ToString());
} }
return false; return false;
} }

View file

@ -349,6 +349,9 @@ namespace TShockAPI
[Description("Player recovers health as damage is taken. Can be one shotted.")] [Description("Player recovers health as damage is taken. Can be one shotted.")]
public static readonly string godmode = "tshock.godmode"; public static readonly string godmode = "tshock.godmode";
[Description("User can godmode other players")]
public static readonly string godmodeother = "tshock.godmode.other";
[Description("Player can chat")] [Description("Player can chat")]
public static readonly string canchat = "tshock.canchat"; public static readonly string canchat = "tshock.canchat";

View file

@ -53,5 +53,5 @@ using System.Runtime.InteropServices;
// Also, be sure to release on github with the exact assembly version tag as below // Also, be sure to release on github with the exact assembly version tag as below
// so that the update manager works correctly (via the Github releases api and mimic) // so that the update manager works correctly (via the Github releases api and mimic)
[assembly: AssemblyVersion("4.2.6")] [assembly: AssemblyVersion("4.2.7")]
[assembly: AssemblyFileVersion("4.2.6")] [assembly: AssemblyFileVersion("4.2.7")]

View file

@ -1,454 +0,0 @@
/*
TShock, a server mod for Terraria
Copyright (C) 2011-2015 Nyx Studios (fka. The TShock Team)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Streams;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using Terraria;
namespace TShockAPI
{
internal class RconHandler
{
public static string Password = "";
private static DateTime LastRequest;
private static DateTime LastHeartbeat;
public static int ListenPort;
public static bool ContinueServer = true;
public static string Response = "";
private static bool Started;
private static UdpClient listener;
private static Thread startThread;
private static Thread heartbeat;
private static Thread listen;
public static void ShutdownAllThreads()
{
if (Started)
{
startThread.Abort();
heartbeat.Abort();
listen.Abort();
Started = false;
}
}
public static void StartThread()
{
if (!Started)
{
startThread = new Thread(Start);
startThread.Start();
heartbeat = new Thread(SendHeartbeat);
heartbeat.Start();
}
Started = true;
}
public static void Start()
{
Log.Info("Starting RconHandler.");
try
{
Console.WriteLine(string.Format("RconHandler is running at UDP port {0} and password is {1}",
ListenPort,
Password));
listen = new Thread(Listener);
listen.Start();
while (true)
{
if (listen.ThreadState != ThreadState.Running)
{
listen.Abort();
while (listen.ThreadState != ThreadState.Stopped)
continue;
listen.Start();
}
Thread.Sleep(3000);
}
}
catch (Exception e)
{
Log.Error(e.ToString());
}
}
private static void Listener()
{
if (listener == null)
try
{
listener = new UdpClient(ListenPort);
}
catch (SocketException e)
{
if (e.SocketErrorCode == SocketError.AddressAlreadyInUse)
Log.ConsoleError("Could not bind to " + ListenPort + ". Are you sure you don't have another instance running?");
}
catch (Exception e)
{
Log.Error(e.ToString());
}
while (ContinueServer)
{
try
{
var listenEP = new IPEndPoint(IPAddress.Any, ListenPort);
LastRequest = DateTime.Now;
byte[] bytes = listener.Receive(ref listenEP);
var packet = ParsePacket(bytes, listenEP);
listener.Send(packet, packet.Length, listenEP);
}
catch (Exception e)
{
Log.Error(e.ToString());
}
}
}
private static string SendPacket(byte[] bytes, string hostname, int port)
{
var response = Encoding.UTF8.GetString(new byte[] {0xFF, 0xFF, 0xFF, 0xFF}) + "disconnect";
try
{
var EP = new IPEndPoint(IPAddress.Any, port);
using (var client = new UdpClient())
{
client.Connect(hostname, port);
client.Client.ReceiveTimeout = 500;
client.Send(bytes, bytes.Length);
response = Encoding.UTF8.GetString(client.Receive(ref EP));
}
}
catch (Exception e)
{
Log.Error(e.ToString());
}
return response;
}
private static byte[] ParsePacket(byte[] bytes, IPEndPoint EP)
{
string response = "";
var packetstring = Encoding.UTF8.GetString(PadPacket(bytes));
var redirect = false;
var print = true;
if ((DateTime.Now - LastRequest).Milliseconds >= 100)
{
if (packetstring.StartsWith("rcon") || packetstring.Substring(4).StartsWith("rcon") ||
packetstring.Substring(5).StartsWith("rcon"))
{
if (!string.IsNullOrEmpty(Password))
{
var args = ParseParameters(packetstring);
if (args.Count >= 3)
{
if (args[1] == Password)
{
args[1] = args[0] = "";
string command = string.Join(" ", args.ToArray());
command = command.TrimEnd(' ').TrimEnd('\0').TrimStart(' ');
Log.ConsoleInfo("Rcon from " + EP + ":" + command);
Response = "";
response = ExecuteCommand(command);
response += "\n" + Response;
Response = "";
response = response.TrimStart('\n');
}
else
{
response = "Bad rcon password.\n";
Log.ConsoleInfo("Bad rcon password from " + EP);
}
}
else
response = "";
}
else
{
response = "No rcon password set on the server.\n";
Log.Info("No password for rcon set");
}
}
else
redirect = true;
}
if (packetstring.StartsWith("getinfo")
|| packetstring.Substring(4).StartsWith("getinfo")
|| packetstring.Substring(5).StartsWith("getinfo"))
{
var challenge = "";
if (packetstring.Split(' ').Length == 2)
challenge = packetstring.Split(' ')[1];
response = "infoResponse\n";
var infostring =
string.Format(
@"\_TShock_ver\{6}\mapname\{1}\sv_maxclients\{2}\clients\{3}\sv_privateClients\{4}\hconly\{5}\gamename\TERRARIA\protocol\100\sv_hostname\{0}\g_needPass\{7}",
TShock.Config.ServerName, Main.worldName, Main.maxNetPlayers,
TShock.Utils.ActivePlayers(), Main.maxNetPlayers - TShock.Config.MaxSlots,
TShock.Config.HardcoreOnly ? 1 : 0, TShock.VersionNum,
Netplay.password != "" ? 1 : 0);
if (challenge != "")
infostring += @"\challenge\" + challenge;
response += infostring;
print = false;
redirect = false;
}
else if (packetstring.StartsWith("getstatus")
|| packetstring.Substring(4).StartsWith("getstatus")
|| packetstring.Substring(5).StartsWith("getstatus"))
{
var challenge = "";
if (packetstring.Split(' ').Length == 2)
challenge = packetstring.Split(' ')[1];
response = "statusResponse\n";
var statusstring = string.Format(
@"\_TShock_ver\{6}\mapname\{1}\sv_maxclients\{2}\clients\{3}\sv_privateClients\{4}\hconly\{5}\gamename\TERRARIA\protocol\100\sv_hostname\{0}\g_needPass\{7}",
TShock.Config.ServerName, Main.worldName, Main.maxNetPlayers,
TShock.Utils.ActivePlayers(), Main.maxNetPlayers - TShock.Config.MaxSlots,
TShock.Config.HardcoreOnly ? 1 : 0, TShock.VersionNum,
Netplay.password != "" ? 1 : 0) + "\n";
if (challenge != "")
statusstring += @"\challenge\" + challenge;
foreach (TSPlayer player in TShock.Players)
{
if (player != null && player.Active)
statusstring += (string.Format("0 0 {0}\n", player.Name));
}
response += statusstring;
print = false;
redirect = false;
}
if (!redirect)
return (ConstructPacket(response, print));
else
return (ConstructPacket("disconnect", false));
}
private static string ExecuteCommand(string text)
{
if (Main.rand == null)
Main.rand = new Random();
if (WorldGen.genRand == null)
WorldGen.genRand = new Random();
if (text.StartsWith("exit"))
{
TShock.Utils.StopServer();
return "Server shutting down.";
}
else if (text.StartsWith("playing") || text.StartsWith("/playing"))
{
int count = 0;
foreach (TSPlayer player in TShock.Players)
{
if (player != null && player.Active)
{
count++;
TSPlayer.Server.SendMessage(string.Format("{0} ({1}) [{2}] <{3}>", player.Name, player.IP, player.Group.Name,
player.UserAccountName));
}
}
TSPlayer.Server.SendMessage(string.Format("{0} players connected.", count));
}
else if (text.StartsWith("status"))
{
Response += "map: " + Main.worldName + "\n";
Response += "num score ping name lastmsg address qport rate\n";
int count = 0;
foreach (TSPlayer player in TShock.Players)
{
if (player != null && player.Active)
{
count++;
Response +=
(string.Format("{0} 0 0 {1}({2}) {3} {4} 0 0", count, player.Name, player.Group.Name,
Netplay.serverSock[player.Index].tcpClient.Client.RemoteEndPoint, "")) + "\n";
}
}
}
else if (text.StartsWith("say "))
{
Log.Info(string.Format("Server said: {0}", text.Remove(0, 4)));
return string.Format("Server said: {0}", text.Remove(0, 4));
}
else if (text == "autosave")
{
Main.autoSave = TShock.Config.AutoSave = !TShock.Config.AutoSave;
Log.ConsoleInfo("AutoSave " + (TShock.Config.AutoSave ? "Enabled" : "Disabled"));
return "AutoSave " + (TShock.Config.AutoSave ? "Enabled" : "Disabled");
}
else if (text.StartsWith("/"))
{
if (!Commands.HandleCommand(TSPlayer.Server, text))
return "Invalid command.";
}
else if (!Commands.HandleCommand(TSPlayer.Server, "/" + text))
return "Invalid command.";
return "";
}
private static byte[] ConstructPacket(string response, bool print)
{
var oob = new byte[] {0xFF, 0xFF, 0xFF, 0xFF};
using (var stream = new MemoryStream())
{
stream.WriteBytes(oob);
if (print)
stream.WriteBytes(Encoding.UTF8.GetBytes(string.Format("print\n{0}", response)));
else
stream.WriteBytes(Encoding.UTF8.GetBytes(response));
var trimmedpacket = new byte[(int) stream.Length];
var packet = stream.GetBuffer();
Array.Copy(packet, trimmedpacket, (int) stream.Length);
return trimmedpacket;
}
}
private static byte[] PadPacket(byte[] packet)
{
var returnpacket = new byte[(4 + packet.Length)];
int h = 0;
if (packet[0] != 0xFF)
{
for (int i = 0; i < 4; i++)
returnpacket[i] = 0xFF;
for (int i = 4; i < returnpacket.Length; i++)
returnpacket[i] = packet[h++];
}
else
returnpacket = packet;
return returnpacket;
}
private static void SendHeartbeat()
{
LastHeartbeat = DateTime.UtcNow.Subtract(new TimeSpan(0, 0, 30));
while (true)
{
if ((DateTime.UtcNow - LastHeartbeat).Seconds >= 30)
{
var packet = ConstructPacket("heartbeat TerrariaShock", false);
if (listener == null)
try
{
listener = new UdpClient(ListenPort);
}
catch (SocketException e)
{
if (e.SocketErrorCode == SocketError.AddressAlreadyInUse)
Log.ConsoleError("Could not bind to " + ListenPort + ". Are you sure you don't have another instance running?");
}
catch (Exception e)
{
Log.Error(e.ToString());
}
listener.Send(packet, packet.Length, TShock.Config.MasterServer, 27950);
LastHeartbeat = DateTime.UtcNow;
}
Thread.Sleep(10000);
}
}
#region ParseParams
private static List<String> ParseParameters(string str)
{
var ret = new List<string>();
var sb = new StringBuilder();
bool instr = false;
for (int i = 0; i < str.Length; i++)
{
char c = str[i];
if (instr)
{
if (c == '\\')
{
if (i + 1 >= str.Length)
break;
c = GetEscape(str[++i]);
}
else if (c == '"')
{
ret.Add(sb.ToString());
sb.Clear();
instr = false;
continue;
}
sb.Append(c);
}
else
{
if (IsWhiteSpace(c))
{
if (sb.Length > 0)
{
ret.Add(sb.ToString());
sb.Clear();
}
}
else if (c == '"')
{
if (sb.Length > 0)
{
ret.Add(sb.ToString());
sb.Clear();
}
instr = true;
}
else
{
sb.Append(c);
}
}
}
if (sb.Length > 0)
ret.Add(sb.ToString());
return ret;
}
private static char GetEscape(char c)
{
switch (c)
{
case '\\':
return '\\';
case '"':
return '"';
case 't':
return '\t';
default:
return c;
}
}
private static bool IsWhiteSpace(char c)
{
return c == ' ' || c == '\t' || c == '\n';
}
#endregion
}
}

View file

@ -157,7 +157,8 @@ namespace Rests
e.Response.Connection.Type = ConnectionType.Close; e.Response.Connection.Type = ConnectionType.Close;
e.Response.ContentType = new ContentTypeHeader("application/json; charset=utf-8"); e.Response.ContentType = new ContentTypeHeader("application/json; charset=utf-8");
e.Response.Add(serverHeader); e.Response.Add(serverHeader);
e.Response.Body.Write(Encoding.UTF8.GetBytes(str), 0, str.Length); var bytes = Encoding.UTF8.GetBytes(str);
e.Response.Body.Write(bytes, 0, bytes.Length);
e.Response.Status = HttpStatusCode.OK; e.Response.Status = HttpStatusCode.OK;
} }
@ -212,7 +213,7 @@ namespace Rests
object result = cmd.Execute(verbs, parms, request); object result = cmd.Execute(verbs, parms, request);
if (cmd.DoLog && TShock.Config.LogRest) if (cmd.DoLog && TShock.Config.LogRest)
{ {
Log.ConsoleInfo("Anonymous requested REST endpoint: " + BuildRequestUri(cmd, verbs, parms, false)); TShock.Log.ConsoleInfo("Anonymous requested REST endpoint: " + BuildRequestUri(cmd, verbs, parms, false));
} }
return result; return result;

View file

@ -179,7 +179,7 @@ namespace TShockAPI
var msg = args.Parameters["msg"]; var msg = args.Parameters["msg"];
if (string.IsNullOrWhiteSpace(msg)) if (string.IsNullOrWhiteSpace(msg))
return RestMissingParam("msg"); return RestMissingParam("msg");
TShock.Utils.Broadcast(msg); TSPlayer.All.SendInfoMessage(msg);
return RestResponse("The message was broadcasted successfully"); return RestResponse("The message was broadcasted successfully");
} }
@ -660,7 +660,7 @@ namespace TShockAPI
TSPlayer player = (TSPlayer)ret; TSPlayer player = (TSPlayer)ret;
player.DamagePlayer(999999); player.DamagePlayer(999999);
var from = string.IsNullOrWhiteSpace(args.Parameters["from"]) ? "Server Admin" : args.Parameters["from"]; var from = string.IsNullOrWhiteSpace(args.Parameters["from"]) ? "Server Admin" : args.Parameters["from"];
player.SendMessage(string.Format("{0} just killed you!", from)); player.SendInfoMessage(string.Format("{0} just killed you!", from));
return RestResponse("Player " + player.Name + " was killed"); return RestResponse("Player " + player.Name + " was killed");
} }
@ -916,7 +916,7 @@ namespace TShockAPI
TSPlayer player = (TSPlayer)ret; TSPlayer player = (TSPlayer)ret;
player.mute = mute; player.mute = mute;
var verb = mute ? "muted" : "unmuted"; var verb = mute ? "muted" : "unmuted";
player.SendMessage("You have been remotely " + verb); player.SendInfoMessage("You have been remotely " + verb);
return RestResponse("Player " + player.Name + " was " + verb); return RestResponse("Player " + player.Name + " was " + verb);
} }

View file

@ -68,7 +68,7 @@ namespace Rests
"The old model will be removed with the next maintenance release of TShock. In order to switch to the new model, ", "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." "change the config setting \"RestUseNewPermissionModel\" to true."
); );
Log.Warn(warningMessage); TShock.Log.Warn(warningMessage);
Console.ForegroundColor = ConsoleColor.Red; Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine(warningMessage); Console.WriteLine(warningMessage);
Console.ForegroundColor = ConsoleColor.Gray; Console.ForegroundColor = ConsoleColor.Gray;
@ -80,7 +80,7 @@ namespace Rests
"with existing REST services. If compatibility problems occur, you can switch back to the unsecure permission ", "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." "model by changing the config setting \"RestUseNewPermissionModel\" to false, which is not recommended."
); );
Log.ConsoleInfo(warningMessage); TShock.Log.ConsoleInfo(warningMessage);
} }
} }

View file

@ -58,8 +58,8 @@ namespace TShockAPI
} }
catch (Exception ex) catch (Exception ex)
{ {
Log.Error("World saved notification failed"); TShock.Log.Error("World saved notification failed");
Log.Error(ex.ToString()); TShock.Log.Error(ex.ToString());
} }
} }
} }
@ -130,12 +130,12 @@ namespace TShockAPI
else else
WorldFile.saveWorld(task.resetTime); WorldFile.saveWorld(task.resetTime);
TShock.Utils.Broadcast("World saved.", Color.Yellow); TShock.Utils.Broadcast("World saved.", Color.Yellow);
Log.Info(string.Format("World saved at ({0})", Main.worldPathName)); TShock.Log.Info(string.Format("World saved at ({0})", Main.worldPathName));
} }
catch (Exception e) catch (Exception e)
{ {
Log.Error("World saved failed"); TShock.Log.Error("World saved failed");
Log.Error(e.ToString()); TShock.Log.Error(e.ToString());
} }
} }
} }

295
TShockAPI/SqlLog.cs Normal file
View file

@ -0,0 +1,295 @@
/*
TShock, a server mod for Terraria
Copyright (C) 2011-2015 Nyx Studios (fka. The TShock Team)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
using System;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using TShockAPI.DB;
namespace TShockAPI
{
struct LogInfo
{
public string timestamp;
public string message;
public string caller;
public LogLevel logLevel;
public override string ToString()
{
return String.Format("Message: {0}: {1}: {2}",
caller, logLevel.ToString().ToUpper(), message);
}
}
/// <summary>
/// Class inheriting ILog for writing logs to TShock's SQL database
/// </summary>
public class SqlLog : ILog, IDisposable
{
private readonly LogLevel _logLevel;
private readonly IDbConnection _database;
private readonly TextLog _backupLog;
private readonly List<LogInfo> _failures = new List<LogInfo>(TShock.Config.RevertToTextLogsOnSqlFailures);
private bool _useTextLog;
public string Name
{
get { return "SQL Log Writer"; }
}
public SqlLog(LogLevel logLevel, IDbConnection db, string textlogFilepath, bool clearTextLog)
{
_logLevel = logLevel;
_database = db;
_backupLog = new TextLog(textlogFilepath, logLevel, clearTextLog);
}
public bool MayWriteType(LogLevel type)
{
return ((_logLevel & type) == type);
}
/// <summary>
/// Writes data to the log file.
/// </summary>
/// <param name="message">The message to be written.</param>
public void Data(String message)
{
Write(message, LogLevel.Data);
}
/// <summary>
/// Writes data to the log file.
/// </summary>
/// <param name="format">The format of the message to be written.</param>
/// <param name="args">The format arguments.</param>
public void Data(string format, params object[] args)
{
Data(String.Format(format, args));
}
/// <summary>
/// Writes an error to the log file.
/// </summary>
/// <param name="message">The message to be written.</param>
public void Error(String message)
{
Write(message, LogLevel.Error);
}
/// <summary>
/// Writes an error to the log file.
/// </summary>
/// <param name="format">The format of the message to be written.</param>
/// <param name="args">The format arguments.</param>
public void Error(string format, params object[] args)
{
Error(String.Format(format, args));
}
/// <summary>
/// Writes an error to the log file.
/// </summary>
/// <param name="message">The message to be written.</param>
public void ConsoleError(String message)
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine(message);
Console.ForegroundColor = ConsoleColor.Gray;
Write(message, LogLevel.Error);
}
/// <summary>
/// Writes an error to the log file.
/// </summary>
/// <param name="format">The format of the message to be written.</param>
/// <param name="args">The format arguments.</param>
public void ConsoleError(string format, params object[] args)
{
ConsoleError(String.Format(format, args));
}
/// <summary>
/// Writes a warning to the log file.
/// </summary>
/// <param name="message">The message to be written.</param>
public void Warn(String message)
{
Write(message, LogLevel.Warning);
}
/// <summary>
/// Writes a warning to the log file.
/// </summary>
/// <param name="format">The format of the message to be written.</param>
/// <param name="args">The format arguments.</param>
public void Warn(string format, params object[] args)
{
Warn(String.Format(format, args));
}
/// <summary>
/// Writes an informative string to the log file.
/// </summary>
/// <param name="message">The message to be written.</param>
public void Info(String message)
{
Write(message, LogLevel.Info);
}
/// <summary>
/// Writes an informative string to the log file.
/// </summary>
/// <param name="format">The format of the message to be written.</param>
/// <param name="args">The format arguments.</param>
public void Info(string format, params object[] args)
{
Info(String.Format(format, args));
}
/// <summary>
/// Writes an informative string to the log file. Also outputs to the console.
/// </summary>
/// <param name="message">The message to be written.</param>
public void ConsoleInfo(String message)
{
Console.ForegroundColor = ConsoleColor.Yellow;
Console.WriteLine(message);
Console.ForegroundColor = ConsoleColor.Gray;
Write(message, LogLevel.Info);
}
/// <summary>
/// Writes an informative string to the log file. Also outputs to the console.
/// </summary>
/// <param name="format">The format of the message to be written.</param>
/// <param name="args">The format arguments.</param>
public void ConsoleInfo(string format, params object[] args)
{
ConsoleInfo(String.Format(format, args));
}
/// <summary>
/// Writes a debug string to the log file.
/// </summary>
/// <param name="message">The message to be written.</param>
public void Debug(String message)
{
Write(message, LogLevel.Debug);
}
/// <summary>
/// Writes a debug string to the log file.
/// </summary>
/// <param name="format">The format of the message to be written.</param>
/// <param name="args">The format arguments.</param>
public void Debug(string format, params object[] args)
{
Debug(String.Format(format, args));
}
public void Write(string message, LogLevel level)
{
if (!MayWriteType(level))
return;
var caller = "TShock";
var frame = new StackTrace().GetFrame(2);
if (frame != null)
{
var meth = frame.GetMethod();
if (meth != null && meth.DeclaringType != null)
caller = meth.DeclaringType.Name;
}
try
{
if (_useTextLog)
{
_backupLog.Write(message, level);
return;
}
_database.Query("INSERT INTO Logs (LogLevel, TimeStamp, Caller, Message) VALUES (@0, @1, @2, @3)",
level, DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture),
caller, message);
var success = true;
while (_failures.Count > 0 && success)
{
var info = _failures.First();
try
{
_database.Query("INSERT INTO Logs (LogLevel, TimeStamp, Caller, Message) VALUES (@0, @1, @2, @3)",
info.logLevel, info.timestamp, info.caller, info.message);
}
catch (Exception ex)
{
success = false;
_failures.Add(new LogInfo
{
caller = "TShock",
logLevel = LogLevel.Error,
message = String.Format("SQL Log insert query failed: {0}", ex),
timestamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture)
});
}
if (success)
_failures.RemoveAt(0);
}
}
catch (Exception ex)
{
_backupLog.ConsoleError("SQL Log insert query failed: {0}", ex);
_failures.Add(new LogInfo
{
logLevel = level,
message = message,
caller = caller,
timestamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture)
});
}
if (_failures.Count >= TShock.Config.RevertToTextLogsOnSqlFailures)
{
_useTextLog = true;
_backupLog.ConsoleError("SQL Logging disabled due to errors. Reverting to text logging.");
foreach(var logInfo in _failures)
{
_backupLog.Write(String.Format("SQL log failed at: {0}. {1}", logInfo.timestamp, logInfo),
LogLevel.Error);
}
_failures.Clear();
}
}
public void Dispose()
{
_backupLog.Dispose();
}
}
}

4
TShockAPI/StatTracker.cs Normal file → Executable file
View file

@ -45,7 +45,7 @@ namespace TShockAPI
var serialized = Newtonsoft.Json.JsonConvert.SerializeObject(data); var serialized = Newtonsoft.Json.JsonConvert.SerializeObject(data);
var encoded = HttpUtility.UrlEncode(serialized); var encoded = HttpUtility.UrlEncode(serialized);
var uri = String.Format("http://96.47.231.227:8000?data={0}", encoded); var uri = String.Format("http://stats.tshock.co/publish/{0}", encoded);
var client = (HttpWebRequest)WebRequest.Create(uri); var client = (HttpWebRequest)WebRequest.Create(uri);
client.Timeout = 5000; client.Timeout = 5000;
try try
@ -64,7 +64,7 @@ namespace TShockAPI
{ {
if (!failed) if (!failed)
{ {
Log.ConsoleError("StatTracker Exception: {0}", e); TShock.Log.ConsoleError("StatTracker Exception: {0}", e);
failed = true; failed = true;
} }
} }

View file

@ -30,29 +30,29 @@ namespace TShockAPI
{ {
public class TSPlayer public class TSPlayer
{ {
/// <summary> /// <summary>
/// This represents the server as a player. /// This represents the server as a player.
/// </summary> /// </summary>
public static readonly TSServerPlayer Server = new TSServerPlayer(); public static readonly TSServerPlayer Server = new TSServerPlayer();
/// <summary> /// <summary>
/// This player represents all the players. /// This player represents all the players.
/// </summary> /// </summary>
public static readonly TSPlayer All = new TSPlayer("All"); public static readonly TSPlayer All = new TSPlayer("All");
/// <summary> /// <summary>
/// The amount of tiles that the player has killed in the last second. /// The amount of tiles that the player has killed in the last second.
/// </summary> /// </summary>
public int TileKillThreshold { get; set; } public int TileKillThreshold { get; set; }
/// <summary> /// <summary>
/// The amount of tiles the player has placed in the last second. /// The amount of tiles the player has placed in the last second.
/// </summary> /// </summary>
public int TilePlaceThreshold { get; set; } public int TilePlaceThreshold { get; set; }
/// <summary> /// <summary>
/// The amount of liquid (in tiles) that the player has placed in the last second. /// The amount of liquid (in tiles) that the player has placed in the last second.
/// </summary> /// </summary>
public int TileLiquidThreshold { get; set; } public int TileLiquidThreshold { get; set; }
/// <summary> /// <summary>
@ -60,9 +60,9 @@ namespace TShockAPI
/// </summary> /// </summary>
public int PaintThreshold { get; set; } public int PaintThreshold { get; set; }
/// <summary> /// <summary>
/// The number of projectiles created by the player in the last second. /// The number of projectiles created by the player in the last second.
/// </summary> /// </summary>
public int ProjectileThreshold { get; set; } public int ProjectileThreshold { get; set; }
/// <summary> /// <summary>
@ -83,130 +83,130 @@ namespace TShockAPI
public int sX = -1; public int sX = -1;
public int sY = -1; public int sY = -1;
/// <summary> /// <summary>
/// A queue of tiles destroyed by the player for reverting. /// A queue of tiles destroyed by the player for reverting.
/// </summary> /// </summary>
public Dictionary<Vector2, Tile> TilesDestroyed { get; protected set; } public Dictionary<Vector2, Tile> TilesDestroyed { get; protected set; }
/// <summary> /// <summary>
/// A queue of tiles placed by the player for reverting. /// A queue of tiles placed by the player for reverting.
/// </summary> /// </summary>
public Dictionary<Vector2, Tile> TilesCreated { get; protected set; } public Dictionary<Vector2, Tile> TilesCreated { get; protected set; }
/// <summary> /// <summary>
/// The player's group. /// The player's group.
/// </summary> /// </summary>
public Group Group public Group Group
{ {
get get
{ {
if (tempGroup != null) if (tempGroup != null)
return tempGroup; return tempGroup;
return group; return group;
} }
set { group = value; } set { group = value; }
} }
/// <summary> /// <summary>
/// The player's temporary group. This overrides the user's actual group. /// The player's temporary group. This overrides the user's actual group.
/// </summary> /// </summary>
public Group tempGroup = null; public Group tempGroup = null;
private Group group = null; private Group group = null;
public bool ReceivedInfo { get; set; } public bool ReceivedInfo { get; set; }
/// <summary> /// <summary>
/// The players index in the player array( Main.players[] ). /// The players index in the player array( Main.players[] ).
/// </summary> /// </summary>
public int Index { get; protected set; } public int Index { get; protected set; }
/// <summary> /// <summary>
/// The last time the player changed their team or pvp status. /// The last time the player changed their team or pvp status.
/// </summary> /// </summary>
public DateTime LastPvPTeamChange; public DateTime LastPvPTeamChange;
/// <summary> /// <summary>
/// Temp points for use in regions and other plugins. /// Temp points for use in regions and other plugins.
/// </summary> /// </summary>
public Point[] TempPoints = new Point[2]; public Point[] TempPoints = new Point[2];
/// <summary> /// <summary>
/// Whether the player is waiting to place/break a tile to set as a temp point. /// Whether the player is waiting to place/break a tile to set as a temp point.
/// </summary> /// </summary>
public int AwaitingTempPoint { get; set; } public int AwaitingTempPoint { get; set; }
/// <summary> /// <summary>
/// A list of command callbacks indexed by the command they need to do. /// A list of command callbacks indexed by the command they need to do.
/// </summary> /// </summary>
public Dictionary<string, Action<object>> AwaitingResponse; public Dictionary<string, Action<object>> AwaitingResponse;
public bool AwaitingName { get; set; } public bool AwaitingName { get; set; }
public string[] AwaitingNameParameters { get; set; } public string[] AwaitingNameParameters { get; set; }
/// <summary> /// <summary>
/// The last time a player broke a grief check. /// The last time a player broke a grief check.
/// </summary> /// </summary>
public DateTime LastThreat { get; set; } public DateTime LastThreat { get; set; }
public bool InitSpawn; public bool InitSpawn;
/// <summary> /// <summary>
/// Whether the player should see logs. /// Whether the player should see logs.
/// </summary> /// </summary>
public bool DisplayLogs = true; public bool DisplayLogs = true;
/// <summary> /// <summary>
/// The last player that the player whispered with (to or from). /// The last player that the player whispered with (to or from).
/// </summary> /// </summary>
public TSPlayer LastWhisper; public TSPlayer LastWhisper;
/// <summary> /// <summary>
/// The number of unsuccessful login attempts. /// The number of unsuccessful login attempts.
/// </summary> /// </summary>
public int LoginAttempts { get; set; } public int LoginAttempts { get; set; }
public Vector2 TeleportCoords = new Vector2(-1, -1); public Vector2 TeleportCoords = new Vector2(-1, -1);
public Vector2 LastNetPosition = Vector2.Zero; public Vector2 LastNetPosition = Vector2.Zero;
/// <summary> /// <summary>
/// The player's login name. /// The player's login name.
/// </summary> /// </summary>
public string UserAccountName { get; set; } public string UserAccountName { get; set; }
/// <summary> /// <summary>
/// Whether the player performed a valid login attempt (i.e. entered valid user name and password) but is still blocked /// 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. /// from logging in because of SSI.
/// </summary> /// </summary>
public bool LoginFailsBySsi { get; set; } public bool LoginFailsBySsi { get; set; }
/// <summary> /// <summary>
/// Whether the player is logged in or not. /// Whether the player is logged in or not.
/// </summary> /// </summary>
public bool IsLoggedIn; public bool IsLoggedIn;
/// <summary> /// <summary>
/// Whether the player has sent their whole inventory to the server while connecting. /// Whether the player has sent their whole inventory to the server while connecting.
/// </summary> /// </summary>
public bool HasSentInventory { get; set; } public bool HasSentInventory { get; set; }
/// <summary> /// <summary>
/// The player's user id( from the db ). /// The player's user id( from the db ).
/// </summary> /// </summary>
public int UserID = -1; public int UserID = -1;
/// <summary> /// <summary>
/// Whether the player has been nagged about logging in. /// Whether the player has been nagged about logging in.
/// </summary> /// </summary>
public bool HasBeenNaggedAboutLoggingIn; public bool HasBeenNaggedAboutLoggingIn;
public bool TPAllow = true; public bool TPAllow = true;
/// <summary> /// <summary>
/// Whether the player is muted or not. /// Whether the player is muted or not.
/// </summary> /// </summary>
public bool mute; public bool mute;
private Player FakePlayer; private Player FakePlayer;
@ -218,16 +218,16 @@ namespace TShockAPI
/// </summary> /// </summary>
public int RespawnTimer; public int RespawnTimer;
/// <summary> /// <summary>
/// Whether the player is dead or not. /// Whether the player is dead or not.
/// </summary> /// </summary>
public bool Dead; public bool Dead;
public string Country = "??"; public string Country = "??";
/// <summary> /// <summary>
/// The players difficulty( normal[softcore], mediumcore, hardcore ). /// The players difficulty( normal[softcore], mediumcore, hardcore ).
/// </summary> /// </summary>
public int Difficulty; public int Difficulty;
private string CacheIP; private string CacheIP;
@ -240,53 +240,53 @@ namespace TShockAPI
public bool IgnoreActionsForClearingTrashCan; public bool IgnoreActionsForClearingTrashCan;
/// <summary> /// <summary>
/// The player's server side inventory data. /// The player's server side inventory data.
/// </summary> /// </summary>
public PlayerData PlayerData; public PlayerData PlayerData;
/// <summary> /// <summary>
/// Whether the player needs to specify a password upon connection( either server or user account ). /// Whether the player needs to specify a password upon connection( either server or user account ).
/// </summary> /// </summary>
public bool RequiresPassword; public bool RequiresPassword;
public bool SilentKickInProgress; public bool SilentKickInProgress;
public bool SilentJoinInProgress; public bool SilentJoinInProgress;
/// <summary> /// <summary>
/// A list of points where ice tiles have been placed. /// A list of points where ice tiles have been placed.
/// </summary> /// </summary>
public List<Point> IceTiles; public List<Point> IceTiles;
/// <summary> /// <summary>
/// Unused, can be removed. /// Unused, can be removed.
/// </summary> /// </summary>
public long RPm = 1; public long RPm = 1;
/// <summary> /// <summary>
/// World protection message cool down. /// World protection message cool down.
/// </summary> /// </summary>
public long WPm = 1; public long WPm = 1;
/// <summary> /// <summary>
/// Spawn protection message cool down. /// Spawn protection message cool down.
/// </summary> /// </summary>
public long SPm = 1; public long SPm = 1;
/// <summary> /// <summary>
/// Permission to build message cool down. /// Permission to build message cool down.
/// </summary> /// </summary>
public long BPm = 1; public long BPm = 1;
/// <summary> /// <summary>
/// The time in ms when the player has logged in. /// The time in ms when the player has logged in.
/// </summary> /// </summary>
public long LoginMS; public long LoginMS;
/// <summary> /// <summary>
/// Whether the player has been harrassed about logging in due to server side inventory or forced login. /// Whether the player has been harrassed about logging in due to server side inventory or forced login.
/// </summary> /// </summary>
public bool LoginHarassed = false; public bool LoginHarassed = false;
/// <summary> /// <summary>
@ -304,9 +304,14 @@ namespace TShockAPI
/// </summary> /// </summary>
public int LastKilledProjectile = 0; public int LastKilledProjectile = 0;
/// <summary> /// <summary>
/// Whether the player is a real, human, player on the server. /// The current region this player is in, or null if none.
/// </summary> /// </summary>
public Region CurrentRegion = null;
/// <summary>
/// Whether the player is a real, human, player on the server.
/// </summary>
public bool RealPlayer public bool RealPlayer
{ {
get { return Index >= 0 && Index < Main.maxNetPlayers && Main.player[Index] != null; } get { return Index >= 0 && Index < Main.maxNetPlayers && Main.player[Index] != null; }
@ -317,7 +322,7 @@ namespace TShockAPI
get get
{ {
return RealPlayer && return RealPlayer &&
(Netplay.serverSock[Index] != null && Netplay.serverSock[Index].active && !Netplay.serverSock[Index].kill); (Netplay.serverSock[Index] != null && Netplay.serverSock[Index].active && !Netplay.serverSock[Index].kill);
} }
} }
@ -372,28 +377,28 @@ namespace TShockAPI
} }
} }
/// <summary> /// <summary>
/// Saves the player's inventory to SSI /// Saves the player's inventory to SSI
/// </summary> /// </summary>
/// <returns>bool - True/false if it saved successfully</returns> /// <returns>bool - True/false if it saved successfully</returns>
public bool SaveServerCharacter() public bool SaveServerCharacter()
{ {
if (!Main.ServerSideCharacter) if (!Main.ServerSideCharacter)
{ {
return false; return false;
} }
try try
{ {
PlayerData.CopyCharacter(this); PlayerData.CopyCharacter(this);
TShock.CharacterDB.InsertPlayerData(this); TShock.CharacterDB.InsertPlayerData(this);
return true; return true;
} catch (Exception e) }
{ catch (Exception e)
Log.Error(e.Message); {
return false; TShock.Log.Error(e.Message);
} return false;
}
} }
/// <summary> /// <summary>
/// Sends the players server side character to client /// Sends the players server side character to client
@ -412,7 +417,7 @@ namespace TShockAPI
} }
catch (Exception e) catch (Exception e)
{ {
Log.Error(e.Message); TShock.Log.Error(e.Message);
return false; return false;
} }
@ -488,9 +493,9 @@ namespace TShockAPI
TilesDestroyed = new Dictionary<Vector2, Tile>(); TilesDestroyed = new Dictionary<Vector2, Tile>();
TilesCreated = new Dictionary<Vector2, Tile>(); TilesCreated = new Dictionary<Vector2, Tile>();
Index = index; Index = index;
Group = Group.DefaultGroup; Group = Group.DefaultGroup;
IceTiles = new List<Point>(); IceTiles = new List<Point>();
AwaitingResponse = new Dictionary<string, Action<object>>(); AwaitingResponse = new Dictionary<string, Action<object>>();
} }
protected TSPlayer(String playerName) protected TSPlayer(String playerName)
@ -499,8 +504,8 @@ namespace TShockAPI
TilesCreated = new Dictionary<Vector2, Tile>(); TilesCreated = new Dictionary<Vector2, Tile>();
Index = -1; Index = -1;
FakePlayer = new Player {name = playerName, whoAmi = -1}; FakePlayer = new Player {name = playerName, whoAmi = -1};
Group = Group.DefaultGroup; Group = Group.DefaultGroup;
AwaitingResponse = new Dictionary<string, Action<object>>(); AwaitingResponse = new Dictionary<string, Action<object>>();
} }
public virtual void Disconnect(string reason) public virtual void Disconnect(string reason)
@ -622,7 +627,6 @@ namespace TShockAPI
public void Spawn() public void Spawn()
{ {
// TPlayer.FindSpawn();
if (this.sX > 0 && this.sY > 0) if (this.sX > 0 && this.sY > 0)
{ {
Spawn(this.sX, this.sY); Spawn(this.sX, this.sY);
@ -662,8 +666,8 @@ namespace TShockAPI
} }
} }
public virtual bool SendTileSquare(int x, int y, int size = 10) public virtual bool SendTileSquare(int x, int y, int size = 10)
{ {
try try
{ {
int num = (size - 1)/2; int num = (size - 1)/2;
@ -707,22 +711,22 @@ namespace TShockAPI
} }
catch (Exception ex) catch (Exception ex)
{ {
Log.Error(ex.ToString()); TShock.Log.Error(ex.ToString());
} }
return false; return false;
} }
public bool GiveItemCheck(int type, string name, int width, int height, int stack, int prefix = 0) 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)) (TShock.Itembans.ItemIsBanned(name, this) || !TShock.Config.AllowAllowedGroupsToSpawnBannedItems))
return false; return false;
GiveItem(type,name,width,height,stack,prefix); GiveItem(type,name,width,height,stack,prefix);
return true; return true;
} }
public virtual void GiveItem(int type, string name, int width, int height, int stack, int prefix = 0) public virtual void GiveItem(int type, string name, int width, int height, int stack, int prefix = 0)
{ {
int itemid = Item.NewItem((int) X, (int) Y, width, height, type, stack, true, prefix, true); int itemid = Item.NewItem((int) X, (int) Y, width, height, type, stack, true, prefix, true);
@ -730,7 +734,7 @@ namespace TShockAPI
Main.item[itemid].SetDefaults(name); Main.item[itemid].SetDefaults(name);
// The set default overrides the wet and stack set by NewItem // The set default overrides the wet and stack set by NewItem
Main.item[itemid].wet = Collision.WetCollision(Main.item[itemid].position, Main.item[itemid].width, Main.item[itemid].wet = Collision.WetCollision(Main.item[itemid].position, Main.item[itemid].width,
Main.item[itemid].height); Main.item[itemid].height);
Main.item[itemid].stack = stack; Main.item[itemid].stack = stack;
Main.item[itemid].owner = Index; Main.item[itemid].owner = Index;
Main.item[itemid].prefix = (byte) prefix; Main.item[itemid].prefix = (byte) prefix;
@ -740,50 +744,44 @@ namespace TShockAPI
NetMessage.SendData((int)PacketTypes.ItemOwner, -1, -1, "", itemid, 0f, 0f, 0f); NetMessage.SendData((int)PacketTypes.ItemOwner, -1, -1, "", itemid, 0f, 0f, 0f);
} }
public virtual void SendInfoMessage(string msg) public virtual void SendInfoMessage(string msg)
{
SendMessage(msg, Color.Yellow);
}
public void SendInfoMessage(string format, params object[] args)
{
SendInfoMessage(string.Format(format, args));
}
public virtual void SendSuccessMessage(string msg)
{
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.OrangeRed);
}
public void SendWarningMessage(string format, params object[] args)
{
SendWarningMessage(string.Format(format, args));
}
public virtual void SendErrorMessage(string msg)
{
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); SendMessage(msg, Color.Yellow);
}
public void SendInfoMessage(string format, params object[] args)
{
SendInfoMessage(string.Format(format, args));
}
public virtual void SendSuccessMessage(string msg)
{
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.OrangeRed);
}
public void SendWarningMessage(string format, params object[] args)
{
SendWarningMessage(string.Format(format, args));
}
public virtual void SendErrorMessage(string msg)
{
SendMessage(msg, Color.Red);
}
public void SendErrorMessage(string format, params object[] args)
{
SendErrorMessage(string.Format(format, args));
} }
public virtual void SendMessage(string msg, Color color) public virtual void SendMessage(string msg, Color color)
@ -796,10 +794,10 @@ namespace TShockAPI
SendData(PacketTypes.ChatText, msg, 255, red, green, blue); SendData(PacketTypes.ChatText, msg, 255, red, green, blue);
} }
public virtual void SendMessageFromPlayer(string msg, byte red, byte green, byte blue, int ply) public virtual void SendMessageFromPlayer(string msg, byte red, byte green, byte blue, int ply)
{ {
SendDataFromPlayer(PacketTypes.ChatText, ply, msg, red, green, blue, 0); SendDataFromPlayer(PacketTypes.ChatText, ply, msg, red, green, blue, 0);
} }
public virtual void DamagePlayer(int damage) public virtual void DamagePlayer(int damage)
{ {
@ -836,11 +834,11 @@ namespace TShockAPI
{ {
if (displayConsole) if (displayConsole)
{ {
Log.ConsoleInfo(string.Format("Player {0} has been disabled for {1}.", Name, reason)); TShock.Log.ConsoleInfo("Player {0} has been disabled for {1}.", Name, reason);
} }
else else
{ {
Log.Info("Player {0} has been disabled for {1}.", Name, reason); TShock.Log.Info("Player {0} has been disabled for {1}.", Name, reason);
} }
LastDisableNotification = DateTime.UtcNow; LastDisableNotification = DateTime.UtcNow;
} }
@ -849,7 +847,7 @@ namespace TShockAPI
StackFrame frame = null; StackFrame frame = null;
frame = trace.GetFrame(1); frame = trace.GetFrame(1);
if (frame != null && frame.GetMethod().DeclaringType != null) if (frame != null && frame.GetMethod().DeclaringType != null)
Log.Debug(frame.GetMethod().DeclaringType.Name + " called Disable()."); TShock.Log.Debug(frame.GetMethod().DeclaringType.Name + " called Disable().");
} }
public virtual void Whoopie(object time) public virtual void Whoopie(object time)
@ -857,7 +855,7 @@ namespace TShockAPI
var time2 = (int) time; var time2 = (int) time;
var launch = DateTime.UtcNow; var launch = DateTime.UtcNow;
var startname = Name; var startname = Name;
SendMessage("You are now being annoyed.", Color.Red); SendInfoMessage("You are now being annoyed.");
while ((DateTime.UtcNow - launch).TotalSeconds < time2 && startname == Name) while ((DateTime.UtcNow - launch).TotalSeconds < time2 && startname == Name)
{ {
SendData(PacketTypes.NpcSpecial, number: Index, number2: 2f); SendData(PacketTypes.NpcSpecial, number: Index, number2: 2f);
@ -883,13 +881,13 @@ namespace TShockAPI
NetMessage.SendData((int) msgType, Index, -1, text, number, number2, number3, number4, number5); NetMessage.SendData((int) msgType, Index, -1, text, number, number2, number3, number4, number5);
} }
public virtual void SendDataFromPlayer(PacketTypes msgType, int ply, string text = "", float number2 = 0f, float number3 = 0f, float number4 = 0f, int number5 = 0) public virtual void SendDataFromPlayer(PacketTypes msgType, int ply, string text = "", float number2 = 0f, float number3 = 0f, float number4 = 0f, int number5 = 0)
{ {
if (RealPlayer && !ConnectionAlive) if (RealPlayer && !ConnectionAlive)
return; return;
NetMessage.SendData((int) msgType, Index, -1, text, ply, number2, number3, number4, number5); NetMessage.SendData((int) msgType, Index, -1, text, ply, number2, number3, number4, number5);
} }
public virtual void SendRawData(byte[] data) public virtual void SendRawData(byte[] data)
{ {
@ -898,20 +896,20 @@ namespace TShockAPI
NetMessage.SendBytes(Netplay.serverSock[Index], data, 0, data.Length, Netplay.serverSock[Index].ServerWriteCallBack, Netplay.serverSock[Index].networkStream); NetMessage.SendBytes(Netplay.serverSock[Index], data, 0, data.Length, Netplay.serverSock[Index].ServerWriteCallBack, Netplay.serverSock[Index].networkStream);
} }
/// <summary> /// <summary>
/// Adds a command callback to a specified command string. /// Adds a command callback to a specified command string.
/// </summary> /// </summary>
/// <param name="name">The string representing the command i.e "yes" == /yes</param> /// <param name="name">The string representing the command i.e "yes" == /yes</param>
/// <param name="callback">The method that will be executed on confirmation ie user accepts</param> /// <param name="callback">The method that will be executed on confirmation ie user accepts</param>
public void AddResponse( string name, Action<object> callback) public void AddResponse( string name, Action<object> callback)
{ {
if( AwaitingResponse.ContainsKey(name)) if( AwaitingResponse.ContainsKey(name))
{ {
AwaitingResponse.Remove(name); AwaitingResponse.Remove(name);
} }
AwaitingResponse.Add(name, callback); AwaitingResponse.Add(name, callback);
} }
} }
public class TSRestPlayer : TSPlayer public class TSRestPlayer : TSPlayer
@ -924,11 +922,6 @@ namespace TShockAPI
AwaitingResponse = new Dictionary<string, Action<object>>(); AwaitingResponse = new Dictionary<string, Action<object>>();
} }
public override void SendMessage(string msg)
{
SendMessage(msg, 0, 255, 0);
}
public override void SendMessage(string msg, Color color) public override void SendMessage(string msg, Color color)
{ {
SendMessage(msg, color.R, color.G, color.B); SendMessage(msg, color.R, color.G, color.B);
@ -967,45 +960,40 @@ namespace TShockAPI
public class TSServerPlayer : TSPlayer public class TSServerPlayer : TSPlayer
{ {
public static string AccountName = "ServerConsole"; public static string AccountName = "ServerConsole";
public TSServerPlayer() public TSServerPlayer()
: base("Server") : base("Server")
{ {
Group = new SuperAdminGroup(); Group = new SuperAdminGroup();
UserAccountName = AccountName; UserAccountName = AccountName;
} }
public override void SendErrorMessage(string msg) 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); 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, Color color) public override void SendMessage(string msg, Color color)
@ -1016,7 +1004,6 @@ namespace TShockAPI
public override void SendMessage(string msg, byte red, byte green, byte blue) public override void SendMessage(string msg, byte red, byte green, byte blue)
{ {
Console.WriteLine(msg); Console.WriteLine(msg);
//RconHandler.Response += msg + "\n";
} }
public void SetFullMoon() public void SetFullMoon()
@ -1093,7 +1080,7 @@ namespace TShockAPI
int spawnTileX; int spawnTileX;
int spawnTileY; int spawnTileY;
TShock.Utils.GetRandomClearTileWithInRange(startTileX, startTileY, tileXRange, tileYRange, out spawnTileX, TShock.Utils.GetRandomClearTileWithInRange(startTileX, startTileY, tileXRange, tileYRange, out spawnTileX,
out spawnTileY); out spawnTileY);
int npcid = NPC.NewNPC(spawnTileX*16, spawnTileY*16, type, 0); int npcid = NPC.NewNPC(spawnTileX*16, spawnTileY*16, type, 0);
// This is for special slimes // This is for special slimes
Main.npc[npcid].SetDefaults(name); Main.npc[npcid].SetDefaults(name);
@ -1407,19 +1394,19 @@ namespace TShockAPI
NetMessage.SendData(5, -1, -1, Main.player[player.Index].armor[8].name, player.Index, 67f, (float)Main.player[player.Index].armor[8].prefix, 0f, 0); NetMessage.SendData(5, -1, -1, Main.player[player.Index].armor[8].name, player.Index, 67f, (float)Main.player[player.Index].armor[8].prefix, 0f, 0);
NetMessage.SendData(5, -1, -1, Main.player[player.Index].armor[9].name, player.Index, 68f, (float)Main.player[player.Index].armor[9].prefix, 0f, 0); NetMessage.SendData(5, -1, -1, Main.player[player.Index].armor[9].name, player.Index, 68f, (float)Main.player[player.Index].armor[9].prefix, 0f, 0);
NetMessage.SendData(5, -1, -1, Main.player[player.Index].armor[10].name, player.Index, 69f, (float)Main.player[player.Index].armor[10].prefix, 0f, 0); NetMessage.SendData(5, -1, -1, Main.player[player.Index].armor[10].name, player.Index, 69f, (float)Main.player[player.Index].armor[10].prefix, 0f, 0);
NetMessage.SendData(5, -1, -1, Main.player[player.Index].armor[11].name, player.Index, 70f, (float)Main.player[player.Index].armor[11].prefix, 0f, 0); NetMessage.SendData(5, -1, -1, Main.player[player.Index].armor[11].name, player.Index, 70f, (float)Main.player[player.Index].armor[11].prefix, 0f, 0);
NetMessage.SendData(5, -1, -1, Main.player[player.Index].armor[12].name, player.Index, 71f, (float)Main.player[player.Index].armor[12].prefix, 0f, 0); NetMessage.SendData(5, -1, -1, Main.player[player.Index].armor[12].name, player.Index, 71f, (float)Main.player[player.Index].armor[12].prefix, 0f, 0);
NetMessage.SendData(5, -1, -1, Main.player[player.Index].armor[13].name, player.Index, 72f, (float)Main.player[player.Index].armor[13].prefix, 0f, 0); NetMessage.SendData(5, -1, -1, Main.player[player.Index].armor[13].name, player.Index, 72f, (float)Main.player[player.Index].armor[13].prefix, 0f, 0);
NetMessage.SendData(5, -1, -1, Main.player[player.Index].armor[14].name, player.Index, 73f, (float)Main.player[player.Index].armor[14].prefix, 0f, 0); NetMessage.SendData(5, -1, -1, Main.player[player.Index].armor[14].name, player.Index, 73f, (float)Main.player[player.Index].armor[14].prefix, 0f, 0);
NetMessage.SendData(5, -1, -1, Main.player[player.Index].armor[15].name, player.Index, 74f, (float)Main.player[player.Index].armor[15].prefix, 0f, 0); NetMessage.SendData(5, -1, -1, Main.player[player.Index].armor[15].name, player.Index, 74f, (float)Main.player[player.Index].armor[15].prefix, 0f, 0);
NetMessage.SendData(5, -1, -1, Main.player[player.Index].dye[0].name, player.Index, 75f, (float)Main.player[player.Index].dye[0].prefix, 0f, 0); NetMessage.SendData(5, -1, -1, Main.player[player.Index].dye[0].name, player.Index, 75f, (float)Main.player[player.Index].dye[0].prefix, 0f, 0);
NetMessage.SendData(5, -1, -1, Main.player[player.Index].dye[1].name, player.Index, 76f, (float)Main.player[player.Index].dye[1].prefix, 0f, 0); NetMessage.SendData(5, -1, -1, Main.player[player.Index].dye[1].name, player.Index, 76f, (float)Main.player[player.Index].dye[1].prefix, 0f, 0);
NetMessage.SendData(5, -1, -1, Main.player[player.Index].dye[2].name, player.Index, 77f, (float)Main.player[player.Index].dye[2].prefix, 0f, 0); NetMessage.SendData(5, -1, -1, Main.player[player.Index].dye[2].name, player.Index, 77f, (float)Main.player[player.Index].dye[2].prefix, 0f, 0);
NetMessage.SendData(5, -1, -1, Main.player[player.Index].dye[3].name, player.Index, 78f, (float)Main.player[player.Index].dye[3].prefix, 0f, 0); NetMessage.SendData(5, -1, -1, Main.player[player.Index].dye[3].name, player.Index, 78f, (float)Main.player[player.Index].dye[3].prefix, 0f, 0);
NetMessage.SendData(5, -1, -1, Main.player[player.Index].dye[4].name, player.Index, 79f, (float)Main.player[player.Index].dye[4].prefix, 0f, 0); NetMessage.SendData(5, -1, -1, Main.player[player.Index].dye[4].name, player.Index, 79f, (float)Main.player[player.Index].dye[4].prefix, 0f, 0);
NetMessage.SendData(5, -1, -1, Main.player[player.Index].dye[5].name, player.Index, 80f, (float)Main.player[player.Index].dye[5].prefix, 0f, 0); NetMessage.SendData(5, -1, -1, Main.player[player.Index].dye[5].name, player.Index, 80f, (float)Main.player[player.Index].dye[5].prefix, 0f, 0);
NetMessage.SendData(5, -1, -1, Main.player[player.Index].dye[6].name, player.Index, 81f, (float)Main.player[player.Index].dye[6].prefix, 0f, 0); NetMessage.SendData(5, -1, -1, Main.player[player.Index].dye[6].name, player.Index, 81f, (float)Main.player[player.Index].dye[6].prefix, 0f, 0);
NetMessage.SendData(5, -1, -1, Main.player[player.Index].dye[7].name, player.Index, 82f, (float)Main.player[player.Index].dye[7].prefix, 0f, 0); NetMessage.SendData(5, -1, -1, Main.player[player.Index].dye[7].name, player.Index, 82f, (float)Main.player[player.Index].dye[7].prefix, 0f, 0);
NetMessage.SendData(4, -1, -1, player.Name, player.Index, 0f, 0f, 0f, 0); NetMessage.SendData(4, -1, -1, player.Name, player.Index, 0f, 0f, 0f, 0);
NetMessage.SendData(42, -1, -1, "", player.Index, 0f, 0f, 0f, 0); NetMessage.SendData(42, -1, -1, "", player.Index, 0f, 0f, 0f, 0);
NetMessage.SendData(16, -1, -1, "", player.Index, 0f, 0f, 0f, 0); NetMessage.SendData(16, -1, -1, "", player.Index, 0f, 0f, 0f, 0);
@ -1428,30 +1415,31 @@ namespace TShockAPI
{ {
NetMessage.SendData(5, player.Index, -1, Main.player[player.Index].inventory[k].name, player.Index, (float)k, (float)Main.player[player.Index].inventory[k].prefix, 0f, 0); NetMessage.SendData(5, player.Index, -1, Main.player[player.Index].inventory[k].name, player.Index, (float)k, (float)Main.player[player.Index].inventory[k].prefix, 0f, 0);
} }
NetMessage.SendData(5, player.Index, -1, Main.player[player.Index].armor[0].name, player.Index, 59f, (float)Main.player[player.Index].armor[0].prefix, 0f, 0);
NetMessage.SendData(5, player.Index, -1, Main.player[player.Index].armor[1].name, player.Index, 60f, (float)Main.player[player.Index].armor[1].prefix, 0f, 0); NetMessage.SendData(5, player.Index, -1, Main.player[player.Index].armor[0].name, player.Index, 59f, (float)Main.player[player.Index].armor[0].prefix, 0f, 0);
NetMessage.SendData(5, player.Index, -1, Main.player[player.Index].armor[2].name, player.Index, 61f, (float)Main.player[player.Index].armor[2].prefix, 0f, 0); NetMessage.SendData(5, player.Index, -1, Main.player[player.Index].armor[1].name, player.Index, 60f, (float)Main.player[player.Index].armor[1].prefix, 0f, 0);
NetMessage.SendData(5, player.Index, -1, Main.player[player.Index].armor[3].name, player.Index, 62f, (float)Main.player[player.Index].armor[3].prefix, 0f, 0); NetMessage.SendData(5, player.Index, -1, Main.player[player.Index].armor[2].name, player.Index, 61f, (float)Main.player[player.Index].armor[2].prefix, 0f, 0);
NetMessage.SendData(5, player.Index, -1, Main.player[player.Index].armor[4].name, player.Index, 63f, (float)Main.player[player.Index].armor[4].prefix, 0f, 0); NetMessage.SendData(5, player.Index, -1, Main.player[player.Index].armor[3].name, player.Index, 62f, (float)Main.player[player.Index].armor[3].prefix, 0f, 0);
NetMessage.SendData(5, player.Index, -1, Main.player[player.Index].armor[5].name, player.Index, 64f, (float)Main.player[player.Index].armor[5].prefix, 0f, 0); NetMessage.SendData(5, player.Index, -1, Main.player[player.Index].armor[4].name, player.Index, 63f, (float)Main.player[player.Index].armor[4].prefix, 0f, 0);
NetMessage.SendData(5, player.Index, -1, Main.player[player.Index].armor[6].name, player.Index, 65f, (float)Main.player[player.Index].armor[6].prefix, 0f, 0); NetMessage.SendData(5, player.Index, -1, Main.player[player.Index].armor[5].name, player.Index, 64f, (float)Main.player[player.Index].armor[5].prefix, 0f, 0);
NetMessage.SendData(5, player.Index, -1, Main.player[player.Index].armor[7].name, player.Index, 66f, (float)Main.player[player.Index].armor[7].prefix, 0f, 0); NetMessage.SendData(5, player.Index, -1, Main.player[player.Index].armor[6].name, player.Index, 65f, (float)Main.player[player.Index].armor[6].prefix, 0f, 0);
NetMessage.SendData(5, player.Index, -1, Main.player[player.Index].armor[8].name, player.Index, 67f, (float)Main.player[player.Index].armor[8].prefix, 0f, 0); NetMessage.SendData(5, player.Index, -1, Main.player[player.Index].armor[7].name, player.Index, 66f, (float)Main.player[player.Index].armor[7].prefix, 0f, 0);
NetMessage.SendData(5, player.Index, -1, Main.player[player.Index].armor[9].name, player.Index, 68f, (float)Main.player[player.Index].armor[9].prefix, 0f, 0); NetMessage.SendData(5, player.Index, -1, Main.player[player.Index].armor[8].name, player.Index, 67f, (float)Main.player[player.Index].armor[8].prefix, 0f, 0);
NetMessage.SendData(5, player.Index, -1, Main.player[player.Index].armor[10].name, player.Index, 69f, (float)Main.player[player.Index].armor[10].prefix, 0f, 0); NetMessage.SendData(5, player.Index, -1, Main.player[player.Index].armor[9].name, player.Index, 68f, (float)Main.player[player.Index].armor[9].prefix, 0f, 0);
NetMessage.SendData(5, player.Index, -1, Main.player[player.Index].armor[11].name, player.Index, 70f, (float)Main.player[player.Index].armor[11].prefix, 0f, 0); NetMessage.SendData(5, player.Index, -1, Main.player[player.Index].armor[10].name, player.Index, 69f, (float)Main.player[player.Index].armor[10].prefix, 0f, 0);
NetMessage.SendData(5, player.Index, -1, Main.player[player.Index].armor[12].name, player.Index, 71f, (float)Main.player[player.Index].armor[12].prefix, 0f, 0); NetMessage.SendData(5, player.Index, -1, Main.player[player.Index].armor[11].name, player.Index, 70f, (float)Main.player[player.Index].armor[11].prefix, 0f, 0);
NetMessage.SendData(5, player.Index, -1, Main.player[player.Index].armor[13].name, player.Index, 72f, (float)Main.player[player.Index].armor[13].prefix, 0f, 0); NetMessage.SendData(5, player.Index, -1, Main.player[player.Index].armor[12].name, player.Index, 71f, (float)Main.player[player.Index].armor[12].prefix, 0f, 0);
NetMessage.SendData(5, player.Index, -1, Main.player[player.Index].armor[14].name, player.Index, 73f, (float)Main.player[player.Index].armor[14].prefix, 0f, 0); NetMessage.SendData(5, player.Index, -1, Main.player[player.Index].armor[13].name, player.Index, 72f, (float)Main.player[player.Index].armor[13].prefix, 0f, 0);
NetMessage.SendData(5, player.Index, -1, Main.player[player.Index].armor[15].name, player.Index, 74f, (float)Main.player[player.Index].armor[15].prefix, 0f, 0); NetMessage.SendData(5, player.Index, -1, Main.player[player.Index].armor[14].name, player.Index, 73f, (float)Main.player[player.Index].armor[14].prefix, 0f, 0);
NetMessage.SendData(5, player.Index, -1, Main.player[player.Index].dye[0].name, player.Index, 75f, (float)Main.player[player.Index].dye[0].prefix, 0f, 0); NetMessage.SendData(5, player.Index, -1, Main.player[player.Index].armor[15].name, player.Index, 74f, (float)Main.player[player.Index].armor[15].prefix, 0f, 0);
NetMessage.SendData(5, player.Index, -1, Main.player[player.Index].dye[1].name, player.Index, 76f, (float)Main.player[player.Index].dye[1].prefix, 0f, 0); NetMessage.SendData(5, player.Index, -1, Main.player[player.Index].dye[0].name, player.Index, 75f, (float)Main.player[player.Index].dye[0].prefix, 0f, 0);
NetMessage.SendData(5, player.Index, -1, Main.player[player.Index].dye[2].name, player.Index, 77f, (float)Main.player[player.Index].dye[2].prefix, 0f, 0); NetMessage.SendData(5, player.Index, -1, Main.player[player.Index].dye[1].name, player.Index, 76f, (float)Main.player[player.Index].dye[1].prefix, 0f, 0);
NetMessage.SendData(5, player.Index, -1, Main.player[player.Index].dye[3].name, player.Index, 78f, (float)Main.player[player.Index].dye[3].prefix, 0f, 0); NetMessage.SendData(5, player.Index, -1, Main.player[player.Index].dye[2].name, player.Index, 77f, (float)Main.player[player.Index].dye[2].prefix, 0f, 0);
NetMessage.SendData(5, player.Index, -1, Main.player[player.Index].dye[4].name, player.Index, 79f, (float)Main.player[player.Index].dye[4].prefix, 0f, 0); NetMessage.SendData(5, player.Index, -1, Main.player[player.Index].dye[3].name, player.Index, 78f, (float)Main.player[player.Index].dye[3].prefix, 0f, 0);
NetMessage.SendData(5, player.Index, -1, Main.player[player.Index].dye[5].name, player.Index, 80f, (float)Main.player[player.Index].dye[5].prefix, 0f, 0); NetMessage.SendData(5, player.Index, -1, Main.player[player.Index].dye[4].name, player.Index, 79f, (float)Main.player[player.Index].dye[4].prefix, 0f, 0);
NetMessage.SendData(5, player.Index, -1, Main.player[player.Index].dye[6].name, player.Index, 81f, (float)Main.player[player.Index].dye[6].prefix, 0f, 0); NetMessage.SendData(5, player.Index, -1, Main.player[player.Index].dye[5].name, player.Index, 80f, (float)Main.player[player.Index].dye[5].prefix, 0f, 0);
NetMessage.SendData(5, player.Index, -1, Main.player[player.Index].dye[7].name, player.Index, 82f, (float)Main.player[player.Index].dye[7].prefix, 0f, 0); NetMessage.SendData(5, player.Index, -1, Main.player[player.Index].dye[6].name, player.Index, 81f, (float)Main.player[player.Index].dye[6].prefix, 0f, 0);
NetMessage.SendData(5, player.Index, -1, Main.player[player.Index].dye[7].name, player.Index, 82f, (float)Main.player[player.Index].dye[7].prefix, 0f, 0);
NetMessage.SendData(4, player.Index, -1, player.Name, player.Index, 0f, 0f, 0f, 0); NetMessage.SendData(4, player.Index, -1, player.Name, player.Index, 0f, 0f, 0f, 0);
NetMessage.SendData(42, player.Index, -1, "", player.Index, 0f, 0f, 0f, 0); NetMessage.SendData(42, player.Index, -1, "", player.Index, 0f, 0f, 0f, 0);
NetMessage.SendData(16, player.Index, -1, "", player.Index, 0f, 0f, 0f, 0); NetMessage.SendData(16, player.Index, -1, "", player.Index, 0f, 0f, 0f, 0);

View file

@ -36,29 +36,27 @@ using Terraria;
using TerrariaApi.Server; using TerrariaApi.Server;
using TShockAPI.DB; using TShockAPI.DB;
using TShockAPI.Net; using TShockAPI.Net;
using System.Threading;
using System.Threading.Tasks;
using TShockAPI.ServerSideCharacters; using TShockAPI.ServerSideCharacters;
namespace TShockAPI namespace TShockAPI
{ {
[ApiVersion(1, 16)] [ApiVersion(1, 17)]
public class TShock : TerrariaPlugin public class TShock : TerrariaPlugin
{ {
public static readonly Version VersionNum = Assembly.GetExecutingAssembly().GetName().Version; public static readonly Version VersionNum = Assembly.GetExecutingAssembly().GetName().Version;
public static readonly string VersionCodename = "And the great beast rose from its slumber, ready to take on the world again."; public static readonly string VersionCodename = "2015!!";
public static string SavePath = "tshock"; public static string SavePath = "tshock";
private const string LogFormatDefault = "yyyy-MM-dd_HH-mm-ss"; private const string LogFormatDefault = "yyyy-MM-dd_HH-mm-ss";
private static string LogFormat = LogFormatDefault; private static string LogFormat = LogFormatDefault;
private const string LogPathDefault = "tshock"; private const string LogPathDefault = "tshock";
private static string LogPath = LogPathDefault; private static string LogPath = LogPathDefault;
private static bool LogClear = false; private static bool LogClear;
public static TSPlayer[] Players = new TSPlayer[Main.maxPlayers]; public static TSPlayer[] Players = new TSPlayer[Main.maxPlayers];
public static BanManager Bans; public static BanManager Bans;
public static WarpManager Warps; public static WarpManager Warps;
public static RegionManager Regions; public static RegionManager Regions;
public static BackupManager Backups; public static BackupManager Backups;
public static GroupManager Groups; public static GroupManager Groups;
public static UserManager Users; public static UserManager Users;
@ -76,7 +74,9 @@ namespace TShockAPI
public static SecureRest RestApi; public static SecureRest RestApi;
public static RestManager RestManager; public static RestManager RestManager;
public static Utils Utils = Utils.Instance; public static Utils Utils = Utils.Instance;
public static StatTracker StatTracker = new StatTracker();
public static UpdateManager UpdateManager; public static UpdateManager UpdateManager;
public static ILog Log;
/// <summary> /// <summary>
/// Used for implementing REST Tokens prior to the REST system starting up. /// Used for implementing REST Tokens prior to the REST system starting up.
/// </summary> /// </summary>
@ -107,10 +107,6 @@ namespace TShockAPI
get { return "The administration modification of the future."; } get { return "The administration modification of the future."; }
} }
public override string UpdateURL
{
get { return ""; }
}
public TShock(Main game) public TShock(Main game)
: base(game) : base(game)
{ {
@ -126,13 +122,13 @@ namespace TShockAPI
[SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands")] [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands")]
public override void Initialize() public override void Initialize()
{ {
string logFilename;
string logPathSetupWarning;
try try
{ {
HandleCommandLine(Environment.GetCommandLineArgs()); HandleCommandLine(Environment.GetCommandLineArgs());
if (Version.Major >= 4)
getTShockAscii();
if (!Directory.Exists(SavePath)) if (!Directory.Exists(SavePath))
Directory.CreateDirectory(SavePath); Directory.CreateDirectory(SavePath);
@ -142,37 +138,29 @@ namespace TShockAPI
Main.ServerSideCharacter = ServerSideCharacterConfig.Enabled; Main.ServerSideCharacter = ServerSideCharacterConfig.Enabled;
DateTime now = DateTime.Now; DateTime now = DateTime.Now;
string logFilename;
string logPathSetupWarning = null;
// Log path was not already set by the command line parameter? // Log path was not already set by the command line parameter?
if (LogPath == LogPathDefault) if (LogPath == LogPathDefault)
LogPath = Config.LogPath; LogPath = Config.LogPath;
try try
{ {
logFilename = Path.Combine(LogPath, now.ToString(LogFormat)+".log"); logFilename = Path.Combine(LogPath, now.ToString(LogFormat) + ".log");
if (!Directory.Exists(LogPath)) if (!Directory.Exists(LogPath))
Directory.CreateDirectory(LogPath); Directory.CreateDirectory(LogPath);
} }
catch(Exception ex) catch (Exception ex)
{ {
logPathSetupWarning = "Could not apply the given log path / log format, defaults will be used. Exception details:\n" + ex; logPathSetupWarning =
Console.ForegroundColor = ConsoleColor.Red; "Could not apply the given log path / log format, defaults will be used. Exception details:\n" + ex;
Console.WriteLine(logPathSetupWarning);
Console.ForegroundColor = ConsoleColor.Gray; ServerApi.LogWriter.PluginWriteLine(this, logPathSetupWarning, TraceLevel.Error);
// Problem with the log path or format use the default // Problem with the log path or format use the default
logFilename = Path.Combine(LogPathDefault, now.ToString(LogFormatDefault) + ".log"); logFilename = Path.Combine(LogPathDefault, now.ToString(LogFormatDefault) + ".log");
} }
#if DEBUG
Log.Initialize(logFilename, LogLevel.All, false);
#else
Log.Initialize(logFilename, LogLevel.All & ~LogLevel.Debug, LogClear);
#endif
if (logPathSetupWarning != null)
Log.Warn(logPathSetupWarning);
AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException; AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
} }
catch(Exception ex) catch (Exception ex)
{ {
// Will be handled by the server api and written to its crashlog.txt. // 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); throw new Exception("Fatal TShock initialization exception. See inner exception for details.", ex);
@ -181,16 +169,6 @@ namespace TShockAPI
// Further exceptions are written to TShock's log from now on. // Further exceptions are written to TShock's log from now on.
try try
{ {
if (File.Exists(Path.Combine(SavePath, "tshock.pid")))
{
Log.ConsoleInfo(
"TShock was improperly shut down. Please use the exit command in the future to prevent this.");
File.Delete(Path.Combine(SavePath, "tshock.pid"));
}
File.WriteAllText(Path.Combine(SavePath, "tshock.pid"), Process.GetCurrentProcess().Id.ToString(CultureInfo.InvariantCulture));
HandleCommandLinePostConfigLoad(Environment.GetCommandLineArgs());
if (Config.StorageType.ToLower() == "sqlite") if (Config.StorageType.ToLower() == "sqlite")
{ {
string sql = Path.Combine(SavePath, "tshock.sqlite"); string sql = Path.Combine(SavePath, "tshock.sqlite");
@ -204,16 +182,16 @@ namespace TShockAPI
DB = new MySqlConnection(); DB = new MySqlConnection();
DB.ConnectionString = DB.ConnectionString =
String.Format("Server={0}; Port={1}; Database={2}; Uid={3}; Pwd={4};", String.Format("Server={0}; Port={1}; Database={2}; Uid={3}; Pwd={4};",
hostport[0], hostport[0],
hostport.Length > 1 ? hostport[1] : "3306", hostport.Length > 1 ? hostport[1] : "3306",
Config.MySqlDbName, Config.MySqlDbName,
Config.MySqlUsername, Config.MySqlUsername,
Config.MySqlPassword Config.MySqlPassword
); );
} }
catch (MySqlException ex) catch (MySqlException ex)
{ {
Log.Error(ex.ToString()); ServerApi.LogWriter.PluginWriteLine(this, ex.ToString(), TraceLevel.Error);
throw new Exception("MySql not setup correctly"); throw new Exception("MySql not setup correctly");
} }
} }
@ -222,12 +200,33 @@ namespace TShockAPI
throw new Exception("Invalid storage type"); throw new Exception("Invalid storage type");
} }
#if DEBUG
var level = LogLevel.All;
#else
var level = LogLevel.All & ~LogLevel.Debug;
#endif
if (Config.UseSqlLogs)
Log = new SqlLog(level, DB, logFilename, LogClear);
else
Log = new TextLog(logFilename, level, LogClear);
if (File.Exists(Path.Combine(SavePath, "tshock.pid")))
{
Log.ConsoleInfo(
"TShock was improperly shut down. Please use the exit command in the future to prevent this.");
File.Delete(Path.Combine(SavePath, "tshock.pid"));
}
File.WriteAllText(Path.Combine(SavePath, "tshock.pid"),
Process.GetCurrentProcess().Id.ToString(CultureInfo.InvariantCulture));
HandleCommandLinePostConfigLoad(Environment.GetCommandLineArgs());
Backups = new BackupManager(Path.Combine(SavePath, "backups")); Backups = new BackupManager(Path.Combine(SavePath, "backups"));
Backups.KeepFor = Config.BackupKeepFor; Backups.KeepFor = Config.BackupKeepFor;
Backups.Interval = Config.BackupInterval; Backups.Interval = Config.BackupInterval;
Bans = new BanManager(DB); Bans = new BanManager(DB);
Warps = new WarpManager(DB); Warps = new WarpManager(DB);
Regions = new RegionManager(DB); Regions = new RegionManager(DB);
Users = new UserManager(DB); Users = new UserManager(DB);
Groups = new GroupManager(DB); Groups = new GroupManager(DB);
Itembans = new ItemManager(DB); Itembans = new ItemManager(DB);
@ -244,7 +243,7 @@ namespace TShockAPI
if (Config.EnableGeoIP && File.Exists(geoippath)) if (Config.EnableGeoIP && File.Exists(geoippath))
Geo = new GeoIPCountry(geoippath); Geo = new GeoIPCountry(geoippath);
Log.ConsoleInfo(string.Format("|> Version {0} ({1}) now running.", Version, VersionCodename)); Log.ConsoleInfo("TShock {0} ({1}) now running.", Version, VersionCodename);
ServerApi.Hooks.GamePostInitialize.Register(this, OnPostInit); ServerApi.Hooks.GamePostInitialize.Register(this, OnPostInit);
ServerApi.Hooks.GameUpdate.Register(this, OnUpdate); ServerApi.Hooks.GameUpdate.Register(this, OnUpdate);
@ -262,15 +261,16 @@ namespace TShockAPI
ServerApi.Hooks.ProjectileSetDefaults.Register(this, OnProjectileSetDefaults); ServerApi.Hooks.ProjectileSetDefaults.Register(this, OnProjectileSetDefaults);
ServerApi.Hooks.WorldStartHardMode.Register(this, OnStartHardMode); ServerApi.Hooks.WorldStartHardMode.Register(this, OnStartHardMode);
ServerApi.Hooks.WorldSave.Register(this, SaveManager.Instance.OnSaveWorld); ServerApi.Hooks.WorldSave.Register(this, SaveManager.Instance.OnSaveWorld);
ServerApi.Hooks.WorldChristmasCheck.Register(this, OnXmasCheck); ServerApi.Hooks.WorldChristmasCheck.Register(this, OnXmasCheck);
ServerApi.Hooks.WorldHalloweenCheck.Register(this, OnHalloweenCheck); ServerApi.Hooks.WorldHalloweenCheck.Register(this, OnHalloweenCheck);
ServerApi.Hooks.NetNameCollision.Register(this, NetHooks_NameCollision); ServerApi.Hooks.NetNameCollision.Register(this, NetHooks_NameCollision);
TShockAPI.Hooks.PlayerHooks.PlayerPreLogin += OnPlayerPreLogin; Hooks.PlayerHooks.PlayerPreLogin += OnPlayerPreLogin;
TShockAPI.Hooks.PlayerHooks.PlayerPostLogin += OnPlayerLogin; Hooks.PlayerHooks.PlayerPostLogin += OnPlayerLogin;
Hooks.AccountHooks.AccountDelete += OnAccountDelete;
Hooks.AccountHooks.AccountCreate += OnAccountCreate;
GetDataHandlers.InitGetDataHandler(); GetDataHandlers.InitGetDataHandler();
Commands.InitCommands(); Commands.InitCommands();
//RconHandler.StartThread();
if (Config.RestApiEnabled) if (Config.RestApiEnabled)
RestApi.Start(); RestApi.Start();
@ -283,6 +283,8 @@ namespace TShockAPI
if (Initialized != null) if (Initialized != null)
Initialized(); Initialized();
Log.ConsoleInfo("Welcome to TShock for Terraria. Initialization complete.");
} }
catch (Exception ex) catch (Exception ex)
{ {
@ -292,25 +294,6 @@ namespace TShockAPI
} }
} }
private static void getTShockAscii()
{
// ReSharper disable LocalizableElement
Console.Write(" ___ ___ ___ ___ ___ \n" +
" ___ / /\\ /__/\\ / /\\ / /\\ /__/| \n" +
" / /\\ / /:/_ \\ \\:\\ / /::\\ / /:/ | |:| \n" +
" / /:/ / /:/ /\\ \\__\\:\\ / /:/\\:\\ / /:/ | |:| \n" +
" / /:/ / /:/ /::\\ ___ / /::\\ / /:/ \\:\\ / /:/ ___ __| |:| \n" +
" / /::\\ /__/:/ /:/\\:\\/__/\\ /:/\\:\\/__/:/ \\__\\:\\/__/:/ / /\\/__/\\_|:|____\n" +
"/__/:/\\:\\\\ \\:\\/:/~/:/\\ \\:\\/:/__\\/\\ \\:\\ / /:/\\ \\:\\ / /:/\\ \\:\\/:::::/\n" +
"\\__\\/ \\:\\\\ \\::/ /:/ \\ \\::/ \\ \\:\\ /:/ \\ \\:\\ /:/ \\ \\::/~~~~ \n" +
" \\ \\:\\\\__\\/ /:/ \\ \\:\\ \\ \\:\\/:/ \\ \\:\\/:/ \\ \\:\\ \n" +
" \\__\\/ /__/:/ \\ \\:\\ \\ \\::/ \\ \\::/ \\ \\:\\ \n" +
" \\__\\/ \\__\\/ \\__\\/ \\__\\/ \\__\\/ \n" +
"");
Console.WriteLine("TShock for Terraria is open & free software. If you paid, you were scammed.");
// ReSharper restore LocalizableElement
}
protected override void Dispose(bool disposing) protected override void Dispose(bool disposing)
{ {
if (disposing) if (disposing)
@ -342,7 +325,7 @@ namespace TShockAPI
ServerApi.Hooks.WorldChristmasCheck.Deregister(this, OnXmasCheck); ServerApi.Hooks.WorldChristmasCheck.Deregister(this, OnXmasCheck);
ServerApi.Hooks.WorldHalloweenCheck.Deregister(this, OnHalloweenCheck); ServerApi.Hooks.WorldHalloweenCheck.Deregister(this, OnHalloweenCheck);
ServerApi.Hooks.NetNameCollision.Deregister(this, NetHooks_NameCollision); ServerApi.Hooks.NetNameCollision.Deregister(this, NetHooks_NameCollision);
TShockAPI.Hooks.PlayerHooks.PlayerPostLogin -= OnPlayerLogin; TShockAPI.Hooks.PlayerHooks.PlayerPostLogin -= OnPlayerLogin;
if (File.Exists(Path.Combine(SavePath, "tshock.pid"))) if (File.Exists(Path.Combine(SavePath, "tshock.pid")))
{ {
@ -379,6 +362,16 @@ namespace TShockAPI
Users.UpdateLogin(u); Users.UpdateLogin(u);
} }
private void OnAccountDelete(Hooks.AccountDeleteEventArgs args)
{
CharacterDB.RemovePlayer(args.User.ID);
}
private void OnAccountCreate(Hooks.AccountCreateEventArgs args)
{
CharacterDB.SeedInitialData(Users.GetUser(args.User));
}
private void OnPlayerPreLogin(Hooks.PlayerPreLoginEventArgs args) private void OnPlayerPreLogin(Hooks.PlayerPreLoginEventArgs args)
{ {
if (args.Player.IsLoggedIn) if (args.Player.IsLoggedIn)
@ -418,17 +411,17 @@ namespace TShockAPI
} }
} }
private void OnXmasCheck(ChristmasCheckEventArgs args) private void OnXmasCheck(ChristmasCheckEventArgs args)
{ {
if (args.Handled) if (args.Handled)
return; return;
if(Config.ForceXmas) if(Config.ForceXmas)
{ {
args.Xmas = true; args.Xmas = true;
args.Handled = true; args.Handled = true;
}
} }
}
private void OnHalloweenCheck(HalloweenCheckEventArgs args) private void OnHalloweenCheck(HalloweenCheckEventArgs args)
{ {
@ -572,14 +565,14 @@ namespace TShockAPI
private void OnPostInit(EventArgs args) private void OnPostInit(EventArgs args)
{ {
SetConsoleTitle(); SetConsoleTitle(false);
if (!File.Exists(Path.Combine(SavePath, "auth.lck")) && !File.Exists(Path.Combine(SavePath, "authcode.txt"))) if (!File.Exists(Path.Combine(SavePath, "auth.lck")) && !File.Exists(Path.Combine(SavePath, "authcode.txt")))
{ {
var r = new Random((int) DateTime.Now.ToBinary()); var r = new Random((int) DateTime.Now.ToBinary());
AuthToken = r.Next(100000, 10000000); AuthToken = r.Next(100000, 10000000);
Console.ForegroundColor = ConsoleColor.Yellow; Console.ForegroundColor = ConsoleColor.Yellow;
Console.WriteLine("TShock Notice: To become SuperAdmin, join the game and type /auth " + AuthToken); Console.WriteLine("TShock Notice: To become SuperAdmin, join the game and type {0}auth {1}", Commands.Specifier, AuthToken);
Console.WriteLine("This token will display until disabled by verification. (/auth-verify)"); Console.WriteLine("This token will display until disabled by verification. ({0}auth-verify)", Commands.Specifier);
Console.ForegroundColor = ConsoleColor.Gray; Console.ForegroundColor = ConsoleColor.Gray;
FileTools.CreateFile(Path.Combine(SavePath, "authcode.txt")); FileTools.CreateFile(Path.Combine(SavePath, "authcode.txt"));
using (var tw = new StreamWriter(Path.Combine(SavePath, "authcode.txt"))) using (var tw = new StreamWriter(Path.Combine(SavePath, "authcode.txt")))
@ -596,8 +589,8 @@ namespace TShockAPI
Console.ForegroundColor = ConsoleColor.Yellow; Console.ForegroundColor = ConsoleColor.Yellow;
Console.WriteLine( Console.WriteLine(
"TShock Notice: authcode.txt is still present, and the AuthToken located in that file will be used."); "TShock Notice: authcode.txt is still present, and the AuthToken located in that file will be used.");
Console.WriteLine("To become superadmin, join the game and type /auth " + AuthToken); Console.WriteLine("To become superadmin, join the game and type {0}auth {1}", Commands.Specifier, AuthToken);
Console.WriteLine("This token will display until disabled by verification. (/auth-verify)"); Console.WriteLine("This token will display until disabled by verification. ({0}auth-verify)", Commands.Specifier);
Console.ForegroundColor = ConsoleColor.Gray; Console.ForegroundColor = ConsoleColor.Gray;
} }
else else
@ -613,6 +606,7 @@ namespace TShockAPI
FixChestStacks(); FixChestStacks();
UpdateManager = new UpdateManager(); UpdateManager = new UpdateManager();
StatTracker.Initialize();
} }
private void ComputeMaxStyles() private void ComputeMaxStyles()
@ -811,7 +805,7 @@ namespace TShockAPI
player.SetBuff(36, 120); //Broken Armor player.SetBuff(36, 120); //Broken Armor
check = "Remove armor/accessory " + item.name; check = "Remove armor/accessory " + item.name;
player.SendErrorMessage(string.Format("You are wearing banned equipment. {0}", check)); player.SendErrorMessage("You are wearing banned equipment. {0}", check);
break; break;
} }
} }
@ -824,16 +818,32 @@ namespace TShockAPI
{ {
player.SetBuff(23, 120); //Cursed player.SetBuff(23, 120); //Cursed
} }
var oldRegion = player.CurrentRegion;
player.CurrentRegion = Regions.GetTopRegion(Regions.InAreaRegion(player.TileX, player.TileY));
if (oldRegion != player.CurrentRegion)
{
if (oldRegion != null)
{
Hooks.RegionHooks.OnRegionLeft(player, oldRegion);
}
if (player.CurrentRegion != null)
{
Hooks.RegionHooks.OnRegionEntered(player);
}
}
} }
} }
SetConsoleTitle(); SetConsoleTitle(false);
} }
private void SetConsoleTitle() private void SetConsoleTitle(bool empty)
{ {
Console.Title = string.Format("{0}{1}/{2} @ {3}:{4} (TerrariaShock v{5})", Console.Title = string.Format("{0}{1}/{2} @ {3}:{4} (TShock for Terraria v{5})",
!string.IsNullOrWhiteSpace(Config.ServerName) ? Config.ServerName + " - " : "", !string.IsNullOrWhiteSpace(Config.ServerName) ? Config.ServerName + " - " : "",
Utils.ActivePlayers(), empty ? 0 : Utils.ActivePlayers(),
Config.MaxSlots, Netplay.serverListenIP, Netplay.serverPort, Version); Config.MaxSlots, Netplay.serverListenIP, Netplay.serverPort, Version);
} }
@ -997,7 +1007,7 @@ namespace TShockAPI
{ {
if (!tsplr.SilentKickInProgress && tsplr.State >= 3) if (!tsplr.SilentKickInProgress && tsplr.State >= 3)
Utils.Broadcast(tsplr.Name + " has left.", Color.Yellow); Utils.Broadcast(tsplr.Name + " has left.", Color.Yellow);
Log.Info(string.Format("{0} disconnected.", tsplr.Name)); Log.Info("{0} disconnected.", tsplr.Name);
if (tsplr.IsLoggedIn && !tsplr.IgnoreActionsForClearingTrashCan && Main.ServerSideCharacter && (!tsplr.Dead || tsplr.TPlayer.difficulty != 2)) if (tsplr.IsLoggedIn && !tsplr.IgnoreActionsForClearingTrashCan && Main.ServerSideCharacter && (!tsplr.Dead || tsplr.TPlayer.difficulty != 2))
{ {
@ -1010,6 +1020,14 @@ namespace TShockAPI
RememberedPos.InsertLeavePos(tsplr.Name, tsplr.IP, (int) (tsplr.X/16), (int) (tsplr.Y/16)); RememberedPos.InsertLeavePos(tsplr.Name, tsplr.IP, (int) (tsplr.X/16), (int) (tsplr.Y/16));
} }
} }
// The last player will leave after this hook is executed.
if (Utils.ActivePlayers() == 1)
{
if (Config.SaveWorldOnLastPlayerExit)
SaveManager.Instance.SaveWorld();
SetConsoleTitle(true);
}
} }
private void OnChat(ServerChatEventArgs args) private void OnChat(ServerChatEventArgs args)
@ -1037,7 +1055,8 @@ namespace TShockAPI
return; return;
}*/ }*/
if (args.Text.StartsWith(Config.CommandSpecifier) && !string.IsNullOrWhiteSpace(args.Text.Substring(1))) if ((args.Text.StartsWith(Config.CommandSpecifier) || args.Text.StartsWith(Config.CommandSilentSpecifier))
&& !string.IsNullOrWhiteSpace(args.Text.Substring(1)))
{ {
try try
{ {
@ -1045,7 +1064,7 @@ namespace TShockAPI
} }
catch (Exception ex) catch (Exception ex)
{ {
Log.ConsoleError("Command exception"); Log.ConsoleError("An exeption occurred executing a command.");
Log.Error(ex.ToString()); Log.Error(ex.ToString());
} }
} }
@ -1087,7 +1106,7 @@ namespace TShockAPI
tsplr.SendMessage(msg, tsplr.Group.R, tsplr.Group.G, tsplr.Group.B); tsplr.SendMessage(msg, tsplr.Group.R, tsplr.Group.G, tsplr.Group.B);
TSPlayer.Server.SendMessage(msg, tsplr.Group.R, tsplr.Group.G, tsplr.Group.B); TSPlayer.Server.SendMessage(msg, tsplr.Group.R, tsplr.Group.G, tsplr.Group.B);
Log.Info(string.Format("Broadcast: {0}", msg)); Log.Info("Broadcast: {0}", msg);
args.Handled = true; args.Handled = true;
} }
} }
@ -1113,7 +1132,7 @@ namespace TShockAPI
WorldGen.genRand = new Random(); WorldGen.genRand = new Random();
} }
if (args.Command.StartsWith("playing") || args.Command.StartsWith("/playing")) if (args.Command.StartsWith("playing") || args.Command.StartsWith("{0}playing".SFormat(Commands.Specifier)))
{ {
int count = 0; int count = 0;
foreach (TSPlayer player in Players) foreach (TSPlayer player in Players)
@ -1121,18 +1140,18 @@ namespace TShockAPI
if (player != null && player.Active) if (player != null && player.Active)
{ {
count++; count++;
TSPlayer.Server.SendInfoMessage(string.Format("{0} ({1}) [{2}] <{3}>", player.Name, player.IP, TSPlayer.Server.SendInfoMessage("{0} ({1}) [{2}] <{3}>", player.Name, player.IP,
player.Group.Name, player.UserAccountName)); player.Group.Name, player.UserAccountName);
} }
} }
TSPlayer.Server.SendInfoMessage(string.Format("{0} players connected.", count)); TSPlayer.Server.SendInfoMessage("{0} players connected.", count);
} }
else if (args.Command == "autosave") else if (args.Command == "autosave")
{ {
Main.autoSave = Config.AutoSave = !Config.AutoSave; Main.autoSave = Config.AutoSave = !Config.AutoSave;
Log.ConsoleInfo("AutoSave " + (Config.AutoSave ? "Enabled" : "Disabled")); Log.ConsoleInfo("AutoSave " + (Config.AutoSave ? "Enabled" : "Disabled"));
} }
else if (args.Command.StartsWith("/")) else if (args.Command.StartsWith(Commands.Specifier))
{ {
Commands.HandleCommand(TSPlayer.Server, args.Command); Commands.HandleCommand(TSPlayer.Server, args.Command);
} }
@ -1190,24 +1209,24 @@ namespace TShockAPI
player.LoginMS = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond; player.LoginMS = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond;
if (TShock.Config.EnableGeoIP && TShock.Geo != null) if (Config.EnableGeoIP && TShock.Geo != null)
{ {
Log.Info(string.Format("{0} ({1}) from '{2}' group from '{3}' joined. ({4}/{5})", player.Name, player.IP, Log.Info("{0} ({1}) from '{2}' group from '{3}' joined. ({4}/{5})", player.Name, player.IP,
player.Group.Name, player.Country, TShock.Utils.ActivePlayers(), player.Group.Name, player.Country, TShock.Utils.ActivePlayers(),
TShock.Config.MaxSlots)); TShock.Config.MaxSlots);
if (!player.SilentJoinInProgress) if (!player.SilentJoinInProgress)
TShock.Utils.Broadcast(string.Format("{0} ({1}) has joined.", player.Name, player.Country), Color.Yellow); Utils.Broadcast(string.Format("{0} ({1}) has joined.", player.Name, player.Country), Color.Yellow);
} }
else else
{ {
Log.Info(string.Format("{0} ({1}) from '{2}' group joined. ({3}/{4})", player.Name, player.IP, Log.Info("{0} ({1}) from '{2}' group joined. ({3}/{4})", player.Name, player.IP,
player.Group.Name, TShock.Utils.ActivePlayers(), TShock.Config.MaxSlots)); player.Group.Name, TShock.Utils.ActivePlayers(), TShock.Config.MaxSlots);
if (!player.SilentJoinInProgress) if (!player.SilentJoinInProgress)
TShock.Utils.Broadcast(player.Name + " has joined.", Color.Yellow); Utils.Broadcast(player.Name + " has joined.", Color.Yellow);
} }
if (TShock.Config.DisplayIPToAdmins) if (Config.DisplayIPToAdmins)
TShock.Utils.SendLogs(string.Format("{0} has joined. IP: {1}", player.Name, player.IP), Color.Blue); Utils.SendLogs(string.Format("{0} has joined. IP: {1}", player.Name, player.IP), Color.Blue);
Utils.ShowFileToUser(player, "motd.txt"); Utils.ShowFileToUser(player, "motd.txt");
@ -1223,14 +1242,13 @@ namespace TShockAPI
{ {
if (Main.ServerSideCharacter) if (Main.ServerSideCharacter)
{ {
player.SendMessage( player.SendErrorMessage(
player.IgnoreActionsForInventory = "Server side characters is enabled! Please /register or /login to play!", player.IgnoreActionsForInventory = "Server side characters is enabled! Please {0}register or {0}login to play!", Commands.Specifier);
Color.Red);
player.LoginHarassed = true; player.LoginHarassed = true;
} }
else if (Config.RequireLogin) else if (Config.RequireLogin)
{ {
player.SendMessage("Please /register or /login to play!", Color.Red); player.SendErrorMessage("Please {0}register or {0}login to play!", Commands.Specifier);
player.LoginHarassed = true; player.LoginHarassed = true;
} }
} }
@ -1240,7 +1258,7 @@ namespace TShockAPI
if (Config.RememberLeavePos && (RememberedPos.GetLeavePos(player.Name, player.IP) != Vector2.Zero) && !player.LoginHarassed) if (Config.RememberLeavePos && (RememberedPos.GetLeavePos(player.Name, player.IP) != Vector2.Zero) && !player.LoginHarassed)
{ {
player.RPPending = 3; player.RPPending = 3;
player.SendMessage("You will be teleported to your last known location...", Color.Red); player.SendInfoMessage("You will be teleported to your last known location...");
} }
args.Handled = true; args.Handled = true;
@ -1552,7 +1570,7 @@ namespace TShockAPI
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.SendErrorMessage("You do not have permission to build!");
player.BPm = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond; player.BPm = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond;
} }
return true; return true;
@ -1566,7 +1584,7 @@ namespace TShockAPI
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.SendErrorMessage("You do not have permission to build!");
player.BPm = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond; player.BPm = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond;
} }
return true; return true;
@ -1577,7 +1595,7 @@ namespace TShockAPI
{ {
if (((DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond) - player.RPm) > 2000) if (((DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond) - player.RPm) > 2000)
{ {
player.SendMessage("This region is protected from changes.", Color.Red); player.SendErrorMessage("This region is protected from changes.");
player.RPm = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond; player.RPm = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond;
} }
return true; return true;
@ -1589,7 +1607,7 @@ namespace TShockAPI
{ {
if (((DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond) - player.WPm) > 2000) if (((DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond) - player.WPm) > 2000)
{ {
player.SendMessage("The world is protected from changes.", Color.Red); player.SendErrorMessage("The world is protected from changes.");
player.WPm = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond; player.WPm = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond;
} }
return true; return true;
@ -1604,7 +1622,7 @@ namespace TShockAPI
{ {
if (((DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond) - player.SPm) > 2000) if (((DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond) - player.SPm) > 2000)
{ {
player.SendMessage("Spawn is protected from changes.", Color.Red); player.SendErrorMessage("Spawn is protected from changes.");
player.SPm = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond; player.SPm = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond;
} }
return true; return true;
@ -1621,7 +1639,7 @@ namespace TShockAPI
{ {
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.SendErrorMessage("You do not have permission to build!");
player.BPm = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond; player.BPm = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond;
} }
return true; return true;
@ -1632,7 +1650,7 @@ namespace TShockAPI
{ {
if (((DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond) - player.RPm) > 2000) if (((DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond) - player.RPm) > 2000)
{ {
player.SendMessage("This region is protected from changes.", Color.Red); player.SendErrorMessage("This region is protected from changes.");
player.RPm = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond; player.RPm = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond;
} }
return true; return true;
@ -1644,7 +1662,7 @@ namespace TShockAPI
{ {
if (((DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond) - player.WPm) > 2000) if (((DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond) - player.WPm) > 2000)
{ {
player.SendMessage("The world is protected from changes.", Color.Red); player.SendErrorMessage("The world is protected from changes.");
player.WPm = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond; player.WPm = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond;
} }
return true; return true;
@ -1659,7 +1677,7 @@ namespace TShockAPI
{ {
if (((DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond) - player.SPm) > 1000) if (((DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond) - player.SPm) > 1000)
{ {
player.SendMessage("Spawn is protected from changes.", Color.Red); player.SendErrorMessage("Spawn is protected from changes.");
player.SPm = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond; player.SPm = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond;
} }
return true; return true;
@ -1778,9 +1796,6 @@ namespace TShockAPI
Netplay.password = ""; Netplay.password = "";
Netplay.spamCheck = false; Netplay.spamCheck = false;
RconHandler.Password = file.RconPassword;
RconHandler.ListenPort = file.RconPort;
Utils.HashAlgo = file.HashAlgorithm; Utils.HashAlgo = file.HashAlgorithm;
} }
} }

View file

@ -39,6 +39,7 @@
<AllowUnsafeBlocks>true</AllowUnsafeBlocks> <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<DocumentationFile>bin\Debug\TShockAPI.XML</DocumentationFile> <DocumentationFile>bin\Debug\TShockAPI.XML</DocumentationFile>
<PlatformTarget>x86</PlatformTarget> <PlatformTarget>x86</PlatformTarget>
<NoWarn>1591</NoWarn>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType> <DebugType>pdbonly</DebugType>
@ -78,6 +79,11 @@
<Compile Include="Hooks\AccountHooks.cs" /> <Compile Include="Hooks\AccountHooks.cs" />
<Compile Include="Hooks\GeneralHooks.cs" /> <Compile Include="Hooks\GeneralHooks.cs" />
<Compile Include="Hooks\PlayerHooks.cs" /> <Compile Include="Hooks\PlayerHooks.cs" />
<Compile Include="Hooks\RegionHooks.cs" />
<Compile Include="ILog.cs" />
<Compile Include="Log.cs" />
<Compile Include="SqlLog.cs" />
<Compile Include="TextLog.cs" />
<Compile Include="PaginationTools.cs" /> <Compile Include="PaginationTools.cs" />
<Compile Include="Rest\RestPermissions.cs" /> <Compile Include="Rest\RestPermissions.cs" />
<Compile Include="SaveManager.cs" /> <Compile Include="SaveManager.cs" />
@ -102,7 +108,6 @@
<Compile Include="GetDataHandlers.cs" /> <Compile Include="GetDataHandlers.cs" />
<Compile Include="Group.cs" /> <Compile Include="Group.cs" />
<Compile Include="Extensions\LinqExt.cs" /> <Compile Include="Extensions\LinqExt.cs" />
<Compile Include="Log.cs" />
<Compile Include="Net\BaseMsg.cs" /> <Compile Include="Net\BaseMsg.cs" />
<Compile Include="Net\DisconnectMsg.cs" /> <Compile Include="Net\DisconnectMsg.cs" />
<Compile Include="Net\NetTile.cs" /> <Compile Include="Net\NetTile.cs" />
@ -111,7 +116,6 @@
<Compile Include="Net\WorldInfoMsg.cs" /> <Compile Include="Net\WorldInfoMsg.cs" />
<Compile Include="PacketBufferer.cs" /> <Compile Include="PacketBufferer.cs" />
<Compile Include="Permissions.cs" /> <Compile Include="Permissions.cs" />
<Compile Include="RconHandler.cs" />
<Compile Include="DB\RememberedPosManager.cs" /> <Compile Include="DB\RememberedPosManager.cs" />
<Compile Include="Resources.Designer.cs"> <Compile Include="Resources.Designer.cs">
<AutoGen>True</AutoGen> <AutoGen>True</AutoGen>
@ -182,7 +186,7 @@
</PropertyGroup> </PropertyGroup>
<ProjectExtensions> <ProjectExtensions>
<VisualStudio> <VisualStudio>
<UserProperties BuildVersion_UpdateAssemblyVersion="True" BuildVersion_UpdateFileVersion="True" BuildVersion_BuildAction="Both" BuildVersion_BuildVersioningStyle="None.None.None.MonthAndDayStamp" BuildVersion_StartDate="2011/6/17" BuildVersion_IncrementBeforeBuild="False" /> <UserProperties BuildVersion_IncrementBeforeBuild="False" BuildVersion_StartDate="2011/6/17" BuildVersion_BuildVersioningStyle="None.None.None.MonthAndDayStamp" BuildVersion_BuildAction="Both" BuildVersion_UpdateFileVersion="True" BuildVersion_UpdateAssemblyVersion="True" />
</VisualStudio> </VisualStudio>
</ProjectExtensions> </ProjectExtensions>
<!-- To modify your build process, add your task inside one of the targets below and uncomment it. <!-- To modify your build process, add your task inside one of the targets below and uncomment it.

250
TShockAPI/TextLog.cs Normal file
View file

@ -0,0 +1,250 @@
/*
TShock, a server mod for Terraria
Copyright (C) 2011-2015 Nyx Studios (fka. The TShock Team)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
using System;
using System.Diagnostics;
using System.Globalization;
using System.IO;
namespace TShockAPI
{
/// <summary>
/// Class inheriting ILog for writing logs to a text file
/// </summary>
public class TextLog : ILog, IDisposable
{
private readonly StreamWriter _logWriter;
private readonly LogLevel _logLevel;
/// <summary>
/// Log file name
/// </summary>
public static string fileName { get; private set; }
/// <summary>
/// Name of the TextLog
/// </summary>
public string Name
{
get { return "Text Log Writer"; }
}
public bool Sql
{
get { return false; }
}
/// <summary>
/// Creates the log file stream and sets the initial log level.
/// </summary>
/// <param name="filename">The output filename. This file will be overwritten if 'clear' is set.</param>
/// <param name="logLevel">The <see cref="LogLevel" /> value which sets the type of messages to output.</param>
/// <param name="clear">Whether or not to clear the log file on initialization.</param>
public TextLog(string filename, LogLevel logLevel, bool clear)
{
fileName = filename;
_logLevel = logLevel;
_logWriter = new StreamWriter(filename, !clear);
}
public bool MayWriteType(LogLevel type)
{
return ((_logLevel & type) == type);
}
/// <summary>
/// Writes data to the log file.
/// </summary>
/// <param name="message">The message to be written.</param>
public void Data(String message)
{
Write(message, LogLevel.Data);
}
/// <summary>
/// Writes data to the log file.
/// </summary>
/// <param name="format">The format of the message to be written.</param>
/// <param name="args">The format arguments.</param>
public void Data(string format, params object[] args)
{
Data(String.Format(format, args));
}
/// <summary>
/// Writes an error to the log file.
/// </summary>
/// <param name="message">The message to be written.</param>
public void Error(String message)
{
Write(message, LogLevel.Error);
}
/// <summary>
/// Writes an error to the log file.
/// </summary>
/// <param name="format">The format of the message to be written.</param>
/// <param name="args">The format arguments.</param>
public void Error(string format, params object[] args)
{
Error(String.Format(format, args));
}
/// <summary>
/// Writes an error to the log file.
/// </summary>
/// <param name="message">The message to be written.</param>
public void ConsoleError(String message)
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine(message);
Console.ForegroundColor = ConsoleColor.Gray;
Write(message, LogLevel.Error);
}
/// <summary>
/// Writes an error to the log file.
/// </summary>
/// <param name="format">The format of the message to be written.</param>
/// <param name="args">The format arguments.</param>
public void ConsoleError(string format, params object[] args)
{
ConsoleError(String.Format(format, args));
}
/// <summary>
/// Writes a warning to the log file.
/// </summary>
/// <param name="message">The message to be written.</param>
public void Warn(String message)
{
Write(message, LogLevel.Warning);
}
/// <summary>
/// Writes a warning to the log file.
/// </summary>
/// <param name="format">The format of the message to be written.</param>
/// <param name="args">The format arguments.</param>
public void Warn(string format, params object[] args)
{
Warn(String.Format(format, args));
}
/// <summary>
/// Writes an informative string to the log file.
/// </summary>
/// <param name="message">The message to be written.</param>
public void Info(String message)
{
Write(message, LogLevel.Info);
}
/// <summary>
/// Writes an informative string to the log file.
/// </summary>
/// <param name="format">The format of the message to be written.</param>
/// <param name="args">The format arguments.</param>
public void Info(string format, params object[] args)
{
Info(String.Format(format, args));
}
/// <summary>
/// Writes an informative string to the log file. Also outputs to the console.
/// </summary>
/// <param name="message">The message to be written.</param>
public void ConsoleInfo(String message)
{
Console.ForegroundColor = ConsoleColor.Yellow;
Console.WriteLine(message);
Console.ForegroundColor = ConsoleColor.Gray;
Write(message, LogLevel.Info);
}
/// <summary>
/// Writes an informative string to the log file. Also outputs to the console.
/// </summary>
/// <param name="format">The format of the message to be written.</param>
/// <param name="args">The format arguments.</param>
public void ConsoleInfo(string format, params object[] args)
{
ConsoleInfo(String.Format(format, args));
}
/// <summary>
/// Writes a debug string to the log file.
/// </summary>
/// <param name="message">The message to be written.</param>
public void Debug(String message)
{
Write(message, LogLevel.Debug);
}
/// <summary>
/// Writes a debug string to the log file.
/// </summary>
/// <param name="format">The format of the message to be written.</param>
/// <param name="args">The format arguments.</param>
public void Debug(string format, params object[] args)
{
Debug(String.Format(format, args));
}
/// <summary>
/// Writes a message to the log
/// </summary>
/// <param name="message"></param>
/// <param name="level"></param>
public void Write(string message, LogLevel level)
{
if (!MayWriteType(level))
return;
var caller = "TShock";
var frame = new StackTrace().GetFrame(2);
if (frame != null)
{
var meth = frame.GetMethod();
if (meth != null && meth.DeclaringType != null)
caller = meth.DeclaringType.Name;
}
try
{
_logWriter.WriteLine("{0} - {1}: {2}: {3}",
DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture),
caller, level.ToString().ToUpper(), message);
_logWriter.Flush();
}
catch (ObjectDisposedException)
{
Console.WriteLine("Unable to write to log as log has been disposed.");
Console.WriteLine("{0} - {1}: {2}: {3}",
DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture),
caller, level.ToString().ToUpper(), message);
}
}
public void Dispose()
{
_logWriter.Dispose();
}
}
}

View file

@ -94,7 +94,7 @@ namespace TShockAPI
} }
catch (Exception e) catch (Exception e)
{ {
Log.ConsoleError("UpdateManager Exception: {0}", e); TShock.Log.ConsoleError("UpdateManager Exception: {0}", e);
throw e; throw e;
} }

View file

@ -35,17 +35,17 @@ namespace TShockAPI
/// </summary> /// </summary>
public class Utils public class Utils
{ {
/// <summary> /// <summary>
/// The lowest id for a prefix. /// The lowest id for a prefix.
/// </summary> /// </summary>
private const int FirstItemPrefix = 1; private const int FirstItemPrefix = 1;
/// <summary> /// <summary>
/// The highest id for a prefix. /// The highest id for a prefix.
/// </summary> /// </summary>
private const int LastItemPrefix = 83; private const int LastItemPrefix = 83;
// Utils is a Singleton // Utils is a Singleton
private static readonly Utils instance = new Utils(); private static readonly Utils instance = new Utils();
private Utils() {} private Utils() {}
public static Utils Instance { get { return instance; } } public static Utils Instance { get { return instance; } }
@ -67,7 +67,7 @@ namespace TShockAPI
/// Used for some places where a list of players might be used. /// Used for some places where a list of players might be used.
/// </summary> /// </summary>
/// <returns>String of players seperated by commas.</returns> /// <returns>String of players seperated by commas.</returns>
[Obsolete("Use GetPlayers and manually create strings. This should never have been kept as far as actual functions go.")] [Obsolete("Use GetPlayers and manually create strings. This should never have been kept as far as actual functions go.")]
public string GetPlayers() public string GetPlayers()
{ {
var sb = new StringBuilder(); var sb = new StringBuilder();
@ -85,56 +85,56 @@ namespace TShockAPI
return sb.ToString(); return sb.ToString();
} }
/// <summary> /// <summary>
/// Returns a list of current players on the server /// Returns a list of current players on the server
/// </summary> /// </summary>
/// <param name="includeIDs">bool includeIDs - whether or not the string of each player name should include ID data</param> /// <param name="includeIDs">bool includeIDs - whether or not the string of each player name should include ID data</param>
/// <returns>List of strings with names</returns> /// <returns>List of strings with names</returns>
public List<string> GetPlayers(bool includeIDs) public List<string> GetPlayers(bool includeIDs)
{ {
var players = new List<string>(); var players = new List<string>();
foreach (TSPlayer ply in TShock.Players) foreach (TSPlayer ply in TShock.Players)
{ {
if (ply != null && ply.Active) if (ply != null && ply.Active)
{ {
if (includeIDs) if (includeIDs)
{ {
players.Add(ply.Name + " (IX: " + ply.Index + ", ID: " + ply.UserID + ")"); players.Add(ply.Name + " (IX: " + ply.Index + ", ID: " + ply.UserID + ")");
} }
else else
{ {
players.Add(ply.Name); players.Add(ply.Name);
} }
} }
} }
return players; return players;
} }
/// <summary> /// <summary>
/// Used for some places where a list of players might be used. /// Used for some places where a list of players might be used.
/// </summary> /// </summary>
/// <returns>String of players and their id seperated by commas.</returns> /// <returns>String of players and their id seperated by commas.</returns>
[Obsolete("Use GetPlayers and manually create strings. This should never have been kept as far as actual functions go.")] [Obsolete("Use GetPlayers and manually create strings. This should never have been kept as far as actual functions go.")]
public string GetPlayersWithIds() public string GetPlayersWithIds()
{ {
var sb = new StringBuilder(); var sb = new StringBuilder();
foreach (TSPlayer player in TShock.Players) foreach (TSPlayer player in TShock.Players)
{ {
if (player != null && player.Active) if (player != null && player.Active)
{ {
if (sb.Length != 0) if (sb.Length != 0)
{ {
sb.Append(", "); sb.Append(", ");
} }
sb.Append(player.Name); sb.Append(player.Name);
string id = "(ID: " + Convert.ToString(TShock.Users.GetUserID(player.UserAccountName)) + ", IX:" + player.Index + ")"; string id = "(ID: " + Convert.ToString(TShock.Users.GetUserID(player.UserAccountName)) + ", IX:" + player.Index + ")";
sb.Append(id); sb.Append(id);
} }
} }
return sb.ToString(); return sb.ToString();
} }
/// <summary> /// <summary>
/// Finds a player and gets IP as string /// Finds a player and gets IP as string
@ -182,21 +182,11 @@ namespace TShockAPI
SaveManager.Instance.SaveWorld(); SaveManager.Instance.SaveWorld();
} }
/// <summary>
/// Broadcasts a message to all players
/// </summary>
/// <param name="msg">string message</param>
[Obsolete("Use TSPlayer.All and send a message via that method rather than using Broadcast.")]
public void Broadcast(string msg)
{
Broadcast(msg, Color.Green);
}
public void Broadcast(string msg, byte red, byte green, byte blue) public void Broadcast(string msg, byte red, byte green, byte blue)
{ {
TSPlayer.All.SendMessage(msg, red, green, blue); TSPlayer.All.SendMessage(msg, red, green, blue);
TSPlayer.Server.SendMessage(msg, red, green, blue); TSPlayer.Server.SendMessage(msg, red, green, blue);
Log.Info(string.Format("Broadcast: {0}", msg)); TShock.Log.Info(string.Format("Broadcast: {0}", msg));
} }
public void Broadcast(string msg, Color color) public void Broadcast(string msg, Color color)
@ -204,20 +194,20 @@ namespace TShockAPI
Broadcast(msg, color.R, color.G, color.B); Broadcast(msg, color.R, color.G, color.B);
} }
/// <summary> /// <summary>
/// Broadcasts a message from a player, not TShock /// Broadcasts a message from a player, not TShock
/// </summary> /// </summary>
/// <param name="ply">TSPlayer ply - the player that will send the packet</param> /// <param name="ply">TSPlayer ply - the player that will send the packet</param>
/// <param name="msg">string msg - the message</param> /// <param name="msg">string msg - the message</param>
/// <param name="red">r</param> /// <param name="red">r</param>
/// <param name="green">g</param> /// <param name="green">g</param>
/// <param name="blue">b</param> /// <param name="blue">b</param>
public void Broadcast(int ply, string msg, byte red, byte green, byte blue) public void Broadcast(int ply, string msg, byte red, byte green, byte blue)
{ {
TSPlayer.All.SendMessageFromPlayer(msg, red, green, blue, ply); TSPlayer.All.SendMessageFromPlayer(msg, red, green, blue, ply);
TSPlayer.Server.SendMessage(Main.player[ply].name + ": " + msg, red, green, blue); TSPlayer.Server.SendMessage(Main.player[ply].name + ": " + msg, red, green, blue);
Log.Info(string.Format("Broadcast: {0}", Main.player[ply].name + ": " + msg)); TShock.Log.Info(string.Format("Broadcast: {0}", Main.player[ply].name + ": " + msg));
} }
/// <summary> /// <summary>
/// Sends message to all players with 'logs' permission. /// Sends message to all players with 'logs' permission.
@ -227,12 +217,12 @@ namespace TShockAPI
/// <param name="excludedPlayer">The player to not send the message to.</param> /// <param name="excludedPlayer">The player to not send the message to.</param>
public void SendLogs(string log, Color color, TSPlayer excludedPlayer = null) public void SendLogs(string log, Color color, TSPlayer excludedPlayer = null)
{ {
Log.Info(log); TShock.Log.Info(log);
TSPlayer.Server.SendMessage(log, color); TSPlayer.Server.SendMessage(log, color);
foreach (TSPlayer player in TShock.Players) foreach (TSPlayer player in TShock.Players)
{ {
if (player != null && player != excludedPlayer && player.Active && player.Group.HasPermission(Permissions.logs) && if (player != null && player != excludedPlayer && player.Active && player.Group.HasPermission(Permissions.logs) &&
player.DisplayLogs && TShock.Config.DisableSpewLogs == false) player.DisplayLogs && TShock.Config.DisableSpewLogs == false)
player.SendMessage(log, color); player.SendMessage(log, color);
} }
} }
@ -293,7 +283,7 @@ namespace TShockAPI
/// <param name="tileX">X location</param> /// <param name="tileX">X location</param>
/// <param name="tileY">Y location</param> /// <param name="tileY">Y location</param>
public void GetRandomClearTileWithInRange(int startTileX, int startTileY, int tileXRange, int tileYRange, public void GetRandomClearTileWithInRange(int startTileX, int startTileY, int tileXRange, int tileYRange,
out int tileX, out int tileY) out int tileX, out int tileY)
{ {
int j = 0; int j = 0;
do do
@ -510,7 +500,7 @@ namespace TShockAPI
return found; return found;
} }
/// <summary> /// <summary>
/// Gets a prefix by ID or name /// Gets a prefix by ID or name
/// </summary> /// </summary>
/// <param name="idOrName">ID or name</param> /// <param name="idOrName">ID or name</param>
@ -593,13 +583,6 @@ namespace TShockAPI
Hooks.GeneralHooks.OnReloadEvent(player); 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)
{
Kick(player, reason, true, false, string.Empty);
}
#endif
/// <summary> /// <summary>
/// Kicks a player from the server without checking for immunetokick permission. /// Kicks a player from the server without checking for immunetokick permission.
/// </summary> /// </summary>
@ -611,13 +594,6 @@ namespace TShockAPI
Kick(player, reason, true, silent, null, saveSSI); Kick(player, reason, true, silent, null, saveSSI);
} }
#if COMPAT_SIGS
[Obsolete("This method is for signature compatibility for external code only")]
public bool Kick(TSPlayer player, string reason, string adminUserName)
{
return Kick(player, reason, false, false, adminUserName);
}
#endif
/// <summary> /// <summary>
/// Kicks a player from the server.. /// Kicks a player from the server..
/// </summary> /// </summary>
@ -635,30 +611,23 @@ namespace TShockAPI
{ {
string playerName = player.Name; string playerName = player.Name;
player.SilentKickInProgress = silent; player.SilentKickInProgress = silent;
if (player.IsLoggedIn && saveSSI) if (player.IsLoggedIn && saveSSI)
player.SaveServerCharacter(); player.SaveServerCharacter();
player.Disconnect(string.Format("Kicked: {0}", reason)); player.Disconnect(string.Format("Kicked: {0}", reason));
Log.ConsoleInfo(string.Format("Kicked {0} for : '{1}'", playerName, reason)); TShock.Log.ConsoleInfo(string.Format("Kicked {0} for : '{1}'", playerName, reason));
string verb = force ? "force " : ""; string verb = force ? "force " : "";
if (!silent) if (!silent)
{ {
if (string.IsNullOrWhiteSpace(adminUserName)) if (string.IsNullOrWhiteSpace(adminUserName))
Broadcast(string.Format("{0} was {1}kicked for '{2}'", playerName, verb, reason.ToLower()), Color.Green); Broadcast(string.Format("{0} was {1}kicked for '{2}'", playerName, verb, reason.ToLower()), Color.Green);
else else
Broadcast(string.Format("{0} {1}kicked {2} for '{3}'", adminUserName, verb, playerName, reason.ToLower()), Color.Green); Broadcast(string.Format("{0} {1}kicked {2} for '{3}'", adminUserName, verb, playerName, reason.ToLower()), Color.Green);
} }
return true; return true;
} }
return false; return false;
} }
#if COMPAT_SIGS
[Obsolete("This method is for signature compatibility for external code only")]
public bool Ban(TSPlayer player, string reason, string adminUserName)
{
return Ban(player, reason, false, adminUserName);
}
#endif
/// <summary> /// <summary>
/// Bans and kicks a player from the server. /// Bans and kicks a player from the server.
/// </summary> /// </summary>
@ -687,28 +656,28 @@ namespace TShockAPI
return false; return false;
} }
public bool HasBanExpired(Ban ban, bool byName = false) public bool HasBanExpired(Ban ban, bool byName = false)
{ {
DateTime exp; DateTime exp;
bool expirationExists = DateTime.TryParse(ban.Expiration, out exp); bool expirationExists = DateTime.TryParse(ban.Expiration, out exp);
if (!string.IsNullOrWhiteSpace(ban.Expiration) && (expirationExists) && if (!string.IsNullOrWhiteSpace(ban.Expiration) && (expirationExists) &&
(DateTime.UtcNow >= exp)) (DateTime.UtcNow >= exp))
{ {
if (byName) if (byName)
{ {
TShock.Bans.RemoveBan(ban.Name, true, true, false); TShock.Bans.RemoveBan(ban.Name, true, true, false);
} }
else else
{ {
TShock.Bans.RemoveBan(ban.IP, false, false, false); TShock.Bans.RemoveBan(ban.IP, false, false, false);
} }
return true; return true;
} }
return false; return false;
} }
/// <summary> /// <summary>
/// Shows a file to the user. /// Shows a file to the user.
@ -762,7 +731,7 @@ namespace TShockAPI
return TShock.Groups.groups[i]; return TShock.Groups.groups[i];
} }
} }
return Group.DefaultGroup; return Group.DefaultGroup;
} }
/// <summary> /// <summary>
@ -796,23 +765,23 @@ namespace TShockAPI
ply.SendErrorMessage("Use \"my query\" for items with spaces"); ply.SendErrorMessage("Use \"my query\" for items with spaces");
} }
/// <summary> /// <summary>
/// Default hashing algorithm. /// Default hashing algorithm.
/// </summary> /// </summary>
public string HashAlgo = "sha512"; public string HashAlgo = "sha512";
/// <summary> /// <summary>
/// A dictionary of hashing algortihms and an implementation object. /// A dictionary of hashing algortihms and an implementation object.
/// </summary> /// </summary>
public readonly Dictionary<string, Func<HashAlgorithm>> HashTypes = new Dictionary<string, Func<HashAlgorithm>> public readonly Dictionary<string, Func<HashAlgorithm>> HashTypes = new Dictionary<string, Func<HashAlgorithm>>
{ {
{"sha512", () => new SHA512Managed()}, {"sha512", () => new SHA512Managed()},
{"sha256", () => new SHA256Managed()}, {"sha256", () => new SHA256Managed()},
{"md5", () => new MD5Cng()}, {"md5", () => new MD5Cng()},
{"sha512-xp", () => SHA512.Create()}, {"sha512-xp", () => SHA512.Create()},
{"sha256-xp", () => SHA256.Create()}, {"sha256-xp", () => SHA256.Create()},
{"md5-xp", () => MD5.Create()}, {"md5-xp", () => MD5.Create()},
}; };
/// <summary> /// <summary>
/// Returns a Sha256 string for a given string /// Returns a Sha256 string for a given string

@ -1 +1 @@
Subproject commit 50a04c45bfc2d1de2de1a31b215f7bdc546cfdd5 Subproject commit f4075507475be946870a83d65a14cb5ae2c348cf

View file

@ -2,31 +2,48 @@ import requests
import json import json
import sys import sys
import os import os
import subprocess
create_release_url = 'https://api.github.com/repos/NyxStudios/TShock/releases' create_release_url = 'https://api.github.com/repos/NyxStudios/TShock/releases'
release_name = 'tshock_release.zip'
#Load variables from ENV, which are put there by the bamboo build.
branch = os.environ["GIT_BRANCH"] branch = os.environ["GIT_BRANCH"]
tag_name = os.environ["bamboo_tag_name"] tag_name = os.environ["bamboo_tag_name"]
name = os.environ["bamboo_release_name"] name = os.environ["bamboo_release_name"]
body = os.environ["bamboo_release_body"]
#build release file name using the tag, stripping the 'v' off the front ie 'v.1.2.3' => '.1.2.3' resulting in a file called 'tshock.1.2.3.zip'
release_name = 'tshock_' + tag_name[1:] + '.zip'
#because we can't find any other secure way to get a token into this script run from bamboo :'( #because we can't find any other secure way to get a token into this script run from bamboo :'(
with open('/home/bamboo/scripts/token.py') as f: with open('/home/bamboo/scripts/token.py') as f:
token = f.read().rsplit('=', 1)[1].strip() token = f.read().rsplit('=', 1)[1].strip()
body = 'This is the newest release for TShock. Please see the release thread for more information @ http://tshock.co/xf' #invoke the mv command on the artifact from bamboo to the new name above
subprocess.call('mv tshock_release.zip ' + release_name, shell=True)
#construct the payload for the post request to github to create the release.
data = {'tag_name':tag_name, 'target_commitish':branch, 'name':name, 'body':body, 'draft':False, 'prerelease':False} data = {'tag_name':tag_name, 'target_commitish':branch, 'name':name, 'body':body, 'draft':False, 'prerelease':False}
#headers for the post request with our oauth token, allowing us write access
create_headers = {'Content-Type': 'application/json', 'Authorization': 'token ' + token} create_headers = {'Content-Type': 'application/json', 'Authorization': 'token ' + token}
#payload is a json string, not a strong typed json object
json_data = json.dumps(data) json_data = json.dumps(data)
#make the post request, creating a release
r = requests.post(create_release_url, data=json_data, headers=create_headers) r = requests.post(create_release_url, data=json_data, headers=create_headers)
#parse the response into an object
json_response = json.loads(r.text) json_response = json.loads(r.text)
#extract the relevant information from the object needed to attach a binary to the release created previously
release_id = json_response['id'] release_id = json_response['id']
upload_url = json_response['upload_url'].rsplit('{')[0] upload_url = json_response['upload_url'].rsplit('{')[0]
#construct the post url using the release name, as that is required by the api
upload_url = upload_url + '?name=' + release_name upload_url = upload_url + '?name=' + release_name
#headers for the post request, need to specify that our file is a zip, and how large it is
upload_headers = {'Authorization': 'token ' + token, 'Content-Type':'application/zip', 'Content-Length':str(os.path.getsize(release_name))} upload_headers = {'Authorization': 'token ' + token, 'Content-Type':'application/zip', 'Content-Length':str(os.path.getsize(release_name))}
#upload the binary, resulting in a complete binary
r = requests.post(upload_url, data=open(release_name, 'rb'), headers = upload_headers, verify=False) r = requests.post(upload_url, data=open(release_name, 'rb'), headers = upload_headers, verify=False)