-
-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added a new VMod: ChestPvPProtection
- Loading branch information
1 parent
6baf5e7
commit f4e3a10
Showing
11 changed files
with
856 additions
and
3 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
25 changes: 25 additions & 0 deletions
25
ChestPvPProtection/Configs/ChestPvPProtectionSystemConfig.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
using BepInEx.Configuration; | ||
|
||
namespace VMods.ChestPvPProtection | ||
{ | ||
public static class ChestPvPProtectionSystemConfig | ||
{ | ||
#region Properties | ||
|
||
public static ConfigEntry<bool> ChestPvPProtectionEnabled { get; private set; } | ||
|
||
public static ConfigEntry<bool> ChestPvPProtectionSendMessage { get; private set; } | ||
|
||
#endregion | ||
|
||
#region Public Methods | ||
|
||
public static void Initialize(ConfigFile config) | ||
{ | ||
ChestPvPProtectionEnabled = config.Bind(nameof(ChestPvPProtection), nameof(ChestPvPProtectionEnabled), false, "Enabled/disable the Chest PvP Protection system."); | ||
ChestPvPProtectionSendMessage = config.Bind(nameof(ChestPvPProtection), nameof(ChestPvPProtectionSendMessage), true, "Enabled/disable the sending of a system message to the player with the PvP Protection buff that's attempting to interact with an enemy player's chest."); | ||
} | ||
|
||
#endregion | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,158 @@ | ||
using HarmonyLib; | ||
using ProjectM; | ||
using ProjectM.Network; | ||
using Unity.Collections; | ||
using Unity.Entities; | ||
using VMods.Shared; | ||
using Wetstone.API; | ||
|
||
namespace VMods.ChestPvPProtection | ||
{ | ||
[HarmonyPatch] | ||
public static class InventoryHooks | ||
{ | ||
#region Events | ||
|
||
public delegate void InventoryInteractionEventHandler(Entity eventEntity, VModCharacter vmodCharacter, params Entity[] inventoryEntities); | ||
public static event InventoryInteractionEventHandler InventoryInteractionEvent; | ||
private static void FireInventoryInteractionEvent(Entity eventEntity, VModCharacter vmodCharacter, params Entity[] inventoryEntities) => InventoryInteractionEvent?.Invoke(eventEntity, vmodCharacter, inventoryEntities); | ||
|
||
#endregion | ||
|
||
#region Private Methods | ||
|
||
[HarmonyPatch(typeof(MoveItemBetweenInventoriesSystem), nameof(MoveItemBetweenInventoriesSystem.OnUpdate))] | ||
[HarmonyPrefix] | ||
private static void MoveItemBetweenInventories(MoveItemBetweenInventoriesSystem __instance) | ||
{ | ||
if(!VWorld.IsServer || __instance._MoveItemBetweenInventoriesEventQuery == null) | ||
{ | ||
return; | ||
} | ||
|
||
var server = VWorld.Server; | ||
var entityManager = server.EntityManager; | ||
var networkIdToEntityMap = __instance._NetworkIdSystem._NetworkIdToEntityMap; | ||
|
||
var entities = __instance._MoveItemBetweenInventoriesEventQuery.ToEntityArray(Allocator.Temp); | ||
foreach(var entity in entities) | ||
{ | ||
var fromCharacter = new VModCharacter(entityManager.GetComponentData<FromCharacter>(entity), entityManager); | ||
var moveEvent = entityManager.GetComponentData<MoveItemBetweenInventoriesEvent>(entity); | ||
FireInventoryInteractionEvent(entity, fromCharacter, moveEvent.FromInventory.GetNetworkedEntity(networkIdToEntityMap)._Entity, moveEvent.ToInventory.GetNetworkedEntity(networkIdToEntityMap)._Entity); | ||
} | ||
} | ||
|
||
[HarmonyPatch(typeof(MoveAllItemsBetweenInventoriesSystem), nameof(MoveAllItemsBetweenInventoriesSystem.OnUpdate))] | ||
[HarmonyPrefix] | ||
private static void MoveAllItemsBetweenInventories(MoveAllItemsBetweenInventoriesSystem __instance) | ||
{ | ||
if(!VWorld.IsServer || __instance.__MoveAllItemsJob_entityQuery == null) | ||
{ | ||
return; | ||
} | ||
|
||
var server = VWorld.Server; | ||
var entityManager = server.EntityManager; | ||
var networkIdToEntityMap = __instance._NetworkIdSystem._NetworkIdToEntityMap; | ||
|
||
var entities = __instance.__MoveAllItemsJob_entityQuery.ToEntityArray(Allocator.Temp); | ||
foreach(var entity in entities) | ||
{ | ||
var fromCharacter = new VModCharacter(entityManager.GetComponentData<FromCharacter>(entity), entityManager); | ||
var moveEvent = entityManager.GetComponentData<MoveAllItemsBetweenInventoriesEvent>(entity); | ||
FireInventoryInteractionEvent(entity, fromCharacter, moveEvent.FromInventory.GetNetworkedEntity(networkIdToEntityMap)._Entity, moveEvent.ToInventory.GetNetworkedEntity(networkIdToEntityMap)._Entity); | ||
} | ||
} | ||
|
||
[HarmonyPatch(typeof(DropInventoryItemSystem), nameof(DropInventoryItemSystem.OnUpdate))] | ||
[HarmonyPrefix] | ||
private static void DropInventoryItem(DropInventoryItemSystem __instance) | ||
{ | ||
if(!VWorld.IsServer || __instance.__DropInventoryItemJob_entityQuery == null) | ||
{ | ||
return; | ||
} | ||
|
||
var server = VWorld.Server; | ||
var entityManager = server.EntityManager; | ||
var networkIdToEntityMap = __instance._NetworkIdSystem._NetworkIdToEntityMap; | ||
|
||
var entities = __instance.__DropInventoryItemJob_entityQuery.ToEntityArray(Allocator.Temp); | ||
foreach(var entity in entities) | ||
{ | ||
var fromCharacter = new VModCharacter(entityManager.GetComponentData<FromCharacter>(entity), entityManager); | ||
var dropEvent = entityManager.GetComponentData<DropInventoryItemEvent>(entity); | ||
FireInventoryInteractionEvent(entity, fromCharacter, dropEvent.Inventory.GetNetworkedEntity(networkIdToEntityMap)._Entity); | ||
} | ||
} | ||
|
||
[HarmonyPatch(typeof(SplitItemSystem), nameof(SplitItemSystem.OnUpdate))] | ||
[HarmonyPrefix] | ||
private static void SplitItem(SplitItemSystem __instance) | ||
{ | ||
if(!VWorld.IsServer || __instance._Query == null) | ||
{ | ||
return; | ||
} | ||
|
||
var server = VWorld.Server; | ||
var entityManager = server.EntityManager; | ||
var networkIdToEntityMap = __instance._NetworkIdSystem._NetworkIdToEntityMap; | ||
|
||
var entities = __instance._Query.ToEntityArray(Allocator.Temp); | ||
foreach(var entity in entities) | ||
{ | ||
var fromCharacter = new VModCharacter(entityManager.GetComponentData<FromCharacter>(entity), entityManager); | ||
var splitEvent = entityManager.GetComponentData<SplitItemEvent>(entity); | ||
FireInventoryInteractionEvent(entity, fromCharacter, splitEvent.Inventory.GetNetworkedEntity(networkIdToEntityMap)._Entity); | ||
} | ||
} | ||
|
||
[HarmonyPatch(typeof(SortAllItemsSystem), nameof(SortAllItemsSystem.OnUpdate))] | ||
[HarmonyPrefix] | ||
private static void SortAllItems(SplitItemSystem __instance) | ||
{ | ||
if(!VWorld.IsServer || __instance._Query == null) | ||
{ | ||
return; | ||
} | ||
|
||
var server = VWorld.Server; | ||
var entityManager = server.EntityManager; | ||
var networkIdToEntityMap = __instance._NetworkIdSystem._NetworkIdToEntityMap; | ||
|
||
var entities = __instance._Query.ToEntityArray(Allocator.Temp); | ||
foreach(var entity in entities) | ||
{ | ||
var fromCharacter = new VModCharacter(entityManager.GetComponentData<FromCharacter>(entity), entityManager); | ||
var sortEvent = entityManager.GetComponentData<SortAllItemsEvent>(entity); | ||
FireInventoryInteractionEvent(entity, fromCharacter, sortEvent.Inventory.GetNetworkedEntity(networkIdToEntityMap)._Entity); | ||
} | ||
} | ||
|
||
[HarmonyPatch(typeof(SmartMergeItemsBetweenInventoriesSystem), nameof(SmartMergeItemsBetweenInventoriesSystem.OnUpdate))] | ||
[HarmonyPrefix] | ||
private static void SmartMergeItemsBetweenInventories(SplitItemSystem __instance) | ||
{ | ||
if(!VWorld.IsServer || __instance._Query == null) | ||
{ | ||
return; | ||
} | ||
|
||
var server = VWorld.Server; | ||
var entityManager = server.EntityManager; | ||
var networkIdToEntityMap = __instance._NetworkIdSystem._NetworkIdToEntityMap; | ||
|
||
var entities = __instance._Query.ToEntityArray(Allocator.Temp); | ||
foreach(var entity in entities) | ||
{ | ||
var fromCharacter = new VModCharacter(entityManager.GetComponentData<FromCharacter>(entity), entityManager); | ||
var mergeEvent = entityManager.GetComponentData<SmartMergeItemsBetweenInventoriesEvent>(entity); | ||
FireInventoryInteractionEvent(entity, fromCharacter, mergeEvent.FromInventory.GetNetworkedEntity(networkIdToEntityMap)._Entity, mergeEvent.ToInventory.GetNetworkedEntity(networkIdToEntityMap)._Entity); | ||
} | ||
} | ||
|
||
#endregion | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
using BepInEx; | ||
using BepInEx.IL2CPP; | ||
using HarmonyLib; | ||
using System.Reflection; | ||
using VMods.Shared; | ||
using Wetstone.API; | ||
|
||
namespace VMods.ChestPvPProtection | ||
{ | ||
[BepInPlugin(PluginInfo.PLUGIN_GUID, PluginInfo.PLUGIN_NAME, PluginInfo.PLUGIN_VERSION)] | ||
[BepInDependency("xyz.molenzwiebel.wetstone")] | ||
[Reloadable] | ||
public class Plugin : BasePlugin | ||
{ | ||
#region Variables | ||
|
||
private Harmony _hooks; | ||
|
||
#endregion | ||
|
||
#region Public Methods | ||
|
||
public sealed override void Load() | ||
{ | ||
if(VWorld.IsClient) | ||
{ | ||
Log.LogMessage($"{PluginInfo.PLUGIN_NAME} only needs to be installed server side."); | ||
return; | ||
} | ||
Utils.Initialize(Log, PluginInfo.PLUGIN_NAME); | ||
|
||
ChestPvPProtectionSystemConfig.Initialize(Config); | ||
|
||
ChestPvPProtectionSystem.Initialize(); | ||
|
||
_hooks = Harmony.CreateAndPatchAll(Assembly.GetExecutingAssembly()); | ||
|
||
Log.LogInfo($"Plugin {PluginInfo.PLUGIN_NAME} (v{PluginInfo.PLUGIN_VERSION}) is loaded!"); | ||
} | ||
|
||
public sealed override bool Unload() | ||
{ | ||
if(VWorld.IsClient) | ||
{ | ||
return true; | ||
} | ||
_hooks?.UnpatchSelf(); | ||
ChestPvPProtectionSystem.Deinitialize(); | ||
Config.Clear(); | ||
Utils.Deinitialize(); | ||
return true; | ||
} | ||
|
||
#endregion | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
using ProjectM; | ||
using ProjectM.Network; | ||
using ProjectM.Scripting; | ||
using System.Linq; | ||
using Unity.Entities; | ||
using VMods.Shared; | ||
using Wetstone.API; | ||
|
||
namespace VMods.ChestPvPProtection | ||
{ | ||
public static class ChestPvPProtectionSystem | ||
{ | ||
#region Public Methods | ||
|
||
public static void Initialize() | ||
{ | ||
InventoryHooks.InventoryInteractionEvent += OnInventoryInteraction; | ||
} | ||
|
||
public static void Deinitialize() | ||
{ | ||
InventoryHooks.InventoryInteractionEvent -= OnInventoryInteraction; | ||
} | ||
|
||
#endregion | ||
|
||
#region Private Methods | ||
|
||
private static void OnInventoryInteraction(Entity eventEntity, VModCharacter vmodCharacter, params Entity[] inventoryEntities) | ||
{ | ||
if(!ChestPvPProtectionSystemConfig.ChestPvPProtectionEnabled.Value) | ||
{ | ||
return; | ||
} | ||
|
||
var server = VWorld.Server; | ||
var entityManager = server.EntityManager; | ||
var teamChecker = server.GetExistingSystem<ServerScriptMapper>()._ServerGameManager._TeamChecker; | ||
|
||
if(!vmodCharacter.HasBuff(Utils.PvPProtectionBuff) || vmodCharacter.User.IsAdmin) | ||
{ | ||
return; | ||
} | ||
|
||
var playerTeam = entityManager.GetComponentData<Team>(vmodCharacter.FromCharacter.Character); | ||
var teams = inventoryEntities.Select(FindTeam); | ||
|
||
// Check if the player is not an ally and the inventory isn't neutral (i.e. an npc chest) of any inventory | ||
if(teams.Any(team => !teamChecker.IsAllies(playerTeam, team) && !teamChecker.IsNeutral(team))) | ||
{ | ||
entityManager.AddComponent<DestroyTag>(eventEntity); | ||
if(ChestPvPProtectionSystemConfig.ChestPvPProtectionSendMessage.Value) | ||
{ | ||
Utils.SendMessage(vmodCharacter.FromCharacter.User, $"Cannot interact with enemy Chests/Workstations while PvP Protected", ServerChatMessageType.System); | ||
} | ||
} | ||
|
||
// Nested Method(s) | ||
Team FindTeam(Entity entity) | ||
{ | ||
if(entityManager.HasComponent<Team>(entity)) | ||
{ | ||
return entityManager.GetComponentData<Team>(entity); | ||
} | ||
else | ||
{ | ||
// Workstations don't have a team but are attached, thus retrieve the team of the station's parent. | ||
var attach = entityManager.GetComponentData<Attach>(entity); | ||
return entityManager.GetComponentData<Team>(attach.Parent); | ||
} | ||
} | ||
} | ||
|
||
#endregion | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
# Chest PvP Protection | ||
A server-side only mod that prevents looting of enemy player chests/workstations by players with the PvP Protection buff. | ||
|
||
Besides looting, it'll also prevent moving, sorting, swapping and merging ("compilsively count") of items within those chests/workstations. | ||
|
||
## How to manually install | ||
* Install [BepInEx](https://v-rising.thunderstore.io/package/BepInEx/BepInExPack_V_Rising/) | ||
* Install [Wetstone](https://v-rising.thunderstore.io/package/molenzwiebel/Wetstone/) | ||
* (Locally hosted games only) Install [ServerLaunchFix](https://v-rising.thunderstore.io/package/Mythic/ServerLaunchFix/) | ||
* Extract the Vmods._mod-name_.dll | ||
* Move the desired mod(s) to the `[VRising (server) folder]/BepInEx/WetstonePlugins/` | ||
* Launch the server (or game) to auto-generate the config files | ||
* Edit the configs as you desire (found in `[VRising (server) folder]/BepInEx/config/`) | ||
* Reload the mods using the Wetstone commands (by default F6 for client-side mods, and/or `!reload` for server-side mods) | ||
* If this doesn't work, or isn't enabled, restart the server/game | ||
|
||
## Commands | ||
Most of the VMods come with a set of commands that can be used. To see the available commands, by default a player or admin can use `!help`. | ||
Normal players won't see the Admin-only commands listed. | ||
The prefix (`!`) can be changed on a per-mod basis. | ||
To prevent spam/abuse there's also a command cooldown for non-admins, this value can also be tweaked on a per-mod basis. | ||
Commands can also be disabled completely on a per-mod basis. | ||
|
||
## More Details | ||
* [ChangeLog](https://github.com/WhiteFang5/VMods/blob/master/CHANGELOG.md#chest-pvp-protection) |
Oops, something went wrong.