private void OnPlayerChestItem(TSPlayer player, BinaryReader reader) { var session = player.GetSession(); var chestId = reader.ReadInt16(); if (!session.IdToChest.TryGetValue(chestId, out var chest)) { Debug.WriteLine($"DEBUG: {player.Name} attempted to modify chest (ID: {chestId})"); return; } Debug.WriteLine($"DEBUG: {player.Name} modified chest at {chest.X}, {chest.Y} (ID: {chestId})"); var index = reader.ReadByte(); var stackSize = reader.ReadInt16(); var prefixId = reader.ReadByte(); var itemId = reader.ReadInt16(); chest.Items[index] = new NetItem(itemId, stackSize, prefixId); _database.Update(chest); }
/// <summary> /// Shows the chest to the specified player. /// </summary> /// <param name="player">The player, which must not be <c>null</c>.</param> /// <param name="newChestId">A new chest ID to use for showing the chest.</param> public void ShowTo(TSPlayer player, int newChestId) { if (RefillTime != null && DateTime.UtcNow - _lastRefill > RefillTime) { Debug.WriteLine($"DEBUG: Chest at {X}, {Y} was refilled"); _lastRefill = DateTime.UtcNow; for (var i = 0; i < Terraria.Chest.maxItems; ++i) { Items[i] = OriginalItems[i]; } } var session = player.GetSession(); if (!session.ChestToId.TryGetValue(this, out var chestId)) { chestId = newChestId; // Remove all mappings of the old chest ID. foreach (var kvp in session.ChestToId.Where(kvp => kvp.Value == chestId).ToList()) { session.ChestToId.Remove(kvp); } session.IdToChest.Remove(chestId); } session.ChestToId[this] = chestId; session.IdToChest[chestId] = this; Debug.WriteLine($"DEBUG: {player.Name} accessing chest at {X}, {Y} (ID: {chestId})"); lock (ChestLock) { var terrariaChest = new Terraria.Chest { x = X, y = Y, name = Name }; Main.chest[chestId] = terrariaChest; player.SendData(PacketTypes.ChestName, "", chestId, X, Y); for (var i = 0; i < Terraria.Chest.maxItems; ++i) { var item = new Item(); item.SetDefaults(Items[i].NetId); item.stack = Items[i].Stack; item.prefix = Items[i].PrefixId; terrariaChest.item[i] = item; player.SendData(PacketTypes.ChestItem, "", chestId, i); } player.SendData(PacketTypes.ChestOpen, "", chestId); Main.chest[chestId] = null; } player.TPlayer.chest = chestId; // Sync player chest indices for everyone. We have to ensure that each player only receives the chest ID // that they received for the chest. foreach (var player2 in TShock.Players.Where(p => p?.Active == true && p != player)) { var session2 = player2.GetSession(); if (session2.ChestToId.TryGetValue(this, out var chestId2)) { player2.SendData(PacketTypes.SyncPlayerChestIndex, "", player.Index, chestId2); } } }
private void OnPlayerChestSet(TSPlayer player, BinaryReader reader) { var chestId = reader.ReadInt16(); reader.ReadInt16(); reader.ReadInt16(); var length = reader.ReadByte(); var name = ""; if (length > 0 && length <= 20) { name = reader.ReadString(); } else if (length != 255) { length = 0; } var tplayer = player.TPlayer; var session = player.GetSession(); var oldChestId = tplayer.chest; if (session.IdToChest.TryGetValue(oldChestId, out var oldChest)) { oldChest.IsInUse = false; if (length != 0) { Debug.WriteLine( $"DEBUG: {player.Name} renamed chest at {oldChest.X}, {oldChest.Y} (ID: {chestId})"); oldChest.Name = name; _database.Update(oldChest); // Sync chest names for everyone. We have to ensure that each player recieves the chest ID that they // received for the chest. foreach (var player2 in TShock.Players.Where(p => p?.Active == true && p != player)) { var session2 = player2.GetSession(); if (session2.ChestToId.TryGetValue(oldChest, out var chestId2)) { player2.SendData(PacketTypes.ChestName, "", chestId2, oldChest.X, oldChest.Y); } } } } tplayer.chest = chestId; // Sync player chest indices for everyone. If the chest ID is positive, we have to ensure that each player // receives the chest ID that they received for the chest. if (chestId >= 0 && session.IdToChest.TryGetValue(chestId, out var chest)) { foreach (var player2 in TShock.Players.Where(p => p?.Active == true && p != player)) { var session2 = player2.GetSession(); if (session2.ChestToId.TryGetValue(chest, out var chestId2)) { player2.SendData(PacketTypes.SyncPlayerChestIndex, "", player.Index, chestId2); } } } else if (chestId == -1) { Debug.WriteLine($"DEBUG: {player.Name} finished accessing chest (ID: {oldChestId})"); NetMessage.SendData((int)PacketTypes.SyncPlayerChestIndex, -1, player.Index, null, player.Index, -1); // Handle biome mimic spawning. if (oldChest == null) { return; } var x = oldChest.X; var y = oldChest.Y; if (!TileID.Sets.BasicChest[Main.tile[x, y].type]) { return; } var npcId = -1; var onlyItemId = oldChest.OnlyItemId; if (onlyItemId == ItemID.LightKey) { npcId = NPCID.BigMimicHallow; } else if (onlyItemId == ItemID.NightKey) { npcId = WorldGen.crimson ? NPCID.BigMimicCrimson : NPCID.BigMimicCorruption; } if (npcId > 0) { if (!player.HasPermission(Permissions.spawnmob)) { Debug.WriteLine($"DEBUG: {player.Name} tried to spawn a biome mimic"); player.SendErrorMessage("You don't have access to spawn mobs."); return; } Debug.WriteLine($"DEBUG: {player.Name} spawned a biome mimic"); _database.Remove(oldChest); Main.tile[x, y].active(false); Main.tile[x, y + 1].active(false); Main.tile[x + 1, y].active(false); Main.tile[x + 1, y + 1].active(false); TSPlayer.All.SendTileSquare(x, y, 2); var npcIndex = NPC.NewNPC(16 * x + 16, 16 * y + 32, npcId); var npc = Main.npc[npcIndex]; npc.whoAmI = npcIndex; TSPlayer.All.SendData(PacketTypes.NpcUpdate, "", npcIndex); npc.BigMimicSpawnSmoke(); } } }
private void OnPlayerChestGet(TSPlayer player, BinaryReader reader) { var x = reader.ReadInt16(); var y = reader.ReadInt16(); var session = player.GetSession(); var chest = _database.GetOrConvert(x, y); if (chest == null) { player.SendErrorMessage("This chest is corrupted."); session.PendingChestAction = ChestAction.None; return; } switch (session.PendingChestAction) { case ChestAction.GetInfo: Debug.WriteLine($"DEBUG: {player.Name} obtained info about chest at {x}, {y}"); player.SendInfoMessage( $"X: {x}, Y: {y}, Owner: {chest.OwnerName ?? "N/A"} {(chest.IsPublic ? "(Public)" : "")}"); if (chest.RefillTime != null) { player.SendInfoMessage($"Refill time: {chest.RefillTime}"); } if (chest.AllowedUsernames.Count > 0) { player.SendInfoMessage($"Allowed users: {string.Join(", ", chest.AllowedUsernames)}"); } if (chest.AllowedGroupNames.Count > 0) { player.SendInfoMessage($"Allowed groups: {string.Join(", ", chest.AllowedGroupNames)}"); } break; case ChestAction.TogglePublic: if (!chest.IsOwner(player)) { Debug.WriteLine( $"DEBUG: {player.Name} attempted to toggle public status for chest at {x}, {y}"); player.SendErrorMessage("This chest is protected."); break; } Debug.WriteLine($"DEBUG: {player.Name} toggled public status for chest at {x}, {y}"); chest.IsPublic = !chest.IsPublic; _database.Update(chest); player.SendInfoMessage($"This chest is now {(chest.IsPublic ? "public" : "private")}."); break; case ChestAction.ToggleMultiuse: if (!chest.IsOwner(player)) { Debug.WriteLine( $"DEBUG: {player.Name} attempted to toggle multiuse status for chest at {x}, {y}"); player.SendErrorMessage("This chest is protected."); break; } Debug.WriteLine($"DEBUG: {player.Name} toggled multiuse status for chest at {x}, {y}"); chest.IsMultiUse = !chest.IsMultiUse; _database.Update(chest); player.SendInfoMessage( $"This can {(chest.IsMultiUse ? "now" : "no longer")} be used by multiple players."); break; case ChestAction.SetRefill: if (!chest.IsOwner(player)) { Debug.WriteLine($"DEBUG: {player.Name} attempted to set refill time for chest at {x}, {y}"); player.SendErrorMessage("This chest is protected."); break; } Debug.WriteLine($"DEBUG: {player.Name} set refill time for chest at {x}, {y}"); chest.RefillTime = session.PendingRefillTime; _database.Update(chest); player.SendInfoMessage(chest.RefillTime == null ? "This chest will no longer refill." : $"This chest will now refill every {chest.RefillTime}."); break; case ChestAction.ToggleUser: if (!chest.IsOwner(player)) { Debug.WriteLine($"DEBUG: {player.Name} attempted to toggle a user for chest at {x}, {y}"); player.SendErrorMessage("This chest is protected."); break; } Debug.WriteLine($"DEBUG: {player.Name} toggled a user for chest at {x}, {y}"); if (chest.AllowedUsernames.Contains(session.PendingUsername)) { chest.AllowedUsernames.Remove(session.PendingUsername); player.SendInfoMessage($"Disallowed {session.PendingUsername} from editing this chest."); } else { chest.AllowedUsernames.Add(session.PendingUsername); player.SendInfoMessage($"Allowed {session.PendingUsername} to edit this chest."); } _database.Update(chest); break; case ChestAction.ToggleGroup: if (!chest.IsOwner(player)) { Debug.WriteLine($"DEBUG: {player.Name} attempted to toggle a group for chest at {x}, {y}"); player.SendErrorMessage("This chest is protected."); break; } Debug.WriteLine($"DEBUG: {player.Name} toggled a group for chest at {x}, {y}"); if (chest.AllowedGroupNames.Contains(session.PendingGroupName)) { chest.AllowedGroupNames.Remove(session.PendingGroupName); player.SendInfoMessage($"Disallowed the {session.PendingGroupName} group from editing this chest."); } else { chest.AllowedGroupNames.Add(session.PendingGroupName); player.SendInfoMessage($"Allowed the {session.PendingGroupName} group to edit this chest."); } _database.Update(chest); break; case ChestAction.Claim: if (!string.IsNullOrEmpty(chest.OwnerName)) { Debug.WriteLine($"DEBUG: {player.Name} attempted to claim a chest at {x}, {y}"); player.SendErrorMessage("This chest is already claimed."); return; } Debug.WriteLine($"DEBUG: {player.Name} claimed a chest at {x}, {y}"); chest.OwnerName = player.User?.Name; _database.Update(chest); player.SendInfoMessage("Claimed chest."); break; case ChestAction.Unclaim: if (!chest.IsOwner(player)) { Debug.WriteLine($"DEBUG: {player.Name} attempted to unclaim a chest at {x}, {y}"); player.SendErrorMessage("This chest is protected."); return; } Debug.WriteLine($"DEBUG: {player.Name} unclaimed a chest at {x}, {y}"); chest.OwnerName = null; _database.Update(chest); player.SendInfoMessage("Unclaimed chest."); break; default: if (!chest.IsAllowed(player)) { Debug.WriteLine($"DEBUG: {player.Name} attempted to access chest at {x}, {y}"); player.SendErrorMessage("This chest is protected."); break; } if (!chest.CanUse) { Debug.WriteLine($"DEBUG: {player.Name} attempted to access chest at {x}, {y}"); player.SendErrorMessage("This chest is currently in use."); break; } var oldChestId = player.TPlayer.chest; if (session.IdToChest.TryGetValue(oldChestId, out var oldChest)) { oldChest.IsInUse = false; } chest.IsInUse = true; chest.ShowTo(player, session.GetNextChestId()); break; } session.PendingChestAction = ChestAction.None; }