From ec78a070a7da1adb726cb6a87d03ae729b47b6ba Mon Sep 17 00:00:00 2001 From: Ivan Date: Sun, 29 Apr 2018 18:33:07 +0200 Subject: [PATCH] Move Region related code into a separate subsystem --- TShockAPI/Bouncer.cs | 76 -------------- TShockAPI/DB/RegionManager.cs | 3 + TShockAPI/RegionHandler.cs | 189 ++++++++++++++++++++++++++++++++++ TShockAPI/TShock.cs | 22 ++-- TShockAPI/TShockAPI.csproj | 4 +- 5 files changed, 201 insertions(+), 93 deletions(-) create mode 100644 TShockAPI/RegionHandler.cs diff --git a/TShockAPI/Bouncer.cs b/TShockAPI/Bouncer.cs index 0c2c0f3e..f1ce0005 100644 --- a/TShockAPI/Bouncer.cs +++ b/TShockAPI/Bouncer.cs @@ -1232,82 +1232,6 @@ namespace TShockAPI return; } - // TODO: Remove from bouncer (does't look like Bouncer code) - if (args.Player.AwaitingName) - { - bool includeUnprotected = false; - bool includeZIndexes = false; - bool persistentMode = false; - foreach (string parameter in args.Player.AwaitingNameParameters) - { - if (parameter.Equals("-u", StringComparison.InvariantCultureIgnoreCase)) - includeUnprotected = true; - if (parameter.Equals("-z", StringComparison.InvariantCultureIgnoreCase)) - includeZIndexes = true; - if (parameter.Equals("-p", StringComparison.InvariantCultureIgnoreCase)) - persistentMode = true; - } - - - // TODO: REMOVE. This does NOT look like Bouncer code. - List outputRegions = new List(); - foreach (Region region in TShock.Regions.Regions.OrderBy(r => r.Z).Reverse()) - { - if (!includeUnprotected && !region.DisableBuild) - continue; - if (tileX < region.Area.Left || tileX > region.Area.Right) - continue; - if (tileY < region.Area.Top || tileY > region.Area.Bottom) - continue; - - string format = "{1}"; - if (includeZIndexes) - format = "{1} (z:{0})"; - - outputRegions.Add(string.Format(format, region.Z, region.Name)); - } - - if (outputRegions.Count == 0) - { - if (includeUnprotected) - args.Player.SendInfoMessage("There are no regions at this point."); - else - args.Player.SendInfoMessage("There are no regions at this point or they are not protected."); - } - else - { - if (includeUnprotected) - args.Player.SendSuccessMessage("Regions at this point:"); - else - args.Player.SendSuccessMessage("Protected regions at this point:"); - - foreach (string line in PaginationTools.BuildLinesFromTerms(outputRegions)) - args.Player.SendMessage(line, Color.White); - } - - if (!persistentMode) - { - args.Player.AwaitingName = false; - args.Player.AwaitingNameParameters = null; - } - - args.Player.SendTileSquare(tileX, tileY, 4); - args.Handled = true; - return; - } - - // TODO: REMOVE. This does NOT look like Bouncer code. - if (args.Player.AwaitingTempPoint > 0) - { - args.Player.TempPoints[args.Player.AwaitingTempPoint - 1].X = tileX; - args.Player.TempPoints[args.Player.AwaitingTempPoint - 1].Y = tileY; - args.Player.SendInfoMessage("Set temp point {0}.", args.Player.AwaitingTempPoint); - args.Player.SendTileSquare(tileX, tileY, 4); - args.Player.AwaitingTempPoint = 0; - args.Handled = true; - return; - } - Item selectedItem = args.Player.SelectedItem; int lastKilledProj = args.Player.LastKilledProjectile; ITile tile = Main.tile[tileX, tileY]; diff --git a/TShockAPI/DB/RegionManager.cs b/TShockAPI/DB/RegionManager.cs index 34a52f8e..3d5bea77 100644 --- a/TShockAPI/DB/RegionManager.cs +++ b/TShockAPI/DB/RegionManager.cs @@ -26,6 +26,9 @@ using Microsoft.Xna.Framework; namespace TShockAPI.DB { + /// + /// Represents the Region database manager. + /// public class RegionManager { /// diff --git a/TShockAPI/RegionHandler.cs b/TShockAPI/RegionHandler.cs new file mode 100644 index 00000000..12ab63dc --- /dev/null +++ b/TShockAPI/RegionHandler.cs @@ -0,0 +1,189 @@ +/* +TShock, a server mod for Terraria +Copyright (C) 2011-2018 Pryaxis & TShock Contributors +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ + +using System; +using System.Collections.Generic; +using System.Data; +using System.Linq; +using Microsoft.Xna.Framework; +using TerrariaApi.Server; +using TShockAPI.DB; +using TShockAPI.Hooks; + +namespace TShockAPI +{ + /// + /// Represents TShock's Region subsystem. This subsystem is in charge of executing region related logic, such as + /// setting temp points. + /// + internal sealed class RegionHandler + { + private readonly RegionManager _regionManager; + private DateTime _lastCheck = DateTime.Now; + + /// + /// Initializes a new instance of the class with the specified TShock instance and database connection. + /// + /// The instance. + /// The database connection. + public RegionHandler(TShock plugin, IDbConnection connection) + { + _regionManager = new RegionManager(connection); + + GetDataHandlers.TileEdit += OnTileEdit; + ServerApi.Hooks.GameUpdate.Register(plugin, OnGameUpdate); + } + + private void OnGameUpdate(EventArgs args) + { + // Do not perform checks unless enough time has passed since the last execution. + if ((DateTime.Now - _lastCheck).TotalSeconds < 1) + { + return; + } + + foreach (var player in TShock.Players.Where(p => p?.Active == true)) + { + // Store the player's last known region and update the current based on known regions at their coordinates. + var oldRegion = player.CurrentRegion; + player.CurrentRegion = _regionManager.GetTopRegion(_regionManager.InAreaRegion(player.TileX, player.TileY)); + + // Do not fire any hooks if the player has not left and/or entered a region. + if (player.CurrentRegion == oldRegion) + { + continue; + } + + // Ensure that the player has left a region before invoking the RegionLeft event + if (oldRegion != null) + { + RegionHooks.OnRegionLeft(player, oldRegion); + } + + // Ensure that the player has entered a valid region before invoking the RegionEntered event + if (player.CurrentRegion != null) + { + RegionHooks.OnRegionEntered(player, player.CurrentRegion); + } + } + + // Set last execution time to this moment so we know when to execute the above code block again + _lastCheck = DateTime.Now; + } + + private void OnTileEdit(object sender, GetDataHandlers.TileEditEventArgs e) + { + #region Region Information Display + + if (e.Player.AwaitingName) + { + bool includeUnprotected = false; + bool includeZIndexes = false; + bool persistentMode = false; + + foreach (string nameParameter in e.Player.AwaitingNameParameters) + { + // If this flag is passed the final output will include unprotected regions, i.e regions + // that do not have the DisableBuild flag set to false + if (nameParameter.Equals("-u", StringComparison.InvariantCultureIgnoreCase)) + { + includeUnprotected = true; + } + + // If this flag is passed the final output will include a region's Z index + if (nameParameter.Equals("-z", StringComparison.InvariantCultureIgnoreCase)) + { + includeZIndexes = true; + } + + // If this flag is passed the player will continue to receive region information upon editing tiles + if (nameParameter.Equals("-p", StringComparison.InvariantCultureIgnoreCase)) + { + persistentMode = true; + } + } + + var output = new List(); + foreach (Region region in _regionManager.Regions.OrderBy(r => r.Z).Reverse()) + { + // Ensure that the specified tile is region protected + if (e.X < region.Area.Left || e.X > region.Area.Right) + { + continue; + } + + if (e.Y < region.Area.Top || e.X > region.Area.Bottom) + { + continue; + } + + // Do not include the current region if it has not been protected and the includeProtected flag has not been set + if (!region.DisableBuild && !includeUnprotected) + { + continue; + } + + output.Add($"{region.Name} {(includeZIndexes ? $"(Z:{region.Z}" : string.Empty)}"); + } + + if (output.Count == 0) + { + e.Player.SendInfoMessage(includeUnprotected + ? "There are no regions at this point." + : "There are no regions at this point, or they are not protected."); + } + else + { + e.Player.SendInfoMessage(includeUnprotected ? "Regions at this point: " : "Protected regions at this point: "); + + foreach (string line in PaginationTools.BuildLinesFromTerms(output)) + { + e.Player.SendMessage(line, Color.White); + } + } + + if (!persistentMode) + { + e.Player.AwaitingName = false; + e.Player.AwaitingNameParameters = null; + } + + // Revert all tile changes and handle the event + e.Player.SendTileSquare(e.X, e.Y, 4); + e.Handled = true; + } + + #endregion + + #region TempPoints Setup + + if (e.Player.AwaitingTempPoint != 0) + { + // Set temp point coordinates to current tile coordinates + e.Player.TempPoints[e.Player.AwaitingTempPoint - 1].X = e.X; + e.Player.TempPoints[e.Player.AwaitingTempPoint - 1].Y = e.Y; + e.Player.SendInfoMessage($"Set temp point {e.Player.AwaitingTempPoint}."); + + e.Player.AwaitingTempPoint = 0; + + // Revert all tile changes and handle the event + e.Player.SendTileSquare(e.X, e.Y, 4); + e.Handled = true; + } + + #endregion + } + } +} diff --git a/TShockAPI/TShock.cs b/TShockAPI/TShock.cs index d309bd07..8e956e37 100644 --- a/TShockAPI/TShock.cs +++ b/TShockAPI/TShock.cs @@ -136,6 +136,11 @@ namespace TShockAPI /// The TShock anti-cheat/anti-exploit system. internal Bouncer Bouncer; + /// + /// TShock's Region subsystem. + /// + internal RegionHandler RegionSystem; + /// /// Called after TShock is initialized. Useful for plugins that needs hooks before tshock but also depend on tshock being loaded. /// @@ -321,6 +326,7 @@ namespace TShockAPI RestManager = new RestManager(RestApi); RestManager.RegisterRestfulCommands(); Bouncer = new Bouncer(); + RegionSystem = new RegionHandler(this, DB); var geoippath = "GeoIP.dat"; if (Config.EnableGeoIP && File.Exists(geoippath)) @@ -1144,22 +1150,6 @@ namespace TShockAPI player.SendErrorMessage($"You are holding a banned item: {player.TPlayer.inventory[player.TPlayer.selectedItem].Name}"); } } - - var oldRegion = player.CurrentRegion; - player.CurrentRegion = Regions.GetTopRegion(Regions.InAreaRegion(player.TileX, player.TileY)); - - if (oldRegion != player.CurrentRegion) - { - if (oldRegion != null) - { - RegionHooks.OnRegionLeft(player, oldRegion); - } - - if (player.CurrentRegion != null) - { - RegionHooks.OnRegionEntered(player, player.CurrentRegion); - } - } } } Utils.SetConsoleTitle(false); diff --git a/TShockAPI/TShockAPI.csproj b/TShockAPI/TShockAPI.csproj index b7bf6f8e..b00339d2 100644 --- a/TShockAPI/TShockAPI.csproj +++ b/TShockAPI/TShockAPI.csproj @@ -96,6 +96,7 @@ + @@ -193,6 +194,7 @@ TerrariaServerAPI + @@ -204,7 +206,7 @@ - +