Merge pull request #911 from WhiteXZ/general-devel
Adds a User object to TSPlayer
This commit is contained in:
commit
3a5b0b1b99
7 changed files with 99 additions and 92 deletions
|
|
@ -744,21 +744,21 @@ namespace TShockAPI
|
|||
bool usingUUID = false;
|
||||
if (args.Parameters.Count == 0 && !TShock.Config.DisableUUIDLogin)
|
||||
{
|
||||
if (Hooks.PlayerHooks.OnPlayerPreLogin(args.Player, args.Player.Name, ""))
|
||||
if (PlayerHooks.OnPlayerPreLogin(args.Player, args.Player.Name, ""))
|
||||
return;
|
||||
user = TShock.Users.GetUserByName(args.Player.Name);
|
||||
usingUUID = true;
|
||||
}
|
||||
else if (args.Parameters.Count == 1)
|
||||
{
|
||||
if (Hooks.PlayerHooks.OnPlayerPreLogin(args.Player, args.Player.Name, args.Parameters[0]))
|
||||
if (PlayerHooks.OnPlayerPreLogin(args.Player, args.Player.Name, args.Parameters[0]))
|
||||
return;
|
||||
user = TShock.Users.GetUserByName(args.Player.Name);
|
||||
password = args.Parameters[0];
|
||||
}
|
||||
else if (args.Parameters.Count == 2 && TShock.Config.AllowLoginAnyUsername)
|
||||
{
|
||||
if (Hooks.PlayerHooks.OnPlayerPreLogin(args.Player, args.Parameters[0], args.Parameters[1]))
|
||||
if (PlayerHooks.OnPlayerPreLogin(args.Player, args.Parameters[0], args.Parameters[1]))
|
||||
return;
|
||||
|
||||
user = TShock.Users.GetUserByName(args.Parameters[0]);
|
||||
|
|
@ -809,8 +809,7 @@ namespace TShockAPI
|
|||
|
||||
args.Player.Group = group;
|
||||
args.Player.tempGroup = null;
|
||||
args.Player.UserAccountName = user.Name;
|
||||
args.Player.UserID = TShock.Users.GetUserID(args.Player.UserAccountName);
|
||||
args.Player.User = user;
|
||||
args.Player.IsLoggedIn = true;
|
||||
args.Player.IgnoreActionsForInventory = "none";
|
||||
|
||||
|
|
@ -874,8 +873,7 @@ namespace TShockAPI
|
|||
{
|
||||
args.Player.tempGroupTimer.Stop();
|
||||
}
|
||||
args.Player.UserAccountName = null;
|
||||
args.Player.UserID = -1;
|
||||
args.Player.User = null;
|
||||
args.Player.IsLoggedIn = false;
|
||||
|
||||
args.Player.SendSuccessMessage("You have been successfully logged out of your account.");
|
||||
|
|
@ -887,19 +885,18 @@ namespace TShockAPI
|
|||
{
|
||||
if (args.Player.IsLoggedIn && args.Parameters.Count == 2)
|
||||
{
|
||||
var user = TShock.Users.GetUserByName(args.Player.UserAccountName);
|
||||
string password = args.Parameters[0];
|
||||
if (user.VerifyPassword(password))
|
||||
if (args.Player.User.VerifyPassword(password))
|
||||
{
|
||||
args.Player.SendSuccessMessage("You changed your password!");
|
||||
TShock.Users.SetUserPassword(user, args.Parameters[1]); // SetUserPassword will hash it for you.
|
||||
TShock.Log.ConsoleInfo(args.Player.IP + " named " + args.Player.Name + " changed the password of account " + user.Name + ".");
|
||||
TShock.Users.SetUserPassword(args.Player.User, args.Parameters[1]); // SetUserPassword will hash it for you.
|
||||
TShock.Log.ConsoleInfo(args.Player.IP + " named " + args.Player.Name + " changed the password of account " + args.Player.User.Name + ".");
|
||||
}
|
||||
else
|
||||
{
|
||||
args.Player.SendErrorMessage("You failed to change your password!");
|
||||
TShock.Log.ConsoleError(args.Player.IP + " named " + args.Player.Name + " failed to change password for account: " +
|
||||
user.Name + ".");
|
||||
args.Player.User.Name + ".");
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
@ -1150,7 +1147,7 @@ namespace TShockAPI
|
|||
}
|
||||
try
|
||||
{
|
||||
args.Player.SendSuccessMessage("IP Address: " + players[0].IP + " Logged in as: " + players[0].UserAccountName + " group: " + players[0].Group.Name);
|
||||
args.Player.SendSuccessMessage("IP Address: " + players[0].IP + " Logged in as: " + players[0].User.Name + " group: " + players[0].Group.Name);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
|
|
@ -1227,8 +1224,8 @@ namespace TShockAPI
|
|||
else
|
||||
{
|
||||
var knownIps = JsonConvert.DeserializeObject<List<string>>(user.KnownIps);
|
||||
TShock.Bans.AddBan(knownIps.Last(), user.Name, user.UUID, reason, false, args.Player.UserAccountName);
|
||||
if (String.IsNullOrWhiteSpace(args.Player.UserAccountName))
|
||||
TShock.Bans.AddBan(knownIps.Last(), user.Name, user.UUID, reason, false, args.Player.User.Name);
|
||||
if (String.IsNullOrWhiteSpace(args.Player.User.Name))
|
||||
{
|
||||
if (args.Silent)
|
||||
{
|
||||
|
|
@ -1259,7 +1256,7 @@ namespace TShockAPI
|
|||
TShock.Utils.SendMultipleMatchError(args.Player, players.Select(p => p.Name));
|
||||
else
|
||||
{
|
||||
if (!TShock.Utils.Ban(players[0], reason, !args.Player.RealPlayer, args.Player.UserAccountName))
|
||||
if (!TShock.Utils.Ban(players[0], reason, !args.Player.RealPlayer, args.Player.User.Name))
|
||||
args.Player.SendErrorMessage("You can't ban {0}!", players[0].Name);
|
||||
}
|
||||
}
|
||||
|
|
@ -1278,7 +1275,7 @@ namespace TShockAPI
|
|||
string reason = args.Parameters.Count > 2
|
||||
? String.Join(" ", args.Parameters.GetRange(2, args.Parameters.Count - 2))
|
||||
: "Manually added IP address ban.";
|
||||
TShock.Bans.AddBan(ip, "", "", reason, false, args.Player.UserAccountName);
|
||||
TShock.Bans.AddBan(ip, "", "", reason, false, args.Player.User.Name);
|
||||
args.Player.SendSuccessMessage("Banned IP {0}.", ip);
|
||||
}
|
||||
#endregion
|
||||
|
|
@ -1316,8 +1313,8 @@ namespace TShockAPI
|
|||
else
|
||||
{
|
||||
var knownIps = JsonConvert.DeserializeObject<List<string>>(user.KnownIps);
|
||||
TShock.Bans.AddBan(knownIps.Last(), user.Name, user.UUID, reason, false, args.Player.UserAccountName, DateTime.UtcNow.AddSeconds(time).ToString("s"));
|
||||
if (String.IsNullOrWhiteSpace(args.Player.UserAccountName))
|
||||
TShock.Bans.AddBan(knownIps.Last(), user.Name, user.UUID, reason, false, args.Player.User.Name, DateTime.UtcNow.AddSeconds(time).ToString("s"));
|
||||
if (String.IsNullOrWhiteSpace(args.Player.User.Name))
|
||||
{
|
||||
if (args.Silent)
|
||||
{
|
||||
|
|
@ -1636,7 +1633,7 @@ namespace TShockAPI
|
|||
|
||||
if (ply.Count > 1)
|
||||
{
|
||||
TShock.Utils.SendMultipleMatchError(args.Player, ply.Select(p => p.UserAccountName));
|
||||
TShock.Utils.SendMultipleMatchError(args.Player, ply.Select(p => p.User.Name));
|
||||
}
|
||||
|
||||
if(!TShock.Groups.GroupExists(args.Parameters[1]))
|
||||
|
|
@ -3872,7 +3869,7 @@ namespace TShockAPI
|
|||
var width = Math.Abs(args.Player.TempPoints[0].X - args.Player.TempPoints[1].X);
|
||||
var height = Math.Abs(args.Player.TempPoints[0].Y - args.Player.TempPoints[1].Y);
|
||||
|
||||
if (TShock.Regions.AddRegion(x, y, width, height, regionName, args.Player.UserAccountName,
|
||||
if (TShock.Regions.AddRegion(x, y, width, height, regionName, args.Player.User.Name,
|
||||
Main.worldID.ToString()))
|
||||
{
|
||||
args.Player.TempPoints[0] = Point.Zero;
|
||||
|
|
|
|||
|
|
@ -615,7 +615,7 @@ namespace TShockAPI.DB
|
|||
return true;
|
||||
}
|
||||
|
||||
return AllowedIDs.Contains(ply.UserID) || AllowedGroups.Contains(ply.Group.Name) || Owner == ply.UserAccountName;
|
||||
return AllowedIDs.Contains(ply.User.ID) || AllowedGroups.Contains(ply.Group.Name) || Owner == ply.User.Name;
|
||||
}
|
||||
|
||||
public void setAllowedIDs(String ids)
|
||||
|
|
|
|||
|
|
@ -167,7 +167,7 @@ namespace TShockAPI.DB
|
|||
throw new UserNotExistException(user.Name);
|
||||
|
||||
// Update player group reference for any logged in player
|
||||
foreach (var player in TShock.Players.Where(p => null != p && p.UserAccountName == user.Name))
|
||||
foreach (var player in TShock.Players.Where(p => null != p && p.User.Name == user.Name))
|
||||
{
|
||||
player.Group = grp;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1464,8 +1464,7 @@ namespace TShockAPI
|
|||
|
||||
args.Player.Group = group;
|
||||
args.Player.tempGroup = null;
|
||||
args.Player.UserAccountName = args.Player.Name;
|
||||
args.Player.UserID = TShock.Users.GetUserID(args.Player.UserAccountName);
|
||||
args.Player.User = user;
|
||||
args.Player.IsLoggedIn = true;
|
||||
args.Player.IgnoreActionsForInventory = "none";
|
||||
|
||||
|
|
@ -1506,55 +1505,54 @@ namespace TShockAPI
|
|||
|
||||
string password = args.Data.ReadString();
|
||||
|
||||
if (Hooks.PlayerHooks.OnPlayerPreLogin(args.Player, args.Player.Name, password))
|
||||
return true;
|
||||
if (Hooks.PlayerHooks.OnPlayerPreLogin(args.Player, args.Player.Name, password))
|
||||
return true;
|
||||
|
||||
var user = TShock.Users.GetUserByName(args.Player.Name);
|
||||
if (user != null && !TShock.Config.DisableLoginBeforeJoin)
|
||||
if (user != null && !TShock.Config.DisableLoginBeforeJoin)
|
||||
{
|
||||
if (user.VerifyPassword(password))
|
||||
{
|
||||
args.Player.RequiresPassword = false;
|
||||
args.Player.PlayerData = TShock.CharacterDB.GetPlayerData(args.Player, TShock.Users.GetUserID(args.Player.Name));
|
||||
args.Player.RequiresPassword = false;
|
||||
args.Player.PlayerData = TShock.CharacterDB.GetPlayerData(args.Player, TShock.Users.GetUserID(args.Player.Name));
|
||||
|
||||
if (args.Player.State == 1)
|
||||
args.Player.State = 2;
|
||||
NetMessage.SendData((int) PacketTypes.WorldInfo, args.Player.Index);
|
||||
if (args.Player.State == 1)
|
||||
args.Player.State = 2;
|
||||
NetMessage.SendData((int) PacketTypes.WorldInfo, args.Player.Index);
|
||||
|
||||
var group = TShock.Utils.GetGroup(user.Group);
|
||||
var group = TShock.Utils.GetGroup(user.Group);
|
||||
|
||||
if (Main.ServerSideCharacter)
|
||||
if (Main.ServerSideCharacter)
|
||||
{
|
||||
if (group.HasPermission(Permissions.bypassssc))
|
||||
{
|
||||
if (group.HasPermission(Permissions.bypassssc))
|
||||
{
|
||||
args.Player.IgnoreActionsForClearingTrashCan = false;
|
||||
}
|
||||
args.Player.PlayerData.RestoreCharacter(args.Player);
|
||||
args.Player.IgnoreActionsForClearingTrashCan = false;
|
||||
}
|
||||
args.Player.PlayerData.RestoreCharacter(args.Player);
|
||||
}
|
||||
args.Player.LoginFailsBySsi = false;
|
||||
|
||||
if (group.HasPermission(Permissions.ignorestackhackdetection))
|
||||
args.Player.IgnoreActionsForCheating = "none";
|
||||
if (group.HasPermission(Permissions.ignorestackhackdetection))
|
||||
args.Player.IgnoreActionsForCheating = "none";
|
||||
|
||||
if (group.HasPermission(Permissions.usebanneditem))
|
||||
args.Player.IgnoreActionsForDisabledArmor = "none";
|
||||
if (group.HasPermission(Permissions.usebanneditem))
|
||||
args.Player.IgnoreActionsForDisabledArmor = "none";
|
||||
|
||||
args.Player.Group = group;
|
||||
args.Player.tempGroup = null;
|
||||
args.Player.UserAccountName = args.Player.Name;
|
||||
args.Player.UserID = TShock.Users.GetUserID(args.Player.UserAccountName);
|
||||
args.Player.IsLoggedIn = true;
|
||||
args.Player.IgnoreActionsForInventory = "none";
|
||||
args.Player.Group = group;
|
||||
args.Player.tempGroup = null;
|
||||
args.Player.User = user;
|
||||
args.Player.IsLoggedIn = true;
|
||||
args.Player.IgnoreActionsForInventory = "none";
|
||||
|
||||
if (!args.Player.IgnoreActionsForClearingTrashCan && Main.ServerSideCharacter)
|
||||
{
|
||||
args.Player.PlayerData.CopyCharacter(args.Player);
|
||||
TShock.CharacterDB.InsertPlayerData(args.Player);
|
||||
}
|
||||
args.Player.SendMessage("Authenticated as " + args.Player.Name + " successfully.", Color.LimeGreen);
|
||||
if (!args.Player.IgnoreActionsForClearingTrashCan && Main.ServerSideCharacter)
|
||||
{
|
||||
args.Player.PlayerData.CopyCharacter(args.Player);
|
||||
TShock.CharacterDB.InsertPlayerData(args.Player);
|
||||
}
|
||||
args.Player.SendMessage("Authenticated as " + args.Player.Name + " successfully.", Color.LimeGreen);
|
||||
TShock.Log.ConsoleInfo(args.Player.Name + " authenticated successfully as user " + args.Player.Name + ".");
|
||||
TShock.Users.SetUserUUID(user, args.Player.UUID);
|
||||
Hooks.PlayerHooks.OnPlayerPostLogin(args.Player);
|
||||
Hooks.PlayerHooks.OnPlayerPostLogin(args.Player);
|
||||
return true;
|
||||
}
|
||||
TShock.Utils.ForceKick(args.Player, "Invalid user account password.", true);
|
||||
|
|
@ -2618,10 +2616,9 @@ namespace TShockAPI
|
|||
|
||||
if (args.TPlayer.difficulty == 2 && Main.ServerSideCharacter && args.Player.IsLoggedIn)
|
||||
{
|
||||
User user = TShock.Users.GetUserByName(args.Player.UserAccountName);
|
||||
if (TShock.CharacterDB.RemovePlayer(user.ID))
|
||||
if (TShock.CharacterDB.RemovePlayer(args.Player.User.ID))
|
||||
{
|
||||
TShock.CharacterDB.SeedInitialData(user);
|
||||
TShock.CharacterDB.SeedInitialData(args.Player.User);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -394,7 +394,7 @@ namespace TShockAPI
|
|||
[Token]
|
||||
private object UserActiveListV2(RestRequestArgs args)
|
||||
{
|
||||
return new RestObject() { { "activeusers", string.Join("\t", TShock.Players.Where(p => null != p && null != p.UserAccountName && p.Active).Select(p => p.UserAccountName)) } };
|
||||
return new RestObject() { { "activeusers", string.Join("\t", TShock.Players.Where(p => null != p && null != p.User && p.Active).Select(p => p.User.Name)) } };
|
||||
}
|
||||
|
||||
[Description("Lists all user accounts in the TShock database.")]
|
||||
|
|
@ -807,7 +807,7 @@ namespace TShockAPI
|
|||
return new RestObject()
|
||||
{
|
||||
{"nickname", player.Name},
|
||||
{"username", null == player.UserAccountName ? "" : player.UserAccountName},
|
||||
{"username", null == player.User ? "" : player.User.Name},
|
||||
{"ip", player.IP},
|
||||
{"group", player.Group.Name},
|
||||
{"position", player.TileX + "," + player.TileY},
|
||||
|
|
@ -834,7 +834,7 @@ namespace TShockAPI
|
|||
return new RestObject()
|
||||
{
|
||||
{"nickname", player.Name},
|
||||
{"username", null == player.UserAccountName ? "" : player.UserAccountName},
|
||||
{"username", null == player.User ? "" : player.User.Name},
|
||||
{"ip", player.IP},
|
||||
{"group", player.Group.Name},
|
||||
{"position", player.TileX + "," + player.TileY},
|
||||
|
|
@ -1214,7 +1214,7 @@ namespace TShockAPI
|
|||
var player = new Dictionary<string, object>
|
||||
{
|
||||
{"nickname", tsPlayer.Name},
|
||||
{"username", tsPlayer.UserAccountName ?? ""},
|
||||
{"username", tsPlayer.User == null ? "" : tsPlayer.User.Name},
|
||||
{"group", tsPlayer.Group.Name},
|
||||
{"active", tsPlayer.Active},
|
||||
{"state", tsPlayer.State},
|
||||
|
|
|
|||
|
|
@ -178,7 +178,17 @@ namespace TShockAPI
|
|||
/// <summary>
|
||||
/// The player's login name.
|
||||
/// </summary>
|
||||
public string UserAccountName { get; set; }
|
||||
[Obsolete("Use User.Name instead")]
|
||||
public string UserAccountName
|
||||
{
|
||||
get { return User == null ? null : User.Name; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// User object associated with the player.
|
||||
/// Set when the player logs in.
|
||||
/// </summary>
|
||||
public User User { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Whether the player performed a valid login attempt (i.e. entered valid user name and password) but is still blocked
|
||||
|
|
@ -199,7 +209,11 @@ namespace TShockAPI
|
|||
/// <summary>
|
||||
/// The player's user id( from the db ).
|
||||
/// </summary>
|
||||
public int UserID = -1;
|
||||
[Obsolete("Use User.ID instead")]
|
||||
public int UserID
|
||||
{
|
||||
get { return User == null ? -1 : User.ID; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Whether the player has been nagged about logging in.
|
||||
|
|
@ -903,12 +917,13 @@ namespace TShockAPI
|
|||
|
||||
public class TSServerPlayer : TSPlayer
|
||||
{
|
||||
public static string AccountName = "ServerConsole";
|
||||
public static string AccountName = "ServerConsole";
|
||||
|
||||
public TSServerPlayer()
|
||||
: base("Server")
|
||||
{
|
||||
Group = new SuperAdminGroup();
|
||||
UserAccountName = AccountName;
|
||||
User = new User{Name = AccountName};
|
||||
}
|
||||
|
||||
public override void SendErrorMessage(string msg)
|
||||
|
|
|
|||
|
|
@ -389,13 +389,12 @@ namespace TShockAPI
|
|||
|
||||
/// <summary>OnPlayerLogin - Fires the PlayerLogin hook to listening plugins.</summary>
|
||||
/// <param name="args">args - The PlayerPostLoginEventArgs object.</param>
|
||||
private void OnPlayerLogin(Hooks.PlayerPostLoginEventArgs args)
|
||||
private void OnPlayerLogin(PlayerPostLoginEventArgs args)
|
||||
{
|
||||
User u = Users.GetUserByName(args.Player.UserAccountName);
|
||||
List<String> KnownIps = new List<string>();
|
||||
if (!string.IsNullOrWhiteSpace(u.KnownIps))
|
||||
if (!string.IsNullOrWhiteSpace(args.Player.User.KnownIps))
|
||||
{
|
||||
KnownIps = JsonConvert.DeserializeObject<List<String>>(u.KnownIps);
|
||||
KnownIps = JsonConvert.DeserializeObject<List<String>>(args.Player.User.KnownIps);
|
||||
}
|
||||
|
||||
bool found = KnownIps.Any(s => s.Equals(args.Player.IP));
|
||||
|
|
@ -409,8 +408,8 @@ namespace TShockAPI
|
|||
KnownIps.Add(args.Player.IP);
|
||||
}
|
||||
|
||||
u.KnownIps = JsonConvert.SerializeObject(KnownIps, Formatting.Indented);
|
||||
Users.UpdateLogin(u);
|
||||
args.Player.User.KnownIps = JsonConvert.SerializeObject(KnownIps, Formatting.Indented);
|
||||
Users.UpdateLogin(args.Player.User);
|
||||
}
|
||||
|
||||
/// <summary>OnAccountDelete - Internal hook fired on account delete.</summary>
|
||||
|
|
@ -445,9 +444,9 @@ namespace TShockAPI
|
|||
/// <param name="args">args - The NameCollisionEventArgs object.</param>
|
||||
private void NetHooks_NameCollision(NameCollisionEventArgs args)
|
||||
{
|
||||
string ip = TShock.Utils.GetRealIP(Netplay.serverSock[args.Who].tcpClient.Client.RemoteEndPoint.ToString());
|
||||
string ip = Utils.GetRealIP(Netplay.serverSock[args.Who].tcpClient.Client.RemoteEndPoint.ToString());
|
||||
|
||||
var player = TShock.Players.First(p => p != null && p.Name == args.Name && p.Index != args.Who);
|
||||
var player = Players.First(p => p != null && p.Name == args.Name && p.Index != args.Who);
|
||||
if (player != null)
|
||||
{
|
||||
if (player.IP == ip)
|
||||
|
|
@ -456,15 +455,13 @@ namespace TShockAPI
|
|||
args.Handled = true;
|
||||
return;
|
||||
}
|
||||
else if (player.IsLoggedIn)
|
||||
if (player.IsLoggedIn)
|
||||
{
|
||||
User user = TShock.Users.GetUserByName(player.UserAccountName);
|
||||
var ips = JsonConvert.DeserializeObject<List<string>>(user.KnownIps);
|
||||
var ips = JsonConvert.DeserializeObject<List<string>>(player.User.KnownIps);
|
||||
if (ips.Contains(ip))
|
||||
{
|
||||
Netplay.serverSock[player.Index].kill = true;
|
||||
args.Handled = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -472,20 +469,20 @@ namespace TShockAPI
|
|||
|
||||
/// <summary>OnXmasCheck - Internal hook fired when the XMasCheck happens.</summary>
|
||||
/// <param name="args">args - The ChristmasCheckEventArgs object.</param>
|
||||
private void OnXmasCheck(ChristmasCheckEventArgs args)
|
||||
{
|
||||
if (args.Handled)
|
||||
return;
|
||||
private void OnXmasCheck(ChristmasCheckEventArgs args)
|
||||
{
|
||||
if (args.Handled)
|
||||
return;
|
||||
|
||||
if(Config.ForceXmas)
|
||||
{
|
||||
args.Xmas = true;
|
||||
args.Handled = true;
|
||||
}
|
||||
}
|
||||
if (Config.ForceXmas)
|
||||
{
|
||||
args.Xmas = true;
|
||||
args.Handled = true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>OnHalloweenCheck - Internal hook fired when the HalloweenCheck happens.</summary>
|
||||
/// <param name="args">args - The HalloweenCheckEventArgs object.</param>
|
||||
/// <summary>OnHalloweenCheck - Internal hook fired when the HalloweenCheck happens.</summary>
|
||||
/// <param name="args">args - The HalloweenCheckEventArgs object.</param>
|
||||
private void OnHalloweenCheck(HalloweenCheckEventArgs args)
|
||||
{
|
||||
if (args.Handled)
|
||||
|
|
@ -497,6 +494,7 @@ namespace TShockAPI
|
|||
args.Handled = true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles exceptions that we didn't catch earlier in the code, or in Terraria.
|
||||
/// </summary>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue