diff --git a/Utility Mods/CameraInfoApi/Data/Scripts/CameraInfoApi/CameraDataPacket.cs b/Utility Mods/CameraInfoApi/Data/Scripts/CameraInfoApi/CameraDataPacket.cs new file mode 100644 index 000000000..d1ceb042d --- /dev/null +++ b/Utility Mods/CameraInfoApi/Data/Scripts/CameraInfoApi/CameraDataPacket.cs @@ -0,0 +1,16 @@ +using ProtoBuf; +using VRage; +using VRageMath; + +namespace CameraInfoApi.Data.Scripts.CameraInfoApi +{ + [ProtoContract] + internal class CameraDataPacket + { + [ProtoMember(1)] public MatrixD Matrix; + [ProtoMember(2)] public float FieldOfView; + [ProtoMember(3)] public long GridId; + + public MyTuple Tuple => new MyTuple(Matrix, FieldOfView); + } +} diff --git a/Utility Mods/CameraInfoApi/Data/Scripts/CameraInfoApi/ClientMain.cs b/Utility Mods/CameraInfoApi/Data/Scripts/CameraInfoApi/ClientMain.cs new file mode 100644 index 000000000..bc079a312 --- /dev/null +++ b/Utility Mods/CameraInfoApi/Data/Scripts/CameraInfoApi/ClientMain.cs @@ -0,0 +1,46 @@ +using CameraInfoApi.Data.Scripts.CameraInfoApi; +using Sandbox.ModAPI; +using System; +using VRage.Game.Components; +using VRage.Game.ModAPI; +using VRageMath; + +namespace CameraInfoApi +{ + [MySessionComponentDescriptor(MyUpdateOrder.AfterSimulation)] + internal class ClientMain : MySessionComponentBase + { + private IMyCubeGrid prevGrid = null; + private int _ticks = 0; + public override void UpdateAfterSimulation() + { + if (MyAPIGateway.Utilities.IsDedicated) + return; + + if (_ticks++ % 10 != 0) + return; + + var clientGrid = (MyAPIGateway.Session.Player?.Controller?.ControlledEntity as IMyShipController)?.CubeGrid; + if (clientGrid == null) + { + if (prevGrid != null) + MyAPIGateway.Multiplayer.SendMessageToServer(3621, MyAPIGateway.Utilities.SerializeToBinary(new CameraDataPacket() + { + Matrix = MatrixD.Identity, + FieldOfView = -1, + GridId = prevGrid.EntityId, + })); + prevGrid = null; + return; + } + + prevGrid = clientGrid; + MyAPIGateway.Multiplayer.SendMessageToServer(3621, MyAPIGateway.Utilities.SerializeToBinary(new CameraDataPacket() + { + Matrix = MyAPIGateway.Session.Camera.ViewMatrix, + FieldOfView = MyAPIGateway.Session.Camera.FieldOfViewAngle, + GridId = prevGrid.EntityId, + })); + } + } +} diff --git a/Utility Mods/CameraInfoApi/Data/Scripts/CameraInfoApi/ServerMain.cs b/Utility Mods/CameraInfoApi/Data/Scripts/CameraInfoApi/ServerMain.cs new file mode 100644 index 000000000..7f0b4123e --- /dev/null +++ b/Utility Mods/CameraInfoApi/Data/Scripts/CameraInfoApi/ServerMain.cs @@ -0,0 +1,81 @@ +using CameraInfoApi.Data.Scripts.CameraInfoApi; +using Sandbox.Game.Entities; +using Sandbox.ModAPI; +using System; +using System.Collections.Generic; +using VRage; +using VRage.Game.Components; +using VRage.Game.ModAPI; +using VRageMath; + +namespace CameraInfoApi +{ + internal class ServerMain : MySessionComponentBase + { + public Dictionary> CameraInfos = new Dictionary>(); + + public override void LoadData() + { + if (!MyAPIGateway.Session.IsServer) + return; + + MyAPIGateway.Multiplayer.RegisterSecureMessageHandler(3621, HandleMessage); + InitPbApi(); + } + + protected override void UnloadData() + { + if (!MyAPIGateway.Session.IsServer) + return; + + MyAPIGateway.Multiplayer.UnregisterSecureMessageHandler(3621, HandleMessage); + } + + private void HandleMessage(ushort handlerId, byte[] package, ulong senderSteamId, bool fromServer) + { + if (package == null || package.Length == 0) + return; + var message = MyAPIGateway.Utilities.SerializeFromBinary(package); + if (message == null) + return; + + var grid = MyAPIGateway.Entities.GetEntityById(message.GridId) as MyCubeGrid; + if (grid == null) + return; + + if (message.FieldOfView == -1) + { + CameraInfos.Remove(grid); + return; + } + + CameraInfos[grid] = message.Tuple; + } + + private void InitPbApi() + { + var property = MyAPIGateway.TerminalControls.CreateProperty?>, IMyProgrammableBlock>("CameraInfoApi"); + property.Getter = b => () => + { + MyTuple info; + if (!CameraInfos.TryGetValue((MyCubeGrid) b.CubeGrid, out info)) + return null; + return new MyTuple?(info); + }; + MyAPIGateway.TerminalControls.AddControl(property); + + MyAPIGateway.Entities.GetEntities(null, ent => + { + var grid = ent as IMyCubeGrid; + if (grid == null) + return false; + + // Workaround for scripts crashing when loading before the API is ready (i.e. on world load) + foreach (var pb in grid.GetFatBlocks()) + if (!pb.IsRunning && pb.ProgramData.Contains("CameraInfoApi")) + pb.Recompile(); + return false; + }); + } + } +} diff --git a/Utility Mods/CameraInfoApi/Properties/AssemblyInfo.cs b/Utility Mods/CameraInfoApi/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..01d77734a --- /dev/null +++ b/Utility Mods/CameraInfoApi/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("CameraInfoApi")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("CameraInfoApi")] +[assembly: AssemblyCopyright("Copyright © 2023")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("4b783ffe-e887-4220-8412-25caa84a7869")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")]