Skip to content
This repository was archived by the owner on Jun 23, 2023. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
187 changes: 187 additions & 0 deletions EssentialsPlugin/EntityManagers/VoxelManagement.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
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<ulong, HashSet<long>> m_userVoxels = new Dictionary<ulong, HashSet<long>>();
private static bool m_voxelCheck = false;

public static void CheckAndSendVoxels()
{
if (m_voxelCheck)
return;

m_voxelCheck = true;

try
{
DateTime start = DateTime.Now;
HashSet<IMyEntity> entities = new HashSet<IMyEntity>();
List<IMyPlayer> players = new List<IMyPlayer>();
try
{
MyAPIGateway.Entities.GetEntities(entities);
MyAPIGateway.Players.GetPlayers(players);
}
catch
{
Logging.WriteLineAndConsole(string.Format("CheckAndSendVoxels(): Entity list busy, skipping check"));
return;
}

HashSet<Tuple<ulong, IMyEntity>> voxelsToSend = new HashSet<Tuple<ulong, IMyEntity>>();
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<long>());

HashSet<long> voxels = m_userVoxels[player.SteamUserId];

if (distance < PluginSettings.Instance.DynamicVoxelDistance && !voxels.Contains(entity.EntityId))
{
voxelsToSend.Add(new Tuple<ulong, IMyEntity>(player.SteamUserId, entity));
}
}
}
}

if (voxelsToSend.Count > 0)
{
Wrapper.GameAction(() =>
{
foreach (Tuple<ulong, IMyEntity> 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<long> 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<long>());

HashSet<long> 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<VoxelHeaderData>(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);

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; }
}
}
}
26 changes: 26 additions & 0 deletions EssentialsPlugin/Essentials.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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.")]
Expand Down
2 changes: 2 additions & 0 deletions EssentialsPlugin/EssentialsPlugin.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@
<Compile Include="ControlForm.Designer.cs">
<DependentUpon>ControlForm.cs</DependentUpon>
</Compile>
<Compile Include="EntityManagers\VoxelManagement.cs" />
<Compile Include="Essentials.cs" />
<Compile Include="EntityManagers\BlockManagement.cs" />
<Compile Include="EntityManagers\TurretManagement.cs" />
Expand All @@ -142,6 +143,7 @@
<Compile Include="ProcessHandlers\ProcessConquest.cs" />
<Compile Include="ProcessHandlers\ProcessLoginTracking.cs" />
<Compile Include="ProcessHandlers\ProcessSpawnShipTracking.cs" />
<Compile Include="ProcessHandlers\ProcessVoxels.cs" />
<Compile Include="ProcessHandlers\ProcessWaypoints.cs" />
<Compile Include="ProcessHandlers\ProcessProtection.cs" />
<Compile Include="Settings\PluginSettings.cs" />
Expand Down
62 changes: 62 additions & 0 deletions EssentialsPlugin/ProcessHandlers/ProcessVoxels.cs
Original file line number Diff line number Diff line change
@@ -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);
}
}
}

24 changes: 24 additions & 0 deletions EssentialsPlugin/Settings/PluginSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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; }
Expand Down Expand Up @@ -792,6 +814,8 @@ public PluginSettings()
_dynamicShowMessages = false;
_dynamicTurretTargetDistance = 2000;
_dynamicTurretManagementEnabled = false;
_dynamicVoxelManagementEnabled = false;
_dynamicVoxelDistance = 20000;

_dockingShipsPerZone = 1;

Expand Down
32 changes: 32 additions & 0 deletions EssentialsPlugin/Utility/Communication.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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; }
}
}
}