* Remove commented out warning disable * Add initial ItemBans segregation infrastructure * Add shell for initial OnSecondUpdate stuff * Add comments yo * Remove duplicated logic * Split out more item ban code This part of the fragments work is primarily aimed at reducing the complexity of OnSecondUpdate in TShock and moving that check out into the ItemBans subsytem. Of major note in this is the removal of "check", which was a string variable that tracked state and replacement of many of the item ban activities with sane private methods that are at least somewhat sensible. Obviously there's a lot to be desired in this system and I'm really going for a run here by trying to continue a branch from so long ago that I barely even remember the whole point of existence. Still to do: GetDataHandlers related item ban code needs to be moved into its own hook in the ItemBan system. Finally, there is a downside to some of this: we're basically iterating over players again and again if we keep this pattern up, which is kinda lame for complexity purposes. * alt j: comment changes * Move item ban check out of main playerupdate check Separates out item ban logic from the rest of GetDataHandlers so that item bans is more isolated in terms of what fragments is asking for. * alt-j: convert indentation to tabs * alt-j: fix botching source code * Move item ban related chest checks out of gdh * Remove chest item change detection from item bans It doesn't do anything. If a user removes an item from a chest, it bypasses this check. If a user adds an item to a chest, the server seems to persist the change anyway, even if the event is handled. That's a bug for sure, but fundamentally, it's not the item ban system's fault. * Revert "Remove chest item change detection from item bans" This reverts commit 758541ac5c4d4096df2db05ba2a398968113e1e4. * Fix logic issues related to item ban handling Re-implements chest item handling and correctly handles events and returns after setting handled event state. * Remove TSPlayer.HasProjectilePermission In infinite wisdom, it turns out this is not a good method for TSPlayer to have. It just checks the states of things as per what the item ban system says is banned and then creates implicit relationships to the projectile ban system. Doing this effectively knocks down another external reference to the item ban system outside of the context of the implementation for the system itself and its related hooks. This commit also adds context around what the heck is going on with some of our more interesting checks as per discussions in Telegram with @Ijwu and @QuiCM. * Update changelog * Remove useless ref to Projectile.SetDefaults * Change item ban to ban based on ID not strings I think I was so confused as to why we were passing strings everywhere that I just felt inclined to continue the trend in previous commits.
216 lines
6.9 KiB
C#
216 lines
6.9 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;
|
|
}
|
|
|
|
/// <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;
|
|
}
|
|
|
|
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);
|
|
}
|
|
}
|
|
}
|