diff --git a/CHANGELOG.md b/CHANGELOG.md index 9a433825a..05cc8a01c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,20 @@ This is the rolling changelog for TShock for Terraria. Use past tense when addin ## Upcoming Changes +## TShock 4.3.22 +* Compatibility with Terraria 1.3.4.4 +* API: Version tick 2.0 +* API: Reduced RAM usage by ~80MB (Large server) (@deathcradle) +* API: Added TSPlayer.KillPlayer() (@WhiteXZ) +* API: Added TSPlayer.Logout() (@ProfessorXZ) +* Fixed connections after max slot is reached (@DeathCradle) +* Fixed server crashes caused by client disconnections when attempting to read closed sockets (@Enerdy) +* Added some code to make trapdoors work better (@DogooFalchion) +* AllowCutTilesAndBreakables config option now correctly allows flowers/vines/herbs to be cut in regions without breaking walls (@WhiteXZ) +* REST: `/status` has been re-added. It will now always point to `/v2/server/status` and includes an `upgrade` field describing the newest status route (@WhiteXZ) +* REST: `/v3/players/read` now includes a `muted` field (@WhiteXZ) +* Fixed fishing quests not saving/loading correctly when login before join, UUID login, and SSC were enabled together (@DogooFalchion) + ## TShock 4.3.21 * Compatibility with Terraria 1.3.4.3 (@Patrikkk, @Zaicon). * API: Version tick 1.26. @@ -26,7 +40,6 @@ This is the rolling changelog for TShock for Terraria. Use past tense when addin * Added `/uploadssc [player]` which allows someone to upload SSC data for [player] and store it on the server. Adds `tshock.ssc.upload` and `tshock.ssc.upload.others` permission nodes to match (@DogooFalchion). * Added hardened stone to the whitelist of tiles editable by players (@DogooFalchion). * Added conversion system to send convert old MOTD format into smart text, while preserving initial line starting values to keep byte optimization for background colors Thanks to (@WhiteXZ, @Simon311, and especially @DogooFalchion) for the hard work on this issue. -* Fixed server-sided inventory issues caused by bank3 (@ProfessorXZ) ## TShock 4.3.20 * Security improvement: The auth system is now automatically disabled if a superadmin exists in the database (@Enerdy). diff --git a/TShockAPI/Commands.cs b/TShockAPI/Commands.cs index e6ee660a4..ba3655867 100644 --- a/TShockAPI/Commands.cs +++ b/TShockAPI/Commands.cs @@ -892,29 +892,7 @@ private static void Logout(CommandArgs args) return; } - PlayerHooks.OnPlayerLogout(args.Player); - - - if (Main.ServerSideCharacter) - { - args.Player.IgnoreActionsForInventory = String.Format("云端存档/强制开荒 模式. 请使用 {0}register \\ {0}login 加入游戏!", Commands.Specifier); - if (!args.Player.IgnoreActionsForClearingTrashCan && (!args.Player.Dead || args.Player.TPlayer.difficulty != 2)) - { - args.Player.PlayerData.CopyCharacter(args.Player); - TShock.CharacterDB.InsertPlayerData(args.Player); - } - } - - args.Player.PlayerData = new PlayerData(args.Player); - args.Player.Group = TShock.Groups.GetGroupByName(TShock.Config.DefaultGuestGroupName); - args.Player.tempGroup = null; - if (args.Player.tempGroupTimer != null) - { - args.Player.tempGroupTimer.Stop(); - } - args.Player.User = null; - args.Player.IsLoggedIn = false; - + args.Player.Logout(); args.Player.SendSuccessMessage("成功登出游戏."); if (Main.ServerSideCharacter) { @@ -1224,16 +1202,20 @@ private static void ViewAccountInfo(CommandArgs args) var user = TShock.Users.GetUserByName(username); if (user != null) { - DateTime LastSeen = DateTime.Parse(user.LastAccessed).ToLocalTime(); + DateTime LastSeen; string Timezone = TimeZone.CurrentTimeZone.GetUtcOffset(DateTime.Now).Hours.ToString("+#;-#"); - args.Player.SendSuccessMessage("{0} 的上次登录时间为 {1} {2} UTC{3}.", user.Name, LastSeen.ToShortDateString(), - LastSeen.ToShortTimeString(), Timezone); + if (DateTime.TryParse(user.LastAccessed, out LastSeen)) + { + LastSeen = DateTime.Parse(user.LastAccessed).ToLocalTime(); + args.Player.SendSuccessMessage("{0} 的上次登录时间为 {1} {2} UTC{3}.", user.Name, LastSeen.ToShortDateString(), + LastSeen.ToShortTimeString(), Timezone); + } if (args.Player.Group.HasPermission(Permissions.advaccountinfo)) { - List KnownIps = JsonConvert.DeserializeObject>(user.KnownIps); - string ip = KnownIps[KnownIps.Count - 1]; + List KnownIps = JsonConvert.DeserializeObject>(user.KnownIps?.ToString() ?? string.Empty); + string ip = KnownIps?[KnownIps.Count - 1] ?? "N/A"; DateTime Registered = DateTime.Parse(user.Registered).ToLocalTime(); args.Player.SendSuccessMessage("{0} 的用户组是 {1}.", user.Name, user.Group); diff --git a/TShockAPI/GetDataHandlers.cs b/TShockAPI/GetDataHandlers.cs index fc4eb57cb..07f5427a8 100644 --- a/TShockAPI/GetDataHandlers.cs +++ b/TShockAPI/GetDataHandlers.cs @@ -1719,15 +1719,7 @@ private static bool HandleSendTileSquare(GetDataHandlerArgs args) var tileX = args.Data.ReadInt16(); var tileY = args.Data.ReadInt16(); - bool isTrapdoor = false; - - if (Main.tile[tileX, tileY].type == TileID.TrapdoorClosed - || Main.tile[tileX, tileY].type == TileID.TrapdoorOpen) - { - isTrapdoor = true; - } - - if (args.Player.HasPermission(Permissions.allowclientsideworldedit) && !isTrapdoor) + if (args.Player.HasPermission(Permissions.allowclientsideworldedit)) return false; if (OnSendTileSquare(size, tileX, tileY)) @@ -1826,7 +1818,7 @@ private static bool HandleSendTileSquare(GetDataHandlerArgs args) changed = true; } - if (tile.active() && newtile.Active) + if (tile.active() && newtile.Active && tile.type != newtile.Type) { // Grass <-> Grass if ((TileID.Sets.Conversion.Grass[tile.type] && TileID.Sets.Conversion.Grass[newtile.Type]) || @@ -1859,6 +1851,17 @@ private static bool HandleSendTileSquare(GetDataHandlerArgs args) Main.tile[realx, realy].wall = newtile.Wall; changed = true; } + + if ((tile.type == TileID.TrapdoorClosed && (newtile.Type == TileID.TrapdoorOpen || !newtile.Active)) || + (tile.type == TileID.TrapdoorOpen && (newtile.Type == TileID.TrapdoorClosed || !newtile.Active)) || + (!tile.active() && newtile.Active && (newtile.Type == TileID.TrapdoorOpen||newtile.Type == TileID.TrapdoorClosed))) + { + Main.tile[realx, realy].type = newtile.Type; + Main.tile[realx, realy].frameX = newtile.FrameX; + Main.tile[realx, realy].frameY = newtile.FrameY; + Main.tile[realx, realy].active(newtile.Active); + changed = true; + } } } @@ -1940,6 +1943,14 @@ public enum EditType { ProjectileID.CrimsandBallGun, TileID.Crimsand }, }; + private static Dictionary ropeCoilPlacements = new Dictionary + { + {ItemID.RopeCoil, TileID.Rope}, + {ItemID.SilkRopeCoil, TileID.SilkRope}, + {ItemID.VineRopeCoil, TileID.VineRope}, + {ItemID.WebRopeCoil, TileID.WebRope} + }; + /// /// Extra place style limits for strange hardcoded values in Terraria /// @@ -2115,7 +2126,8 @@ private static bool HandleTile(GetDataHandlerArgs args) // If they aren't selecting the item which creates the tile or wall, they're hacking. if (!(selectedItem.netID == ItemID.IceRod && editData == TileID.MagicalIceBlock) && - editData != (action == EditAction.PlaceTile ? selectedItem.createTile : selectedItem.createWall)) + (editData != (action == EditAction.PlaceTile ? selectedItem.createTile : selectedItem.createWall) && + !(ropeCoilPlacements.ContainsKey(selectedItem.netID) && editData == ropeCoilPlacements[selectedItem.netID]))) { args.Player.SendTileSquare(tileX, tileY, 4); return true; @@ -2191,8 +2203,13 @@ private static bool HandleTile(GetDataHandlerArgs args) return true; } } - if (TShock.Config.AllowCutTilesAndBreakables && Main.tileCut[Main.tile[tileX, tileY].type]) + if (TShock.Config.AllowCutTilesAndBreakables && Main.tileCut[tile.type]) { + if (action == EditAction.KillWall) + { + args.Player.SendTileSquare(tileX, tileY, 1); + return true; + } return false; } diff --git a/TShockAPI/NetItem.cs b/TShockAPI/NetItem.cs index a1770978d..317168fcc 100644 --- a/TShockAPI/NetItem.cs +++ b/TShockAPI/NetItem.cs @@ -71,6 +71,11 @@ public struct NetItem /// public static readonly int MiscDyeSlots = MiscEquipSlots; + /// + /// 1 - The number of trash can slots. + /// + public static readonly int TrashSlots = 1; + /// /// 180 - The inventory size (inventory, held item, armour, dies, coins, ammo, piggy, safe, and trash) /// @@ -83,7 +88,8 @@ public struct NetItem public static readonly Tuple MiscDyeIndex = new Tuple(MiscEquipIndex.Item2, MiscEquipIndex.Item2 + MiscDyeSlots); public static readonly Tuple PiggyIndex = new Tuple(MiscDyeIndex.Item2, MiscDyeIndex.Item2 + PiggySlots); public static readonly Tuple SafeIndex = new Tuple(PiggyIndex.Item2, PiggyIndex.Item2 + SafeSlots); - public static readonly Tuple ForgeIndex = new Tuple(SafeIndex.Item2, SafeIndex.Item2 + ForgeSlots); + public static readonly Tuple TrashIndex = new Tuple(SafeIndex.Item2, SafeIndex.Item2 + TrashSlots); + public static readonly Tuple ForgeIndex = new Tuple(TrashIndex.Item2, TrashIndex.Item2 + ForgeSlots); [JsonProperty("物品")] private int _netId; diff --git a/TShockAPI/PlayerData.cs b/TShockAPI/PlayerData.cs index 9cd7c97b9..cc82cab63 100644 --- a/TShockAPI/PlayerData.cs +++ b/TShockAPI/PlayerData.cs @@ -164,16 +164,17 @@ public void CopyCharacter(TSPlayer player) var index = i - NetItem.SafeIndex.Item1; this.inventory[i] = (NetItem)safe[index]; } - else if (i < NetItem.ForgeIndex.Item2) + else if (i < NetItem.TrashIndex.Item2) { //179-219 - var index = i - NetItem.ForgeIndex.Item1; - this.inventory[i] = (NetItem)forge[index]; + this.inventory[i] = (NetItem)trash; } else { //220 - this.inventory[i] = (NetItem)trash; + var index = i - NetItem.ForgeIndex.Item1; + this.inventory[i] = (NetItem)forge[index]; + } } } @@ -226,7 +227,7 @@ public void RestoreCharacter(TSPlayer player) for (int i = 0; i < NetItem.MaxInventory; i++) { - if (i < NetItem.InventorySlots) + if (i < NetItem.InventoryIndex.Item2) { //0-58 player.TPlayer.inventory[i].netDefaults(this.inventory[i].NetId); @@ -237,10 +238,10 @@ public void RestoreCharacter(TSPlayer player) player.TPlayer.inventory[i].prefix = this.inventory[i].PrefixId; } } - else if (i < NetItem.InventorySlots + NetItem.ArmorSlots) + else if (i < NetItem.ArmorIndex.Item2) { //59-78 - var index = i - NetItem.InventorySlots; + var index = i - NetItem.ArmorIndex.Item1; player.TPlayer.armor[index].netDefaults(this.inventory[i].NetId); if (player.TPlayer.armor[index].netID != 0) @@ -249,10 +250,10 @@ public void RestoreCharacter(TSPlayer player) player.TPlayer.armor[index].prefix = (byte)this.inventory[i].PrefixId; } } - else if (i < NetItem.InventorySlots + NetItem.ArmorSlots + NetItem.DyeSlots) + else if (i < NetItem.DyeIndex.Item2) { //79-88 - var index = i - (NetItem.InventorySlots + NetItem.ArmorSlots); + var index = i - NetItem.DyeIndex.Item1; player.TPlayer.dye[index].netDefaults(this.inventory[i].NetId); if (player.TPlayer.dye[index].netID != 0) @@ -261,11 +262,10 @@ public void RestoreCharacter(TSPlayer player) player.TPlayer.dye[index].prefix = (byte)this.inventory[i].PrefixId; } } - else if (i < - NetItem.InventorySlots + NetItem.ArmorSlots + NetItem.DyeSlots + NetItem.MiscEquipSlots) + else if (i < NetItem.MiscEquipIndex.Item2) { //89-93 - var index = i - (NetItem.InventorySlots + NetItem.ArmorSlots + NetItem.DyeSlots); + var index = i - NetItem.MiscEquipIndex.Item1; player.TPlayer.miscEquips[index].netDefaults(this.inventory[i].NetId); if (player.TPlayer.miscEquips[index].netID != 0) @@ -274,13 +274,10 @@ public void RestoreCharacter(TSPlayer player) player.TPlayer.miscEquips[index].prefix = (byte)this.inventory[i].PrefixId; } } - else if (i < - NetItem.InventorySlots + NetItem.ArmorSlots + NetItem.DyeSlots + NetItem.MiscEquipSlots - + NetItem.MiscDyeSlots) + else if (i < NetItem.MiscDyeIndex.Item2) { //93-98 - var index = i - (NetItem.InventorySlots + NetItem.ArmorSlots + NetItem.DyeSlots - + NetItem.MiscEquipSlots); + var index = i - NetItem.MiscDyeIndex.Item1; player.TPlayer.miscDyes[index].netDefaults(this.inventory[i].NetId); if (player.TPlayer.miscDyes[index].netID != 0) @@ -289,13 +286,10 @@ public void RestoreCharacter(TSPlayer player) player.TPlayer.miscDyes[index].prefix = (byte)this.inventory[i].PrefixId; } } - else if (i < - NetItem.InventorySlots + NetItem.ArmorSlots + NetItem.DyeSlots + NetItem.MiscEquipSlots + - NetItem.MiscDyeSlots + NetItem.PiggySlots) + else if (i < NetItem.PiggyIndex.Item2) { //98-138 - var index = i - (NetItem.InventorySlots + NetItem.ArmorSlots + NetItem.DyeSlots - + NetItem.MiscEquipSlots + NetItem.MiscDyeSlots); + var index = i - NetItem.PiggyIndex.Item1; player.TPlayer.bank.item[index].netDefaults(this.inventory[i].NetId); if (player.TPlayer.bank.item[index].netID != 0) @@ -304,12 +298,10 @@ public void RestoreCharacter(TSPlayer player) player.TPlayer.bank.item[index].prefix = (byte)this.inventory[i].PrefixId; } } - else if (i < - NetItem.InventorySlots + NetItem.ArmorSlots + NetItem.DyeSlots + NetItem.MiscEquipSlots + - NetItem.MiscDyeSlots + NetItem.PiggySlots + NetItem.SafeSlots) + else if (i < NetItem.SafeIndex.Item2) { - var index = i - (NetItem.InventorySlots + NetItem.ArmorSlots + NetItem.DyeSlots - + NetItem.MiscEquipSlots + NetItem.MiscDyeSlots + NetItem.PiggySlots); + //138-178 + var index = i - NetItem.SafeIndex.Item1; player.TPlayer.bank2.item[index].netDefaults(this.inventory[i].NetId); if (player.TPlayer.bank2.item[index].netID != 0) @@ -318,29 +310,30 @@ public void RestoreCharacter(TSPlayer player) player.TPlayer.bank2.item[index].prefix = (byte)this.inventory[i].PrefixId; } } - else if (i < - NetItem.InventorySlots + NetItem.ArmorSlots + NetItem.DyeSlots + NetItem.MiscEquipSlots + - NetItem.MiscDyeSlots + NetItem.PiggySlots + NetItem.SafeSlots + NetItem.ForgeSlots) + else if (i < NetItem.TrashIndex.Item2) { - var index = i - (NetItem.InventorySlots + NetItem.ArmorSlots + NetItem.DyeSlots - + NetItem.MiscEquipSlots + NetItem.MiscDyeSlots + NetItem.PiggySlots + NetItem.SafeSlots); - player.TPlayer.bank3.item[index].netDefaults(this.inventory[i].NetId); + //179-219 + var index = i - NetItem.TrashIndex.Item1; + player.TPlayer.trashItem.netDefaults(this.inventory[i].NetId); - if (player.TPlayer.bank3.item[index].netID != 0) + if (player.TPlayer.trashItem.netID != 0) { - player.TPlayer.bank3.item[index].stack = this.inventory[i].Stack; - player.TPlayer.bank3.item[index].prefix = (byte)this.inventory[i].PrefixId; + player.TPlayer.trashItem.stack = this.inventory[i].Stack; + player.TPlayer.trashItem.prefix = (byte)this.inventory[i].PrefixId; } } else { - player.TPlayer.trashItem.netDefaults(this.inventory[i].NetId); + //220 + var index = i - NetItem.ForgeIndex.Item1; + player.TPlayer.bank3.item[index].netDefaults(this.inventory[i].NetId); - if (player.TPlayer.trashItem.netID != 0) + if (player.TPlayer.bank3.item[index].netID != 0) { - player.TPlayer.trashItem.stack = this.inventory[i].Stack; - player.TPlayer.trashItem.prefix = (byte)this.inventory[i].PrefixId; + player.TPlayer.bank3.item[index].stack = this.inventory[i].Stack; + player.TPlayer.bank3.item[index].Prefix((byte)this.inventory[i].PrefixId); } + } } @@ -380,13 +373,13 @@ public void RestoreCharacter(TSPlayer player) NetMessage.SendData(5, -1, -1, Main.player[player.Index].bank2.item[k].name, player.Index, slot, (float)Main.player[player.Index].bank2.item[k].prefix); slot++; } + NetMessage.SendData(5, -1, -1, Main.player[player.Index].trashItem.name, player.Index, slot++, (float)Main.player[player.Index].trashItem.prefix); for (int k = 0; k < NetItem.ForgeSlots; k++) { NetMessage.SendData(5, -1, -1, Main.player[player.Index].bank3.item[k].name, player.Index, slot, (float)Main.player[player.Index].bank3.item[k].prefix); slot++; } - NetMessage.SendData(5, -1, -1, Main.player[player.Index].trashItem.name, player.Index, slot, (float)Main.player[player.Index].trashItem.prefix); NetMessage.SendData(4, -1, -1, player.Name, player.Index, 0f, 0f, 0f, 0); NetMessage.SendData(42, -1, -1, "", player.Index, 0f, 0f, 0f, 0); @@ -428,13 +421,14 @@ public void RestoreCharacter(TSPlayer player) NetMessage.SendData(5, player.Index, -1, Main.player[player.Index].bank2.item[k].name, player.Index, slot, (float)Main.player[player.Index].bank2.item[k].prefix); slot++; } + NetMessage.SendData(5, player.Index, -1, Main.player[player.Index].trashItem.name, player.Index, slot++, (float)Main.player[player.Index].trashItem.prefix); for (int k = 0; k < NetItem.ForgeSlots; k++) { NetMessage.SendData(5, player.Index, -1, Main.player[player.Index].bank3.item[k].name, player.Index, slot, (float)Main.player[player.Index].bank3.item[k].prefix); slot++; } - NetMessage.SendData(5, player.Index, -1, Main.player[player.Index].trashItem.name, player.Index, slot, (float)Main.player[player.Index].trashItem.prefix); + NetMessage.SendData(4, player.Index, -1, player.Name, player.Index, 0f, 0f, 0f, 0); NetMessage.SendData(42, player.Index, -1, "", player.Index, 0f, 0f, 0f, 0); @@ -444,8 +438,17 @@ public void RestoreCharacter(TSPlayer player) { player.TPlayer.buffType[k] = 0; } + + /* + * The following packets are sent twice because the server will not send a packet to a client + * if they have not spawned yet if the remoteclient is -1 + * This is for when players login via uuid or serverpassword instead of via + * the login command. + */ NetMessage.SendData(50, -1, -1, "", player.Index, 0f, 0f, 0f, 0); NetMessage.SendData(50, player.Index, -1, "", player.Index, 0f, 0f, 0f, 0); + + NetMessage.SendData(76, player.Index, -1, "", player.Index); NetMessage.SendData(76, -1, -1, "", player.Index); NetMessage.SendData(39, player.Index, -1, "", 400); diff --git a/TShockAPI/Properties/AssemblyInfo.cs b/TShockAPI/Properties/AssemblyInfo.cs index 816fe778b..ad8216817 100644 --- a/TShockAPI/Properties/AssemblyInfo.cs +++ b/TShockAPI/Properties/AssemblyInfo.cs @@ -53,5 +53,5 @@ You should have received a copy of the GNU General Public License // Also, be sure to release on github with the exact assembly version tag as below // so that the update manager works correctly (via the Github releases api and mimic) -[assembly: AssemblyVersion("4.3.21")] -[assembly: AssemblyFileVersion("4.3.21")] +[assembly: AssemblyVersion("4.3.22")] +[assembly: AssemblyFileVersion("4.3.22")] diff --git a/TShockAPI/Rest/RestManager.cs b/TShockAPI/Rest/RestManager.cs index 8933e07e1..38fe5f6c5 100644 --- a/TShockAPI/Rest/RestManager.cs +++ b/TShockAPI/Rest/RestManager.cs @@ -23,7 +23,6 @@ You should have received a copy of the GNU General Public License using System.IO; using System.Linq; using System.Reflection; -using System.Reflection.Emit; using System.Text; using HttpServer; using Rests; @@ -103,12 +102,14 @@ public void RegisterRestfulCommands() // Server Commands if (TShock.Config.EnableTokenEndpointAuthentication) { + Rest.Register(new SecureRestCommand("/status", ServerStatusRoot)); Rest.Register(new SecureRestCommand("/v2/server/status", ServerStatusV2)); Rest.Register(new SecureRestCommand("/v3/server/motd", ServerMotd)); Rest.Register(new SecureRestCommand("/v3/server/rules", ServerRules)); } else { + Rest.Register(new RestCommand("/status", (a) => this.ServerStatusRoot(new RestRequestArgs(a.Verbs, a.Parameters, a.Request, SecureRest.TokenData.None, a.Context)))); Rest.Register(new RestCommand("/v2/server/status", (a) => this.ServerStatusV2(new RestRequestArgs(a.Verbs, a.Parameters, a.Request, SecureRest.TokenData.None, a.Context)))); Rest.Register(new RestCommand("/v3/server/motd", (a) => this.ServerMotd(new RestRequestArgs(a.Verbs, a.Parameters, a.Request, SecureRest.TokenData.None, a.Context)))); Rest.Register(new RestCommand("/v3/server/rules", (a) => this.ServerRules(new RestRequestArgs(a.Verbs, a.Parameters, a.Request, SecureRest.TokenData.None, a.Context)))); @@ -275,6 +276,16 @@ private object ServerRules(RestRequestArgs args) }; } + [Description("Get a list of information about the current TShock server.")] + [Route("/status")] + [Token] + private object ServerStatusRoot(RestRequestArgs args) + { + RestObject status = (RestObject)ServerStatusV2(args); + status.Add("upgrade", "/v2/server/status"); + return status; + } + [Description("Get a list of information about the current TShock server.")] [Route("/v2/server/status")] [Token] @@ -762,10 +773,11 @@ private object PlayerReadV3(RestRequestArgs args) return new RestObject() { {"nickname", player.Name}, - {"username", null == player.User ? "" : player.User.Name}, + {"username", player.User?.Name}, {"ip", player.IP}, {"group", player.Group.Name}, - {"registered", null == player.User ? "" : player.User.Registered}, + {"registered", player.User?.Registered}, + {"muted", player.mute }, {"position", player.TileX + "," + player.TileY}, {"inventory", string.Join(", ", inventory.Select(p => (p.name + ":" + p.stack)))}, {"armor", string.Join(", ", equipment.Select(p => (p.netID + ":" + p.prefix)))}, diff --git a/TShockAPI/TSPlayer.cs b/TShockAPI/TSPlayer.cs index cbbeef527..c6704172c 100644 --- a/TShockAPI/TSPlayer.cs +++ b/TShockAPI/TSPlayer.cs @@ -637,6 +637,33 @@ public object RemoveData(string key) return null; } + /// + /// Logs the player out of an account. + /// + public void Logout() + { + PlayerHooks.OnPlayerLogout(this); + if (Main.ServerSideCharacter) + { + IgnoreActionsForInventory = $"云端存档/强制开荒 模式. 请使用 {Commands.Specifier}register \\ {Commands.Specifier}login 加入游戏!"; + if (!IgnoreActionsForClearingTrashCan && (!Dead || TPlayer.difficulty != 2)) + { + PlayerData.CopyCharacter(this); + TShock.CharacterDB.InsertPlayerData(this); + } + } + + PlayerData = new PlayerData(this); + Group = TShock.Groups.GetGroupByName(TShock.Config.DefaultGuestGroupName); + tempGroup = null; + if (tempGroupTimer != null) + { + tempGroupTimer.Stop(); + } + User = null; + IsLoggedIn = false; + } + /// /// Initializes a new instance of the class. /// diff --git a/TShockAPI/TShock.cs b/TShockAPI/TShock.cs index 2a970cbb5..62e0dd5ac 100644 --- a/TShockAPI/TShock.cs +++ b/TShockAPI/TShock.cs @@ -56,9 +56,9 @@ public class TShock : TerrariaPlugin /// VersionCodename - The version codename is displayed when the server starts. Inspired by software codenames conventions. public static readonly string VersionCodename = "Mintaka"; /// CNMode - ʾǰ汾Ϣ. - public static readonly string CNMode = "߼-"; + public static readonly string CNMode = "advcn-stable"; /// CNVersion - ʾǰ汾. - public static readonly Version CNVersion = new Version(2, 1, 1, 0); + public static readonly Version CNVersion = new Version(2, 2, 0, 0); /// 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"; @@ -828,6 +828,7 @@ public static void HandleCommandLinePostConfigLoad(string[] parms) /// AuthToken - The auth token used by the /auth system to grant temporary superadmin access to new admins. public static int AuthToken = -1; + private string _cliPassword = null; /// OnPostInit - Fired when the server loads a map, to perform world specific operations. /// args - The EventArgs object. @@ -835,6 +836,16 @@ private void OnPostInit(EventArgs args) { SetConsoleTitle(false); + //This is to prevent a bug where a CLI-defined password causes packets to be + //sent in an unexpected order, resulting in clients being unable to connect + if (!string.IsNullOrEmpty(Netplay.ServerPassword)) + { + //CLI defined password overrides a config password + _cliPassword = Netplay.ServerPassword; + Netplay.ServerPassword = ""; + Config.ServerPassword = _cliPassword; + } + // Disable the auth system if "auth.lck" is present or a superadmin exists if (File.Exists(Path.Combine(SavePath, "auth.lck")) || Users.GetUsers().Exists(u => u.Group == new SuperAdminGroup().Name)) { @@ -1968,10 +1979,9 @@ public static bool HackedInventory(TSPlayer player) Item[] safe = player.TPlayer.bank2.item; Item[] forge = player.TPlayer.bank3.item; Item trash = player.TPlayer.trashItem; - for (int i = 0; i < NetItem.MaxInventory; i++) { - if (i < NetItem.InventorySlots) + if (i < NetItem.InventoryIndex.Item2) { //0-58 Item item = new Item(); @@ -1989,11 +1999,11 @@ public static bool HackedInventory(TSPlayer player) } } } - else if (i < NetItem.InventorySlots + NetItem.ArmorSlots) + else if (i < NetItem.ArmorIndex.Item2) { //59-78 + var index = i - NetItem.ArmorIndex.Item1; Item item = new Item(); - var index = i - NetItem.InventorySlots; if (armor[index] != null && armor[index].netID != 0) { item.netDefaults(armor[index].netID); @@ -2008,11 +2018,11 @@ public static bool HackedInventory(TSPlayer player) } } } - else if (i < NetItem.InventorySlots + NetItem.ArmorSlots + NetItem.DyeSlots) + else if (i < NetItem.DyeIndex.Item2) { //79-88 + var index = i - NetItem.DyeIndex.Item1; Item item = new Item(); - var index = i - (NetItem.InventorySlots + NetItem.ArmorSlots); if (dye[index] != null && dye[index].netID != 0) { item.netDefaults(dye[index].netID); @@ -2027,12 +2037,11 @@ public static bool HackedInventory(TSPlayer player) } } } - else if (i < - NetItem.InventorySlots + NetItem.ArmorSlots + NetItem.DyeSlots + NetItem.MiscEquipSlots) + else if (i < NetItem.MiscEquipIndex.Item2) { //89-93 + var index = i - NetItem.MiscEquipIndex.Item1; Item item = new Item(); - var index = i - (NetItem.InventorySlots + NetItem.ArmorSlots + NetItem.DyeSlots); if (miscEquips[index] != null && miscEquips[index].netID != 0) { item.netDefaults(miscEquips[index].netID); @@ -2047,14 +2056,11 @@ public static bool HackedInventory(TSPlayer player) } } } - else if (i < - NetItem.InventorySlots + NetItem.ArmorSlots + NetItem.DyeSlots + NetItem.MiscEquipSlots - + NetItem.MiscDyeSlots) + else if (i < NetItem.MiscDyeIndex.Item2) { //93-98 + var index = i - NetItem.MiscDyeIndex.Item1; Item item = new Item(); - var index = i - (NetItem.InventorySlots + NetItem.ArmorSlots + NetItem.DyeSlots - + NetItem.MiscEquipSlots); if (miscDyes[index] != null && miscDyes[index].netID != 0) { item.netDefaults(miscDyes[index].netID); @@ -2069,14 +2075,11 @@ public static bool HackedInventory(TSPlayer player) } } } - else if (i < - NetItem.InventorySlots + NetItem.ArmorSlots + NetItem.DyeSlots + NetItem.MiscEquipSlots + - NetItem.MiscDyeSlots + NetItem.PiggySlots) + else if (i < NetItem.PiggyIndex.Item2) { //98-138 + var index = i - NetItem.PiggyIndex.Item1; Item item = new Item(); - var index = i - (NetItem.InventorySlots + NetItem.ArmorSlots + NetItem.DyeSlots - + NetItem.MiscEquipSlots + NetItem.MiscDyeSlots); if (piggy[index] != null && piggy[index].netID != 0) { item.netDefaults(piggy[index].netID); @@ -2092,14 +2095,11 @@ public static bool HackedInventory(TSPlayer player) } } } - else if (i < - NetItem.InventorySlots + NetItem.ArmorSlots + NetItem.DyeSlots + NetItem.MiscEquipSlots + - NetItem.MiscDyeSlots + NetItem.PiggySlots + NetItem.SafeSlots) + else if (i < NetItem.SafeIndex.Item2) { //138-178 + var index = i - NetItem.SafeIndex.Item1; Item item = new Item(); - var index = i - (NetItem.InventorySlots + NetItem.ArmorSlots + NetItem.DyeSlots - + NetItem.MiscEquipSlots + NetItem.MiscDyeSlots + NetItem.PiggySlots); if (safe[index] != null && safe[index].netID != 0) { item.netDefaults(safe[index].netID); @@ -2115,46 +2115,45 @@ public static bool HackedInventory(TSPlayer player) } } } - else if (i < - NetItem.InventorySlots + NetItem.ArmorSlots + NetItem.DyeSlots + NetItem.MiscEquipSlots + - NetItem.MiscDyeSlots + NetItem.PiggySlots + NetItem.SafeSlots + NetItem.ForgeSlots) + else if (i < NetItem.TrashIndex.Item2) { //179-219 Item item = new Item(); - var index = i - (NetItem.InventorySlots + NetItem.ArmorSlots + NetItem.DyeSlots - + NetItem.MiscEquipSlots + NetItem.MiscDyeSlots + NetItem.PiggySlots + NetItem.SafeSlots); - if (forge[index] != null && forge[index].netID != 0) + if (trash != null && trash.netID != 0) { - item.netDefaults(forge[index].netID); - item.Prefix(forge[index].prefix); + item.netDefaults(trash.netID); + item.Prefix(trash.prefix); item.AffixName(); - if (forge[index].stack > item.maxStack) + if (trash.stack > item.maxStack) { check = true; player.SendMessage( - String.Format("Stack cheat detected. Remove Defender's Forge item {0} ({1}) and then rejoin", item.name, forge[index].stack), + $"Ʒ({trash.stack}/{item.maxStack}). {trash.name}({trash.stack}) Ȼ¼Ϸ.", Color.Cyan); } } } else { + //220 + var index = i - NetItem.ForgeIndex.Item1; Item item = new Item(); - if (trash != null && trash.netID != 0) + if (forge[index] != null && forge[index].netID != 0) { - item.netDefaults(trash.netID); - item.Prefix(trash.prefix); + item.netDefaults(forge[index].netID); + item.Prefix(forge[index].prefix); item.AffixName(); - if (trash.stack > item.maxStack) + if (forge[index].stack > item.maxStack) { check = true; player.SendMessage( - $"Ʒ({trash.stack}/{item.maxStack}). {trash.name}({trash.stack}) Ȼ¼Ϸ.", - Color.Cyan); + String.Format("¯Ʒ. 붪 {0} ({1}) ټϷ.", item.name, forge[index].stack), + Color.Cyan); } } + } } @@ -2190,7 +2189,14 @@ public void OnConfigRead(ConfigFile file) if (file.MaxSlots > 235) file.MaxSlots = 235; Main.maxNetPlayers = file.MaxSlots + 20; + Netplay.ServerPassword = ""; + if (!string.IsNullOrEmpty(_cliPassword)) + { + //This prevents a config reload from removing/updating a CLI-defined password + file.ServerPassword = _cliPassword; + } + Netplay.spamCheck = false; } } diff --git a/TerrariaServerAPI b/TerrariaServerAPI index 302124e1b..ca93c2d67 160000 --- a/TerrariaServerAPI +++ b/TerrariaServerAPI @@ -1 +1 @@ -Subproject commit 302124e1bcf6a6661d518b84f630384a90dbcbcb +Subproject commit ca93c2d6719ee59bb791cff500b1d9d32bb74547