This change moves the ban checks used to determine, during TileEdit events, if an item is banned, out of Bouncer and into the newly isolated ItemBan subsystem. Rather than creating a large pull request for all of these, I'm just going to create a series of commits and send them in one at a time. This should result in about one PR per hook that uses item bans that needs to move.
238 lines
7.6 KiB
C#
238 lines
7.6 KiB
C#
/*
|
|
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 <http://www.gnu.org/licenses/>.
|
|
*/
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using Terraria.ID;
|
|
using TShockAPI.DB;
|
|
using TShockAPI.Net;
|
|
using Terraria;
|
|
using Microsoft.Xna.Framework;
|
|
using OTAPI.Tile;
|
|
using TShockAPI.Localization;
|
|
using static TShockAPI.GetDataHandlers;
|
|
using TerrariaApi.Server;
|
|
using Terraria.ObjectData;
|
|
using Terraria.DataStructures;
|
|
using Terraria.Localization;
|
|
using System.Data;
|
|
|
|
namespace TShockAPI
|
|
{
|
|
/// <summary>The TShock item ban subsystem. It handles keeping things out of people's inventories.</summary>
|
|
internal sealed class ItemBans
|
|
{
|
|
|
|
/// <summary>The database connection layer to for the item ban subsystem.</summary>
|
|
private ItemManager DataModel;
|
|
|
|
/// <summary>The last time the second update process was run. Used to throttle task execution.</summary>
|
|
private DateTime LastTimelyRun = DateTime.UtcNow;
|
|
|
|
/// <summary>A reference to the TShock plugin so we can register events.</summary>
|
|
private TShock Plugin;
|
|
|
|
/// <summary>Creates an ItemBan system given a plugin to register events to and a database.</summary>
|
|
/// <param name="plugin">The executing plugin.</param>
|
|
/// <param name="database">The database the item ban information is stored in.</param>
|
|
/// <returns>A new item ban system.</returns>
|
|
internal ItemBans(TShock plugin, IDbConnection database)
|
|
{
|
|
DataModel = new ItemManager(database);
|
|
Plugin = plugin;
|
|
|
|
ServerApi.Hooks.GameUpdate.Register(plugin, OnGameUpdate);
|
|
GetDataHandlers.PlayerUpdate += OnPlayerUpdate;
|
|
GetDataHandlers.ChestItemChange += OnChestItemChange;
|
|
GetDataHandlers.TileEdit += OnTileEdit;
|
|
}
|
|
|
|
/// <summary>Called on the game update loop (the XNA tickrate).</summary>
|
|
/// <param name="args">The standard event arguments.</param>
|
|
internal void OnGameUpdate(EventArgs args)
|
|
{
|
|
if ((DateTime.UtcNow - LastTimelyRun).TotalSeconds >= 1)
|
|
{
|
|
OnSecondlyUpdate(args);
|
|
}
|
|
}
|
|
|
|
/// <summary>Called by OnGameUpdate once per second to execute tasks regularly but not too often.</summary>
|
|
/// <param name="args">The standard event arguments.</param>
|
|
internal void OnSecondlyUpdate(EventArgs args)
|
|
{
|
|
DisableFlags disableFlags = TShock.Config.DisableSecondUpdateLogs ? DisableFlags.WriteToConsole : DisableFlags.WriteToLogAndConsole;
|
|
|
|
foreach (TSPlayer player in TShock.Players)
|
|
{
|
|
if (player == null || !player.Active)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
// Untaint now, re-taint if they fail the check.
|
|
UnTaint(player);
|
|
|
|
// No matter the player type, we do a check when a player is holding an item that's banned.
|
|
if (DataModel.ItemIsBanned(EnglishLanguage.GetItemNameById(player.TPlayer.inventory[player.TPlayer.selectedItem].netID), player))
|
|
{
|
|
string itemName = player.TPlayer.inventory[player.TPlayer.selectedItem].Name;
|
|
player.Disable($"holding banned item: {itemName}", disableFlags);
|
|
SendCorrectiveMessage(player, itemName);
|
|
}
|
|
|
|
// If SSC isn't enabled OR if SSC is enabled and the player is logged in
|
|
// In a case like this, we do the full check too.
|
|
if (!Main.ServerSideCharacter || (Main.ServerSideCharacter && player.IsLoggedIn))
|
|
{
|
|
// The Terraria inventory is composed of a multicultural set of arrays
|
|
// with various different contents and beliefs
|
|
|
|
// Armor ban checks
|
|
foreach (Item item in player.TPlayer.armor)
|
|
{
|
|
if (DataModel.ItemIsBanned(EnglishLanguage.GetItemNameById(item.type), player))
|
|
{
|
|
Taint(player);
|
|
SendCorrectiveMessage(player, item.Name);
|
|
}
|
|
}
|
|
|
|
// Dye ban checks
|
|
foreach (Item item in player.TPlayer.dye)
|
|
{
|
|
if (DataModel.ItemIsBanned(EnglishLanguage.GetItemNameById(item.type), player))
|
|
{
|
|
Taint(player);
|
|
SendCorrectiveMessage(player, item.Name);
|
|
}
|
|
}
|
|
|
|
// Misc equip ban checks
|
|
foreach (Item item in player.TPlayer.miscEquips)
|
|
{
|
|
if (DataModel.ItemIsBanned(EnglishLanguage.GetItemNameById(item.type), player))
|
|
{
|
|
Taint(player);
|
|
SendCorrectiveMessage(player, item.Name);
|
|
}
|
|
}
|
|
|
|
// Misc dye ban checks
|
|
foreach (Item item in player.TPlayer.miscDyes)
|
|
{
|
|
if (DataModel.ItemIsBanned(EnglishLanguage.GetItemNameById(item.type), player))
|
|
{
|
|
Taint(player);
|
|
SendCorrectiveMessage(player, item.Name);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Set the update time to now, so that we know when to execute next.
|
|
// We do this at the end so that the task can't re-execute faster than we expected.
|
|
// (If we did this at the start of the method, the method execution would count towards the timer.)
|
|
LastTimelyRun = DateTime.UtcNow;
|
|
}
|
|
|
|
internal void OnPlayerUpdate(object sender, PlayerUpdateEventArgs args)
|
|
{
|
|
DisableFlags disableFlags = TShock.Config.DisableSecondUpdateLogs ? DisableFlags.WriteToConsole : DisableFlags.WriteToLogAndConsole;
|
|
bool useItem = ((BitsByte) args.Control)[5];
|
|
TSPlayer player = args.Player;
|
|
string itemName = player.TPlayer.inventory[args.Item].Name;
|
|
|
|
if (DataModel.ItemIsBanned(EnglishLanguage.GetItemNameById(player.TPlayer.inventory[args.Item].netID), args.Player))
|
|
{
|
|
player.TPlayer.controlUseItem = false;
|
|
player.Disable($"holding banned item: {itemName}", disableFlags);
|
|
|
|
SendCorrectiveMessage(player, itemName);
|
|
|
|
player.TPlayer.Update(player.TPlayer.whoAmI);
|
|
NetMessage.SendData((int)PacketTypes.PlayerUpdate, -1, player.Index, NetworkText.Empty, player.Index);
|
|
|
|
args.Handled = true;
|
|
return;
|
|
}
|
|
|
|
args.Handled = false;
|
|
return;
|
|
}
|
|
|
|
internal void OnChestItemChange(object sender, ChestItemEventArgs args)
|
|
{
|
|
Item item = new Item();
|
|
item.netDefaults(args.Type);
|
|
|
|
|
|
if (DataModel.ItemIsBanned(EnglishLanguage.GetItemNameById(item.type), args.Player))
|
|
{
|
|
SendCorrectiveMessage(args.Player, item.Name);
|
|
args.Handled = true;
|
|
return;
|
|
}
|
|
|
|
args.Handled = false;
|
|
return;
|
|
}
|
|
|
|
internal void OnTileEdit(object sender, TileEditEventArgs args)
|
|
{
|
|
if (args.Action == EditAction.PlaceTile || args.Action == EditAction.PlaceWall)
|
|
{
|
|
if (args.Player.TPlayer.autoActuator && DataModel.ItemIsBanned("Actuator", args.Player))
|
|
{
|
|
args.Player.SendTileSquare(args.X, args.Y, 1);
|
|
args.Player.SendErrorMessage("You do not have permission to place actuators.");
|
|
args.Handled = true;
|
|
return;
|
|
}
|
|
|
|
if (DataModel.ItemIsBanned(EnglishLanguage.GetItemNameById(args.Player.SelectedItem.netID), args.Player))
|
|
{
|
|
args.Player.SendTileSquare(args.X, args.Y, 4);
|
|
args.Handled = true;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
private void UnTaint(TSPlayer player)
|
|
{
|
|
player.IsDisabledForBannedWearable = false;
|
|
}
|
|
|
|
private void Taint(TSPlayer player)
|
|
{
|
|
// Arbitrarily does things to the player
|
|
player.SetBuff(BuffID.Frozen, 330, true);
|
|
player.SetBuff(BuffID.Stoned, 330, true);
|
|
player.SetBuff(BuffID.Webbed, 330, true);
|
|
|
|
// Marks them as a target for future disables
|
|
player.IsDisabledForBannedWearable = true;
|
|
}
|
|
|
|
private void SendCorrectiveMessage(TSPlayer player, string itemName)
|
|
{
|
|
player.SendErrorMessage("{0} is banned! Remove it!", itemName);
|
|
}
|
|
}
|
|
}
|