diff --git a/.github/workflows/Aristeas_BuildScripts.yml b/.github/workflows/Aristeas_BuildScripts.yml index 37bea3400..5dff320f8 100644 --- a/.github/workflows/Aristeas_BuildScripts.yml +++ b/.github/workflows/Aristeas_BuildScripts.yml @@ -23,4 +23,4 @@ jobs: # done - id: build-mods run: | - & "C:\Program Files\SCUniversalUpload\SC_NewUniversalUpload.exe" "build" --repo "${{ github.workspace }}" --changes "${{ steps.changed-files.outputs.all_changed_and_modified_files }}" + & "C:\Program Files\SCUniversalUpload\SC_NewUniversalUpload.exe" "build" --repo "${{ github.workspace }}" diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 000000000..d8e933aa1 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,35 @@ +### Prerequsites: +- (extremely recommended) github Desktop, GitExtentions, or something similar +- knowing the layout of SE mod files +- enough space to download the entire git repo (~5gb)? + +### Step 1: +- ``Fork`` this repository to a folder on your computer. Name it something like SCModRepository-Yourname. This is where your edits can be made, and is apparently how actual projects do it. + +### Step 2: +- ``Make a branch`` for the changes you want to do on ``your local repository``. (i.e. SCModRepository-Yourname/BuffMyFavoriteGunPlease) Use your local repository's ``Main`` branch to keep in sync with starcore's ``Main`` branch, it makes edits much easier. You just click the button on github to sync it. + +### Step 3: +- To test your changes ingame, Copy the mod you want to edit to your ``%Appdata%/SpaceEngineers/Mods`` folder. + +### Step 4: +- Make your edits and throw it back in the repository folder. you can use the ``.bat file`` included in the repository to link your local Space Engineers mods with the ones in the repository. + +### Step 5: +- Submit a pull request so that the branch can be merged into the SCModRepository/Main one. +- You can merge your PR yourself if you're confident, or ask for review. Once merged, the development version of the mod will automatically be updated. + +Note - the `Main` branch is for the ModDev world, and `Stable` is for the primary combat and build worlds. `Stable` pushes are done in bulk after Test Tournaments. + + +*** + + +## How does this work? +The repository contains a .github folder, Space Engineers mod folders, and a .gitignore file. +### .github folder: +- contains the instructions to the bot what to do after a "push", currently set to upload to the steam workshop after [SCUniversalUpload](https://github.com/StarCoreSE/SCModRepository/blob/main/.github/workflows/Aristeas%20NewUniversalUpload.yml) detects a change in a folder with a `modinfo_BRANCHNAME.sbmi` file. +### SE Mod folders: +- contains all the data that would load normally as an SE mod +### .gitignore file +- tells git what to exclude during a push (like .sln files in visual studio) diff --git a/Gamemode Mods/Starcore_Pointslist/Data/Scripts/Additions/PointAdditions.cs b/Gamemode Mods/Starcore_Pointslist/Data/Scripts/Additions/PointAdditions.cs index 3bcf84387..c087de018 100644 --- a/Gamemode Mods/Starcore_Pointslist/Data/Scripts/Additions/PointAdditions.cs +++ b/Gamemode Mods/Starcore_Pointslist/Data/Scripts/Additions/PointAdditions.cs @@ -762,9 +762,9 @@ internal class PointAdditions : MySessionComponentBase ["Caster_Reactor"] = 125, ["Heat_Heatsink"] = 10, ["Heat_FlatRadiator"] = 10, - ["ActiveRadiator"] = 250, - ["RadiatorPanel"] = 5, - ["ExtendableRadiatorBase"] = 5, + ["ActiveRadiator"] = 250, + ["RadiatorPanel"] = 10, + ["ExtendableRadiatorBase"] = 5, #endregion }; diff --git a/Gamemode Mods/Starcore_Sharetrack/Data/Scripts/ShipPoints/API/StealthAPI.cs b/Gamemode Mods/Starcore_Sharetrack/Data/Scripts/ShipPoints/API/StealthAPI.cs new file mode 100644 index 000000000..8f62cc6da --- /dev/null +++ b/Gamemode Mods/Starcore_Sharetrack/Data/Scripts/ShipPoints/API/StealthAPI.cs @@ -0,0 +1,119 @@ +using Sandbox.ModAPI; +using System; +using System.Collections.Generic; +using VRage.Game.ModAPI; + +namespace StealthSystem +{ + internal class StealthAPI + { + /// Returns true if drive status was toggled successfully. + /// Ignore power requirements and overheat. + public bool ToggleStealth(IMyTerminalBlock drive, bool force) => _toggleStealth?.Invoke(drive, force) ?? false; + + /// Returns status of drive. 0 = Ready, 1 = Active, 2 = Cooldown, 3 = Not enough power, 4 = Offline + public int GetStatus(IMyTerminalBlock drive) => _getStatus?.Invoke(drive) ?? 4; + + /// Returns remaining duration of stealth/cooldown. + public int GetDuration(IMyTerminalBlock drive) => _getDuration?.Invoke(drive) ?? 0; + + /// Retuns active stealth drive on grid if one exists, otherwise returns null. + public IMyTerminalBlock GetMainDrive(IMyCubeGrid grid) => _getMainDrive?.Invoke(grid); + + /// Collection to populate with heat sinks on grid. + public void GetHeatSinks(IMyCubeGrid grid, ICollection sinks) => _getHeatSinks?.Invoke(grid, sinks); + + + + private const long CHANNEL = 2172757427; + private bool _isRegistered; + private bool _apiInit; + private Action _readyCallback; + + private Func _toggleStealth; + private Func _getStatus; + private Func _getDuration; + private Func _getMainDrive; + private Action> _getHeatSinks; + + public bool IsReady { get; private set; } + + + /// + /// Ask CoreSystems to send the API methods. + /// Throws an exception if it gets called more than once per session without . + /// + /// Method to be called when CoreSystems replies. + public void Load(Action readyCallback = null) + { + if (_isRegistered) + throw new Exception($"{GetType().Name}.Load() should not be called multiple times!"); + + _readyCallback = readyCallback; + _isRegistered = true; + MyAPIGateway.Utilities.RegisterMessageHandler(CHANNEL, HandleMessage); + MyAPIGateway.Utilities.SendModMessage(CHANNEL, "ApiEndpointRequest"); + } + + public void Unload() + { + MyAPIGateway.Utilities.UnregisterMessageHandler(CHANNEL, HandleMessage); + + ApiAssign(null); + + _isRegistered = false; + _apiInit = false; + IsReady = false; + } + + private void HandleMessage(object obj) + { + if (_apiInit || obj is string + ) // the sent "ApiEndpointRequest" will also be received here, explicitly ignoring that + return; + + var dict = obj as IReadOnlyDictionary; + + if (dict == null) + return; + + ApiAssign(dict); + + IsReady = true; + _readyCallback?.Invoke(); + } + + public void ApiAssign(IReadOnlyDictionary delegates) + { + _apiInit = (delegates != null); + /// base methods + AssignMethod(delegates, "ToggleStealth", ref _toggleStealth); + AssignMethod(delegates, "GetStatus", ref _getStatus); + AssignMethod(delegates, "GetDuration", ref _getDuration); + AssignMethod(delegates, "GetMainDrive", ref _getMainDrive); + AssignMethod(delegates, "GetHeatSinks", ref _getHeatSinks); + } + + private void AssignMethod(IReadOnlyDictionary delegates, string name, ref T field) + where T : class + { + if (delegates == null) + { + field = null; + return; + } + + Delegate del; + if (!delegates.TryGetValue(name, out del)) + throw new Exception($"{GetType().Name} :: Couldn't find {name} delegate of type {typeof(T)}"); + + field = del as T; + + if (field == null) + throw new Exception( + $"{GetType().Name} :: Delegate {name} is not type {typeof(T)}, instead it's: {del.GetType()}"); + } + + } + +} \ No newline at end of file diff --git a/Gamemode Mods/Starcore_Sharetrack/Data/Scripts/ShipPoints/MasterSession.cs b/Gamemode Mods/Starcore_Sharetrack/Data/Scripts/ShipPoints/MasterSession.cs index 9d1c78f61..19d6edb72 100644 --- a/Gamemode Mods/Starcore_Sharetrack/Data/Scripts/ShipPoints/MasterSession.cs +++ b/Gamemode Mods/Starcore_Sharetrack/Data/Scripts/ShipPoints/MasterSession.cs @@ -4,6 +4,7 @@ using StarCore.ShareTrack.HeartNetworking; using StarCore.ShareTrack.ShipTracking; using StarCore.ShareTrack.TrackerApi; +using StealthSystem; using VRage.Game.Components; using VRageMath; @@ -20,6 +21,7 @@ internal class MasterSession : MySessionComponentBase public static MasterSession I; public static SharetrackConfig Config; + public StealthAPI StealthApi = new StealthAPI(); public HudAPIv2 TextHudApi; public Action HudRegistered = () => { }; @@ -46,6 +48,8 @@ public override void LoadData() _buildingBlockPoints = new BuildingBlockPoints(); TrackingManager.Init(); // Initialize TrackingManager, but don't start tracking yet + StealthApi.Load(); + if (!MyAPIGateway.Utilities.IsDedicated) // Initialize the sphere entities // Initialize the text_api with the HUDRegistered callback diff --git a/Gamemode Mods/Starcore_Sharetrack/Data/Scripts/ShipPoints/ShipTracking/ShipTracker.cs b/Gamemode Mods/Starcore_Sharetrack/Data/Scripts/ShipPoints/ShipTracking/ShipTracker.cs index 1c9c81463..2fb19819d 100644 --- a/Gamemode Mods/Starcore_Sharetrack/Data/Scripts/ShipPoints/ShipTracking/ShipTracker.cs +++ b/Gamemode Mods/Starcore_Sharetrack/Data/Scripts/ShipPoints/ShipTracking/ShipTracker.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Text; @@ -351,6 +351,14 @@ public void UpdateHud() camera.WorldMatrix.Forward); var stealthed = ((uint)Grid.Flags & 0x1000000) > 0; + + if (MasterSession.I.StealthApi?.IsReady ?? false) + { + var mainStealthDrive = MasterSession.I.StealthApi.GetMainDrive(Grid); + if (mainStealthDrive != null) + stealthed |= MasterSession.I.StealthApi.GetStatus(mainStealthDrive) == 1; + } + var visible = !(newOrigin.X > 1 || newOrigin.X < -1 || newOrigin.Y > 1 || newOrigin.Y < -1) && angle <= fov && !stealthed; @@ -687,4 +695,4 @@ public float CurrentFieldPower #endregion #endregion } -} \ No newline at end of file +} diff --git a/README.md b/README.md index 19b4b32ac..6ea2b2695 100644 --- a/README.md +++ b/README.md @@ -9,16 +9,18 @@ In StarCore, teams build their own ships and battle for the spot of champion in a StarCore Tournament. They normally take place on Saturdays and are streamed live by one of several streamers over on Twitch (See #content-announcements in the StarCore Discord for more information). It's time to join the arena! +*** ## Contribution guide -### prerequsites: + +### Prerequsites: - (extremely recommended) github Desktop, GitExtentions, or something similar - knowing the layout of SE mod files - enough space to download the entire git repo (~5gb)? ### Step 1: -- ``Fork`` this repository to a folder on your computer. Name it something like SCModRepository-Yourname. This is where your edits can be made, and is apparently how actual projects do it. You can do this in GitHub desktop by git cloning the url, or through the github website, with the "fork" button which you can then git clone to a folder on your computer where you can make changes. +- ``Fork`` this repository to a folder on your computer. Name it something like SCModRepository-Yourname. This is where your edits can be made, and is apparently how actual projects do it. ### Step 2: - ``Make a branch`` for the changes you want to do on ``your local repository``. (i.e. SCModRepository-Yourname/BuffMyFavoriteGunPlease) Use your local repository's ``Main`` branch to keep in sync with starcore's ``Main`` branch, it makes edits much easier. You just click the button on github to sync it. @@ -30,17 +32,19 @@ In StarCore, teams build their own ships and battle for the spot of champion in - Make your edits and throw it back in the repository folder. you can use the ``.bat file`` included in the repository to link your local Space Engineers mods with the ones in the repository. ### Step 5: -- Submit a pull request so that the branch can be merged into the SCModRepository/master one. - +- Submit a pull request so that the branch can be merged into the SCModRepository/Main one. +- You can merge your PR yourself if you're confident, or ask for review. Once merged, the development version of the mod will automatically be updated. +Note - the `Main` branch is for the ModDev world, and `Stable` is for the primary combat and build worlds. `Stable` pushes are done in bulk after Test Tournaments. +*** ## How does this work? The repository contains a .github folder, Space Engineers mod folders, and a .gitignore file. ### .github folder: -- contains the instructions to the bot what to do after a "push", currently set to upload to the steam workshop after the respective .yml file detects a change in the folder its looking for +- contains the instructions to the bot what to do after a "push", currently set to upload to the steam workshop after [SCUniversalUpload](https://github.com/StarCoreSE/SCModRepository/blob/main/.github/workflows/Aristeas%20NewUniversalUpload.yml) detects a change in a folder with a `modinfo_BRANCHNAME.sbmi` file. ### SE Mod folders: - contains all the data that would load normally as an SE mod ### .gitignore file 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..c3a52df5a --- /dev/null +++ b/Utility Mods/CameraInfoApi/Data/Scripts/CameraInfoApi/ServerMain.cs @@ -0,0 +1,82 @@ +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 +{ + [MySessionComponentDescriptor(MyUpdateOrder.NoUpdate)] + 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")] diff --git a/Utility Mods/CameraInfoApi/uploaddisable_main.sbmi b/Utility Mods/CameraInfoApi/uploaddisable_main.sbmi new file mode 100644 index 000000000..e69de29bb diff --git a/Utility Mods/CameraInfoApi/uploaddisable_stable.sbmi b/Utility Mods/CameraInfoApi/uploaddisable_stable.sbmi new file mode 100644 index 000000000..e69de29bb diff --git a/Utility Mods/MoA Fusion Systems/Data/BlockCategories.sbc b/Utility Mods/MoA Fusion Systems/Data/BlockCategories.sbc index 47d25cb99..caa2b293a 100644 --- a/Utility Mods/MoA Fusion Systems/Data/BlockCategories.sbc +++ b/Utility Mods/MoA Fusion Systems/Data/BlockCategories.sbc @@ -24,6 +24,7 @@ ExtendableRadiatorBase Heat_FlatRadiator ActiveRadiator + ActiveRadiatorFake diff --git a/Utility Mods/MoA Fusion Systems/Data/CubeBlocks/ActiveRadiator.sbc b/Utility Mods/MoA Fusion Systems/Data/CubeBlocks/ActiveRadiator.sbc index d915be8dc..b3dbadc28 100644 --- a/Utility Mods/MoA Fusion Systems/Data/CubeBlocks/ActiveRadiator.sbc +++ b/Utility Mods/MoA Fusion Systems/Data/CubeBlocks/ActiveRadiator.sbc @@ -36,6 +36,43 @@ X + + + + TerminalBlock + ActiveRadiatorFake + + RealFake Rotary Active Radiator + + Looks just like the Rotary Active Radiator, but doesn't actually reduce heat! + Animation tied to grid power draw. + + Textures\GUI\Icons\Cubes\ActiveRadiator.dds + Large + TriangleMesh + + + Models\ActiveRadiator.mwm + + + + + + + + + + 0.3 + ActiveRadiatorFake + + + + + + + + + X \ No newline at end of file diff --git a/Utility Mods/MoA Fusion Systems/Data/Scripts/ModularAssemblies/HeatParts/ExtendableRadiators/ActiveRadiatorAnimation.cs b/Utility Mods/MoA Fusion Systems/Data/Scripts/ModularAssemblies/HeatParts/ExtendableRadiators/ActiveRadiatorAnimation.cs index b21d9f7df..a9b2abf5b 100644 --- a/Utility Mods/MoA Fusion Systems/Data/Scripts/ModularAssemblies/HeatParts/ExtendableRadiators/ActiveRadiatorAnimation.cs +++ b/Utility Mods/MoA Fusion Systems/Data/Scripts/ModularAssemblies/HeatParts/ExtendableRadiators/ActiveRadiatorAnimation.cs @@ -9,12 +9,15 @@ namespace Epstein_Fusion_DS.HeatParts.ExtendableRadiators { - [MyEntityComponentDescriptor(typeof(MyObjectBuilder_TerminalBlock), false, "ActiveRadiator")] + [MyEntityComponentDescriptor(typeof(MyObjectBuilder_TerminalBlock), false, "ActiveRadiator", "ActiveRadiatorFake")] internal class ActiveRadiatorAnimation : MyGameLogicComponent { private IMyCubeBlock Block; private MyEntitySubpart FanPart; private MyParticleEffect Particle; + private readonly MyDefinitionId ElectricityId = MyDefinitionId.Parse("GasProperties/Electricity"); + + private float UsedPowerPct => Block.CubeGrid.ResourceDistributor.TotalRequiredInputByType(ElectricityId, Block.CubeGrid) / Block.CubeGrid.ResourceDistributor.MaxAvailableResourceByType(ElectricityId); public override void Init(MyObjectBuilder_EntityBase objectBuilder) { @@ -41,7 +44,9 @@ public override void UpdateOnceBeforeFrame() public override void UpdateAfterSimulation() { - float heatLevel = HeatManager.I.GetGridHeatLevel(Block.CubeGrid); + float heatLevel = Block.BlockDefinition.SubtypeName == "ActiveRadiatorFake" ? UsedPowerPct : HeatManager.I.GetGridHeatLevel(Block.CubeGrid); + if (!Block.IsWorking) + heatLevel = 0; Matrix refMatrix = MatrixD.CreateFromAxisAngle(Vector3D.Up, -0.1 * heatLevel) * FanPart.PositionComp.LocalMatrixRef; refMatrix.Translation = FanPart.PositionComp.LocalMatrixRef.Translation; diff --git a/Utility Mods/SCDefenseBlocks/Data/Scripts/OneFuckingFolderDeeper/FieldGenerator/FieldGenerator_Config.cs b/Utility Mods/SCDefenseBlocks/Data/Scripts/OneFuckingFolderDeeper/FieldGenerator/FieldGenerator_Config.cs index 4822e35e5..b89c15cc8 100644 --- a/Utility Mods/SCDefenseBlocks/Data/Scripts/OneFuckingFolderDeeper/FieldGenerator/FieldGenerator_Config.cs +++ b/Utility Mods/SCDefenseBlocks/Data/Scripts/OneFuckingFolderDeeper/FieldGenerator/FieldGenerator_Config.cs @@ -33,8 +33,8 @@ public class Generator_Settings public float MaxPowerDraw = 500.00f; public float MinPowerDraw = 50.00f; - public int MaxSiegeTime = 60; - public int MinSiegeTime = 15; + public int MaxSiegeTime = 60; + public int MinSiegeTime = 15; public int SiegePowerDraw = 900; public float SiegeModeResistence = 0.9f; @@ -75,79 +75,79 @@ void LoadConfig(MyIni iniParser) void SaveConfig(MyIni iniParser) { - iniParser.Set(IniSection, nameof(MaxModuleCount), MaxModuleCount); - iniParser.SetComment(IniSection, nameof(MaxModuleCount), - " \n[Maximum number of upgrade modules that can be attached to the Field Generator core.]\n" + - "[Each core has 4 mounting points by default.]\n" + - "[Default: 4]"); - - iniParser.Set(IniSection, nameof(PerModuleAmount), PerModuleAmount); - iniParser.SetComment(IniSection, nameof(PerModuleAmount), - " \n[Amount of resistance each attached upgrade module provides.]\n" + - "[Default: 10.0]"); - - iniParser.Set(IniSection, nameof(MaxPowerDraw), MaxPowerDraw); - iniParser.SetComment(IniSection, nameof(MaxPowerDraw), - " \n[The maximum power draw (in MW) when the Field Generator is at full power.]\n" + - "[Default: 500 MW]"); - - iniParser.Set(IniSection, nameof(MinPowerDraw), MinPowerDraw); - iniParser.SetComment(IniSection, nameof(MinPowerDraw), - " \n[Baseline power draw (in MW) at minimum field power.]\n" + - "[Default: 50 MW]"); - - iniParser.Set(IniSection, nameof(MaxSiegeTime), MaxSiegeTime); - iniParser.SetComment(IniSection, nameof(MaxSiegeTime), - " \n[Maximum duration (in seconds) the Field Generator can remain in Siege mode.]\n" + - "[Default: 60s]\n"); - - iniParser.Set(IniSection, nameof(SiegePowerDraw), SiegePowerDraw); - iniParser.SetComment(IniSection, nameof(SiegePowerDraw), - " \n[Power draw (in MW) while Siege mode is active.]\n" + - "[Overrides normal scaled power draw.]\n" + - "[Default: 900 MW]"); - - iniParser.Set(IniSection, nameof(SiegeModeResistence), SiegeModeResistence); - iniParser.SetComment(IniSection, nameof(SiegeModeResistence), - " \n[Amount of damage resistance provided by Siege mode (0.0 to 1.0).]\n" + - "[Example: 0.9 means 90% damage reduction from normal.]\n" + - "[Default: 0.9]"); - - iniParser.Set(IniSection, nameof(SimplifiedMode), SimplifiedMode); - iniParser.SetComment(IniSection, nameof(SimplifiedMode), - " \n[Whether to disable (true) or enable (false) the advanced stability system.]\n" + - "[Default: true]"); - - iniParser.Set(IniSection, nameof(DamageEventThreshold), DamageEventThreshold); - iniParser.SetComment(IniSection, nameof(DamageEventThreshold), - " \n[Number of damage events (within ResetInterval) needed to trigger stability reduction.]\n" + - "[Default: 6]"); - - iniParser.Set(IniSection, nameof(ResetInterval), ResetInterval); - iniParser.SetComment(IniSection, nameof(ResetInterval), - " \n[Time interval (in seconds) between damage counter resets.]\n" + - "[Default: 3]"); - - iniParser.Set(IniSection, nameof(MinBlockCount), MinBlockCount); - iniParser.SetComment(IniSection, nameof(MinBlockCount), - " \n[Minimum grid block count used in the size-based stability calculation.]\n" + - "[Default: 2500]"); - - iniParser.Set(IniSection, nameof(MaxBlockCount), MaxBlockCount); - iniParser.SetComment(IniSection, nameof(MaxBlockCount), - " \n[Maximum grid block count used in the size-based stability calculation.]\n" + - "[Default: 35000]"); - - iniParser.Set(IniSection, nameof(SizeModifierMin), SizeModifierMin); - iniParser.SetComment(IniSection, nameof(SizeModifierMin), - " \n[The lower bound of the size modifier.]\n" + - "[Size Modifier can reduce or increase stability change based on the grid size. This Min is the Increase at Min Grid Size]\n" + - "[Default: 1.2]"); - - iniParser.Set(IniSection, nameof(SizeModifierMax), SizeModifierMax); - iniParser.SetComment(IniSection, nameof(SizeModifierMax), - " \n[The upper bound of the size modifier.]\n" + - "[Size Modifier can reduce or increase stability change based on the grid size. This Max is the Reduction at Max Grid Size]\n" + + iniParser.Set(IniSection, nameof(MaxModuleCount), MaxModuleCount); + iniParser.SetComment(IniSection, nameof(MaxModuleCount), + " \n[Maximum number of upgrade modules that can be attached to the Field Generator core.]\n" + + "[Each core has 4 mounting points by default.]\n" + + "[Default: 4]"); + + iniParser.Set(IniSection, nameof(PerModuleAmount), PerModuleAmount); + iniParser.SetComment(IniSection, nameof(PerModuleAmount), + " \n[Amount of resistance each attached upgrade module provides.]\n" + + "[Default: 10.0]"); + + iniParser.Set(IniSection, nameof(MaxPowerDraw), MaxPowerDraw); + iniParser.SetComment(IniSection, nameof(MaxPowerDraw), + " \n[The maximum power draw (in MW) when the Field Generator is at full power.]\n" + + "[Default: 500 MW]"); + + iniParser.Set(IniSection, nameof(MinPowerDraw), MinPowerDraw); + iniParser.SetComment(IniSection, nameof(MinPowerDraw), + " \n[Baseline power draw (in MW) at minimum field power.]\n" + + "[Default: 50 MW]"); + + iniParser.Set(IniSection, nameof(MaxSiegeTime), MaxSiegeTime); + iniParser.SetComment(IniSection, nameof(MaxSiegeTime), + " \n[Maximum duration (in seconds) the Field Generator can remain in Siege mode.]\n" + + "[Default: 60s]\n"); + + iniParser.Set(IniSection, nameof(SiegePowerDraw), SiegePowerDraw); + iniParser.SetComment(IniSection, nameof(SiegePowerDraw), + " \n[Power draw (in MW) while Siege mode is active.]\n" + + "[Overrides normal scaled power draw.]\n" + + "[Default: 900 MW]"); + + iniParser.Set(IniSection, nameof(SiegeModeResistence), SiegeModeResistence); + iniParser.SetComment(IniSection, nameof(SiegeModeResistence), + " \n[Amount of damage resistance provided by Siege mode (0.0 to 1.0).]\n" + + "[Example: 0.9 means 90% damage reduction from normal.]\n" + + "[Default: 0.9]"); + + iniParser.Set(IniSection, nameof(SimplifiedMode), SimplifiedMode); + iniParser.SetComment(IniSection, nameof(SimplifiedMode), + " \n[Whether to disable (true) or enable (false) the advanced stability system.]\n" + + "[Default: true]"); + + iniParser.Set(IniSection, nameof(DamageEventThreshold), DamageEventThreshold); + iniParser.SetComment(IniSection, nameof(DamageEventThreshold), + " \n[Number of damage events (within ResetInterval) needed to trigger stability reduction.]\n" + + "[Default: 6]"); + + iniParser.Set(IniSection, nameof(ResetInterval), ResetInterval); + iniParser.SetComment(IniSection, nameof(ResetInterval), + " \n[Time interval (in seconds) between damage counter resets.]\n" + + "[Default: 3]"); + + iniParser.Set(IniSection, nameof(MinBlockCount), MinBlockCount); + iniParser.SetComment(IniSection, nameof(MinBlockCount), + " \n[Minimum grid block count used in the size-based stability calculation.]\n" + + "[Default: 2500]"); + + iniParser.Set(IniSection, nameof(MaxBlockCount), MaxBlockCount); + iniParser.SetComment(IniSection, nameof(MaxBlockCount), + " \n[Maximum grid block count used in the size-based stability calculation.]\n" + + "[Default: 35000]"); + + iniParser.Set(IniSection, nameof(SizeModifierMin), SizeModifierMin); + iniParser.SetComment(IniSection, nameof(SizeModifierMin), + " \n[The lower bound of the size modifier.]\n" + + "[Size Modifier can reduce or increase stability change based on the grid size. This Min is the Increase at Min Grid Size]\n" + + "[Default: 1.2]"); + + iniParser.Set(IniSection, nameof(SizeModifierMax), SizeModifierMax); + iniParser.SetComment(IniSection, nameof(SizeModifierMax), + " \n[The upper bound of the size modifier.]\n" + + "[Size Modifier can reduce or increase stability change based on the grid size. This Max is the Reduction at Max Grid Size]\n" + "[Default: 0.8]"); } diff --git a/Utility Mods/SCDefenseBlocks/Data/Scripts/OneFuckingFolderDeeper/FieldGenerator/FieldGenerator_Core.cs b/Utility Mods/SCDefenseBlocks/Data/Scripts/OneFuckingFolderDeeper/FieldGenerator/FieldGenerator_Core.cs index cb8c55567..28f4cdf96 100644 --- a/Utility Mods/SCDefenseBlocks/Data/Scripts/OneFuckingFolderDeeper/FieldGenerator/FieldGenerator_Core.cs +++ b/Utility Mods/SCDefenseBlocks/Data/Scripts/OneFuckingFolderDeeper/FieldGenerator/FieldGenerator_Core.cs @@ -471,7 +471,7 @@ private void EndSiegeMode() SiegeBlockEnabler(Block.CubeGrid.GetFatBlocks(), true); - SiegeCooldownTime.Value = (SiegeElapsedTime.Value > Config.MinSiegeTime) ? (SiegeElapsedTime.Value * 2) : Config.MinSiegeTime; + SiegeCooldownTime.Value = Math.Max(SiegeElapsedTime.Value * 2, Config.MinSiegeTime); SiegeElapsedTime.Value = 0; SiegeCooldownActive.Value = true; } diff --git a/Utility Mods/StarCore Tournament Weapon Category/Data/BlockCategories_StarCoreCorporate.sbc b/Utility Mods/StarCore Tournament Weapon Category/Data/BlockCategories_StarCoreCorporate.sbc index 99d8c16c0..9acfa59a7 100644 --- a/Utility Mods/StarCore Tournament Weapon Category/Data/BlockCategories_StarCoreCorporate.sbc +++ b/Utility Mods/StarCore Tournament Weapon Category/Data/BlockCategories_StarCoreCorporate.sbc @@ -8,86 +8,150 @@ GuiBlockCategoryDefinition - SC [All Access] - .SC_.[All Access] + SC [All Access] Utility + .SC_.[ALL]_A true - + GravityGenerator + Door + AirtightHangarDoor + SurvivalKitLarge + SmallLight + LargeBlockFrontLight + + SC_PowerControlSystem_L + SC_RCS_Computer + + LargeBlockConveyorPipeJunction + LargeBlockConveyor + ConveyorTube + ConveyorTubeDuct + + MA_Buster_ArmorBlock + + LargeDecoy + LargeBlockRadioAntenna + LargeFlightMovement + + LargeTurretControlBlock + SELtdLargeNanobotBuildAndRepairSystem - - - FieldGen_Core - FieldGen_Capacity_Upgrade + + LargeProgrammableBlock + 6SidePB + LargeBlockRemoteControl + + DampeningEnhancer_x2_Large + LargeStator + WorklightSmall + + + + + + + GuiBlockCategoryDefinition + + [ALL] Mobility + .SC_.[ALL]_B + true + + - MA_Afterburner_Large_5x SC_SRB DETPAK + MA_Afterburner_Large_5x AncientAfterburnerT40 - LargeDecoy_MetalFoam - - SC_Flare + BlinkDriveLarge - - Starcore_RWR_Projectiles + LargeBlockGyro + AQD_LG_GyroBooster + AQD_LG_LargeGyro + AQD_LG_GyroUpgrade - - Caster_Accelerator_0 - Caster_Accelerator_90 - Caster_Feeder - Caster_CentralPipe_0 - Caster_CentralPipe_90 - Caster_CentralPipe_T + LargeBlockLargeThrust + HugeHydrogenThruster + AWGFocusDrive + IonHeavyCovered + + Caster_FocusLens - Caster_Reactor - - SC_RCS_Computer - DampeningEnhancer_x2_Large - SC_PowerControlSystem_L - LargeLargeBlockUpgrade - AQD_LG_GyroBooster - AQD_LG_GyroUpgrade + LargeHydrogenTank + LargeHydrogenTankSmall + + + + + + + GuiBlockCategoryDefinition + + [ALL] Defense + .SC_.[ALL]_C + true + + + + FieldGen_Core + FieldGen_Capacity_Upgrade + + + Starcore_RWR_Projectiles SC_Radome - WorklightSmall - BlinkDriveLarge + Mk25Rangefinder - - GIGA_BLASTPLATE + 3x3_Blastplate_A + 3x3_Blastplate_B + 3x3_Blastplate_C + ACTIVE_BLASTPLATE + + SC_Flare + LargeDecoy_MetalFoam + + DSControlLarge + EmitterL + LargeShieldModulator + LargeEnhancer + + Barbette5x5 + + + + + + + GuiBlockCategoryDefinition + + [ALL] Power + .SC_.[ALL]_D + true + + + LargeBlockSolarPanel + LargeBlockBatteryBlock + LargeBlockSmallGenerator + SmallLargeBlockUpgrade + LargeBlockLargeGenerator + LargeLargeBlockUpgrade + + + Caster_Accelerator_0 + Caster_CentralPipe_0 + Caster_Reactor + RadiatorPanel + Heat_Heatsink - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + @@ -99,18 +163,11 @@ - NovaCannon - GothicTorp - MacroCannon + AegisFlakTurret + MacroCannon HeavyMacroCannon - FixedLance LanceBattery - LanceLightBattery - LanceHeavyBattery - MacroTurret - MacroLightTurret - MacroHeavyTurret - AegisFlakTurret + NovaCannon @@ -126,22 +183,15 @@ + Priest_Block + PriestReskin_Block + Reaver_Coilgun + Assault_Coil_Turret DualSnubLaserTurret - UnguidedRocketTurret DualPulseLaserTurret - DrunkRocketTurret - Reaver_Coilgun - - Assault_Coil_Turret - APE_Strong - Devastator_Torp - Priest_Block - Type18_Artillery - Type19_Driver - Type21_Artillery - Type22_Driver - Type24_Artillery - Type25_Driver + APE_Strong + Type18_Artillery + Devastator_Torp @@ -151,23 +201,17 @@ GuiBlockCategoryDefinition - [FLAW] - .SC_[FLAW] + [FLW] + .SC_[FLW] true - + LargeRailgun_SC GoalieCasemate - KreegMagnetarCannon - Thagomizer - HeavyFighterBay - HeavyCarronade_5x5_Turret - X4_7x7_HeavyTurret - VindicatorKineticLance - HadeanPlasmaBlastgun - JN_175Fixed - longsword + X4_7x7_HeavyTurret + HeavyCarronade_5x5_Turret + JN_175Fixed @@ -183,18 +227,14 @@ - MA_Fixed_T3 + MA_PDX + MA_Gimbal_Laser + UNN_Heavy_Torpedo + MA_AC150 MA_Gimbal_Laser_T2 - MA_Gladius - MA_Guardian - MA_Derecho - MCRN_Heavy_Torpedo MA_T2PDX - MA_AC150 - MA_Gimbal_Laser - MA_PDX - MA_Tiger - UNN_Heavy_Torpedo + MA_Derecho + MA_Gladius @@ -210,20 +250,13 @@ - NHI_Heavy_Gun_Turret - NHI_Autocannon_Turret - NHI_Fixed_Autocannon NHI_PD_Turret + NHI_Gatling_Laser_Turret + NHI_Autocannon_Turret NHI_Kinetic_Cannon_Turret - NHI_Fixed_Gatling_Laser - SC_Coil_Cannon - NHI_Mk1_Cannon_Turret NHI_Mk2_Cannon_Turret - NHI_Mk3_Cannon_Turret - NHI_Light_Railgun_Turret - NHI_Gatling_Laser_Turret - NHI_Light_Autocannon_Turret - + SC_Coil_Cannon + NHI_Mk3_Cannon_Turret @@ -238,16 +271,10 @@ - SC_AR_Eris - SC_AR_MagnaStar SC_AR_Tumult - SC_AR_Afflictor - SC_AR_Afflictor_Slanted SC_AR_Deimos - SC_AR_FocusedBeam SC_AR_Forager - SC_AR_Heliod - SC_AR_Phobos + SC_AR_Eris @@ -263,17 +290,12 @@ - K_SA_HeavyMetal_Gauss_A - K_SA_HeavyMetal_Gauss_ERII - K_SA_HeavyMetal_Gauss_PGBC SA_HMI_Erebos - Hellfire_Laser_Block - K_SA_HeavyMetal_Spinal_Rotary_Reskin - K_SA_HeavyMetal_Spinal_Rotary - K_SA_Gauss_ERC + K_SA_HeavyMetal_Gauss_A K_SA_HeavyMetal_Gauss_ERFM + K_SA_HeavyMetal_Gauss_PGBC - + @@ -287,15 +309,10 @@ - K_SA_Launcher_VIV - HAS_Cyclops - HAS_Mammon - HAS_Nyx K_SA_Launcher_VI - HAS_Thanatos - HAS_Esper + K_SA_Launcher_VIV HAS_Avenger - HAS_Crossfield + HAS_Esper @@ -313,12 +330,6 @@ Hexcannon MetalStorm - TaiidanHangarBomber - TaiidanHangarBomberMedium - TaiidanRailBomber - TaiidanHangarFighter - TaiidanRailFighter - TaiidanSingleHangar @@ -332,24 +343,22 @@ .SC_[BTI] true + - Starcore_AMS_II_Block - ERPPC - Starcore_L_Laser_Block - ModularLRM5 + ModularLRM5 ModularLRM5Angled ModularLRM5AngledReversed - ModularMiddleLRM5 - Starcore_M_Laser_Block - ModularMRM10 + ModularMiddleLRM5 + Starcore_Arrow_Block_Single + ModularMRM10 ModularMRM10Angled ModularMRM10AngledReversed ModularMiddleMRM10 - Starcore_AMS_I_Block - Starcore_PPC_Block - ModularSRM8 - Starcore_Arrow_Block - Starcore_Arrow_Block_Single + Starcore_AMS_I_Block + Starcore_AMS_II_Block + Starcore_Arrow_Block + ERPPC + @@ -363,13 +372,13 @@ MagnaPulse_Gen - - Impulse_Torch - + + + Counter_Battery - S_Chem_Laser_Block - S_Armored_Laser_Block - + + + Nariman_Dart_Turret SolHyp_Magnetic_Coilgun @@ -383,26 +392,19 @@ .SC_[FAS] true + - 16InchTriple - 6InchTriple + BoforTwinRemodel + QuadBofor + PomPomMain 127mmMk32 127mmMk12 127mmMk24 - 381mmDualR - 15cmTbtsKC36 - 105mmTwin + 203mmTwin 380mmMLE1935 - 15cmSKC28R - 15cmSKC28NR - PomPomMain - BoforTwinRemodel - BoforSingleRemodel - TorpBarbette - Barbette5x5 - QuadBofor - 20InchTwin - 406alternate + 381mmDualR + 16InchTriple + diff --git a/Utility Mods/Stealth Drive - Starcore Edition/Data/BlockVariantGroups.sbc b/Utility Mods/Stealth Drive - Starcore Edition/Data/BlockVariantGroups.sbc new file mode 100644 index 000000000..33e0c7ff6 --- /dev/null +++ b/Utility Mods/Stealth Drive - Starcore Edition/Data/BlockVariantGroups.sbc @@ -0,0 +1,32 @@ + + + + + + + + Textures\GUI\Icons\Cubes\Aryx_AWE_TacticalModule.dds + Stealth Drive + Allows a ship to enter stealth, becoming almost invisible as well as undetectable by weapon systems. + + + + + + + + + + + + + + StealthDrive + + 6 + 18 + + + + + \ No newline at end of file diff --git a/Utility Mods/Stealth Drive - Starcore Edition/Data/CubeBlocks_1x1Drive.sbc b/Utility Mods/Stealth Drive - Starcore Edition/Data/CubeBlocks_1x1Drive.sbc new file mode 100644 index 000000000..7eb7b3d03 --- /dev/null +++ b/Utility Mods/Stealth Drive - Starcore Edition/Data/CubeBlocks_1x1Drive.sbc @@ -0,0 +1,58 @@ + + + + + + + UpgradeModule + StealthDrive1x1 + + Stealth Drive + Textures\GUI\Icons\Cubes\Aryx_AWE_TacticalModule.dds + Allows a ship to enter stealth, becoming almost invisible as well as undetectable by weapon systems. + Large + false + TriangleMesh + + + Models\Cubes\large\StealthDrive1x1.mwm + + + + + + + + + + + + + + + + + + + + + + + + + StealthDrive1x1 + Z + Y + Light + true + BlockModuleEfficiency + Damage_Electrical_Damaged + ParticleElectrical + Default + BlockDestroyedExplosion_Large + WepSmallWarheadExpl + 500 + + + + \ No newline at end of file diff --git a/Utility Mods/Stealth Drive - Starcore Edition/Data/CubeBlocks_Stealth.sbc b/Utility Mods/Stealth Drive - Starcore Edition/Data/CubeBlocks_Stealth.sbc new file mode 100644 index 000000000..d0074524c --- /dev/null +++ b/Utility Mods/Stealth Drive - Starcore Edition/Data/CubeBlocks_Stealth.sbc @@ -0,0 +1,206 @@ + + + + + + + UpgradeModule + StealthDrive + + Stealth Drive + Textures\GUI\Icons\Cubes\Aryx_AWE_TacticalModule.dds + Allows a ship to enter stealth, becoming almost invisible as well as undetectable by weapon systems. + Large + false + TriangleMesh + + + Models\AWE_Aegis\ARYX_TacticalModule.mwm + + + + + + + + + + + + + + + + + + + + + + + + + StealthDrive + Z + Y + Light + true + BlockModuleEfficiency + Damage_Electrical_Damaged + ParticleElectrical + Default + BlockDestroyedExplosion_Large + WepSmallWarheadExpl + 500 + + + + + UpgradeModule + StealthDriveSmall + + Stealth Drive + Textures\GUI\Icons\Cubes\Aryx_AWE_TacticalModule.dds + Allows a ship to enter stealth, becoming almost invisible as well as undetectable by weapon systems. + Small + false + TriangleMesh + + + Models\Cubes\small\StealthDriveSmall.mwm + + + + + + + + + + + + + + + + + + + + + + + + + StealthDrive + Z + Y + Light + true + BlockModuleEfficiency + Damage_Electrical_Damaged + ParticleElectrical + Default + BlockDestroyedExplosion_Large + WepSmallWarheadExpl + 500 + + + + + UpgradeModule + StealthHeatSink + + Heat Sink + Textures\GUI\Icons\Cubes\UpgradeEnergy.dds + Increases the duration a ship can stay in stealth before needing to drop out of stealth to vent heat. + Large + false + TriangleMesh + + + Models\Cubes\large\StealthHeatSink.mwm + + + + + + + + + + + + + + + + + + + + + + StealthHeatSink + Y + X + Light + BlockModuleEfficiency + Damage_Electrical_Damaged + ParticleElectrical + Default + BlockDestroyedExplosion_Large + WepSmallWarheadExpl + 500 + + + + + UpgradeModule + StealthHeatSinkSmall + + Heat Sink + Textures\GUI\Icons\Cubes\UpgradeEnergy.dds + Increases the duration a ship can stay in stealth before needing to drop out of stealth to vent heat. + Small + false + TriangleMesh + + + Models\Cubes\small\StealthHeatSinkSmall.mwm + + + + + + + + + + + + + + + + + + + + + + StealthHeatSink + Y + X + Light + BlockModuleEfficiency + Damage_Electrical_Damaged + ParticleElectrical + Default + BlockDestroyedExplosion_Large + WepSmallWarheadExpl + 500 + + + + \ No newline at end of file diff --git a/Utility Mods/Stealth Drive - Starcore Edition/Data/EntityComponents.sbc b/Utility Mods/Stealth Drive - Starcore Edition/Data/EntityComponents.sbc new file mode 100644 index 000000000..47eb42706 --- /dev/null +++ b/Utility Mods/Stealth Drive - Starcore Edition/Data/EntityComponents.sbc @@ -0,0 +1,13 @@ + + + + + ModStorageComponent + StealthMod + + + 75BBB4F5-4FB9-4230-AAAA-BB79C9811507 + + + + \ No newline at end of file diff --git a/Utility Mods/Stealth Drive - Starcore Edition/Data/Fonts.sbc b/Utility Mods/Stealth Drive - Starcore Edition/Data/Fonts.sbc new file mode 100644 index 000000000..9c285804d --- /dev/null +++ b/Utility Mods/Stealth Drive - Starcore Edition/Data/Fonts.sbc @@ -0,0 +1,34 @@ + + + + + + + FontDefinition + StealthOrange + + + 227 + 69 + 0 + + + + + + + + + + + + + + + + + + + + + diff --git a/Utility Mods/Stealth Drive - Starcore Edition/Data/Scripts/Stealth System/API/Backend/APIBackend.cs b/Utility Mods/Stealth Drive - Starcore Edition/Data/Scripts/Stealth System/API/Backend/APIBackend.cs new file mode 100644 index 000000000..acc95cd17 --- /dev/null +++ b/Utility Mods/Stealth Drive - Starcore Edition/Data/Scripts/Stealth System/API/Backend/APIBackend.cs @@ -0,0 +1,115 @@ +using Sandbox.ModAPI; +using System; +using System.Collections.Generic; +using IMyTerminalBlock = Sandbox.ModAPI.Ingame.IMyTerminalBlock; +using IMyCubeGrid = VRage.Game.ModAPI.Ingame.IMyCubeGrid; + +namespace StealthSystem +{ + internal class APIBackend + { + internal readonly Dictionary ModApiMethods; + internal Dictionary PbApiMethods; + + private readonly StealthSession _session; + + internal APIBackend(StealthSession session) + { + _session = session; + + ModApiMethods = new Dictionary + { + ["ToggleStealth"] = new Func(ToggleStealth), + ["GetStatus"] = new Func(GetStatus), + ["GetDuration"] = new Func(GetDuration), + ["GetMainDrive"] = new Func(GetMainDrive), + ["GetHeatSinks"] = new Action>(GetHeatSinks), + }; + } + + + internal void PbInit() + { + PbApiMethods = new Dictionary + { + ["ToggleStealth"] = new Func(ToggleStealthPB), + ["GetStatus"] = new Func(GetStatus), + ["GetDuration"] = new Func(GetDuration), + ["GetMainDrive"] = new Func(GetMainDrive), + ["GetHeatSinks"] = new Action>(GetHeatSinksPB), + }; + var pb = MyAPIGateway.TerminalControls.CreateProperty, Sandbox.ModAPI.IMyTerminalBlock>("StealthPbAPI"); + pb.Getter = b => PbApiMethods; + MyAPIGateway.TerminalControls.AddControl(pb); + _session.PbApiInited = true; + } + + private bool ToggleStealth(IMyTerminalBlock block, bool force) + { + DriveComp comp; + if (!_session.DriveMap.TryGetValue(block.EntityId, out comp)) + return false; + + return comp.ToggleStealth(force); + } + + private bool ToggleStealthPB(IMyTerminalBlock block) + { + return ToggleStealth(block, false); + } + + private int GetStatus(IMyTerminalBlock block) + { + DriveComp comp; + if (!_session.DriveMap.TryGetValue(block.EntityId, out comp)) + return 4; + + var status = !comp.Online ? 4 : !comp.SufficientPower ? 3 : comp.CoolingDown ? 2 : comp.StealthActive ? 1 : 0; + return status; + } + + private int GetDuration(IMyTerminalBlock block) + { + DriveComp comp; + if (!_session.DriveMap.TryGetValue(block.EntityId, out comp)) + return 0; + + var duration = comp.StealthActive ? comp.TotalTime - comp.TimeElapsed : comp.CoolingDown ? comp.TimeElapsed : comp.MaxDuration; + return duration; + } + + private Sandbox.ModAPI.IMyTerminalBlock GetMainDrive(IMyCubeGrid grid) + { + GridComp comp; + if (!_session.GridMap.TryGetValue(grid as VRage.Game.ModAPI.IMyCubeGrid, out comp)) + return null; + + return comp.MasterComp?.Block; + } + + private void GetHeatSinksPB(IMyCubeGrid grid, ICollection blocks) + { + GridComp comp; + if (_session.GridMap.TryGetValue(grid as VRage.Game.ModAPI.IMyCubeGrid, out comp)) + { + for (int i = 0; i < comp.HeatComps.Count; i++) + blocks.Add(comp.HeatComps[i].Block); + } + + return; + } + + private void GetHeatSinks(VRage.Game.ModAPI.IMyCubeGrid grid, ICollection blocks) + { + GridComp comp; + if (_session.GridMap.TryGetValue(grid, out comp)) + { + for (int i = 0; i < comp.HeatComps.Count; i++) + blocks.Add(comp.HeatComps[i].Block); + } + + return; + } + + } +} diff --git a/Utility Mods/Stealth Drive - Starcore Edition/Data/Scripts/Stealth System/API/Backend/APIServer.cs b/Utility Mods/Stealth Drive - Starcore Edition/Data/Scripts/Stealth System/API/Backend/APIServer.cs new file mode 100644 index 000000000..cc577f3ce --- /dev/null +++ b/Utility Mods/Stealth Drive - Starcore Edition/Data/Scripts/Stealth System/API/Backend/APIServer.cs @@ -0,0 +1,65 @@ +using Sandbox.ModAPI; +using System; +using System.Collections.Generic; + +namespace StealthSystem +{ + internal class APIServer + { + private const long CHANNEL = 2172757427; + + private readonly StealthSession _session; + + internal APIServer(StealthSession session) + { + _session = session; + } + + /// + /// Is the API ready to be serve + /// + public bool IsReady { get; private set; } + + private void HandleMessage(object o) + { + if ((o as string) == "ApiEndpointRequest") + MyAPIGateway.Utilities.SendModMessage(CHANNEL, _session.API.ModApiMethods); + } + + private bool _isRegistered; + + /// + /// Prepares the client to receive API endpoints and requests an update. + /// + public void Load() + { + if (!_isRegistered) + { + _isRegistered = true; + MyAPIGateway.Utilities.RegisterMessageHandler(CHANNEL, HandleMessage); + } + IsReady = true; + try + { + MyAPIGateway.Utilities.SendModMessage(CHANNEL, _session.API.ModApiMethods); + + } + catch (Exception ex) { Logs.WriteLine($"Exception in APIServer.Load() - {ex}"); } + } + + + /// + /// Unloads all API endpoints and detaches events. + /// + public void Unload() + { + if (_isRegistered) + { + _isRegistered = false; + MyAPIGateway.Utilities.UnregisterMessageHandler(CHANNEL, HandleMessage); + } + IsReady = false; + MyAPIGateway.Utilities.SendModMessage(CHANNEL, new Dictionary()); + } + } +} diff --git a/Utility Mods/Stealth Drive - Starcore Edition/Data/Scripts/Stealth System/API/StealthAPI.cs b/Utility Mods/Stealth Drive - Starcore Edition/Data/Scripts/Stealth System/API/StealthAPI.cs new file mode 100644 index 000000000..61b82f6a2 --- /dev/null +++ b/Utility Mods/Stealth Drive - Starcore Edition/Data/Scripts/Stealth System/API/StealthAPI.cs @@ -0,0 +1,119 @@ +using Sandbox.ModAPI; +using System; +using System.Collections.Generic; +using VRage.Game.ModAPI; + +namespace StealthSystem +{ + internal class StealthAPI + { + /// Returns true if drive status was toggled successfully. + /// Ignore power requirements and overheat. + public bool ToggleStealth(IMyTerminalBlock drive, bool force) => _toggleStealth?.Invoke(drive, force) ?? false; + + /// Returns status of drive. 0 = Ready, 1 = Active, 2 = Cooldown, 3 = Not enough power, 4 = Offline + public int GetStatus(IMyTerminalBlock drive) => _getStatus?.Invoke(drive) ?? 4; + + /// Returns remaining duration of stealth/cooldown. + public int GetDuration(IMyTerminalBlock drive) => _getDuration?.Invoke(drive) ?? 0; + + /// Retuns active stealth drive on grid if one exists, otherwise returns null. + public IMyTerminalBlock GetMainDrive(IMyCubeGrid grid) => _getMainDrive?.Invoke(grid); + + /// Collection to populate with heat sinks on grid. + public void GetHeatSinks(IMyCubeGrid grid, ICollection sinks) => _getHeatSinks?.Invoke(grid, sinks); + + + + private const long CHANNEL = 2172757427; + private bool _isRegistered; + private bool _apiInit; + private Action _readyCallback; + + private Func _toggleStealth; + private Func _getStatus; + private Func _getDuration; + private Func _getMainDrive; + private Action> _getHeatSinks; + + public bool IsReady { get; private set; } + + + /// + /// Ask CoreSystems to send the API methods. + /// Throws an exception if it gets called more than once per session without . + /// + /// Method to be called when CoreSystems replies. + public void Load(Action readyCallback = null) + { + if (_isRegistered) + throw new Exception($"{GetType().Name}.Load() should not be called multiple times!"); + + _readyCallback = readyCallback; + _isRegistered = true; + MyAPIGateway.Utilities.RegisterMessageHandler(CHANNEL, HandleMessage); + MyAPIGateway.Utilities.SendModMessage(CHANNEL, "ApiEndpointRequest"); + } + + public void Unload() + { + MyAPIGateway.Utilities.UnregisterMessageHandler(CHANNEL, HandleMessage); + + ApiAssign(null); + + _isRegistered = false; + _apiInit = false; + IsReady = false; + } + + private void HandleMessage(object obj) + { + if (_apiInit || obj is string + ) // the sent "ApiEndpointRequest" will also be received here, explicitly ignoring that + return; + + var dict = obj as IReadOnlyDictionary; + + if (dict == null) + return; + + ApiAssign(dict); + + IsReady = true; + _readyCallback?.Invoke(); + } + + public void ApiAssign(IReadOnlyDictionary delegates) + { + _apiInit = (delegates != null); + /// base methods + AssignMethod(delegates, "ToggleStealth", ref _toggleStealth); + AssignMethod(delegates, "GetStatus", ref _getStatus); + AssignMethod(delegates, "GetDuration", ref _getDuration); + AssignMethod(delegates, "GetMainDrive", ref _getMainDrive); + AssignMethod(delegates, "GetHeatSinks", ref _getHeatSinks); + } + + private void AssignMethod(IReadOnlyDictionary delegates, string name, ref T field) + where T : class + { + if (delegates == null) + { + field = null; + return; + } + + Delegate del; + if (!delegates.TryGetValue(name, out del)) + throw new Exception($"{GetType().Name} :: Couldn't find {name} delegate of type {typeof(T)}"); + + field = del as T; + + if (field == null) + throw new Exception( + $"{GetType().Name} :: Delegate {name} is not type {typeof(T)}, instead it's: {del.GetType()}"); + } + + } + +} diff --git a/Utility Mods/Stealth Drive - Starcore Edition/Data/Scripts/Stealth System/API/StealthAPI_PB.cs b/Utility Mods/Stealth Drive - Starcore Edition/Data/Scripts/Stealth System/API/StealthAPI_PB.cs new file mode 100644 index 000000000..e31056e7e --- /dev/null +++ b/Utility Mods/Stealth Drive - Starcore Edition/Data/Scripts/Stealth System/API/StealthAPI_PB.cs @@ -0,0 +1,73 @@ +using System; +using System.Collections.Generic; +using Sandbox.ModAPI.Interfaces; + +namespace StealthSystem +{ + internal class StealthPbAPI + { + /// Returns true if drive status was toggled successfully. + public bool ToggleStealth(Sandbox.ModAPI.Ingame.IMyTerminalBlock drive) => _toggleStealth?.Invoke(drive) ?? false; + + /// Returns status of drive. 0 = Ready, 1 = Active, 2 = Cooldown, 3 = Not enough power, 4 = Offline + public int GetStatus(Sandbox.ModAPI.Ingame.IMyTerminalBlock drive) => _getStatus?.Invoke(drive) ?? 4; + + /// Returns remaining duration of stealth/cooldown. + public int GetDuration(Sandbox.ModAPI.Ingame.IMyTerminalBlock drive) => _getDuration?.Invoke(drive) ?? 0; + + /// Retuns active stealth drive on grid if one exists, otherwise returns null. + public Sandbox.ModAPI.Ingame.IMyTerminalBlock GetMainDrive(VRage.Game.ModAPI.Ingame.IMyCubeGrid grid) => _getMainDrive?.Invoke(grid); + + /// Collection to populate with heat sinks on grid. + public void GetHeatSinks(VRage.Game.ModAPI.Ingame.IMyCubeGrid grid, ICollection sinks) => _getHeatSinks?.Invoke(grid, sinks); + + + + + private Func _toggleStealth; + private Func _getStatus; + private Func _getDuration; + private Func _getMainDrive; + private Action> _getHeatSinks; + + public bool Activate(Sandbox.ModAPI.Ingame.IMyTerminalBlock pbBlock) + { + var dict = pbBlock.GetProperty("StealthPbAPI")?.As>().GetValue(pbBlock); + if (dict == null) throw new Exception("StealthPbAPI failed to activate"); + return ApiAssign(dict); + } + + public bool ApiAssign(IReadOnlyDictionary delegates) + { + if (delegates == null) + return false; + + AssignMethod(delegates, "ToggleStealth", ref _toggleStealth); + AssignMethod(delegates, "GetStatus", ref _getStatus); + AssignMethod(delegates, "GetDuration", ref _getDuration); + AssignMethod(delegates, "GetMainDrive", ref _getMainDrive); + AssignMethod(delegates, "GetHeatSinks", ref _getHeatSinks); + return true; + } + + private void AssignMethod(IReadOnlyDictionary delegates, string name, ref T field) where T : class + { + if (delegates == null) + { + field = null; + return; + } + + Delegate del; + if (!delegates.TryGetValue(name, out del)) + throw new Exception($"{GetType().Name} :: Couldn't find {name} delegate of type {typeof(T)}"); + + field = del as T; + if (field == null) + throw new Exception( + $"{GetType().Name} :: Delegate {name} is not type {typeof(T)}, instead it's: {del.GetType()}"); + } + + } + +} diff --git a/Utility Mods/Stealth Drive - Starcore Edition/Data/Scripts/Stealth System/Comp/CompData.cs b/Utility Mods/Stealth Drive - Starcore Edition/Data/Scripts/Stealth System/Comp/CompData.cs new file mode 100644 index 000000000..1ebec4775 --- /dev/null +++ b/Utility Mods/Stealth Drive - Starcore Edition/Data/Scripts/Stealth System/Comp/CompData.cs @@ -0,0 +1,486 @@ +using ProtoBuf; +using Sandbox.ModAPI; +using System; +using VRage.Game.ModAPI; +using VRage.ModAPI; +using System.Collections.Generic; +using VRageMath; +using Sandbox.Game.Entities; + +namespace StealthSystem +{ + + [ProtoContract] + public class DriveRepo + { + [ProtoMember(1)] public bool StealthActive; + [ProtoMember(2)] public bool CoolingDown; + [ProtoMember(3)] public int RemainingDuration; //TimeElapsed + [ProtoMember(4)] public int TotalTime; + + + public void Sync(DriveComp comp) + { + StealthActive = comp.StealthActive; + CoolingDown = comp.CoolingDown; + //RemainingDuration = comp.RemainingDuration; + RemainingDuration = comp.TimeElapsed; + TotalTime = comp.TotalTime; + } + + } + + [ProtoContract] + public class SinkRepo + { + [ProtoMember(1)] public bool Accumulating; + [ProtoMember(2)] public bool Radiating; + [ProtoMember(3)] public byte HeatPercent; + + + public void Sync(SinkComp comp) + { + Accumulating = comp.Accumulating; + Radiating = comp.Radiating; + HeatPercent = comp.HeatPercent; + } + + } + + internal class WaterData + { + public WaterData(MyPlanet planet) + { + Planet = planet; + WaterId = planet.EntityId; + } + + internal MyPlanet Planet; + internal long WaterId; + internal Vector3D Centre; + internal float Radius; + } + + internal class GridComp + { + internal List StealthComps = new List(); + internal List HeatComps = new List(); + + internal List ShieldBlocks = new List(); + internal List Turrets; + + internal DriveComp MasterComp; + internal GroupMap GroupMap; + internal IMyCubeGrid Grid; + internal MyPlanet Planet; + internal BoundingSphereD Water; + + internal bool GroupsDirty; + internal bool Revealed; + internal bool Underwater; + internal bool WaterValid = true; + internal bool DisableShields; + internal bool DisableWeapons; + + internal int DamageTaken; + internal int SinkBonus; + + private StealthSession _session; + + internal void Init(IMyCubeGrid grid, StealthSession session) + { + _session = session; + + Grid = grid; + + Grid.OnBlockAdded += BlockAdded; + Grid.OnBlockRemoved += BlockRemoved; + + DisableShields = _session.DisableShields; + DisableWeapons = _session.DisableWeapons && !_session.WcActive; + + if (DisableWeapons) Turrets = new List(); + + var group = MyAPIGateway.GridGroups.GetGridGroup(GridLinkTypeEnum.Physical, grid); + if (group != null) + { + GroupMap map; + if (_session.GridGroupMap.TryGetValue(group, out map)) + GroupMap = map; + } + else Logs.WriteLine("group null at GridComp.Init()"); + + GroupsDirty = true; + + if (!DisableShields && !DisableWeapons) return; + + var blocks = grid.GetFatBlocks(); + foreach (var block in blocks) + { + if (block?.BlockDefinition == null) continue; + + if (DisableShields && _session.ShieldBlocks.Contains(block.BlockDefinition.SubtypeName)) + ShieldBlocks.Add(block as IMyFunctionalBlock); + + if (DisableWeapons && block is IMyUserControllableGun) + Turrets.Add(block as IMyUserControllableGun); + } + + if (_session.TrackWater) + { + Planet = MyGamePruningStructure.GetClosestPlanet(Grid.PositionComp.WorldAABB.Center); + + WaterData waterData; + if (Planet != null && _session.WaterMap.TryGetValue(Planet.EntityId, out waterData)) + { + Water = new BoundingSphereD(waterData.Centre, waterData.Radius + _session.WaterTransitionDepth); + + var planetVector = Grid.PositionComp.WorldAABB.Center - waterData.Centre; + var radius = waterData.Radius + _session.WaterTransitionDepth; + var radiusSqr = radius * radius; + if (planetVector.LengthSquared() < radiusSqr) + { + Underwater = true; + + var obb = new MyOrientedBoundingBoxD(Grid.PositionComp.LocalAABB, Grid.PositionComp.WorldMatrixRef); + obb.GetCorners(_session.ObbCorners, 0); + for (int j = 0; j < 8; j++) + { + var corner = _session.ObbCorners[j]; + planetVector = corner = waterData.Centre; + if (planetVector.LengthSquared() > radiusSqr) + { + Underwater = false; + break; + } + } + } + WaterValid = Underwater == _session.WorkInWater; + } + } + } + + private void BlockAdded(IMySlimBlock slim) + { + if (slim.FatBlock == null) return; + + var fat = slim.FatBlock; + if (fat is IMyUpgradeModule) + { + var module = fat as IMyUpgradeModule; + if (_session.DriveDefinitions.ContainsKey(module.BlockDefinition.SubtypeName)) + { + if (!_session.DriveMap.ContainsKey(module.EntityId)) + { + Logs.WriteLine("BlockAdded() - Drive not in map!"); + return; + } + + var dComp = _session.DriveMap[module.EntityId]; + + if (!dComp.Inited) + { + Logs.WriteLine("BlockAdded() - Drive not yet Inited!"); + return; + } + + var gridComp = _session.GridMap[Grid]; + + if (gridComp.StealthComps.Contains(dComp)) + { + Logs.WriteLine("BlockAdded() - Drive already in correct GridComp!"); + return; + } + + try + { + dComp.GridChange(); + } + catch (Exception ex) + { + Logs.WriteLine($"Exception in GridChange() {ex}"); + } + } + } + + if (DisableShields && _session.ShieldBlocks.Contains(fat.BlockDefinition.SubtypeName)) + ShieldBlocks.Add(fat as IMyFunctionalBlock); + + if (DisableWeapons && fat is IMyUserControllableGun) + Turrets.Add(fat as IMyUserControllableGun); + } + + private void BlockRemoved(IMySlimBlock slim) + { + if (slim.FatBlock == null) return; + + var func = slim.FatBlock as IMyFunctionalBlock; + if (DisableShields && func != null && ShieldBlocks.Contains(func)) + ShieldBlocks.Remove(func); + + var wep = func as IMyUserControllableGun; + if (DisableWeapons && wep != null && Turrets.Contains(wep)) + Turrets.Remove(wep); + } + + internal void Clean() + { + Grid.OnBlockAdded -= BlockAdded; + Grid.OnBlockRemoved -= BlockRemoved; + + StealthComps.Clear(); + HeatComps.Clear(); + ShieldBlocks.Clear(); + + if (DisableWeapons) Turrets.Clear(); + + MasterComp = null; + GroupMap = null; + Grid = null; + + GroupsDirty = false; + Revealed = false; + DamageTaken = 0; + + _session = null; + } + } + + internal class GroupMap + { + private StealthSession _session; + + public IMyGridGroupData GroupData; + + internal List ConnectedGrids = new List(); + + internal List SlimBlocks = new List(); + internal HashSet Children = new HashSet(); + + internal void Init(IMyGridGroupData data, StealthSession session) + { + GroupData = data; + + _session = session; + } + + public void OnGridAdded(IMyGridGroupData newGroup, IMyCubeGrid grid, IMyGridGroupData oldGroup) + { + try + { + ConnectedGrids.Add(grid); + + GridComp gridComp; + if (!_session.GridMap.TryGetValue(grid, out gridComp)) + return; + + gridComp.GroupMap = this; + gridComp.GroupsDirty = true; + + bool thisActive = false; + var thisMaster = gridComp.MasterComp; + if (thisMaster != null && thisMaster.StealthActive) //Added grid has active drive + thisActive = true; + else if (((uint)grid.Flags & StealthSession.IsStealthedFlag) > 0) //Added grid is being stealthed by another grid + return; + + var newSubgrids = new List(); + GridComp subgridComp; + DriveComp subgridMaster = null; + + GroupData.GetGrids(newSubgrids); + for (int i = 0; i < newSubgrids.Count; i++) + { + var newSubgrid = newSubgrids[i]; + if (newSubgrid == grid) continue; + + if (thisActive) + { + if (((uint)newSubgrid.Flags & StealthSession.IsStealthedFlag) > 0) continue; //Other grid already stealthed + + newSubgrid.Flags |= _session.StealthFlag; + + if (!_session.IsDedicated && !thisMaster.VisibleToClient) + StealthConnectedGrid(newSubgrid, thisMaster, true); + + //continue; + } + + if (!_session.GridMap.TryGetValue(newSubgrid, out subgridComp)) + continue; + + if (thisActive) //Reenable shield emitters/vanilla turrets since previously connected grid is no longer stealthed + { + if (gridComp.DisableShields) + thisMaster.DisableShields(subgridComp); + + if (gridComp.DisableWeapons) + thisMaster.DisableTurrets(subgridComp); + + continue; + } + + subgridMaster = subgridComp.MasterComp; + if (subgridMaster == null) continue; + + if (subgridMaster.StealthActive) //Other grid has active drive so stealth this grid + { + grid.Flags |= _session.StealthFlag; + + if (!_session.IsDedicated && !subgridMaster.VisibleToClient) + StealthConnectedGrid(grid, subgridMaster, true); + + if (gridComp.DisableShields) + subgridMaster.DisableShields(gridComp); + + if (gridComp.DisableWeapons) + subgridMaster.DisableTurrets(gridComp); + + return; + } + } + } + catch (Exception ex) + { + Logs.WriteLine($"Exception in OnGridAdded(): {ex}"); + } + + } + + public void OnGridRemoved(IMyGridGroupData oldGroup, IMyCubeGrid grid, IMyGridGroupData newGroup) + { + try + { + ConnectedGrids.Remove(grid); + + GridComp gridComp; + if (!_session.GridMap.TryGetValue(grid, out gridComp)) + return; + + gridComp.GroupsDirty = true; + + bool thisActive = false; + var thisMaster = gridComp.MasterComp; + if (thisMaster != null && thisMaster.StealthActive) //Removed grid has active drive + thisActive = true; + //else if (((uint)grid.Flags & IsStealthedFlag) > 0) + // return; + + var formerSubgrids = new List(); + GridComp subgridComp; + DriveComp subgridMaster = null; + + GroupData.GetGrids(formerSubgrids); + for (int i = 0; i < formerSubgrids.Count; i++) + { + var formerSubgrid = formerSubgrids[i]; + if (formerSubgrid == grid) continue; + + if (thisActive) //Unstealth previously connected grid since this grid was providing stealth + { + formerSubgrid.Flags ^= _session.StealthFlag; + + if (!_session.IsDedicated) + StealthConnectedGrid(formerSubgrid, thisMaster, false); + } + + if (!_session.GridMap.TryGetValue(formerSubgrid, out subgridComp)) + continue; + + if (thisActive) //Reenable shield emitters/vanilla turrets since previously connected grid is no longer stealthed + { + if (gridComp.DisableShields) + thisMaster.ReEnableShields(subgridComp); + + if (gridComp.DisableWeapons) + thisMaster.ReEnableTurrets(subgridComp); + + continue; + } + + //We only keep going if the removed grid wasn't providing stealth + //We check if the grid it was connected to was stealthing it + + subgridMaster = subgridComp.MasterComp; + if (subgridMaster == null) continue; + + if (subgridMaster.StealthActive) //Connected grid was providing stealth so destealth this + { + grid.Flags ^= _session.StealthFlag; + + if (!_session.IsDedicated) + StealthConnectedGrid(grid, subgridMaster, false); + + if (gridComp.DisableShields) + subgridMaster.ReEnableShields(gridComp); + + if (gridComp.DisableWeapons) + subgridMaster.ReEnableTurrets(gridComp); + + return; + } + } + } + catch (Exception ex) + { + Logs.WriteLine($"Exception in OnGridRemoved(): {ex}"); + } + + } + + internal void StealthConnectedGrid(IMyCubeGrid grid, DriveComp comp, bool stealth) + { + if (stealth) _session.StealthedGrids.Add(grid); + else _session.StealthedGrids.Remove(grid); + + grid.GetBlocks(SlimBlocks); + + var dither = stealth ? _session.Transparency : 0f; + foreach (var slim in SlimBlocks) + { + var fatBlock = slim.FatBlock; + if (fatBlock == null) + { + slim.Dithering = dither; + continue; + } + + fatBlock.Render.Transparency = dither; + fatBlock.Render.UpdateTransparency(); + + fatBlock.Hierarchy.GetChildrenRecursive(Children); + foreach (var child in Children) + { + child.Render.Transparency = dither; + child.Render.UpdateTransparency(); + } + Children.Clear(); + + //var cockpit = fatBlock as IMyCockpit; + //if (cockpit != null && cockpit.Pilot != null) + // cockpit.Pilot.Render.Visible = !add; + + var jump = fatBlock as IMyJumpDrive; + if (jump != null) + { + if (stealth) comp.JumpDrives.Add(jump, jump.CurrentStoredPower); + else comp.JumpDrives.Remove(jump); + } + } + SlimBlocks.Clear(); + } + + internal void Clean() + { + GroupData = null; + + ConnectedGrids.Clear(); + + SlimBlocks.Clear(); + Children.Clear(); + + _session = null; + } + } + +} diff --git a/Utility Mods/Stealth Drive - Starcore Edition/Data/Scripts/Stealth System/Comp/DriveComp.cs b/Utility Mods/Stealth Drive - Starcore Edition/Data/Scripts/Stealth System/Comp/DriveComp.cs new file mode 100644 index 000000000..89ea57241 --- /dev/null +++ b/Utility Mods/Stealth Drive - Starcore Edition/Data/Scripts/Stealth System/Comp/DriveComp.cs @@ -0,0 +1,1068 @@ +using Sandbox.ModAPI; +using System; +using VRage.Game; +using VRage.Game.Components; +using VRage.Game.ModAPI; +using VRage.ModAPI; +using VRageMath; +using VRage.Utils; +using Sandbox.Game.Entities; +using SpaceEngineers.Game.ModAPI; +using VRage.Game.Entity; +using System.Collections.Generic; +using Sandbox.Game.EntityComponents; +using System.Text; +using Sandbox.ModAPI.Interfaces.Terminal; +using System.Collections.Concurrent; +using Sandbox.ModAPI.Interfaces; + +namespace StealthSystem +{ + public class DriveComp : MyEntityComponentBase + { + internal IMyFunctionalBlock Block; + internal IMyCubeGrid Grid; + internal MyResourceSinkComponent Sink; + internal MyResourceDistributorComponent Source; + internal IMyTerminalControlOnOffSwitch ShowInToolbarSwitch; + internal IMyGps HeatSignature; + + internal DriveRepo Repo; + internal GridComp GridComp; + internal Definitions.DriveDefinition Definition; + + //internal List ConnectedGrids = new List(); + internal List SlimBlocks = new List(); + internal List FadeEntities = new List(); + internal List FadeSlims = new List(); + internal HashSet Children = new HashSet(); + internal HashSet StealthedExternalGrids = new HashSet(); + internal Dictionary JumpDrives = new Dictionary(); + internal ConcurrentDictionary DisabledBlocks = new ConcurrentDictionary(); + internal List ReplicatedClients = new List(); + internal HashSet PreviousEntities = new HashSet(); + internal HashSet CurrentEntities = new HashSet(); + + internal List NearbyTurrets; + internal MyOrientedBoundingBoxD ExpandedOBB; + internal Color OldColour; + + internal bool IsPrimary; + internal bool Inited; + internal bool Online; + internal bool CoolingDown; + internal bool SufficientPower; + internal bool StealthActive; + internal bool EnterStealth; + internal bool ExitStealth; + internal bool VisibleToClient; + internal bool Fading; + internal bool GridUpdated; + internal bool BlocksDirty; + internal bool PowerDirty; + internal bool TransferFailed; + internal bool StealthOnInit; + internal bool CdOnInit; + internal bool Transfer; + internal bool ShieldWaiting; + internal bool IgnorePower; + + internal int Fade; + internal int ShieldWait; + internal int SurfaceArea; + internal int MaxDuration; + internal int RemainingDuration; + internal int TimeElapsed; + internal int TotalTime; + internal long CompTick15; + internal long CompTick60; + internal long SignalDistance; + internal long SignalDistanceSquared; + + internal float RequiredPower; + internal float Transparency; + internal float TransOffset = -0.35f; + + private readonly StealthSession _session; + + private List _entities; + private BoundingSphereD _sphere; + private readonly Vector3D[] _obbCorners = new Vector3D[8]; + + internal DriveComp(IMyFunctionalBlock stealthBlock, Definitions.DriveDefinition def, StealthSession session) + { + _session = session; + + Block = stealthBlock; + Definition = def; + + Transparency = -_session.Transparency; + + if (!_session.WcActive) + { + NearbyTurrets = new List(); + _entities = new List(); + _sphere = new BoundingSphereD(Vector3D.Zero, 1200); + } + } + + public override void OnAddedToContainer() + { + base.OnAddedToContainer(); + } + + public override void OnAddedToScene() + { + base.OnAddedToScene(); + + if (!MyAPIGateway.Session.IsServer) StealthSession.SendPacketToServer(new ReplicationPacket { EntityId = Block.EntityId, Fresh = true, Type = PacketType.Replicate }); + } + + public override void OnBeforeRemovedFromContainer() + { + base.OnBeforeRemovedFromContainer(); + + Close(); + } + + public override bool IsSerialized() + { + if (Block.Storage == null || Repo == null) return false; + + Repo.Sync(this); + + Block.Storage[_session.CompDataGuid] = Convert.ToBase64String(MyAPIGateway.Utilities.SerializeToBinary(Repo)); + + return false; + } + + internal void Init() + { + Grid = Block.CubeGrid; + if (Grid == null) + { + Logs.WriteLine("DriveComp.Init() - Grid null"); + return; + } + + var gridData = _session.GridMap[Grid]; + if (gridData.StealthComps.Count == 1) + { + IsPrimary = true; + GridComp = gridData; + gridData.MasterComp = this; + } + + Block.Components.Add(this); + CompTick15 = Block.EntityId % 15; + CompTick60 = Block.EntityId % 60; + + SinkInit(); + StorageInit(); + + Inited = true; + GridUpdated = true; + VisibleToClient = true; + + Grid.OnGridSplit += GridSplit; + Grid.OnBlockAdded += BlockAdded; + Grid.OnBlockRemoved += BlockRemoved; + + Block.EnabledChanged += EnabledChanged; + Source.SystemChanged += SourceChanged; + + if (!_session.IsDedicated) + { + GetShowInToolbarSwitch(); + Block.AppendingCustomInfo += AppendingCustomData; + } + + if (!MyAPIGateway.Session.IsServer) + StealthSession.SendPacketToServer(new ReplicationPacket { EntityId = Block.EntityId, Fresh = true, Type = PacketType.Replicate }); + } + + internal void Close() + { + if (Transfer) return; + + if (IsPrimary) + TransferPrimary(true); + + _session.DriveMap.Remove(Block.EntityId); + + GridComp gridComp; + if (_session.GridMap.TryGetValue(Grid, out gridComp)) + { + gridComp.StealthComps.Remove(this); + } + + Grid.OnGridSplit -= GridSplit; + Grid.OnBlockAdded -= BlockAdded; + Grid.OnBlockRemoved -= BlockRemoved; + + Block.EnabledChanged -= EnabledChanged; + + if (Source != null) + Source.SystemChanged -= SourceChanged; + else Logs.WriteLine("Source null on close"); + + if (StealthActive && !VisibleToClient) + { + SwitchStealth(false); + + foreach (var entity in PreviousEntities) + { + if (entity == null) + { + Logs.WriteLine($"Previous entity null on close"); + continue; + } + + if (!_session.IsDedicated) + { + if (entity is IMyCubeGrid) + StealthExternalGrid(false, entity as IMyCubeGrid); + else + entity.Render.Visible = true; + } + + entity.Flags ^= _session.StealthFlag; + } + } + + if (HeatSignature != null) + MyAPIGateway.Session.GPS.RemoveLocalGps(HeatSignature); + + if (!_session.IsDedicated) + Block.AppendingCustomInfo -= AppendingCustomData; + + if (!MyAPIGateway.Session.IsServer) + StealthSession.SendPacketToServer(new ReplicationPacket { EntityId = Block.EntityId, Fresh = false, Type = PacketType.Replicate }); + + Clean(); + } + + internal void Clean() + { + Block = null; + Grid = null; + Sink = null; + Source = null; + ShowInToolbarSwitch = null; + HeatSignature = null; + + Repo = null; + GridComp = null; + + //ConnectedGrids = null; + SlimBlocks = null; + FadeEntities = null; + FadeSlims = null; + StealthedExternalGrids = null; + JumpDrives = null; + DisabledBlocks = null; + ReplicatedClients = null; + PreviousEntities = null; + CurrentEntities = null; + NearbyTurrets = null; + } + + internal void GridChange() + { + Grid.OnGridSplit -= GridSplit; + Grid.OnBlockAdded -= BlockAdded; + Grid.OnBlockRemoved -= BlockRemoved; + + if (StealthActive) + SwitchStealth(false, true); + + var gridData = _session.GridMap[Grid]; + if (TransferPrimary(true)) + { + var newPrimary = gridData.MasterComp; + newPrimary.IsPrimary = true; + //newPrimary.RemainingDuration = StealthActive ? MaxDuration - RemainingDuration : RemainingDuration; + //newPrimary.CoolingDown = RemainingDuration > 0; + newPrimary.TotalTime = TotalTime; + newPrimary.TimeElapsed = TimeElapsed; + newPrimary.CoolingDown = TimeElapsed < TotalTime; + + } + + gridData.StealthComps.Remove(this); + + Grid = Block.CubeGrid; + + //if (StealthActive) + // Grid.Visible = false; + + var newGridData = _session.GridMap[Block.CubeGrid]; + GridComp = newGridData; + newGridData.StealthComps.Add(this); + if (newGridData.MasterComp == null) + { + newGridData.MasterComp = this; + IsPrimary = true; + } + else + { + IsPrimary = false; + } + + Grid.OnGridSplit += GridSplit; + Grid.OnBlockAdded += BlockAdded; + Grid.OnBlockRemoved += BlockRemoved; + + Source = Grid.ResourceDistributor as MyResourceDistributorComponent; + CalculatePowerRequirements(); + UpdateStatus(true); + + Transfer = false; + } + + internal bool TransferPrimary(bool force) + { + var gridData = _session.GridMap[Grid]; + + if (gridData.StealthComps.Count <= 1) + return false; + + DriveComp newPrimary = null; + for (int i = 0; i < gridData.StealthComps.Count; i++) + { + var comp = gridData.StealthComps[i]; + + if (comp == this || comp.Block.CubeGrid != Grid) + continue; + + if (comp.Block.IsFunctional) + { + newPrimary = comp; + break; + } + + if (force && newPrimary == null) + newPrimary = comp; + } + + if (newPrimary == null) + return false; + + IsPrimary = false; + newPrimary.IsPrimary = true; + gridData.MasterComp = newPrimary; + return true; + } + + private void SourceChanged() + { + PowerDirty = true; + GridUpdated = true; + } + + private void EnabledChanged(IMyTerminalBlock block) + { + UpdateStatus(); + block.RefreshCustomInfo(); + } + + private void GridSplit(IMyCubeGrid grid1, IMyCubeGrid grid2) + { + GridUpdated = true; + BlocksDirty = true; + } + + private void BlockAdded(IMySlimBlock slim) + { + GridUpdated = true; + BlocksDirty = true; + + if (StealthActive) + DitherBlock(true, slim); + } + + private void BlockRemoved(IMySlimBlock slim) + { + GridUpdated = true; + BlocksDirty = true; + + if (StealthActive) + DitherBlock(false, slim); + } + + private void AppendingCustomData(IMyTerminalBlock block, StringBuilder builder) + { + var status = !IsPrimary ? "Standby" + : !Online ? "Offline" + : !SufficientPower ? "Insufficient Power" + : CoolingDown ? "Cooling Down" + : !GridComp.WaterValid ? _session.WorkInWater ? "Not Submerged" : "Submerged" + : StealthActive ? "Stealth Engaged" + : "Ready"; + + builder.Append("Drive Status: ") + .Append(status) + .Append("\n"); + + if (!IsPrimary) return; + + if (Online) + { + if (!StealthActive && !CoolingDown) + builder.Append($"Stealth Duration: {MaxDuration / 60}s \n"); + + builder.Append($"Surface Area: {SurfaceArea} blocks square \n") + .Append($"Required Power: {RequiredPower.ToString("F1")}MW \n") + .Append($"Detection Radius: {SignalDistance}m \n"); + } + + if (StealthActive) + { + int timeLeft = (TotalTime - TimeElapsed) / 60; + int seconds = timeLeft % 60; + int minutes = (timeLeft - seconds) / 60; + builder.Append("Time Remaining: ") + .Append($"{minutes.ToString("00")}:{seconds.ToString("00")}\n"); + } + + if (CoolingDown) + { + int timeLeft = (TimeElapsed) / 60; + int seconds = timeLeft % 60; + int minutes = (timeLeft - seconds) / 60; + builder.Append("Time Remaining: ") + .Append($"{minutes.ToString("00")}:{seconds.ToString("00")}\n"); + } + } + + internal void UpdateStatus(bool gridChange = false) + { + if (PowerDirty || Source == null) + { + Source = Grid.ResourceDistributor as MyResourceDistributorComponent; + PowerDirty = false; + } + var available = Source.MaxAvailableResourceByType(MyResourceDistributorComponent.ElectricityId, (MyCubeGrid)Grid) - Source.TotalRequiredInputByType(MyResourceDistributorComponent.ElectricityId, (MyCubeGrid)Grid); + SufficientPower = StealthActive ? available >= 0 : available >= RequiredPower; + Online = Block.IsFunctional && Block.Enabled && available > 0; + + if (!_session.IsDedicated) + SetEmissiveColor(gridChange); + } + + internal void SetEmissiveColor(bool force) + { + var emissiveColor = !Block.IsFunctional ? Color.Black : !Online ? EmissiveValues.RED : StealthActive ? Color.Cyan : CoolingDown ? Color.OrangeRed : EmissiveValues.GREEN; + if (!force && emissiveColor == OldColour) + return; + + OldColour = emissiveColor; + Block.SetEmissiveParts(StealthSession.STATUS_EMISSIVE, emissiveColor, 1f); + } + + internal void RefreshTerminal() + { + Block.RefreshCustomInfo(); + + if (ShowInToolbarSwitch != null) + { + var originalSetting = ShowInToolbarSwitch.Getter(Block); + ShowInToolbarSwitch.Setter(Block, !originalSetting); + ShowInToolbarSwitch.Setter(Block, originalSetting); + } + } + + internal void CalculatePowerRequirements() + { + //ConnectedGrids.Clear(); + //MyAPIGateway.GridGroups.GetGroup(Grid, GridLinkTypeEnum.Physical, ConnectedGrids); + + CalculateExpandedOBB(); + var scale = Grid.GridSizeEnum == MyCubeSize.Large ? 6.25 : 0.25; + var areaMetres = (int)OBBSurfaceArea(ExpandedOBB); + SurfaceArea = (int)(areaMetres / scale); + + RequiredPower = areaMetres * Definition.PowerScale; + SignalDistance = (int)(RequiredPower * Definition.SignalRangeScale); + SignalDistanceSquared = SignalDistance * SignalDistance; + + } + + internal void CalculateExpandedOBB() + { + var worldMat = Grid.PositionComp.WorldMatrixRef; + var halfExtents = (Vector3D)Grid.PositionComp.LocalAABB.HalfExtents; + var newCentre = Grid.PositionComp.WorldAABB.Center; + + var left = worldMat.Left; + var up = worldMat.Up; + var back = worldMat.Backward; + + var grids = GridComp.GroupMap.ConnectedGrids; + for (int i = 0; i < grids.Count; i++) + { + var cGrid = grids[i]; + if (cGrid == Grid) continue; + + var obb = new MyOrientedBoundingBoxD(cGrid.PositionComp.LocalAABB, cGrid.PositionComp.WorldMatrixRef); + obb.GetCorners(_obbCorners, 0); + for (int j = 0; j < 8; j++) + { + var point = _obbCorners[j]; + var offset = point - newCentre; + if (offset.LengthSquared() < Math.Pow(halfExtents.Min(), 2)) + continue; + + var xDot = Vector3D.Dot(offset, left); + var xAbs = Math.Abs(xDot); + if (xAbs > halfExtents.X) + { + var dist = (xAbs - halfExtents.X) / 2; + halfExtents.X += dist; + newCentre += left * dist * Math.Sign(xDot); + } + + var yDot = Vector3D.Dot(offset, up); + var yAbs = Math.Abs(yDot); + if (yAbs > halfExtents.Y) + { + var dist = (yAbs - halfExtents.Y) / 2; + halfExtents.Y += dist; + newCentre += up * dist * Math.Sign(yDot); + } + + var zDot = Vector3D.Dot(offset, back); + var zAbs = Math.Abs(zDot); + if (zAbs > halfExtents.Z) + { + var dist = (zAbs - halfExtents.Z) / 2; + halfExtents.Z += dist; + newCentre += back * dist * Math.Sign(zDot); + } + } + } + + var orientation = Quaternion.CreateFromRotationMatrix(worldMat); + ExpandedOBB = new MyOrientedBoundingBoxD(newCentre, halfExtents, orientation); + + } + + internal double OBBSurfaceArea(MyOrientedBoundingBoxD obb) + { + var halfExtent = obb.HalfExtent; + + return 8 * (halfExtent.X * halfExtent.Y + halfExtent.X * halfExtent.Z + halfExtent.Y * halfExtent.Z); + } + + internal void PrepGrids(bool set) + { + //ConnectedGrids.Clear(); + //MyAPIGateway.GridGroups.GetGroup(Grid, GridLinkTypeEnum.Physical, ConnectedGrids); + + var grids = GridComp.GroupMap.ConnectedGrids; + for (int i = 0; i < grids.Count; i++) + { + var grid = grids[i]; + var comp = _session.GridMap[grid]; + + if (set) + { + grid.Flags |= _session.StealthFlag; + _session.StealthedGrids.Add(grid); + + if (GridComp.DisableShields) + DisableShields(comp); + + if (GridComp.DisableWeapons) + DisableTurrets(comp); + } + else + { + grid.Flags ^= _session.StealthFlag; + _session.StealthedGrids.Remove(grid); + + if (GridComp.DisableWeapons) + ReEnableTurrets(comp); + } + } + + if (!set && _session.DisableShields) + { + ShieldWait = _session.ShieldDelay; + ShieldWaiting = true; + } + + } + + internal void DisableShields(GridComp comp) + { + for (int j = 0; j < comp.ShieldBlocks.Count; j++) + { + var block = comp.ShieldBlocks[j]; + + DisabledBlocks[block] = block.Enabled; + + block.Enabled = false; + block.EnabledChanged += OnEnabledChanged; + } + } + + internal void DisableTurrets(GridComp comp) + { + for (int j = 0; j < comp.Turrets.Count; j++) + { + var block = comp.Turrets[j]; + + DisabledBlocks[block] = block.Enabled; + + block.Enabled = false; + block.EnabledChanged += OnEnabledChanged; + } + } + + internal void ReEnableShields(GridComp comp) + { + for (int j = 0; j < comp.ShieldBlocks.Count; j++) + { + var block = comp.ShieldBlocks[j]; + + bool wasEnabled; + if (!DisabledBlocks.TryGetValue(block, out wasEnabled)) + continue; + + block.EnabledChanged -= OnEnabledChanged; + block.Enabled = wasEnabled; + + DisabledBlocks.Remove(block); + } + } + + internal void ReEnableTurrets(GridComp comp) + { + for (int j = 0; j < comp.Turrets.Count; j++) + { + var block = comp.Turrets[j]; + + bool wasEnabled; + if (!DisabledBlocks.TryGetValue(block, out wasEnabled)) + continue; + + block.EnabledChanged -= OnEnabledChanged; + block.Enabled = wasEnabled; + + DisabledBlocks.Remove(block); + } + } + + internal void OnEnabledChanged(IMyTerminalBlock block) + { + (block as IMyFunctionalBlock).Enabled = false; + } + + internal bool ToggleStealth(bool force = false) + { + if (!Online || !StealthActive && !force && (!SufficientPower || CoolingDown || !GridComp.WaterValid)) + { + var status = !Online ? "Drive Offline" + : !SufficientPower ? "Insufficient Power" + : CoolingDown ? $"Drive Cooling Down - {TimeElapsed / 60}s Remaining" + : !GridComp.WaterValid ? _session.WorkInWater ? "Drive not Submerged" + : "Drive Submerged" : ""; + MyAPIGateway.Utilities.ShowNotification(status, 2000, "Red"); + + return false; + } + + EnterStealth = !StealthActive; + ExitStealth = StealthActive; + + var message = EnterStealth ? $"Engaging Stealth - {TotalTime / 60}s Remaining" : $"Disengaging Stealth - {TimeElapsed / 60}s Cooldown"; + var colour = EnterStealth ? "Green" : "StealthOrange"; + MyAPIGateway.Utilities.ShowNotification(message, 2000, colour); + + IgnorePower = force && EnterStealth; + + return true; + } + + internal void SwitchStealth(bool stealth, bool fade = false) + { + if (stealth) + { + var antiAliasEnabled = (uint)MyAPIGateway.Session?.Config?.AntialiasingMode == 1u; + Transparency = antiAliasEnabled ? -_session.Transparency : -1f; + TransOffset = antiAliasEnabled ? -0.35f : -0.2f; + + JumpDrives.Clear(); + } + + var dither = stealth ? Transparency : 0f; + + if (fade) + { + var steps = _session.FadeSteps; + float fraction = (stealth ? 1 : steps - 1) / (float)steps; + dither = TransOffset + fraction * (Transparency - TransOffset); + + FadeEntities.Clear(); + FadeSlims.Clear(); + } + + for (int i = 0; i < GridComp.GroupMap.ConnectedGrids.Count; i++) + { + var grid = GridComp.GroupMap.ConnectedGrids[i]; + grid.GetBlocks(SlimBlocks); + + for (int j = 0; j < SlimBlocks.Count; j++) + { + var slim = SlimBlocks[j]; + var fatBlock = slim.FatBlock; + if (fatBlock == null || fatBlock is IMyOxygenFarm) + { + slim.Dithering = dither; + if (fade) FadeSlims.Add(slim); + continue; + } + if (fatBlock is MyThrust && _session.HideThrusterFlames) + { + var thrust = (MyThrust)fatBlock; + if (stealth) + { + if (_session.RecolourableThrust) + (thrust as Sandbox.ModAPI.Ingame.IMyTerminalBlock).GetProperty("HideThrustFlames").AsBool().SetValue(fatBlock, true); + else + { + var def = thrust.BlockDefinition; + var flameIdle = def.FlameIdleColor; + var flameFull = def.FlameFullColor; + + def.FlameIdleColor = Vector4.Zero; + def.FlameFullColor = Vector4.Zero; + thrust.Render.UpdateFlameAnimatorData(); + + def.FlameIdleColor = flameIdle; + def.FlameFullColor = flameFull; + } + + } + else if (!fade) + { + if (_session.RecolourableThrust) + (thrust as Sandbox.ModAPI.Ingame.IMyTerminalBlock).GetProperty("HideThrustFlames").AsBool().SetValue(fatBlock, false); + else + thrust.Render.UpdateFlameAnimatorData(); + } + + } + + if (fade) FadeEntities.Add(fatBlock); + + fatBlock.Render.Transparency = dither; + fatBlock.Render.UpdateTransparency(); + + fatBlock.Hierarchy.GetChildrenRecursive(Children); + foreach (var child in Children) + { + if (fade) FadeEntities.Add(child); + + child.Render.Transparency = dither; + child.Render.UpdateTransparency(); + } + Children.Clear(); + + if (stealth) + { + var jump = fatBlock as IMyJumpDrive; + if (jump != null) + JumpDrives.Add(jump, jump.CurrentStoredPower); + } + } + SlimBlocks.Clear(); + } + + if (fade) + { + Fade = Fading ? _session.FadeTime - Fade : _session.FadeTime; + Fading = true; + } + + VisibleToClient = !stealth; + } + + internal void ReCacheBlocks() + { + FadeSlims.Clear(); + FadeEntities.Clear(); + + var grids = GridComp.GroupMap.ConnectedGrids; + for (int i = 0; i < grids.Count; i++) + { + var grid = grids[i]; + grid.GetBlocks(SlimBlocks); + + for (int j = 0; j < SlimBlocks.Count; j++) + { + var slim = SlimBlocks[j]; + + if (slim.IsDestroyed) + continue; + + var fatBlock = slim.FatBlock; + if (fatBlock == null) + { + FadeSlims.Add(slim); + continue; + } + + FadeEntities.Add(fatBlock); + + fatBlock.Hierarchy.GetChildrenRecursive(Children); + foreach (var child in Children) + FadeEntities.Add(child); + + Children.Clear(); + } + SlimBlocks.Clear(); + } + BlocksDirty = false; + } + + internal void FadeBlocks(bool fadeOut, int step) + { + var steps = _session.FadeSteps; + var fraction = (fadeOut ? steps - step : step) / (float)steps; + var reset = !fadeOut && step == 0; + var dither = reset? 0f : TransOffset + fraction * (Transparency - TransOffset); + + Fading = step != 0; + + for (int i = 0; i < FadeSlims.Count; i++) + { + var slim = FadeSlims[i]; + if (slim.IsDestroyed) + { + FadeSlims.RemoveAtFast(i); + i--; + continue; + } + + slim.Dithering = dither; + } + + for (int i = 0; i < FadeEntities.Count; i++) + { + var entity = FadeEntities[i]; + entity.Render.Transparency = dither; + entity.Render.UpdateTransparency(); + + if (Fading || fadeOut || entity.Render is MyNullRenderComponent) //Not final step + continue; + + var thrust = entity as MyThrust; + if (thrust != null && _session.HideThrusterFlames) + { + if (_session.RecolourableThrust) + (thrust as Sandbox.ModAPI.Ingame.IMyTerminalBlock).GetProperty("HideThrustFlames").AsBool().SetValue(thrust, false); + else + thrust.Render.UpdateFlameAnimatorData(); + } + + } + Grid.Render.UpdateTransparency(); + + } + + internal void StealthExternalGrid(bool stealth, IMyCubeGrid grid) + { + if (stealth) StealthedExternalGrids.Add(grid); + else StealthedExternalGrids.Remove(grid); + + var dither = stealth ? Transparency : 0f; + + grid.GetBlocks(SlimBlocks); + foreach (var slim in SlimBlocks) + { + var block = slim.FatBlock; + if (block == null) + { + slim.Dithering = dither; + continue; + } + + block.Render.Transparency = dither; + block.Render.UpdateTransparency(); + + block.Hierarchy.GetChildrenRecursive(Children); + foreach (var child in Children) + { + child.Render.Transparency = dither; + child.Render.UpdateTransparency(); + } + } + SlimBlocks.Clear(); + + (grid as MyCubeGrid).UpdateDirty(null, true); + } + + internal void DitherBlock(bool stealth, IMySlimBlock slim) + { + var dither = stealth ? Transparency : 0f; + + if (slim.FatBlock == null) + { + if (!slim.IsDestroyed) + slim.Dithering = dither; + return; + } + + var fat = slim.FatBlock; + + fat.Render.Transparency = dither; + fat.Render.UpdateTransparency(); + + fat.Hierarchy.GetChildrenRecursive(Children); + foreach (var child in Children) + { + child.Render.Transparency = dither; + child.Render.UpdateTransparency(); + } + Children.Clear(); + } + + internal void CreateHeatSignature() + { + var gps = MyAPIGateway.Session.GPS.Create("Heat Signature", "Heat signature from a cooling down stealth drive.", Block.PositionComp.WorldAABB.Center, true, true); + gps.GPSColor = Color.OrangeRed; + HeatSignature = gps; + MyAPIGateway.Session.GPS.AddLocalGps(gps); + } + + internal void SinkInit() + { + var sinkInfo = new MyResourceSinkInfo() + { + MaxRequiredInput = 0, + RequiredInputFunc = PowerFunc, + ResourceTypeId = MyResourceDistributorComponent.ElectricityId + }; + + Sink = Block.Components?.Get(); + if (Sink != null) + { + Sink.RemoveType(ref sinkInfo.ResourceTypeId); + Sink.AddType(ref sinkInfo); + } + else + { + Sink = new MyResourceSinkComponent(); + Sink.Init(MyStringHash.GetOrCompute("Utility"), sinkInfo); + (Block as MyCubeBlock).Components.Add(Sink); + } + + Source = Grid.ResourceDistributor as MyResourceDistributorComponent; + if (Source != null) + Source.AddSink(Sink); + else + Logs.WriteLine($"DriveComp.SinkInit() - Distributor null"); + + Sink.Update(); + } + + private void GetShowInToolbarSwitch() + { + List items; + MyAPIGateway.TerminalControls.GetControls(out items); + + foreach (var item in items) + { + + if (item.Id == "ShowInToolbarConfig") + { + ShowInToolbarSwitch = (IMyTerminalControlOnOffSwitch)item; + break; + } + } + } + + private void StorageInit() + { + string rawData; + DriveRepo loadRepo = null; + if (Block.Storage == null) + { + Block.Storage = new MyModStorageComponent(); + } + else if (Block.Storage.TryGetValue(_session.CompDataGuid, out rawData)) + { + try + { + var base64 = Convert.FromBase64String(rawData); + loadRepo = MyAPIGateway.Utilities.SerializeFromBinary(base64); + } + catch (Exception ex) + { + Logs.WriteLine($"DriveComp - Exception at StorageInit() - {ex}"); + } + } + + if (loadRepo != null) + { + Sync(loadRepo); + } + else + { + Repo = new DriveRepo(); + } + } + + private float PowerFunc() + { + if (!Online) + return 0f; + if (StealthActive) + return RequiredPower; + return 0.001f; + } + + private void Sync(DriveRepo repo) + { + Repo = repo; + + StealthActive = repo.StealthActive; + CoolingDown = repo.CoolingDown; + TimeElapsed = repo.RemainingDuration; + TotalTime = repo.TotalTime; + + StealthOnInit = repo.StealthActive; + CdOnInit = repo.CoolingDown; + } + + // + // Vanilla Cope + // + + internal void GetNearbyTurrets() + { + _sphere.Center = Block.PositionComp.WorldAABB.Center; + + MyGamePruningStructure.GetAllEntitiesInSphere(ref _sphere, _entities); + + NearbyTurrets.Clear(); + for (int i = 0; i < _entities.Count; i++) + { + var entity = _entities[i]; + if (!(entity is IMyLargeTurretBase)) continue; + + var turret = entity as IMyLargeTurretBase; + if (turret.CubeGrid == Grid) continue; + + NearbyTurrets.Add(turret); + } + _entities.Clear(); + + } + + public override string ComponentTypeDebugString => "StealthMod"; + + } +} diff --git a/Utility Mods/Stealth Drive - Starcore Edition/Data/Scripts/Stealth System/Comp/SinkComp.cs b/Utility Mods/Stealth Drive - Starcore Edition/Data/Scripts/Stealth System/Comp/SinkComp.cs new file mode 100644 index 000000000..f0d21a8fd --- /dev/null +++ b/Utility Mods/Stealth Drive - Starcore Edition/Data/Scripts/Stealth System/Comp/SinkComp.cs @@ -0,0 +1,362 @@ +using Sandbox.ModAPI; +using System; +using VRage.Game; +using VRage.Game.Components; +using VRage.Game.ModAPI; +using VRageMath; +using VRage.Utils; +using Sandbox.Game.Entities; +using VRage.Game.Entity; +using System.Collections.Generic; +using Sandbox.Game.EntityComponents; +using System.Text; +using Sandbox.ModAPI.Interfaces.Terminal; +using VRage.Game.ModAPI.Interfaces; +using static VRage.Game.ObjectBuilders.Definitions.MyObjectBuilder_GameDefinition; + +namespace StealthSystem +{ + public class SinkComp : MyEntityComponentBase + { + internal IMyFunctionalBlock Block; + internal IMyCubeGrid Grid; + internal MyResourceSinkComponent Sink; + internal MyResourceDistributorComponent Source; + internal IMyTerminalControlOnOffSwitch ShowInToolbarSwitch; + + internal SinkRepo Repo; + internal DriveComp Master; + internal Definitions.SinkDefinition Definition; + + internal Color OldColour; + internal MyOrientedBoundingBoxD DamageBox; + internal MyOrientedBoundingBoxD BlockBox; + + internal bool Inited; + internal bool PowerDirty; + internal bool Working = true; + internal bool SufficientPower; + internal bool Accumulating; + internal bool Radiating; + internal bool WasAccumulating; + internal bool WorkingChanged; + + internal long CompTick; + internal byte HeatPercent; + + private StealthSession _session; + + internal SinkComp(IMyFunctionalBlock sinkBlock, Definitions.SinkDefinition def, StealthSession session) + { + _session = session; + + Block = sinkBlock; + Definition = def; + } + + public override void OnBeforeRemovedFromContainer() + { + base.OnBeforeRemovedFromContainer(); + + Close(); + } + + public override bool IsSerialized() + { + if (Block.Storage == null || Repo == null) return false; + + Repo.Sync(this); + + Block.Storage[_session.CompDataGuid] = Convert.ToBase64String(MyAPIGateway.Utilities.SerializeToBinary(Repo)); + + return false; + } + + internal void Init() + { + Grid = Block.CubeGrid; + + //Block.IsWorkingChanged += IsWorkingChanged; + + Block.Components.Add(this); + CompTick = Block.EntityId % 20; + + Block.SetEmissiveParts(StealthSession.RADIANT_EMISSIVE, Color.DarkSlateGray, 0.1f); + + SinkInit(); + StorageInit(); + + Source.SystemChanged += SourceChanged; + + Inited = true; + + if (!_session.IsDedicated) + { + GetShowInToolbarSwitch(); + Block.AppendingCustomInfo += AppendingCustomData; + } + } + + internal void Close() + { + GridComp gridComp; + if (_session.GridMap.TryGetValue(Grid, out gridComp)) + { + gridComp.HeatComps.Remove(this); + } + + //Block.IsWorkingChanged -= IsWorkingChanged; + + Source.SystemChanged -= SourceChanged; + + if (!_session.IsDedicated) + Block.AppendingCustomInfo -= AppendingCustomData; + + Clean(); + } + + internal void Clean() + { + Block = null; + Grid = null; + Sink = null; + Source = null; + ShowInToolbarSwitch = null; + + Repo = null; + Master = null; + } + + private void IsWorkingChanged(IMyCubeBlock block) + { + Working = block.IsWorking; + } + + private void AppendingCustomData(IMyTerminalBlock block, StringBuilder builder) + { + var status = !Working ? "Offline" : !SufficientPower ? "Insufficient Power" : Radiating ? "Venting ඞ" : Accumulating ? "Accumulating Heat" : "Ready"; + + builder.Append("Heat Sink Status: ") + .Append(status) + .Append("\n") + .Append("Stored Heat: ") + .Append($"{HeatPercent}%"); + } + + private void SourceChanged() + { + PowerDirty = true; + } + + internal void GridChange(GridComp gridComp) + { + gridComp.HeatComps.Remove(this); + + Grid = Block.CubeGrid; + + var newGridComp = _session.GridMap[Grid]; + newGridComp.HeatComps.Add(this); + + Source = Grid.ResourceDistributor as MyResourceDistributorComponent; + } + + internal void UpdateStatus() + { + if (PowerDirty || Source == null) + { + Source = Grid.ResourceDistributor as MyResourceDistributorComponent; + PowerDirty = false; + } + var available = Source.MaxAvailableResourceByType(MyResourceDistributorComponent.ElectricityId, (MyCubeGrid)Grid) - Source.TotalRequiredInputByType(MyResourceDistributorComponent.ElectricityId, (MyCubeGrid)Grid); + SufficientPower = available > 0; + + var isWorking = Block.IsFunctional && Block.Enabled && SufficientPower; + if (isWorking != Working) + { + Working = isWorking; + WorkingChanged = true; + } + //SufficientPower = StealthActive ? available >= 0 : available >= RequiredPower; + //Online = Block.IsFunctional && Block.Enabled && available > 0; + + if (!_session.IsDedicated) + SetEmissiveColor(); + } + + internal void SetEmissiveColor() + { + if (Radiating) + Block.SetEmissiveParts(StealthSession.RADIANT_EMISSIVE, Color.DarkRed, HeatPercent / 200); + + var emissiveColor = !Block.IsFunctional ? Color.Black : !Working ? EmissiveValues.RED : Accumulating ? Color.Cyan : Radiating ? Color.OrangeRed : EmissiveValues.GREEN; + if (emissiveColor == OldColour) + return; + + OldColour = emissiveColor; + Block.SetEmissiveParts(StealthSession.STATUS_EMISSIVE, emissiveColor, 1f); + } + + internal List BlockBoxes = new List(); + + internal void DamageBlocks() + { + var large = Grid.GridSizeEnum == MyCubeSize.Large; + var box = large ? _session.LargeBox : _session.SmallBox; + var radius = large ? 7.25 : 6.45; + var offset = large ? 7.75 : 7.25; + var matrix = Block.WorldMatrix; + matrix.Translation += Block.WorldMatrix.Up * offset; + var obb = new MyOrientedBoundingBoxD(box, matrix); + //DamageBox = obb; + + var hits = new List(); + MyGamePruningStructure.GetAllEntitiesInOBB(ref obb, hits); + + //BlockBoxes.Clear(); + for (int i = 0; i < hits.Count; i++) + { + var ent = hits[i]; + + var dest = ent as IMyDestroyableObject; + if (dest != null) + { + var entObb = new MyOrientedBoundingBoxD(ent.PositionComp.LocalAABB, ent.PositionComp.WorldMatrixRef); + if (entObb.Contains(ref obb) != ContainmentType.Disjoint) + dest.DoDamage(9f, MyDamageType.Temperature, true); + + continue; + } + + var grid = ent as IMyCubeGrid; + if (grid != null) + { + var sphere = new BoundingSphereD(matrix.Translation, radius); + var slims = grid.GetBlocksInsideSphere(ref sphere); + + for (int j = 0; j < slims.Count; j++) + { + var slim = slims[j]; + var fat = slim.FatBlock; + MyOrientedBoundingBoxD blockBox; + if (fat == null) + { + var gridSize = (double)Grid.GridSize; + var aabb = new BoundingBoxD(slim.Min * gridSize - gridSize / 2, slim.Max * gridSize + gridSize / 2); + blockBox = new MyOrientedBoundingBoxD(aabb, grid.PositionComp.WorldMatrixRef); + } + else + { + blockBox = new MyOrientedBoundingBoxD(fat.PositionComp.LocalAABB, fat.PositionComp.WorldMatrixRef); + } + + if (obb.Contains(ref blockBox) != ContainmentType.Disjoint) + { + slim.DoDamage(500f, MyDamageType.Temperature, true); + //BlockBoxes.Add(blockBox); + } + + } + } + } + } + + internal void SinkInit() + { + var sinkInfo = new MyResourceSinkInfo() + { + MaxRequiredInput = 0, + RequiredInputFunc = PowerFunc, + ResourceTypeId = MyResourceDistributorComponent.ElectricityId + }; + + Sink = Block.Components?.Get(); + if (Sink != null) + { + Sink.RemoveType(ref sinkInfo.ResourceTypeId); + Sink.AddType(ref sinkInfo); + } + else + { + Sink = new MyResourceSinkComponent(); + Sink.Init(MyStringHash.GetOrCompute("Utility"), sinkInfo); + (Block as MyCubeBlock).Components.Add(Sink); + } + + Source = Grid.ResourceDistributor as MyResourceDistributorComponent; + if (Source != null) + Source.AddSink(Sink); + else + Logs.WriteLine($"SinkComp.SinkInit() - Distributor null"); + + Sink.Update(); + } + + private float PowerFunc() + { + if (!Working) + return 0f; + if (Accumulating) + return Definition.Power; + return 0.001f; + } + + private void GetShowInToolbarSwitch() + { + List items; + MyAPIGateway.TerminalControls.GetControls(out items); + + foreach (var item in items) + { + + if (item.Id == "ShowInToolbarConfig") + { + ShowInToolbarSwitch = (IMyTerminalControlOnOffSwitch)item; + break; + } + } + } + + private void StorageInit() + { + string rawData; + SinkRepo loadRepo = null; + if (Block.Storage == null) + { + Block.Storage = new MyModStorageComponent(); + } + else if (Block.Storage.TryGetValue(_session.CompDataGuid, out rawData)) + { + try + { + var base64 = Convert.FromBase64String(rawData); + loadRepo = MyAPIGateway.Utilities.SerializeFromBinary(base64); + } + catch (Exception ex) + { + Logs.WriteLine($"SinkComp - Exception at StorageInit() - {ex}"); + } + } + + if (loadRepo != null) + { + Sync(loadRepo); + } + else + { + Repo = new SinkRepo(); + } + } + + private void Sync(SinkRepo repo) + { + Repo = repo; + + Accumulating = repo.Accumulating; + Radiating = repo.Radiating; + HeatPercent = repo.HeatPercent; + } + + public override string ComponentTypeDebugString => "StealthMod"; + + } +} diff --git a/Utility Mods/Stealth Drive - Starcore Edition/Data/Scripts/Stealth System/Definitions/Definitions.cs b/Utility Mods/Stealth Drive - Starcore Edition/Data/Scripts/Stealth System/Definitions/Definitions.cs new file mode 100644 index 000000000..36816b7d2 --- /dev/null +++ b/Utility Mods/Stealth Drive - Starcore Edition/Data/Scripts/Stealth System/Definitions/Definitions.cs @@ -0,0 +1,40 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace StealthSystem +{ + internal class Definitions + { + internal class DriveDefinition + { + internal int Duration; + internal float PowerScale; + internal float SignalRangeScale; + + public DriveDefinition(int duration, float powerScale, float signalScale) + { + Duration = duration; + PowerScale = powerScale; + SignalRangeScale = signalScale; + } + } + + internal class SinkDefinition + { + internal int Duration; + internal float Power; + internal bool DoDamage; + + public SinkDefinition(int duration, float power, bool damage) + { + Duration = duration; + Power = power; + DoDamage = damage; + } + } + + } +} diff --git a/Utility Mods/Stealth Drive - Starcore Edition/Data/Scripts/Stealth System/Session/SessionControls.cs b/Utility Mods/Stealth Drive - Starcore Edition/Data/Scripts/Stealth System/Session/SessionControls.cs new file mode 100644 index 000000000..971d5e017 --- /dev/null +++ b/Utility Mods/Stealth Drive - Starcore Edition/Data/Scripts/Stealth System/Session/SessionControls.cs @@ -0,0 +1,255 @@ +using Sandbox.ModAPI; +using VRage.Utils; +using System.Collections.Generic; +using Sandbox.ModAPI.Interfaces.Terminal; +using System.Text; + +namespace StealthSystem +{ + public partial class StealthSession + { + private readonly List _customControls = new List(); + private readonly List _customActions = new List(); + + internal IMyTerminalBlock LastTerminal; + + private void CustomControlGetter(IMyTerminalBlock block, List controls) + { + if (block is IMyUpgradeModule && DriveDefinitions.ContainsKey(block.BlockDefinition.SubtypeName)) + { + foreach (var control in _customControls) + controls.Add(control); + } + + LastTerminal = block; + } + + private void CustomActionGetter(IMyTerminalBlock block, List actions) + { + if (block is IMyUpgradeModule && DriveDefinitions.ContainsKey(block.BlockDefinition.SubtypeName)) + { + foreach (var action in _customActions) + actions.Add(action); + } + } + + internal void CreateTerminalControls() where T : IMyUpgradeModule + { + _customControls.Add(Separator()); + _customControls.Add(CreateEnterStealth()); + _customControls.Add(CreateExitStealth()); + + _customActions.Add(CreateEnterAction()); + _customActions.Add(CreateExitAction()); + _customActions.Add(CreateSwitchAction()); + } + + internal IMyTerminalControlSeparator Separator() where T : IMyTerminalBlock + { + var c = MyAPIGateway.TerminalControls.CreateControl("Stealth_Separator"); + + c.Enabled = IsTrue; + c.Visible = IsTrue; + + return c; + } + + internal IMyTerminalControlButton CreateEnterStealth() where T : IMyUpgradeModule + { + var control = MyAPIGateway.TerminalControls.CreateControl($"Stealth_Enter"); + + control.Title = MyStringId.GetOrCompute("Enter Stealth"); + control.Tooltip = MyStringId.GetOrCompute("Engage Stealth Drive to become virtually undetectable."); + control.Action = EnterStealth; + control.Visible = IsTrue; + control.Enabled = CanEnterStealth; + + return control; + } + + internal IMyTerminalControlButton CreateExitStealth() where T : IMyUpgradeModule + { + var control = MyAPIGateway.TerminalControls.CreateControl($"Stealth_Exit"); + + control.Title = MyStringId.GetOrCompute("Leave Stealth"); + control.Tooltip = MyStringId.GetOrCompute("Disengage Stealth Drive."); + control.Action = ExitStealth; + control.Visible = IsTrue; + control.Enabled = CanExitStealth; + + return control; + } + + internal IMyTerminalAction CreateEnterAction() where T : IMyUpgradeModule + { + var action = MyAPIGateway.TerminalControls.CreateAction("Stealth_Enter_Action"); + action.Icon = ModPath + @"\Textures\GUI\Icons\Actions\StealthSwitchOn.dds"; + action.Name = new StringBuilder("Enter Stealth"); + action.Action = EnterStealth; + action.Writer = EnterStealthWriter; + action.Enabled = IsTrue; + + return action; + } + + internal IMyTerminalAction CreateExitAction() where T : IMyUpgradeModule + { + var action = MyAPIGateway.TerminalControls.CreateAction("Stealth_Exit_Action"); + action.Icon = ModPath + @"\Textures\GUI\Icons\Actions\StealthSwitchOff.dds"; + action.Name = new StringBuilder("Leave Stealth"); + action.Action = ExitStealth; + action.Writer = ExitStealthWriter; + action.Enabled = IsTrue; + + return action; + } + + internal IMyTerminalAction CreateSwitchAction() where T : IMyUpgradeModule + { + var action = MyAPIGateway.TerminalControls.CreateAction("Stealth_Switch_Action"); + action.Icon = ModPath + @"\Textures\GUI\Icons\Actions\StealthSwitchToggle.dds"; + action.Name = new StringBuilder("Switch Stealth"); + action.Action = SwitchStealth; + action.Writer = SwitchStealthWriter; + action.Enabled = IsTrue; + + return action; + } + + internal bool IsTrue(IMyTerminalBlock block) + { + return true; + } + + internal bool CanEnterStealth(IMyTerminalBlock block) + { + DriveComp comp; + if (!DriveMap.TryGetValue(block.EntityId, out comp)) + { + Logs.WriteLine("CanEnterStealth() - Comp not found!"); + return false; + } + + return comp.Online && comp.SufficientPower && !comp.CoolingDown && !comp.StealthActive && comp.GridComp.WaterValid; + } + + internal bool CanExitStealth(IMyTerminalBlock block) + { + DriveComp comp; + if (!DriveMap.TryGetValue(block.EntityId, out comp)) + { + Logs.WriteLine("CanExitStealth() - Comp not found!"); + return false; + } + + return comp.Online && comp.StealthActive; + } + + internal void EnterStealthWriter(IMyTerminalBlock block, StringBuilder builder) + { + DriveComp comp; + if (!DriveMap.TryGetValue(block.EntityId, out comp)) + { + Logs.WriteLine("EnterStealthWriter() - Comp not found!"); + return; + } + + if (comp.StealthActive) + builder.Append("Cloaked"); + else + builder.Append("Cloak"); + } + + internal void ExitStealthWriter(IMyTerminalBlock block, StringBuilder builder) + { + DriveComp comp; + if (!DriveMap.TryGetValue(block.EntityId, out comp)) + { + Logs.WriteLine("ExitStealthWriter() - Comp not found!"); + return; + } + + if (comp.StealthActive) + builder.Append("Uncloak"); + else + builder.Append("Uncloaked"); + } + + internal void SwitchStealthWriter(IMyTerminalBlock block, StringBuilder builder) + { + DriveComp comp; + if (!DriveMap.TryGetValue(block.EntityId, out comp)) + { + Logs.WriteLine("ExitStealthWriter() - Comp not found!"); + return; + } + + if (comp.StealthActive) + builder.Append("Uncloak"); + else + builder.Append("Cloak"); + } + + internal void EnterStealth(IMyTerminalBlock block) + { + DriveComp comp; + if (!DriveMap.TryGetValue(block.EntityId, out comp)) + { + Logs.WriteLine("EnterStealth() - Comp not found!"); + return; + } + + if (!comp.Online || !comp.SufficientPower || comp.CoolingDown || comp.StealthActive || !comp.GridComp.WaterValid) + { + var status = !comp.Online ? "Drive Offline" + : !comp.SufficientPower ? "Insufficient Power" + : comp.CoolingDown ? $"Drive Cooling Down - {comp.TimeElapsed / 60}s Remaining" + : comp.StealthActive ? "Drive Already Engaged" + : !comp.GridComp.WaterValid ? WorkInWater ? "Drive not Submerged" + : "Drive Submerged" : ""; + MyAPIGateway.Utilities.ShowNotification(status, 2000, "Red"); + return; + } + + comp.EnterStealth = true; + MyAPIGateway.Utilities.ShowNotification($"Engaging Stealth - {comp.TotalTime / 60}s Remaining", 2000, "Green"); + + foreach (var control in _customControls) + control.UpdateVisual(); + } + + internal void ExitStealth(IMyTerminalBlock block) + { + DriveComp comp; + if (!DriveMap.TryGetValue(block.EntityId, out comp)) + { + Logs.WriteLine("ExitStealth() - Comp not found!"); + return; + } + + if (!comp.Online || !comp.StealthActive) return; + + comp.ExitStealth = true; + MyAPIGateway.Utilities.ShowNotification($"Disengaging Stealth - {comp.TimeElapsed / 60}s Cooldown", 2000, "StealthOrange"); + + foreach (var control in _customControls) + control.UpdateVisual(); + } + + internal void SwitchStealth(IMyTerminalBlock block) + { + DriveComp comp; + if (!DriveMap.TryGetValue(block.EntityId, out comp)) + { + Logs.WriteLine("SwitchStealth() - Comp not found!"); + return; + } + + comp.ToggleStealth(); + + foreach (var control in _customControls) + control.UpdateVisual(); + } + + } +} diff --git a/Utility Mods/Stealth Drive - Starcore Edition/Data/Scripts/Stealth System/Session/SessionEvents.cs b/Utility Mods/Stealth Drive - Starcore Edition/Data/Scripts/Stealth System/Session/SessionEvents.cs new file mode 100644 index 000000000..27a28fbec --- /dev/null +++ b/Utility Mods/Stealth Drive - Starcore Edition/Data/Scripts/Stealth System/Session/SessionEvents.cs @@ -0,0 +1,184 @@ +using Sandbox.ModAPI; +using System; +using VRage.Game.ModAPI; +using VRage.ModAPI; +using Sandbox.Game.Entities; +using VRage.Game.Entity; +using System.Collections.Generic; + +namespace StealthSystem +{ + public partial class StealthSession + { + private void OnEntityCreate(MyEntity entity) + { + try + { + if (!Inited) lock (InitObj) Init(); + + var planet = entity as MyPlanet; + if (planet != null) + PlanetTemp.TryAdd(planet, byte.MaxValue); //More keen jank workarounds + + var grid = entity as IMyCubeGrid; + if (grid != null) + { + (grid as MyCubeGrid).AddedToScene += AddToStart => _startGrids.Add(grid); + return; + } + + var upgrade = entity as IMyUpgradeModule; + if (upgrade != null) + { + var subtype = upgrade.BlockDefinition.SubtypeName; + if (Enforced && !DriveDefinitions.ContainsKey(subtype) && !SinkDefinitions.ContainsKey(subtype)) + return; + + (upgrade as MyCubeBlock).AddedToScene += AddToStart => _startBlocks.Add(upgrade); + } + + if (!PbApiInited && IsServer && entity is IMyProgrammableBlock) + { + MyAPIGateway.Utilities.InvokeOnGameThread(() => API.PbInit()); + PbApiInited = true; + } + } + catch (Exception ex) + { + Logs.WriteLine($"Exception in EntityCreate: {entity.GetType()} - {ex}"); + } + + } + + private void OnGridClose(IMyEntity entity) + { + var grid = entity as IMyCubeGrid; + + if (GridMap.ContainsKey(grid)) + { + var comp = GridMap[grid]; + GridMap.Remove(grid); + GridList.Remove(comp); + + comp.Clean(); + _gridCompPool.Push(comp); + } + else Logs.WriteLine("OnGridClose() - grid not in map!!!"); + } + + private void OnCloseAll() + { + try + { + var list = new List(GridGroupMap.Keys); + foreach (var value in list) + GridGroupsOnOnGridGroupDestroyed(value); + + MyAPIGateway.GridGroups.OnGridGroupDestroyed -= GridGroupsOnOnGridGroupDestroyed; + MyAPIGateway.GridGroups.OnGridGroupCreated -= GridGroupsOnOnGridGroupCreated; + + GridGroupMap.Clear(); + } + catch (Exception ex) + { + Logs.WriteLine($"Exception in CloseAll: {ex}"); + } + + } + + private void GridGroupsOnOnGridGroupCreated(IMyGridGroupData groupData) + { + if (groupData.LinkType != GridLinkTypeEnum.Physical) + return; + + var map = _groupMapPool.Count > 0 ? _groupMapPool.Pop() : new GroupMap(); + map.Init(groupData, this); + + //groupData.OnReleased += map.OnReleased; + groupData.OnGridAdded += map.OnGridAdded; + groupData.OnGridRemoved += map.OnGridRemoved; + GridGroupMap[groupData] = map; + } + + private void GridGroupsOnOnGridGroupDestroyed(IMyGridGroupData groupData) + { + if (groupData.LinkType != GridLinkTypeEnum.Physical) + return; + + GroupMap map; + if (GridGroupMap.TryGetValue(groupData, out map)) + { + //groupData.OnReleased -= map.OnReleased; + groupData.OnGridAdded -= map.OnGridAdded; + groupData.OnGridRemoved -= map.OnGridRemoved; + + GridGroupMap.Remove(groupData); + map.Clean(); + _groupMapPool.Push(map); + } + else + Logs.WriteLine($"GridGroupsOnOnGridGroupDestroyed could not find map"); + } + + private void PlayerConnected(long id) + { + try + { + MyAPIGateway.Multiplayer.Players.GetPlayers(null, myPlayer => FindPlayer(myPlayer, id)); + } + catch (Exception ex) { Logs.WriteLine($"Exception in PlayerConnected: {ex}"); } + } + + private bool FindPlayer(IMyPlayer player, long id) + { + if (player.IdentityId == id) + { + var packet = new SettingsPacket { EntityId = 0, Settings = ConfigSettings.Config, Type = PacketType.Settings }; + SendPacketToClient(packet, player.SteamUserId); + } + return false; + } + + internal void AfterDamageApplied(object target, MyDamageInformation info) + { + if (!DisableWeapons && RevealOnDamage) //Reveal grid on dealing damage + { + var ent = MyEntities.GetEntityById(info.AttackerId); + if (!(ent is MyCubeBlock)) return; + + var attackingGrid = (ent as IMyCubeBlock).CubeGrid; + if (attackingGrid == null) return; + + if (!StealthedGrids.Contains(attackingGrid)) + return; + + GridComp gridCompA; + if (!GridMap.TryGetValue(attackingGrid, out gridCompA)) + { + Logs.WriteLine("Attacking grid not mapped in damage handler"); + return; + } + + gridCompA.Revealed = true; + } + + if (!TrackDamage) return; + + if (info.AttackerId == 0 || !(target is IMySlimBlock)) + return; + + var targetGrid = (target as IMySlimBlock).CubeGrid; + + if (targetGrid == null || !StealthedGrids.Contains(targetGrid)) return; + + GridComp gridComp; + if (!GridMap.TryGetValue(targetGrid, out gridComp)) + { + Logs.WriteLine("Grid not mapped in damage handler"); + return; + } + + gridComp.DamageTaken += (int)info.Amount; + } + } +} diff --git a/Utility Mods/Stealth Drive - Starcore Edition/Data/Scripts/Stealth System/Session/SessionFields.cs b/Utility Mods/Stealth Drive - Starcore Edition/Data/Scripts/Stealth System/Session/SessionFields.cs new file mode 100644 index 000000000..181da45a1 --- /dev/null +++ b/Utility Mods/Stealth Drive - Starcore Edition/Data/Scripts/Stealth System/Session/SessionFields.cs @@ -0,0 +1,133 @@ +using Sandbox.ModAPI; +using System; +using VRage.Game.ModAPI; +using VRage.ModAPI; +using VRageMath; +using VRage.Utils; +using VRage.Game.Entity; +using System.Collections.Generic; +using VRage.Collections; +using Jakaria.API; +using System.Collections.Concurrent; +using Sandbox.Game.Entities; +using Sandbox.Definitions; + +namespace StealthSystem +{ + public partial class StealthSession + { + internal const string STATUS_EMISSIVE = "Emissive"; + internal const string RADIANT_EMISSIVE = "Emissive0"; + + internal const int FADE_INTERVAL = 5; + internal const int IsStealthedFlag = 0x20000000; + + internal readonly Dictionary DriveDefinitions = new Dictionary(); + internal readonly Dictionary SinkDefinitions = new Dictionary(); + + internal readonly HashSet ShieldBlocks = new HashSet() + { + "EmitterL", + "EmitterS", + "EmitterST", + "EmitterLA", + "EmitterSA", + "LargeShipSmallShieldGeneratorBase", + "LargeShipLargeShieldGeneratorBase", + "SmallShipSmallShieldGeneratorBase", + "SmallShipMicroShieldGeneratorBase", + "LargeGridLargeShield", + "LargeGridSmallShield", + "SmallGridLargeShield", + "SmallGridSmallShield", + }; + + internal string ModPath; + internal readonly Guid CompDataGuid = new Guid("75BBB4F5-4FB9-4230-AAAA-BB79C9811507"); + internal static readonly MyStringId _square = MyStringId.GetOrCompute("Square"); + + internal BoundingBoxD LargeBox; + internal BoundingBoxD SmallBox; + + internal EntityFlags StealthFlag; + + internal int ShieldDelay; + internal int JumpPenalty; + internal int FadeTime; + internal int FadeSteps; + internal int DamageThreshold; + internal float Transparency; + internal float WaterTransitionDepth; + internal float WaterOffsetSqr; + internal bool DisableShields; + internal bool DisableWeapons; + internal bool HideThrusterFlames; + internal bool WorkInWater; + internal bool WorkOutOfWater; + internal bool TrackWater; + internal bool TrackDamage; + internal bool RevealOnDamage; + + internal readonly Dictionary DriveMap = new Dictionary(); + internal readonly Dictionary GridMap = new Dictionary(); + internal readonly Dictionary GridGroupMap = new Dictionary(); + internal readonly List GridList = new List(); + internal readonly HashSet StealthedGrids = new HashSet(); + internal readonly Vector3D[] ObbCorners = new Vector3D[8]; + + internal Settings ConfigSettings; + internal APIBackend API; + internal APIServer APIServer; + internal readonly WaterModAPI WaterAPI = new WaterModAPI(); + + internal object InitObj = new object(); + internal bool Enforced; + internal bool Inited; + internal bool PbApiInited; + + internal bool WcActive; + internal bool WaterMod; + internal bool RecolourableThrust; + + internal readonly ConcurrentDictionary WaterMap = new ConcurrentDictionary(); + internal readonly ConcurrentDictionary PlanetMap = new ConcurrentDictionary(); + internal readonly ConcurrentDictionary PlanetTemp = new ConcurrentDictionary(); + + private readonly List _entities = new List(); + private readonly ConcurrentCachingList _startBlocks = new ConcurrentCachingList(); + private readonly ConcurrentCachingList _startGrids = new ConcurrentCachingList(); + private readonly Stack _groupMapPool = new Stack(64); + private readonly Stack _gridCompPool = new Stack(128); + + private readonly Vector3D _large = new Vector3D(1.125, 6.25, 3.5); + private readonly Vector3D _small = new Vector3D(1.125, 6.25, 1.125); + + public StealthSession() + { + API = new APIBackend(this); + APIServer = new APIServer(this); + } + + private void Clean() + { + DriveDefinitions.Clear(); + SinkDefinitions.Clear(); + ShieldBlocks.Clear(); + + DriveMap.Clear(); + GridMap.Clear(); + GridGroupMap.Clear(); + GridList.Clear(); + StealthedGrids.Clear(); + + _entities.Clear(); + _startBlocks.ClearImmediate(); + _startGrids.ClearImmediate(); + _groupMapPool.Clear(); + _gridCompPool.Clear(); + + _customControls.Clear(); + _customActions.Clear(); + } + } +} diff --git a/Utility Mods/Stealth Drive - Starcore Edition/Data/Scripts/Stealth System/Session/SessionLogic.cs b/Utility Mods/Stealth Drive - Starcore Edition/Data/Scripts/Stealth System/Session/SessionLogic.cs new file mode 100644 index 000000000..1f598a77d --- /dev/null +++ b/Utility Mods/Stealth Drive - Starcore Edition/Data/Scripts/Stealth System/Session/SessionLogic.cs @@ -0,0 +1,614 @@ +using Sandbox.ModAPI; +using System; +using VRage.Game.ModAPI; +using VRageMath; +using Sandbox.Game.Entities; +using VRage.Game.Entity; +using System.Collections.Generic; +using VRage.Game.ModAPI.Interfaces; + +namespace StealthSystem +{ + public partial class StealthSession + { + internal void CompLoop() + { + //var position = MyAPIGateway.Session.LocalHumanPlayer?.Character?.PositionComp.WorldAABB.Center ?? MyAPIGateway.Session?.Camera?.Position; + //var controlledGrid = (MyAPIGateway.Session.ControlledObject as MyCubeBlock)?.GetTopMostParent(); + + if (GridList.Count == 0) return; + + for (int i = 0; i < GridList.Count; i++) + { + var gridComp = GridList[i]; + var master = gridComp.MasterComp; + + if (gridComp.GroupMap == null) + { + var group = MyAPIGateway.GridGroups.GetGridGroup(GridLinkTypeEnum.Physical, gridComp.Grid); + if (group != null) + { + GroupMap map; + if (GridGroupMap.TryGetValue(group, out map)) + gridComp.GroupMap = map; + } + } + + bool enter = false; + bool exit = false; + bool cold = false; + + try + { + for (int j = 0; j < gridComp.StealthComps.Count; j++) + { + var comp = gridComp.StealthComps[j]; + + if (comp.Grid != comp.Block.CubeGrid) + { + if (!GridMap.ContainsKey(comp.Block.CubeGrid)) + { + comp.Transfer = true; + continue; + } + + comp.GridChange(); + } + + if (!IsDedicated && comp.Fading) + { + if (comp.StealthActive && (gridComp.GroupsDirty || comp.BlocksDirty)) + comp.ReCacheBlocks(); + + if (comp.Fade-- % FADE_INTERVAL == 0) + comp.FadeBlocks(comp.StealthActive, comp.Fade / FADE_INTERVAL); + } + + if (comp.ShieldWaiting) + { + if (comp.ShieldWait-- <= 0) + { + comp.ShieldWaiting = false; + + foreach (var block in comp.DisabledBlocks.Keys) + { + block.EnabledChanged -= comp.OnEnabledChanged; + block.Enabled = comp.DisabledBlocks[block]; + } + comp.DisabledBlocks.Clear(); + } + } + + //Update cooldown and heat signal + if (comp.CoolingDown) + { + if (comp.TimeElapsed-- <= 0 || comp.EnterStealth) //comp.RemainingDuration-- <= 0 + { + if (!IsDedicated && comp.HeatSignature != null) + { + MyAPIGateway.Session.GPS.RemoveLocalGps(comp.HeatSignature); + comp.HeatSignature = null; + } + comp.CoolingDown = false; + cold = true; + } + else if (!IsDedicated && comp.HeatSignature != null) + { + comp.HeatSignature.Coords = comp.Block.PositionComp.WorldAABB.Center; + } + + if (!IsDedicated && comp.CdOnInit) + { + var position = MyAPIGateway.Session?.Camera?.Position ?? Vector3D.Zero; + if (Vector3D.DistanceSquared(position, comp.Block.PositionComp.WorldAABB.Center) < comp.SignalDistanceSquared) + comp.CreateHeatSignature(); + + comp.CdOnInit = false; + } + } + + //Hide/unhide main grid after delay to match slimblock transparency update + //if (comp.DelayedRender) + //{ + // if (comp.Delay-- == 0) + // { + // foreach (var grid in comp.ConnectedGrids) + // comp.DitherFatBlocks(!comp.VisibleToClient); + + // comp.DelayedRender = false; + // } + //} + + if (!comp.IsPrimary && !comp.StealthActive) + continue; + + if (comp != master && (master == null || !master.Online)) + { + Logs.WriteLine($"[StealthMod] Primary != master - master null: {master == null}"); + master = comp; + } + + if (!comp.Block.IsFunctional && (!comp.TransferFailed || Tick120)) + comp.TransferFailed = !comp.TransferPrimary(false); + + //Calculate grid surface area and drive power + if (gridComp.GroupsDirty || Tick60 && comp.GridUpdated) + { + comp.CalculatePowerRequirements(); + gridComp.GroupsDirty = false; + comp.GridUpdated = false; + } + + if (TrackWater) + { + WaterData waterData; + if (Tick3600) + { + var planet = MyGamePruningStructure.GetClosestPlanet(gridComp.Grid.PositionComp.WorldAABB.Center); + + if (planet != gridComp.Planet && planet != null && WaterMap.TryGetValue(planet.EntityId, out waterData)) + gridComp.Water = new BoundingSphereD(waterData.Centre, waterData.Radius + WaterTransitionDepth); + + gridComp.Planet = planet; + } + + if (Tick60 && gridComp.Planet != null && WaterMap.TryGetValue(gridComp.Planet.EntityId, out waterData)) + { + gridComp.Underwater = false; + + var planetVector = gridComp.Grid.PositionComp.WorldAABB.Center - waterData.Centre; + var radius = waterData.Radius + WaterTransitionDepth; + var radiusSqr = radius * radius; + if (planetVector.LengthSquared() < radiusSqr) + { + gridComp.Underwater = true; + + var obb = new MyOrientedBoundingBoxD(gridComp.Grid.PositionComp.LocalAABB, gridComp.Grid.PositionComp.WorldMatrixRef); + obb.GetCorners(ObbCorners, 0); + for (int k = 0; k < 8; k++) + { + var corner = ObbCorners[j]; + planetVector = corner - waterData.Centre; + + if (planetVector.LengthSquared() > radiusSqr) + { + gridComp.Underwater = false; + break; + } + } + } + gridComp.WaterValid = gridComp.Underwater == WorkInWater; + } + } + + //Update comp state and refresh custom info + if (Tick20 || comp.PowerDirty) + { + comp.UpdateStatus(); + if (!IsDedicated && LastTerminal == comp.Block && MyAPIGateway.Gui.GetCurrentScreen == MyTerminalPageEnum.ControlPanel) + comp.RefreshTerminal(); + } + + if (comp.StealthActive) + { + //Exit stealth conditions + var forcedExit = !comp.IsPrimary || !comp.Online || gridComp.Revealed || !gridComp.WaterValid || TrackDamage && gridComp.DamageTaken > DamageThreshold; + if (forcedExit || !comp.IgnorePower && (!comp.SufficientPower || comp.TimeElapsed++ >= comp.TotalTime)) //comp.RemainingDuration-- <= 0 + comp.ExitStealth = true; + + //Decrease remaining stealth duration after jump + if (Tick120) + { + var jumpList = new List(comp.JumpDrives.Keys); + foreach (var jump in jumpList) + { + if (jump.CurrentStoredPower < comp.JumpDrives[jump]) + comp.TotalTime -= JumpPenalty; + //comp.RemainingDuration -= JumpPenalty; + + comp.JumpDrives[jump] = jump.CurrentStoredPower; + } + } + + //Vanilla fuckery + if (!WcActive) + { + if (TickMod60 == comp.CompTick60) + comp.GetNearbyTurrets(); + + for (int k = 0; k < comp.NearbyTurrets.Count; k++) + { + var turret = comp.NearbyTurrets[k]; + + if (!turret.HasTarget) continue; + + var target = turret.Target; + + var block = target as IMyCubeBlock; + if (block != null && ((uint)block.CubeGrid.Flags & IsStealthedFlag) > 0) + { + turret.ResetTargetingToDefault(); + continue; + } + + if (((uint)target.Flags & IsStealthedFlag) > 0) + turret.ResetTargetingToDefault(); + } + } + } + + //if (comp.ExpandedOBB != null) DrawBox(comp.ExpandedOBB, Color.AliceBlue); + + if (comp.EnterStealth || comp.ExitStealth || comp.StealthOnInit || comp.StealthActive && TickMod15 == comp.CompTick15) + { + comp.CalculateExpandedOBB(); + + Vector3D position = Vector3D.Zero; + bool inside = false; + if (!IsDedicated) + { + position = MyAPIGateway.Session?.Camera?.Position ?? Vector3D.Zero; + inside = comp.ExpandedOBB.Contains(ref position); + } + + if (comp.EnterStealth) + { + comp.EnterStealth = false; + comp.UpdateStatus(); + if (!comp.Online || !comp.IgnorePower && !comp.SufficientPower) + continue; + + enter = true; + + gridComp.DamageTaken = 0; + gridComp.Revealed = false; + comp.StealthActive = true; + //comp.RemainingDuration = comp.MaxDuration; + comp.TotalTime = comp.MaxDuration; + comp.TimeElapsed = 0; + + //comp.Grid.Flags |= (EntityFlags)IsStealthedFlag; + + comp.Sink.Update(); + + var packet = new UpdateStatePacket { EntityId = comp.Block.EntityId, EnterStealth = true, Type = PacketType.UpdateState }; + if (IsServer) + SendPacketToClients(packet, comp.ReplicatedClients); + + comp.PrepGrids(true); + + if (!WcActive) comp.GetNearbyTurrets(); + + if (!IsDedicated) + { + if (IsClient) + SendPacketToServer(packet); + + if (!inside) + comp.SwitchStealth(true, true); + + comp.RefreshTerminal(); + + } + + } + else if (comp.ExitStealth) + { + exit = true; + Logs.WriteLine($"Exiting stealth: {comp.IsPrimary} {comp.Online} {gridComp.Revealed} {gridComp.WaterValid} {TrackDamage && gridComp.DamageTaken > DamageThreshold}" + + $" {comp.SufficientPower} {comp.TimeElapsed} / {comp.TotalTime}"); + + comp.ExitStealth = false; + comp.StealthActive = false; + comp.IgnorePower = false; + + comp.CoolingDown = true; + //comp.RemainingDuration = comp.MaxDuration - comp.RemainingDuration; + //comp.TotalTime = comp.TimeElapsed; + //comp.TimeElapsed = 0; + + //comp.Grid.Flags ^= (EntityFlags)IsStealthedFlag; + + comp.Sink.Update(); + + var packet = new UpdateStatePacket { EntityId = comp.Block.EntityId, ExitStealth = true, Type = PacketType.UpdateState }; + if (IsServer) + SendPacketToClients(packet, comp.ReplicatedClients); + + comp.PrepGrids(false); + + foreach (var entity in comp.PreviousEntities) + { + if (!IsDedicated) + { + if (entity is IMyCubeGrid) + comp.StealthExternalGrid(false, entity as IMyCubeGrid); + else + entity.Render.Visible = true; + } + + entity.Flags ^= StealthFlag; + } + + if (!IsDedicated) + { + if (IsClient) + SendPacketToServer(packet); + + if (!comp.VisibleToClient) + comp.SwitchStealth(false, true); + + comp.RefreshTerminal(); + + if (Vector3D.DistanceSquared(position, comp.Block.PositionComp.WorldAABB.Center) < comp.SignalDistanceSquared) + comp.CreateHeatSignature(); + } + + } + else + { + if (comp.StealthOnInit) + { + if (!WcActive) comp.GetNearbyTurrets(); + comp.PrepGrids(true); + comp.StealthOnInit = false; + } + + if (!IsDedicated && (comp.StealthOnInit || inside != comp.VisibleToClient)) + { + comp.SwitchStealth(!inside); + comp.Fading = false; + } + + MyGamePruningStructure.GetAllEntitiesInOBB(ref comp.ExpandedOBB, _entities); + + for (int k = 0; k < _entities.Count; k++) + { + MyEntity entity = _entities[k]; + if (!(entity is IMyDestroyableObject || entity is IMyCubeGrid)) + continue; + + if (entity is IMyCubeGrid) + { + var grid = (IMyCubeGrid)entity; + if (StealthedGrids.Contains(grid)) continue; + + var obb = new MyOrientedBoundingBoxD(grid.PositionComp.LocalAABB, grid.PositionComp.WorldMatrixRef); + if (comp.ExpandedOBB.Contains(ref obb) != ContainmentType.Contains) continue; + + + if (!IsDedicated && inside == comp.StealthedExternalGrids.Contains(grid)) + comp.StealthExternalGrid(!inside, grid); + } + else if (!IsDedicated) entity.Render.Visible = inside; + + comp.CurrentEntities.Add(entity); + + if (comp.PreviousEntities.Remove(entity)) + continue; + + entity.Flags |= StealthFlag; + } + _entities.Clear(); + + foreach (var entity in comp.PreviousEntities) + { + var grid = entity as IMyCubeGrid; + if (grid != null && gridComp.GroupMap.ConnectedGrids.Contains(grid)) + { + comp.StealthedExternalGrids.Remove(grid); + continue; + } + + if (!IsDedicated) + { + if (grid != null) + comp.StealthExternalGrid(false, grid); + else + entity.Render.Visible = true; + } + entity.Flags ^= StealthFlag; + } + + comp.PreviousEntities = new HashSet(comp.CurrentEntities); + comp.CurrentEntities.Clear(); + } + } + } + + } + catch (Exception ex) + { + Logs.WriteLine($"Exception in stealth comp loop: {ex}"); + } + + + if (Tick20) + { + if (master != null) + master.MaxDuration = master.Definition.Duration + gridComp.SinkBonus; + + gridComp.SinkBonus = 0; + } + + if (gridComp.HeatComps.Count == 0) continue; + + try + { + for (int j = 0; j < gridComp.HeatComps.Count; j++) + { + var comp = gridComp.HeatComps[j]; + + if (comp.Grid != comp.Block.CubeGrid) + { + comp.GridChange(gridComp); + j--; + // Deal with conditionals? + continue; + } + + if (enter) + { + comp.Accumulating = true; + } + else if (exit) + { + comp.Accumulating = false; + comp.Radiating = true; + comp.Block.SetEmissiveParts(RADIANT_EMISSIVE, Color.DarkRed, 0.5f); + } + else if (cold) + { + comp.Radiating = false; + comp.Block.SetEmissiveParts(RADIANT_EMISSIVE, Color.DarkSlateGray, 0.1f); + comp.HeatPercent = 0; + } + + //DrawBox(comp.DamageBox, Color.OrangeRed); + + //foreach (var box in comp.BlockBoxes) + // DrawBox(box, Color.Red); + + if (TickMod20 != comp.CompTick) + continue; + + comp.UpdateStatus(); + if (!IsDedicated && LastTerminal == comp.Block && MyAPIGateway.Gui.GetCurrentScreen == MyTerminalPageEnum.ControlPanel) + RefreshTerminal(comp.Block, comp.ShowInToolbarSwitch); + + if (comp.WorkingChanged && master != null) + { + if (master.StealthActive) + { + var timeChange = comp.Working ? comp.Definition.Duration : -comp.Definition.Duration; + master.TotalTime += timeChange; + + comp.Accumulating = comp.Working; + } + comp.WorkingChanged = false; + } + + if (comp.Working) + { + if (comp.Accumulating) + { + //comp.HeatPercent = (byte)(100 * (1 - (master.RemainingDuration / (float)_duration))); + comp.HeatPercent = (byte)(100f * (float)master.TimeElapsed / (float)master.TotalTime); + } + else if (comp.Radiating) + { + //comp.HeatPercent = (byte)(100 * (master.RemainingDuration / (float)_duration)); + comp.HeatPercent = (byte)(100f * ((float)master.TimeElapsed / (float)master.TotalTime)); + if (!IsClient && comp.Definition.DoDamage) comp.DamageBlocks(); + } + + gridComp.SinkBonus += comp.Definition.Duration; + + //if (master != null) + //master.MaxDuration += SinkDuration; + + } + else + { + if (comp.Accumulating) + { + comp.Accumulating = false; + comp.WasAccumulating = true; + //master.RemainingDuration -= SinkDuration * (100 - comp.HeatPercent) / 100; + } + + if (comp.HeatPercent > 0) + { + var loss = (byte)(100 / (comp.Definition.Duration / 20f)); + if (loss >= comp.HeatPercent) + comp.HeatPercent = 0; + else + comp.HeatPercent -= loss; + + if (!IsClient && comp.Definition.DoDamage) comp.DamageBlocks(); + //do heat signature + } + } + } + + } + catch (Exception ex) + { + Logs.WriteLine($"Exception in heat comp loop: {ex}"); + } + + } + + } + + internal void StartComps() + { + try + { + _startGrids.ApplyAdditions(); + if (_startGrids.Count > 0) + { + for (int i = 0; i < _startGrids.Count; i++) + { + var grid = _startGrids[i]; + + if ((grid as MyCubeGrid).IsPreview) + continue; + + var gridComp = _gridCompPool.Count > 0 ? _gridCompPool.Pop() : new GridComp(); + gridComp.Init(grid, this); + + GridList.Add(gridComp); + GridMap[grid] = gridComp; + grid.OnClose += OnGridClose; + } + _startGrids.ClearImmediate(); + } + + _startBlocks.ApplyAdditions(); + for (int i = 0; i < _startBlocks.Count; i++) + { + var module = _startBlocks[i]; + + if (module?.CubeGrid == null || !GridMap.ContainsKey(module.CubeGrid)) + continue; + + if (module.CubeGrid.Physics == null || (module.CubeGrid as MyCubeGrid).IsPreview) + { + Logs.WriteLine($"invalid grid in startblocks - IsPreview {(module.CubeGrid as MyCubeGrid).IsPreview} - physics null {module.CubeGrid.Physics == null}"); + continue; + } + + var gridData = GridMap[module.CubeGrid]; + + Definitions.DriveDefinition dDef; + if (DriveDefinitions.TryGetValue(module.BlockDefinition.SubtypeName, out dDef)) + { + if (DriveMap.ContainsKey(module.EntityId)) continue; + + var comp = new DriveComp(module, dDef, this); + DriveMap[module.EntityId] = comp; + gridData.StealthComps.Add(comp); + comp.Init(); + + continue; + } + + Definitions.SinkDefinition sDef; + if (SinkDefinitions.TryGetValue(module.BlockDefinition.SubtypeName, out sDef)) + { + var comp = new SinkComp(module, sDef, this); + gridData.HeatComps.Add(comp); + comp.Init(); + } + } + _startBlocks.ClearImmediate(); + } + catch (Exception ex) + { + Logs.WriteLine($"Exception in StartComps: {ex}"); + } + + } + } +} diff --git a/Utility Mods/Stealth Drive - Starcore Edition/Data/Scripts/Stealth System/Session/SessionMethods.cs b/Utility Mods/Stealth Drive - Starcore Edition/Data/Scripts/Stealth System/Session/SessionMethods.cs new file mode 100644 index 000000000..8af8f4121 --- /dev/null +++ b/Utility Mods/Stealth Drive - Starcore Edition/Data/Scripts/Stealth System/Session/SessionMethods.cs @@ -0,0 +1,205 @@ +using Sandbox.Definitions; +using Sandbox.ModAPI; +using VRage.Game; +using VRage.Game.ModAPI; +using VRage.ModAPI; +using VRageMath; +using VRage.Utils; +using System.Collections.Generic; +using Sandbox.ModAPI.Interfaces.Terminal; +using Jakaria.API; +using System; +using Sandbox.Game.Entities; +using Sandbox.Common.ObjectBuilders; + +namespace StealthSystem +{ + public partial class StealthSession + { + private void Init() + { + if (Inited) return; + Inited = true; + + MyAPIGateway.GridGroups.OnGridGroupCreated += GridGroupsOnOnGridGroupCreated; + MyAPIGateway.GridGroups.OnGridGroupDestroyed += GridGroupsOnOnGridGroupDestroyed; + } + + internal void ModCheck() + { + foreach (var mod in Session.Mods) + { + if (mod.PublishedFileId == 1918681825 || mod.PublishedFileId == 2496225055 || mod.PublishedFileId == 2726343161) + WcActive = true; + + else if (mod.Name == "WeaponCore" || mod.Name == "CoreSystems") + WcActive = true; + + else if (mod.PublishedFileId == 2200451495) + WaterMod = true; + + else if (mod.PublishedFileId == 1354870812) + RecolourableThrust = true; + + } + } + + internal bool PlayerInit() + { + try + { + //if (MyAPIGateway.Session.LocalHumanPlayer == null) + // return false; + + List players = new List(); + MyAPIGateway.Multiplayer.Players.GetPlayers(players); + + for (int i = 0; i < players.Count; i++) + PlayerConnected(players[i].IdentityId); + + return true; + } + catch (Exception ex) + { + Logs.WriteLine($"Caught exception in PlayerInit() - {ex}"); + } + + return false; + } + + internal void UpdateWaters() + { + if (IsClient && PlayersLoaded && MyAPIGateway.Session.Player?.Character != null) + { + var character = MyAPIGateway.Session.Player.Character.PositionComp.WorldAABB.Center; + var closestPlanet = MyGamePruningStructure.GetClosestPlanet(character); + if (closestPlanet.EntityId != 0 && !PlanetMap.ContainsKey(closestPlanet.EntityId)) + PlanetTemp.TryAdd(closestPlanet, closestPlanet.EntityId); + } + + if (!PlanetTemp.IsEmpty) + { + foreach (var planetToAdd in PlanetTemp) + { + if (planetToAdd.Key.EntityId != 0) + PlanetMap.TryAdd(planetToAdd.Key.EntityId, planetToAdd.Key); + } + + PlanetTemp.Clear(); + } + + foreach (var planet in PlanetMap.Values) + { + WaterData data; + if (WaterModAPI.HasWater(planet)) + { + if (!WaterMap.TryGetValue(planet.EntityId, out data)) + { + data = new WaterData(planet); + WaterMap[planet.EntityId] = data; + } + + var radiusInfo = WaterModAPI.GetPhysical(planet); + data.Centre = radiusInfo.Item1; + data.Radius = radiusInfo.Item2; + } + else WaterMap.TryRemove(planet.EntityId, out data); + } + } + + internal void UpdateEnforcement(StealthSettings settings) + { + Enforced = true; + Logs.WriteLine($"Config settings loaded"); + + JumpPenalty = settings.JumpPenalty; + Transparency = settings.Transparency; + ShieldDelay = settings.ShieldDelay; + FadeTime = settings.FadeTime; + DamageThreshold = settings.DamageThreshold; + DisableShields = settings.DisableShields; + DisableWeapons = settings.DisableWeapons; + HideThrusterFlames = settings.HideThrusterFlames; + WorkInWater = settings.WorkInWater; + WorkOutOfWater = settings.WorkOutOfWater; + WaterTransitionDepth = settings.WaterTransitionDepth; + RevealOnDamage = settings.RevealOnDamage; + + WaterOffsetSqr = WaterTransitionDepth * Math.Abs(WaterTransitionDepth); + TrackWater = WaterMod && WorkInWater != WorkOutOfWater; + TrackDamage = DamageThreshold > 0; + + FadeSteps = FadeTime / FADE_INTERVAL + 1; + + foreach (var drive in settings.DriveConfigs) + { + var def = new Definitions.DriveDefinition(drive.Duration, drive.PowerScale, drive.SignalRangeScale); + DriveDefinitions[drive.Subtype] = def; + } + + foreach (var sink in settings.SinkConfigs) + { + var def = new Definitions.SinkDefinition(sink.Duration, sink.Power, sink.DoDamage); + SinkDefinitions[sink.Subtype] = def; + } + + StealthFlag = (EntityFlags)(DisableWeapons ? IsStealthedFlag + 4 : IsStealthedFlag); + } + + internal void RemoveEdges() + { + var defs = MyDefinitionManager.Static.GetAllDefinitions(); + foreach (var def in defs) + { + if (def is MyCubeBlockDefinition && def.Id.SubtypeName.Contains("Armor")) + { + var armorDef = (MyCubeBlockDefinition)def; + if (armorDef.CubeDefinition == null) + continue; + + armorDef.CubeDefinition.ShowEdges = false; + } + } + } + + internal void RefreshTerminal(IMyFunctionalBlock block, IMyTerminalControlOnOffSwitch control) + { + block.RefreshCustomInfo(); + + if (control != null) + { + var originalSetting = control.Getter(block); + control.Setter(block, !originalSetting); + control.Setter(block, originalSetting); + } + } + + internal static void DrawBox(MyOrientedBoundingBoxD obb, Color color) + { + var box = new BoundingBoxD(-obb.HalfExtent, obb.HalfExtent); + var wm = MatrixD.CreateFromTransformScale(obb.Orientation, obb.Center, Vector3D.One); + var material = MyStringId.GetOrCompute("Square"); + MySimpleObjectDraw.DrawTransparentBox(ref wm, ref box, ref color, MySimpleObjectRasterizer.Wireframe, 1, 0.01f, null, material); + } + + internal static void DrawScaledPoint(Vector3D pos, double radius, Color color, int divideRatio = 20, bool solid = true, float lineWidth = 0.5f) + { + var posMatCenterScaled = MatrixD.CreateTranslation(pos); + var posMatScaler = MatrixD.Rescale(posMatCenterScaled, radius); + var material = MyStringId.GetOrCompute("Square"); + MySimpleObjectDraw.DrawTransparentSphere(ref posMatScaler, 1f, ref color, solid ? MySimpleObjectRasterizer.Solid : MySimpleObjectRasterizer.Wireframe, divideRatio, null, material, lineWidth); + } + + internal static void DrawLine(Vector3D start, Vector3D end, Vector4 color, float width) + { + var c = color; + MySimpleObjectDraw.DrawLine(start, end, _square, ref c, width); + } + + internal static void DrawLine(Vector3D start, Vector3D dir, Vector4 color, float width, float length) + { + var c = color; + MySimpleObjectDraw.DrawLine(start, start + (dir * length), _square, ref c, width); + } + } +} diff --git a/Utility Mods/Stealth Drive - Starcore Edition/Data/Scripts/Stealth System/Session/SessionNetwork.cs b/Utility Mods/Stealth Drive - Starcore Edition/Data/Scripts/Stealth System/Session/SessionNetwork.cs new file mode 100644 index 000000000..086091a16 --- /dev/null +++ b/Utility Mods/Stealth Drive - Starcore Edition/Data/Scripts/Stealth System/Session/SessionNetwork.cs @@ -0,0 +1,126 @@ +using ProtoBuf; +using Sandbox.ModAPI; +using System; +using System.Collections.Generic; + +namespace StealthSystem +{ + public partial class StealthSession + { + internal const ushort ServerPacketId = 65347; + internal const ushort ClientPacketId = 65348; + + public static void SendPacketToServer(Packet packet) + { + var rawData = MyAPIGateway.Utilities.SerializeToBinary(packet); + MyModAPIHelper.MyMultiplayer.Static.SendMessageToServer(ServerPacketId, rawData, true); + } + + public static void SendPacketToClient(Packet packet, ulong client) + { + var rawData = MyAPIGateway.Utilities.SerializeToBinary(packet); + MyModAPIHelper.MyMultiplayer.Static.SendMessageTo(ClientPacketId, rawData, client, true); + } + + public static void SendPacketToClients(Packet packet, List clients) + { + var rawData = MyAPIGateway.Utilities.SerializeToBinary(packet); + + foreach (var client in clients) + MyModAPIHelper.MyMultiplayer.Static.SendMessageTo(ClientPacketId, rawData, client, true); + } + + internal void ProcessPacket(ushort id, byte[] rawData, ulong sender, bool reliable) + { + try + { + var packet = MyAPIGateway.Utilities.SerializeFromBinary(rawData); + if (packet == null || packet.EntityId != 0 && !DriveMap.ContainsKey(packet.EntityId)) + { + Logs.WriteLine($"Invalid packet - null:{packet == null}"); + return; + } + + var comp = packet.EntityId == 0 ? null : DriveMap[packet.EntityId]; + switch (packet.Type) + { + case PacketType.UpdateState: + var uPacket = packet as UpdateStatePacket; + comp.EnterStealth = uPacket.EnterStealth && !comp.StealthActive; + comp.ExitStealth = uPacket.ExitStealth && comp.StealthActive; + break; + case PacketType.UpdateDuration: + var dPacket = packet as UpdateDurationPacket; + //comp.RemainingDuration += dPacket.DurationChange; + comp.TotalTime += dPacket.DurationChange; + break; + case PacketType.Replicate: + var rPacket = packet as ReplicationPacket; + if (rPacket.Fresh) + comp.ReplicatedClients.Add(sender); + else + comp.ReplicatedClients.Remove(sender); + break; + case PacketType.Settings: + var sPacket = packet as SettingsPacket; + UpdateEnforcement(sPacket.Settings); + break; + default: + Logs.WriteLine($"Invalid packet type - {packet.GetType()}"); + break; + } + } + catch (Exception ex) + { + Logs.WriteLine($"Exception in ProcessPacket: {ex}"); + } + + } + + } + + [ProtoContract] + [ProtoInclude(4, typeof(UpdateStatePacket))] + [ProtoInclude(5, typeof(UpdateDurationPacket))] + [ProtoInclude(6, typeof(ReplicationPacket))] + [ProtoInclude(7, typeof(SettingsPacket))] + public class Packet + { + [ProtoMember(1)] internal long EntityId; + [ProtoMember(2)] internal PacketType Type; + } + + [ProtoContract] + public class UpdateStatePacket : Packet + { + [ProtoMember(1)] internal bool EnterStealth; + [ProtoMember(2)] internal bool ExitStealth; + } + + [ProtoContract] + public class UpdateDurationPacket : Packet + { + [ProtoMember(1)] internal int DurationChange; + } + + [ProtoContract] + public class ReplicationPacket : Packet + { + [ProtoMember(1)] internal bool Fresh; + } + + [ProtoContract] + public class SettingsPacket : Packet + { + [ProtoMember(1)] internal StealthSettings Settings; + } + + public enum PacketType + { + UpdateState, + UpdateDuration, + Replicate, + Settings + } + +} diff --git a/Utility Mods/Stealth Drive - Starcore Edition/Data/Scripts/Stealth System/Session/SessionRun.cs b/Utility Mods/Stealth Drive - Starcore Edition/Data/Scripts/Stealth System/Session/SessionRun.cs new file mode 100644 index 000000000..59e9ba63f --- /dev/null +++ b/Utility Mods/Stealth Drive - Starcore Edition/Data/Scripts/Stealth System/Session/SessionRun.cs @@ -0,0 +1,130 @@ +using Sandbox.ModAPI; +using VRage.Game.Components; +using VRageMath; +using Sandbox.Game.Entities; +using Sandbox.Game; +using VRage.Game; + +namespace StealthSystem +{ + [MySessionComponentDescriptor(MyUpdateOrder.AfterSimulation)] + public partial class StealthSession : MySessionComponentBase + { + internal static int Tick; + internal int TickMod15; + internal int TickMod20; + internal int TickMod60; + internal bool Tick10; + internal bool Tick20; + internal bool Tick60; + internal bool Tick120; + internal bool Tick600; + internal bool Tick3600; + internal bool IsServer; + internal bool IsClient; + internal bool IsDedicated; + internal bool PlayersLoaded; + + public override void LoadData() + { + IsServer = MyAPIGateway.Multiplayer.MultiplayerActive && MyAPIGateway.Session.IsServer; + IsClient = MyAPIGateway.Multiplayer.MultiplayerActive && !MyAPIGateway.Session.IsServer; + IsDedicated = MyAPIGateway.Utilities.IsDedicated; + + LargeBox = new BoundingBoxD(-_large, _large); + SmallBox = new BoundingBoxD(-_small, _small); + + Logs.InitLogs(); + + ModPath = ModContext.ModPath; + ModCheck(); + + //RemoveEdges(); + CreateTerminalControls(); + + MyEntities.OnEntityCreate += OnEntityCreate; + //MyEntities.OnEntityDelete += OnEntityDelete; + MyEntities.OnCloseAll += OnCloseAll; + MyAPIGateway.TerminalControls.CustomControlGetter += CustomControlGetter; + MyAPIGateway.TerminalControls.CustomActionGetter += CustomActionGetter; + } + + public override void BeforeStart() + { + if (IsClient) + MyAPIGateway.Multiplayer.RegisterSecureMessageHandler(ClientPacketId, ProcessPacket); + else if (IsServer) + { + MyAPIGateway.Multiplayer.RegisterSecureMessageHandler(ServerPacketId, ProcessPacket); + MyVisualScriptLogicProvider.PlayerRespawnRequest += PlayerConnected; + } + + if (!IsClient) + MyAPIGateway.Session.DamageSystem.RegisterAfterDamageHandler(0, AfterDamageApplied); + + ConfigSettings = new Settings(this); + + APIServer.Load(); + + if (WaterMod) + WaterAPI.Register(); + } + + public override void UpdateAfterSimulation() + { + Tick++; + + TickMod15 = Tick % 15; + TickMod20 = Tick % 20; + TickMod60 = Tick % 60; + + Tick10 = Tick % 10 == 0; + Tick20 = TickMod20 == 0; + Tick60 = TickMod60 == 0; + Tick120 = Tick % 120 == 0; + Tick600 = Tick % 600 == 0; + Tick3600 = Tick % 3600 == 0; + + if (!PlayersLoaded && IsServer && PlayerInit()) + PlayersLoaded = true; + + if (TrackWater && (Tick3600 || Tick60 && WaterMap.IsEmpty)) + UpdateWaters(); + + if (Enforced && (!_startBlocks.IsEmpty || !_startGrids.IsEmpty)) + StartComps(); + + CompLoop(); + } + + protected override void UnloadData() + { + if (IsClient) + MyAPIGateway.Multiplayer.UnregisterSecureMessageHandler(ClientPacketId, ProcessPacket); + else if (IsServer) + { + MyAPIGateway.Multiplayer.UnregisterSecureMessageHandler(ServerPacketId, ProcessPacket); + MyVisualScriptLogicProvider.PlayerRespawnRequest -= PlayerConnected; + } + + MyEntities.OnEntityCreate -= OnEntityCreate; + MyEntities.OnCloseAll -= OnCloseAll; + + MyAPIGateway.TerminalControls.CustomControlGetter -= CustomControlGetter; + MyAPIGateway.TerminalControls.CustomActionGetter -= CustomActionGetter; + + Logs.Close(); + APIServer.Unload(); + if (WaterMod) + WaterAPI.Unregister(); + + Clean(); + } + + public override MyObjectBuilder_SessionComponent GetObjectBuilder() + { + return base.GetObjectBuilder(); + } + + } +} diff --git a/Utility Mods/Stealth Drive - Starcore Edition/Data/Scripts/Stealth System/Support/WaterModAPI.cs b/Utility Mods/Stealth Drive - Starcore Edition/Data/Scripts/Stealth System/Support/WaterModAPI.cs new file mode 100644 index 000000000..34ba4ba3e --- /dev/null +++ b/Utility Mods/Stealth Drive - Starcore Edition/Data/Scripts/Stealth System/Support/WaterModAPI.cs @@ -0,0 +1,281 @@ +using Sandbox.Game.Entities; +using Sandbox.ModAPI; +using System; +using System.Collections.Generic; +using VRage; +using VRage.Game; +using VRage.Game.Components; +using VRage.Utils; +using VRageMath; + +namespace Jakaria.API +{ + //See the steam guide for how to use this + //https://steamcommunity.com/sharedfiles/filedetails/?id=2639207010 + /// + /// https://github.com/jakarianstudios/SE-Water/blob/master/API/WaterModAPI.cs + /// + + [MySessionComponentDescriptor(MyUpdateOrder.NoUpdate)] + public class WaterModAPI : MySessionComponentBase + { + public static string ModName = ""; + public const ushort ModHandlerID = 50271; + public const int ModAPIVersion = 19; + public static bool Registered { get; private set; } = false; + + private static Dictionary ModAPIMethods; + + private static Func _VerifyVersion; + + private static Func _IsUnderwater; + private static Func _LineIntersectsWater; + private static Action, ICollection, MyPlanet> _LineIntersectsWaterList; + private static Func _GetClosestWater; + private static Func _SphereIntersectsWater; + private static Action, ICollection, MyPlanet> _SphereIntersectsWaterList; + private static Func _GetClosestSurfacePoint; + private static Action, ICollection, MyPlanet> _GetClosestSurfacePointList; + private static Func _GetDepth; + private static Action _ForceSync; + private static Action _RunCommand; + private static Func _GetUpDirection; + private static Func _HasWater; + private static Func _GetBuoyancyMultiplier; + private static Func _GetCrushDepth; + + private static Func> _GetPhysicalData; + private static Func> _GetWaveData; + private static Func> _GetRenderData; + private static Func> _GetPhysicsData; + private static Func> _GetTideData; + private static Func _GetTideDirection; + + private static Action _CreateSplash; + private static Action _CreateBubble; + private static Action _CreatePhysicsSplash; + + /// + /// Returns true if the version is compatibile with the API Backend, this is automatically called + /// + public static bool VerifyVersion(int Version, string ModName) => _VerifyVersion?.Invoke(Version, ModName) ?? false; + + /// + /// Returns true if the provided planet entity ID has water + /// + public static bool HasWater(MyPlanet planet) => _HasWater?.Invoke(planet) ?? false; + + /// + /// Returns true if the position is underwater + /// + public static bool IsUnderwater(Vector3D Position, MyPlanet ID = null) => _IsUnderwater?.Invoke(Position, ID) ?? false; + + /// + /// Overwater = 0, ExitsWater = 1, EntersWater = 2, Underwater = 3 + /// + public static int LineIntersectsWater(LineD Line, MyPlanet ID = null) => _LineIntersectsWater?.Invoke(Line, ID) ?? 0; + + /// + /// Overwater = 0, ExitsWater = 1, EntersWater = 2, Underwater = 3 + /// + public static void LineIntersectsWater(List Lines, ICollection Intersections, MyPlanet ID = null) => _LineIntersectsWaterList?.Invoke(Lines, Intersections, ID); + + /// + /// Gets the closest water to the provided water + /// + public static MyPlanet GetClosestWater(Vector3D Position) => _GetClosestWater?.Invoke(Position) ?? null; + + /// + /// Overwater = 0, ExitsWater = 1, EntersWater = 2, Underwater = 3 + /// + public static int SphereIntersectsWater(BoundingSphereD Sphere, MyPlanet ID = null) => _SphereIntersectsWater?.Invoke(Sphere, ID) ?? 0; + + /// + /// Overwater = 0, ExitsWater = 1, EntersWater = 2, Underwater = 3 + /// + public static void SphereIntersectsWater(List Spheres, ICollection Intersections, MyPlanet ID = null) => _SphereIntersectsWaterList?.Invoke(Spheres, Intersections, ID); + + + /// + /// Returns the closest position on the water surface + /// + public static Vector3D GetClosestSurfacePoint(Vector3D Position, MyPlanet ID = null) => _GetClosestSurfacePoint?.Invoke(Position, ID) ?? Position; + + /// + /// Returns the closest position on the water surface + /// + public static void GetClosestSurfacePoint(List Positions, ICollection Points, MyPlanet ID = null) => _GetClosestSurfacePointList?.Invoke(Positions, Points, ID); + + + /// + /// Returns the depth the position is underwater + /// + public static float? GetDepth(Vector3D Position, MyPlanet ID = null) => _GetDepth?.Invoke(Position, ID) ?? null; + + /// + /// Creates a splash at the provided position + /// + public static void CreateSplash(Vector3D Position, float Radius, bool Audible) => _CreateSplash?.Invoke(Position, Radius, Audible); + + /// + /// Creates a physical splash at the provided position (Particles outside of the water) + /// + public static void CreatePhysicsSplash(Vector3D Position, Vector3D Velocity, float Radius, int Count = 1) => _CreatePhysicsSplash?.Invoke(Position, Velocity, Radius, Count); + + /// + /// Creates a bubble at the provided position + /// + public static void CreateBubble(Vector3D Position, float Radius) => _CreateBubble?.Invoke(Position, Radius); + + /// + /// Forces the server to sync with the client + /// + public static void ForceSync() => _ForceSync?.Invoke(); + + /// + /// Simulates a command being run by the client, EX: /wcreate, client must have permissions to run the command + /// + public static void RunCommand(string MessageText) => _RunCommand?.Invoke(MessageText); + + /// + /// Gets the up direction at the position + /// + public static Vector3D GetUpDirection(Vector3D Position, MyPlanet ID = null) => _GetUpDirection?.Invoke(Position, ID) ?? Vector3D.Up; + + /// + /// Gets the buoyancy multiplier to help calculate buoyancy of a grid, used in the final calculation of grid buoyancy. + /// + public static float GetBuoyancyMultiplier(Vector3D Position, MyCubeSize GridSize, MyPlanet ID = null) => _GetBuoyancyMultiplier?.Invoke(Position, GridSize, ID) ?? 0; + + /// + /// Gets crush damage + /// + [Obsolete] + public static float GetCrushDepth(MyPlanet planet) => _GetCrushDepth?.Invoke(planet) ?? 500; + + /// + /// Gets position, radius, minimum radius, and maximum radius- in that order. + /// + public static MyTuple GetPhysical(MyPlanet planet) => (MyTuple)(_GetPhysicalData?.Invoke(planet) ?? null); + + /// + /// Gets wave height, wave speed, wave scale, and seed- in that order. + /// + public static MyTuple GetWaveData(MyPlanet planet) => (MyTuple)(_GetWaveData?.Invoke(planet) ?? null); + + /// + /// Gets fog color, transparency toggle, and lighting toggle- in that order. + /// + public static MyTuple GetRenderData(MyPlanet planet) => (MyTuple)(_GetRenderData?.Invoke(planet) ?? null); + + /// + /// Gets tide height and tide speed- in that order. + /// + public static MyTuple GetTideData(MyPlanet planet) => (MyTuple)(_GetTideData?.Invoke(planet) ?? null); + + /// + /// Gets density and buoyancy multiplier- in that order. + /// + public static MyTuple GetPhysicsData(MyPlanet planet) => (MyTuple)(_GetPhysicsData?.Invoke(planet) ?? null); + + /// + /// Gets the direction of high tide, from center of the water to the surface + /// + public static Vector3D GetTideDirection(MyPlanet planet) => (Vector3D)(_GetTideDirection?.Invoke(planet) ?? null); + + /// + /// Do not use. This is for the session component to register automatically + /// + public override void LoadData() + { + Register(); + } + + /// + /// Do not use. This is for the session component to register automatically + /// + protected override void UnloadData() + { + Unregister(); + } + + /// + /// Registers the mod and sets the mod name if it is not already set + /// + public void Register() + { + MyAPIGateway.Utilities.RegisterMessageHandler(ModHandlerID, ModHandler); + + if (ModName == "") + { + if (MyAPIGateway.Utilities.GamePaths.ModScopeName.Contains("_")) + ModName = MyAPIGateway.Utilities.GamePaths.ModScopeName.Split('_')[1]; + else + ModName = MyAPIGateway.Utilities.GamePaths.ModScopeName; + } + } + + /// + /// Unregisters the mod + /// + public void Unregister() + { + MyAPIGateway.Utilities.UnregisterMessageHandler(ModHandlerID, ModHandler); + Registered = false; + } + + private void ModHandler(object obj) + { + if (obj == null) + { + return; + } + + if (obj is Dictionary) + { + ModAPIMethods = (Dictionary)obj; + _VerifyVersion = (Func)ModAPIMethods["VerifyVersion"]; + + Registered = VerifyVersion(ModAPIVersion, ModName); + + MyLog.Default.WriteLine("Registering WaterAPI for Mod '" + ModName + "'"); + + if (Registered) + { + try + { + _IsUnderwater = (Func)ModAPIMethods["IsUnderwater"]; + _GetClosestWater = (Func)ModAPIMethods["GetClosestWater"]; + _SphereIntersectsWater = (Func)ModAPIMethods["SphereIntersectsWater"]; + _SphereIntersectsWaterList = (Action, ICollection, MyPlanet>)ModAPIMethods["SphereIntersectsWaterList"]; + _GetClosestSurfacePoint = (Func)ModAPIMethods["GetClosestSurfacePoint"]; + _GetClosestSurfacePointList = (Action, ICollection, MyPlanet>)ModAPIMethods["GetClosestSurfacePointList"]; + _LineIntersectsWater = (Func)ModAPIMethods["LineIntersectsWater"]; + _LineIntersectsWaterList = (Action, ICollection, MyPlanet>)ModAPIMethods["LineIntersectsWaterList"]; + _GetDepth = (Func)ModAPIMethods["GetDepth"]; + _CreateSplash = (Action)ModAPIMethods["CreateSplash"]; + _CreatePhysicsSplash = (Action)ModAPIMethods["CreatePhysicsSplash"]; + _CreateBubble = (Action)ModAPIMethods["CreateBubble"]; + _ForceSync = (Action)ModAPIMethods["ForceSync"]; + _RunCommand = (Action)ModAPIMethods["RunCommand"]; + _GetUpDirection = (Func)ModAPIMethods["GetUpDirection"]; + _HasWater = (Func)ModAPIMethods["HasWater"]; + _GetBuoyancyMultiplier = (Func)ModAPIMethods["GetBuoyancyMultiplier"]; + _GetCrushDepth = (Func)ModAPIMethods["GetCrushDepth"]; + _GetPhysicalData = (Func>)ModAPIMethods["GetPhysicalData"]; + _GetWaveData = (Func>)ModAPIMethods["GetWaveData"]; + _GetRenderData = (Func>)ModAPIMethods["GetRenderData"]; + _GetPhysicsData = (Func>)ModAPIMethods["GetPhysicsData"]; + _GetTideData = (Func>)ModAPIMethods["GetTideData"]; + _GetTideDirection = (Func)ModAPIMethods["GetTideDirection"]; + } + catch (Exception e) + { + MyAPIGateway.Utilities.ShowMessage("WaterMod", "Mod '" + ModName + "' encountered an error when registering the Water Mod API, see log for more info."); + MyLog.Default.WriteLine("WaterMod: " + e); + } + } + } + } + } +} \ No newline at end of file diff --git a/Utility Mods/Stealth Drive - Starcore Edition/Data/Scripts/Stealth System/Utils/EmissiveValues.cs b/Utility Mods/Stealth Drive - Starcore Edition/Data/Scripts/Stealth System/Utils/EmissiveValues.cs new file mode 100644 index 000000000..d093238bf --- /dev/null +++ b/Utility Mods/Stealth Drive - Starcore Edition/Data/Scripts/Stealth System/Utils/EmissiveValues.cs @@ -0,0 +1,48 @@ +using Sandbox.ModAPI; +using VRage.Game.Components; +using VRageMath; + +namespace StealthSystem +{ + [MySessionComponentDescriptor(MyUpdateOrder.NoUpdate)] + public class EmissiveValues : MySessionComponentBase + { + internal static Color GREEN = new Color(0, 255, 0); + internal static Color RED = new Color(255, 0, 0); + + public override void BeforeStart() + { + if (MyAPIGateway.Utilities.IsDedicated) return; + + UpdateEmissiveValues(); + + } + + private void UpdateEmissiveValues() + { + bool aqdVisualsPresent = false; + bool emissiveColorsPresent = false; + + foreach (var mod in MyAPIGateway.Session.Mods) + { + if (mod.PublishedFileId == 2244563617) // AQD - Visuals + aqdVisualsPresent = true; + else if (mod.PublishedFileId == 2212516940) // Emissive Colors - Red / Green Color Vision Deficiency + emissiveColorsPresent = true; + + if (aqdVisualsPresent && emissiveColorsPresent) + break; + } + + if (aqdVisualsPresent) + { + RED = new Color(171, 42, 29); + GREEN = emissiveColorsPresent ? new Color(10, 255, 25) : new Color(60, 163, 33); + } + else if (emissiveColorsPresent) + { + GREEN = new Color(10, 255, 25); + } + } + } +} diff --git a/Utility Mods/Stealth Drive - Starcore Edition/Data/Scripts/Stealth System/Utils/Logs.cs b/Utility Mods/Stealth Drive - Starcore Edition/Data/Scripts/Stealth System/Utils/Logs.cs new file mode 100644 index 000000000..ee6246781 --- /dev/null +++ b/Utility Mods/Stealth Drive - Starcore Edition/Data/Scripts/Stealth System/Utils/Logs.cs @@ -0,0 +1,98 @@ +using Sandbox.ModAPI; +using System; +using System.IO; +using VRage.Game.ModAPI; + +namespace StealthSystem +{ + internal class Logs + { + internal const string LOG_PREFIX = "StealthMod_"; + internal const string LOG_SUFFIX = ".log"; + internal const int LOGS_TO_KEEP = 5; + + internal static TextWriter TextWriter; + + internal static void InitLogs() + { + int last = LOGS_TO_KEEP - 1; + string lastName = LOG_PREFIX + last + LOG_SUFFIX; + if (MyAPIGateway.Utilities.FileExistsInLocalStorage(lastName, typeof(Logs))) + MyAPIGateway.Utilities.DeleteFileInLocalStorage(lastName, typeof(Logs)); + + if (last > 0) + { + for (int i = last; i > 0; i--) + { + string oldName = LOG_PREFIX + (i - 1) + LOG_SUFFIX; + string newName = LOG_PREFIX + i + LOG_SUFFIX; + RenameFileInLocalStorage(oldName, newName, typeof(Logs)); + } + } + + string fileName = LOG_PREFIX + 0 + LOG_SUFFIX; + TextWriter = MyAPIGateway.Utilities.WriteFileInLocalStorage(fileName, typeof(Logs)); + + var message = $"{DateTime.Now:dd-MM-yy HH-mm-ss} - Logging Started"; + TextWriter.WriteLine(message); + TextWriter.WriteLine(" Tick - Log"); + TextWriter.Flush(); + + } + + internal static void RenameFileInLocalStorage(string oldName, string newName, Type anyObjectInYourMod) + { + if (!MyAPIGateway.Utilities.FileExistsInLocalStorage(oldName, anyObjectInYourMod)) + return; + + if (MyAPIGateway.Utilities.FileExistsInLocalStorage(newName, anyObjectInYourMod)) + return; + + using (var read = MyAPIGateway.Utilities.ReadFileInLocalStorage(oldName, anyObjectInYourMod)) + { + using (var write = MyAPIGateway.Utilities.WriteFileInLocalStorage(newName, anyObjectInYourMod)) + { + write.Write(read.ReadToEnd()); + write.Flush(); + write.Dispose(); + } + } + + MyAPIGateway.Utilities.DeleteFileInLocalStorage(oldName, anyObjectInYourMod); + } + + internal static void WriteLine(string text) + { + string line = $"{StealthSession.Tick,6} - " + text; + TextWriter.WriteLine(line); + TextWriter.Flush(); + } + + internal static void Close() + { + var message = $"{DateTime.Now:dd-MM-yy HH-mm-ss} - Logging Stopped"; + TextWriter.WriteLine(message); + + TextWriter.Flush(); + TextWriter.Close(); + TextWriter.Dispose(); + } + + internal static void CheckGrid() + { + if (MyAPIGateway.Session.LocalHumanPlayer?.Character == null) return; + + var from = MyAPIGateway.Session.LocalHumanPlayer.Character.PositionComp.WorldMatrixRef.Translation; + var to = from + MyAPIGateway.Session.LocalHumanPlayer.Character.PositionComp.WorldMatrixRef.Forward * 100; + IHitInfo info; + MyAPIGateway.Physics.CastRay(from, to, out info); + + if (info == null) return; + + var grid = info.HitEntity as IMyCubeGrid; + if (grid == null) return; + + Logs.WriteLine($"Grid: {grid.DisplayName} - has flag: {((uint)grid.Flags & StealthSession.IsStealthedFlag) > 0}"); + } + } +} diff --git a/Utility Mods/Stealth Drive - Starcore Edition/Data/Scripts/Stealth System/Utils/Settings.cs b/Utility Mods/Stealth Drive - Starcore Edition/Data/Scripts/Stealth System/Utils/Settings.cs new file mode 100644 index 000000000..5b414ee95 --- /dev/null +++ b/Utility Mods/Stealth Drive - Starcore Edition/Data/Scripts/Stealth System/Utils/Settings.cs @@ -0,0 +1,342 @@ +using ProtoBuf; +using Sandbox.ModAPI; +using System; +using System.Collections.Generic; +using System.IO; + +namespace StealthSystem +{ + internal class Settings + { + private readonly StealthSession _session; + + internal const string CONFIG_FILE = "StealthMod.cfg"; + internal const int CONFIG_VERSION = 8; + + internal StealthSettings Config; + + internal Settings(StealthSession session) + { + _session = session; + + LoadConfig(); + } + + private void LoadConfig() + { + try + { + if (MyAPIGateway.Utilities.FileExistsInWorldStorage(CONFIG_FILE, typeof(StealthSettings))) + { + + var writer = MyAPIGateway.Utilities.ReadFileInWorldStorage(CONFIG_FILE, typeof(StealthSettings)); + + StealthSettings xmlData = null; + + try { xmlData = MyAPIGateway.Utilities.SerializeFromXML(writer.ReadToEnd()); } + catch (Exception ex) + { + writer.Dispose(); + Logs.WriteLine($"Exception in SerializeFromXML: {ex}"); + } + + writer.Dispose(); + + if (xmlData?.Version == CONFIG_VERSION) + { + Logs.WriteLine($"Found up to date config file"); + + Config = xmlData; + CorruptionCheck(); + SaveConfig(); + } + else + { + var versionStr = xmlData != null ? xmlData.Version.ToString() : "null"; + Logs.WriteLine($"Found config file with version {versionStr} : updating to version {CONFIG_VERSION}"); + + GenerateConfig(xmlData); + } + } + else + { + Logs.WriteLine($"No config file found, generating..."); + + GenerateConfig(); + } + + _session.UpdateEnforcement(Config); + } + catch (Exception ex) + { + Logs.WriteLine($"Exception in LoadConfig: {ex}"); + } + } + + private void GenerateConfig(StealthSettings oldSettings = null) + { + + if (oldSettings != null) + { + RebuildConfig(oldSettings); + } + else + Config = new StealthSettings { Version = CONFIG_VERSION }; + + CorruptionCheck(); + SaveConfig(); + } + + private void RebuildConfig(StealthSettings oldSettings) + { + Config = new StealthSettings { Version = CONFIG_VERSION }; + + var fade = oldSettings.Version < 4; + var five = oldSettings.Version < 5; + var six = oldSettings.Version < 6; + var seven = oldSettings.Version < 7; + var eight = oldSettings.Version < 8; + + Config.FadeTime = fade ? 150 : oldSettings.FadeTime; + Config.ShieldDelay = five ? 300 : oldSettings.ShieldDelay; + Config.JumpPenalty = oldSettings.JumpPenalty; + Config.Transparency = oldSettings.Transparency; + Config.DisableShields = five ? true : oldSettings.DisableShields; + Config.DamageThreshold = oldSettings.DamageThreshold; + Config.DisableWeapons = six ? true : oldSettings.DisableWeapons; + Config.HideThrusterFlames = seven ? true : oldSettings.HideThrusterFlames; + Config.WorkInWater = eight ? true : oldSettings.WorkInWater; + Config.WorkOutOfWater = eight ? true : oldSettings.WorkOutOfWater; + Config.WaterTransitionDepth = eight ? 0f : oldSettings.WaterTransitionDepth; + + Config.DriveConfig = oldSettings.DriveConfig; + Config.SinkConfig = oldSettings.SinkConfig; + + Config.DriveConfigs = oldSettings.DriveConfigs; + Config.SinkConfigs = oldSettings.SinkConfigs; + + + } + + private void CorruptionCheck() + { + if (Config.FadeTime < 0) + { + Config.FadeTime = 210; + Logs.WriteLine($"Config error: FadeTime cannot be negative!"); + } + if (Config.ShieldDelay < 0) + { + Config.ShieldDelay = 300; + Logs.WriteLine($"Config error: ShieldDelay cannot be negative!"); + } + if (Config.JumpPenalty < 0) + { + Config.JumpPenalty = 180; + Logs.WriteLine($"Config error: JumpPenalty cannot be negative!"); + } + if (Config.Transparency <= 0) + { + Config.Transparency = 0.9f; + Logs.WriteLine($"Config error: Transparency must be greater than zero!"); + } + + if (Config.WorkInWater == false && Config.WorkOutOfWater == false) + { + Config.WorkInWater = Config.WorkOutOfWater = true; + Logs.WriteLine($"Config error: WorkInWater and WorkOutOfWater cannot both be false!"); + } + + if (Config.DriveConfigs == null || Config.DriveConfigs.Length == 0) + { + var oldDrive = Config.DriveConfig; + Config.DriveConfigs = new StealthSettings.DriveSettings[3] + { + new StealthSettings.DriveSettings(oldDrive) + { + Subtype = "StealthDrive", + }, + new StealthSettings.DriveSettings(oldDrive) + { + Subtype = "StealthDriveSmall", + }, + new StealthSettings.DriveSettings(oldDrive) + { + Subtype = "StealthDrive1x1", + Duration = 600, + }, + }; + Logs.WriteLine($"Config error: No Drive configs found, regenerating..."); + } + else + { + var drives = new List(); + for (int i = 0; i < Config.DriveConfigs.Length; i++) + { + var drive = Config.DriveConfigs[i]; + if (string.IsNullOrEmpty(drive.Subtype)) + { + Logs.WriteLine($"Drive config error: Invalid SubtypeId!"); + continue; + } + + if (drive.Duration <= 0) + { + drive.Duration = 1800; + Logs.WriteLine($"Drive config error ({drive.Subtype}): Duration must be greater than zero!"); + } + if (drive.PowerScale <= 0f) + { + drive.PowerScale = 0.02f; + Logs.WriteLine($"Drive config error ({drive.Subtype}): PowerScale must be greater than zero!"); + } + if (drive.SignalRangeScale <= 0f) + { + drive.SignalRangeScale = 20f; + Logs.WriteLine($"Drive config error ({drive.Subtype}): SignalRangeScale must be greater than zero!"); + } + + drives.Add(drive); + } + if (drives.Count > 0) + Config.DriveConfigs = drives.ToArray(); + } + + if (Config.SinkConfigs == null || Config.SinkConfigs.Length == 0) + { + var oldSink = Config.SinkConfig; + Config.SinkConfigs = new StealthSettings.SinkSettings[2] + { + new StealthSettings.SinkSettings(oldSink) + { + Subtype = "StealthHeatSink", + }, + new StealthSettings.SinkSettings(oldSink) + { + Subtype = "StealthHeatSinkSmall", + }, + }; + Logs.WriteLine($"Config error: No Heatsink configs found, regenerating..."); + } + else + { + var sinks = new List(); + for (int i = 0; i < Config.SinkConfigs.Length; i++) + { + var sink = Config.SinkConfigs[i]; + if (string.IsNullOrEmpty(sink.Subtype)) + { + Logs.WriteLine($"Heatsink config error: Invalid SubtypeId!"); + continue; + } + + if (sink.Duration <= 0) + { + sink.Duration = 900; + Logs.WriteLine($"Heatsink config error ({sink.Subtype}): Duration must be greater than zero!"); + } + if (sink.Power <= 0f) + { + sink.Power = 10f; + Logs.WriteLine($"Heatsink config error ({sink.Subtype}): Power must be greater than zero!"); + } + + sinks.Add(sink); + } + if (sinks.Count > 0) + Config.SinkConfigs = sinks.ToArray(); + } + + Config.DriveConfig = null; + Config.SinkConfig = null; + + } + + private void SaveConfig() + { + MyAPIGateway.Utilities.DeleteFileInWorldStorage(CONFIG_FILE, typeof(StealthSettings)); + var writer = MyAPIGateway.Utilities.WriteFileInWorldStorage(CONFIG_FILE, typeof(StealthSettings)); + var data = MyAPIGateway.Utilities.SerializeToXML(Config); + Write(writer, data); + } + + private static void Write(TextWriter writer, string data) + { + writer.Write(data); + writer.Flush(); + writer.Dispose(); + } + } + + [ProtoContract] + public class StealthSettings + { + [ProtoMember(1)] public int Version = -1; + [ProtoMember(2)] public int FadeTime = 210; + [ProtoMember(3)] public int ShieldDelay = 300; + [ProtoMember(4)] public int JumpPenalty = 180; + + [ProtoMember(7)] public float Transparency = 0.9f; + [ProtoMember(8)] public bool DisableShields = true; + [ProtoMember(9)] public int DamageThreshold = 1000; + [ProtoMember(10)] public bool DisableWeapons = true; + [ProtoMember(11)] public bool HideThrusterFlames = true; + [ProtoMember(12)] public bool WorkInWater = true; + [ProtoMember(13)] public bool WorkOutOfWater = true; + [ProtoMember(14)] public float WaterTransitionDepth = 0f; + [ProtoMember(15)] public bool RevealOnDamage = true; + + [ProtoMember(20)] public DriveSettings DriveConfig; + [ProtoMember(21)] public SinkSettings SinkConfig; + + [ProtoMember(30)] public DriveSettings[] DriveConfigs; + [ProtoMember(31)] public SinkSettings[] SinkConfigs; + + [ProtoContract] + public class DriveSettings + { + [ProtoMember(1)] public string Subtype; + [ProtoMember(2)] public int Duration = 1800; + [ProtoMember(3)] public float PowerScale = 0.02f; + [ProtoMember(4)] public float SignalRangeScale = 20f; + + public DriveSettings() + { + + } + + public DriveSettings(DriveSettings old) + { + if (old == null) return; + + Duration = old.Duration; + PowerScale = old.PowerScale; + SignalRangeScale = old.SignalRangeScale; + } + } + + [ProtoContract] + public class SinkSettings + { + [ProtoMember(1)] public string Subtype; + [ProtoMember(2)] public int Duration = 600; + [ProtoMember(3)] public float Power = 10f; + [ProtoMember(4)] public bool DoDamage = true; + + public SinkSettings() + { + + } + + public SinkSettings(SinkSettings old) + { + if (old == null) return; + + Duration = old.Duration; + Power = old.Power; + DoDamage = old.DoDamage; + } + } + + } +} diff --git a/Utility Mods/Stealth Drive - Starcore Edition/Models/AWE_Aegis/ARYX_TacticalModule.mwm b/Utility Mods/Stealth Drive - Starcore Edition/Models/AWE_Aegis/ARYX_TacticalModule.mwm new file mode 100644 index 000000000..1eedbbca2 Binary files /dev/null and b/Utility Mods/Stealth Drive - Starcore Edition/Models/AWE_Aegis/ARYX_TacticalModule.mwm differ diff --git a/Utility Mods/Stealth Drive - Starcore Edition/Models/AWE_Aegis/ARYX_TacticalModule.sbc b/Utility Mods/Stealth Drive - Starcore Edition/Models/AWE_Aegis/ARYX_TacticalModule.sbc new file mode 100644 index 000000000..05c215b6b --- /dev/null +++ b/Utility Mods/Stealth Drive - Starcore Edition/Models/AWE_Aegis/ARYX_TacticalModule.sbc @@ -0,0 +1,39 @@ + + + + + + CubeBlock + ARYX_TacticalModule + + DisplayName_ARYX_TacticalModule + Description_ARYX_TacticalModule + Textures\GUI\Icons\AstronautBackpack.dds + Large + TriangleMesh + + + Models\AWE_Aegis\ARYX_TacticalModule.mwm + + + + + + + + + + + + + + + + + + ARYX_TacticalModule + Z + Y + + + diff --git a/Utility Mods/Stealth Drive - Starcore Edition/Models/AWE_Aegis/ARYX_TacticalModule_BS1.mwm b/Utility Mods/Stealth Drive - Starcore Edition/Models/AWE_Aegis/ARYX_TacticalModule_BS1.mwm new file mode 100644 index 000000000..8eecf63c3 Binary files /dev/null and b/Utility Mods/Stealth Drive - Starcore Edition/Models/AWE_Aegis/ARYX_TacticalModule_BS1.mwm differ diff --git a/Utility Mods/Stealth Drive - Starcore Edition/Models/AWE_Aegis/ARYX_TacticalModule_BS2.mwm b/Utility Mods/Stealth Drive - Starcore Edition/Models/AWE_Aegis/ARYX_TacticalModule_BS2.mwm new file mode 100644 index 000000000..31a0d40a8 Binary files /dev/null and b/Utility Mods/Stealth Drive - Starcore Edition/Models/AWE_Aegis/ARYX_TacticalModule_BS2.mwm differ diff --git a/Utility Mods/Stealth Drive - Starcore Edition/Models/AWE_Aegis/ARYX_TacticalModule_BS3.mwm b/Utility Mods/Stealth Drive - Starcore Edition/Models/AWE_Aegis/ARYX_TacticalModule_BS3.mwm new file mode 100644 index 000000000..79b719a64 Binary files /dev/null and b/Utility Mods/Stealth Drive - Starcore Edition/Models/AWE_Aegis/ARYX_TacticalModule_BS3.mwm differ diff --git a/Utility Mods/Stealth Drive - Starcore Edition/Models/AWE_Aegis/ARYX_TacticalModule_LOD1.mwm b/Utility Mods/Stealth Drive - Starcore Edition/Models/AWE_Aegis/ARYX_TacticalModule_LOD1.mwm new file mode 100644 index 000000000..e5c9f5ccc Binary files /dev/null and b/Utility Mods/Stealth Drive - Starcore Edition/Models/AWE_Aegis/ARYX_TacticalModule_LOD1.mwm differ diff --git a/Utility Mods/Stealth Drive - Starcore Edition/Models/AWE_Aegis/ARYX_TacticalModule_LOD2.mwm b/Utility Mods/Stealth Drive - Starcore Edition/Models/AWE_Aegis/ARYX_TacticalModule_LOD2.mwm new file mode 100644 index 000000000..a30694882 Binary files /dev/null and b/Utility Mods/Stealth Drive - Starcore Edition/Models/AWE_Aegis/ARYX_TacticalModule_LOD2.mwm differ diff --git a/Utility Mods/Stealth Drive - Starcore Edition/Models/AWE_Aegis/ARYX_TacticalModule_LOD3.mwm b/Utility Mods/Stealth Drive - Starcore Edition/Models/AWE_Aegis/ARYX_TacticalModule_LOD3.mwm new file mode 100644 index 000000000..eaea06c2f Binary files /dev/null and b/Utility Mods/Stealth Drive - Starcore Edition/Models/AWE_Aegis/ARYX_TacticalModule_LOD3.mwm differ diff --git a/Utility Mods/Stealth Drive - Starcore Edition/Models/Cubes/large/StealthDrive1x1.mwm b/Utility Mods/Stealth Drive - Starcore Edition/Models/Cubes/large/StealthDrive1x1.mwm new file mode 100644 index 000000000..2cb1cc92e Binary files /dev/null and b/Utility Mods/Stealth Drive - Starcore Edition/Models/Cubes/large/StealthDrive1x1.mwm differ diff --git a/Utility Mods/Stealth Drive - Starcore Edition/Models/Cubes/large/StealthDrive1x1_BS1.mwm b/Utility Mods/Stealth Drive - Starcore Edition/Models/Cubes/large/StealthDrive1x1_BS1.mwm new file mode 100644 index 000000000..a66247ddf Binary files /dev/null and b/Utility Mods/Stealth Drive - Starcore Edition/Models/Cubes/large/StealthDrive1x1_BS1.mwm differ diff --git a/Utility Mods/Stealth Drive - Starcore Edition/Models/Cubes/large/StealthDrive1x1_BS2.mwm b/Utility Mods/Stealth Drive - Starcore Edition/Models/Cubes/large/StealthDrive1x1_BS2.mwm new file mode 100644 index 000000000..979bc9195 Binary files /dev/null and b/Utility Mods/Stealth Drive - Starcore Edition/Models/Cubes/large/StealthDrive1x1_BS2.mwm differ diff --git a/Utility Mods/Stealth Drive - Starcore Edition/Models/Cubes/large/StealthDrive1x1_BS3.mwm b/Utility Mods/Stealth Drive - Starcore Edition/Models/Cubes/large/StealthDrive1x1_BS3.mwm new file mode 100644 index 000000000..6e4dc5c38 Binary files /dev/null and b/Utility Mods/Stealth Drive - Starcore Edition/Models/Cubes/large/StealthDrive1x1_BS3.mwm differ diff --git a/Utility Mods/Stealth Drive - Starcore Edition/Models/Cubes/large/StealthDrive1x1_LOD1.mwm b/Utility Mods/Stealth Drive - Starcore Edition/Models/Cubes/large/StealthDrive1x1_LOD1.mwm new file mode 100644 index 000000000..b2dd01f47 Binary files /dev/null and b/Utility Mods/Stealth Drive - Starcore Edition/Models/Cubes/large/StealthDrive1x1_LOD1.mwm differ diff --git a/Utility Mods/Stealth Drive - Starcore Edition/Models/Cubes/large/StealthDrive1x1_LOD2.mwm b/Utility Mods/Stealth Drive - Starcore Edition/Models/Cubes/large/StealthDrive1x1_LOD2.mwm new file mode 100644 index 000000000..ac9627c70 Binary files /dev/null and b/Utility Mods/Stealth Drive - Starcore Edition/Models/Cubes/large/StealthDrive1x1_LOD2.mwm differ diff --git a/Utility Mods/Stealth Drive - Starcore Edition/Models/Cubes/large/StealthDrive1x1_LOD3.mwm b/Utility Mods/Stealth Drive - Starcore Edition/Models/Cubes/large/StealthDrive1x1_LOD3.mwm new file mode 100644 index 000000000..3f8405d5e Binary files /dev/null and b/Utility Mods/Stealth Drive - Starcore Edition/Models/Cubes/large/StealthDrive1x1_LOD3.mwm differ diff --git a/Utility Mods/Stealth Drive - Starcore Edition/Models/Cubes/large/StealthHeatSink.mwm b/Utility Mods/Stealth Drive - Starcore Edition/Models/Cubes/large/StealthHeatSink.mwm new file mode 100644 index 000000000..68b8e0e8c Binary files /dev/null and b/Utility Mods/Stealth Drive - Starcore Edition/Models/Cubes/large/StealthHeatSink.mwm differ diff --git a/Utility Mods/Stealth Drive - Starcore Edition/Models/Cubes/large/StealthHeatSink_BS1.mwm b/Utility Mods/Stealth Drive - Starcore Edition/Models/Cubes/large/StealthHeatSink_BS1.mwm new file mode 100644 index 000000000..6fe24ce16 Binary files /dev/null and b/Utility Mods/Stealth Drive - Starcore Edition/Models/Cubes/large/StealthHeatSink_BS1.mwm differ diff --git a/Utility Mods/Stealth Drive - Starcore Edition/Models/Cubes/large/StealthHeatSink_BS2.mwm b/Utility Mods/Stealth Drive - Starcore Edition/Models/Cubes/large/StealthHeatSink_BS2.mwm new file mode 100644 index 000000000..9ca488cb5 Binary files /dev/null and b/Utility Mods/Stealth Drive - Starcore Edition/Models/Cubes/large/StealthHeatSink_BS2.mwm differ diff --git a/Utility Mods/Stealth Drive - Starcore Edition/Models/Cubes/large/StealthHeatSink_BS3.mwm b/Utility Mods/Stealth Drive - Starcore Edition/Models/Cubes/large/StealthHeatSink_BS3.mwm new file mode 100644 index 000000000..af2334420 Binary files /dev/null and b/Utility Mods/Stealth Drive - Starcore Edition/Models/Cubes/large/StealthHeatSink_BS3.mwm differ diff --git a/Utility Mods/Stealth Drive - Starcore Edition/Models/Cubes/small/StealthDriveSmall.mwm b/Utility Mods/Stealth Drive - Starcore Edition/Models/Cubes/small/StealthDriveSmall.mwm new file mode 100644 index 000000000..b7b27e2b0 Binary files /dev/null and b/Utility Mods/Stealth Drive - Starcore Edition/Models/Cubes/small/StealthDriveSmall.mwm differ diff --git a/Utility Mods/Stealth Drive - Starcore Edition/Models/Cubes/small/StealthDriveSmall_BS1.mwm b/Utility Mods/Stealth Drive - Starcore Edition/Models/Cubes/small/StealthDriveSmall_BS1.mwm new file mode 100644 index 000000000..57b8a8f81 Binary files /dev/null and b/Utility Mods/Stealth Drive - Starcore Edition/Models/Cubes/small/StealthDriveSmall_BS1.mwm differ diff --git a/Utility Mods/Stealth Drive - Starcore Edition/Models/Cubes/small/StealthDriveSmall_BS2.mwm b/Utility Mods/Stealth Drive - Starcore Edition/Models/Cubes/small/StealthDriveSmall_BS2.mwm new file mode 100644 index 000000000..fe8e6f9eb Binary files /dev/null and b/Utility Mods/Stealth Drive - Starcore Edition/Models/Cubes/small/StealthDriveSmall_BS2.mwm differ diff --git a/Utility Mods/Stealth Drive - Starcore Edition/Models/Cubes/small/StealthDriveSmall_BS3.mwm b/Utility Mods/Stealth Drive - Starcore Edition/Models/Cubes/small/StealthDriveSmall_BS3.mwm new file mode 100644 index 000000000..8ea3c46cc Binary files /dev/null and b/Utility Mods/Stealth Drive - Starcore Edition/Models/Cubes/small/StealthDriveSmall_BS3.mwm differ diff --git a/Utility Mods/Stealth Drive - Starcore Edition/Models/Cubes/small/StealthDriveSmall_LOD1.mwm b/Utility Mods/Stealth Drive - Starcore Edition/Models/Cubes/small/StealthDriveSmall_LOD1.mwm new file mode 100644 index 000000000..fffcb4d7e Binary files /dev/null and b/Utility Mods/Stealth Drive - Starcore Edition/Models/Cubes/small/StealthDriveSmall_LOD1.mwm differ diff --git a/Utility Mods/Stealth Drive - Starcore Edition/Models/Cubes/small/StealthDriveSmall_LOD2.mwm b/Utility Mods/Stealth Drive - Starcore Edition/Models/Cubes/small/StealthDriveSmall_LOD2.mwm new file mode 100644 index 000000000..ef7ef5c6f Binary files /dev/null and b/Utility Mods/Stealth Drive - Starcore Edition/Models/Cubes/small/StealthDriveSmall_LOD2.mwm differ diff --git a/Utility Mods/Stealth Drive - Starcore Edition/Models/Cubes/small/StealthDriveSmall_LOD3.mwm b/Utility Mods/Stealth Drive - Starcore Edition/Models/Cubes/small/StealthDriveSmall_LOD3.mwm new file mode 100644 index 000000000..07f290bf7 Binary files /dev/null and b/Utility Mods/Stealth Drive - Starcore Edition/Models/Cubes/small/StealthDriveSmall_LOD3.mwm differ diff --git a/Utility Mods/Stealth Drive - Starcore Edition/Models/Cubes/small/StealthHeatSinkSmall.mwm b/Utility Mods/Stealth Drive - Starcore Edition/Models/Cubes/small/StealthHeatSinkSmall.mwm new file mode 100644 index 000000000..3ef3c0f0f Binary files /dev/null and b/Utility Mods/Stealth Drive - Starcore Edition/Models/Cubes/small/StealthHeatSinkSmall.mwm differ diff --git a/Utility Mods/Stealth Drive - Starcore Edition/Models/Cubes/small/StealthHeatSinkSmall_BS1.mwm b/Utility Mods/Stealth Drive - Starcore Edition/Models/Cubes/small/StealthHeatSinkSmall_BS1.mwm new file mode 100644 index 000000000..11f63b4a8 Binary files /dev/null and b/Utility Mods/Stealth Drive - Starcore Edition/Models/Cubes/small/StealthHeatSinkSmall_BS1.mwm differ diff --git a/Utility Mods/Stealth Drive - Starcore Edition/Models/Cubes/small/StealthHeatSinkSmall_BS2.mwm b/Utility Mods/Stealth Drive - Starcore Edition/Models/Cubes/small/StealthHeatSinkSmall_BS2.mwm new file mode 100644 index 000000000..ac6305c84 Binary files /dev/null and b/Utility Mods/Stealth Drive - Starcore Edition/Models/Cubes/small/StealthHeatSinkSmall_BS2.mwm differ diff --git a/Utility Mods/Stealth Drive - Starcore Edition/Models/Cubes/small/StealthHeatSinkSmall_BS3.mwm b/Utility Mods/Stealth Drive - Starcore Edition/Models/Cubes/small/StealthHeatSinkSmall_BS3.mwm new file mode 100644 index 000000000..114d95c45 Binary files /dev/null and b/Utility Mods/Stealth Drive - Starcore Edition/Models/Cubes/small/StealthHeatSinkSmall_BS3.mwm differ diff --git a/Utility Mods/Stealth Drive - Starcore Edition/Textures/GUI/Icons/Actions/StealthSwitchOff.dds b/Utility Mods/Stealth Drive - Starcore Edition/Textures/GUI/Icons/Actions/StealthSwitchOff.dds new file mode 100644 index 000000000..f271e6c87 Binary files /dev/null and b/Utility Mods/Stealth Drive - Starcore Edition/Textures/GUI/Icons/Actions/StealthSwitchOff.dds differ diff --git a/Utility Mods/Stealth Drive - Starcore Edition/Textures/GUI/Icons/Actions/StealthSwitchOff.png b/Utility Mods/Stealth Drive - Starcore Edition/Textures/GUI/Icons/Actions/StealthSwitchOff.png new file mode 100644 index 000000000..5e812623a Binary files /dev/null and b/Utility Mods/Stealth Drive - Starcore Edition/Textures/GUI/Icons/Actions/StealthSwitchOff.png differ diff --git a/Utility Mods/Stealth Drive - Starcore Edition/Textures/GUI/Icons/Actions/StealthSwitchOn.dds b/Utility Mods/Stealth Drive - Starcore Edition/Textures/GUI/Icons/Actions/StealthSwitchOn.dds new file mode 100644 index 000000000..c10376a55 Binary files /dev/null and b/Utility Mods/Stealth Drive - Starcore Edition/Textures/GUI/Icons/Actions/StealthSwitchOn.dds differ diff --git a/Utility Mods/Stealth Drive - Starcore Edition/Textures/GUI/Icons/Actions/StealthSwitchOn.png b/Utility Mods/Stealth Drive - Starcore Edition/Textures/GUI/Icons/Actions/StealthSwitchOn.png new file mode 100644 index 000000000..8fdd4ae60 Binary files /dev/null and b/Utility Mods/Stealth Drive - Starcore Edition/Textures/GUI/Icons/Actions/StealthSwitchOn.png differ diff --git a/Utility Mods/Stealth Drive - Starcore Edition/Textures/GUI/Icons/Actions/StealthSwitchOn.xcf b/Utility Mods/Stealth Drive - Starcore Edition/Textures/GUI/Icons/Actions/StealthSwitchOn.xcf new file mode 100644 index 000000000..5eb1221e9 Binary files /dev/null and b/Utility Mods/Stealth Drive - Starcore Edition/Textures/GUI/Icons/Actions/StealthSwitchOn.xcf differ diff --git a/Utility Mods/Stealth Drive - Starcore Edition/Textures/GUI/Icons/Actions/StealthSwitchToggle.dds b/Utility Mods/Stealth Drive - Starcore Edition/Textures/GUI/Icons/Actions/StealthSwitchToggle.dds new file mode 100644 index 000000000..3d36a45aa Binary files /dev/null and b/Utility Mods/Stealth Drive - Starcore Edition/Textures/GUI/Icons/Actions/StealthSwitchToggle.dds differ diff --git a/Utility Mods/Stealth Drive - Starcore Edition/Textures/GUI/Icons/Actions/StealthSwitchToggle.png b/Utility Mods/Stealth Drive - Starcore Edition/Textures/GUI/Icons/Actions/StealthSwitchToggle.png new file mode 100644 index 000000000..2a3e826ff Binary files /dev/null and b/Utility Mods/Stealth Drive - Starcore Edition/Textures/GUI/Icons/Actions/StealthSwitchToggle.png differ diff --git a/Utility Mods/Stealth Drive - Starcore Edition/Textures/GUI/Icons/Cubes/Aryx_AWE_TacticalModule.dds b/Utility Mods/Stealth Drive - Starcore Edition/Textures/GUI/Icons/Cubes/Aryx_AWE_TacticalModule.dds new file mode 100644 index 000000000..91236f0c1 Binary files /dev/null and b/Utility Mods/Stealth Drive - Starcore Edition/Textures/GUI/Icons/Cubes/Aryx_AWE_TacticalModule.dds differ diff --git a/Utility Mods/Stealth Drive - Starcore Edition/Textures/Models/Cubes/Atlas3_Colorable_add.dds b/Utility Mods/Stealth Drive - Starcore Edition/Textures/Models/Cubes/Atlas3_Colorable_add.dds new file mode 100644 index 000000000..a573fbbea Binary files /dev/null and b/Utility Mods/Stealth Drive - Starcore Edition/Textures/Models/Cubes/Atlas3_Colorable_add.dds differ diff --git a/Utility Mods/Stealth Drive - Starcore Edition/Textures/Models/Cubes/Atlas3_Colorable_cm.dds b/Utility Mods/Stealth Drive - Starcore Edition/Textures/Models/Cubes/Atlas3_Colorable_cm.dds new file mode 100644 index 000000000..d89e64fe4 Binary files /dev/null and b/Utility Mods/Stealth Drive - Starcore Edition/Textures/Models/Cubes/Atlas3_Colorable_cm.dds differ diff --git a/Utility Mods/Stealth Drive - Starcore Edition/Textures/Models/Cubes/Atlas3_Colorable_ng.dds b/Utility Mods/Stealth Drive - Starcore Edition/Textures/Models/Cubes/Atlas3_Colorable_ng.dds new file mode 100644 index 000000000..0f7243303 Binary files /dev/null and b/Utility Mods/Stealth Drive - Starcore Edition/Textures/Models/Cubes/Atlas3_Colorable_ng.dds differ diff --git a/Utility Mods/Stealth Drive - Starcore Edition/Textures/Models/Cubes/Atlas3_alphamask.dds b/Utility Mods/Stealth Drive - Starcore Edition/Textures/Models/Cubes/Atlas3_alphamask.dds new file mode 100644 index 000000000..277f2c57b Binary files /dev/null and b/Utility Mods/Stealth Drive - Starcore Edition/Textures/Models/Cubes/Atlas3_alphamask.dds differ diff --git a/Utility Mods/Stealth Drive - Starcore Edition/Textures/Models/Cubes/Atlas4_Colorable_add.dds b/Utility Mods/Stealth Drive - Starcore Edition/Textures/Models/Cubes/Atlas4_Colorable_add.dds new file mode 100644 index 000000000..f6b1c3209 Binary files /dev/null and b/Utility Mods/Stealth Drive - Starcore Edition/Textures/Models/Cubes/Atlas4_Colorable_add.dds differ diff --git a/Utility Mods/Stealth Drive - Starcore Edition/Textures/Models/Cubes/Atlas4_Colorable_cm.dds b/Utility Mods/Stealth Drive - Starcore Edition/Textures/Models/Cubes/Atlas4_Colorable_cm.dds new file mode 100644 index 000000000..2dd7709ed Binary files /dev/null and b/Utility Mods/Stealth Drive - Starcore Edition/Textures/Models/Cubes/Atlas4_Colorable_cm.dds differ diff --git a/Utility Mods/Stealth Drive - Starcore Edition/Textures/Models/Cubes/Atlas4_Colorable_ng.dds b/Utility Mods/Stealth Drive - Starcore Edition/Textures/Models/Cubes/Atlas4_Colorable_ng.dds new file mode 100644 index 000000000..48a0daab1 Binary files /dev/null and b/Utility Mods/Stealth Drive - Starcore Edition/Textures/Models/Cubes/Atlas4_Colorable_ng.dds differ diff --git a/Utility Mods/Stealth Drive - Starcore Edition/Textures/Models/Cubes/Atlas4_alphamask.dds b/Utility Mods/Stealth Drive - Starcore Edition/Textures/Models/Cubes/Atlas4_alphamask.dds new file mode 100644 index 000000000..d893de672 Binary files /dev/null and b/Utility Mods/Stealth Drive - Starcore Edition/Textures/Models/Cubes/Atlas4_alphamask.dds differ diff --git a/Utility Mods/Stealth Drive - Starcore Edition/Textures/Models/Cubes/Copper1_add.dds b/Utility Mods/Stealth Drive - Starcore Edition/Textures/Models/Cubes/Copper1_add.dds new file mode 100644 index 000000000..f5eeac05f Binary files /dev/null and b/Utility Mods/Stealth Drive - Starcore Edition/Textures/Models/Cubes/Copper1_add.dds differ diff --git a/Utility Mods/Stealth Drive - Starcore Edition/Textures/Models/Cubes/Copper1_cm.dds b/Utility Mods/Stealth Drive - Starcore Edition/Textures/Models/Cubes/Copper1_cm.dds new file mode 100644 index 000000000..2fc8f1943 Binary files /dev/null and b/Utility Mods/Stealth Drive - Starcore Edition/Textures/Models/Cubes/Copper1_cm.dds differ diff --git a/Utility Mods/Stealth Drive - Starcore Edition/Textures/Models/Cubes/Copper1_ng.dds b/Utility Mods/Stealth Drive - Starcore Edition/Textures/Models/Cubes/Copper1_ng.dds new file mode 100644 index 000000000..fcabe892d Binary files /dev/null and b/Utility Mods/Stealth Drive - Starcore Edition/Textures/Models/Cubes/Copper1_ng.dds differ diff --git a/Utility Mods/Stealth Drive - Starcore Edition/Textures/Models/Cubes/PaintedMetalColorable_add.dds b/Utility Mods/Stealth Drive - Starcore Edition/Textures/Models/Cubes/PaintedMetalColorable_add.dds new file mode 100644 index 000000000..fb2f2a0bb Binary files /dev/null and b/Utility Mods/Stealth Drive - Starcore Edition/Textures/Models/Cubes/PaintedMetalColorable_add.dds differ diff --git a/Utility Mods/Stealth Drive - Starcore Edition/Textures/Models/Cubes/PaintedMetalColorable_cm.dds b/Utility Mods/Stealth Drive - Starcore Edition/Textures/Models/Cubes/PaintedMetalColorable_cm.dds new file mode 100644 index 000000000..0cd4ec850 Binary files /dev/null and b/Utility Mods/Stealth Drive - Starcore Edition/Textures/Models/Cubes/PaintedMetalColorable_cm.dds differ diff --git a/Utility Mods/Stealth Drive - Starcore Edition/Textures/Models/Cubes/PaintedMetalColorable_ng.dds b/Utility Mods/Stealth Drive - Starcore Edition/Textures/Models/Cubes/PaintedMetalColorable_ng.dds new file mode 100644 index 000000000..9f6ea4a4e Binary files /dev/null and b/Utility Mods/Stealth Drive - Starcore Edition/Textures/Models/Cubes/PaintedMetalColorable_ng.dds differ diff --git a/Utility Mods/Stealth Drive - Starcore Edition/metadata.mod b/Utility Mods/Stealth Drive - Starcore Edition/metadata.mod new file mode 100644 index 000000000..83173346a --- /dev/null +++ b/Utility Mods/Stealth Drive - Starcore Edition/metadata.mod @@ -0,0 +1,4 @@ + + + 1.0 + \ No newline at end of file diff --git a/Utility Mods/Stealth Drive - Starcore Edition/modinfo_main.sbmi b/Utility Mods/Stealth Drive - Starcore Edition/modinfo_main.sbmi new file mode 100644 index 000000000..229fc7352 --- /dev/null +++ b/Utility Mods/Stealth Drive - Starcore Edition/modinfo_main.sbmi @@ -0,0 +1,11 @@ + + + 76561198049738491 + 0 + + + 3436896074 + Steam + + + diff --git a/Utility Mods/Stealth Drive - Starcore Edition/thumb.png b/Utility Mods/Stealth Drive - Starcore Edition/thumb.png new file mode 100644 index 000000000..3a3e809ab Binary files /dev/null and b/Utility Mods/Stealth Drive - Starcore Edition/thumb.png differ diff --git a/Utility Mods/Stealth Drive - Starcore Edition/uploaddisable_stable.sbmi b/Utility Mods/Stealth Drive - Starcore Edition/uploaddisable_stable.sbmi new file mode 100644 index 000000000..e69de29bb diff --git a/unfuckaudio.py b/fixaudio.py similarity index 97% rename from unfuckaudio.py rename to fixaudio.py index 272770be4..a2aa8e427 100644 --- a/unfuckaudio.py +++ b/fixaudio.py @@ -109,4 +109,4 @@ def process_directory(): process_directory() except KeyboardInterrupt: print("\n\n❗ Process interrupted by user. Exiting gracefully.") - sys.exit(0) \ No newline at end of file + sys.exit(0)