From 18fc772caf8c17d4c4a2a1e7596abf6164eb6979 Mon Sep 17 00:00:00 2001 From: Tyrsis Date: Mon, 25 May 2015 13:32:01 -0400 Subject: [PATCH 1/2] Add voxel management This needs to be fixed to work in your version of essentials. So I'm only going to do a push so it can be cleaned / fixed to work when someone has time. I've delayed this too long. --- .../EntityManagers/VoxelManagement.cs | 190 ++++++++++++++++++ EssentialsPlugin/Essentials.cs | 26 +++ EssentialsPlugin/EssentialsPlugin.csproj | 2 + .../ProcessHandlers/ProcessVoxels.cs | 62 ++++++ EssentialsPlugin/Settings/PluginSettings.cs | 24 +++ EssentialsPlugin/Utility/Communication.cs | 32 +++ 6 files changed, 336 insertions(+) create mode 100644 EssentialsPlugin/EntityManagers/VoxelManagement.cs create mode 100644 EssentialsPlugin/ProcessHandlers/ProcessVoxels.cs diff --git a/EssentialsPlugin/EntityManagers/VoxelManagement.cs b/EssentialsPlugin/EntityManagers/VoxelManagement.cs new file mode 100644 index 0000000..67f8c4b --- /dev/null +++ b/EssentialsPlugin/EntityManagers/VoxelManagement.cs @@ -0,0 +1,190 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.IO; +using System.Xml.Serialization; + +using EssentialsPlugin.Utility; + +using Sandbox.ModAPI; +using Sandbox.Common.ObjectBuilders; +using Sandbox.Common.ObjectBuilders.VRageData; + +using SEModAPIInternal.API.Entity.Sector.SectorObject.CubeGrid.CubeBlock; +using SEModAPIInternal.API.Server; + +using EssentialsPlugin.UtilityClasses; + +namespace EssentialsPlugin.EntityManagers +{ + public class VoxelManagement + { + private static Dictionary> m_userVoxels = new Dictionary>(); + private static bool m_voxelCheck = false; + + public static void CheckAndSendVoxels() + { + if (m_voxelCheck) + return; + + m_voxelCheck = true; + + try + { + DateTime start = DateTime.Now; + HashSet entities = new HashSet(); + List players = new List(); + try + { + MyAPIGateway.Entities.GetEntities(entities); + MyAPIGateway.Players.GetPlayers(players); + } + catch + { + Logging.WriteLineAndConsole(string.Format("CheckAndSendVoxels(): Entity list busy, skipping check")); + return; + } + + HashSet> voxelsToSend = new HashSet>(); + foreach (IMyEntity entity in entities) + { + if (!(entity is IMyVoxelMap)) + continue; + + IMyVoxelMap voxel = (IMyVoxelMap)entity; + + foreach (IMyPlayer player in players) + { + double distance = 0d; + if (Entity.GetDistanceBetweenPointAndPlayer(entity.GetPosition(), player, out distance)) + { + if (!m_userVoxels.ContainsKey(player.SteamUserId)) + m_userVoxels.Add(player.SteamUserId, new HashSet()); + + HashSet voxels = m_userVoxels[player.SteamUserId]; + + if (distance < PluginSettings.Instance.DynamicVoxelDistance && !voxels.Contains(entity.EntityId)) + { + voxelsToSend.Add(new Tuple(player.SteamUserId, entity)); + } + } + } + } + + if (voxelsToSend.Count > 0) + { + Wrapper.GameAction(() => + { + foreach (Tuple p in voxelsToSend) + { + SendVoxel(p.Item1, p.Item2); + } + }); + } + + if ((DateTime.Now - start).TotalSeconds > 1) + Logging.WriteLineAndConsole(string.Format("CheckAndSendVoxels(): {0}ms", (DateTime.Now - start).TotalMilliseconds)); + } + catch (Exception ex) + { + Logging.WriteLineAndConsole(string.Format("CheckAndSendVoxels(): {0}", ex.ToString())); + } + finally + { + m_voxelCheck = false; + } + } + + public static void ClearCache(ulong steamId) + { + if (!m_userVoxels.ContainsKey(steamId)) + return; + + HashSet voxels = m_userVoxels[steamId]; + voxels.Clear(); + } + + private static void SendVoxel(ulong steamId, IMyEntity voxel) + { + if (!m_userVoxels.ContainsKey(steamId)) + m_userVoxels.Add(steamId, new HashSet()); + + HashSet voxels = m_userVoxels[steamId]; + voxels.Add(voxel.EntityId); + + SendVoxelData(steamId, voxel); + } + + private static void SendVoxelData(ulong steamId, IMyEntity voxel) + { + try + { + IMyVoxelMap voxelMap = (IMyVoxelMap)voxel; + + byte[] voxelData; + voxelMap.Storage.Save(out voxelData); + + VoxelHeaderData header = new VoxelHeaderData(); + header.EntityId = voxel.EntityId; + header.HalfExtent = voxelMap.Storage.Size / 2; + header.Position = voxel.GetPosition(); + header.Name = voxelMap.StorageName; + header.DataLength = voxelData.Length; + + string headerString = MyAPIGateway.Utilities.SerializeToXML(header); + ushort length = (ushort)headerString.Length; + + byte[] headerData = new byte[2 + headerString.Length]; + + headerData[0] = (byte)length; + headerData[1] = (byte)(length >> 8); + + for (int r = 0; r < headerString.Length; r++) + { + headerData[r + 2] = (byte)headerString[r]; + } + Logging.WriteLineAndConsole(string.Format("Sending Voxel Header Data: {0} / {1} - {2} ({3})", voxelData.Length, headerData.Length, steamId, voxel.GetPosition())); + Communication.SendDataMessage(steamId, 5001, headerData); + + //if(RadarManagement.Instance.IsEnabled(steamId)) + // Communication.SendClientMessage(steamId, string.Format("/waypoint add \"{0}\" \"{1}\" Neutral {2} {3} {4} 30000", voxelMap.StorageName, "Asteroid", Math.Floor(header.Position.X), Math.Floor(header.Position.Y), Math.Floor(header.Position.Z))); + + int blockSize = 4096; + for (ushort r = 0; r < (voxelData.Length / blockSize) + 1; r++) + { + int partLength = voxelData.Length - (r * blockSize); + + if (partLength > blockSize) + partLength = blockSize; + + byte[] outData = new byte[partLength + 12]; + + for (int s = 0; s < 8; s++) + outData[s] = (byte)(header.EntityId >> (s * 8)); + + for (int s = 0; s < 2; s++) + outData[s + 8] = (byte)(partLength >> (s * 8)); + + for (int s = 0; s < 2; s++) + outData[s + 10] = (byte)(r >> (s * 8)); + + Buffer.BlockCopy(voxelData, r * blockSize, outData, 12, partLength); + Communication.SendDataMessage(steamId, 5002, outData); + } + } + catch (Exception ex) + { + Logging.WriteLineAndConsole(string.Format("SendVoxelData(): {0}", ex.ToString())); + } + } + + public class VoxelHeaderData + { + public long EntityId { get; set; } + public string Name { get; set; } + public SerializableVector3I HalfExtent { get; set; } + public SerializableVector3D Position { get; set; } + public int DataLength { get; set; } + } + } +} diff --git a/EssentialsPlugin/Essentials.cs b/EssentialsPlugin/Essentials.cs index 8824a07..6f2a708 100644 --- a/EssentialsPlugin/Essentials.cs +++ b/EssentialsPlugin/Essentials.cs @@ -683,6 +683,32 @@ public DynamicTurretManagementMode DynamicTurretManagementMode } } + [Category("Dynamic Entity Management")] + [Description("Enable / Disable dynamic voxel management.")] + [Browsable(true)] + [ReadOnly(false)] + public bool DynamicVoxelManagementEnabled + { + get { return PluginSettings.Instance.DynamicVoxelManagementEnabled; } + set + { + PluginSettings.Instance.DynamicVoxelManagementEnabled = value; + } + } + + [Category("Dynamic Entity Management")] + [Description("Sets the distance in which voxels are sent to the client")] + [Browsable(true)] + [ReadOnly(false)] + public int DynamicVoxelDistance + { + get { return PluginSettings.Instance.DynamicVoxelDistance; } + set + { + PluginSettings.Instance.DynamicVoxelDistance = value; + } + } + /* [Category("Dynamic Entity Management")] [Description("Enable / Disable dynamic block management. This manager disables blocks of ships that can't be concealed to further increase gamelogic savings.")] diff --git a/EssentialsPlugin/EssentialsPlugin.csproj b/EssentialsPlugin/EssentialsPlugin.csproj index 52dcd66..50bbc5d 100644 --- a/EssentialsPlugin/EssentialsPlugin.csproj +++ b/EssentialsPlugin/EssentialsPlugin.csproj @@ -129,6 +129,7 @@ ControlForm.cs + @@ -142,6 +143,7 @@ + diff --git a/EssentialsPlugin/ProcessHandlers/ProcessVoxels.cs b/EssentialsPlugin/ProcessHandlers/ProcessVoxels.cs new file mode 100644 index 0000000..ad842f6 --- /dev/null +++ b/EssentialsPlugin/ProcessHandlers/ProcessVoxels.cs @@ -0,0 +1,62 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using EssentialsPlugin.Utility; +using Sandbox.ModAPI; +using SEModAPIInternal.API.Common; +using System.IO; +using System.Xml; +using System.Xml.Serialization; +using VRage.Common.Utils; +using System.Text.RegularExpressions; +using System.Threading; + +using SEModAPIInternal.API.Entity.Sector.SectorObject; +using SEModAPIInternal.API.Entity.Sector.SectorObject.CubeGrid; +using SEModAPIInternal.API.Entity.Sector.SectorObject.CubeGrid.CubeBlock; +using SEModAPIInternal.API.Entity; + +using Sandbox.Common.ObjectBuilders; + +using EssentialsPlugin.Settings; +using EssentialsPlugin.EntityManagers; + +using Sandbox.Definitions; + +namespace EssentialsPlugin.ProcessHandler +{ + public class ProcessVoxels : ProcessHandlerBase + { + private static DateTime m_lastEnableCheck; + + + public override int GetUpdateResolution() + { + return 1000; + } + + public override void Handle() + { + if (PluginSettings.Instance.DynamicVoxelManagementEnabled) + { + if (DateTime.Now - m_lastEnableCheck > TimeSpan.FromSeconds(5)) + { + VoxelManagement.CheckAndSendVoxels(); + m_lastEnableCheck = DateTime.Now; + } + } + + base.Handle(); + } + + public override void OnPlayerJoined(ulong remoteUserId) + { + if (!PluginSettings.Instance.DynamicVoxelManagementEnabled) + return; + + VoxelManagement.ClearCache(remoteUserId); + } + } +} + diff --git a/EssentialsPlugin/Settings/PluginSettings.cs b/EssentialsPlugin/Settings/PluginSettings.cs index a567f57..8e64efe 100644 --- a/EssentialsPlugin/Settings/PluginSettings.cs +++ b/EssentialsPlugin/Settings/PluginSettings.cs @@ -83,6 +83,8 @@ public class PluginSettings private bool _dynamicTurretAllowExemption; private bool _dynamicBlockManagementEnabled; private DynamicTurretManagementMode _mDynamicTurretManagementMode; + private bool _dynamicVoxelManagementEnabled; + private int _dynamicVoxelDistance; private bool _dynamicConcealServerOnly; private bool _dynamicClientConcealEnabled; @@ -636,6 +638,26 @@ public DynamicTurretManagementMode DynamicTurretManagementMode } } + public bool DynamicVoxelManagementEnabled + { + get { return _dynamicVoxelManagementEnabled; } + set + { + _dynamicVoxelManagementEnabled = value; + Save(); + } + } + + public int DynamicVoxelDistance + { + get { return _dynamicVoxelDistance; } + set + { + _dynamicVoxelDistance = value; + Save(); + } + } + public bool DynamicBlockManagementEnabled { get { return _dynamicBlockManagementEnabled; } @@ -792,6 +814,8 @@ public PluginSettings() _dynamicShowMessages = false; _dynamicTurretTargetDistance = 2000; _dynamicTurretManagementEnabled = false; + _dynamicVoxelManagementEnabled = false; + _dynamicVoxelDistance = 20000; _dockingShipsPerZone = 1; diff --git a/EssentialsPlugin/Utility/Communication.cs b/EssentialsPlugin/Utility/Communication.cs index eae049e..b2a63fb 100644 --- a/EssentialsPlugin/Utility/Communication.cs +++ b/EssentialsPlugin/Utility/Communication.cs @@ -105,5 +105,37 @@ public static void DisplayDialog(ulong steamId, string header, string subheader, { SendClientMessage(steamId, string.Format("/dialog \"{0}\" \"{1}\" \"{2}\" \"{3}\" \"{4}\"", header, subheader, " ", content.Replace("\r\n", "|"), buttonText)); } + + public static void SendDataMessage(ulong steamId, long msgId, byte[] data) + { + string msgIdString = msgId.ToString(); + byte[] newData = new byte[data.Length + msgIdString.Length + 1]; + newData[0] = (byte)msgIdString.Length; + for (int r = 0; r < msgIdString.Length; r++) + newData[r + 1] = (byte)msgIdString[r]; + + Buffer.BlockCopy(data, 0, newData, msgIdString.Length + 1, data.Length); + + ServerNetworkManager.SendDataMessage(9000, newData, steamId); + } + + public static void BroadcastDataMessage(long msgId, byte[] data) + { + string msgIdString = msgId.ToString(); + byte[] newData = new byte[data.Length + msgIdString.Length + 1]; + newData[0] = (byte)msgIdString.Length; + for (int r = 0; r < msgIdString.Length; r++) + newData[r + 1] = (byte)msgIdString[r]; + + Buffer.BlockCopy(data, 0, newData, msgIdString.Length + 1, data.Length); + + MyAPIGateway.Multiplayer.SendMessageToOthers(9000, newData); + } + + public class ServerMessageItem + { + public string From { get; set; } + public string Message { get; set; } + } } } From e8787187de87b5105520ce2e8d73626645d5d935 Mon Sep 17 00:00:00 2001 From: Tyrsis Date: Mon, 25 May 2015 14:05:05 -0400 Subject: [PATCH 2/2] Get rid of some junk Some older commented code, no need for it. --- EssentialsPlugin/EntityManagers/VoxelManagement.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/EssentialsPlugin/EntityManagers/VoxelManagement.cs b/EssentialsPlugin/EntityManagers/VoxelManagement.cs index 67f8c4b..701d848 100644 --- a/EssentialsPlugin/EntityManagers/VoxelManagement.cs +++ b/EssentialsPlugin/EntityManagers/VoxelManagement.cs @@ -146,9 +146,6 @@ private static void SendVoxelData(ulong steamId, IMyEntity voxel) Logging.WriteLineAndConsole(string.Format("Sending Voxel Header Data: {0} / {1} - {2} ({3})", voxelData.Length, headerData.Length, steamId, voxel.GetPosition())); Communication.SendDataMessage(steamId, 5001, headerData); - //if(RadarManagement.Instance.IsEnabled(steamId)) - // Communication.SendClientMessage(steamId, string.Format("/waypoint add \"{0}\" \"{1}\" Neutral {2} {3} {4} 30000", voxelMap.StorageName, "Asteroid", Math.Floor(header.Position.X), Math.Floor(header.Position.Y), Math.Floor(header.Position.Z))); - int blockSize = 4096; for (ushort r = 0; r < (voxelData.Length / blockSize) + 1; r++) {