From 156df4777750ca3f4c8bd3d589924fb9c93cb20b Mon Sep 17 00:00:00 2001 From: DogooFalchion Date: Sun, 23 Oct 2016 18:10:30 -0400 Subject: [PATCH 1/3] Add mechanism to upload a specific PlayerData to a player. --- TShockAPI/DB/CharacterManager.cs | 102 +++++++++++++++++++++++++++++-- 1 file changed, 96 insertions(+), 6 deletions(-) diff --git a/TShockAPI/DB/CharacterManager.cs b/TShockAPI/DB/CharacterManager.cs index e2461205..57f28560 100755 --- a/TShockAPI/DB/CharacterManager.cs +++ b/TShockAPI/DB/CharacterManager.cs @@ -131,15 +131,15 @@ namespace TShockAPI.DB string initialItems = String.Join("~", items.Take(NetItem.MaxInventory)); try { - database.Query("INSERT INTO tsCharacter (Account, Health, MaxHealth, Mana, MaxMana, Inventory, spawnX, spawnY, questsCompleted) VALUES (@0, @1, @2, @3, @4, @5, @6, @7, @8);", + database.Query("INSERT INTO tsCharacter (Account, Health, MaxHealth, Mana, MaxMana, Inventory, spawnX, spawnY, questsCompleted) VALUES (@0, @1, @2, @3, @4, @5, @6, @7, @8);", user.ID, TShock.ServerSideCharacterConfig.StartingHealth, TShock.ServerSideCharacterConfig.StartingHealth, TShock.ServerSideCharacterConfig.StartingMana, - TShock.ServerSideCharacterConfig.StartingMana, - initialItems, - -1, - -1, + TShock.ServerSideCharacterConfig.StartingMana, + initialItems, + -1, + -1, 0); return true; } @@ -159,7 +159,7 @@ namespace TShockAPI.DB public bool InsertPlayerData(TSPlayer player) { PlayerData playerData = player.PlayerData; - + if (!player.IsLoggedIn) return false; @@ -219,5 +219,95 @@ namespace TShockAPI.DB return false; } + + /// + /// Inserts a specific PlayerData into the SSC table for a player. + /// + /// The player to store the data for. + /// The player data to store. + /// If the command succeeds. + public bool InsertSpecificPlayerData(TSPlayer player, PlayerData data) + { + PlayerData playerData = data; + + if (!player.IsLoggedIn) + return false; + + if (player.HasPermission(Permissions.bypassssc)) + { + TShock.Log.ConsoleInfo("Skipping SSC Backup for " + player.User.Name); // Debug code + return true; + } + + if (!GetPlayerData(player, player.User.ID).exists) + { + try + { + database.Query( + "INSERT INTO tsCharacter (Account, Health, MaxHealth, Mana, MaxMana, Inventory, extraSlot, spawnX, spawnY, skinVariant, hair, hairDye, hairColor, pantsColor, shirtColor, underShirtColor, shoeColor, hideVisuals, skinColor, eyeColor, questsCompleted) VALUES (@0, @1, @2, @3, @4, @5, @6, @7, @8, @9, @10, @11, @12, @13, @14, @15, @16, @17, @18, @19, @20);", + player.User.ID, + playerData.health, + playerData.maxHealth, + playerData.mana, + playerData.maxMana, + String.Join("~", playerData.inventory), + playerData.extraSlot, + playerData.spawnX, + playerData.spawnX, + playerData.skinVariant, + playerData.hair, + playerData.hairDye, + TShock.Utils.EncodeColor(playerData.hairColor), + TShock.Utils.EncodeColor(playerData.pantsColor), + TShock.Utils.EncodeColor(playerData.shirtColor), + TShock.Utils.EncodeColor(playerData.underShirtColor), + TShock.Utils.EncodeColor(playerData.shoeColor), + TShock.Utils.EncodeBoolArray(playerData.hideVisuals), + TShock.Utils.EncodeColor(playerData.skinColor), + TShock.Utils.EncodeColor(playerData.eyeColor), + playerData.questsCompleted); + return true; + } + catch (Exception ex) + { + TShock.Log.Error(ex.ToString()); + } + } + else + { + try + { + database.Query( + "UPDATE tsCharacter SET Health = @0, MaxHealth = @1, Mana = @2, MaxMana = @3, Inventory = @4, spawnX = @6, spawnY = @7, hair = @8, hairDye = @9, hairColor = @10, pantsColor = @11, shirtColor = @12, underShirtColor = @13, shoeColor = @14, hideVisuals = @15, skinColor = @16, eyeColor = @17, questsCompleted = @18, skinVariant = @19, extraSlot = @20 WHERE Account = @5;", + playerData.health, + playerData.maxHealth, + playerData.mana, + playerData.maxMana, + String.Join("~", playerData.inventory), + player.User.ID, + playerData.spawnX, + playerData.spawnX, + playerData.skinVariant, + playerData.hair, + playerData.hairDye, + TShock.Utils.EncodeColor(playerData.hairColor), + TShock.Utils.EncodeColor(playerData.pantsColor), + TShock.Utils.EncodeColor(playerData.shirtColor), + TShock.Utils.EncodeColor(playerData.underShirtColor), + TShock.Utils.EncodeColor(playerData.shoeColor), + TShock.Utils.EncodeBoolArray(playerData.hideVisuals), + TShock.Utils.EncodeColor(playerData.skinColor), + TShock.Utils.EncodeColor(playerData.eyeColor), + playerData.questsCompleted, + playerData.extraSlot ?? 0); + return true; + } + catch (Exception ex) + { + TShock.Log.Error(ex.ToString()); + } + } + return false; + } } } From f1ce158efd9e9120ae6e5cab9f2f8a96fcb77163 Mon Sep 17 00:00:00 2001 From: DogooFalchion Date: Sun, 23 Oct 2016 18:11:44 -0400 Subject: [PATCH 2/3] Implement logic to store the data of a player when they join, and allow for a command to be run that will upload that data in place of their existing SSC data. --- TShockAPI/Commands.cs | 17 +++++++++++++++++ TShockAPI/GetDataHandlers.cs | 2 ++ TShockAPI/Permissions.cs | 3 +++ TShockAPI/TSPlayer.cs | 29 +++++++++++++++++------------ 4 files changed, 39 insertions(+), 12 deletions(-) diff --git a/TShockAPI/Commands.cs b/TShockAPI/Commands.cs index 2fcfa3c7..25641be2 100755 --- a/TShockAPI/Commands.cs +++ b/TShockAPI/Commands.cs @@ -298,6 +298,11 @@ namespace TShockAPI { HelpText = "Saves all serverside characters." }); + add(new Command(Permissions.uploaddata, UploadJoinData, "uploadssc") + { + HelpText = "Upload the account information when you joined the server as your Server Side Character data.", + AllowServer = false + }); add(new Command(Permissions.settempgroup, TempGroup, "tempgroup") { HelpText = "Temporarily sets another player's group." @@ -1691,6 +1696,18 @@ namespace TShockAPI args.Player.SendSuccessMessage("SSC of player \"{0}\" has been overriden.", matchedPlayer.Name); } + private static void UploadJoinData(CommandArgs args) + { + if (TShock.CharacterDB.InsertSpecificPlayerData(args.Player, args.Player.DataWhenJoined)) { + args.Player.DataWhenJoined.RestoreCharacter(args.Player); + args.Player.SendSuccessMessage("Your Join Data has been uploaded to the server."); + } + else + { + args.Player.SendErrorMessage("Failed to upload your data, please find an admin."); + } + } + private static void ForceHalloween(CommandArgs args) { TShock.Config.ForceHalloween = !TShock.Config.ForceHalloween; diff --git a/TShockAPI/GetDataHandlers.cs b/TShockAPI/GetDataHandlers.cs index aae3839b..fd9ce50a 100755 --- a/TShockAPI/GetDataHandlers.cs +++ b/TShockAPI/GetDataHandlers.cs @@ -1506,6 +1506,8 @@ namespace TShockAPI private static bool HandleConnecting(GetDataHandlerArgs args) { var user = TShock.Users.GetUserByName(args.Player.Name); + args.Player.DataWhenJoined = new PlayerData(args.Player); + args.Player.DataWhenJoined.CopyCharacter(args.Player); if (user != null && !TShock.Config.DisableUUIDLogin) { diff --git a/TShockAPI/Permissions.cs b/TShockAPI/Permissions.cs index 7aaf6f86..fef9683d 100644 --- a/TShockAPI/Permissions.cs +++ b/TShockAPI/Permissions.cs @@ -88,6 +88,9 @@ namespace TShockAPI [Description("User can save all the players SSI state.")] public static readonly string savessc = "tshock.admin.savessi"; + [Description("User can upload their joined character data as SSC data.")] + public static readonly string uploaddata = "tshock.ssc.upload"; + [Description("User can elevate other users' groups temporarily.")] public static readonly string settempgroup = "tshock.admin.tempgroup"; diff --git a/TShockAPI/TSPlayer.cs b/TShockAPI/TSPlayer.cs index 5addd336..ca1660aa 100755 --- a/TShockAPI/TSPlayer.cs +++ b/TShockAPI/TSPlayer.cs @@ -73,7 +73,7 @@ namespace TShockAPI /// The amount of tiles that the player has killed in the last second. /// public int TileKillThreshold { get; set; } - + /// /// The amount of tiles the player has placed in the last second. /// @@ -113,10 +113,10 @@ namespace TShockAPI /// A system to delay Remembered Position Teleports a few seconds /// public int RPPending = 0; - + public int sX = -1; public int sY = -1; - + /// /// A queue of tiles destroyed by the player for reverting. /// @@ -145,7 +145,7 @@ namespace TShockAPI /// The player's temporary group. This overrides the user's actual group. /// public Group tempGroup = null; - + public Timer tempGroupTimer; private Group group = null; @@ -158,7 +158,7 @@ namespace TShockAPI public int Index { get; protected set; } /// - /// The last time the player changed their team or pvp status. + /// The last time the player changed their team or pvp status. /// public DateTime LastPvPTeamChange; @@ -175,7 +175,7 @@ namespace TShockAPI /// /// A list of command callbacks indexed by the command they need to do. /// - public Dictionary> AwaitingResponse; + public Dictionary> AwaitingResponse; public bool AwaitingName { get; set; } @@ -332,14 +332,14 @@ namespace TShockAPI /// Spawn protection message cool down. /// public long SPm = 1; - + /// /// Permission to build message cool down. /// public long BPm = 1; /// - /// The time in ms when the player has logged in. + /// The time in ms when the player has logged in. /// public long LoginMS; @@ -372,7 +372,7 @@ namespace TShockAPI /// Contains data stored by plugins /// protected ConcurrentDictionary data = new ConcurrentDictionary(); - + /// /// Whether the player is a real, human, player on the server. /// @@ -591,6 +591,11 @@ namespace TShockAPI } } + /// + /// This contains the character data a player has when they join the server. + /// + public PlayerData DataWhenJoined { get; set; } + /// /// Determines whether the player's storage contains the given key. /// @@ -755,7 +760,7 @@ namespace TShockAPI /// Spawns the player at his spawn point. /// public void Spawn() - { + { if (this.sX > 0 && this.sY > 0) { Spawn(this.sX, this.sY); @@ -867,7 +872,7 @@ namespace TShockAPI /// True or false, depending if the item passed the check or not. public bool GiveItemCheck(int type, string name, int width, int height, int stack, int prefix = 0) { - if ((TShock.Itembans.ItemIsBanned(name) && TShock.Config.PreventBannedItemSpawn) && + if ((TShock.Itembans.ItemIsBanned(name) && TShock.Config.PreventBannedItemSpawn) && (TShock.Itembans.ItemIsBanned(name, this) || !TShock.Config.AllowAllowedGroupsToSpawnBannedItems)) return false; @@ -983,7 +988,7 @@ namespace TShockAPI } /// - /// Sends a message with the specified color. + /// Sends a message with the specified color. /// /// The message. /// The message color. From 49a0cc0cc50deeb28314e41a6aabf846c18b08a2 Mon Sep 17 00:00:00 2001 From: DogooFalchion Date: Sun, 23 Oct 2016 19:59:57 -0400 Subject: [PATCH 3/3] Add permission for uploading other's SSC data. Allow this to run from console. Allow command to upload remote user's data. --- TShockAPI/Commands.cs | 56 +++++++++++++++++++++++++++++++++++----- TShockAPI/Permissions.cs | 3 +++ 2 files changed, 53 insertions(+), 6 deletions(-) diff --git a/TShockAPI/Commands.cs b/TShockAPI/Commands.cs index 25641be2..846825fa 100755 --- a/TShockAPI/Commands.cs +++ b/TShockAPI/Commands.cs @@ -300,8 +300,7 @@ namespace TShockAPI }); add(new Command(Permissions.uploaddata, UploadJoinData, "uploadssc") { - HelpText = "Upload the account information when you joined the server as your Server Side Character data.", - AllowServer = false + HelpText = "Upload the account information when you joined the server as your Server Side Character data." }); add(new Command(Permissions.settempgroup, TempGroup, "tempgroup") { @@ -1698,13 +1697,58 @@ namespace TShockAPI private static void UploadJoinData(CommandArgs args) { - if (TShock.CharacterDB.InsertSpecificPlayerData(args.Player, args.Player.DataWhenJoined)) { - args.Player.DataWhenJoined.RestoreCharacter(args.Player); - args.Player.SendSuccessMessage("Your Join Data has been uploaded to the server."); + TSPlayer targetPlayer = args.Player; + if (args.Parameters.Count == 1 && args.Player.HasPermission(Permissions.uploadothersdata)) + { + List players = TShock.Utils.FindPlayer(args.Parameters[0]); + if (players.Count > 1) + { + TShock.Utils.SendMultipleMatchError(args.Player, players.Select(p => p.Name)); + return; + } + else if (players.Count == 0) + { + args.Player.SendErrorMessage("No player was found matching'{0}'", args.Parameters[0]); + return; + } + else + { + targetPlayer = players[0]; + } + } + else if (args.Parameters.Count == 1) + { + args.Player.SendErrorMessage("You do not have permission to upload another player's data."); + return; + } + else if (args.Parameters.Count > 0) + { + args.Player.SendErrorMessage("Usage: /uploadssc [playername]"); + return; + } + else if (args.Parameters.Count == 0 && args.Player is TSServerPlayer) + { + args.Player.SendErrorMessage("A console can not upload their player data."); + args.Player.SendErrorMessage("Usage: /uploadssc [playername]"); + return; + } + + if (targetPlayer.IsLoggedIn) + { + if (TShock.CharacterDB.InsertSpecificPlayerData(targetPlayer, targetPlayer.DataWhenJoined)) + { + targetPlayer.DataWhenJoined.RestoreCharacter(targetPlayer); + targetPlayer.SendSuccessMessage("Your Join Data has been uploaded to the server."); + args.Player.SendSuccessMessage("The player's data was successfully uploaded."); + } + else + { + args.Player.SendErrorMessage("Failed to upload your data, are you logged in to an account?"); + } } else { - args.Player.SendErrorMessage("Failed to upload your data, please find an admin."); + args.Player.SendErrorMessage("The target player has not logged in yet."); } } diff --git a/TShockAPI/Permissions.cs b/TShockAPI/Permissions.cs index fef9683d..3d3734e4 100644 --- a/TShockAPI/Permissions.cs +++ b/TShockAPI/Permissions.cs @@ -91,6 +91,9 @@ namespace TShockAPI [Description("User can upload their joined character data as SSC data.")] public static readonly string uploaddata = "tshock.ssc.upload"; + [Description("User can upload other players join data to the SSC database.")] + public static readonly string uploadothersdata = "tshock.ssc.upload.others"; + [Description("User can elevate other users' groups temporarily.")] public static readonly string settempgroup = "tshock.admin.tempgroup";