diff --git a/Meds.Wrapper/Audit/AuditPayloads.cs b/Meds.Wrapper/Audit/AuditPayloads.cs index 9a97777..497eb9a 100644 --- a/Meds.Wrapper/Audit/AuditPayloads.cs +++ b/Meds.Wrapper/Audit/AuditPayloads.cs @@ -9,7 +9,9 @@ using Sandbox.Game; using Sandbox.Game.Entities; using Sandbox.Game.Players; +using VRage.Components.Entity.CubeGrid; using VRage.Game; +using VRage.Game.Entity; using VRage.Library.Utils; using VRageMath; using ZLogger; @@ -28,6 +30,9 @@ public enum AuditEvent MedievalMasterStart, MedievalMasterStop, + + ClipboardCut, + ClipboardPaste, } public class AuditPayload @@ -41,6 +46,8 @@ public class AuditPayload public ControlOpPayload? ControlOp; + public ClipboardOpPayload? ClipboardOp; + public static AuditPayload Create(AuditEvent evt, MyPlayer acting, MyPlayer owning = null, Vector3D? owningLocation = null) { var payload = new AuditPayload @@ -83,6 +90,12 @@ public AuditPayload ControlOpPayload(in ControlOpPayload payload) return this; } + public AuditPayload ClipboardOpPayload(in ClipboardOpPayload payload) + { + ClipboardOp = payload; + return this; + } + private static AuditLoggerHolder _logger; public void Emit() @@ -104,8 +117,8 @@ public void Emit() } log.Logger.ZLogInformationWithPayload(this, "{0} by {1} on {2} ({3})", AuditEvent, ActingPlayer.DisplayName, - InventoryOp?.ToEntity ?? InventoryOp?.FromEntity ?? ControlOp?.Entity, - OwningPlayer?.DisplayName); + InventoryOp?.ToEntity ?? InventoryOp?.FromEntity ?? ControlOp?.Entity, + OwningPlayer?.DisplayName); } private sealed class AuditLoggerHolder @@ -143,6 +156,24 @@ public struct ControlOpPayload public string Slot; } + public struct ClipboardOpPayload + { + public int Grids; + public int Blocks; + + public void Add(MyGridDataComponent grid) + { + Grids++; + Blocks += grid.BlockCount; + } + + public void Add(MyEntity entity) + { + if (entity.Components.TryGet(out MyGridDataComponent grid)) + Add(grid); + } + } + public struct PlayerPayload { public ulong SteamId; diff --git a/Meds.Wrapper/Audit/MedievalMasterAudit.cs b/Meds.Wrapper/Audit/MedievalMasterAudit.cs index 8f0991c..57ff8c3 100644 --- a/Meds.Wrapper/Audit/MedievalMasterAudit.cs +++ b/Meds.Wrapper/Audit/MedievalMasterAudit.cs @@ -1,9 +1,15 @@ +using System.Collections.Generic; using HarmonyLib; +using Medieval.GameSystems.Building; using Meds.Wrapper.Shim; using Sandbox.Game.Multiplayer; using Sandbox.Game.Players; +using Sandbox.Game.SessionComponents.Clipboard; using Sandbox.Game.World; +using VRage.Game.Components; using VRage.Network; +using VRage.Scene; +using VRageMath; namespace Meds.Wrapper.Audit { @@ -26,5 +32,68 @@ public static void Postfix() .Emit(); } } + + [HarmonyPatch(typeof(MyGridPlacer), "ProcessPasting")] + [AlwaysPatch] + public static class AuditPasteGrids + { + public static void Postfix(List createdScenes) + { + var userId = MyEventContext.Current.IsLocallyInvoked ? Sync.MyId : MyEventContext.Current.Sender.Value; + var player = MyPlayers.Static?.GetPlayer(new MyPlayer.PlayerId(userId)); + if (player == null) + return; + var clipboard = new ClipboardOpPayload(); + var bounds = BoundingBoxD.CreateInvalid(); + foreach (var scene in createdScenes) + foreach (var grid in scene.Grids) + { + clipboard.Add(grid); + bounds.Include(grid.Container.Get().WorldAABB); + } + + if (clipboard.Grids == 0) + return; + + AuditPayload.Create(AuditEvent.ClipboardPaste, player, owningLocation: bounds.Center) + .ClipboardOpPayload(in clipboard) + .Emit(); + } + } + + [HarmonyPatch(typeof(MyClipboardComponent), "OnGridClosedRequest")] + [AlwaysPatch] + public static class AuditCutGrids + { + public static void Prefix(EntityId entityId) + { + var scene = MySession.Static.Scene; + if (!scene.TryGetEntity(entityId, out var entity)) + return; + var userId = MyEventContext.Current.IsLocallyInvoked ? Sync.MyId : MyEventContext.Current.Sender.Value; + var player = MyPlayers.Static?.GetPlayer(new MyPlayer.PlayerId(userId)); + if (player == null) + return; + + var clipboard = new ClipboardOpPayload(); + var bounds = BoundingBoxD.CreateInvalid(); + + var collector = scene.GetCollector(); + collector.CollectAllConnectedEntities(entity); + + foreach (var attached in collector.Entities) + { + clipboard.Add(attached); + bounds.Include(attached.PositionComp.WorldAABB); + } + + if (clipboard.Grids == 0) + return; + + AuditPayload.Create(AuditEvent.ClipboardCut, player, owningLocation: bounds.Center) + .ClipboardOpPayload(in clipboard) + .Emit(); + } + } } } \ No newline at end of file