153 lines
5.8 KiB
C#
153 lines
5.8 KiB
C#
using BepInEx;
|
|
using BepInEx.Configuration;
|
|
using R2API;
|
|
using R2API.Utils;
|
|
using RoR2;
|
|
using UnityEngine;
|
|
using UnityEngine.Networking;
|
|
|
|
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)]
|
|
|
|
// We only do server-side stuff :)
|
|
[NetworkCompatibility(compatibility: CompatibilityLevel.NoNeedForSync)]
|
|
|
|
// 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
|
|
public class AntiYoinkPlugin : BaseUnityPlugin
|
|
{
|
|
// 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";
|
|
|
|
private const bool DevMode = true;
|
|
|
|
public static ConfigEntry<uint> MaxItemCountDelta { get; set; }
|
|
|
|
private float naughtyLast = 0;
|
|
|
|
// 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);
|
|
|
|
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) => { };
|
|
}
|
|
}
|
|
|
|
public void OnEnable()
|
|
{
|
|
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)
|
|
{
|
|
if (ItemCatalog.GetItemDef(i).hidden) continue;
|
|
itemCount += inv.GetItemCount(i);
|
|
}
|
|
|
|
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;
|
|
|
|
int itemCount = GetTotalItems(playerBody.inventory);
|
|
if (yoinkerItemCount - itemCount > delta)
|
|
{
|
|
lowestPlayer = playerBody;
|
|
delta = yoinkerItemCount - itemCount;
|
|
}
|
|
}
|
|
if (lowestPlayer != body && delta > MaxItemCountDelta.Value)
|
|
{
|
|
if (Run.instance.time - naughtyLast > 1)
|
|
{
|
|
ChatMessage.Send($"<color=#ff0000>Naughty, naughty! {body.GetUserName()} has {delta} more items than poor {lowestPlayer.GetUserName()}");
|
|
naughtyLast = Run.instance.time;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
private void GenericPickupController_AttemptGrant(On.RoR2.GenericPickupController.orig_AttemptGrant orig, GenericPickupController self, CharacterBody body)
|
|
{
|
|
if (!NetworkServer.active)
|
|
{
|
|
Debug.LogWarning("[Server] AntiYoink hook function 'GenericPickupController_AttemptGrant' called on client");
|
|
return;
|
|
}
|
|
TeamComponent component = body.GetComponent<TeamComponent>();
|
|
if (!component || component.teamIndex != TeamIndex.Player)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (!AllowedToPickUp(body)) {
|
|
return;
|
|
}
|
|
|
|
orig(self, body);
|
|
}
|
|
|
|
// 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;
|
|
}
|
|
}
|
|
orig(self, activator);
|
|
}
|
|
}
|
|
}
|