From 164d0d60cea68dafe62acb30d50d23ad9c326915 Mon Sep 17 00:00:00 2001 From: godhatesaustralia Date: Fri, 17 May 2024 17:14:39 -0400 Subject: [PATCH 1/7] Create file.txt --- Weapon Mods/Development/REEECore-Dev/file.txt | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 Weapon Mods/Development/REEECore-Dev/file.txt diff --git a/Weapon Mods/Development/REEECore-Dev/file.txt b/Weapon Mods/Development/REEECore-Dev/file.txt new file mode 100644 index 00000000..e69de29b From eccf323ff5ac972d3171183bd85b6887bf1e28e3 Mon Sep 17 00:00:00 2001 From: godhatesaustralia Date: Fri, 17 May 2024 18:10:00 -0400 Subject: [PATCH 2/7] Created ULTRALogger project files --- .../Data/Scripts/Logger/ScCoordWriter.cs | 420 ++++++++++++++++++ .../Data/Scripts/Logger/Session.cs | 110 +++++ 2 files changed, 530 insertions(+) create mode 100644 Utility Mods/Development/ULTRALogger/Data/Scripts/Logger/ScCoordWriter.cs create mode 100644 Utility Mods/Development/ULTRALogger/Data/Scripts/Logger/Session.cs diff --git a/Utility Mods/Development/ULTRALogger/Data/Scripts/Logger/ScCoordWriter.cs b/Utility Mods/Development/ULTRALogger/Data/Scripts/Logger/ScCoordWriter.cs new file mode 100644 index 00000000..1d68bd23 --- /dev/null +++ b/Utility Mods/Development/ULTRALogger/Data/Scripts/Logger/ScCoordWriter.cs @@ -0,0 +1,420 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using Sandbox.Game; +using Sandbox.Game.Entities; +using Sandbox.ModAPI; +using VRage.Game; +using VRage.Game.Components; +using VRage.Game.ModAPI; +using VRage.ModAPI; +using VRage.Utils; +using VRageMath; + +namespace YourName.ModName.Data.Scripts.ScCoordWriter +{ + [MySessionComponentDescriptor(MyUpdateOrder.AfterSimulation)] + public class ScCoordWriter : MySessionComponentBase + { + public static ScCoordWriter Instance; + private ushort NetworkId; + private List TrackedItems = new List(); + private TextWriter Writer; + private bool Recording; + + private const int Version = 2; + private readonly string[] _columns = + { + "kind", "name", "owner", "faction", "factionColor", "entityId", "health", "position", "rotation", "gridSize" + }; + + private const string Extension = ".scc"; + private const string CommandPrefix = "/coordwriter"; + public string Usage = $"Usage: {CommandPrefix} [stop|start]"; + + private int TickCounter = 0; + + private class TrackedItem + { + public object item; + public int initialBlockCount; + public bool isVolumeExported; + + public TrackedItem(object item, int initialBlockCount = 1) + { + this.item = item; + this.initialBlockCount = initialBlockCount; + } + } + + public override void LoadData() + { + Instance = this; + NetworkId = 12493; + if (!MyAPIGateway.Utilities.IsDedicated) + { + MyAPIGateway.Utilities.MessageEnteredSender += HandleMessage; + } + else + { + MyAPIGateway.Multiplayer.RegisterSecureMessageHandler(NetworkId, ReceivedPacket); + } + + MyAPIGateway.Entities.GetEntities(null, entity => + { + if (ShouldBeTracked(entity)) + { + var grid = entity as IMyCubeGrid; + if (grid != null) + { + var blocks = new List(); + grid.GetBlocks(blocks); + TrackedItems.Add(new TrackedItem(grid, blocks.Count)); + } + } + return false; + }); + MyAPIGateway.Entities.OnEntityAdd += OnEntityAdd; + MyAPIGateway.Entities.OnEntityRemove += OnEntityRemove; + } + + private void OnEntityAdd(IMyEntity entity) + { + if (ShouldBeTracked(entity)) + { + var grid = entity as IMyCubeGrid; + if (grid != null) + { + var blocks = new List(); + grid.GetBlocks(blocks); + TrackedItems.Add(new TrackedItem(grid, blocks.Count)); + } + } + } + + private void OnEntityRemove(IMyEntity entity) + { + for (var i = 0; i < TrackedItems.Count; ++i) + { + var cur = TrackedItems[i]; + var grid = cur.item as IMyCubeGrid; + if (grid != null && grid.EntityId == entity.EntityId) + { + TrackedItems.RemoveAt(i); + break; + } + } + } + + private bool ShouldBeTracked(IMyEntity entity) + { + var grid = entity as IMyCubeGrid; + return grid != null && !grid.IsStatic && grid.Physics != null; + } + + protected override void UnloadData() + { + Writer?.Close(); + TrackedItems?.Clear(); + if (!MyAPIGateway.Utilities.IsDedicated) + { + MyAPIGateway.Utilities.MessageEnteredSender -= HandleMessage; + } + else + { + MyAPIGateway.Multiplayer.UnregisterSecureMessageHandler(NetworkId, ReceivedPacket); + } + MyAPIGateway.Entities.OnEntityAdd -= OnEntityAdd; + MyAPIGateway.Entities.OnEntityRemove -= OnEntityRemove; + } + + public void Start() + { + var fileName = $"{DateTime.Now:dd-MM-yyyy HHmm}{Extension}"; + + try + { + Writer = MyAPIGateway.Utilities.WriteFileInWorldStorage(fileName, typeof(ScCoordWriter)); + Writer.NewLine = "\n"; + MyVisualScriptLogicProvider.SendChatMessage("Global grid tracker file created"); + Writer.WriteLine($"version {Version}"); + Writer.WriteLine(string.Join(",", _columns)); + } + catch (Exception ex) + { + MyLog.Default.WriteLine("Failed to create grid tracker file."); + MyVisualScriptLogicProvider.SendChatMessage("Failed to create grid tracker file."); + MyLog.Default.WriteLine(ex); + } + + if (TrackedItems != null) + { + foreach (var element in TrackedItems) + { + element.isVolumeExported = false; + } + } + + Recording = true; + MyAPIGateway.Multiplayer.SendMessageToServer(NetworkId, new byte[] { 1 }); + MyAPIGateway.Utilities.ShowNotification("Recording started."); + } + + public void Stop() + { + Recording = false; + MyAPIGateway.Multiplayer.SendMessageToServer(NetworkId, new byte[] { 0 }); + MyAPIGateway.Utilities.ShowNotification("Recording ended."); + } + + public override void UpdateAfterSimulation() + { + if (!Recording) return; + if (TrackedItems == null) + { + MyVisualScriptLogicProvider.SendChatMessage("TrackedItems is null"); + return; + } + + if (TickCounter++ < 60) { return; } + TickCounter = 0; + + Writer.WriteLine($"start_block,{DateTime.Now}"); + TrackedItems.ForEach(element => + { + if (element.item == null) + { + MyLog.Default.WriteLine("null item in TrackedItems"); + return; + } + + var grid = element.item as IMyCubeGrid; + var owner = GetGridOwner(grid); + var factionName = GetFactionName(owner); + var factionColor = GetFactionColor(owner); + + // Use the grid's world matrix for position and rotation + MatrixD worldMatrix = grid.WorldMatrix; + Vector3D position = grid.Physics.CenterOfMassWorld; + Quaternion rotation = Quaternion.CreateFromForwardUp(worldMatrix.Forward, worldMatrix.Up); + + var blockList = new List(); + grid.GetBlocks(blockList); + var currentBlockCount = blockList.Count; + if (currentBlockCount > element.initialBlockCount) + { + element.initialBlockCount = currentBlockCount; + } + var healthPercent = (float)currentBlockCount / element.initialBlockCount; + + // Determine if the grid is small or large + var gridSize = grid.GridSizeEnum == MyCubeSize.Small ? "Small" : "Large"; + + Writer.WriteLine($"grid,{grid.CustomName},{owner?.DisplayName ?? "Unowned"},{factionName},{factionColor},{grid.EntityId},{SmallDouble(healthPercent)},{SmallVector3D(position)},{SmallQuaternion(rotation)},{gridSize}"); + + if (!element.isVolumeExported) + { + var volume = ConvertToBase64BinaryVolume(grid); + Writer.WriteLine($"volume,{grid.EntityId},{volume}"); + element.isVolumeExported = true; + } + }); + Writer.Flush(); + } + + public string SmallQuaternion(Quaternion q) + { + return + $"{SmallDouble(q.X)} {SmallDouble(q.Y)} {SmallDouble(q.Z)} {SmallDouble(q.W)}"; + } + public string SmallVector3D(Vector3D v) + { + + return $"{SmallDouble(v.X)} {SmallDouble(v.Y)} {SmallDouble(v.Z)}"; + } + public string SmallDouble(double value) + { + const int decimalPlaces = 2; + return value.ToString($"F{decimalPlaces}"); + } + + public void HandleMessage(ulong sender, string messageText, ref bool sendToOthers) + { + if (!messageText.StartsWith(CommandPrefix)) return; + sendToOthers = false; + + var args = messageText.Split(' '); + + if (args.Length != 2) + { + return; + + } + + switch (args[1]) + { + case "start": + Start(); + break; + case "stop": + Stop(); + break; + default: + { + var error = $"[{nameof(ScCoordWriter)}] Unknown command '{args[1]}'"; + MyLog.Default.WriteLine(error); + MyAPIGateway.Utilities.ShowMessage($"[{nameof(ScCoordWriter)}]", error); + MyAPIGateway.Utilities.ShowMessage($"[{nameof(ScCoordWriter)}]", Usage); + } + break; + } + } + + public void ReceivedPacket(ushort channelId, byte[] data, ulong steamSenderId, bool isSenderServer) + { + if (data != null && data.Length == 1) + { + Recording = data[0] == 1; + if (Recording) + { + Start(); + } + else + { + Stop(); + } + } + } + + private string GetFactionName(IMyIdentity player) + { + if (player == null) return "Unowned"; + IMyFaction playerFaction = MyAPIGateway.Session.Factions.TryGetPlayerFaction(player.IdentityId); + return playerFaction != null ? playerFaction.Name : "Unowned"; + } + + private string GetFactionColor(IMyIdentity owner) + { + if (owner == null) return SmallVector3D(Vector3D.Zero); + + var faction = MyAPIGateway.Session.Factions.TryGetPlayerFaction(owner.IdentityId); + if (faction != null) + { + // Example, replace with actual way to get faction color if available + + return SmallVector3D(faction.CustomColor); + } + return SmallVector3D(Vector3D.Zero); // Default color if no faction or no color defined + } + + + public IMyIdentity GetGridOwner(IMyCubeGrid grid) + { + IMyIdentity owner = null; + if (grid.BigOwners.Count > 0) + { + var identities = new List(); + MyAPIGateway.Players.GetAllIdentites(identities, id => id.IdentityId == grid.BigOwners[0]); + if (identities.Count > 0) + { + owner = identities[0]; + } + } + return owner; + } + + public string ConvertToBase64BinaryVolume(IMyCubeGrid grid) + { + // Get grid dimensions + var extents = grid.Max - grid.Min + Vector3I.One; + int width = extents.X; + int height = extents.Y; + int depth = extents.Z; + + // Calculate number of bytes needed to store the volume + int numBytes = (width * height * depth + 7) / 8; + + // Create byte array to store binary volume + byte[] binaryVolume = new byte[numBytes]; + + // Iterate over grid cells + for (int z = 0; z < depth; z++) + { + for (int y = 0; y < height; y++) + { + for (int x = 0; x < width; x++) + { + // Calculate index in byte array + int byteIndex = z * width * height + y * width + x; + int bytePosition = byteIndex % 8; + + // Check if block is present at the cell + var block = grid.GetCubeBlock(new Vector3I(x, y, z) + grid.Min); + bool blockPresent = block != null; + + // Set corresponding bit in byte + if (blockPresent) + { + binaryVolume[byteIndex / 8] |= (byte)(1 << (7 - bytePosition)); // Invert the byte position + } + } + } + } + + // Create header with grid extents + byte[] header = BitConverter.GetBytes(width) + .Concat(BitConverter.GetBytes(height)) + .Concat(BitConverter.GetBytes(depth)) + .ToArray(); + + // Combine header and binary volume + byte[] result = header.Concat(binaryVolume).ToArray(); + + // Compress the result using RLE + byte[] compressedData = Compress(result); + + // Convert to base64 string + string base64String = Convert.ToBase64String(compressedData); + + return base64String; + } + + private byte[] Compress(byte[] data) + { + List compressedData = new List(); + + int count = 1; + byte currentByte = data[0]; + + for (int i = 1; i < data.Length; i++) + { + if (data[i] == currentByte) + { + count++; + if (count == 256) + { + // Add the current byte and max count (255), reset the count + compressedData.Add(currentByte); + compressedData.Add(255); + count = 1; + } + } + else + { + compressedData.Add(currentByte); + compressedData.Add((byte)count); + count = 1; + currentByte = data[i]; + } + } + + // Add the last byte and its count + compressedData.Add(currentByte); + compressedData.Add((byte)count); + + return compressedData.ToArray(); + } + } +} diff --git a/Utility Mods/Development/ULTRALogger/Data/Scripts/Logger/Session.cs b/Utility Mods/Development/ULTRALogger/Data/Scripts/Logger/Session.cs new file mode 100644 index 00000000..ed620e10 --- /dev/null +++ b/Utility Mods/Development/ULTRALogger/Data/Scripts/Logger/Session.cs @@ -0,0 +1,110 @@ +using System; +using Sandbox.Definitions; +using Sandbox.Game; +using Sandbox.Game.Entities; +using Sandbox.ModAPI; +using VRage.Game; +using VRage.Game.Components; +using VRage.Utils; +using BlendTypeEnum = VRageRender.MyBillboard.BlendTypeEnum; // required for MyTransparentGeometry/MySimpleObjectDraw to be able to set blend type. + +namespace Digi.Examples +{ + // This object is always present, from the world load to world unload. + // NOTE: all clients and server run mod scripts, keep that in mind. + // NOTE: this and gamelogic comp's update methods run on the main game thread, don't do too much in a tick or you'll lower sim speed. + // NOTE: also mind allocations, avoid realtime allocations, re-use collections/ref-objects (except value types like structs, integers, etc). + // + // The MyUpdateOrder arg determines what update overrides are actually called. + // Remove any method that you don't need, none of them are required, they're only there to show what you can use. + // Also remove all comments you've read to avoid the overload of comments that is this file. + [MySessionComponentDescriptor(MyUpdateOrder.BeforeSimulation | MyUpdateOrder.AfterSimulation)] + public class Logger : MySessionComponentBase + { + public static Logger Instance; // the only way to access session comp from other classes and the only accepted static field. + + public override void LoadData() + { + // amogst the earliest execution points, but not everything is available at this point. + + // These can be used anywhere, not just in this method/class: + // MyAPIGateway. - main entry point for the API + // MyDefinitionManager.Static. - reading/editing definitions + // MyGamePruningStructure. - fast way of finding entities in an area + // MyTransparentGeometry. and MySimpleObjectDraw. - to draw sprites (from TransparentMaterials.sbc) in world (they usually live a single tick) + // MyVisualScriptLogicProvider. - mainly designed for VST but has its uses, use as a last resort. + // System.Diagnostics.Stopwatch - for measuring code execution time. + // ...and many more things, ask in #programming-modding in keen's discord for what you want to do to be pointed at the available things to use. + + Instance = this; + } + + public override void BeforeStart() + { + // executed before the world starts updating + } + + protected override void UnloadData() + { + // executed when world is exited to unregister events and stuff + + Instance = null; // important for avoiding this object to remain allocated in memory + } + + public override void HandleInput() + { + // gets called 60 times a second before all other update methods, regardless of framerate, game pause or MyUpdateOrder. + } + + public override void UpdateBeforeSimulation() + { + // executed every tick, 60 times a second, before physics simulation and only if game is not paused. + } + + public override void Simulate() + { + // executed every tick, 60 times a second, during physics simulation and only if game is not paused. + // NOTE in this example this won't actually be called because of the lack of MyUpdateOrder.Simulation argument in MySessionComponentDescriptor + } + + public override void UpdateAfterSimulation() + { + // executed every tick, 60 times a second, after physics simulation and only if game is not paused. + + try // example try-catch for catching errors and notifying player, use only for non-critical code! + { + // ... + } + catch(Exception e) // NOTE: never use try-catch for code flow or to ignore errors! catching has a noticeable performance impact. + { + MyLog.Default.WriteLineAndConsole($"{e.Message}\n{e.StackTrace}"); + + if(MyAPIGateway.Session?.Player != null) + MyAPIGateway.Utilities.ShowNotification($"[ ERROR: {GetType().FullName}: {e.Message} | Send SpaceEngineers.Log to mod author ]", 10000, MyFontEnum.Red); + } + } + + public override void Draw() + { + // gets called 60 times a second after all other update methods, regardless of framerate, game pause or MyUpdateOrder. + // NOTE: this is the only place where the camera matrix (MyAPIGateway.Session.Camera.WorldMatrix) is accurate, everywhere else it's 1 frame behind. + } + + public override void SaveData() + { + // executed AFTER world was saved + } + + public override MyObjectBuilder_SessionComponent GetObjectBuilder() + { + // executed during world save, most likely before entities. + + return base.GetObjectBuilder(); // leave as-is. + } + + public override void UpdatingStopped() + { + // executed when game is paused + } + } +} \ No newline at end of file From a3b01cfbb4d908ec959984d011603234449d978b Mon Sep 17 00:00:00 2001 From: InvalidArgument3 Date: Fri, 17 May 2024 17:17:34 -0500 Subject: [PATCH 3/7] init ultralogger template --- .../Data/Scripts/Logger/Session.cs | 110 ------------------ .../Data/Scripts/Logger/ULTRALogger.cs | 72 ++++++++++++ 2 files changed, 72 insertions(+), 110 deletions(-) delete mode 100644 Utility Mods/Development/ULTRALogger/Data/Scripts/Logger/Session.cs create mode 100644 Utility Mods/Development/ULTRALogger/Data/Scripts/Logger/ULTRALogger.cs diff --git a/Utility Mods/Development/ULTRALogger/Data/Scripts/Logger/Session.cs b/Utility Mods/Development/ULTRALogger/Data/Scripts/Logger/Session.cs deleted file mode 100644 index ed620e10..00000000 --- a/Utility Mods/Development/ULTRALogger/Data/Scripts/Logger/Session.cs +++ /dev/null @@ -1,110 +0,0 @@ -using System; -using Sandbox.Definitions; -using Sandbox.Game; -using Sandbox.Game.Entities; -using Sandbox.ModAPI; -using VRage.Game; -using VRage.Game.Components; -using VRage.Utils; -using BlendTypeEnum = VRageRender.MyBillboard.BlendTypeEnum; // required for MyTransparentGeometry/MySimpleObjectDraw to be able to set blend type. - -namespace Digi.Examples -{ - // This object is always present, from the world load to world unload. - // NOTE: all clients and server run mod scripts, keep that in mind. - // NOTE: this and gamelogic comp's update methods run on the main game thread, don't do too much in a tick or you'll lower sim speed. - // NOTE: also mind allocations, avoid realtime allocations, re-use collections/ref-objects (except value types like structs, integers, etc). - // - // The MyUpdateOrder arg determines what update overrides are actually called. - // Remove any method that you don't need, none of them are required, they're only there to show what you can use. - // Also remove all comments you've read to avoid the overload of comments that is this file. - [MySessionComponentDescriptor(MyUpdateOrder.BeforeSimulation | MyUpdateOrder.AfterSimulation)] - public class Logger : MySessionComponentBase - { - public static Logger Instance; // the only way to access session comp from other classes and the only accepted static field. - - public override void LoadData() - { - // amogst the earliest execution points, but not everything is available at this point. - - // These can be used anywhere, not just in this method/class: - // MyAPIGateway. - main entry point for the API - // MyDefinitionManager.Static. - reading/editing definitions - // MyGamePruningStructure. - fast way of finding entities in an area - // MyTransparentGeometry. and MySimpleObjectDraw. - to draw sprites (from TransparentMaterials.sbc) in world (they usually live a single tick) - // MyVisualScriptLogicProvider. - mainly designed for VST but has its uses, use as a last resort. - // System.Diagnostics.Stopwatch - for measuring code execution time. - // ...and many more things, ask in #programming-modding in keen's discord for what you want to do to be pointed at the available things to use. - - Instance = this; - } - - public override void BeforeStart() - { - // executed before the world starts updating - } - - protected override void UnloadData() - { - // executed when world is exited to unregister events and stuff - - Instance = null; // important for avoiding this object to remain allocated in memory - } - - public override void HandleInput() - { - // gets called 60 times a second before all other update methods, regardless of framerate, game pause or MyUpdateOrder. - } - - public override void UpdateBeforeSimulation() - { - // executed every tick, 60 times a second, before physics simulation and only if game is not paused. - } - - public override void Simulate() - { - // executed every tick, 60 times a second, during physics simulation and only if game is not paused. - // NOTE in this example this won't actually be called because of the lack of MyUpdateOrder.Simulation argument in MySessionComponentDescriptor - } - - public override void UpdateAfterSimulation() - { - // executed every tick, 60 times a second, after physics simulation and only if game is not paused. - - try // example try-catch for catching errors and notifying player, use only for non-critical code! - { - // ... - } - catch(Exception e) // NOTE: never use try-catch for code flow or to ignore errors! catching has a noticeable performance impact. - { - MyLog.Default.WriteLineAndConsole($"{e.Message}\n{e.StackTrace}"); - - if(MyAPIGateway.Session?.Player != null) - MyAPIGateway.Utilities.ShowNotification($"[ ERROR: {GetType().FullName}: {e.Message} | Send SpaceEngineers.Log to mod author ]", 10000, MyFontEnum.Red); - } - } - - public override void Draw() - { - // gets called 60 times a second after all other update methods, regardless of framerate, game pause or MyUpdateOrder. - // NOTE: this is the only place where the camera matrix (MyAPIGateway.Session.Camera.WorldMatrix) is accurate, everywhere else it's 1 frame behind. - } - - public override void SaveData() - { - // executed AFTER world was saved - } - - public override MyObjectBuilder_SessionComponent GetObjectBuilder() - { - // executed during world save, most likely before entities. - - return base.GetObjectBuilder(); // leave as-is. - } - - public override void UpdatingStopped() - { - // executed when game is paused - } - } -} \ No newline at end of file diff --git a/Utility Mods/Development/ULTRALogger/Data/Scripts/Logger/ULTRALogger.cs b/Utility Mods/Development/ULTRALogger/Data/Scripts/Logger/ULTRALogger.cs new file mode 100644 index 00000000..2233c357 --- /dev/null +++ b/Utility Mods/Development/ULTRALogger/Data/Scripts/Logger/ULTRALogger.cs @@ -0,0 +1,72 @@ +using System; +using System.IO; +using Sandbox.ModAPI; +using VRage.Game; +using VRage.Game.Components; +using VRage.ModAPI; +using VRage.Utils; + +namespace ULTRALogger +{ + [MySessionComponentDescriptor(MyUpdateOrder.AfterSimulation)] + public class Logger : MySessionComponentBase + { + public static Logger Instance; + private TextWriter _writer; + private const string Extension = ".log"; + private bool _isRecording; + + public override void LoadData() + { + Instance = this; + StartLogging(); + MyAPIGateway.Entities.OnEntityAdd += OnEntityAdd; + } + + protected override void UnloadData() + { + StopLogging(); + MyAPIGateway.Entities.OnEntityAdd -= OnEntityAdd; + Instance = null; + } + + private void StartLogging() + { + var fileName = $"ULTRALog_{DateTime.Now:yyyy-MM-dd_HH-mm-ss}{Extension}"; + try + { + _writer = MyAPIGateway.Utilities.WriteFileInWorldStorage(fileName, typeof(Logger)); + _writer.WriteLine("Timestamp, BlockType, Position"); + _isRecording = true; + MyAPIGateway.Utilities.ShowNotification("ULTRALogger started."); + } + catch (Exception ex) + { + MyLog.Default.WriteLineAndConsole($"[ULTRALogger] Error creating log file: {ex.Message}\n{ex.StackTrace}"); + } + } + + private void StopLogging() + { + if (_isRecording) + { + _isRecording = false; + _writer?.Close(); + MyAPIGateway.Utilities.ShowNotification("ULTRALogger stopped."); + } + } + + private void OnEntityAdd(IMyEntity entity) + { + if (_isRecording && entity is IMyCubeBlock block) + { + var timestamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); + var blockType = block.BlockDefinition.DisplayNameText; + var position = block.GetPosition(); + + _writer.WriteLine($"{timestamp}, {blockType}, {position}"); + _writer.Flush(); + } + } + } +} From 0c732e01c042f53ec4f8662d8de2cb4ecffbaf9b Mon Sep 17 00:00:00 2001 From: godhatesaustralia Date: Fri, 17 May 2024 18:38:30 -0400 Subject: [PATCH 4/7] Update ULTRALogger.cs --- .../Data/Scripts/Logger/ULTRALogger.cs | 21 ++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/Utility Mods/Development/ULTRALogger/Data/Scripts/Logger/ULTRALogger.cs b/Utility Mods/Development/ULTRALogger/Data/Scripts/Logger/ULTRALogger.cs index 2233c357..a967b1ad 100644 --- a/Utility Mods/Development/ULTRALogger/Data/Scripts/Logger/ULTRALogger.cs +++ b/Utility Mods/Development/ULTRALogger/Data/Scripts/Logger/ULTRALogger.cs @@ -1,8 +1,10 @@ using System; using System.IO; +using Sandbox.Game; using Sandbox.ModAPI; using VRage.Game; using VRage.Game.Components; +using VRage.Game.ModAPI; using VRage.ModAPI; using VRage.Utils; @@ -38,7 +40,8 @@ private void StartLogging() _writer = MyAPIGateway.Utilities.WriteFileInWorldStorage(fileName, typeof(Logger)); _writer.WriteLine("Timestamp, BlockType, Position"); _isRecording = true; - MyAPIGateway.Utilities.ShowNotification("ULTRALogger started."); + MyAPIGateway.Utilities.ShowNotification("ULTRALogger started.", 10000); + MyVisualScriptLogicProvider.SendChatMessage($"Logger started at {DateTime.Now}."); } catch (Exception ex) { @@ -58,14 +61,18 @@ private void StopLogging() private void OnEntityAdd(IMyEntity entity) { - if (_isRecording && entity is IMyCubeBlock block) + if (_isRecording) { - var timestamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); - var blockType = block.BlockDefinition.DisplayNameText; - var position = block.GetPosition(); + var block = entity as IMyCubeBlock; + if (block != null) + { + var timestamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); + var blockType = block.BlockDefinition.SubtypeId; + var position = block.GetPosition(); - _writer.WriteLine($"{timestamp}, {blockType}, {position}"); - _writer.Flush(); + _writer.WriteLine($"{timestamp}, {blockType}, {position}"); + _writer.Flush(); + } } } } From 7dda09862bd85497c2a76945cbf50f35c973202a Mon Sep 17 00:00:00 2001 From: godhatesaustralia Date: Fri, 17 May 2024 18:45:52 -0400 Subject: [PATCH 5/7] Update ULTRALogger.cs --- .../Development/ULTRALogger/Data/Scripts/Logger/ULTRALogger.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Utility Mods/Development/ULTRALogger/Data/Scripts/Logger/ULTRALogger.cs b/Utility Mods/Development/ULTRALogger/Data/Scripts/Logger/ULTRALogger.cs index a967b1ad..119174fd 100644 --- a/Utility Mods/Development/ULTRALogger/Data/Scripts/Logger/ULTRALogger.cs +++ b/Utility Mods/Development/ULTRALogger/Data/Scripts/Logger/ULTRALogger.cs @@ -63,7 +63,9 @@ private void OnEntityAdd(IMyEntity entity) { if (_isRecording) { + MyAPIGateway.Utilities.ShowNotification($"Added new entity.{entity.EntityId.ToString("X")}", 1000); var block = entity as IMyCubeBlock; + if (block != null) { var timestamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); From 5f168b2bebc7c42ca5c12cebd311a3c4c7ef5bdb Mon Sep 17 00:00:00 2001 From: godhatesaustralia Date: Fri, 17 May 2024 18:47:16 -0400 Subject: [PATCH 6/7] Update ULTRALogger.cs --- .../ULTRALogger/Data/Scripts/Logger/ULTRALogger.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Utility Mods/Development/ULTRALogger/Data/Scripts/Logger/ULTRALogger.cs b/Utility Mods/Development/ULTRALogger/Data/Scripts/Logger/ULTRALogger.cs index 119174fd..93345b38 100644 --- a/Utility Mods/Development/ULTRALogger/Data/Scripts/Logger/ULTRALogger.cs +++ b/Utility Mods/Development/ULTRALogger/Data/Scripts/Logger/ULTRALogger.cs @@ -11,9 +11,9 @@ namespace ULTRALogger { [MySessionComponentDescriptor(MyUpdateOrder.AfterSimulation)] - public class Logger : MySessionComponentBase + public class ULTRALogger : MySessionComponentBase { - public static Logger Instance; + public static ULTRALogger Instance; private TextWriter _writer; private const string Extension = ".log"; private bool _isRecording; @@ -37,7 +37,7 @@ private void StartLogging() var fileName = $"ULTRALog_{DateTime.Now:yyyy-MM-dd_HH-mm-ss}{Extension}"; try { - _writer = MyAPIGateway.Utilities.WriteFileInWorldStorage(fileName, typeof(Logger)); + _writer = MyAPIGateway.Utilities.WriteFileInWorldStorage(fileName, typeof(ULTRALogger)); _writer.WriteLine("Timestamp, BlockType, Position"); _isRecording = true; MyAPIGateway.Utilities.ShowNotification("ULTRALogger started.", 10000); From 94238347a962db9c8f5c12e6f03160a03ff31e40 Mon Sep 17 00:00:00 2001 From: godhatesaustralia Date: Fri, 17 May 2024 23:31:20 -0400 Subject: [PATCH 7/7] Update ULTRALogger.cs setup most of the logging, made a few assumptions/shortcuts because i'm pretty sure they'll help keep this as low impact/simple as possible --- .../Data/Scripts/Logger/ULTRALogger.cs | 170 ++++++++++++++++-- 1 file changed, 151 insertions(+), 19 deletions(-) diff --git a/Utility Mods/Development/ULTRALogger/Data/Scripts/Logger/ULTRALogger.cs b/Utility Mods/Development/ULTRALogger/Data/Scripts/Logger/ULTRALogger.cs index 93345b38..e70beaba 100644 --- a/Utility Mods/Development/ULTRALogger/Data/Scripts/Logger/ULTRALogger.cs +++ b/Utility Mods/Development/ULTRALogger/Data/Scripts/Logger/ULTRALogger.cs @@ -1,12 +1,13 @@ using System; +using System.Collections.Generic; using System.IO; using Sandbox.Game; using Sandbox.ModAPI; -using VRage.Game; using VRage.Game.Components; using VRage.Game.ModAPI; using VRage.ModAPI; using VRage.Utils; +using VRageMath; namespace ULTRALogger { @@ -14,34 +15,79 @@ namespace ULTRALogger public class ULTRALogger : MySessionComponentBase { public static ULTRALogger Instance; - private TextWriter _writer; + private TextWriter + _gridsWriter, + _playersWriter, + _projectilesWriter; + private const string Extension = ".log"; private bool _isRecording; + private DateTime _last; + private Vector3D _badVector = new Vector3D(double.NaN); + private HashSet _playerIdentities = new HashSet(); + + #region common + + private void CheckTime() + { + // i just feel like it + if ((DateTime.Now - _last).TotalSeconds != 0) + { + _gridsWriter.WriteLine('\n'); + _last = DateTime.Now; + } + } + + private string ShorterPositionString(Vector3D position) => position != _badVector ? $"(X = {position.X:#0.#}, Y = {position.Y:#0.#}, Z {position.Z:#0.#}) " : ""; + + private string Timestamp() => $"[{DateTime.Now:yyyy-MM-dd HH:mm:ss}]"; + + #endregion public override void LoadData() { Instance = this; StartLogging(); MyAPIGateway.Entities.OnEntityAdd += OnEntityAdd; + //MyVisualScriptLogicProvider.PlayerConnected + MyVisualScriptLogicProvider.PlayerRespawnRequest += OnPlayerRespawn; + MyAPIGateway.Entities.OnEntityRemove += OnEntityRemove; + + MyAPIGateway.Players.GetAllIdentites(null, b => + { + if (!_playerIdentities.Contains(b.IdentityId)) + _playerIdentities.Add(b.IdentityId); + return true; + }); } protected override void UnloadData() { StopLogging(); MyAPIGateway.Entities.OnEntityAdd -= OnEntityAdd; + MyAPIGateway.Entities.OnEntityRemove -= OnEntityRemove; Instance = null; } + + private void StartLogging() { - var fileName = $"ULTRALog_{DateTime.Now:yyyy-MM-dd_HH-mm-ss}{Extension}"; + var fileName = $"{DateTime.Now:yyyy-MM-dd_HH-mm-ss}{Extension}"; + string ascii = " __ __ __ .___________..______ ___ __ ______ _______ _______ _______ .______ \r\n| | | | | | | || _ \\ / \\ | | / __ \\ / _____| / _____|| ____|| _ \\ \r\n| | | | | | `---| |----`| |_) | / ^ \\ | | | | | | | | __ | | __ | |__ | |_) | \r\n| | | | | | | | | / / /_\\ \\ | | | | | | | | |_ | | | |_ | | __| | / \r\n| `--' | | `----. | | | |\\ \\----./ _____ \\ | `----.| `--' | | |__| | | |__| | | |____ | |\\ \\----.\r\n \\______/ |_______| |__| | _| `._____/__/ \\__\\ |_______| \\______/ \\______| \\______| |_______|| _| `._____|\r\n\n"; try { - _writer = MyAPIGateway.Utilities.WriteFileInWorldStorage(fileName, typeof(ULTRALogger)); - _writer.WriteLine("Timestamp, BlockType, Position"); + _gridsWriter = MyAPIGateway.Utilities.WriteFileInWorldStorage("ULTRALog_GRIDS", typeof(ULTRALogger)); + _gridsWriter.Write(ascii); + _gridsWriter.WriteLine("GRID LOG"); + + _playersWriter = MyAPIGateway.Utilities.WriteFileInWorldStorage("ULTRALog_PLAYERS", typeof (ULTRALogger)); + _playersWriter.Write(ascii); + _playersWriter.WriteLine("PLAYER LOG"); + + // TODO: wc stuff. laterrrr + _isRecording = true; - MyAPIGateway.Utilities.ShowNotification("ULTRALogger started.", 10000); - MyVisualScriptLogicProvider.SendChatMessage($"Logger started at {DateTime.Now}."); } catch (Exception ex) { @@ -51,31 +97,117 @@ private void StartLogging() private void StopLogging() { - if (_isRecording) - { _isRecording = false; - _writer?.Close(); + _gridsWriter?.Close(); + _playersWriter?.Close(); + _projectilesWriter?.Close(); MyAPIGateway.Utilities.ShowNotification("ULTRALogger stopped."); - } } + #region grids + private void OnEntityAdd(IMyEntity entity) { if (_isRecording) { - MyAPIGateway.Utilities.ShowNotification($"Added new entity.{entity.EntityId.ToString("X")}", 1000); - var block = entity as IMyCubeBlock; + CheckTime(); + var grid = entity as IMyCubeGrid; - if (block != null) + if (grid != null) + { + var owner = MyAPIGateway.Players.TryGetIdentityId(grid.BigOwners[0]).DisplayName; + grid.OnBlockAdded += OnBlockAdded; + grid.OnGridBlockDamaged += OnDamaged; + grid.OnBlockRemoved += OnBlockRemoved; + _playersWriter.WriteLine($"{Timestamp()} {owner} added new grid: \"{grid.CustomName}\" at {ShorterPositionString(grid.GetPosition())}"); + _playersWriter.Flush(); + } + } + } + private void OnEntityRemove(IMyEntity entity) + { + if (_isRecording) + { + CheckTime(); + var grid = entity as IMyCubeGrid; + if (grid != null) { - var timestamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); - var blockType = block.BlockDefinition.SubtypeId; - var position = block.GetPosition(); + // do i need this? + grid.OnBlockAdded -= OnBlockAdded; + grid.OnBlockRemoved -= OnBlockRemoved; + grid.OnGridBlockDamaged -= OnDamaged; + _gridsWriter.WriteLine($"{Timestamp()} Removed grid: \"{grid.CustomName}\" at {ShorterPositionString(grid.GetPosition())}"); + _gridsWriter.Flush(); + } + } + } + + private void OnDamaged(IMySlimBlock block, float whatever, MyHitInfo? hit, long presumablyEntityID) + { + if (_isRecording) + { + CheckTime(); + string + parent = block?.CubeGrid.CustomName, + blockType = block.FatBlock?.BlockDefinition.SubtypeId ?? "slim", + position = block.FatBlock != null ? "at " + ShorterPositionString((hit.HasValue ? hit.Value.Position : _badVector)) : ""; + + _gridsWriter.WriteLine($"{Timestamp()} {blockType} block {position}on parent grid \"{parent}\""); + _gridsWriter.Flush(); + } + } + + #endregion + + #region players - _writer.WriteLine($"{timestamp}, {blockType}, {position}"); - _writer.Flush(); + private void OnPlayerRespawn(long identityId) + { + var player = MyAPIGateway.Players.TryGetIdentityId(identityId); + if (player != null) + { + if (_playerIdentities.Contains(identityId)) + _playersWriter.WriteLine($"{Timestamp()} {MyAPIGateway.Players.TryGetIdentityId(identityId).DisplayName} respawned at {ShorterPositionString(player.GetPosition())}"); + else + { + _playersWriter.WriteLine($"{Timestamp()} {MyAPIGateway.Players.TryGetIdentityId(identityId).DisplayName} joined the server and respawned at {ShorterPositionString(player.GetPosition())}"); + _playerIdentities.Add(identityId); } + _playersWriter.Flush(); } } + + private void OnBlockAdded(IMySlimBlock block) + { + if (_isRecording) + { + CheckTime(); + string + builder = MyAPIGateway.Players.TryGetIdentityId(block.BuiltBy).DisplayName, + parent = block?.CubeGrid.CustomName, + blockType = block.FatBlock?.BlockDefinition.SubtypeId ?? "slim", + position = block.FatBlock != null ? "at " + ShorterPositionString(block.FatBlock.GetPosition()) : ""; + + _gridsWriter.WriteLine($"{Timestamp()} {builder} added new {blockType} block {position}on parent grid \"{parent}\""); + _gridsWriter.Flush(); + } + } + + private void OnBlockRemoved(IMySlimBlock block) + { + if (_isRecording) + { + CheckTime(); + string + parent = block?.CubeGrid.CustomName, + blockType = block.FatBlock?.BlockDefinition.SubtypeId ?? "slim", + position = block.FatBlock != null ? "at " + ShorterPositionString(block.FatBlock.GetPosition()) : ""; + + _gridsWriter.WriteLine($"{Timestamp()} Removed {blockType} block {position}from parent grid \"{parent}\""); + _gridsWriter.Flush(); + } + } + + #endregion } }