RoR2-AntiYoink/AntiYoink/AntiYoink.cs

153 lines
5.8 KiB
C#
Raw Permalink Normal View History

2024-09-15 18:49:00 +01:00
using BepInEx;
2024-09-16 01:42:19 +01:00
using BepInEx.Configuration;
2024-09-15 18:49:00 +01:00
using R2API;
2024-09-16 01:42:19 +01:00
using R2API.Utils;
2024-09-15 18:49:00 +01:00
using RoR2;
using UnityEngine;
2024-09-16 01:42:19 +01:00
using UnityEngine.Networking;
2024-09-15 18:49:00 +01:00
namespace AntiYoink
{
// This attribute specifies that we have a dependency on a given BepInEx Plugin,
// We need the R2API ItemAPI dependency because we are using for adding our item to the game.
// You don't need this if you're not using R2API in your plugin,
// it's just to tell BepInEx to initialize R2API before this plugin so it's safe to use R2API.
[BepInDependency(ItemAPI.PluginGUID)]
// This one is because we use a .language file for language tokens
// More info in https://risk-of-thunder.github.io/R2Wiki/Mod-Creation/Assets/Localization/
[BepInDependency(LanguageAPI.PluginGUID)]
// This attribute is required, and lists metadata for your plugin.
[BepInPlugin(PluginGUID, PluginName, PluginVersion)]
2024-09-16 01:42:19 +01:00
// We only do server-side stuff :)
[NetworkCompatibility(compatibility: CompatibilityLevel.NoNeedForSync)]
2024-09-15 18:49:00 +01:00
// This is the main declaration of our plugin class.
// BepInEx searches for all classes inheriting from BaseUnityPlugin to initialize on startup.
// BaseUnityPlugin itself inherits from MonoBehaviour,
// so you can use this as a reference for what you can declare and use in your plugin class
// More information in the Unity Docs: https://docs.unity3d.com/ScriptReference/MonoBehaviour.html
2024-09-16 01:42:19 +01:00
public class AntiYoinkPlugin : BaseUnityPlugin
2024-09-15 18:49:00 +01:00
{
// The Plugin GUID should be a unique ID for this plugin,
// which is human readable (as it is used in places like the config).
public const string PluginGUID = PluginAuthor + "." + PluginName;
public const string PluginAuthor = "devplayer0";
public const string PluginName = "AntiYoink";
public const string PluginVersion = "0.1.0";
2024-09-16 01:42:19 +01:00
private const bool DevMode = true;
public static ConfigEntry<uint> MaxItemCountDelta { get; set; }
private float naughtyLast = 0;
2024-09-15 18:49:00 +01:00
// The Awake() method is run at the very start when the game is initialized.
public void Awake()
{
// Init our logging class so that we can properly log for debugging
Log.Init(Logger);
2024-09-16 01:42:19 +01:00
MaxItemCountDelta = Config.Bind<uint>(
"General",
"MaxItemCountDelta",
3,
"Maximum delta between player with the lowest number of items");
if (DevMode)
{
On.RoR2.Networking.NetworkManagerSystemSteam.OnClientConnect += (s, u, t) => { };
}
2024-09-15 18:49:00 +01:00
}
2024-09-16 01:42:19 +01:00
public void OnEnable()
2024-09-15 18:49:00 +01:00
{
2024-09-16 01:42:19 +01:00
On.RoR2.GenericPickupController.AttemptGrant += GenericPickupController_AttemptGrant;
On.RoR2.PickupPickerController.OnInteractionBegin += PickupPickerController_OnInteractionBegin;
}
public void OnDisable()
{
On.RoR2.GenericPickupController.AttemptGrant -= GenericPickupController_AttemptGrant;
On.RoR2.PickupPickerController.OnInteractionBegin -= PickupPickerController_OnInteractionBegin;
}
public static int GetTotalItems(Inventory inv)
{
int itemCount = 0;
foreach (var i in inv.itemAcquisitionOrder)
2024-09-15 18:49:00 +01:00
{
2024-09-16 01:42:19 +01:00
if (ItemCatalog.GetItemDef(i).hidden) continue;
itemCount += inv.GetItemCount(i);
2024-09-15 18:49:00 +01:00
}
2024-09-16 01:42:19 +01:00
return itemCount;
}
private bool AllowedToPickUp(CharacterBody body)
{
CharacterBody lowestPlayer = body;
int yoinkerItemCount = GetTotalItems(body.inventory);
int delta = 0;
foreach (var player in PlayerCharacterMasterController.instances)
{
var playerBody = player.master.GetBody();
if (!playerBody || !playerBody.healthComponent.alive || playerBody == body) continue;
2024-09-15 18:49:00 +01:00
2024-09-16 01:42:19 +01:00
int itemCount = GetTotalItems(playerBody.inventory);
if (yoinkerItemCount - itemCount > delta)
{
lowestPlayer = playerBody;
delta = yoinkerItemCount - itemCount;
}
}
if (lowestPlayer != body && delta > MaxItemCountDelta.Value)
2024-09-15 18:49:00 +01:00
{
2024-09-16 01:42:19 +01:00
if (Run.instance.time - naughtyLast > 1)
2024-09-15 18:49:00 +01:00
{
2024-09-16 01:42:19 +01:00
ChatMessage.Send($"<color=#ff0000>Naughty, naughty! {body.GetUserName()} has {delta} more items than poor {lowestPlayer.GetUserName()}");
naughtyLast = Run.instance.time;
2024-09-15 18:49:00 +01:00
}
2024-09-16 01:42:19 +01:00
return false;
2024-09-15 18:49:00 +01:00
}
2024-09-16 01:42:19 +01:00
return true;
2024-09-15 18:49:00 +01:00
}
2024-09-16 01:42:19 +01:00
private void GenericPickupController_AttemptGrant(On.RoR2.GenericPickupController.orig_AttemptGrant orig, GenericPickupController self, CharacterBody body)
2024-09-15 18:49:00 +01:00
{
2024-09-16 01:42:19 +01:00
if (!NetworkServer.active)
2024-09-15 18:49:00 +01:00
{
2024-09-16 01:42:19 +01:00
Debug.LogWarning("[Server] AntiYoink hook function 'GenericPickupController_AttemptGrant' called on client");
return;
}
TeamComponent component = body.GetComponent<TeamComponent>();
if (!component || component.teamIndex != TeamIndex.Player)
{
return;
}
2024-09-15 18:49:00 +01:00
2024-09-16 01:42:19 +01:00
if (!AllowedToPickUp(body)) {
return;
}
orig(self, body);
}
2024-09-15 18:49:00 +01:00
2024-09-16 01:42:19 +01:00
// For Artifact of Command
private void PickupPickerController_OnInteractionBegin(On.RoR2.PickupPickerController.orig_OnInteractionBegin orig, PickupPickerController self, Interactor activator)
{
if (NetworkServer.active)
{
CharacterBody body = activator.GetComponent<CharacterBody>();
if (body && !AllowedToPickUp(body))
{
return;
}
2024-09-15 18:49:00 +01:00
}
2024-09-16 01:42:19 +01:00
orig(self, activator);
2024-09-15 18:49:00 +01:00
}
}
}