diff --git a/.idea/.idea.TShock/.idea/indexLayout.xml b/.idea/.idea.TShock/.idea/indexLayout.xml
new file mode 100644
index 000000000..7b08163ce
--- /dev/null
+++ b/.idea/.idea.TShock/.idea/indexLayout.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/.idea.TShock/.idea/projectSettingsUpdater.xml b/.idea/.idea.TShock/.idea/projectSettingsUpdater.xml
new file mode 100644
index 000000000..4bb9f4d2a
--- /dev/null
+++ b/.idea/.idea.TShock/.idea/projectSettingsUpdater.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/.idea.TShock/.idea/vcs.xml b/.idea/.idea.TShock/.idea/vcs.xml
new file mode 100644
index 000000000..35eb1ddfb
--- /dev/null
+++ b/.idea/.idea.TShock/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/.idea.TShock/.idea/workspace.xml b/.idea/.idea.TShock/.idea/workspace.xml
new file mode 100644
index 000000000..213339039
--- /dev/null
+++ b/.idea/.idea.TShock/.idea/workspace.xml
@@ -0,0 +1,142 @@
+
+
+
+ TShockInstaller/TShockInstaller.csproj
+ TShockLauncher/TShockLauncher.csproj
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1706669685380
+
+
+ 1706669685380
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/TShockAPI/Commands.cs b/TShockAPI/Commands.cs
index d39b84e0c..449b360ea 100644
--- a/TShockAPI/Commands.cs
+++ b/TShockAPI/Commands.cs
@@ -28,7 +28,7 @@ You should have received a copy of the GNU General Public License
using Terraria;
using Terraria.ID;
using Terraria.Localization;
-using TShockAPI.DB;
+using TShockAPI.Database;
using TerrariaApi.Server;
using TShockAPI.Hooks;
using Terraria.GameContent.Events;
@@ -1038,7 +1038,7 @@ private static void RegisterUser(CommandArgs args)
return;
}
- account.Group = TShock.Config.Settings.DefaultRegistrationGroupName; // FIXME -- we should get this from the DB. --Why?
+ account.Group = TShock.Config.Settings.DefaultRegistrationGroupName; // FIXME -- we should get this from the Database. --Why?
account.UUID = args.Player.UUID;
if (TShock.UserAccounts.GetUserAccountByName(account.Name) == null && account.Name != TSServerPlayer.AccountName) // Cheap way of checking for existance of a user
@@ -1458,7 +1458,7 @@ void MoreHelp(string cmd)
void DisplayBanDetails(Ban ban)
{
- args.Player.SendMessage(GetString($"{"Ban Details".Color(Utils.BoldHighlight)} - Ticket Number: {ban.TicketNumber.Color(Utils.GreenHighlight)}"), Color.White);
+ args.Player.SendMessage(GetString($"{"Ban Details".Color(Utils.BoldHighlight)} - Ticket Number: {ban.BanId.Color(Utils.GreenHighlight)}"), Color.White);
args.Player.SendMessage(GetString($"{"Identifier:".Color(Utils.BoldHighlight)} {ban.Identifier}"), Color.White);
args.Player.SendMessage(GetString($"{"Reason:".Color(Utils.BoldHighlight)} {ban.Reason}"), Color.White);
args.Player.SendMessage(GetString($"{"Banned by:".Color(Utils.BoldHighlight)} {ban.BanningUser.Color(Utils.GreenHighlight)} on {ban.BanDateTime.ToString("yyyy/MM/dd").Color(Utils.RedHighlight)} ({ban.GetPrettyTimeSinceBanString().Color(Utils.YellowHighlight)} ago)"), Color.White);
@@ -1487,7 +1487,7 @@ AddBanResult DoBan(string ident, string reason, DateTime expiration)
AddBanResult banResult = TShock.Bans.InsertBan(ident, reason, args.Player.Account.Name, DateTime.UtcNow, expiration);
if (banResult.Ban != null)
{
- args.Player.SendSuccessMessage(GetString($"Ban added. Ticket Number {banResult.Ban.TicketNumber.Color(Utils.GreenHighlight)} was created for identifier {ident.Color(Utils.WhiteHighlight)}."));
+ args.Player.SendSuccessMessage(GetString($"Ban added. Ticket Number {banResult.Ban.BanId.Color(Utils.GreenHighlight)} was created for identifier {ident.Color(Utils.WhiteHighlight)}."));
}
else
{
@@ -1610,7 +1610,7 @@ void AddBan()
if (banResult?.Ban != null)
{
- player.Disconnect(GetString($"#{banResult.Ban.TicketNumber} - You have been banned: {banResult.Ban.Reason}."));
+ player.Disconnect(GetString($"#{banResult.Ban.BanId} - You have been banned: {banResult.Ban.Reason}."));
}
}
diff --git a/TShockAPI/Configuration/TShockConfig.cs b/TShockAPI/Configuration/TShockConfig.cs
index 79c374b25..b40354b26 100644
--- a/TShockAPI/Configuration/TShockConfig.cs
+++ b/TShockAPI/Configuration/TShockConfig.cs
@@ -466,6 +466,17 @@ public class TShockSettings
public bool DisableCustomDeathMessages = true;
#endregion
+ #region MongoDB Settings
+
+ [Description("The connection string for MongoDB")]
+ public string MongoConnectionString = "required";
+
+ [Description("The global database, or default. This database will be used to synchronize data between servers.")]
+ public string DefaultGlobalDatabase = "tsd";
+
+ [Description("The local database, essentially replacing a server's SQlite databases.")]
+ public string LocalDatabase = "server1";
+ #endregion
#region Chat Settings
@@ -493,7 +504,7 @@ public class TShockSettings
/// The superadmin chat prefix.
[Description("The superadmin chat prefix.")]
- public string SuperAdminChatPrefix = GetString("(Super Admin) ");
+ public string SuperAdminChatPrefix = GetString("[Admin] ");
/// The superadmin chat suffix.
[Description("The superadmin chat suffix.")]
@@ -526,43 +537,6 @@ public class TShockSettings
#endregion
- #region MySQL Settings
-
- /// The type of database to use when storing data (either "sqlite" or "mysql").
- [Description("The type of database to use when storing data (either \"sqlite\" or \"mysql\").")]
- public string StorageType = "sqlite";
-
- /// The path of sqlite db.
- [Description("The path of sqlite db.")]
- public string SqliteDBPath = "tshock.sqlite";
-
- /// The MySQL hostname and port to direct connections to.
- [Description("The MySQL hostname and port to direct connections to.")]
- public string MySqlHost = "localhost:3306";
-
- /// The database name to connect to when using MySQL as the database type.
- [Description("The database name to connect to when using MySQL as the database type.")]
- public string MySqlDbName = "";
-
- /// The username used when connecting to a MySQL database.
- [Description("The username used when connecting to a MySQL database.")]
- public string MySqlUsername = "";
-
- /// The password used when connecting to a MySQL database.
- [Description("The password used when connecting to a MySQL database.")]
- public string MySqlPassword = "";
-
- /// Whether or not to save logs to the SQL database instead of a text file.
- [Description("Whether or not to save logs to the SQL database instead of a text file.\nDefault = false.")]
- public bool UseSqlLogs = false;
-
- /// Number of times the SQL log must fail to insert logs before falling back to the text log.
- [Description("Number of times the SQL log must fail to insert logs before falling back to the text log.")]
- public int RevertToTextLogsOnSqlFailures = 10;
-
- #endregion
-
-
#region REST API Settings
/// Enable or disable the REST API.
diff --git a/TShockAPI/DB/BanManager.cs b/TShockAPI/DB/BanManager.cs
deleted file mode 100644
index 428921006..000000000
--- a/TShockAPI/DB/BanManager.cs
+++ /dev/null
@@ -1,776 +0,0 @@
-/*
-TShock, a server mod for Terraria
-Copyright (C) 2011-2019 Pryaxis & TShock Contributors
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program. If not, see .
-*/
-
-using System;
-using System.Linq;
-using System.Collections.Generic;
-using System.Data;
-using MySql.Data.MySqlClient;
-using System.Collections.ObjectModel;
-
-namespace TShockAPI.DB
-{
- ///
- /// Class that manages bans.
- ///
- public class BanManager
- {
- private IDbConnection database;
-
- private Dictionary _bans;
-
- ///
- /// Readonly dictionary of Bans, keyed on ban ticket number.
- ///
- public ReadOnlyDictionary Bans => new ReadOnlyDictionary(_bans);
-
- ///
- /// Event invoked when a ban is checked for validity
- ///
- public static event EventHandler OnBanValidate;
- ///
- /// Event invoked before a ban is added
- ///
- public static event EventHandler OnBanPreAdd;
- ///
- /// Event invoked after a ban is added
- ///
- public static event EventHandler OnBanPostAdd;
-
- ///
- /// Initializes a new instance of the class.
- ///
- /// A valid connection to the TShock database
- public BanManager(IDbConnection db)
- {
- database = db;
-
- var table = new SqlTable("PlayerBans",
- new SqlColumn("TicketNumber", MySqlDbType.Int32) { Primary = true, AutoIncrement = true },
- new SqlColumn("Identifier", MySqlDbType.Text),
- new SqlColumn("Reason", MySqlDbType.Text),
- new SqlColumn("BanningUser", MySqlDbType.Text),
- new SqlColumn("Date", MySqlDbType.Int64),
- new SqlColumn("Expiration", MySqlDbType.Int64)
- );
- var creator = new SqlTableCreator(db,
- db.GetSqlType() == SqlType.Sqlite
- ? (IQueryBuilder)new SqliteQueryCreator()
- : new MysqlQueryCreator());
- try
- {
- creator.EnsureTableStructure(table);
- }
- catch (DllNotFoundException)
- {
- System.Console.WriteLine(GetString("Possible problem with your database - is Sqlite3.dll present?"));
- throw new Exception(GetString("Could not find a database library (probably Sqlite3.dll)"));
- }
-
- EnsureBansCollection();
- TryConvertBans();
-
- OnBanValidate += BanValidateCheck;
- OnBanPreAdd += BanAddedCheck;
- }
-
- ///
- /// Ensures the collection is ready to use.
- ///
- private void EnsureBansCollection()
- {
- if (_bans == null)
- {
- _bans = RetrieveAllBans().ToDictionary(b => b.TicketNumber);
- }
- }
-
- ///
- /// Converts bans from the old ban system to the new.
- ///
- public void TryConvertBans()
- {
- int res;
- if (database.GetSqlType() == SqlType.Mysql)
- {
- res = database.QueryScalar("SELECT COUNT(table_name) FROM information_schema.tables WHERE table_schema = @0 and table_name = 'Bans'", TShock.Config.Settings.MySqlDbName);
- }
- else
- {
- res = database.QueryScalar("SELECT COUNT(name) FROM sqlite_master WHERE type='table' AND name = 'Bans'");
- }
-
- if (res != 0)
- {
- var bans = new List();
- using (var reader = database.QueryReader("SELECT * FROM Bans"))
- {
- while (reader.Read())
- {
- var ip = reader.Get("IP");
- var uuid = reader.Get("UUID");
- var account = reader.Get("AccountName");
- var reason = reader.Get("Reason");
- var banningUser = reader.Get("BanningUser");
- var date = reader.Get("Date");
- var expiration = reader.Get("Expiration");
-
- if (!DateTime.TryParse(date, out DateTime start))
- {
- start = DateTime.UtcNow;
- }
-
- if (!DateTime.TryParse(expiration, out DateTime end))
- {
- end = DateTime.MaxValue;
- }
-
- if (!string.IsNullOrWhiteSpace(ip))
- {
- bans.Add(new BanPreAddEventArgs
- {
- Identifier = $"{Identifier.IP}{ip}",
- Reason = reason,
- BanningUser = banningUser,
- BanDateTime = start,
- ExpirationDateTime = end
- });
- }
-
- if (!string.IsNullOrWhiteSpace(account))
- {
- bans.Add(new BanPreAddEventArgs
- {
- Identifier = $"{Identifier.Account}{account}",
- Reason = reason,
- BanningUser = banningUser,
- BanDateTime = start,
- ExpirationDateTime = end
- });
- }
-
- if (!string.IsNullOrWhiteSpace(uuid))
- {
- bans.Add(new BanPreAddEventArgs
- {
- Identifier = $"{Identifier.UUID}{uuid}",
- Reason = reason,
- BanningUser = banningUser,
- BanDateTime = start,
- ExpirationDateTime = end
- });
- }
- }
- }
-
- foreach (var ban in bans)
- InsertBan(ban);
-
- database.Query("DROP TABLE Bans");
- }
- }
-
- internal bool CheckBan(TSPlayer player)
- {
- List identifiers = new List
- {
- $"{Identifier.UUID}{player.UUID}",
- $"{Identifier.Name}{player.Name}",
- $"{Identifier.IP}{player.IP}"
- };
-
- if (player.Account != null)
- {
- identifiers.Add($"{Identifier.Account}{player.Account.Name}");
- }
-
- Ban ban = TShock.Bans.Bans.FirstOrDefault(b => identifiers.Contains(b.Value.Identifier) && TShock.Bans.IsValidBan(b.Value, player)).Value;
-
- if (ban != null)
- {
- if (ban.ExpirationDateTime == DateTime.MaxValue)
- {
- player.Disconnect(GetParticularString("{0} is ban number, {1} is ban reason", $"#{ban.TicketNumber} - You are banned: {ban.Reason}"));
- return true;
- }
-
- TimeSpan ts = ban.ExpirationDateTime - DateTime.UtcNow;
- player.Disconnect(GetParticularString("{0} is ban number, {1} is ban reason, {2} is a timestamp", $"#{ban.TicketNumber} - You are banned: {ban.Reason} ({ban.GetPrettyExpirationString()} remaining)"));
- return true;
- }
-
- return false;
- }
-
- ///
- /// Determines whether or not a ban is valid
- ///
- ///
- ///
- ///
- public bool IsValidBan(Ban ban, TSPlayer player)
- {
- BanEventArgs args = new BanEventArgs
- {
- Ban = ban,
- Player = player
- };
-
- OnBanValidate?.Invoke(this, args);
-
- return args.Valid;
- }
-
- internal void BanValidateCheck(object sender, BanEventArgs args)
- {
- //Only perform validation if the event has not been cancelled before we got here
- if (args.Valid)
- {
- //We consider a ban to be valid if the start time is before now and the end time is after now
- args.Valid = (DateTime.UtcNow > args.Ban.BanDateTime && DateTime.UtcNow < args.Ban.ExpirationDateTime);
- }
- }
-
- internal void BanAddedCheck(object sender, BanPreAddEventArgs args)
- {
- //Only perform validation if the event has not been cancelled before we got here
- if (args.Valid)
- {
- //We consider a ban valid to add if no other *current* bans exist for the identifier provided.
- //E.g., if a previous ban has expired, a new ban is valid.
- //However, if a previous ban on the provided identifier is still in effect, a new ban is not valid
- args.Valid = !Bans.Any(b => b.Value.Identifier == args.Identifier && b.Value.ExpirationDateTime > DateTime.UtcNow);
- args.Message = args.Valid ? null : GetString("The ban is invalid because a current ban for this identifier already exists.");
- }
- }
-
- ///
- /// Adds a new ban for the given identifier. Returns a Ban object if the ban was added, else null
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- public AddBanResult InsertBan(string identifier, string reason, string banningUser, DateTime fromDate, DateTime toDate)
- {
- BanPreAddEventArgs args = new BanPreAddEventArgs
- {
- Identifier = identifier,
- Reason = reason,
- BanningUser = banningUser,
- BanDateTime = fromDate,
- ExpirationDateTime = toDate
- };
- return InsertBan(args);
- }
-
- ///
- /// Adds a new ban for the given data. Returns a Ban object if the ban was added, else null
- ///
- /// A predefined instance of
- ///
- public AddBanResult InsertBan(BanPreAddEventArgs args)
- {
- OnBanPreAdd?.Invoke(this, args);
-
- if (!args.Valid)
- {
- string message = args.Message ?? GetString("The ban was not valid for an unknown reason.");
- return new AddBanResult { Message = message };
- }
-
- string query = "INSERT INTO PlayerBans (Identifier, Reason, BanningUser, Date, Expiration) VALUES (@0, @1, @2, @3, @4);";
-
- if (database.GetSqlType() == SqlType.Mysql)
- {
- query += "SELECT LAST_INSERT_ID();";
- }
- else
- {
- query += "SELECT CAST(last_insert_rowid() as INT);";
- }
-
- int ticketId = database.QueryScalar(query, args.Identifier, args.Reason, args.BanningUser, args.BanDateTime.Ticks, args.ExpirationDateTime.Ticks);
-
- if (ticketId == 0)
- {
- return new AddBanResult { Message = GetString("Inserting the ban into the database failed.") };
- }
-
- Ban b = new Ban(ticketId, args.Identifier, args.Reason, args.BanningUser, args.BanDateTime, args.ExpirationDateTime);
- _bans.Add(ticketId, b);
-
- OnBanPostAdd?.Invoke(this, new BanEventArgs { Ban = b });
-
- return new AddBanResult { Ban = b };
- }
-
- ///
- /// Attempts to remove a ban. Returns true if the ban was removed or expired. False if the ban could not be removed or expired
- ///
- /// The ticket number of the ban to change
- /// If true, deletes the ban from the database. If false, marks the expiration time as now, rendering the ban expired. Defaults to false
- ///
- public bool RemoveBan(int ticketNumber, bool fullDelete = false)
- {
- int rowsModified;
- if (fullDelete)
- {
- rowsModified = database.Query("DELETE FROM PlayerBans WHERE TicketNumber=@0", ticketNumber);
- _bans.Remove(ticketNumber);
- }
- else
- {
- rowsModified = database.Query("UPDATE PlayerBans SET Expiration=@0 WHERE TicketNumber=@1", DateTime.UtcNow.Ticks, ticketNumber);
- _bans[ticketNumber].ExpirationDateTime = DateTime.UtcNow;
- }
-
- return rowsModified > 0;
- }
-
- ///
- /// Retrieves a single ban from a ban's ticket number
- ///
- ///
- ///
- public Ban GetBanById(int id)
- {
- if (Bans.ContainsKey(id))
- {
- return Bans[id];
- }
-
- using (var reader = database.QueryReader("SELECT * FROM PlayerBans WHERE TicketNumber=@0", id))
- {
- if (reader.Read())
- {
- var ticketNumber = reader.Get("TicketNumber");
- var identifier = reader.Get("Identifier");
- var reason = reader.Get("Reason");
- var banningUser = reader.Get("BanningUser");
- var date = reader.Get("Date");
- var expiration = reader.Get("Expiration");
-
- return new Ban(ticketNumber, identifier, reason, banningUser, date, expiration);
- }
- }
-
- return null;
- }
-
- ///
- /// Retrieves an enumerable of all bans for a given identifier
- ///
- /// Identifier to search with
- /// Whether or not to exclude expired bans
- ///
- public IEnumerable RetrieveBansByIdentifier(string identifier, bool currentOnly = true)
- {
- string query = "SELECT * FROM PlayerBans WHERE Identifier=@0";
- if (currentOnly)
- {
- query += $" AND Expiration > {DateTime.UtcNow.Ticks}";
- }
-
- using (var reader = database.QueryReader(query, identifier))
- {
- while (reader.Read())
- {
- var ticketNumber = reader.Get("TicketNumber");
- var ident = reader.Get("Identifier");
- var reason = reader.Get("Reason");
- var banningUser = reader.Get("BanningUser");
- var date = reader.Get("Date");
- var expiration = reader.Get("Expiration");
-
- yield return new Ban(ticketNumber, ident, reason, banningUser, date, expiration);
- }
- }
- }
-
- ///
- /// Retrieves an enumerable of bans for a given set of identifiers
- ///
- /// Whether or not to exclude expired bans
- ///
- ///
- public IEnumerable GetBansByIdentifiers(bool currentOnly = true, params string[] identifiers)
- {
- //Generate a sequence of '@0, @1, @2, ... etc'
- var parameters = string.Join(", ", Enumerable.Range(0, identifiers.Count()).Select(p => $"@{p}"));
-
- string query = $"SELECT * FROM PlayerBans WHERE Identifier IN ({parameters})";
- if (currentOnly)
- {
- query += $" AND Expiration > {DateTime.UtcNow.Ticks}";
- }
-
- using (var reader = database.QueryReader(query, identifiers))
- {
- while (reader.Read())
- {
- var ticketNumber = reader.Get("TicketNumber");
- var identifier = reader.Get("Identifier");
- var reason = reader.Get("Reason");
- var banningUser = reader.Get("BanningUser");
- var date = reader.Get("Date");
- var expiration = reader.Get("Expiration");
-
- yield return new Ban(ticketNumber, identifier, reason, banningUser, date, expiration);
- }
- }
- }
-
- ///
- /// Retrieves a list of bans from the database, sorted by their addition date from newest to oldest
- ///
- public IEnumerable RetrieveAllBans() => RetrieveAllBansSorted(BanSortMethod.AddedNewestToOldest);
-
- ///
- /// Retrieves an enumerable of s from the database, sorted using the provided sort method
- ///
- ///
- ///
- public IEnumerable RetrieveAllBansSorted(BanSortMethod sortMethod)
- {
- List banlist = new List();
- try
- {
- var orderBy = SortToOrderByMap[sortMethod];
- using (var reader = database.QueryReader($"SELECT * FROM PlayerBans ORDER BY {orderBy}"))
- {
- while (reader.Read())
- {
- var ticketNumber = reader.Get("TicketNumber");
- var identifier = reader.Get("Identifier");
- var reason = reader.Get("Reason");
- var banningUser = reader.Get("BanningUser");
- var date = reader.Get("Date");
- var expiration = reader.Get("Expiration");
-
- var ban = new Ban(ticketNumber, identifier, reason, banningUser, date, expiration);
- banlist.Add(ban);
- }
- }
- }
- catch (Exception ex)
- {
- TShock.Log.Error(ex.ToString());
- Console.WriteLine(ex.StackTrace);
- }
-
- return banlist;
- }
-
- ///
- /// Removes all bans from the database
- ///
- /// true, if bans were cleared, false otherwise.
- public bool ClearBans()
- {
- try
- {
- return database.Query("DELETE FROM PlayerBans") != 0;
- }
- catch (Exception ex)
- {
- TShock.Log.Error(ex.ToString());
- }
- return false;
- }
-
- internal Dictionary SortToOrderByMap = new Dictionary
- {
- { BanSortMethod.AddedNewestToOldest, "Date DESC" },
- { BanSortMethod.AddedOldestToNewest, "Date ASC" },
- { BanSortMethod.ExpirationSoonestToLatest, "Expiration ASC" },
- { BanSortMethod.ExpirationLatestToSoonest, "Expiration DESC" }
- };
- }
-
- ///
- /// Enum containing sort options for ban retrieval
- ///
- public enum BanSortMethod
- {
- ///
- /// Bans will be sorted on expiration date, from soonest to latest
- ///
- ExpirationSoonestToLatest,
- ///
- /// Bans will be sorted on expiration date, from latest to soonest
- ///
- ExpirationLatestToSoonest,
- ///
- /// Bans will be sorted by the date they were added, from newest to oldest
- ///
- AddedNewestToOldest,
- ///
- /// Bans will be sorted by the date they were added, from oldest to newest
- ///
- AddedOldestToNewest,
- ///
- /// Bans will be sorted by their ticket number
- ///
- TicketNumber
- }
-
- ///
- /// Result of an attempt to add a ban
- ///
- public class AddBanResult
- {
- ///
- /// Message generated from the attempt
- ///
- public string Message { get; set; }
- ///
- /// Ban object generated from the attempt, or null if the attempt failed
- ///
- public Ban Ban { get; set; }
- }
-
- ///
- /// Event args used for completed bans
- ///
- public class BanEventArgs : EventArgs
- {
- ///
- /// Complete ban object
- ///
- public Ban Ban { get; set; }
-
- ///
- /// Player ban is being applied to
- ///
- public TSPlayer Player { get; set; }
-
- ///
- /// Whether or not the operation should be considered to be valid
- ///
- public bool Valid { get; set; } = true;
- }
-
- ///
- /// Event args used for ban data prior to a ban being formalized
- ///
- public class BanPreAddEventArgs : EventArgs
- {
- ///
- /// An identifiable piece of information to ban
- ///
- public string Identifier { get; set; }
-
- ///
- /// Gets or sets the ban reason.
- ///
- /// The ban reason.
- public string Reason { get; set; }
-
- ///
- /// Gets or sets the name of the user who added this ban entry.
- ///
- /// The banning user.
- public string BanningUser { get; set; }
-
- ///
- /// DateTime from which the ban will take effect
- ///
- public DateTime BanDateTime { get; set; }
-
- ///
- /// DateTime at which the ban will end
- ///
- public DateTime ExpirationDateTime { get; set; }
-
- ///
- /// Whether or not the operation should be considered to be valid
- ///
- public bool Valid { get; set; } = true;
-
- ///
- /// Optional message to explain why the event was invalidated, if it was
- ///
- public string Message { get; set; }
- }
-
- ///
- /// Describes an identifier used by the ban system
- ///
- public class Identifier
- {
- ///
- /// Identifiers currently registered
- ///
- public static List Available = new List();
-
- ///
- /// The prefix of the identifier. E.g, 'ip:'
- ///
- public string Prefix { get; }
- ///
- /// Short description of the identifier and its basic usage
- ///
- public string Description { get; set; }
-
- ///
- /// IP identifier
- ///
- public static Identifier IP = Register("ip:", GetString($"An identifier for an IP Address in octet format. e.g., '{"127.0.0.1".Color(Utils.RedHighlight)}'."));
- ///
- /// UUID identifier
- ///
- public static Identifier UUID = Register("uuid:", GetString("An identifier for a UUID."));
- ///
- /// Player name identifier
- ///
- public static Identifier Name = Register("name:", GetString("An identifier for a character name."));
- ///
- /// User account identifier
- ///
- public static Identifier Account = Register("acc:", GetString("An identifier for a TShock User Account name."));
-
- private Identifier(string prefix, string description)
- {
- Prefix = prefix;
- Description = description;
- }
-
- ///
- /// Returns the identifier's prefix
- ///
- ///
- public override string ToString()
- {
- return Prefix;
- }
-
- ///
- /// Registers a new identifier with the given prefix and description
- ///
- ///
- ///
- public static Identifier Register(string prefix, string description)
- {
- var ident = new Identifier(prefix, description);
- Available.Add(ident);
-
- return ident;
- }
- }
-
- ///
- /// Model class that represents a ban entry in the TShock database.
- ///
- public class Ban
- {
- ///
- /// A unique ID assigned to this ban
- ///
- public int TicketNumber { get; set; }
-
- ///
- /// An identifiable piece of information to ban
- ///
- public string Identifier { get; set; }
-
- ///
- /// Gets or sets the ban reason.
- ///
- /// The ban reason.
- public string Reason { get; set; }
-
- ///
- /// Gets or sets the name of the user who added this ban entry.
- ///
- /// The banning user.
- public string BanningUser { get; set; }
-
- ///
- /// DateTime from which the ban will take effect
- ///
- public DateTime BanDateTime { get; set; }
-
- ///
- /// DateTime at which the ban will end
- ///
- public DateTime ExpirationDateTime { get; set; }
-
- ///
- /// Returns a string in the format dd:mm:hh:ss indicating the time until the ban expires.
- /// If the ban is not set to expire (ExpirationDateTime == DateTime.MaxValue), returns the string 'Never'
- ///
- ///
- public string GetPrettyExpirationString()
- {
- if (ExpirationDateTime == DateTime.MaxValue)
- {
- return "Never";
- }
-
- TimeSpan ts = (ExpirationDateTime - DateTime.UtcNow).Duration(); // Use duration to avoid pesky negatives for expired bans
- return $"{ts.Days:00}:{ts.Hours:00}:{ts.Minutes:00}:{ts.Seconds:00}";
- }
-
- ///
- /// Returns a string in the format dd:mm:hh:ss indicating the time elapsed since the ban was added.
- ///
- ///
- public string GetPrettyTimeSinceBanString()
- {
- TimeSpan ts = (DateTime.UtcNow - BanDateTime).Duration();
- return $"{ts.Days:00}:{ts.Hours:00}:{ts.Minutes:00}:{ts.Seconds:00}";
- }
-
- ///
- /// Initializes a new instance of the class.
- ///
- /// Unique ID assigned to the ban
- /// Identifier to apply the ban to
- /// Reason for the ban
- /// Account name that executed the ban
- /// System ticks at which the ban began
- /// System ticks at which the ban will end
- public Ban(int ticketNumber, string identifier, string reason, string banningUser, long start, long end)
- : this(ticketNumber, identifier, reason, banningUser, new DateTime(start), new DateTime(end))
- {
- }
-
-
- ///
- /// Initializes a new instance of the class.
- ///
- /// Unique ID assigned to the ban
- /// Identifier to apply the ban to
- /// Reason for the ban
- /// Account name that executed the ban
- /// DateTime at which the ban will start
- /// DateTime at which the ban will end
- public Ban(int ticketNumber, string identifier, string reason, string banningUser, DateTime start, DateTime end)
- {
- TicketNumber = ticketNumber;
- Identifier = identifier;
- Reason = reason;
- BanningUser = banningUser;
- BanDateTime = start;
- ExpirationDateTime = end;
- }
- }
-}
diff --git a/TShockAPI/Database/BanManager.cs b/TShockAPI/Database/BanManager.cs
new file mode 100644
index 000000000..f86b59ed8
--- /dev/null
+++ b/TShockAPI/Database/BanManager.cs
@@ -0,0 +1,369 @@
+/*
+TShock, a server mod for Terraria
+Copyright (C) 2011-2019 Pryaxis & TShock Contributors
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see .
+*/
+
+using System;
+using System.Linq;
+using System.Collections.Generic;
+using System.Data;
+using MySql.Data.MySqlClient;
+using System.Collections.ObjectModel;
+using System.Threading.Tasks;
+using MongoDB.Bson;
+using MongoDB.Bson.Serialization.Attributes;
+using MongoDB.Driver;
+using MongoDB.Entities;
+using Entity = Terraria.Entity;
+
+namespace TShockAPI.Database
+{
+ ///
+ /// Class that manages bans.
+ ///
+ public static class BanManager
+ {
+ ///
+ /// Returns the number of bans that already exist
+ ///
+ /// Total number of bans
+ public static async Task CountBans()
+ {
+ return await DB.CountAsync();
+ }
+
+ ///
+ /// Event invoked after a ban is added
+ ///
+ public static event EventHandler OnBanAdd;
+
+ ///
+ /// Event invoked after a user is unbanned
+ ///
+ public static event EventHandler OnBanRemove;
+
+
+ internal static async Task IsPlayerBanned(TSPlayer player)
+ {
+ // Attempt to find a ban by account name if the player is logged in,
+ // otherwise, find by IP address or UUID.
+ var banFilter = player.IsLoggedIn
+ ? Builders.Filter.Eq(b => b.AccountName, player.Account.Name)
+ : Builders.Filter.Or(
+ Builders.Filter.Eq(b => b.IpAddress, player.IP),
+ Builders.Filter.Eq(b => b.Uuid, player.UUID));
+
+ // Execute the database query to find a matching ban.
+ var ban = await DB.Find().Match(banFilter).ExecuteFirstAsync();
+
+ // If no ban is found, the player is not banned.
+ if (ban == null) return false;
+
+ // Disconnect the player with an appropriate message based on the ban expiration.
+ var disconnectMessage = GetBanDisconnectMessage(ban);
+ player.Disconnect(disconnectMessage);
+ return true;
+ }
+
+ private static string GetBanDisconnectMessage(Ban ban)
+ {
+ var baseMessage = $"#{ban.BanId} - You are banned: {ban.Reason}";
+
+ // If the ban is permanent.
+ if (ban.ExpirationDateTime == DateTime.MaxValue)
+ {
+ return GetParticularString("{0} is ban number, {1} is ban reason", baseMessage);
+ }
+
+ // If the ban has an expiration date.
+ var timeRemaining = ban.ExpirationDateTime - DateTime.UtcNow;
+ var prettyExpiration =
+ ban.GetPrettyExpirationString(); // Assuming this method exists and formats the expiration nicely.
+ return GetParticularString("{0} is ban number, {1} is ban reason, {2} is a timestamp",
+ $"{baseMessage} ({prettyExpiration} remaining)");
+ }
+
+ ///
+ /// Retrieves a single ban from a ban's ID
+ ///
+ /// The ban identifier
+ /// The requested ban
+ public static async Task GetBanById(int id)
+ {
+ return await DB.Find()
+ .Match(x => x.BanId == id)
+ .ExecuteFirstAsync();
+ }
+
+ ///
+ /// Retrieves a list of bans from the database, sorted by their addition date from newest to oldest
+ ///
+ public static async Task> RetrieveAllBans() => await RetrieveAllBansSorted(BanSortMethod.DateBanned, true);
+
+ ///
+ /// Retrieves an enumerable of Bans from the database, sorted using the provided sort method
+ ///
+ /// The method to sort the bans.
+ /// Whether the sort should be in descending order.
+ /// A sorted enumerable of Ban objects.
+ public static async Task> RetrieveAllBansSorted(BanSortMethod sortMethod, bool descending = true)
+ {
+ var sortDefinition = descending
+ ? Builders.Sort.Descending(GetSortField(sortMethod))
+ : Builders.Sort.Ascending(GetSortField(sortMethod));
+
+ var banList = await DB.Find().Sort(x=>sortDefinition).ExecuteAsync();
+ return banList;
+ }
+
+ private static string GetSortField(BanSortMethod sortMethod)
+ {
+ return sortMethod switch
+ {
+ BanSortMethod.TicketNumber => nameof(BanSortMethod.TicketNumber),
+ BanSortMethod.DateBanned => nameof(BanSortMethod.DateBanned),
+ BanSortMethod.EndDate => nameof(BanSortMethod.EndDate),
+ _ => throw new ArgumentOutOfRangeException(nameof(sortMethod), $"Not expected sort method value: {sortMethod}"),
+ };
+ }
+
+ public static Ban CreateBan(BanType type, string value, string reason, UserAccount banningUser, DateTime start,
+ DateTime? endDate = null)
+ {
+ Ban ban = new()
+ {
+ Reason = reason,
+ BanningUser = banningUser.Name,
+ BanDateTime = start,
+ ExpirationDateTime = endDate ?? DateTime.MaxValue
+ };
+
+ switch (type)
+ {
+ case BanType.Uuid:
+ {
+ ban.Uuid = value;
+ break;
+ }
+ case BanType.AccountName:
+ {
+ ban.AccountName = value;
+ break;
+ }
+ case BanType.IpAddress:
+ {
+ ban.IpAddress = value;
+ break;
+ }
+ default: throw new Exception("Invalid ban type!");
+ }
+
+ TShock.Log.Info("A new ban has been created for: ");
+ return ban;
+ }
+
+ public static bool UnbanPlayer(string accountName)
+ {
+
+ }
+
+
+ ///
+ /// Removes all bans from the database
+ ///
+ public static async Task ClearBans() => await DB.DeleteAsync(Builders.Filter.Empty);
+
+ }
+
+ ///
+ /// Enum containing sort options for ban retrieval
+ ///
+ public enum BanSortMethod
+ {
+ DateBanned,
+ EndDate,
+ TicketNumber
+ }
+
+ ///
+ /// Result of an attempt to add a ban
+ ///
+ public class AddBanResult
+ {
+ ///
+ /// Message generated from the attempt
+ ///
+ public string Message { get; set; }
+
+ ///
+ /// Ban object generated from the attempt, or null if the attempt failed
+ ///
+ public Ban Ban { get; set; }
+ }
+
+ ///
+ /// Event args used for completed bans
+ ///
+ public class BanEventArgs : EventArgs
+ {
+ ///
+ /// Complete ban object
+ ///
+ public Ban Ban { get; set; }
+
+ ///
+ /// Player ban is being applied to
+ ///
+ public TSPlayer Player { get; set; }
+
+ ///
+ /// Whether or not the operation should be considered to be valid
+ ///
+ public bool Valid { get; set; } = true;
+ }
+
+ ///
+ /// Event args used for ban data prior to a ban being formalized
+ ///
+ public class BanPreAddEventArgs : EventArgs
+ {
+ ///
+ /// An identifiable piece of information to ban
+ ///
+ public string Identifier { get; set; }
+
+ ///
+ /// Gets or sets the ban reason.
+ ///
+ /// The ban reason.
+ public string Reason { get; set; }
+
+ ///
+ /// Gets or sets the name of the user who added this ban entry.
+ ///
+ /// The banning user.
+ public string BanningUser { get; set; }
+
+ ///
+ /// DateTime from which the ban will take effect
+ ///
+ public DateTime BanDateTime { get; set; }
+
+ ///
+ /// DateTime at which the ban will end
+ ///
+ public DateTime ExpirationDateTime { get; set; }
+
+ ///
+ /// Whether or not the operation should be considered to be valid
+ ///
+ public bool Valid { get; set; } = true;
+
+ ///
+ /// Optional message to explain why the event was invalidated, if it was
+ ///
+ public string Message { get; set; }
+ }
+
+ ///
+ /// Model class that represents a ban entry in the database.
+ ///
+ public class Ban : MongoDB.Entities.Entity
+ {
+ ///
+ /// A unique ID assigned to this ban
+ ///
+ public int BanId { get; set; }
+
+ ///
+ /// A possible IP address we are banning
+ ///
+ public string? IpAddress { get; set; }
+
+ ///
+ /// A possible UUID we are banning
+ ///
+ public string? Uuid { get; set; }
+
+ ///
+ /// A possible account name we are banning
+ ///
+ public string? AccountName { get; set; }
+
+ ///
+ /// Gets or sets the ban reason.
+ ///
+ /// The ban reason.
+ public string Reason { get; set; }
+
+ ///
+ /// Gets or sets the name of the user who added this ban entry.
+ ///
+ /// The banning user.
+ public string BanningUser { get; set; }
+
+ ///
+ /// DateTime from which the ban will take effect
+ ///
+ public DateTime BanDateTime { get; set; }
+
+ ///
+ /// DateTime at which the ban will end
+ ///
+ public DateTime ExpirationDateTime { get; set; }
+
+ ///
+ /// Returns whether or not the ban is still in effect
+ ///
+ [Ignore] public bool Valid => ExpirationDateTime > BanDateTime;
+
+ ///
+ /// Returns a string in the format dd:mm:hh:ss indicating the time until the ban expires.
+ /// If the ban is not set to expire (ExpirationDateTime == DateTime.MaxValue), returns the string 'Never'
+ ///
+ ///
+ public string GetPrettyExpirationString()
+ {
+ if (ExpirationDateTime == DateTime.MaxValue)
+ {
+ return "Never";
+ }
+
+ TimeSpan
+ ts = (ExpirationDateTime - DateTime.UtcNow)
+ .Duration(); // Use duration to avoid pesky negatives for expired bans
+ return $"{ts.Days:00}:{ts.Hours:00}:{ts.Minutes:00}:{ts.Seconds:00}";
+ }
+
+ ///
+ /// Returns a string in the format dd:mm:hh:ss indicating the time elapsed since the ban was added.
+ ///
+ ///
+ public string GetPrettyTimeSinceBanString()
+ {
+ TimeSpan ts = (DateTime.UtcNow - BanDateTime).Duration();
+ return $"{ts.Days:00}:{ts.Hours:00}:{ts.Minutes:00}:{ts.Seconds:00}";
+ }
+
+ }
+
+ public enum BanType
+ {
+ Uuid,
+ AccountName,
+ IpAddress
+ }
+}
diff --git a/TShockAPI/DB/CharacterManager.cs b/TShockAPI/Database/CharacterManager.cs
similarity index 99%
rename from TShockAPI/DB/CharacterManager.cs
rename to TShockAPI/Database/CharacterManager.cs
index 5a5e13a64..ec7cfabdc 100644
--- a/TShockAPI/DB/CharacterManager.cs
+++ b/TShockAPI/Database/CharacterManager.cs
@@ -24,7 +24,7 @@ You should have received a copy of the GNU General Public License
using MySql.Data.MySqlClient;
using Terraria;
-namespace TShockAPI.DB
+namespace TShockAPI.Database
{
public class CharacterManager
{
diff --git a/TShockAPI/DB/GroupManager.cs b/TShockAPI/Database/GroupManager.cs
similarity index 98%
rename from TShockAPI/DB/GroupManager.cs
rename to TShockAPI/Database/GroupManager.cs
index 8e0e31923..d8c29b291 100644
--- a/TShockAPI/DB/GroupManager.cs
+++ b/TShockAPI/Database/GroupManager.cs
@@ -24,7 +24,7 @@ You should have received a copy of the GNU General Public License
using System.Linq;
using MySql.Data.MySqlClient;
-namespace TShockAPI.DB
+namespace TShockAPI.Database
{
///
/// Represents the GroupManager, which is in charge of group management.
@@ -196,7 +196,7 @@ public GroupManager(IDbConnection db)
Permissions.createdumps));
}
- // Load Permissions from the DB
+ // Load Permissions from the Database
LoadPermisions();
Group.DefaultGroup = GetGroupByName(TShock.Config.Settings.DefaultGuestGroupName);
@@ -360,7 +360,7 @@ public void UpdateGroup(string name, string parentname, string permissions, stri
}
}
- // Ensure any group validation is also persisted to the DB.
+ // Ensure any group validation is also persisted to the Database.
var newGroup = new Group(name, parent, chatcolor, permissions);
newGroup.Prefix = prefix;
newGroup.Suffix = suffix;
@@ -531,7 +531,7 @@ public String AddPermissions(String name, List permissions)
if (database.Query("UPDATE GroupList SET Commands=@0 WHERE GroupName=@1", group.Permissions, name) == 1)
return "Group " + name + " has been modified successfully.";
- // Restore old permissions so DB and internal object are in a consistent state
+ // Restore old permissions so Database and internal object are in a consistent state
group.Permissions = oldperms;
return "";
}
@@ -554,7 +554,7 @@ public String DeletePermissions(String name, List permissions)
if (database.Query("UPDATE GroupList SET Commands=@0 WHERE GroupName=@1", group.Permissions, name) == 1)
return "Group " + name + " has been modified successfully.";
- // Restore old permissions so DB and internal object are in a consistent state
+ // Restore old permissions so Database and internal object are in a consistent state
group.Permissions = oldperms;
return "";
}
diff --git a/TShockAPI/DB/IQueryBuilder.cs b/TShockAPI/Database/IQueryBuilder.cs
similarity index 99%
rename from TShockAPI/DB/IQueryBuilder.cs
rename to TShockAPI/Database/IQueryBuilder.cs
index c2be131d3..33735b5a9 100644
--- a/TShockAPI/DB/IQueryBuilder.cs
+++ b/TShockAPI/Database/IQueryBuilder.cs
@@ -24,7 +24,7 @@ You should have received a copy of the GNU General Public License
using System.Text;
using TShockAPI.Extensions;
-namespace TShockAPI.DB
+namespace TShockAPI.Database
{
///
/// Interface for various SQL related utilities.
diff --git a/TShockAPI/DB/ItemManager.cs b/TShockAPI/Database/ItemManager.cs
similarity index 99%
rename from TShockAPI/DB/ItemManager.cs
rename to TShockAPI/Database/ItemManager.cs
index 012132dc6..21610eafc 100644
--- a/TShockAPI/DB/ItemManager.cs
+++ b/TShockAPI/Database/ItemManager.cs
@@ -23,7 +23,7 @@ You should have received a copy of the GNU General Public License
using MySql.Data.MySqlClient;
using TShockAPI.Hooks;
-namespace TShockAPI.DB
+namespace TShockAPI.Database
{
public class ItemManager
{
diff --git a/TShockAPI/DB/ProjectileManager.cs b/TShockAPI/Database/ProjectileManager.cs
similarity index 98%
rename from TShockAPI/DB/ProjectileManager.cs
rename to TShockAPI/Database/ProjectileManager.cs
index 0e6cabe04..5d90219a2 100644
--- a/TShockAPI/DB/ProjectileManager.cs
+++ b/TShockAPI/Database/ProjectileManager.cs
@@ -23,14 +23,14 @@ You should have received a copy of the GNU General Public License
using MySql.Data.MySqlClient;
using TShockAPI.Hooks;
-namespace TShockAPI.DB
+namespace TShockAPI.Database
{
- public class ProjectileManagager
+ public class ProjectileManager
{
private IDbConnection database;
public List ProjectileBans = new List();
- public ProjectileManagager(IDbConnection db)
+ public ProjectileManager(IDbConnection db)
{
database = db;
diff --git a/TShockAPI/DB/RegionManager.cs b/TShockAPI/Database/RegionManager.cs
similarity index 99%
rename from TShockAPI/DB/RegionManager.cs
rename to TShockAPI/Database/RegionManager.cs
index 1a284ff30..8f47e74cf 100644
--- a/TShockAPI/DB/RegionManager.cs
+++ b/TShockAPI/Database/RegionManager.cs
@@ -24,7 +24,7 @@ You should have received a copy of the GNU General Public License
using Terraria;
using Microsoft.Xna.Framework;
-namespace TShockAPI.DB
+namespace TShockAPI.Database
{
///
/// Represents the Region database manager.
diff --git a/TShockAPI/DB/RememberedPosManager.cs b/TShockAPI/Database/RememberedPosManager.cs
similarity index 99%
rename from TShockAPI/DB/RememberedPosManager.cs
rename to TShockAPI/Database/RememberedPosManager.cs
index c49c5912b..4d9857223 100644
--- a/TShockAPI/DB/RememberedPosManager.cs
+++ b/TShockAPI/Database/RememberedPosManager.cs
@@ -22,7 +22,7 @@ You should have received a copy of the GNU General Public License
using Terraria;
using Microsoft.Xna.Framework;
-namespace TShockAPI.DB
+namespace TShockAPI.Database
{
public class RememberedPosManager
{
diff --git a/TShockAPI/DB/ResearchDatastore.cs b/TShockAPI/Database/ResearchDatastore.cs
similarity index 97%
rename from TShockAPI/DB/ResearchDatastore.cs
rename to TShockAPI/Database/ResearchDatastore.cs
index 0d2429d7a..2430046de 100644
--- a/TShockAPI/DB/ResearchDatastore.cs
+++ b/TShockAPI/Database/ResearchDatastore.cs
@@ -8,7 +8,7 @@
using Terraria;
using Terraria.ID;
-namespace TShockAPI.DB
+namespace TShockAPI.Database
{
///
/// This class is used as the data interface for Journey mode research.
@@ -26,7 +26,7 @@ public class ResearchDatastore
private Dictionary _itemsSacrificed;
///
- /// Initializes a new instance of the class.
+ /// Initializes a new instance of the class.
///
/// A valid connection to the TShock database
public ResearchDatastore(IDbConnection db)
diff --git a/TShockAPI/DB/SqlColumn.cs b/TShockAPI/Database/SqlColumn.cs
similarity index 98%
rename from TShockAPI/DB/SqlColumn.cs
rename to TShockAPI/Database/SqlColumn.cs
index 27c45435c..a3a677bd4 100644
--- a/TShockAPI/DB/SqlColumn.cs
+++ b/TShockAPI/Database/SqlColumn.cs
@@ -19,7 +19,7 @@ You should have received a copy of the GNU General Public License
using MySql.Data.MySqlClient;
using System;
-namespace TShockAPI.DB
+namespace TShockAPI.Database
{
public class SqlColumn
{
diff --git a/TShockAPI/DB/SqlTable.cs b/TShockAPI/Database/SqlTable.cs
similarity index 98%
rename from TShockAPI/DB/SqlTable.cs
rename to TShockAPI/Database/SqlTable.cs
index 1f0c45936..e56e217c5 100644
--- a/TShockAPI/DB/SqlTable.cs
+++ b/TShockAPI/Database/SqlTable.cs
@@ -22,7 +22,7 @@ You should have received a copy of the GNU General Public License
using System.Linq;
using MySql.Data.MySqlClient;
-namespace TShockAPI.DB
+namespace TShockAPI.Database
{
public class SqlTable
{
diff --git a/TShockAPI/DB/SqlValue.cs b/TShockAPI/Database/SqlValue.cs
similarity index 98%
rename from TShockAPI/DB/SqlValue.cs
rename to TShockAPI/Database/SqlValue.cs
index aa70e2d62..5ed0b5d43 100644
--- a/TShockAPI/DB/SqlValue.cs
+++ b/TShockAPI/Database/SqlValue.cs
@@ -19,7 +19,7 @@ You should have received a copy of the GNU General Public License
using System.Collections.Generic;
using System.Data;
-namespace TShockAPI.DB
+namespace TShockAPI.Database
{
public class SqlValue
{
diff --git a/TShockAPI/DB/TileManager.cs b/TShockAPI/Database/TileManager.cs
similarity index 99%
rename from TShockAPI/DB/TileManager.cs
rename to TShockAPI/Database/TileManager.cs
index bd918e733..820d1a0ad 100644
--- a/TShockAPI/DB/TileManager.cs
+++ b/TShockAPI/Database/TileManager.cs
@@ -23,7 +23,7 @@ You should have received a copy of the GNU General Public License
using MySql.Data.MySqlClient;
using TShockAPI.Hooks;
-namespace TShockAPI.DB
+namespace TShockAPI.Database
{
public class TileManager
{
diff --git a/TShockAPI/DB/UserManager.cs b/TShockAPI/Database/UserManager.cs
similarity index 99%
rename from TShockAPI/DB/UserManager.cs
rename to TShockAPI/Database/UserManager.cs
index 0354989e7..611caacff 100644
--- a/TShockAPI/DB/UserManager.cs
+++ b/TShockAPI/Database/UserManager.cs
@@ -26,7 +26,7 @@ You should have received a copy of the GNU General Public License
using BCrypt.Net;
using System.Security.Cryptography;
-namespace TShockAPI.DB
+namespace TShockAPI.Database
{
/// UserAccountManager - Methods for dealing with database user accounts and other related functionality within TShock.
public class UserAccountManager
diff --git a/TShockAPI/DB/WarpsManager.cs b/TShockAPI/Database/WarpsManager.cs
similarity index 99%
rename from TShockAPI/DB/WarpsManager.cs
rename to TShockAPI/Database/WarpsManager.cs
index bd13ce4d1..954b2ec8f 100644
--- a/TShockAPI/DB/WarpsManager.cs
+++ b/TShockAPI/Database/WarpsManager.cs
@@ -25,7 +25,7 @@ You should have received a copy of the GNU General Public License
using Terraria;
using Microsoft.Xna.Framework;
-namespace TShockAPI.DB
+namespace TShockAPI.Database
{
public class WarpManager
{
diff --git a/TShockAPI/Extensions/DbExt.cs b/TShockAPI/Extensions/DbExt.cs
index b5a2c6182..df76ed5f8 100644
--- a/TShockAPI/Extensions/DbExt.cs
+++ b/TShockAPI/Extensions/DbExt.cs
@@ -21,7 +21,7 @@ You should have received a copy of the GNU General Public License
using System.Data;
using System.Diagnostics.CodeAnalysis;
-namespace TShockAPI.DB
+namespace TShockAPI.Database
{
///
/// Database extensions
diff --git a/TShockAPI/GetDataHandlers.cs b/TShockAPI/GetDataHandlers.cs
index 1ef2f4f8b..ad10ca0a5 100644
--- a/TShockAPI/GetDataHandlers.cs
+++ b/TShockAPI/GetDataHandlers.cs
@@ -26,7 +26,7 @@ You should have received a copy of the GNU General Public License
using System.Text;
using System.Threading.Tasks;
using Terraria.ID;
-using TShockAPI.DB;
+using TShockAPI.Database;
using TShockAPI.Net;
using Terraria;
using Terraria.ObjectData;
diff --git a/TShockAPI/Hooks/AccountHooks.cs b/TShockAPI/Hooks/AccountHooks.cs
index 9c08b26dc..666d8efe3 100644
--- a/TShockAPI/Hooks/AccountHooks.cs
+++ b/TShockAPI/Hooks/AccountHooks.cs
@@ -16,7 +16,7 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
-using TShockAPI.DB;
+using TShockAPI.Database;
namespace TShockAPI.Hooks
{
public class AccountDeleteEventArgs
diff --git a/TShockAPI/Hooks/PlayerHooks.cs b/TShockAPI/Hooks/PlayerHooks.cs
index 7a3e20679..b3451fae7 100644
--- a/TShockAPI/Hooks/PlayerHooks.cs
+++ b/TShockAPI/Hooks/PlayerHooks.cs
@@ -18,7 +18,7 @@ You should have received a copy of the GNU General Public License
using System.Collections.Generic;
using System.ComponentModel;
-using TShockAPI.DB;
+using TShockAPI.Database;
namespace TShockAPI.Hooks
{
diff --git a/TShockAPI/Hooks/RegionHooks.cs b/TShockAPI/Hooks/RegionHooks.cs
index 0322846ab..36270f782 100644
--- a/TShockAPI/Hooks/RegionHooks.cs
+++ b/TShockAPI/Hooks/RegionHooks.cs
@@ -16,7 +16,7 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
-using TShockAPI.DB;
+using TShockAPI.Database;
namespace TShockAPI.Hooks
{
diff --git a/TShockAPI/ItemBans.cs b/TShockAPI/ItemBans.cs
index df0d36b05..0a626dcb5 100644
--- a/TShockAPI/ItemBans.cs
+++ b/TShockAPI/ItemBans.cs
@@ -19,7 +19,7 @@ You should have received a copy of the GNU General Public License
using System.Collections.Generic;
using System.Linq;
using Terraria.ID;
-using TShockAPI.DB;
+using TShockAPI.Database;
using TShockAPI.Net;
using Terraria;
using Microsoft.Xna.Framework;
diff --git a/TShockAPI/RegionHandler.cs b/TShockAPI/RegionHandler.cs
index 9c61b7008..17add632b 100644
--- a/TShockAPI/RegionHandler.cs
+++ b/TShockAPI/RegionHandler.cs
@@ -17,7 +17,7 @@ You should have received a copy of the GNU General Public License
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
-using TShockAPI.DB;
+using TShockAPI.Database;
using TShockAPI.Hooks;
namespace TShockAPI
diff --git a/TShockAPI/Rest/RestManager.cs b/TShockAPI/Rest/RestManager.cs
index c41e7767b..b6508fd2f 100644
--- a/TShockAPI/Rest/RestManager.cs
+++ b/TShockAPI/Rest/RestManager.cs
@@ -27,7 +27,7 @@ You should have received a copy of the GNU General Public License
using HttpServer;
using Rests;
using Terraria;
-using TShockAPI.DB;
+using TShockAPI.Database;
using Newtonsoft.Json;
namespace TShockAPI
@@ -665,7 +665,7 @@ private object BanCreateV3(RestRequestArgs args)
player.Kick(reason, true);
}
- return RestResponse(GetString($"Ban added. Ticket number: {banResult.Ban.TicketNumber}"));
+ return RestResponse(GetString($"Ban added. Ticket number: {banResult.Ban.BanId}"));
}
return RestError(GetString($"Failed to add ban. {banResult.Message}"), status: "500");
@@ -723,7 +723,7 @@ private object BanInfoV3(RestRequestArgs args)
return new RestObject
{
- { "ticket_number", ban.TicketNumber },
+ { "ticket_number", ban.BanId },
{ "identifier", ban.Identifier },
{ "reason", ban.Reason },
{ "banning_user", ban.BanningUser },
@@ -746,7 +746,7 @@ private object BanListV3(RestRequestArgs args)
banList.Add(
new Dictionary
{
- { "ticket_number", ban.TicketNumber },
+ { "ticket_number", ban.BanId },
{ "identifier", ban.Identifier },
{ "reason", ban.Reason },
{ "banning_user", ban.BanningUser },
diff --git a/TShockAPI/Rest/SecureRest.cs b/TShockAPI/Rest/SecureRest.cs
index 5d785219e..1e4f2047e 100644
--- a/TShockAPI/Rest/SecureRest.cs
+++ b/TShockAPI/Rest/SecureRest.cs
@@ -22,7 +22,7 @@ You should have received a copy of the GNU General Public License
using System.Net;
using HttpServer;
using TShockAPI;
-using TShockAPI.DB;
+using TShockAPI.Database;
using Microsoft.Xna.Framework;
using Terraria;
using System.Security.Cryptography;
diff --git a/TShockAPI/SqlLog.cs b/TShockAPI/SqlLog.cs
deleted file mode 100644
index 3e79aaaba..000000000
--- a/TShockAPI/SqlLog.cs
+++ /dev/null
@@ -1,358 +0,0 @@
-/*
-TShock, a server mod for Terraria
-Copyright (C) 2011-2019 Pryaxis & TShock Contributors
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program. If not, see .
-*/
-
-using System;
-using System.Collections.Generic;
-using System.Data;
-using System.Diagnostics;
-using System.Globalization;
-using System.Linq;
-using MySql.Data.MySqlClient;
-using TShockAPI.DB;
-
-namespace TShockAPI
-{
- struct LogInfo
- {
- public string timestamp;
- public string message;
- public string caller;
- public TraceLevel logLevel;
-
- public override string ToString()
- {
- return GetString("Message: {0}: {1}: {2}",
- caller, logLevel.ToString().ToUpper(), message);
- }
- }
-
- ///
- /// Class inheriting ILog for writing logs to TShock's SQL database
- ///
- public class SqlLog : ILog, IDisposable
- {
- private readonly IDbConnection _database;
- private readonly TextLog _backupLog;
- private readonly List _failures = new List(TShock.Config.Settings.RevertToTextLogsOnSqlFailures);
- private bool _useTextLog;
-
- public string FileName { get; set; }
-
- ///
- /// Sets the database connection and the initial log level.
- ///
- /// Database connection
- /// File path to a backup text log in case the SQL log fails
- ///
- public SqlLog(IDbConnection db, string textlogFilepath, bool clearTextLog)
- {
- FileName = string.Format("{0}://database", db.GetSqlType());
- _database = db;
- _backupLog = new TextLog(textlogFilepath, clearTextLog);
-
- var table = new SqlTable("Logs",
- new SqlColumn("ID", MySqlDbType.Int32) {AutoIncrement = true, Primary = true},
- new SqlColumn("TimeStamp", MySqlDbType.Text),
- new SqlColumn("LogLevel", MySqlDbType.Int32),
- new SqlColumn("Caller", MySqlDbType.Text),
- new SqlColumn("Message", MySqlDbType.Text)
- );
-
- var creator = new SqlTableCreator(db,
- db.GetSqlType() == SqlType.Sqlite
- ? (IQueryBuilder) new SqliteQueryCreator()
- : new MysqlQueryCreator());
- creator.EnsureTableStructure(table);
- }
-
- public bool MayWriteType(TraceLevel type)
- {
- return type != TraceLevel.Off;
- }
-
- ///
- /// Writes data to the log file.
- ///
- /// The message to be written.
- public void Data(string message)
- {
- Write(message, TraceLevel.Verbose);
- }
-
- ///
- /// Writes data to the log file.
- ///
- /// The format of the message to be written.
- /// The format arguments.
- public void Data(string format, params object[] args)
- {
- Data(string.Format(format, args));
- }
-
- ///
- /// Writes an error to the log file.
- ///
- /// The message to be written.
- public void Error(string message)
- {
- Write(message, TraceLevel.Error);
- }
-
- ///
- /// Writes an error to the log file.
- ///
- /// The format of the message to be written.
- /// The format arguments.
- public void Error(string format, params object[] args)
- {
- Error(string.Format(format, args));
- }
-
- ///
- /// Writes an error to the log file.
- ///
- /// The message to be written.
- public void ConsoleError(string message)
- {
- Console.ForegroundColor = ConsoleColor.Red;
- Console.WriteLine(message);
- Console.ForegroundColor = ConsoleColor.Gray;
- Write(message, TraceLevel.Error);
- }
-
- ///
- /// Writes an error to the log file.
- ///
- /// The format of the message to be written.
- /// The format arguments.
- public void ConsoleError(string format, params object[] args)
- {
- ConsoleError(string.Format(format, args));
- }
-
- ///
- /// Writes an error to the log file.
- ///
- /// The message to be written.
- public void ConsoleWarn(string message)
- {
- Console.ForegroundColor = ConsoleColor.Yellow;
- Console.WriteLine(message);
- Console.ForegroundColor = ConsoleColor.Gray;
- Write(message, TraceLevel.Warning);
- }
-
- ///
- /// Writes an error to the log file.
- ///
- /// The format of the message to be written.
- /// The format arguments.
- public void ConsoleWarn(string format, params object[] args)
- {
- ConsoleWarn(string.Format(format, args));
- }
-
- ///
- /// Writes a warning to the log file.
- ///
- /// The message to be written.
- public void Warn(string message)
- {
- Write(message, TraceLevel.Warning);
- }
-
- ///
- /// Writes a warning to the log file.
- ///
- /// The format of the message to be written.
- /// The format arguments.
- public void Warn(string format, params object[] args)
- {
- Warn(string.Format(format, args));
- }
-
- ///
- /// Writes an informative string to the log file.
- ///
- /// The message to be written.
- public void Info(string message)
- {
- Write(message, TraceLevel.Info);
- }
-
- ///
- /// Writes an informative string to the log file.
- ///
- /// The format of the message to be written.
- /// The format arguments.
- public void Info(string format, params object[] args)
- {
- Info(string.Format(format, args));
- }
-
- ///
- /// Writes an informative string to the log file. Also outputs to the console.
- ///
- /// The message to be written.
- public void ConsoleInfo(string message)
- {
- Console.ForegroundColor = ConsoleColor.Yellow;
- Console.WriteLine(message);
- Console.ForegroundColor = ConsoleColor.Gray;
- Write(message, TraceLevel.Info);
- }
-
- ///
- /// Writes an informative string to the log file. Also outputs to the console.
- ///
- /// The format of the message to be written.
- /// The format arguments.
- public void ConsoleInfo(string format, params object[] args)
- {
- ConsoleInfo(string.Format(format, args));
- }
-
- ///
- /// Writes a debug string to the log file. Also outputs to the console. Requires config TShock.DebugLogs to be true.
- ///
- /// The message to be written.
- public void ConsoleDebug(string message)
- {
- if (TShock.Config.Settings.DebugLogs)
- {
- Console.WriteLine("Debug: " + message);
- Write(message, TraceLevel.Verbose);
- }
- }
-
- ///
- /// Writes a debug string to the log file. Also outputs to the console. Requires config TShock.DebugLogs to be true.
- ///
- /// The format of the message to be written.
- /// The format arguments.
- public void ConsoleDebug(string format, params object[] args)
- {
- ConsoleDebug(string.Format(format, args));
- }
-
- ///
- /// Writes a debug string to the log file.
- ///
- /// The message to be written.
- public void Debug(string message)
- {
- if (TShock.Config.Settings.DebugLogs)
- Write(message, TraceLevel.Verbose);
- }
-
- ///
- /// Writes a debug string to the log file.
- ///
- /// The format of the message to be written.
- /// The format arguments.
- public void Debug(string format, params object[] args)
- {
- if (TShock.Config.Settings.DebugLogs)
- Debug(string.Format(format, args));
- }
-
- public void Write(string message, TraceLevel 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 (TimeStamp, Caller, LogLevel, Message) VALUES (@0, @1, @2, @3)",
- DateTime.UtcNow.ToString("yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture), caller, (int)level, message);
-
- var success = true;
- while (_failures.Count > 0 && success)
- {
- var info = _failures.First();
-
- try
- {
- _database.Query("INSERT INTO Logs (TimeStamp, Caller, LogLevel, Message) VALUES (@0, @1, @2, @3)",
- info.timestamp, info.caller, (int)info.logLevel, info.message);
- }
- catch (Exception ex)
- {
- success = false;
- _failures.Add(new LogInfo
- {
- caller = "TShock",
- logLevel = TraceLevel.Error,
- message = GetString("SQL Log insert query failed: {0}", ex),
- timestamp = DateTime.UtcNow.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.UtcNow.ToString("yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture)
- });
- }
-
- if (_failures.Count >= TShock.Config.Settings.RevertToTextLogsOnSqlFailures)
- {
- _useTextLog = true;
- _backupLog.ConsoleError("SQL Logging disabled due to errors. Reverting to text logging.");
-
- foreach (var logInfo in _failures)
- {
- _backupLog.Write(GetString("SQL log failed at: {0}. {1}", logInfo.timestamp, logInfo),
- TraceLevel.Error);
- }
- _failures.Clear();
- }
- }
-
- public void Dispose()
- {
- _backupLog.Dispose();
- }
- }
-}
diff --git a/TShockAPI/TSPlayer.cs b/TShockAPI/TSPlayer.cs
index c9194c368..e7e9b7b41 100644
--- a/TShockAPI/TSPlayer.cs
+++ b/TShockAPI/TSPlayer.cs
@@ -29,7 +29,7 @@ You should have received a copy of the GNU General Public License
using Terraria.DataStructures;
using Terraria.ID;
using Terraria.Localization;
-using TShockAPI.DB;
+using TShockAPI.Database;
using TShockAPI.Hooks;
using TShockAPI.Net;
using Timer = System.Timers.Timer;
diff --git a/TShockAPI/TSServerPlayer.cs b/TShockAPI/TSServerPlayer.cs
index 6c95de78e..bc0aec19b 100644
--- a/TShockAPI/TSServerPlayer.cs
+++ b/TShockAPI/TSServerPlayer.cs
@@ -22,7 +22,7 @@ You should have received a copy of the GNU General Public License
using Terraria;
using Terraria.Utilities;
using TShockAPI;
-using TShockAPI.DB;
+using TShockAPI.Database;
using Terraria.Localization;
using System.Linq;
using Terraria.DataStructures;
diff --git a/TShockAPI/TShock.cs b/TShockAPI/TShock.cs
index 054e31dfa..0ee3a4332 100644
--- a/TShockAPI/TShock.cs
+++ b/TShockAPI/TShock.cs
@@ -35,7 +35,6 @@ You should have received a copy of the GNU General Public License
using Terraria.ID;
using Terraria.Localization;
using TerrariaApi.Server;
-using TShockAPI.DB;
using TShockAPI.Hooks;
using Terraria.Utilities;
using Microsoft.Xna.Framework;
@@ -45,11 +44,16 @@ You should have received a copy of the GNU General Public License
using TShockAPI.Configuration;
using Terraria.GameContent.Creative;
using System.Runtime.InteropServices;
+using System.Threading.Tasks;
+using MongoDB.Driver;
+using MongoDB.Entities;
using MonoMod.Cil;
using Terraria.Achievements;
using Terraria.Initializers;
using Terraria.UI.Chat;
+using TShockAPI.Database;
using TShockAPI.Modules;
+using ServerApi = TerrariaApi.Server.ServerApi;
namespace TShockAPI
{
@@ -62,20 +66,26 @@ public class TShock : TerrariaPlugin
{
/// VersionNum - The version number the TerrariaAPI will return back to the API. We just use the Assembly info.
public static readonly Version VersionNum = Assembly.GetExecutingAssembly().GetName().Version;
+
/// VersionCodename - The version codename is displayed when the server starts. Inspired by software codenames conventions.
public static readonly string VersionCodename = "Intensity";
/// SavePath - This is the path TShock saves its data in. This path is relative to the TerrariaServer.exe (not in ServerPlugins).
public static string SavePath = "tshock";
+
/// LogFormatDefault - This is the default log file naming format. Actually, this is the only log format, because it never gets set again.
private const string LogFormatDefault = "yyyy-MM-dd_HH-mm-ss";
+
//TODO: Set the log path in the config file.
/// LogFormat - This is the log format, which is never set again.
private static string LogFormat = LogFormatDefault;
+
/// LogPathDefault - The default log path.
private const string LogPathDefault = "tshock/logs";
+
/// This is the log path, which is initially set to the default log path, and then to the config file log path later.
private static string LogPath = LogPathDefault;
+
/// LogClear - Determines whether or not the log file should be cleared on initialization.
private static bool LogClear;
@@ -84,58 +94,80 @@ public class TShock : TerrariaPlugin
/// Players - Contains all TSPlayer objects for accessing TSPlayers currently on the server
public static TSPlayer[] Players = new TSPlayer[Main.maxPlayers];
+
/// Bans - Static reference to the ban manager for accessing bans & related functions.
public static BanManager Bans;
+
/// Warps - Static reference to the warp manager for accessing the warp system.
public static WarpManager Warps;
+
/// Regions - Static reference to the region manager for accessing the region system.
public static RegionManager Regions;
+
/// Backups - Static reference to the backup manager for accessing the backup system.
public static BackupManager Backups;
+
/// Groups - Static reference to the group manager for accessing the group system.
public static GroupManager Groups;
+
/// Users - Static reference to the user manager for accessing the user database system.
public static UserAccountManager UserAccounts;
+
/// ProjectileBans - Static reference to the projectile ban system.
- public static ProjectileManagager ProjectileBans;
+ public static ProjectileManager ProjectileBans;
+
/// TileBans - Static reference to the tile ban system.
public static TileManager TileBans;
+
/// RememberedPos - Static reference to the remembered position manager.
public static RememberedPosManager RememberedPos;
+
/// CharacterDB - Static reference to the SSC character manager.
public static CharacterManager CharacterDB;
+
/// Contains the information about what research has been performed in Journey mode.
public static ResearchDatastore ResearchDatastore;
+
/// Config - Static reference to the config system, for accessing values set in users' config files.
public static TShockConfig Config { get; set; }
+
/// ServerSideCharacterConfig - Static reference to the server side character config, for accessing values set by users to modify SSC.
public static ServerSideConfig ServerSideCharacterConfig;
- /// DB - Static reference to the database.
- public static IDbConnection DB;
+
/// OverridePort - Determines if TShock should override the server port.
public static bool OverridePort;
+
/// Geo - Static reference to the GeoIP system which determines the location of an IP address.
public static GeoIPCountry Geo;
+
/// RestApi - Static reference to the Rest API authentication manager.
public static SecureRest RestApi;
+
/// RestManager - Static reference to the Rest API manager.
public static RestManager RestManager;
+
/// Utils - Static reference to the utilities class, which contains a variety of utility functions.
public static Utils Utils = Utils.Instance;
+
/// UpdateManager - Static reference to the update checker, which checks for updates and notifies server admins of updates.
public static UpdateManager UpdateManager;
+
/// Log - Static reference to the log system, which outputs to either SQL or a text file, depending on user config.
public static ILog Log;
+
/// instance - Static reference to the TerrariaPlugin instance.
public static TerrariaPlugin instance;
+
///
/// Static reference to a used for simple command-line parsing
///
public static CommandLineParser CliParser { get; } = new CommandLineParser();
+
///
/// Used for implementing REST Tokens prior to the REST system starting up.
///
- public static Dictionary RESTStartupTokens = new Dictionary();
+ public static Dictionary RESTStartupTokens =
+ new Dictionary();
/// The TShock anti-cheat/anti-exploit system.
internal Bouncer Bouncer;
@@ -166,21 +198,19 @@ public override Version Version
/// value - "TShock"
public override string Name
{
- get { return "TShock"; }
+ get { return "TShockModified"; }
}
/// Author - The author of the plugin.
- /// value - "The TShock Team"
public override string Author
{
- get { return "The TShock Team"; }
+ get { return "TSD"; }
}
/// Description - The plugin description.
- /// value - "The administration modification of the future."
public override string Description
{
- get { return "The administration modification of the future."; }
+ get { return "A modified version of TShock to fit the needs of TSD."; }
}
/// TShock - The constructor for the TShock plugin.
@@ -199,6 +229,7 @@ public TShock(Main game)
static Dictionary _nativeCache = new Dictionary();
+
static IntPtr ResolveNativeDep(string libraryName, Assembly assembly, DllImportSearchPath? searchPath)
{
if (_nativeCache.TryGetValue(libraryName, out IntPtr cached))
@@ -246,16 +277,35 @@ static IntPtr ResolveNativeDep(string libraryName, Assembly assembly, DllImportS
return handle;
}
+ public void CrashDueToError(Exception? ex = null)
+ {
+ void SafeError(string message)
+ {
+ if (Log is not null) Log.ConsoleError(message);
+ else Console.WriteLine(message);
+ }
+
+ ;
+
+ SafeError(GetString(
+ "TShock encountered a problem from which it cannot recover. The following message may help diagnose the problem."));
+ SafeError(GetString(
+ "Until the problem is resolved, TShock will not be able to start (and will crash on startup)."));
+ if (ex is not null)
+ {
+ SafeError(ex.ToString());
+ }
+
+ Environment.Exit(1);
+ }
+
/// Initialize - Called by the TerrariaServerAPI during initialization.
[SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands")]
- public override void Initialize()
+ public override async Task Initialize()
{
string logFilename;
- OTAPI.Hooks.Netplay.CreateTcpListener += (sender, args) =>
- {
- args.Result = new LinuxTcpSocket();
- };
+ OTAPI.Hooks.Netplay.CreateTcpListener += (sender, args) => { args.Result = new LinuxTcpSocket(); };
OTAPI.Hooks.NetMessage.PlayerAnnounce += (sender, args) =>
{
//TShock handles this
@@ -297,7 +347,10 @@ public override void Initialize()
}
catch (Exception ex)
{
- ServerApi.LogWriter.PluginWriteLine(this, GetString("Could not apply the given log path / log format, defaults will be used. Exception details:\n{0}", ex), TraceLevel.Error);
+ ServerApi.LogWriter.PluginWriteLine(this,
+ GetString(
+ "Could not apply the given log path / log format, defaults will be used. Exception details:\n{0}",
+ ex), TraceLevel.Error);
// Problem with the log path or format use the default
logFilename = Path.Combine(LogPathDefault, now.ToString(LogFormatDefault) + ".log");
@@ -311,45 +364,27 @@ public override void Initialize()
throw new Exception("Fatal TShock initialization exception. See inner exception for details.", ex);
}
- // Further exceptions are written to TShock's log from now on.
try
{
- if (Config.Settings.StorageType.ToLower() == "sqlite")
- {
- string sql = Path.Combine(SavePath, Config.Settings.SqliteDBPath);
- Directory.CreateDirectory(Path.GetDirectoryName(sql));
- DB = new Microsoft.Data.Sqlite.SqliteConnection(string.Format("Data Source={0}", sql));
- }
- else if (Config.Settings.StorageType.ToLower() == "mysql")
- {
- try
- {
- var hostport = Config.Settings.MySqlHost.Split(':');
- DB = new MySqlConnection();
- DB.ConnectionString =
- String.Format("Server={0}; Port={1}; Database={2}; Uid={3}; Pwd={4};",
- hostport[0],
- hostport.Length > 1 ? hostport[1] : "3306",
- Config.Settings.MySqlDbName,
- Config.Settings.MySqlUsername,
- Config.Settings.MySqlPassword
- );
- }
- catch (MySqlException ex)
- {
- ServerApi.LogWriter.PluginWriteLine(this, ex.ToString(), TraceLevel.Error);
- throw new Exception("MySql not setup correctly");
- }
- }
- else
+ if (string.IsNullOrWhiteSpace(Config.Settings.MongoConnectionString))
{
- throw new Exception("Invalid storage type");
+ throw new Exception("The mongo connection string was left empty!");
}
- if (Config.Settings.UseSqlLogs)
- Log = new SqlLog(DB, logFilename, LogClear);
- else
- Log = new TextLog(logFilename, LogClear);
+ var mongoConnectionSettings =
+ MongoClientSettings.FromConnectionString(Config.Settings.MongoConnectionString);
+
+ // attempt to make connection to global database
+ await DB.InitAsync(Config.Settings.DefaultGlobalDatabase, mongoConnectionSettings);
+
+ // attempt to make connection to local database
+ await DB.InitAsync(Config.Settings.LocalDatabase, mongoConnectionSettings);
+
+ // POSSIBLY REIMPLEMENT THIS LATER WITH MONGODB
+ /*if (Config.Settings.UseSqlLogs)
+ Log = new SqlLog(Database, logFilename, LogClear);
+ else*/
+ Log = new TextLog(logFilename, LogClear);
if (File.Exists(Path.Combine(SavePath, "tshock.pid")))
{
@@ -357,6 +392,7 @@ public override void Initialize()
"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));
@@ -366,36 +402,39 @@ public override void Initialize()
Backups = new BackupManager(Path.Combine(SavePath, "backups"));
Backups.KeepFor = Config.Settings.BackupKeepFor;
Backups.Interval = Config.Settings.BackupInterval;
- Bans = new BanManager(DB);
- Warps = new WarpManager(DB);
- Regions = new RegionManager(DB);
- UserAccounts = new UserAccountManager(DB);
- Groups = new GroupManager(DB);
- ProjectileBans = new ProjectileManagager(DB);
- TileBans = new TileManager(DB);
- RememberedPos = new RememberedPosManager(DB);
- CharacterDB = new CharacterManager(DB);
- ResearchDatastore = new ResearchDatastore(DB);
+ Bans = new BanManager();
+ Warps = new WarpManager();
+ Regions = new RegionManager();
+ UserAccounts = new UserAccountManager();
+ Groups = new GroupManager();
+ ProjectileBans = new ProjectileManager();
+ TileBans = new TileManager();
+ RememberedPos = new RememberedPosManager();
+ CharacterDB = new CharacterManager();
+ ResearchDatastore = new ResearchDatastore();
RestApi = new SecureRest(Netplay.ServerIP, Config.Settings.RestApiPort);
RestManager = new RestManager(RestApi);
RestManager.RegisterRestfulCommands();
Bouncer = new Bouncer();
RegionSystem = new RegionHandler(Regions);
- ItemBans = new ItemBans(this, DB);
+ ItemBans = new ItemBans(this);
- var geoippath = "GeoIP.dat";
- if (Config.Settings.EnableGeoIP && File.Exists(geoippath))
- Geo = new GeoIPCountry(geoippath);
+ var geoIpData = "GeoIP.dat";
+ if (Config.Settings.EnableGeoIP && File.Exists(geoIpData))
+ Geo = new GeoIPCountry(geoIpData);
+ // NOTE FROM AVERAGE: THIS MAY BE WORTH EXPLORING
// check if a custom tile provider is to be used
- switch(Config.Settings.WorldTileProvider?.ToLower())
+ switch (Config.Settings.WorldTileProvider?.ToLower())
{
case "heaptile":
- Log.ConsoleInfo(GetString($"Using {nameof(HeapTile)} for tile implementation"), TraceLevel.Info);
+ Log.ConsoleInfo(GetString($"Using {nameof(HeapTile)} for tile implementation"),
+ TraceLevel.Info);
Main.tile = new TileProvider();
break;
case "constileation":
- Log.ConsoleInfo(GetString($"Using {nameof(ConstileationProvider)} for tile implementation"), TraceLevel.Info);
+ Log.ConsoleInfo(GetString($"Using {nameof(ConstileationProvider)} for tile implementation"),
+ TraceLevel.Info);
Main.tile = new ConstileationProvider();
break;
}
@@ -479,20 +518,10 @@ public override void Initialize()
Log.ConsoleInfo(GetString("Welcome to TShock for Terraria!"));
Log.ConsoleInfo(GetString("TShock comes with no warranty & is free software."));
Log.ConsoleInfo(GetString("You can modify & distribute it under the terms of the GNU GPLv3."));
-
}
catch (Exception ex)
{
- // handle if Log was not initialised
- void SafeError(string message)
- {
- if (Log is not null) Log.ConsoleError(message);
- else Console.WriteLine(message);
- };
- SafeError(GetString("TShock encountered a problem from which it cannot recover. The following message may help diagnose the problem."));
- SafeError(GetString("Until the problem is resolved, TShock will not be able to start (and will crash on startup)."));
- SafeError(ex.ToString());
- Environment.Exit(1);
+ CrashDueToError(ex);
}
}
@@ -522,6 +551,7 @@ protected override void Dispose(bool disposing)
{
Geo.Dispose();
}
+
SaveManager.Instance.Dispose();
IL.Terraria.Initializers.AchievementInitializer.Load -= OnAchievementInitializerLoad;
@@ -561,6 +591,7 @@ protected override void Dispose(bool disposing)
RegionSystem.Dispose();
}
+
base.Dispose(disposing);
}
@@ -595,7 +626,7 @@ private void OnPlayerLogin(PlayerPostLoginEventArgs args)
args.Player.Account.KnownIps = JsonConvert.SerializeObject(KnownIps, Formatting.Indented);
UserAccounts.UpdateLogin(args.Player.Account);
- Bans.CheckBan(args.Player);
+ Bans.IsPlayerBanned(args.Player);
}
/// OnAccountDelete - Internal hook fired on account delete.
@@ -640,6 +671,7 @@ private void NetHooks_NameCollision(NameCollisionEventArgs args)
args.Handled = true;
return;
}
+
if (player.IsLoggedIn)
{
var ips = JsonConvert.DeserializeObject>(player.Account.KnownIps);
@@ -678,7 +710,8 @@ private void OnItemForceIntoChest(ForceItemIntoChestEventArgs args)
{
// After checking for protected regions, no further range checking is necessarily because the client packet only specifies the
// inventory slot to quick stack. The vanilla Terraria server itself determines what chests are close enough to the player.
- if (Config.Settings.RegionProtectChests && !Regions.CanBuild((int)args.WorldPosition.X, (int)args.WorldPosition.Y, tsplr))
+ if (Config.Settings.RegionProtectChests &&
+ !Regions.CanBuild((int)args.WorldPosition.X, (int)args.WorldPosition.Y, tsplr))
{
args.Handled = true;
return;
@@ -724,7 +757,7 @@ private void CurrentDomain_UnhandledException(object sender, UnhandledExceptionE
Log.Error(e.ExceptionObject.ToString());
if (e.ExceptionObject.ToString().Contains("Terraria.Netplay.ListenForClients") ||
- e.ExceptionObject.ToString().Contains("Terraria.Netplay.ServerLoop"))
+ e.ExceptionObject.ToString().Contains("Terraria.Netplay.ServerLoop"))
{
var sb = new List();
for (int i = 0; i < Netplay.Clients.Length; i++)
@@ -738,6 +771,7 @@ private void CurrentDomain_UnhandledException(object sender, UnhandledExceptionE
sb.Add("Tcp[" + i + "]");
}
}
+
Log.Error(string.Join(", ", sb));
}
@@ -763,6 +797,7 @@ private void ConsoleCancelHandler(object sender, ConsoleCancelEventArgs args)
System.Environment.Exit(1);
return;
}
+
// Cancel the default behavior
args.Cancel = true;
@@ -792,95 +827,95 @@ private void HandleCommandLine(string[] parms)
//Prepare the parser with all the flags available
CliParser
.AddFlag("-configpath", pathChecker)
- //The .After Action is run after the pathChecker Action
- .After(() =>
+ //The .After Action is run after the pathChecker Action
+ .After(() =>
+ {
+ SavePath = path ?? "tshock";
+ if (path != null)
{
- SavePath = path ?? "tshock";
- if (path != null)
- {
- ServerApi.LogWriter.PluginWriteLine(this, GetString("Config path has been set to {0}", path), TraceLevel.Info);
- }
- })
-
+ ServerApi.LogWriter.PluginWriteLine(this, GetString("Config path has been set to {0}", path),
+ TraceLevel.Info);
+ }
+ })
.AddFlag("-worldselectpath", pathChecker)
- .After(() =>
+ .After(() =>
+ {
+ if (path != null)
{
- if (path != null)
- {
- Main.WorldPath = path;
- ServerApi.LogWriter.PluginWriteLine(this, GetString("World path has been set to {0}", path), TraceLevel.Info);
- }
- })
-
+ Main.WorldPath = path;
+ ServerApi.LogWriter.PluginWriteLine(this, GetString("World path has been set to {0}", path),
+ TraceLevel.Info);
+ }
+ })
.AddFlag("-logpath", pathChecker)
- .After(() =>
+ .After(() =>
+ {
+ if (path != null)
{
- if (path != null)
- {
- LogPath = path;
- ServerApi.LogWriter.PluginWriteLine(this, GetString("Log path has been set to {0}", path), TraceLevel.Info);
- }
- })
-
+ LogPath = path;
+ ServerApi.LogWriter.PluginWriteLine(this, GetString("Log path has been set to {0}", path),
+ TraceLevel.Info);
+ }
+ })
.AddFlag("-logformat", (format) =>
+ {
+ if (!string.IsNullOrWhiteSpace(format))
{
- if (!string.IsNullOrWhiteSpace(format)) { LogFormat = format; }
- })
-
+ LogFormat = format;
+ }
+ })
.AddFlag("-config", (cfg) =>
+ {
+ if (!string.IsNullOrWhiteSpace(cfg))
{
- if (!string.IsNullOrWhiteSpace(cfg))
- {
- ServerApi.LogWriter.PluginWriteLine(this, GetString("Loading dedicated config file: {0}", cfg), TraceLevel.Verbose);
- Main.instance.LoadDedConfig(cfg);
- }
- })
-
+ ServerApi.LogWriter.PluginWriteLine(this, GetString("Loading dedicated config file: {0}", cfg),
+ TraceLevel.Verbose);
+ Main.instance.LoadDedConfig(cfg);
+ }
+ })
.AddFlag("-port", (p) =>
+ {
+ int port;
+ if (int.TryParse(p, out port))
{
- int port;
- if (int.TryParse(p, out port))
- {
- Netplay.ListenPort = port;
- ServerApi.LogWriter.PluginWriteLine(this, GetString("Listening on port {0}.", port), TraceLevel.Verbose);
- }
- })
-
+ Netplay.ListenPort = port;
+ ServerApi.LogWriter.PluginWriteLine(this, GetString("Listening on port {0}.", port),
+ TraceLevel.Verbose);
+ }
+ })
.AddFlag("-worldname", (world) =>
+ {
+ if (!string.IsNullOrWhiteSpace(world))
{
- if (!string.IsNullOrWhiteSpace(world))
- {
- Main.instance.SetWorldName(world);
- ServerApi.LogWriter.PluginWriteLine(this, GetString("World name will be overridden by: {0}", world), TraceLevel.Verbose);
- }
- })
-
+ Main.instance.SetWorldName(world);
+ ServerApi.LogWriter.PluginWriteLine(this,
+ GetString("World name will be overridden by: {0}", world), TraceLevel.Verbose);
+ }
+ })
.AddFlag("-ip", (ip) =>
+ {
+ IPAddress addr;
+ if (IPAddress.TryParse(ip, out addr))
{
- IPAddress addr;
- if (IPAddress.TryParse(ip, out addr))
- {
- Netplay.ServerIP = addr;
- ServerApi.LogWriter.PluginWriteLine(this, GetString("Listening on IP {0}.", addr), TraceLevel.Verbose);
- }
- else
- {
- // The server should not start up if this argument is invalid.
- throw new InvalidOperationException("Invalid value given for command line argument \"-ip\".");
- }
- })
-
+ Netplay.ServerIP = addr;
+ ServerApi.LogWriter.PluginWriteLine(this, GetString("Listening on IP {0}.", addr),
+ TraceLevel.Verbose);
+ }
+ else
+ {
+ // The server should not start up if this argument is invalid.
+ throw new InvalidOperationException("Invalid value given for command line argument \"-ip\".");
+ }
+ })
.AddFlag("-autocreate", (size) =>
+ {
+ if (!string.IsNullOrWhiteSpace(size))
{
- if (!string.IsNullOrWhiteSpace(size))
- {
- Main.instance.autoCreate(size);
- }
- })
-
+ Main.instance.autoCreate(size);
+ }
+ })
.AddFlag("-worldevil", (value) =>
{
-
int worldEvil;
switch (value.ToLower())
{
@@ -894,10 +929,13 @@ private void HandleCommandLine(string[] parms)
worldEvil = 1;
break;
default:
- throw new InvalidOperationException("Invalid value given for command line argument \"-worldevil\".");
+ throw new InvalidOperationException(
+ "Invalid value given for command line argument \"-worldevil\".");
}
- ServerApi.LogWriter.PluginWriteLine(this, GetString("New worlds will be generated with the {0} world evil type!", value), TraceLevel.Verbose);
+ ServerApi.LogWriter.PluginWriteLine(this,
+ GetString("New worlds will be generated with the {0} world evil type!", value),
+ TraceLevel.Verbose);
WorldGen.WorldGenParam_Evil = worldEvil;
})
@@ -921,30 +959,31 @@ public static void HandleCommandLinePostConfigLoad(string[] parms)
CliParser
.AddFlags(portSet, (p) =>
+ {
+ int port;
+ if (int.TryParse(p, out port))
{
- int port;
- if (int.TryParse(p, out port))
- {
- Netplay.ListenPort = port;
- Config.Settings.ServerPort = port;
- OverridePort = true;
- Log.ConsoleInfo(GetString("Port overridden by startup argument. Set to {0}", port));
- }
- })
+ Netplay.ListenPort = port;
+ Config.Settings.ServerPort = port;
+ OverridePort = true;
+ Log.ConsoleInfo(GetString("Port overridden by startup argument. Set to {0}", port));
+ }
+ })
.AddFlags(restTokenSet, (token) =>
- {
- RESTStartupTokens.Add(token, new SecureRest.TokenData { Username = "null", UserGroupName = "superadmin" });
- Console.WriteLine(GetString("Startup parameter overrode REST token."));
- })
+ {
+ RESTStartupTokens.Add(token,
+ new SecureRest.TokenData { Username = "null", UserGroupName = "superadmin" });
+ Console.WriteLine(GetString("Startup parameter overrode REST token."));
+ })
.AddFlags(restEnableSet, (e) =>
+ {
+ bool enabled;
+ if (bool.TryParse(e, out enabled))
{
- bool enabled;
- if (bool.TryParse(e, out enabled))
- {
- Config.Settings.RestApiEnabled = enabled;
- Console.WriteLine(GetString("Startup parameter overrode REST enable."));
- }
- })
+ Config.Settings.RestApiEnabled = enabled;
+ Console.WriteLine(GetString("Startup parameter overrode REST enable."));
+ }
+ })
.AddFlags(restPortSet, (p) =>
{
int restPort;
@@ -955,20 +994,22 @@ public static void HandleCommandLinePostConfigLoad(string[] parms)
}
})
.AddFlags(playerSet, (p) =>
+ {
+ int slots;
+ if (int.TryParse(p, out slots))
{
- int slots;
- if (int.TryParse(p, out slots))
- {
- Config.Settings.MaxSlots = slots;
- Console.WriteLine(GetString("Startup parameter overrode maximum player slot configuration value."));
- }
- });
+ Config.Settings.MaxSlots = slots;
+ Console.WriteLine(
+ GetString("Startup parameter overrode maximum player slot configuration value."));
+ }
+ });
CliParser.ParseFromSource(parms);
}
/// SetupToken - The auth token used by the setup system to grant temporary superadmin access to new admins.
public static int SetupToken = -1;
+
private string _cliPassword = null;
/// OnPostInit - Fired when the server loads a map, to perform world specific operations.
@@ -984,19 +1025,24 @@ private void OnPostInit(EventArgs args)
//CLI defined password overrides a config password
if (!string.IsNullOrEmpty(Config.Settings.ServerPassword))
{
- Log.ConsoleError(GetString("!!! The server password in config.json was overridden by the interactive prompt and will be ignored."));
+ Log.ConsoleError(GetString(
+ "!!! The server password in config.json was overridden by the interactive prompt and will be ignored."));
}
if (!Config.Settings.DisableUUIDLogin)
{
- Log.ConsoleError(GetString("!!! UUID login is enabled. If a user's UUID matches an account, the server password will be bypassed."));
- Log.ConsoleError(GetString("!!! > Set DisableUUIDLogin to true in the config file and /reload if this is a problem."));
+ Log.ConsoleError(GetString(
+ "!!! UUID login is enabled. If a user's UUID matches an account, the server password will be bypassed."));
+ Log.ConsoleError(GetString(
+ "!!! > Set DisableUUIDLogin to true in the config file and /reload if this is a problem."));
}
if (!Config.Settings.DisableLoginBeforeJoin)
{
- Log.ConsoleError(GetString("!!! Login before join is enabled. Existing accounts can login & the server password will be bypassed."));
- Log.ConsoleError(GetString("!!! > Set DisableLoginBeforeJoin to true in the config file and /reload if this is a problem."));
+ Log.ConsoleError(GetString(
+ "!!! Login before join is enabled. Existing accounts can login & the server password will be bypassed."));
+ Log.ConsoleError(GetString(
+ "!!! > Set DisableLoginBeforeJoin to true in the config file and /reload if this is a problem."));
}
_cliPassword = Netplay.ServerPassword;
@@ -1013,13 +1059,15 @@ private void OnPostInit(EventArgs args)
if (!Config.Settings.DisableLoginBeforeJoin)
{
- Log.ConsoleInfo(GetString("Login before join enabled. Users may be prompted for an account specific password instead of a server password on connect."));
+ Log.ConsoleInfo(GetString(
+ "Login before join enabled. Users may be prompted for an account specific password instead of a server password on connect."));
}
if (!Config.Settings.DisableUUIDLogin)
{
Log.ConsoleInfo(GetString("Login using UUID enabled. Users automatically login via UUID."));
- Log.ConsoleInfo(GetString("A malicious server can easily steal a user's UUID. You may consider turning this option off if you run a public server."));
+ Log.ConsoleInfo(GetString(
+ "A malicious server can easily steal a user's UUID. You may consider turning this option off if you run a public server."));
}
// Disable the auth system if "setup.lock" is present or a user account already exists
@@ -1029,8 +1077,10 @@ private void OnPostInit(EventArgs args)
if (File.Exists(Path.Combine(SavePath, "setup-code.txt")))
{
- Log.ConsoleInfo(GetString("An account has been detected in the user database, but setup-code.txt is still present."));
- Log.ConsoleInfo(GetString("TShock will now disable the initial setup system and remove setup-code.txt as it is no longer needed."));
+ Log.ConsoleInfo(GetString(
+ "An account has been detected in the user database, but setup-code.txt is still present."));
+ Log.ConsoleInfo(GetString(
+ "TShock will now disable the initial setup system and remove setup-code.txt as it is no longer needed."));
File.Delete(Path.Combine(SavePath, "setup-code.txt"));
}
@@ -1045,8 +1095,10 @@ private void OnPostInit(EventArgs args)
var r = new Random((int)DateTime.Now.ToBinary());
SetupToken = r.Next(100000, 10000000);
Console.ForegroundColor = ConsoleColor.Yellow;
- Console.WriteLine(GetString("To setup the server, join the game and type {0}setup {1}", Commands.Specifier, SetupToken));
- Console.WriteLine(GetString("This token will display until disabled by verification. ({0}setup)", Commands.Specifier));
+ Console.WriteLine(GetString("To setup the server, join the game and type {0}setup {1}",
+ Commands.Specifier, SetupToken));
+ Console.WriteLine(GetString("This token will display until disabled by verification. ({0}setup)",
+ Commands.Specifier));
Console.ResetColor();
File.WriteAllText(Path.Combine(SavePath, "setup-code.txt"), SetupToken.ToString());
}
@@ -1054,9 +1106,12 @@ private void OnPostInit(EventArgs args)
{
SetupToken = Convert.ToInt32(File.ReadAllText(Path.Combine(SavePath, "setup-code.txt")));
Console.ForegroundColor = ConsoleColor.Yellow;
- Console.WriteLine(GetString("TShock Notice: setup-code.txt is still present, and the code located in that file will be used."));
- Console.WriteLine(GetString("To setup the server, join the game and type {0}setup {1}", Commands.Specifier, SetupToken));
- Console.WriteLine(GetString("This token will display until disabled by verification. ({0}setup)", Commands.Specifier));
+ Console.WriteLine(GetString(
+ "TShock Notice: setup-code.txt is still present, and the code located in that file will be used."));
+ Console.WriteLine(GetString("To setup the server, join the game and type {0}setup {1}",
+ Commands.Specifier, SetupToken));
+ Console.WriteLine(GetString("This token will display until disabled by verification. ({0}setup)",
+ Commands.Specifier));
Console.ResetColor();
}
@@ -1100,17 +1155,18 @@ private void OnUpdate(EventArgs args)
LastCheck = DateTime.UtcNow;
}
- if (Main.ServerSideCharacter && (DateTime.UtcNow - LastSave).TotalMinutes >= ServerSideCharacterConfig.Settings.ServerSideCharacterSave)
+ if (Main.ServerSideCharacter && (DateTime.UtcNow - LastSave).TotalMinutes >=
+ ServerSideCharacterConfig.Settings.ServerSideCharacterSave)
{
foreach (TSPlayer player in Players)
{
// prevent null point exceptions
if (player != null && player.IsLoggedIn && !player.IsDisabledPendingTrashRemoval)
{
-
CharacterDB.InsertPlayerData(player);
}
}
+
LastSave = DateTime.UtcNow;
}
}
@@ -1118,7 +1174,9 @@ private void OnUpdate(EventArgs args)
/// OnSecondUpdate - Called effectively every second for all time based checks.
private void OnSecondUpdate()
{
- DisableFlags flags = Config.Settings.DisableSecondUpdateLogs ? DisableFlags.WriteToConsole : DisableFlags.WriteToLogAndConsole;
+ DisableFlags flags = Config.Settings.DisableSecondUpdateLogs
+ ? DisableFlags.WriteToConsole
+ : DisableFlags.WriteToLogAndConsole;
if (Config.Settings.ForceTime != "normal")
{
@@ -1146,6 +1204,7 @@ private void OnSecondUpdate()
player.TilesDestroyed.Clear();
}
}
+
if (player.TileKillThreshold > 0)
{
player.TileKillThreshold = 0;
@@ -1166,6 +1225,7 @@ private void OnSecondUpdate()
}
}
}
+
if (player.TilePlaceThreshold > 0)
{
player.TilePlaceThreshold = 0;
@@ -1174,7 +1234,8 @@ private void OnSecondUpdate()
if (player.RecentFuse > 0)
player.RecentFuse--;
- if ((Main.ServerSideCharacter) && (player.TPlayer.SpawnX > 0) && (player.sX != player.TPlayer.SpawnX))
+ if ((Main.ServerSideCharacter) && (player.TPlayer.SpawnX > 0) &&
+ (player.sX != player.TPlayer.SpawnX))
{
player.sX = player.TPlayer.SpawnX;
player.sY = player.TPlayer.SpawnY;
@@ -1204,6 +1265,7 @@ private void OnSecondUpdate()
{
player.Disable(GetString("Reached TileLiquid threshold"), flags);
}
+
if (player.TileLiquidThreshold > 0)
{
player.TileLiquidThreshold = 0;
@@ -1213,6 +1275,7 @@ private void OnSecondUpdate()
{
player.Disable(GetString("Reached projectile threshold"), flags);
}
+
if (player.ProjectileThreshold > 0)
{
player.ProjectileThreshold = 0;
@@ -1222,6 +1285,7 @@ private void OnSecondUpdate()
{
player.Disable(GetString("Reached paint threshold"), flags);
}
+
if (player.PaintThreshold > 0)
{
player.PaintThreshold = 0;
@@ -1231,6 +1295,7 @@ private void OnSecondUpdate()
{
player.Disable(GetString("Reached HealOtherPlayer threshold"), flags);
}
+
if (player.HealOtherThreshold > 0)
{
player.HealOtherThreshold = 0;
@@ -1294,13 +1359,13 @@ private void OnWorldGrassSpread(GrassSpreadEventArgs args)
private bool OnCreep(int tileType)
{
if (!Config.Settings.AllowCrimsonCreep && (tileType == TileID.Dirt || tileType == TileID.CrimsonGrass
- || TileID.Sets.Crimson[tileType]))
+ || TileID.Sets.Crimson[tileType]))
{
return false;
}
if (!Config.Settings.AllowCorruptionCreep && (tileType == TileID.Dirt || tileType == TileID.CorruptThorns
- || TileID.Sets.Corrupt[tileType]))
+ || TileID.Sets.Corrupt[tileType]))
{
return false;
}
@@ -1317,7 +1382,8 @@ private bool OnCreep(int tileType)
/// args - The StatueSpawnEventArgs object.
private void OnStatueSpawn(StatueSpawnEventArgs args)
{
- if (args.Within200 < Config.Settings.StatueSpawn200 && args.Within600 < Config.Settings.StatueSpawn600 && args.WorldWide < Config.Settings.StatueSpawnWorld)
+ if (args.Within200 < Config.Settings.StatueSpawn200 && args.Within600 < Config.Settings.StatueSpawn600 &&
+ args.WorldWide < Config.Settings.StatueSpawnWorld)
{
args.Handled = true;
}
@@ -1333,7 +1399,8 @@ private void OnConnect(ConnectEventArgs args)
{
if (ShuttingDown)
{
- NetMessage.SendData((int)PacketTypes.Disconnect, args.Who, -1, NetworkText.FromLiteral(GetString("Server is shutting down...")));
+ NetMessage.SendData((int)PacketTypes.Disconnect, args.Who, -1,
+ NetworkText.FromLiteral(GetString("Server is shutting down...")));
args.Handled = true;
return;
}
@@ -1368,6 +1435,7 @@ private void OnConnect(ConnectEventArgs args)
}
}
}
+
Players[args.Who] = player;
}
@@ -1384,12 +1452,14 @@ private void OnJoin(JoinEventArgs args)
if (Config.Settings.KickEmptyUUID && String.IsNullOrWhiteSpace(player.UUID))
{
- player.Kick(GetString("Your client sent a blank UUID. Configure it to send one or use a different client."), true, true, null, false);
+ player.Kick(
+ GetString("Your client sent a blank UUID. Configure it to send one or use a different client."),
+ true, true, null, false);
args.Handled = true;
return;
}
- Bans.CheckBan(player);
+ Bans.IsPlayerBanned(player);
}
/// OnLeave - Called when a player leaves the server.
@@ -1433,7 +1503,8 @@ private void OnLeave(LeaveEventArgs args)
Utils.Broadcast(GetString("{0} has left.", tsplr.Name), Color.Yellow);
Log.Info(GetString("{0} disconnected.", tsplr.Name));
- if (tsplr.IsLoggedIn && !tsplr.IsDisabledPendingTrashRemoval && Main.ServerSideCharacter && (!tsplr.Dead || tsplr.TPlayer.difficulty != 2))
+ if (tsplr.IsLoggedIn && !tsplr.IsDisabledPendingTrashRemoval && Main.ServerSideCharacter &&
+ (!tsplr.Dead || tsplr.TPlayer.difficulty != 2))
{
tsplr.PlayerData.CopyCharacter(tsplr);
CharacterDB.InsertPlayerData(tsplr);
@@ -1503,12 +1574,14 @@ private void OnChat(ServerChatEventArgs args)
{
text = item.Key.Value;
}
+
break;
}
}
- if ((text.StartsWith(Config.Settings.CommandSpecifier) || text.StartsWith(Config.Settings.CommandSilentSpecifier))
- && !string.IsNullOrWhiteSpace(text.Substring(1)))
+ if ((text.StartsWith(Config.Settings.CommandSpecifier) ||
+ text.StartsWith(Config.Settings.CommandSilentSpecifier))
+ && !string.IsNullOrWhiteSpace(text.Substring(1)))
{
try
{
@@ -1516,7 +1589,8 @@ private void OnChat(ServerChatEventArgs args)
if (!Commands.HandleCommand(tsplr, text))
{
// This is required in case anyone makes HandleCommand return false again
- tsplr.SendErrorMessage(GetString("Unable to parse command. Please contact an administrator for assistance."));
+ tsplr.SendErrorMessage(
+ GetString("Unable to parse command. Please contact an administrator for assistance."));
Log.ConsoleError(GetString("Unable to parse command '{0}' from player {1}."), text, tsplr.Name);
}
}
@@ -1539,8 +1613,9 @@ private void OnChat(ServerChatEventArgs args)
}
else if (!TShock.Config.Settings.EnableChatAboveHeads)
{
- text = String.Format(Config.Settings.ChatFormat, tsplr.Group.Name, tsplr.Group.Prefix, tsplr.Name, tsplr.Group.Suffix,
- args.Text);
+ text = String.Format(Config.Settings.ChatFormat, tsplr.Group.Name, tsplr.Group.Prefix, tsplr.Name,
+ tsplr.Group.Suffix,
+ args.Text);
//Invoke the PlayerChat hook. If this hook event is handled then we need to prevent sending the chat message
bool cancelChat = PlayerHooks.OnPlayerChat(tsplr, args.Text, ref text);
@@ -1557,9 +1632,11 @@ private void OnChat(ServerChatEventArgs args)
{
Player ply = Main.player[args.Who];
string name = ply.name;
- ply.name = String.Format(Config.Settings.ChatAboveHeadsFormat, tsplr.Group.Name, tsplr.Group.Prefix, tsplr.Name, tsplr.Group.Suffix);
+ ply.name = String.Format(Config.Settings.ChatAboveHeadsFormat, tsplr.Group.Name, tsplr.Group.Prefix,
+ tsplr.Name, tsplr.Group.Suffix);
//Update the player's name to format text nicely. This needs to be done because Terraria automatically formats messages against our will
- NetMessage.SendData((int)PacketTypes.PlayerInfo, -1, -1, NetworkText.FromLiteral(ply.name), args.Who, 0, 0, 0, 0);
+ NetMessage.SendData((int)PacketTypes.PlayerInfo, -1, -1, NetworkText.FromLiteral(ply.name),
+ args.Who, 0, 0, 0, 0);
//Give that poor player their name back :'c
ply.name = name;
@@ -1572,18 +1649,22 @@ private void OnChat(ServerChatEventArgs args)
}
//This netpacket is used to send chat text from the server to clients, in this case on behalf of a client
- Terraria.Net.NetPacket packet = Terraria.GameContent.NetModules.NetTextModule.SerializeServerMessage(
- NetworkText.FromLiteral(text), new Color(tsplr.Group.R, tsplr.Group.G, tsplr.Group.B), (byte)args.Who
- );
+ Terraria.Net.NetPacket packet =
+ Terraria.GameContent.NetModules.NetTextModule.SerializeServerMessage(
+ NetworkText.FromLiteral(text), new Color(tsplr.Group.R, tsplr.Group.G, tsplr.Group.B),
+ (byte)args.Who
+ );
//Broadcast to everyone except the player who sent the message.
//This is so that we can send them the same nicely formatted message that everyone else gets
Terraria.Net.NetManager.Instance.Broadcast(packet, args.Who);
//Reset their name
- NetMessage.SendData((int)PacketTypes.PlayerInfo, -1, -1, NetworkText.FromLiteral(name), args.Who, 0, 0, 0, 0);
+ NetMessage.SendData((int)PacketTypes.PlayerInfo, -1, -1, NetworkText.FromLiteral(name), args.Who, 0,
+ 0, 0, 0);
string msg = String.Format("<{0}> {1}",
- String.Format(Config.Settings.ChatAboveHeadsFormat, tsplr.Group.Name, tsplr.Group.Prefix, tsplr.Name, tsplr.Group.Suffix),
+ String.Format(Config.Settings.ChatAboveHeadsFormat, tsplr.Group.Name, tsplr.Group.Prefix,
+ tsplr.Name, tsplr.Group.Suffix),
text
);
@@ -1633,6 +1714,7 @@ private void ServerHooks_OnCommand(CommandEventArgs args)
{
Commands.HandleCommand(TSPlayer.Server, "/" + args.Command);
}
+
args.Handled = true;
}
@@ -1658,8 +1740,9 @@ private void OnGetData(GetDataEventArgs e)
return;
}
- if ((player.State < 10 || player.Dead) && (int)type > 12 && (int)type != 16 && (int)type != 42 && (int)type != 50 &&
- (int)type != 38 && (int)type != 21 && (int)type != 22 && type != PacketTypes.SyncLoadout)
+ if ((player.State < 10 || player.Dead) && (int)type > 12 && (int)type != 16 && (int)type != 42 &&
+ (int)type != 50 &&
+ (int)type != 38 && (int)type != 21 && (int)type != 22 && type != PacketTypes.SyncLoadout)
{
e.Handled = true;
return;
@@ -1670,6 +1753,7 @@ private void OnGetData(GetDataEventArgs e)
{
length = 0;
}
+
using (var data = new MemoryStream(e.Msg.readBuffer, e.Index, e.Length - 1))
{
// Exceptions are already handled
@@ -1693,15 +1777,15 @@ private void OnGreetPlayer(GreetPlayerEventArgs args)
if (Config.Settings.EnableGeoIP && TShock.Geo != null)
{
Log.Info(GetString("{0} ({1}) from '{2}' group from '{3}' joined. ({4}/{5})", player.Name, player.IP,
- player.Group.Name, player.Country, TShock.Utils.GetActivePlayerCount(),
- TShock.Config.Settings.MaxSlots));
+ player.Group.Name, player.Country, TShock.Utils.GetActivePlayerCount(),
+ TShock.Config.Settings.MaxSlots));
if (!player.SilentJoinInProgress)
Utils.Broadcast(GetString("{0} ({1}) has joined.", player.Name, player.Country), Color.Yellow);
}
else
{
Log.Info(GetString("{0} ({1}) from '{2}' group joined. ({3}/{4})", player.Name, player.IP,
- player.Group.Name, TShock.Utils.GetActivePlayerCount(), TShock.Config.Settings.MaxSlots));
+ player.Group.Name, TShock.Utils.GetActivePlayerCount(), TShock.Config.Settings.MaxSlots));
if (!player.SilentJoinInProgress)
Utils.Broadcast(GetString("{0} has joined.", player.Name), Color.Yellow);
}
@@ -1724,7 +1808,9 @@ private void OnGreetPlayer(GreetPlayerEventArgs args)
if (Main.ServerSideCharacter)
{
player.IsDisabledForSSC = true;
- player.SendErrorMessage(GetString("Server side characters is enabled! Please {0}register or {0}login to play!", Commands.Specifier));
+ player.SendErrorMessage(GetString(
+ "Server side characters is enabled! Please {0}register or {0}login to play!",
+ Commands.Specifier));
player.LoginHarassed = true;
}
else if (Config.Settings.RequireLogin)
@@ -1736,7 +1822,8 @@ private void OnGreetPlayer(GreetPlayerEventArgs args)
player.LastNetPosition = new Vector2(Main.spawnTileX * 16f, Main.spawnTileY * 16f);
- if (Config.Settings.RememberLeavePos && (RememberedPos.GetLeavePos(player.Name, player.IP) != Vector2.Zero) && !player.LoginHarassed)
+ if (Config.Settings.RememberLeavePos &&
+ (RememberedPos.GetLeavePos(player.Name, player.IP) != Vector2.Zero) && !player.LoginHarassed)
{
player.RPPending = 3;
player.SendInfoMessage(GetString("You will be teleported to your last known location..."));
@@ -1763,7 +1850,9 @@ private void NpcHooks_OnStrikeNpc(NpcStrikeEventArgs e)
private void OnProjectileSetDefaults(SetDefaultsEventArgs e)
{
//tombstone fix.
- if (e.Info == ProjectileID.Tombstone || (e.Info >= ProjectileID.GraveMarker && e.Info <= ProjectileID.Obelisk) || (e.Info >= ProjectileID.RichGravestone1 && e.Info <= ProjectileID.RichGravestone5))
+ if (e.Info == ProjectileID.Tombstone ||
+ (e.Info >= ProjectileID.GraveMarker && e.Info <= ProjectileID.Obelisk) ||
+ (e.Info >= ProjectileID.RichGravestone1 && e.Info <= ProjectileID.RichGravestone5))
if (Config.Settings.DisableTombstones)
e.Object.SetDefaults(0);
if (e.Info == ProjectileID.HappyBomb)
@@ -1795,7 +1884,8 @@ private void NetHooks_SendData(SendDataEventArgs e)
{
var projectile = Main.projectile[e.number];
if (projectile.active && projectile.owner >= 0 &&
- (GetDataHandlers.projectileCreatesLiquid.ContainsKey(projectile.type) || GetDataHandlers.projectileCreatesTile.ContainsKey(projectile.type)))
+ (GetDataHandlers.projectileCreatesLiquid.ContainsKey(projectile.type) ||
+ GetDataHandlers.projectileCreatesTile.ContainsKey(projectile.type)))
{
var player = Players[projectile.owner];
if (player != null)
@@ -1841,6 +1931,7 @@ public void OnConfigRead(ConfigFile file)
Backups.KeepFor = file.Settings.BackupKeepFor;
Backups.Interval = file.Settings.BackupInterval;
}
+
if (!OverridePort)
{
Netplay.ListenPort = file.Settings.ServerPort;
diff --git a/TShockAPI/TShockAPI.csproj b/TShockAPI/TShockAPI.csproj
index a37317092..f4beabedc 100644
--- a/TShockAPI/TShockAPI.csproj
+++ b/TShockAPI/TShockAPI.csproj
@@ -28,12 +28,15 @@
GPL-3.0-or-laterPryaxis & TShock ContributorsTShock is a toolbox for Terraria servers and communities.
- TShock
+ TShock
+ enable
+
+
diff --git a/TShockLauncher.Tests/GroupTests.cs b/TShockLauncher.Tests/GroupTests.cs
index 5eff651fa..99e362802 100644
--- a/TShockLauncher.Tests/GroupTests.cs
+++ b/TShockLauncher.Tests/GroupTests.cs
@@ -1,6 +1,6 @@
using NUnit.Framework;
using TShockAPI;
-using TShockAPI.DB;
+using TShockAPI.Database;
namespace TShockLauncher.Tests;
diff --git a/TShockLauncher.Tests/TestSetup.cs b/TShockLauncher.Tests/TestSetup.cs
index 016f26790..ec39de2da 100644
--- a/TShockLauncher.Tests/TestSetup.cs
+++ b/TShockLauncher.Tests/TestSetup.cs
@@ -23,6 +23,6 @@ public static void SetupTShock()
Lang.InitializeLegacyLocalization(); // TShockAPI.Localization will fail without preparing NPC names etc
var ts = new TShock(null); // prepares configs etc
- ts.Initialize(); // used to prepare tshocks own static variables, such as the TShock.DB instance
+ ts.Initialize(); // used to prepare tshocks own static variables, such as the TShock.Database instance
}
}
diff --git a/docs/changelog.md b/docs/changelog.md
index 035df8ada..ca88a35a7 100644
--- a/docs/changelog.md
+++ b/docs/changelog.md
@@ -90,6 +90,7 @@ Use past tense when adding new entries; sign your name off when you add or chang
* Added a property `TSPlayer.Hostile`, which gets pvp player mode. (@AgaSpace)
* Fixed typo in `/gbuff`. (@sgkoishi, #2955)
* Rewrote the `.dockerignore` file into a denylist. (@timschumi)
+* Fixed typo with class name `ProjectileManager`. (@renderbr)
## TShock 5.2
* An additional option `pvpwithnoteam` is added at `PvPMode` to enable PVP with no team. (@CelestialAnarchy, #2617, @ATFGK)