|
1 | 1 | using System; |
| 2 | +using System.Collections; |
2 | 3 | using System.Collections.Generic; |
3 | 4 | using System.Collections.ObjectModel; |
4 | 5 | using System.Diagnostics.Contracts; |
5 | 6 | using System.Globalization; |
6 | 7 | using System.IO; |
7 | 8 | using System.Linq; |
| 9 | +using System.Runtime.CompilerServices; |
8 | 10 | using System.Text; |
9 | 11 | using Microsoft.Xna.Framework; |
10 | 12 | using OTAPI.Tile; |
|
15 | 17 | using Terraria.Plugins.Common; |
16 | 18 | using Terraria.Plugins.Common.Collections; |
17 | 19 | using TShockAPI; |
| 20 | +using TShockAPI.DB; |
18 | 21 |
|
19 | 22 | namespace Terraria.Plugins.CoderCow.Protector { |
20 | 23 | public class UserInteractionHandler: UserInteractionHandlerBase, IDisposable { |
@@ -134,6 +137,15 @@ public UserInteractionHandler( |
134 | 137 | this.TradeChestCommand_Exec, this.TradeChestCommand_HelpCallback, ProtectorPlugin.SetTradeChests_Permission, |
135 | 138 | allowServer: false |
136 | 139 | ); |
| 140 | + base.RegisterCommand( |
| 141 | + new[] { "scanchests" }, |
| 142 | + this.ScanChestsCommand_Exec, this.ScanChestsCommand_HelpCallback, ProtectorPlugin.ScanChests_Permission |
| 143 | + ); |
| 144 | + base.RegisterCommand( |
| 145 | + new[] { "tpchest" }, |
| 146 | + this.TpChestCommand_Exec, this.TpChestCommand_HelpCallback, ProtectorPlugin.ScanChests_Permission, |
| 147 | + allowServer: false |
| 148 | + ); |
137 | 149 | #endregion |
138 | 150 |
|
139 | 151 | #if DEBUG |
@@ -2080,6 +2092,158 @@ private bool TradeChestCommand_HelpCallback(CommandArgs args) { |
2080 | 2092 | } |
2081 | 2093 | #endregion |
2082 | 2094 |
|
| 2095 | + private readonly ConditionalWeakTable<TSPlayer, DPoint[]> scanChestsResults = new ConditionalWeakTable<TSPlayer, DPoint[]>(); |
| 2096 | + #region [Command Handling /scanchests] |
| 2097 | + private void ScanChestsCommand_Exec(CommandArgs args) { |
| 2098 | + if (args == null || this.IsDisposed) |
| 2099 | + return; |
| 2100 | + |
| 2101 | + if (args.Parameters.Count == 0) { |
| 2102 | + args.Player.SendErrorMessage("Proper syntax: /scanchests <item name> [<page>]"); |
| 2103 | + args.Player.SendInfoMessage("Type /scanchests help to get more information about this command."); |
| 2104 | + return; |
| 2105 | + } |
| 2106 | + |
| 2107 | + string itemNamePart; |
| 2108 | + int pageNumber = 1; |
| 2109 | + if (args.Parameters.Count == 1) { |
| 2110 | + itemNamePart = args.Parameters[0]; |
| 2111 | + } else { |
| 2112 | + string lastParam = args.Parameters[args.Parameters.Count - 1]; |
| 2113 | + if (lastParam.Length <= 2 && int.TryParse(lastParam, out pageNumber)) |
| 2114 | + itemNamePart = args.ParamsToSingleString(0, 1); |
| 2115 | + else |
| 2116 | + itemNamePart = args.ParamsToSingleString(); |
| 2117 | + |
| 2118 | + if (pageNumber < 1) { |
| 2119 | + args.Player.SendErrorMessage($"\"{lastParam}\" is not a valid page number."); |
| 2120 | + return; |
| 2121 | + } |
| 2122 | + } |
| 2123 | + |
| 2124 | + List<Item> itemsToLookup = TShock.Utils.GetItemByIdOrName(itemNamePart); |
| 2125 | + if (itemsToLookup.Count == 0) { |
| 2126 | + args.Player.SendErrorMessage($"Unable to guess a valid item type from \"{itemNamePart}\"."); |
| 2127 | + return; |
| 2128 | + } |
| 2129 | + |
| 2130 | + // DPoint is the chest location. |
| 2131 | + List<Tuple<ItemData[], DPoint>> results = new List<Tuple<ItemData[], DPoint>>(); |
| 2132 | + foreach (IChest chest in this.ChestManager.EnumerateAllChests()) { |
| 2133 | + List<ItemData> matchingItems = new List<ItemData>( |
| 2134 | + from item in chest.Items |
| 2135 | + where itemsToLookup.Any(li => li.netID == item.Type) |
| 2136 | + select item); |
| 2137 | + |
| 2138 | + if (matchingItems.Count > 0) |
| 2139 | + results.Add(new Tuple<ItemData[], DPoint>(matchingItems.ToArray(), chest.Location)); |
| 2140 | + } |
| 2141 | + |
| 2142 | + DPoint[] resultsChestLocations = results.Select(r => r.Item2).ToArray(); |
| 2143 | + this.scanChestsResults.Remove(args.Player); |
| 2144 | + this.scanChestsResults.Add(args.Player, resultsChestLocations); |
| 2145 | + |
| 2146 | + PaginationTools.SendPage(args.Player, pageNumber, results, new PaginationTools.Settings { |
| 2147 | + HeaderFormat = $"The Following Chests Contain \"{itemNamePart}\" (Page {{0}} of {{1}})", |
| 2148 | + NothingToDisplayString = $"No chest contains items matching \"{itemNamePart}\"", |
| 2149 | + LineTextColor = Color.LightGray, |
| 2150 | + MaxLinesPerPage = 10, |
| 2151 | + LineFormatter = (lineData, dataIndex, pageNumberLocal) => { |
| 2152 | + var result = (lineData as Tuple<ItemData[], DPoint>); |
| 2153 | + if (result == null) |
| 2154 | + return null; |
| 2155 | + |
| 2156 | + ItemData[] foundItems = result.Item1; |
| 2157 | + DPoint chestLocation = result.Item2; |
| 2158 | + |
| 2159 | + string foundItemsString = string.Join(" ", foundItems.Select(i => TShock.Utils.ItemTag(i.ToItem()))); |
| 2160 | + |
| 2161 | + string chestOwner = "{not protected}"; |
| 2162 | + ProtectionEntry protection = this.ProtectionManager.GetProtectionAt(chestLocation); |
| 2163 | + if (protection != null) { |
| 2164 | + User tsUser = TShock.Users.GetUserByID(protection.Owner); |
| 2165 | + chestOwner = tsUser?.Name ?? $"{{user id: {protection.Owner}}}"; |
| 2166 | + } |
| 2167 | + |
| 2168 | + return new Tuple<string,Color>($"{dataIndex}. Chest owned by {TShock.Utils.ColorTag(chestOwner, Color.Red)} contains {foundItemsString}", Color.LightGray); |
| 2169 | + } |
| 2170 | + }); |
| 2171 | + |
| 2172 | + if (results.Count > 0) |
| 2173 | + args.Player.SendSuccessMessage("Type /tpchest <result index> to teleport to the respective chest."); |
| 2174 | + } |
| 2175 | + |
| 2176 | + private bool ScanChestsCommand_HelpCallback(CommandArgs args) { |
| 2177 | + if (args == null || this.IsDisposed) |
| 2178 | + return false; |
| 2179 | + |
| 2180 | + int pageNumber; |
| 2181 | + if (!PaginationTools.TryParsePageNumber(args.Parameters, 1, args.Player, out pageNumber)) |
| 2182 | + return false; |
| 2183 | + |
| 2184 | + switch (pageNumber) { |
| 2185 | + default: |
| 2186 | + args.Player.SendMessage("Command reference for /scanchests (Page 1 of 1)", Color.Lime); |
| 2187 | + args.Player.SendMessage("/scanchests <item name> [page]", Color.White); |
| 2188 | + args.Player.SendMessage("Searches all chests in the current world for items matching the given name. The user will be able to teleport to the chests found by this command using /tpchest.", Color.LightGray); |
| 2189 | + args.Player.SendMessage(string.Empty, Color.LightGray); |
| 2190 | + args.Player.SendMessage("item name = Part of name of the item(s) to check for.", Color.LightGray); |
| 2191 | + break; |
| 2192 | + } |
| 2193 | + |
| 2194 | + return true; |
| 2195 | + } |
| 2196 | + #endregion |
| 2197 | + |
| 2198 | + #region [Command Handling /tpchest] |
| 2199 | + private void TpChestCommand_Exec(CommandArgs args) { |
| 2200 | + if (args == null || this.IsDisposed) |
| 2201 | + return; |
| 2202 | + |
| 2203 | + if (args.Parameters.Count != 1) { |
| 2204 | + args.Player.SendErrorMessage("Proper syntax: /tpchest <result index>"); |
| 2205 | + args.Player.SendInfoMessage("Type /tpchest help to get more information about this command."); |
| 2206 | + return; |
| 2207 | + } |
| 2208 | + |
| 2209 | + DPoint[] chestLocations; |
| 2210 | + if (!this.scanChestsResults.TryGetValue(args.Player, out chestLocations)) { |
| 2211 | + args.Player.SendErrorMessage("You have to use /scanchests before using this command."); |
| 2212 | + return; |
| 2213 | + } |
| 2214 | + |
| 2215 | + int chestIndex; |
| 2216 | + if (!int.TryParse(args.Parameters[0], out chestIndex) || chestIndex < 1 || chestIndex > chestLocations.Length) { |
| 2217 | + args.Player.SendErrorMessage($"\"{args.Parameters[0]}\" is not a valid result index."); |
| 2218 | + return; |
| 2219 | + } |
| 2220 | + |
| 2221 | + DPoint chestLocation = chestLocations[chestIndex - 1]; |
| 2222 | + args.Player.Teleport(chestLocation.X * 16, chestLocation.Y * 16); |
| 2223 | + } |
| 2224 | + |
| 2225 | + private bool TpChestCommand_HelpCallback(CommandArgs args) { |
| 2226 | + if (args == null || this.IsDisposed) |
| 2227 | + return false; |
| 2228 | + |
| 2229 | + int pageNumber; |
| 2230 | + if (!PaginationTools.TryParsePageNumber(args.Parameters, 1, args.Player, out pageNumber)) |
| 2231 | + return false; |
| 2232 | + |
| 2233 | + switch (pageNumber) { |
| 2234 | + default: |
| 2235 | + args.Player.SendMessage("Command reference for /tpchest (Page 1 of 1)", Color.Lime); |
| 2236 | + args.Player.SendMessage("/tpchest <result index>", Color.White); |
| 2237 | + args.Player.SendMessage("Teleports you to a chest that was found by the /scanchests command.", Color.LightGray); |
| 2238 | + args.Player.SendMessage(string.Empty, Color.LightGray); |
| 2239 | + args.Player.SendMessage("result index = The index of the search result.", Color.LightGray); |
| 2240 | + break; |
| 2241 | + } |
| 2242 | + |
| 2243 | + return true; |
| 2244 | + } |
| 2245 | + #endregion |
| 2246 | + |
2083 | 2247 | #region [Hook Handlers] |
2084 | 2248 | public override bool HandleTileEdit(TSPlayer player, TileEditType editType, int blockType, DPoint location, int objectStyle) { |
2085 | 2249 | return this.HandleTileEdit(player, editType, blockType, location, objectStyle, false); |
|
0 commit comments