From 2577969ad25a7ba15dddae2fce608463d5bbe15e Mon Sep 17 00:00:00 2001 From: InvalidArgument3 Date: Sat, 7 Dec 2024 07:41:24 -0600 Subject: [PATCH 1/4] Revert "reversion to the old fucking logic" This reverts commit af7dd1d6c18de8dd86138af210309949b5fd248f. --- .../TeleportGateway/TeleportBubbleManager.cs | 42 +- .../Scripts/TeleportGateway/TeleportCore.cs | 314 +++---- .../TeleportGateway/TeleportGateway.cs | 829 +++++++++++++----- .../TeleportGatewaySettings.cs | 5 + 4 files changed, 783 insertions(+), 407 deletions(-) diff --git a/Ringway/Data/Scripts/TeleportGateway/TeleportBubbleManager.cs b/Ringway/Data/Scripts/TeleportGateway/TeleportBubbleManager.cs index d3e2ce5c..3f5b4985 100644 --- a/Ringway/Data/Scripts/TeleportGateway/TeleportBubbleManager.cs +++ b/Ringway/Data/Scripts/TeleportGateway/TeleportBubbleManager.cs @@ -14,50 +14,40 @@ public static class TeleportBubbleManager private static readonly object _lock = new object(); private static readonly Color _bubbleColor = new Color(0, 0, 255, 64); // Blue with 25% opacity - public static void CreateOrUpdateBubble(IMyCollector gateway) - { + public static void CreateOrUpdateBubble(IMyCollector gateway, Color color) { var gatewayLogic = gateway.GameLogic.GetAs(); - if (gatewayLogic == null || !gatewayLogic.Settings.ShowSphere) - { + if (gatewayLogic == null || !gatewayLogic.Settings.ShowSphere) { RemoveBubble(gateway); // Remove the bubble if ShowSphere is false return; } - lock (_lock) - { + lock (_lock) { float sphereRadius = gatewayLogic.Settings.SphereDiameter / 2.0f; - Vector3D position = gateway.GetPosition() + gateway.WorldMatrix.Forward * sphereRadius; // Adjusted to use the sphere radius + Vector3D position = gateway.GetPosition() + gateway.WorldMatrix.Forward * sphereRadius; _bubblePositions[gateway.EntityId] = position; } } - public static void DrawBubble(IMyCollector gateway) - { - try - { + public static void DrawBubble(IMyCollector gateway, Color color) { + try { // Check if we're on a dedicated server - if (MyAPIGateway.Utilities.IsDedicated) - { + if (MyAPIGateway.Utilities.IsDedicated) { return; } // Check if the Session object is available - if (MyAPIGateway.Session == null) - { + if (MyAPIGateway.Session == null) { return; } var gatewayLogic = gateway.GameLogic.GetAs(); - if (gatewayLogic == null || !gatewayLogic.Settings.ShowSphere) - { + if (gatewayLogic == null || !gatewayLogic.Settings.ShowSphere) { return; } Vector3D position; - lock (_lock) - { - if (!_bubblePositions.TryGetValue(gateway.EntityId, out position)) - { + lock (_lock) { + if (!_bubblePositions.TryGetValue(gateway.EntityId, out position)) { return; } } @@ -66,14 +56,10 @@ public static void DrawBubble(IMyCollector gateway) MatrixD worldMatrix = gateway.WorldMatrix; MatrixD adjustedMatrix = MatrixD.CreateWorld(position, worldMatrix.Forward, worldMatrix.Up); - // Create a non-readonly copy of the color - Color bubbleColor = _bubbleColor; - - // Draw a solid sphere - MySimpleObjectDraw.DrawTransparentSphere(ref adjustedMatrix, radius, ref bubbleColor, MySimpleObjectRasterizer.Solid, 20, null, MyStringId.GetOrCompute("Square")); + // Use the specified color + MySimpleObjectDraw.DrawTransparentSphere(ref adjustedMatrix, radius, ref color, MySimpleObjectRasterizer.Solid, 20, null, MyStringId.GetOrCompute("Square")); } - catch (Exception exc) - { + catch (Exception exc) { MyLog.Default.WriteLineAndConsole($"TeleportBubbleManager: Error drawing bubble: {exc.Message}\n{exc.StackTrace}"); } } diff --git a/Ringway/Data/Scripts/TeleportGateway/TeleportCore.cs b/Ringway/Data/Scripts/TeleportGateway/TeleportCore.cs index 1b60bbb6..516a21ab 100644 --- a/Ringway/Data/Scripts/TeleportGateway/TeleportCore.cs +++ b/Ringway/Data/Scripts/TeleportGateway/TeleportCore.cs @@ -17,82 +17,70 @@ using SpaceEngineers.Game.ModAPI.Ingame; using Sandbox.Game.Entities; using System.Reflection.Emit; +using Sandbox.Game; -namespace TeleportMechanisms -{ - public static class TeleportCore - { +namespace TeleportMechanisms { + public static class TeleportCore { internal static Dictionary> _TeleportLinks = new Dictionary>(); internal static Dictionary _instances = new Dictionary(); internal static readonly object _lock = new object(); - public static void UpdateTeleportLinks() - { - lock (_lock) - { + public static void UpdateTeleportLinks() { + lock (_lock) { _TeleportLinks.Clear(); MyLogger.Log($"TPCore: UpdateTeleportLinks: Updating Teleport links. Total instances: {_instances.Count}"); var gateways = new HashSet(); - foreach (var instance in _instances.Values) - { - if (instance.Block != null && (instance.Block.BlockDefinition.SubtypeName == "RingwayCore" || instance.Block.BlockDefinition.SubtypeName == "RingwayCoreSmall")) - { - MyLogger.Log($"TPCore: UpdateTeleportLinks: Found instance gateway: {instance.Block.CustomName}, EntityId: {instance.Block.EntityId}, IsWorking: {instance.Block.IsWorking}"); - gateways.Add(instance.Block); + foreach (var instance in _instances.Values) { + if (instance.RingwayBlock != null && + instance.RingwayBlock.IsWorking && + (instance.RingwayBlock.BlockDefinition.SubtypeName == "RingwayCore" || + instance.RingwayBlock.BlockDefinition.SubtypeName == "SmallRingwayCore")) { + MyLogger.Log($"TPCore: UpdateTeleportLinks: Found instance gateway: {instance.RingwayBlock.CustomName}, EntityId: {instance.RingwayBlock.EntityId}, IsWorking: {instance.RingwayBlock.IsWorking}"); + gateways.Add(instance.RingwayBlock); } - else - { + else { MyLogger.Log($"TPCore: UpdateTeleportLinks: Instance has null or invalid gateway"); } } MyLogger.Log($"TPCore: UpdateTeleportLinks: Total gateways found: {gateways.Count}"); - foreach (var gateway in gateways) - { + foreach (var gateway in gateways) { var gatewayLogic = gateway.GameLogic.GetAs(); var link = GetTeleportLink(gateway); - if (!string.IsNullOrEmpty(link)) - { - if (!_TeleportLinks.ContainsKey(link)) - { + if (!string.IsNullOrEmpty(link)) { + if (!_TeleportLinks.ContainsKey(link)) { _TeleportLinks[link] = new List(); } _TeleportLinks[link].Add(gateway.EntityId); MyLogger.Log($"TPCore: UpdateTeleportLinks: Added gateway {gateway.CustomName} (EntityId: {gateway.EntityId}) to link {link}. AllowPlayers: {gatewayLogic.Settings.AllowPlayers}, AllowShips: {gatewayLogic.Settings.AllowShips}"); } - else - { + else { MyLogger.Log($"TPCore: UpdateTeleportLinks: Gateway {gateway.CustomName} (EntityId: {gateway.EntityId}) does not have a valid teleport link"); } } MyLogger.Log($"TPCore: UpdateTeleportLinks: Total Teleport links: {_TeleportLinks.Count}"); - foreach (var kvp in _TeleportLinks) - { + foreach (var kvp in _TeleportLinks) { MyLogger.Log($"TPCore: UpdateTeleportLinks: Link {kvp.Key}: {string.Join(", ", kvp.Value)}"); } } } - public static string GetTeleportLink(IMyCollector gateway) - { + public static string GetTeleportLink(IMyCollector gateway) { var gatewayLogic = gateway.GameLogic.GetAs(); - if (gatewayLogic != null) - { + if (gatewayLogic != null) { MyLogger.Log($"TPCore: GetTeleportLink: GatewayName: {gatewayLogic.Settings.GatewayName}, AllowPlayers: {gatewayLogic.Settings.AllowPlayers}, AllowShips: {gatewayLogic.Settings.AllowShips}"); return gatewayLogic.Settings.GatewayName; } return null; } - public static void RequestTeleport(long playerId, long sourceGatewayId, string link) - { + public static void RequestTeleport(long playerId, long sourceGatewayId, string link) { MyLogger.Log($"TPCore: RequestTeleport: Player {playerId}, Gateway {sourceGatewayId}, Link {link}"); - var message = new TeleportRequestMessage - { + var message = new TeleportRequestMessage { PlayerId = (ulong)playerId, SourceGatewayId = sourceGatewayId, TeleportLink = link @@ -103,110 +91,92 @@ public static void RequestTeleport(long playerId, long sourceGatewayId, string l MyAPIGateway.Multiplayer.SendMessageToServer(NetworkHandler.TeleportRequestId, data); } - public static void ServerProcessTeleportRequest(TeleportRequestMessage message) - { + public static void ServerProcessTeleportRequest(TeleportRequestMessage message) { MyLogger.Log($"TPCore: ProcessTeleportRequest: Player {message.PlayerId}, Link {message.TeleportLink}"); - MyLogger.Log($"TPCore: ProcessTeleportRequest: Current Teleport links: {string.Join(", ", _TeleportLinks.Keys)}"); List linkedGateways; - lock (_lock) - { - if (!_TeleportLinks.TryGetValue(message.TeleportLink, out linkedGateways)) - { + lock (_lock) { + if (!_TeleportLinks.TryGetValue(message.TeleportLink, out linkedGateways)) { MyLogger.Log($"TPCore: ProcessTeleportRequest: No linked gateways found for link {message.TeleportLink}"); return; } } - MyLogger.Log($"TPCore: ProcessTeleportRequest: Found {linkedGateways.Count} linked gateways for link {message.TeleportLink}"); - - if (linkedGateways.Count < 2) - { - MyLogger.Log("TPCore: ProcessTeleportRequest: At least two linked gateways are required for teleportation. Aborting."); + var sourceGateway = MyAPIGateway.Entities.GetEntityById(message.SourceGatewayId) as IMyCollector; + if (sourceGateway == null) { + MyLogger.Log($"TPCore: ProcessTeleportRequest: Source gateway {message.SourceGatewayId} not found"); return; } - var sourceIndex = linkedGateways.IndexOf(message.SourceGatewayId); - if (sourceIndex == -1) - { - MyLogger.Log($"TPCore: ProcessTeleportRequest: Source gateway {message.SourceGatewayId} not found in linked gateways"); - return; - } + var sourcePosition = sourceGateway.GetPosition(); + long nearestGatewayId = 0; + double nearestDistance = double.MaxValue; + + foreach (var gatewayId in linkedGateways) { + if (gatewayId == message.SourceGatewayId) continue; - var destIndex = (sourceIndex + 1) % linkedGateways.Count; - var destGatewayId = linkedGateways[destIndex]; + var candidateGateway = MyAPIGateway.Entities.GetEntityById(gatewayId) as IMyCollector; + if (candidateGateway == null) continue; + + var distance = Vector3D.Distance(sourcePosition, candidateGateway.GetPosition()); + if (distance < nearestDistance) { + nearestDistance = distance; + nearestGatewayId = gatewayId; + } + } - var destGateway = MyAPIGateway.Entities.GetEntityById(destGatewayId) as IMyCollector; - if (destGateway == null) - { - MyLogger.Log($"TPCore: ProcessTeleportRequest: Destination gateway {destGatewayId} not found"); + if (nearestGatewayId == 0) { + MyLogger.Log($"TPCore: ProcessTeleportRequest: No valid destination gateway found for link {message.TeleportLink}"); return; } - var player = GetPlayerById((long)message.PlayerId); - if (player == null || player.Character == null) - { - MyLogger.Log($"TPCore: ProcessTeleportRequest: Player {message.PlayerId} or their character not found"); + var destGateway = MyAPIGateway.Entities.GetEntityById(nearestGatewayId) as IMyCollector; + if (destGateway == null) { + MyLogger.Log($"TPCore: ProcessTeleportRequest: Destination gateway {nearestGatewayId} not found"); return; } - var sourceGateway = MyAPIGateway.Entities.GetEntityById(message.SourceGatewayId) as IMyCollector; - if (sourceGateway == null) - { - MyLogger.Log($"TPCore: ProcessTeleportRequest: Source gateway {message.SourceGatewayId} not found"); + var player = GetPlayerById((long)message.PlayerId); + if (player == null || player.Character == null) { + MyLogger.Log($"TPCore: ProcessTeleportRequest: Player {message.PlayerId} or their character not found"); return; } - // Check the source gateway settings var sourceGatewayLogic = sourceGateway.GameLogic.GetAs(); - if (sourceGatewayLogic == null) - { + if (sourceGatewayLogic == null) { MyLogger.Log($"TPCore: ProcessTeleportRequest: Could not retrieve TeleportGateway for source gateway {sourceGateway.EntityId}"); return; } var sourceGatewaySettings = sourceGatewayLogic.Settings; - MyLogger.Log($"TPCore: ProcessTeleportRequest: Source gateway settings - AllowPlayers: {sourceGatewaySettings.AllowPlayers}, AllowShips: {sourceGatewaySettings.AllowShips}"); - - if (!sourceGatewaySettings.AllowPlayers) - { + if (!sourceGatewaySettings.AllowPlayers) { MyLogger.Log($"TPCore: ProcessTeleportRequest: Player teleportation is not allowed for source gateway {sourceGateway.EntityId}"); return; } var isShip = player.Controller.ControlledEntity is IMyCubeBlock; - if (isShip && !sourceGatewaySettings.AllowShips) - { + if (isShip && !sourceGatewaySettings.AllowShips) { MyLogger.Log($"TPCore: ProcessTeleportRequest: Ship teleportation is not allowed for source gateway {sourceGateway.EntityId}"); return; } - // Perform teleportation TeleportEntity(player.Character, sourceGateway, destGateway); var grid = player.Controller.ControlledEntity?.Entity.GetTopMostParent() as IMyCubeGrid; - if (grid != null) - { - // Ensure the grid is not static - if (grid.IsStatic) - { + if (grid != null) { + if (grid.IsStatic) { MyLogger.Log($"TPCore: ProcessTeleportRequest: Grid {grid.DisplayName} is static, teleportation aborted"); return; } - - // Ensure the grid is not locked to a static grid - if (HasLockedLandingGear(grid)) - { + if (HasLockedLandingGear(grid)) { MyLogger.Log($"TPCore: ProcessTeleportRequest: Grid {grid.DisplayName} has locked landing gear, teleportation aborted"); return; } - TeleportEntity(grid, sourceGateway, destGateway); } } - private static void TeleportEntity(IMyEntity entity, IMyCollector sourceGateway, IMyCollector destGateway) - { + public static void TeleportEntity(IMyEntity entity, IMyCollector sourceGateway, IMyCollector destGateway) { MyLogger.Log($"TPCore: TeleportEntity: Teleporting entity {entity.EntityId}"); var relativePosition = entity.GetPosition() - sourceGateway.GetPosition(); @@ -218,16 +188,13 @@ private static void TeleportEntity(IMyEntity entity, IMyCollector sourceGateway, var newOrientation = relativeOrientation * destGateway.WorldMatrix; var character = entity as IMyCharacter; - if (character != null) - { + if (character != null) { character.Teleport(newOrientation); character.SetWorldMatrix(newOrientation); } - else - { + else { var grid = entity as IMyCubeGrid; - if (grid != null) - { + if (grid != null) { TeleportGrid(grid, newOrientation, sourceGateway.WorldMatrix, destGateway.WorldMatrix); } } @@ -235,8 +202,7 @@ private static void TeleportEntity(IMyEntity entity, IMyCollector sourceGateway, MyLogger.Log($"TPCore: TeleportEntity: Entity {entity.EntityId} teleported to {newPosition}"); } - private static void TeleportGrid(IMyCubeGrid mainGrid, MatrixD newOrientation, MatrixD sourceGatewayMatrix, MatrixD destinationGatewayMatrix) - { + private static void TeleportGrid(IMyCubeGrid mainGrid, MatrixD newOrientation, MatrixD sourceGatewayMatrix, MatrixD destinationGatewayMatrix) { var allGrids = new List(); MyAPIGateway.GridGroups.GetGroup(mainGrid, GridLinkTypeEnum.Physical, allGrids); @@ -247,8 +213,7 @@ private static void TeleportGrid(IMyCubeGrid mainGrid, MatrixD newOrientation, M Dictionary relativeLocalMatrices = new Dictionary(); // Calculate and store the relative local matrix for each subgrid - foreach (var subgrid in subgrids) - { + foreach (var subgrid in subgrids) { MatrixD relativeMatrix = subgrid.WorldMatrix * MatrixD.Invert(mainGrid.WorldMatrix); relativeLocalMatrices[subgrid] = relativeMatrix; MyLogger.Log($"TPCore: TeleportGrid: Calculated relative matrix for subgrid {subgrid.DisplayName} (EntityId: {subgrid.EntityId}), Relative Matrix: {relativeMatrix}"); @@ -261,8 +226,7 @@ private static void TeleportGrid(IMyCubeGrid mainGrid, MatrixD newOrientation, M // Update physics for the main grid var mainPhysics = mainGrid.Physics; - if (mainPhysics != null) - { + if (mainPhysics != null) { mainPhysics.LinearVelocity = Vector3D.Zero; mainPhysics.AngularVelocity = Vector3D.Zero; @@ -276,24 +240,20 @@ private static void TeleportGrid(IMyCubeGrid mainGrid, MatrixD newOrientation, M HashSet processedSubgrids = new HashSet(); // Transform and update all subgrids - foreach (var subgrid in subgrids) - { - if (processedSubgrids.Contains(subgrid.EntityId)) - { + foreach (var subgrid in subgrids) { + if (processedSubgrids.Contains(subgrid.EntityId)) { MyLogger.Log($"TPCore: TeleportGrid: Skipping already processed subgrid {subgrid.DisplayName} (EntityId: {subgrid.EntityId})"); continue; } - try - { + try { MatrixD newGridWorldMatrix = relativeLocalMatrices[subgrid] * mainGrid.WorldMatrix; MyLogger.Log($"TPCore: TeleportGrid: Calculating new WorldMatrix for subgrid {subgrid.DisplayName} (EntityId: {subgrid.EntityId}), New World Matrix: {newGridWorldMatrix}"); subgrid.WorldMatrix = newGridWorldMatrix; MyLogger.Log($"TPCore: TeleportGrid: Updated WorldMatrix for subgrid {subgrid.DisplayName} (EntityId: {subgrid.EntityId}), New World Matrix: {newGridWorldMatrix}"); var physics = subgrid.Physics; - if (physics != null) - { + if (physics != null) { physics.LinearVelocity = Vector3D.Zero; physics.AngularVelocity = Vector3D.Zero; physics.Gravity = mainPhysics?.Gravity ?? Vector3.Zero; @@ -303,8 +263,7 @@ private static void TeleportGrid(IMyCubeGrid mainGrid, MatrixD newOrientation, M // Mark this subgrid as processed processedSubgrids.Add(subgrid.EntityId); } - catch (Exception ex) - { + catch (Exception ex) { MyLogger.Log($"TPCore: TeleportGrid: Exception occurred while handling subgrid {subgrid.DisplayName} (EntityId: {subgrid.EntityId}): {ex.Message}"); } } @@ -316,30 +275,25 @@ private static void TeleportGrid(IMyCubeGrid mainGrid, MatrixD newOrientation, M MyLogger.Log($"TPCore: TeleportGrid: Teleportation complete for main grid {mainGrid.DisplayName} (EntityId: {mainGrid.EntityId}) and its {subgrids.Count} subgrids"); } - public static void ClientApplyTeleportResponse(TeleportResponseMessage message) - { + public static void ClientApplyTeleportResponse(TeleportResponseMessage message) { MyLogger.Log($"TPCore: ApplyTeleport: Player {message.PlayerId}, Success {message.Success}"); - if (!message.Success) - { + if (!message.Success) { MyLogger.Log($"TPCore: ApplyTeleport: Teleport unsuccessful for player {message.PlayerId}"); return; } var player = GetPlayerById((long)message.PlayerId); - if (player == null || player.Character == null) - { + if (player == null || player.Character == null) { MyLogger.Log($"TPCore: ApplyTeleport: Player {message.PlayerId} or their character not found during teleport"); return; } // Teleport the player's controlled grid, if any var controlledEntity = player.Controller.ControlledEntity; - if (controlledEntity != null) - { + if (controlledEntity != null) { var topMostParent = controlledEntity.Entity.GetTopMostParent(); var grid = topMostParent as IMyCubeGrid; - if (grid != null) - { + if (grid != null) { MyLogger.Log($"TPCore: ApplyTeleport: Attempting to teleport ship: {grid.DisplayName}"); var shipRelativeOrientation = grid.WorldMatrix * MatrixD.Invert(player.Character.WorldMatrix); var newShipOrientation = shipRelativeOrientation * message.NewOrientation; @@ -351,8 +305,7 @@ public static void ClientApplyTeleportResponse(TeleportResponseMessage message) } } - else - { + else { // Teleport the player's character player.Character.Teleport(message.NewOrientation); player.Character.SetWorldMatrix(message.NewOrientation); @@ -360,42 +313,54 @@ public static void ClientApplyTeleportResponse(TeleportResponseMessage message) } } - public static long GetDestinationGatewayId(string link, long sourceGatewayId) - { + public static long GetDestinationGatewayId(string link, long sourceGatewayId) { List linkedGateways; - lock (_lock) - { - if (!_TeleportLinks.TryGetValue(link, out linkedGateways)) - { - MyLogger.Log($"TPCore: GetDestinationGatewayId: No linked gateways found for link {link}"); + lock (_lock) { + if (!_TeleportLinks.TryGetValue(link, out linkedGateways) || linkedGateways.Count < 2) { + MyLogger.Log($"TPCore: GetDestinationGatewayId: No valid linked gateways found for link {link}"); return 0; } } - MyLogger.Log($"TPCore: GetDestinationGatewayId: Found {linkedGateways.Count} linked gateways for link {link}"); - - if (linkedGateways.Count < 2) - { - MyLogger.Log("TPCore: GetDestinationGatewayId: At least two linked gateways are required for teleportation. Aborting."); + var sourceGateway = MyAPIGateway.Entities.GetEntityById(sourceGatewayId) as IMyCollector; + if (sourceGateway == null) { + MyLogger.Log($"TPCore: GetDestinationGatewayId: Source gateway {sourceGatewayId} not found"); return 0; } - var sourceIndex = linkedGateways.IndexOf(sourceGatewayId); - if (sourceIndex == -1) - { - MyLogger.Log($"TPCore: GetDestinationGatewayId: Source gateway {sourceGatewayId} not found in linked gateways"); - return 0; + var sourcePosition = sourceGateway.GetPosition(); + + long nearestGatewayId = 0; + double nearestDistance = double.MaxValue; + + foreach (var gatewayId in linkedGateways) { + if (gatewayId == sourceGatewayId) continue; + + var destinationGateway = MyAPIGateway.Entities.GetEntityById(gatewayId) as IMyCollector; + if (destinationGateway == null) continue; + + var distance = Vector3D.Distance(sourcePosition, destinationGateway.GetPosition()); + if (distance < nearestDistance) { + nearestDistance = distance; + nearestGatewayId = gatewayId; + } + } + + if (nearestGatewayId == 0) { + MyLogger.Log($"TPCore: GetDestinationGatewayId: No valid destination gateway found for link {link}"); } - var destIndex = (sourceIndex + 1) % linkedGateways.Count; - return linkedGateways[destIndex]; + return nearestGatewayId; } - public static int TeleportNearbyShips(IMyCollector sourceGateway, IMyCollector destGateway) - { + public static int TeleportNearbyShips(IMyCollector sourceGateway, IMyCollector destGateway) { + if (!sourceGateway.IsWorking || !destGateway.IsWorking) { + MyLogger.Log($"TPCore: TeleportNearbyShips: Source or destination gateway not functional"); + return 0; + } + var teleportGatewayLogic = sourceGateway.GameLogic.GetAs(); - if (teleportGatewayLogic == null) - { + if (teleportGatewayLogic == null) { MyLogger.Log($"TPCore: TeleportNearbyShips: TeleportGateway logic not found for source gateway {sourceGateway.EntityId}"); return 0; } @@ -414,11 +379,9 @@ public static int TeleportNearbyShips(IMyCollector sourceGateway, IMyCollector d int teleportedShipsCount = 0; - foreach (var entity in potentialEntities) - { + foreach (var entity in potentialEntities) { var grid = entity as IMyCubeGrid; - if (grid == null || grid.IsStatic || grid.EntityId == sourceGateway.CubeGrid.EntityId) - { + if (grid == null || grid.IsStatic || grid.EntityId == sourceGateway.CubeGrid.EntityId) { continue; } @@ -430,37 +393,34 @@ public static int TeleportNearbyShips(IMyCollector sourceGateway, IMyCollector d MyLogger.Log($" Sphere radius: {sphereRadius}"); // Only teleport if the grid's center is within the sphere - if (distanceToSphereCenter > sphereRadius) - { + if (distanceToSphereCenter > sphereRadius) { MyLogger.Log($" Grid is outside the teleport sphere, skipping"); continue; } - if (IsControlledByPlayer(grid)) - { + if (IsControlledByPlayer(grid)) { MyLogger.Log($" Grid is controlled by a player, skipping"); continue; } - if (IsSubgridOrConnectedToLargerGrid(grid)) - { + if (IsSubgridOrConnectedToLargerGrid(grid)) { MyLogger.Log($" Grid is a subgrid or connected to a larger grid, skipping"); continue; } - if (HasLockedLandingGear(grid)) - { + if (HasLockedLandingGear(grid)) { MyLogger.Log($" Grid has locked landing gear, skipping"); continue; } - if (!teleportGatewayLogic.Settings.AllowShips) - { + if (!teleportGatewayLogic.Settings.AllowShips) { MyLogger.Log($" Ship teleportation is not allowed for this gateway, skipping"); continue; } + // Teleport the ship and play effects at its position TeleportEntity(grid, sourceGateway, destGateway); + PlayEffectsAtPosition(grid.GetPosition()); // Play particle and sound effects at the ship's position MyLogger.Log($" Teleported grid {grid.DisplayName}"); teleportedShipsCount++; } @@ -469,24 +429,26 @@ public static int TeleportNearbyShips(IMyCollector sourceGateway, IMyCollector d return teleportedShipsCount; } - private static bool IsControlledByPlayer(IMyCubeGrid grid) - { + // Separate method to play effects at a specific position + private static void PlayEffectsAtPosition(Vector3D position) { + MyVisualScriptLogicProvider.CreateParticleEffectAtPosition("TeleportEntityEffect", position); + MyVisualScriptLogicProvider.PlaySingleSoundAtPosition("TeleportEntitySound", position); + } + + private static bool IsControlledByPlayer(IMyCubeGrid grid) { var blocks = new List(); grid.GetBlocks(blocks); - foreach (var block in blocks) - { + foreach (var block in blocks) { var controller = block.FatBlock as IMyShipController; - if (controller != null && controller.Pilot != null) - { + if (controller != null && controller.Pilot != null) { return true; } } return false; } - private static bool IsSubgridOrConnectedToLargerGrid(IMyCubeGrid grid) - { + private static bool IsSubgridOrConnectedToLargerGrid(IMyCubeGrid grid) { // Get the group of grids the current grid is part of var group = MyAPIGateway.GridGroups.GetGroup(grid, GridLinkTypeEnum.Physical); @@ -494,11 +456,9 @@ private static bool IsSubgridOrConnectedToLargerGrid(IMyCubeGrid grid) IMyCubeGrid largestGrid = null; int largestBlockCount = 0; - foreach (var g in group) - { + foreach (var g in group) { var myGrid = g as MyCubeGrid; - if (myGrid != null && myGrid.BlocksCount > largestBlockCount) - { + if (myGrid != null && myGrid.BlocksCount > largestBlockCount) { largestGrid = myGrid; largestBlockCount = myGrid.BlocksCount; } @@ -508,16 +468,13 @@ private static bool IsSubgridOrConnectedToLargerGrid(IMyCubeGrid grid) return largestGrid != null && largestGrid.EntityId != grid.EntityId; } - private static bool HasLockedLandingGear(IMyCubeGrid grid) - { + private static bool HasLockedLandingGear(IMyCubeGrid grid) { List landingGears = new List(); grid.GetBlocks(landingGears, b => b.FatBlock is SpaceEngineers.Game.ModAPI.Ingame.IMyLandingGear); - foreach (var gear in landingGears) - { + foreach (var gear in landingGears) { var landingGear = gear.FatBlock as SpaceEngineers.Game.ModAPI.Ingame.IMyLandingGear; - if (landingGear != null && landingGear.IsLocked) - { + if (landingGear != null && landingGear.IsLocked) { return true; } } @@ -525,8 +482,7 @@ private static bool HasLockedLandingGear(IMyCubeGrid grid) return false; } - private static IMyPlayer GetPlayerById(long playerId) - { + private static IMyPlayer GetPlayerById(long playerId) { var playerList = new List(); MyAPIGateway.Players.GetPlayers(playerList); return playerList.Find(p => p.IdentityId == playerId); diff --git a/Ringway/Data/Scripts/TeleportGateway/TeleportGateway.cs b/Ringway/Data/Scripts/TeleportGateway/TeleportGateway.cs index 936a33a4..9571a964 100644 --- a/Ringway/Data/Scripts/TeleportGateway/TeleportGateway.cs +++ b/Ringway/Data/Scripts/TeleportGateway/TeleportGateway.cs @@ -11,16 +11,23 @@ using VRage.Game.ModAPI; using VRage.Game; using System; +using Sandbox.Game; using Sandbox.Game.EntityComponents; using VRage.ModAPI; - -namespace TeleportMechanisms -{ - [MyEntityComponentDescriptor(typeof(MyObjectBuilder_Collector), false, "RingwayCore", "RingwayCoreSmall")] - public class TeleportGateway : MyGameLogicComponent - { - public IMyCollector Block { get; private set; } +using Sandbox.ModAPI.Ingame; +using IMyShipController = Sandbox.ModAPI.IMyShipController; +using IMyCollector = Sandbox.ModAPI.IMyCollector; +using Sandbox.Game.GameSystems.Electricity; +using VRage.Game.ObjectBuilders.Definitions; +using IMyTerminalBlock = Sandbox.ModAPI.IMyTerminalBlock; +using VRage.Noise.Patterns; + +namespace TeleportMechanisms { + [MyEntityComponentDescriptor(typeof(MyObjectBuilder_Collector), false, + "RingwayCore", "SmallRingwayCore")] + public class TeleportGateway : MyGameLogicComponent { public TeleportGatewaySettings Settings { get; private set; } = new TeleportGatewaySettings(); + public IMyCollector RingwayBlock; private static bool _controlsCreated = false; private static readonly Guid StorageGuid = new Guid("7F995845-BCEF-4E37-9B47-A035AC2A8E0B"); @@ -28,160 +35,480 @@ public class TeleportGateway : MyGameLogicComponent private const int SAVE_INTERVAL_FRAMES = 100; private int _frameCounter = 0; - static TeleportGateway() - { + private int _linkUpdateCounter = 0; + private const int LINK_UPDATE_INTERVAL = 1; + + private const float CHARGE_RATE = 1.0f; // 0.5 MWh per second when charging + private MyResourceSinkComponent Sink = null; + private bool _isTeleporting = false; + private int _teleportCountdown = 0; + private double _jumpDistance = 0; + + private const float POWER_THRESHOLD = 0.1f; // 10% power threshold for failure + private const float BASE_COUNTDOWN_SECONDS = 5; // Minimum countdown time + private const float SECONDS_PER_100KM = 0.1f; // Additional second per 100km + private const float POWER_PER_100KM = 1.0f; // 1 MWh per 100km + private const float MIN_TELEPORT_CHARGE_PERCENTAGE = 0.1f; // 10% charge threshold + + private const double MAX_TELEPORT_DISTANCE = 1000000.0 * 1000; // 1,000,000 km in meters + private static MyParticleEffect teleportEffect; + + static TeleportGateway() { CreateControls(); } - public override void Init(MyObjectBuilder_EntityBase objectBuilder) - { - base.Init(objectBuilder); - - Block = Entity as IMyCollector; - if (Block == null) - { - MyLogger.Log($"TPGate: Init: Entity is not a terminal block. EntityId: {Entity?.EntityId}"); + public override void Init(MyObjectBuilder_EntityBase objectBuilder) { + RingwayBlock = Entity as IMyCollector; + if (RingwayBlock == null) { + MyLogger.Log($"TPGate: Init: Entity is not an upgrade module. EntityId: {Entity?.EntityId}"); return; } - Settings = Load(Block); - MyLogger.Log($"TPGate: Init: Initialized for EntityId: {Block.EntityId}, GatewayName: {Settings.GatewayName}"); + Settings = Load(RingwayBlock); + RingwayBlock.AppendingCustomInfo += AppendingCustomInfo; - CreateControls(); + // Initialize power sink for charging + Sink = RingwayBlock.Components.Get(); + if (Sink != null) { + Sink.SetRequiredInputFuncByType(MyResourceDistributorComponent.ElectricityId, ComputeRequiredPower); + } - lock (TeleportCore._lock) - { - TeleportCore._instances[Block.EntityId] = this; - MyLogger.Log($"TPGate: Init: Added instance for EntityId {Entity.EntityId}. Total instances: {TeleportCore._instances.Count}"); + NeedsUpdate |= MyEntityUpdateEnum.EACH_FRAME; + NeedsUpdate |= MyEntityUpdateEnum.EACH_10TH_FRAME; + NeedsUpdate |= MyEntityUpdateEnum.EACH_100TH_FRAME; + + lock (TeleportCore._lock) { + TeleportCore._instances[RingwayBlock.EntityId] = this; + } + } + + private float ComputeRequiredPower() { + if (!RingwayBlock.IsWorking) return 0f; + + // When not teleporting, draw power to charge + if (!_isTeleporting) { + if (Settings.StoredPower < Settings.MaxStoredPower) { + return CHARGE_RATE * 1000f; // Convert to watts + } + + return 0f; } - NeedsUpdate = MyEntityUpdateEnum.EACH_FRAME; + // During teleport, draw a massive amount of power + float powerRequired = CalculatePowerRequired(_jumpDistance); + float powerPerSecond = powerRequired / (_teleportCountdown / 60f); + return powerPerSecond * 1000f; // Convert to watts } - public override void UpdateAfterSimulation() - { + private void AppendingCustomInfo(IMyTerminalBlock block, StringBuilder sb) { + try { + if (!block.IsWorking) { + sb.Append("--- Gateway Offline ---\n"); + sb.Append("The gateway is not functional. Check power and block integrity.\n"); + return; + } + + sb.Append("--- Teleport Gateway Status ---\n"); + + if (Sink != null) { + float currentStoredPower = (float)Settings.StoredPower; + float maxStoredPower = Settings.MaxStoredPower; + float chargePercentage = (currentStoredPower / maxStoredPower) * 100f; + + // Display power level + sb.Append($"Charge: {chargePercentage:F1}% ({currentStoredPower:F2}/{maxStoredPower:F2} MWh)\n"); + sb.Append($"Minimum Charge for Teleport: {MIN_TELEPORT_CHARGE_PERCENTAGE * 100}%\n"); + + // Status based on charging and power availability + if (_isTeleporting) { + sb.Append("Status: Teleporting...\n"); + } + else if (Settings.StoredPower >= maxStoredPower) { + sb.Append("Status: Fully Charged - Ready to Jump\n"); + } + else if (Sink.IsPowerAvailable(MyResourceDistributorComponent.ElectricityId, CHARGE_RATE * 1000f)) { + sb.Append("Status: Charging...\n"); + + float remainingPower = maxStoredPower - currentStoredPower; + float timeToFullCharge = remainingPower / CHARGE_RATE; // in seconds + sb.Append($"Time to Full Charge: {timeToFullCharge:F1} seconds\n"); + } + else { + sb.Append("Status: Insufficient Power for Charging\n"); + sb.Append("Check reactor output or power supply.\n"); + } + + // Warning if power level is low and teleport cannot proceed + if (Settings.StoredPower < maxStoredPower * POWER_THRESHOLD && !_isTeleporting) { + sb.Append("Warning: Power below safe teleport threshold\n"); + sb.Append("Charge to at least 10% to ensure successful teleport.\n"); + } + } + + // Display linked gateways info (unchanged) + var linkedGateways = TeleportCore._TeleportLinks.ContainsKey(Settings.GatewayName) + ? TeleportCore._TeleportLinks[Settings.GatewayName] + : new List(); + int linkedCount = linkedGateways.Count; + sb.Append($"Linked Gateways: {linkedCount}\n"); + + if (linkedCount > 2) { + sb.Append($"WARNING: More than two gateways on channel '{Settings.GatewayName}'.\n"); + sb.Append(" Only the nearest gateway will be used.\n"); + } + + if (linkedCount > 0) { + sb.Append("Linked To:\n"); + var sourcePosition = RingwayBlock.GetPosition(); + + IMyCollector nearestGateway = null; + double nearestDistance = double.MaxValue; + + foreach (var gatewayId in linkedGateways) { + if (gatewayId != RingwayBlock.EntityId) { + var linkedGateway = MyAPIGateway.Entities.GetEntityById(gatewayId) as IMyCollector; + if (linkedGateway != null) { + var distance = Vector3D.Distance(sourcePosition, linkedGateway.GetPosition()); + string distanceStr = $"{distance / 1000:F1} km"; + + if (distance < nearestDistance) { + nearestDistance = distance; + nearestGateway = linkedGateway; + } + + sb.Append($" - {linkedGateway.CustomName}: {distanceStr}\n"); + } + else { + sb.Append($" - Unknown (ID: {gatewayId})\n"); + } + } + } + + if (nearestGateway != null && linkedCount > 1) { + sb.Append($"Active Destination: {nearestGateway.CustomName}\n"); + } + } + else { + sb.Append("Status: Not linked to any other gateways\n"); + } + + // Settings Info (unchanged) + sb.Append($"Allow Players: {(Settings.AllowPlayers ? "Yes" : "No")}\n"); + sb.Append($"Allow Ships: {(Settings.AllowShips ? "Yes" : "No")}\n"); + sb.Append($"Show Sphere: {(Settings.ShowSphere ? "Yes" : "No")}\n"); + sb.Append($"Sphere Diameter: {Settings.SphereDiameter} m\n"); + + } + catch (Exception e) { + MyLog.Default.WriteLineAndConsole($"Error in AppendingCustomInfo: {e}"); + } + } + + public override void UpdateOnceBeforeFrame() { + try { + base.UpdateOnceBeforeFrame(); + if (RingwayBlock?.CubeGrid?.Physics == null) + return; + + Sink = RingwayBlock.Components.Get(); + if (Sink != null) { + var powerReq = new MyResourceSinkInfo() { + ResourceTypeId = MyResourceDistributorComponent.ElectricityId, + MaxRequiredInput = 1000f, + RequiredInputFunc = CalculatePowerDraw + }; + Sink.AddType(ref powerReq); // This is the critical line we were missing + Sink.SetRequiredInputFuncByType(MyResourceDistributorComponent.ElectricityId, CalculatePowerDraw); + Sink.Update(); + + MyLog.Default.WriteLineAndConsole( + $"TPGate: UpdateOnceBeforeFrame: Initialized power sink for {RingwayBlock.EntityId}"); + } + + NeedsUpdate |= MyEntityUpdateEnum.EACH_FRAME; + NeedsUpdate |= MyEntityUpdateEnum.EACH_10TH_FRAME; + } + catch (Exception e) { + MyLog.Default.WriteLineAndConsole($"Ringway.UpdateOnceBeforeFrame: {e}"); + } + } + + private float CalculatePowerDraw() { + if (!RingwayBlock.IsWorking) return 0f; + if (_isTeleporting) { + float powerRequired = CalculatePowerRequired(_jumpDistance); + return (powerRequired / (_teleportCountdown / 60f)) * 1000f; + } + + return Settings.StoredPower < Settings.MaxStoredPower ? CHARGE_RATE * 1000f : 0f; + } + + private float _targetPowerDrain = 0f; + private float _initialPower; + private bool _showSphereDuringCountdown; + + public override void UpdateAfterSimulation() { base.UpdateAfterSimulation(); - if (++_frameCounter >= SAVE_INTERVAL_FRAMES) - { + if (RingwayBlock == null) return; + + // Draw a debug line to the nearest linked gateway, if one exists + DrawDebugLineToNearestLinkedGateway(); + + // Retrieve destination position for teleport effects + var destGatewayId = TeleportCore.GetDestinationGatewayId(Settings.GatewayName, RingwayBlock.EntityId); + var destGateway = MyAPIGateway.Entities.GetEntityById(destGatewayId) as IMyCollector; + Vector3D destinationPosition = destGateway?.GetPosition() ?? Vector3D.Zero; + + if (_isTeleporting) { + if (_teleportCountdown > 0) { + _teleportCountdown--; + + // Show countdown text notification each second + if (_teleportCountdown % 60 == 0) { + int secondsLeft = _teleportCountdown / 60; + NotifyPlayersInRange( + $"Jump in {secondsLeft}s... Distance: {_jumpDistance / 1000:F1}km", + RingwayBlock.GetPosition(), + 100, + "White" + ); + } + + // Render the sphere in transparent yellow during countdown + if (Settings.ShowSphere) { + Color countdownColor = new Color(255, 255, 0, 10); // Yellow with transparency + TeleportBubbleManager.CreateOrUpdateBubble(RingwayBlock, countdownColor); + TeleportBubbleManager.DrawBubble(RingwayBlock, countdownColor); + } + + return; + } + + // Teleportation completion + float powerRequired = CalculatePowerRequired(_jumpDistance); + Settings.StoredPower = Math.Max(0, Settings.StoredPower - powerRequired); + Settings.Changed = true; + + NotifyPlayersInRange( + $"Jump completed to destination {_jumpDistance / 1000:F1}km away.", + RingwayBlock.GetPosition(), + 100, + "White" + ); + + _isTeleporting = false; + _showSphereDuringCountdown = false; + + if (!MyAPIGateway.Multiplayer.IsServer) { + var message = new JumpRequestMessage { + GatewayId = RingwayBlock.EntityId, + Link = Settings.GatewayName + }; + MyAPIGateway.Multiplayer.SendMessageToServer( + NetworkHandler.JumpRequestId, + MyAPIGateway.Utilities.SerializeToBinary(message) + ); + } + else { + ProcessJumpRequest(RingwayBlock.EntityId, Settings.GatewayName); + } + } + else { + if (RingwayBlock.IsWorking && Settings.StoredPower < Settings.MaxStoredPower) { + if (Sink != null && Sink.IsPowerAvailable(MyResourceDistributorComponent.ElectricityId, CHARGE_RATE * 1000f)) { + if (Settings.StoredPower == 0) { + // Charging started - can handle any non-particle effects here if needed + } + + // Increment stored power as part of the charging process + Settings.StoredPower = Math.Min(Settings.MaxStoredPower, Settings.StoredPower + (CHARGE_RATE / 60f)); + Settings.Changed = true; + Sink.SetRequiredInputByType(MyResourceDistributorComponent.ElectricityId, CHARGE_RATE * 1000f); + Sink.Update(); + } + else { + Sink?.SetRequiredInputByType(MyResourceDistributorComponent.ElectricityId, 0f); + Sink?.Update(); + } + } + } + + // Save settings periodically + if (++_frameCounter >= SAVE_INTERVAL_FRAMES) { _frameCounter = 0; TrySave(); } - // Only update and draw the bubble if we're not on a dedicated server and the session is available - if (!MyAPIGateway.Utilities.IsDedicated && MyAPIGateway.Session != null) - { - TeleportBubbleManager.CreateOrUpdateBubble(Block); - TeleportBubbleManager.DrawBubble(Block); + if (MyAPIGateway.Gui.GetCurrentScreen == MyTerminalPageEnum.ControlPanel) { + RingwayBlock.RefreshCustomInfo(); + RingwayBlock.SetDetailedInfoDirty(); + } + + // Display teleport bubble if in a client session + if (!MyAPIGateway.Utilities.IsDedicated && MyAPIGateway.Session != null) { + if (!_showSphereDuringCountdown && Settings.ShowSphere) { + Color defaultColor = new Color(0, 0, 255, 10); // Blue with transparency + TeleportBubbleManager.CreateOrUpdateBubble(RingwayBlock, defaultColor); + TeleportBubbleManager.DrawBubble(RingwayBlock, defaultColor); + } } } - private void TrySave() - { + public override void UpdateAfterSimulation100() { + if (!RingwayBlock.IsWorking) return; + + try { + + // New link update logic + if (++_linkUpdateCounter >= LINK_UPDATE_INTERVAL) { + _linkUpdateCounter = 0; + TeleportCore.UpdateTeleportLinks(); + MyLogger.Log("TPGate: UpdateAfterSimulation100: Updated teleport links"); + } + + // Refresh custom info only when the terminal is open + if (MyAPIGateway.Gui.GetCurrentScreen == MyTerminalPageEnum.ControlPanel) { + RingwayBlock.RefreshCustomInfo(); + RingwayBlock.SetDetailedInfoDirty(); + } + } + catch (Exception e) { + MyLogger.Log($"TPGate: UpdateAfterSimulation100: Exception - {e}"); + } + } + + private void TrySave() { if (!Settings.Changed) return; Save(); - MyLogger.Log($"TPGate: TrySave: Settings saved for EntityId: {Block.EntityId}"); + MyLogger.Log($"TPGate: TrySave: Settings saved for EntityId: {RingwayBlock.EntityId}"); } - private void Save() - { - if (Block.Storage == null) - { - Block.Storage = new MyModStorageComponent(); + private void Save() { + if (RingwayBlock.Storage == null) { + RingwayBlock.Storage = new MyModStorageComponent(); } string serializedData = MyAPIGateway.Utilities.SerializeToXML(Settings); - Block.Storage.SetValue(StorageGuid, serializedData); + RingwayBlock.Storage.SetValue(StorageGuid, serializedData); // Send the updated settings to the server - var message = new SyncSettingsMessage { EntityId = Block.EntityId, Settings = this.Settings }; + var message = new SyncSettingsMessage { EntityId = RingwayBlock.EntityId, Settings = this.Settings }; var data = MyAPIGateway.Utilities.SerializeToBinary(message); MyAPIGateway.Multiplayer.SendMessageToServer(NetworkHandler.SyncSettingsId, data); Settings.Changed = false; Settings.LastSaved = MyAPIGateway.Session.ElapsedPlayTime; - MyLogger.Log($"TPGate: Save: Settings saved for EntityId: {Block.EntityId}"); + MyLogger.Log($"TPGate: Save: Settings saved for EntityId: {RingwayBlock.EntityId}"); } - public void ApplySettings(TeleportGatewaySettings settings) - { + public void ApplySettings(TeleportGatewaySettings settings) { this.Settings = settings; - MyLogger.Log($"TPGate: ApplySettings: Applied settings for EntityId: {Block.EntityId}, GatewayName: {Settings.GatewayName}"); + MyLogger.Log( + $"TPGate: ApplySettings: Applied settings for EntityId: {RingwayBlock.EntityId}, GatewayName: {Settings.GatewayName}"); } - private static TeleportGatewaySettings Load(IMyCollector block) - { + private static TeleportGatewaySettings Load(IMyCollector block) { MyLogger.Log($"TPGate: Load: Called. Attempting to load with StorageGuid: {StorageGuid}"); - if (block == null) - { - MyLogger.Log($"TPGate: Load: Block is null."); + if (block == null) { + MyLogger.Log($"TPGate: Load: RingwayBlock is null."); return new TeleportGatewaySettings(); } - if (block.Storage == null) - { - MyLogger.Log($"TPGate: Load: Block Storage is null. Creating new Storage."); + + if (block.Storage == null) { + MyLogger.Log($"TPGate: Load: RingwayBlock Storage is null. Creating new Storage."); block.Storage = new MyModStorageComponent(); } - MyLogger.Log($"TPGate: Load: Block and Storage not null."); + + MyLogger.Log($"TPGate: Load: RingwayBlock and Storage not null."); string data; - if (block.Storage.TryGetValue(StorageGuid, out data)) - { + if (block.Storage.TryGetValue(StorageGuid, out data)) { MyLogger.Log($"TPGate: Load: blockid:{block.EntityId} Storage had data: {data}"); - try - { + try { var settings = MyAPIGateway.Utilities.SerializeFromXML(data); - if (settings != null) - { + if (settings != null) { settings.Changed = false; settings.LastSaved = MyAPIGateway.Session.ElapsedPlayTime; MyLogger.Log($"TPGate: Load: Successfully loaded settings."); return settings; } - else - { + else { MyLogger.Log($"TPGate: Load: Deserialized settings were null."); } } - catch (Exception ex) - { + catch (Exception ex) { MyLogger.Log($"TPGate: Load - Exception loading settings: {ex}"); } } - else - { + else { MyLogger.Log($"TPGate: Load: No data found for StorageGuid."); } + MyLogger.Log($"TPGate: Load: Creating and returning new TeleportGatewaySettings."); var newSettings = new TeleportGatewaySettings(); newSettings.Changed = true; // Mark as changed so it will be saved return newSettings; } - public override void Close() - { + public override void Close() { Save(); - lock (TeleportCore._lock) - { - TeleportCore._instances.Remove(Block.EntityId); - MyLogger.Log($"TPGate: Close: Removed instance for EntityId {Entity.EntityId}. Remaining instances: {TeleportCore._instances.Count}"); + lock (TeleportCore._lock) { + TeleportCore._instances.Remove(RingwayBlock.EntityId); + MyLogger.Log( + $"TPGate: Close: Removed instance for EntityId {Entity.EntityId}. Remaining instances: {TeleportCore._instances.Count}"); } - TeleportBubbleManager.RemoveBubble(Block); + TeleportBubbleManager.RemoveBubble(RingwayBlock); base.Close(); } - public override bool IsSerialized() - { + private void DrawDebugLineToNearestLinkedGateway() { + // Check if there are linked gateways for the current gateway + List linkedGateways; + if (!TeleportCore._TeleportLinks.TryGetValue(Settings.GatewayName, out linkedGateways) || + linkedGateways.Count <= 1) { + return; // No links or only linked to itself + } + + Vector3D sourcePosition = RingwayBlock.GetPosition(); + IMyCollector nearestGateway = null; + double nearestDistance = double.MaxValue; + + foreach (var gatewayId in linkedGateways) { + if (gatewayId == RingwayBlock.EntityId) continue; // Skip self + + var linkedGateway = MyAPIGateway.Entities.GetEntityById(gatewayId) as IMyCollector; + if (linkedGateway != null) { + double distance = Vector3D.Distance(sourcePosition, linkedGateway.GetPosition()); + if (distance < nearestDistance) { + nearestDistance = distance; + nearestGateway = linkedGateway; + } + } + } + + // Draw the line if a nearest gateway was found + if (nearestGateway != null) { + Vector3D destinationPosition = nearestGateway.GetPosition(); + Vector4 green = Color.Green; + if (!MyAPIGateway.Utilities.IsDedicated) { + MySimpleObjectDraw.DrawLine(sourcePosition, destinationPosition, MyStringId.GetOrCompute("Square"), + ref green, 0.1f); + } + } + } + + + public override bool IsSerialized() { Save(); return base.IsSerialized(); } - private static void CreateControls() - { + private static void CreateControls() { if (_controlsCreated) return; MyLogger.Log("TPGate: CreateControl: Creating custom controls and actions"); @@ -198,24 +525,22 @@ private static void CreateControls() var actions = new List { - CreateJumpAction(), - CreateToggleShowSphereAction(), - CreateShowSphereOnAction(), - CreateShowSphereOffAction() + CreateJumpAction(), + CreateToggleShowSphereAction(), + CreateShowSphereOnAction(), + CreateShowSphereOffAction() }; - MyAPIGateway.TerminalControls.CustomControlGetter += (block, blockControls) => - { - if (block is IMyCollector && (block.BlockDefinition.SubtypeName == "RingwayCore" || block.BlockDefinition.SubtypeName == "RingwayCoreSmall")) - { + MyAPIGateway.TerminalControls.CustomControlGetter += (block, blockControls) => { + if (block is IMyCollector && (block.BlockDefinition.SubtypeName == "RingwayCore" || + block.BlockDefinition.SubtypeName == "SmallRingwayCore")) { blockControls.AddRange(controls); } }; - MyAPIGateway.TerminalControls.CustomActionGetter += (block, blockActions) => - { - if (block is IMyCollector && (block.BlockDefinition.SubtypeName == "RingwayCore" || block.BlockDefinition.SubtypeName == "RingwayCoreSmall")) - { + MyAPIGateway.TerminalControls.CustomActionGetter += (block, blockActions) => { + if (block is IMyCollector && (block.BlockDefinition.SubtypeName == "RingwayCore" || + block.BlockDefinition.SubtypeName == "SmallRingwayCore")) { blockActions.AddRange(actions); } }; @@ -224,20 +549,17 @@ private static void CreateControls() MyLogger.Log("TPGate: CreateControl: Custom controls and actions created"); } - private static IMyTerminalControl CreateGatewayNameControl() - { - var control = MyAPIGateway.TerminalControls.CreateControl("GatewayName"); + private static IMyTerminalControl CreateGatewayNameControl() { + var control = + MyAPIGateway.TerminalControls.CreateControl("GatewayName"); control.Title = MyStringId.GetOrCompute("Gateway Name"); - control.Getter = (block) => - { + control.Getter = (block) => { var gateway = block.GameLogic.GetAs(); return gateway != null ? new StringBuilder(gateway.Settings.GatewayName) : new StringBuilder(); }; - control.Setter = (block, value) => - { + control.Setter = (block, value) => { var gateway = block.GameLogic.GetAs(); - if (gateway != null) - { + if (gateway != null) { gateway.Settings.GatewayName = value.ToString(); gateway.Settings.Changed = true; gateway.TrySave(); @@ -247,20 +569,17 @@ private static IMyTerminalControl CreateGatewayNameControl() return control; } - private static IMyTerminalControl CreateAllowPlayersCheckbox() - { - var control = MyAPIGateway.TerminalControls.CreateControl("AllowPlayers"); + private static IMyTerminalControl CreateAllowPlayersCheckbox() { + var control = + MyAPIGateway.TerminalControls.CreateControl("AllowPlayers"); control.Title = MyStringId.GetOrCompute("Allow Players"); - control.Getter = (block) => - { + control.Getter = (block) => { var gateway = block.GameLogic.GetAs(); return gateway != null ? gateway.Settings.AllowPlayers : false; }; - control.Setter = (block, value) => - { + control.Setter = (block, value) => { var gateway = block.GameLogic.GetAs(); - if (gateway != null) - { + if (gateway != null) { gateway.Settings.AllowPlayers = value; gateway.Settings.Changed = true; gateway.TrySave(); @@ -271,20 +590,17 @@ private static IMyTerminalControl CreateAllowPlayersCheckbox() return control; } - private static IMyTerminalControl CreateAllowShipsCheckbox() - { - var control = MyAPIGateway.TerminalControls.CreateControl("AllowShips"); + private static IMyTerminalControl CreateAllowShipsCheckbox() { + var control = + MyAPIGateway.TerminalControls.CreateControl("AllowShips"); control.Title = MyStringId.GetOrCompute("Allow Ships"); - control.Getter = (block) => - { + control.Getter = (block) => { var gateway = block.GameLogic.GetAs(); return gateway != null ? gateway.Settings.AllowShips : false; }; - control.Setter = (block, value) => - { + control.Setter = (block, value) => { var gateway = block.GameLogic.GetAs(); - if (gateway != null) - { + if (gateway != null) { gateway.Settings.AllowShips = value; gateway.Settings.Changed = true; gateway.TrySave(); @@ -295,26 +611,23 @@ private static IMyTerminalControl CreateAllowShipsCheckbox() return control; } - private static IMyTerminalControl CreateJumpButton() - { - var control = MyAPIGateway.TerminalControls.CreateControl("JumpButton"); + private static IMyTerminalControl CreateJumpButton() { + var control = + MyAPIGateway.TerminalControls.CreateControl("JumpButton"); control.Title = MyStringId.GetOrCompute("Jump"); control.Visible = (block) => true; - control.Action = (block) => - { + control.Action = (block) => { var gateway = block.GameLogic.GetAs(); if (gateway != null) gateway.JumpAction(block as IMyCollector); }; return control; } - private static IMyTerminalAction CreateJumpAction() - { + private static IMyTerminalAction CreateJumpAction() { var action = MyAPIGateway.TerminalControls.CreateAction("Jump"); action.Name = new StringBuilder("Jump"); action.Icon = @"Textures\GUI\Icons\Actions\Jump.dds"; - action.Action = (block) => - { + action.Action = (block) => { var gateway = block.GameLogic.GetAs(); if (gateway != null) gateway.JumpAction(block as IMyCollector); }; @@ -322,20 +635,17 @@ private static IMyTerminalAction CreateJumpAction() return action; } - private static IMyTerminalControl CreateShowSphereCheckbox() - { - var control = MyAPIGateway.TerminalControls.CreateControl("ShowSphere"); + private static IMyTerminalControl CreateShowSphereCheckbox() { + var control = + MyAPIGateway.TerminalControls.CreateControl("ShowSphere"); control.Title = MyStringId.GetOrCompute("Show Sphere"); - control.Getter = (block) => - { + control.Getter = (block) => { var gateway = block.GameLogic.GetAs(); return gateway != null ? gateway.Settings.ShowSphere : false; }; - control.Setter = (block, value) => - { + control.Setter = (block, value) => { var gateway = block.GameLogic.GetAs(); - if (gateway != null) - { + if (gateway != null) { gateway.Settings.ShowSphere = value; gateway.Settings.Changed = true; gateway.TrySave(); @@ -346,31 +656,26 @@ private static IMyTerminalControl CreateShowSphereCheckbox() return control; } - private static IMyTerminalControl CreateSphereDiameterSlider() - { - var control = MyAPIGateway.TerminalControls.CreateControl("SphereDiameter"); + private static IMyTerminalControl CreateSphereDiameterSlider() { + var control = + MyAPIGateway.TerminalControls.CreateControl("SphereDiameter"); control.Title = MyStringId.GetOrCompute("Sphere Diameter"); - control.SetLimits(1, 300); // Set the range from 1 to 300 - control.Getter = (block) => - { + control.SetLimits(1, 100); // Set the range from 1 to 300 + control.Getter = (block) => { var gateway = block.GameLogic.GetAs(); return gateway != null ? gateway.Settings.SphereDiameter : 50.0f; }; - control.Setter = (block, value) => - { + control.Setter = (block, value) => { var gateway = block.GameLogic.GetAs(); - if (gateway != null) - { + if (gateway != null) { gateway.Settings.SphereDiameter = value; gateway.Settings.Changed = true; gateway.TrySave(); } }; - control.Writer = (block, sb) => - { + control.Writer = (block, sb) => { var gateway = block.GameLogic.GetAs(); - if (gateway != null) - { + if (gateway != null) { sb.Append($"{gateway.Settings.SphereDiameter} meters"); } }; @@ -378,36 +683,33 @@ private static IMyTerminalControl CreateSphereDiameterSlider() return control; } - private static IMyTerminalAction CreateToggleShowSphereAction() - { + private static IMyTerminalAction CreateToggleShowSphereAction() { var action = MyAPIGateway.TerminalControls.CreateAction("ToggleShowSphere"); action.Name = new StringBuilder("Toggle Show Sphere"); action.Icon = @"Textures\GUI\Icons\Actions\SwitchOn.dds"; // You may want to use a different icon - action.Action = (block) => - { + action.Action = (block) => { var gateway = block.GameLogic.GetAs(); - if (gateway != null) - { + if (gateway != null) { gateway.Settings.ShowSphere = !gateway.Settings.ShowSphere; gateway.Settings.Changed = true; gateway.TrySave(); - MyLogger.Log($"TPGate: ShowSphere toggled to {gateway.Settings.ShowSphere} for EntityId: {block.EntityId}"); + MyLogger.Log( + $"TPGate: ShowSphere toggled to {gateway.Settings.ShowSphere} for EntityId: {block.EntityId}"); } }; - action.Writer = (b, sb) => sb.Append(b.GameLogic.GetAs()?.Settings.ShowSphere == true ? "Hide Sphere" : "Show Sphere"); + action.Writer = (b, sb) => sb.Append(b.GameLogic.GetAs()?.Settings.ShowSphere == true + ? "Hide Sphere" + : "Show Sphere"); return action; } - private static IMyTerminalAction CreateShowSphereOnAction() - { + private static IMyTerminalAction CreateShowSphereOnAction() { var action = MyAPIGateway.TerminalControls.CreateAction("ShowSphereOn"); action.Name = new StringBuilder("Show Sphere On"); action.Icon = @"Textures\GUI\Icons\Actions\SwitchOn.dds"; // You may want to use a different icon - action.Action = (block) => - { + action.Action = (block) => { var gateway = block.GameLogic.GetAs(); - if (gateway != null) - { + if (gateway != null) { gateway.Settings.ShowSphere = true; gateway.Settings.Changed = true; gateway.TrySave(); @@ -418,16 +720,13 @@ private static IMyTerminalAction CreateShowSphereOnAction() return action; } - private static IMyTerminalAction CreateShowSphereOffAction() - { + private static IMyTerminalAction CreateShowSphereOffAction() { var action = MyAPIGateway.TerminalControls.CreateAction("ShowSphereOff"); action.Name = new StringBuilder("Show Sphere Off"); action.Icon = @"Textures\GUI\Icons\Actions\SwitchOff.dds"; // You may want to use a different icon - action.Action = (block) => - { + action.Action = (block) => { var gateway = block.GameLogic.GetAs(); - if (gateway != null) - { + if (gateway != null) { gateway.Settings.ShowSphere = false; gateway.Settings.Changed = true; gateway.TrySave(); @@ -438,38 +737,112 @@ private static IMyTerminalAction CreateShowSphereOffAction() return action; } + private int CalculateCountdown(double distanceInMeters) { + float distanceInKm = (float)(distanceInMeters / 1000); + float additionalSeconds = (distanceInKm / 100) * SECONDS_PER_100KM; + float totalSeconds = Math.Max(BASE_COUNTDOWN_SECONDS, BASE_COUNTDOWN_SECONDS + additionalSeconds); + + return (int)(totalSeconds * 60); // Convert total time to ticks (assuming 60 ticks per second) + } + + private float CalculatePowerRequired(double distanceInMeters) + { + distanceInMeters = Math.Min(distanceInMeters, MAX_TELEPORT_DISTANCE); // Clamp distance + float distanceInKm = (float)(distanceInMeters / 1000); + float maxDistanceInKm = (float)(MAX_TELEPORT_DISTANCE / 1000); + float chargePercentage = MathHelper.Clamp(distanceInKm / maxDistanceInKm, MIN_TELEPORT_CHARGE_PERCENTAGE, 1.0f); + return Settings.MaxStoredPower * chargePercentage; + } + private void JumpAction(IMyCollector block) { MyLogger.Log($"TPGate: JumpAction: Jump action triggered for EntityId: {block.EntityId}"); var link = Settings.GatewayName; - if (string.IsNullOrEmpty(link)) return; + if (string.IsNullOrEmpty(link)) + { + MyLogger.Log($"TPGate: JumpAction: No valid link set"); + return; + } - // Instead of performing the teleport logic here, send a request to the server - if (!MyAPIGateway.Multiplayer.IsServer) + var destGatewayId = TeleportCore.GetDestinationGatewayId(link, block.EntityId); + if (destGatewayId == 0) { - MyLogger.Log($"TPGate: JumpAction: Sending jump request to server"); - var message = new JumpRequestMessage - { - GatewayId = block.EntityId, - Link = link - }; - MyAPIGateway.Multiplayer.SendMessageToServer(NetworkHandler.JumpRequestId, MyAPIGateway.Utilities.SerializeToBinary(message)); + MyLogger.Log($"TPGate: JumpAction: No valid destination gateway found"); + return; } - else + + // Calculate distance to destination + var destGateway = MyAPIGateway.Entities.GetEntityById(destGatewayId) as IMyCollector; + if (destGateway == null) return; + + _jumpDistance = Vector3D.Distance(block.GetPosition(), destGateway.GetPosition()); + + // Enforce the maximum distance restriction + if (_jumpDistance > MAX_TELEPORT_DISTANCE) { - // If we are the server, process the jump directly - ProcessJumpRequest(block.EntityId, link); + MyLogger.Log($"TPGate: JumpAction: Jump distance {_jumpDistance / 1000:F1}km exceeds maximum allowed distance {MAX_TELEPORT_DISTANCE / 1000:F1}km."); + NotifyPlayersInRange( + $"Jump distance {_jumpDistance / 1000:F1}km exceeds maximum allowed range of {MAX_TELEPORT_DISTANCE / 1000:F1}km.", + block.GetPosition(), + 100, + "Red" + ); + return; } + + float powerRequired = CalculatePowerRequired(_jumpDistance); + MyLogger.Log( + $"TPGate: JumpAction: Distance: {_jumpDistance / 1000:F1}km, Power Required: {powerRequired:F1}MWh"); + + if (Settings.StoredPower < powerRequired) + { + MyLogger.Log( + $"TPGate: JumpAction: Not enough power for jump. Required: {powerRequired:F1}MWh, Available: {Settings.StoredPower:F1}MWh"); + NotifyPlayersInRange( + $"Insufficient power for {_jumpDistance / 1000:F1}km jump. Need {powerRequired:F1}MWh", + block.GetPosition(), + 100, + "Red" + ); + return; + } + + // Start teleport sequence + _isTeleporting = true; + _teleportCountdown = CalculateCountdown(_jumpDistance); // Apply calculated countdown + _initialPower = Settings.StoredPower; + + float totalSeconds = _teleportCountdown / 60f; + NotifyPlayersInRange( + $"Initiating {_jumpDistance / 1000:F1}km jump - {totalSeconds:F1} seconds", + block.GetPosition(), + 100, + "White" + ); } - // New method to process jump requests on the server - public static void ProcessJumpRequest(long gatewayId, string link) - { + private static void NotifyPlayersInRange(string text, Vector3D position, double radius, string font = "White") { + BoundingSphereD bound = new BoundingSphereD(position, radius); + List nearbyEntities = MyAPIGateway.Entities.GetEntitiesInSphere(ref bound); + + foreach (var entity in nearbyEntities) { + IMyCharacter character = entity as IMyCharacter; + if (character != null && character.IsPlayer) { + var notification = MyAPIGateway.Utilities.CreateNotification(text, 2000, font); + notification.Show(); + } + } + } + + public static void ProcessJumpRequest(long gatewayId, string link) { MyLogger.Log($"TPGate: ProcessJumpRequest: Processing jump request for gateway {gatewayId}, link {link}"); var block = MyAPIGateway.Entities.GetEntityById(gatewayId) as IMyCollector; - if (block == null) return; + if (block == null || !block.IsWorking) { + MyLogger.Log($"TPCore: ProcessJumpRequest: Gateway {gatewayId} is null or not functional"); + return; + } // Update teleport links TeleportCore.UpdateTeleportLinks(); @@ -481,17 +854,47 @@ public static void ProcessJumpRequest(long gatewayId, string link) int playersToTeleport = 0; int shipsToTeleport = 0; + // Get destination gateway + var destGatewayId = TeleportCore.GetDestinationGatewayId(link, block.EntityId); + var destGateway = MyAPIGateway.Entities.GetEntityById(destGatewayId) as IMyCollector; + if (destGateway == null) return; + + // Define the teleport sphere for range-based operations + float sphereRadius = block.GameLogic.GetAs()?.Settings.SphereDiameter / 2.0f ?? 25.0f; + Vector3D sphereCenter = block.GetPosition() + block.WorldMatrix.Forward * sphereRadius; + BoundingSphereD sphere = new BoundingSphereD(sphereCenter, sphereRadius); + + // Teleport each player in range and play effects foreach (var player in playerList) { - float sphereRadius = block.GameLogic.GetAs()?.Settings.SphereDiameter / 2.0f ?? 25.0f; - var distance = Vector3D.Distance(player.GetPosition(), block.GetPosition() + block.WorldMatrix.Forward * sphereRadius); + var distance = Vector3D.Distance(player.GetPosition(), sphereCenter); if (distance <= sphereRadius) { + // Check if player is inside a grid that is being teleported + IMyCubeGrid gridBeingTeleported = player.Controller?.ControlledEntity?.Entity?.GetTopMostParent() as IMyCubeGrid; + if (gridBeingTeleported != null) + { + MyLogger.Log($"TPGate: ProcessJumpRequest: Player {player.IdentityId} is inside grid {gridBeingTeleported.DisplayName}. Skipping individual teleport."); + continue; // Skip teleporting the player individually + } + + // Play "enter" particle and sound effect at the starting position + MyVisualScriptLogicProvider.CreateParticleEffectAtPosition("InvalidCustomBlinkParticleEnter", player.GetPosition()); + MyVisualScriptLogicProvider.PlaySingleSoundAtPosition("ShipPrototechJumpDriveJumpIn", player.GetPosition()); + + // Teleport the player TeleportCore.RequestTeleport(player.IdentityId, block.EntityId, link); teleportAttempted = true; playersToTeleport++; + // Get player's new position after teleport + Vector3D newPlayerPosition = player.GetPosition(); + + // Play "leave" particle and sound effect at the new position + MyVisualScriptLogicProvider.CreateParticleEffectAtPosition("InvalidCustomBlinkParticleLeave", newPlayerPosition); + MyVisualScriptLogicProvider.PlaySingleSoundAtPosition("ShipPrototechJumpDriveJumpOut", newPlayerPosition); + if (player.Controller.ControlledEntity is IMyShipController) { shipsToTeleport++; @@ -499,23 +902,49 @@ public static void ProcessJumpRequest(long gatewayId, string link) } } - var destGatewayId = TeleportCore.GetDestinationGatewayId(link, block.EntityId); - var destGateway = MyAPIGateway.Entities.GetEntityById(destGatewayId) as IMyCollector; - if (destGateway != null) + + // Teleport unpiloted ships in range and play directional effects + List potentialEntities = MyAPIGateway.Entities.GetEntitiesInSphere(ref sphere); + foreach (var entity in potentialEntities) { - var unpilotedShipsCount = TeleportCore.TeleportNearbyShips(block, destGateway); - shipsToTeleport += unpilotedShipsCount; - if (unpilotedShipsCount > 0) + var grid = entity as IMyCubeGrid; + if (grid == null || grid.IsStatic || grid.EntityId == block.CubeGrid.EntityId) { - teleportAttempted = true; + continue; + } + + // Skip grid if it already contains a player being teleported + bool hasPlayer = false; + foreach (var player in playerList) + { + if (player.Controller?.ControlledEntity?.Entity?.GetTopMostParent() == grid) + { + hasPlayer = true; + break; + } } + + if (hasPlayer) + { + MyLogger.Log($"TPGate: ProcessJumpRequest: Grid {grid.DisplayName} already contains a teleporting player. Skipping grid teleport."); + continue; + } + + // Teleport the grid + TeleportCore.TeleportEntity(grid, block, destGateway); + shipsToTeleport++; } - if (teleportAttempted) - { + if (teleportAttempted) { MyLogger.Log($"TPGate: ProcessJumpRequest: Teleport attempted"); - MyAPIGateway.Utilities.ShowNotification($"TPGate: Teleporting {playersToTeleport} player(s) and {shipsToTeleport} ship(s)", 5000, "White"); + NotifyPlayersInRange( + $"TPGate: Teleporting {playersToTeleport} player(s) and {shipsToTeleport} ship(s)", + block.GetPosition(), + 100, + "White" + ); } } + } } diff --git a/Ringway/Data/Scripts/TeleportGateway/TeleportGatewaySettings.cs b/Ringway/Data/Scripts/TeleportGateway/TeleportGatewaySettings.cs index 39b78bdc..ab86e201 100644 --- a/Ringway/Data/Scripts/TeleportGateway/TeleportGatewaySettings.cs +++ b/Ringway/Data/Scripts/TeleportGateway/TeleportGatewaySettings.cs @@ -21,6 +21,11 @@ public class TeleportGatewaySettings [ProtoMember(5)] public float SphereDiameter { get; set; } = 50.0f; + [ProtoMember(6)] + public float StoredPower { get; set; } = 0f; + [ProtoMember(7)] + public float MaxStoredPower { get; set; } = 1000f; + [ProtoIgnore] public bool Changed { get; set; } = false; From 1d1b19899a372e1c8b1745738c823b6b66f75db3 Mon Sep 17 00:00:00 2001 From: InvalidArgument3 Date: Sat, 7 Dec 2024 08:17:15 -0600 Subject: [PATCH 2/4] hmm --- .../TeleportGateway/NetworkMessages.cs | 7 - .../Scripts/TeleportGateway/TeleportCore.cs | 187 +++++------------- .../TeleportGateway/TeleportGateway.cs | 178 ++--------------- 3 files changed, 71 insertions(+), 301 deletions(-) diff --git a/Ringway/Data/Scripts/TeleportGateway/NetworkMessages.cs b/Ringway/Data/Scripts/TeleportGateway/NetworkMessages.cs index 6680c542..0e3861f5 100644 --- a/Ringway/Data/Scripts/TeleportGateway/NetworkMessages.cs +++ b/Ringway/Data/Scripts/TeleportGateway/NetworkMessages.cs @@ -168,13 +168,6 @@ private static void HandleSyncSettings(byte[] data) } private static void HandleTeleportRequest(byte[] data) { - MyLogger.Log("NetworkHandler: HandleTeleportRequest: called"); - if (!MyAPIGateway.Multiplayer.IsServer) - { - MyLogger.Log("NetworkHandler: HandleTeleportRequest: Not server, ignoring TeleportRequest"); - return; - } - var message = MyAPIGateway.Utilities.SerializeFromBinary(data); TeleportCore.ServerProcessTeleportRequest(message); } diff --git a/Ringway/Data/Scripts/TeleportGateway/TeleportCore.cs b/Ringway/Data/Scripts/TeleportGateway/TeleportCore.cs index 516a21ab..f23bcf7b 100644 --- a/Ringway/Data/Scripts/TeleportGateway/TeleportCore.cs +++ b/Ringway/Data/Scripts/TeleportGateway/TeleportCore.cs @@ -25,46 +25,27 @@ public static class TeleportCore { internal static Dictionary _instances = new Dictionary(); internal static readonly object _lock = new object(); - public static void UpdateTeleportLinks() { - lock (_lock) { + public static void UpdateTeleportLinks() + { + lock (_lock) + { _TeleportLinks.Clear(); - MyLogger.Log($"TPCore: UpdateTeleportLinks: Updating Teleport links. Total instances: {_instances.Count}"); - - var gateways = new HashSet(); - foreach (var instance in _instances.Values) { - if (instance.RingwayBlock != null && - instance.RingwayBlock.IsWorking && - (instance.RingwayBlock.BlockDefinition.SubtypeName == "RingwayCore" || - instance.RingwayBlock.BlockDefinition.SubtypeName == "SmallRingwayCore")) { - MyLogger.Log($"TPCore: UpdateTeleportLinks: Found instance gateway: {instance.RingwayBlock.CustomName}, EntityId: {instance.RingwayBlock.EntityId}, IsWorking: {instance.RingwayBlock.IsWorking}"); - gateways.Add(instance.RingwayBlock); - } - else { - MyLogger.Log($"TPCore: UpdateTeleportLinks: Instance has null or invalid gateway"); - } - } - - MyLogger.Log($"TPCore: UpdateTeleportLinks: Total gateways found: {gateways.Count}"); - - foreach (var gateway in gateways) { - var gatewayLogic = gateway.GameLogic.GetAs(); - var link = GetTeleportLink(gateway); - if (!string.IsNullOrEmpty(link)) { - if (!_TeleportLinks.ContainsKey(link)) { - _TeleportLinks[link] = new List(); + foreach (var instance in _instances.Values) + { + var gateway = instance.RingwayBlock; + if (gateway != null && gateway.IsWorking) + { + var link = GetTeleportLink(gateway); + if (!string.IsNullOrEmpty(link)) + { + if (!_TeleportLinks.ContainsKey(link)) + { + _TeleportLinks[link] = new List(); + } + _TeleportLinks[link].Add(gateway.EntityId); } - _TeleportLinks[link].Add(gateway.EntityId); - MyLogger.Log($"TPCore: UpdateTeleportLinks: Added gateway {gateway.CustomName} (EntityId: {gateway.EntityId}) to link {link}. AllowPlayers: {gatewayLogic.Settings.AllowPlayers}, AllowShips: {gatewayLogic.Settings.AllowShips}"); - } - else { - MyLogger.Log($"TPCore: UpdateTeleportLinks: Gateway {gateway.CustomName} (EntityId: {gateway.EntityId}) does not have a valid teleport link"); } } - - MyLogger.Log($"TPCore: UpdateTeleportLinks: Total Teleport links: {_TeleportLinks.Count}"); - foreach (var kvp in _TeleportLinks) { - MyLogger.Log($"TPCore: UpdateTeleportLinks: Link {kvp.Key}: {string.Join(", ", kvp.Value)}"); - } } } @@ -91,88 +72,42 @@ public static void RequestTeleport(long playerId, long sourceGatewayId, string l MyAPIGateway.Multiplayer.SendMessageToServer(NetworkHandler.TeleportRequestId, data); } - public static void ServerProcessTeleportRequest(TeleportRequestMessage message) { - MyLogger.Log($"TPCore: ProcessTeleportRequest: Player {message.PlayerId}, Link {message.TeleportLink}"); - - List linkedGateways; - lock (_lock) { - if (!_TeleportLinks.TryGetValue(message.TeleportLink, out linkedGateways)) { - MyLogger.Log($"TPCore: ProcessTeleportRequest: No linked gateways found for link {message.TeleportLink}"); - return; - } - } + public static void ServerProcessTeleportRequest(TeleportRequestMessage message) + { + MyLogger.Log($"Processing teleport request: Player {message.PlayerId}, Link: {message.TeleportLink}"); var sourceGateway = MyAPIGateway.Entities.GetEntityById(message.SourceGatewayId) as IMyCollector; - if (sourceGateway == null) { - MyLogger.Log($"TPCore: ProcessTeleportRequest: Source gateway {message.SourceGatewayId} not found"); + if (sourceGateway == null) + { + MyLogger.Log($"Source gateway not found: {message.SourceGatewayId}"); return; } - var sourcePosition = sourceGateway.GetPosition(); - long nearestGatewayId = 0; - double nearestDistance = double.MaxValue; - - foreach (var gatewayId in linkedGateways) { - if (gatewayId == message.SourceGatewayId) continue; - - var candidateGateway = MyAPIGateway.Entities.GetEntityById(gatewayId) as IMyCollector; - if (candidateGateway == null) continue; - - var distance = Vector3D.Distance(sourcePosition, candidateGateway.GetPosition()); - if (distance < nearestDistance) { - nearestDistance = distance; - nearestGatewayId = gatewayId; - } - } - - if (nearestGatewayId == 0) { - MyLogger.Log($"TPCore: ProcessTeleportRequest: No valid destination gateway found for link {message.TeleportLink}"); + // Assume the destination is valid without relying on client sync + var destGatewayId = GetDestinationGatewayId(message.TeleportLink, message.SourceGatewayId); + if (destGatewayId == 0) + { + MyLogger.Log($"No valid destination gateway found for link {message.TeleportLink}"); return; } - var destGateway = MyAPIGateway.Entities.GetEntityById(nearestGatewayId) as IMyCollector; - if (destGateway == null) { - MyLogger.Log($"TPCore: ProcessTeleportRequest: Destination gateway {nearestGatewayId} not found"); + var destGateway = MyAPIGateway.Entities.GetEntityById(destGatewayId) as IMyCollector; + if (destGateway == null) + { + MyLogger.Log($"Destination gateway not found: {destGatewayId}"); return; } + // Process teleportation var player = GetPlayerById((long)message.PlayerId); - if (player == null || player.Character == null) { - MyLogger.Log($"TPCore: ProcessTeleportRequest: Player {message.PlayerId} or their character not found"); - return; - } - - var sourceGatewayLogic = sourceGateway.GameLogic.GetAs(); - if (sourceGatewayLogic == null) { - MyLogger.Log($"TPCore: ProcessTeleportRequest: Could not retrieve TeleportGateway for source gateway {sourceGateway.EntityId}"); - return; - } - - var sourceGatewaySettings = sourceGatewayLogic.Settings; - if (!sourceGatewaySettings.AllowPlayers) { - MyLogger.Log($"TPCore: ProcessTeleportRequest: Player teleportation is not allowed for source gateway {sourceGateway.EntityId}"); - return; + if (player?.Character != null) + { + TeleportEntity(player.Character, sourceGateway, destGateway); + MyLogger.Log($"Player {message.PlayerId} teleported."); } - - var isShip = player.Controller.ControlledEntity is IMyCubeBlock; - if (isShip && !sourceGatewaySettings.AllowShips) { - MyLogger.Log($"TPCore: ProcessTeleportRequest: Ship teleportation is not allowed for source gateway {sourceGateway.EntityId}"); - return; - } - - TeleportEntity(player.Character, sourceGateway, destGateway); - - var grid = player.Controller.ControlledEntity?.Entity.GetTopMostParent() as IMyCubeGrid; - if (grid != null) { - if (grid.IsStatic) { - MyLogger.Log($"TPCore: ProcessTeleportRequest: Grid {grid.DisplayName} is static, teleportation aborted"); - return; - } - if (HasLockedLandingGear(grid)) { - MyLogger.Log($"TPCore: ProcessTeleportRequest: Grid {grid.DisplayName} has locked landing gear, teleportation aborted"); - return; - } - TeleportEntity(grid, sourceGateway, destGateway); + else + { + MyLogger.Log($"Player {message.PlayerId} or their character not found."); } } @@ -275,42 +210,26 @@ private static void TeleportGrid(IMyCubeGrid mainGrid, MatrixD newOrientation, M MyLogger.Log($"TPCore: TeleportGrid: Teleportation complete for main grid {mainGrid.DisplayName} (EntityId: {mainGrid.EntityId}) and its {subgrids.Count} subgrids"); } - public static void ClientApplyTeleportResponse(TeleportResponseMessage message) { - MyLogger.Log($"TPCore: ApplyTeleport: Player {message.PlayerId}, Success {message.Success}"); - if (!message.Success) { - MyLogger.Log($"TPCore: ApplyTeleport: Teleport unsuccessful for player {message.PlayerId}"); + public static void ClientApplyTeleportResponse(TeleportResponseMessage message) + { + MyLogger.Log($"Applying teleport response: Player {message.PlayerId}, Success: {message.Success}"); + + if (!message.Success) + { + MyLogger.Log($"Teleport unsuccessful for player {message.PlayerId}"); return; } var player = GetPlayerById((long)message.PlayerId); - if (player == null || player.Character == null) { - MyLogger.Log($"TPCore: ApplyTeleport: Player {message.PlayerId} or their character not found during teleport"); + if (player?.Character == null) + { + MyLogger.Log($"Player {message.PlayerId} or their character not found."); return; } - // Teleport the player's controlled grid, if any - var controlledEntity = player.Controller.ControlledEntity; - if (controlledEntity != null) { - var topMostParent = controlledEntity.Entity.GetTopMostParent(); - var grid = topMostParent as IMyCubeGrid; - if (grid != null) { - MyLogger.Log($"TPCore: ApplyTeleport: Attempting to teleport ship: {grid.DisplayName}"); - var shipRelativeOrientation = grid.WorldMatrix * MatrixD.Invert(player.Character.WorldMatrix); - var newShipOrientation = shipRelativeOrientation * message.NewOrientation; - - // Use the new TeleportGrid method with source and destination gateway orientations - TeleportGrid(grid, newShipOrientation, message.SourceGatewayMatrix, message.DestinationGatewayMatrix); - - MyLogger.Log($"TPCore: ApplyTeleport: Ship {grid.DisplayName} teleported"); - - } - } - else { - // Teleport the player's character - player.Character.Teleport(message.NewOrientation); - player.Character.SetWorldMatrix(message.NewOrientation); - MyLogger.Log($"TPCore: ApplyTeleport: Player {message.PlayerId} teleported to {message.NewPosition}"); - } + // Teleport directly without checking linkage + player.Character.Teleport(message.NewOrientation); + MyLogger.Log($"Player {message.PlayerId} teleported to {message.NewPosition}"); } public static long GetDestinationGatewayId(string link, long sourceGatewayId) { diff --git a/Ringway/Data/Scripts/TeleportGateway/TeleportGateway.cs b/Ringway/Data/Scripts/TeleportGateway/TeleportGateway.cs index 9571a964..c2dec30e 100644 --- a/Ringway/Data/Scripts/TeleportGateway/TeleportGateway.cs +++ b/Ringway/Data/Scripts/TeleportGateway/TeleportGateway.cs @@ -100,108 +100,17 @@ private float ComputeRequiredPower() { return powerPerSecond * 1000f; // Convert to watts } - private void AppendingCustomInfo(IMyTerminalBlock block, StringBuilder sb) { - try { - if (!block.IsWorking) { - sb.Append("--- Gateway Offline ---\n"); - sb.Append("The gateway is not functional. Check power and block integrity.\n"); - return; - } - - sb.Append("--- Teleport Gateway Status ---\n"); - - if (Sink != null) { - float currentStoredPower = (float)Settings.StoredPower; - float maxStoredPower = Settings.MaxStoredPower; - float chargePercentage = (currentStoredPower / maxStoredPower) * 100f; - - // Display power level - sb.Append($"Charge: {chargePercentage:F1}% ({currentStoredPower:F2}/{maxStoredPower:F2} MWh)\n"); - sb.Append($"Minimum Charge for Teleport: {MIN_TELEPORT_CHARGE_PERCENTAGE * 100}%\n"); - - // Status based on charging and power availability - if (_isTeleporting) { - sb.Append("Status: Teleporting...\n"); - } - else if (Settings.StoredPower >= maxStoredPower) { - sb.Append("Status: Fully Charged - Ready to Jump\n"); - } - else if (Sink.IsPowerAvailable(MyResourceDistributorComponent.ElectricityId, CHARGE_RATE * 1000f)) { - sb.Append("Status: Charging...\n"); - - float remainingPower = maxStoredPower - currentStoredPower; - float timeToFullCharge = remainingPower / CHARGE_RATE; // in seconds - sb.Append($"Time to Full Charge: {timeToFullCharge:F1} seconds\n"); - } - else { - sb.Append("Status: Insufficient Power for Charging\n"); - sb.Append("Check reactor output or power supply.\n"); - } - - // Warning if power level is low and teleport cannot proceed - if (Settings.StoredPower < maxStoredPower * POWER_THRESHOLD && !_isTeleporting) { - sb.Append("Warning: Power below safe teleport threshold\n"); - sb.Append("Charge to at least 10% to ensure successful teleport.\n"); - } - } - - // Display linked gateways info (unchanged) - var linkedGateways = TeleportCore._TeleportLinks.ContainsKey(Settings.GatewayName) - ? TeleportCore._TeleportLinks[Settings.GatewayName] - : new List(); - int linkedCount = linkedGateways.Count; - sb.Append($"Linked Gateways: {linkedCount}\n"); - - if (linkedCount > 2) { - sb.Append($"WARNING: More than two gateways on channel '{Settings.GatewayName}'.\n"); - sb.Append(" Only the nearest gateway will be used.\n"); - } - - if (linkedCount > 0) { - sb.Append("Linked To:\n"); - var sourcePosition = RingwayBlock.GetPosition(); - - IMyCollector nearestGateway = null; - double nearestDistance = double.MaxValue; - - foreach (var gatewayId in linkedGateways) { - if (gatewayId != RingwayBlock.EntityId) { - var linkedGateway = MyAPIGateway.Entities.GetEntityById(gatewayId) as IMyCollector; - if (linkedGateway != null) { - var distance = Vector3D.Distance(sourcePosition, linkedGateway.GetPosition()); - string distanceStr = $"{distance / 1000:F1} km"; - - if (distance < nearestDistance) { - nearestDistance = distance; - nearestGateway = linkedGateway; - } - - sb.Append($" - {linkedGateway.CustomName}: {distanceStr}\n"); - } - else { - sb.Append($" - Unknown (ID: {gatewayId})\n"); - } - } - } - - if (nearestGateway != null && linkedCount > 1) { - sb.Append($"Active Destination: {nearestGateway.CustomName}\n"); - } - } - else { - sb.Append("Status: Not linked to any other gateways\n"); - } + private void AppendingCustomInfo(IMyTerminalBlock block, StringBuilder sb) + { + sb.Append("--- Teleport Gateway Status ---\n"); - // Settings Info (unchanged) - sb.Append($"Allow Players: {(Settings.AllowPlayers ? "Yes" : "No")}\n"); - sb.Append($"Allow Ships: {(Settings.AllowShips ? "Yes" : "No")}\n"); - sb.Append($"Show Sphere: {(Settings.ShowSphere ? "Yes" : "No")}\n"); - sb.Append($"Sphere Diameter: {Settings.SphereDiameter} m\n"); + // Always show linked destinations, assuming server knows best + sb.Append($"Gateway Name: {Settings.GatewayName}\n"); + sb.Append($"Linked Gateways: {TeleportCore._TeleportLinks[Settings.GatewayName]?.Count ?? 0}\n"); + sb.Append("Status: Ready to Jump\n"); - } - catch (Exception e) { - MyLog.Default.WriteLineAndConsole($"Error in AppendingCustomInfo: {e}"); - } + sb.Append($"Allow Players: {(Settings.AllowPlayers ? "Yes" : "No")}\n"); + sb.Append($"Allow Ships: {(Settings.AllowShips ? "Yes" : "No")}\n"); } public override void UpdateOnceBeforeFrame() { @@ -756,70 +665,19 @@ private float CalculatePowerRequired(double distanceInMeters) private void JumpAction(IMyCollector block) { - MyLogger.Log($"TPGate: JumpAction: Jump action triggered for EntityId: {block.EntityId}"); + MyLogger.Log($"JumpAction: Triggered by client for Gateway {block.EntityId}"); - var link = Settings.GatewayName; - if (string.IsNullOrEmpty(link)) + // Send a jump request to the server with no client-side validation + var message = new JumpRequestMessage { - MyLogger.Log($"TPGate: JumpAction: No valid link set"); - return; - } - - var destGatewayId = TeleportCore.GetDestinationGatewayId(link, block.EntityId); - if (destGatewayId == 0) - { - MyLogger.Log($"TPGate: JumpAction: No valid destination gateway found"); - return; - } - - // Calculate distance to destination - var destGateway = MyAPIGateway.Entities.GetEntityById(destGatewayId) as IMyCollector; - if (destGateway == null) return; - - _jumpDistance = Vector3D.Distance(block.GetPosition(), destGateway.GetPosition()); - - // Enforce the maximum distance restriction - if (_jumpDistance > MAX_TELEPORT_DISTANCE) - { - MyLogger.Log($"TPGate: JumpAction: Jump distance {_jumpDistance / 1000:F1}km exceeds maximum allowed distance {MAX_TELEPORT_DISTANCE / 1000:F1}km."); - NotifyPlayersInRange( - $"Jump distance {_jumpDistance / 1000:F1}km exceeds maximum allowed range of {MAX_TELEPORT_DISTANCE / 1000:F1}km.", - block.GetPosition(), - 100, - "Red" - ); - return; - } - - float powerRequired = CalculatePowerRequired(_jumpDistance); - MyLogger.Log( - $"TPGate: JumpAction: Distance: {_jumpDistance / 1000:F1}km, Power Required: {powerRequired:F1}MWh"); + GatewayId = block.EntityId, + Link = Settings.GatewayName + }; - if (Settings.StoredPower < powerRequired) - { - MyLogger.Log( - $"TPGate: JumpAction: Not enough power for jump. Required: {powerRequired:F1}MWh, Available: {Settings.StoredPower:F1}MWh"); - NotifyPlayersInRange( - $"Insufficient power for {_jumpDistance / 1000:F1}km jump. Need {powerRequired:F1}MWh", - block.GetPosition(), - 100, - "Red" - ); - return; - } + var data = MyAPIGateway.Utilities.SerializeToBinary(message); + MyAPIGateway.Multiplayer.SendMessageToServer(NetworkHandler.JumpRequestId, data); - // Start teleport sequence - _isTeleporting = true; - _teleportCountdown = CalculateCountdown(_jumpDistance); // Apply calculated countdown - _initialPower = Settings.StoredPower; - - float totalSeconds = _teleportCountdown / 60f; - NotifyPlayersInRange( - $"Initiating {_jumpDistance / 1000:F1}km jump - {totalSeconds:F1} seconds", - block.GetPosition(), - 100, - "White" - ); + MyLogger.Log($"JumpAction: Request sent to server for Gateway {block.EntityId}"); } private static void NotifyPlayersInRange(string text, Vector3D position, double radius, string font = "White") { From c934c692826732c651c0d515ea78a46d0b14f45e Mon Sep 17 00:00:00 2001 From: InvalidArgument3 Date: Sat, 7 Dec 2024 08:17:18 -0600 Subject: [PATCH 3/4] Revert "hmm" This reverts commit 1d1b19899a372e1c8b1745738c823b6b66f75db3. --- .../TeleportGateway/NetworkMessages.cs | 7 + .../Scripts/TeleportGateway/TeleportCore.cs | 187 +++++++++++++----- .../TeleportGateway/TeleportGateway.cs | 178 +++++++++++++++-- 3 files changed, 301 insertions(+), 71 deletions(-) diff --git a/Ringway/Data/Scripts/TeleportGateway/NetworkMessages.cs b/Ringway/Data/Scripts/TeleportGateway/NetworkMessages.cs index 0e3861f5..6680c542 100644 --- a/Ringway/Data/Scripts/TeleportGateway/NetworkMessages.cs +++ b/Ringway/Data/Scripts/TeleportGateway/NetworkMessages.cs @@ -168,6 +168,13 @@ private static void HandleSyncSettings(byte[] data) } private static void HandleTeleportRequest(byte[] data) { + MyLogger.Log("NetworkHandler: HandleTeleportRequest: called"); + if (!MyAPIGateway.Multiplayer.IsServer) + { + MyLogger.Log("NetworkHandler: HandleTeleportRequest: Not server, ignoring TeleportRequest"); + return; + } + var message = MyAPIGateway.Utilities.SerializeFromBinary(data); TeleportCore.ServerProcessTeleportRequest(message); } diff --git a/Ringway/Data/Scripts/TeleportGateway/TeleportCore.cs b/Ringway/Data/Scripts/TeleportGateway/TeleportCore.cs index f23bcf7b..516a21ab 100644 --- a/Ringway/Data/Scripts/TeleportGateway/TeleportCore.cs +++ b/Ringway/Data/Scripts/TeleportGateway/TeleportCore.cs @@ -25,27 +25,46 @@ public static class TeleportCore { internal static Dictionary _instances = new Dictionary(); internal static readonly object _lock = new object(); - public static void UpdateTeleportLinks() - { - lock (_lock) - { + public static void UpdateTeleportLinks() { + lock (_lock) { _TeleportLinks.Clear(); - foreach (var instance in _instances.Values) - { - var gateway = instance.RingwayBlock; - if (gateway != null && gateway.IsWorking) - { - var link = GetTeleportLink(gateway); - if (!string.IsNullOrEmpty(link)) - { - if (!_TeleportLinks.ContainsKey(link)) - { - _TeleportLinks[link] = new List(); - } - _TeleportLinks[link].Add(gateway.EntityId); + MyLogger.Log($"TPCore: UpdateTeleportLinks: Updating Teleport links. Total instances: {_instances.Count}"); + + var gateways = new HashSet(); + foreach (var instance in _instances.Values) { + if (instance.RingwayBlock != null && + instance.RingwayBlock.IsWorking && + (instance.RingwayBlock.BlockDefinition.SubtypeName == "RingwayCore" || + instance.RingwayBlock.BlockDefinition.SubtypeName == "SmallRingwayCore")) { + MyLogger.Log($"TPCore: UpdateTeleportLinks: Found instance gateway: {instance.RingwayBlock.CustomName}, EntityId: {instance.RingwayBlock.EntityId}, IsWorking: {instance.RingwayBlock.IsWorking}"); + gateways.Add(instance.RingwayBlock); + } + else { + MyLogger.Log($"TPCore: UpdateTeleportLinks: Instance has null or invalid gateway"); + } + } + + MyLogger.Log($"TPCore: UpdateTeleportLinks: Total gateways found: {gateways.Count}"); + + foreach (var gateway in gateways) { + var gatewayLogic = gateway.GameLogic.GetAs(); + var link = GetTeleportLink(gateway); + if (!string.IsNullOrEmpty(link)) { + if (!_TeleportLinks.ContainsKey(link)) { + _TeleportLinks[link] = new List(); } + _TeleportLinks[link].Add(gateway.EntityId); + MyLogger.Log($"TPCore: UpdateTeleportLinks: Added gateway {gateway.CustomName} (EntityId: {gateway.EntityId}) to link {link}. AllowPlayers: {gatewayLogic.Settings.AllowPlayers}, AllowShips: {gatewayLogic.Settings.AllowShips}"); + } + else { + MyLogger.Log($"TPCore: UpdateTeleportLinks: Gateway {gateway.CustomName} (EntityId: {gateway.EntityId}) does not have a valid teleport link"); } } + + MyLogger.Log($"TPCore: UpdateTeleportLinks: Total Teleport links: {_TeleportLinks.Count}"); + foreach (var kvp in _TeleportLinks) { + MyLogger.Log($"TPCore: UpdateTeleportLinks: Link {kvp.Key}: {string.Join(", ", kvp.Value)}"); + } } } @@ -72,42 +91,88 @@ public static void RequestTeleport(long playerId, long sourceGatewayId, string l MyAPIGateway.Multiplayer.SendMessageToServer(NetworkHandler.TeleportRequestId, data); } - public static void ServerProcessTeleportRequest(TeleportRequestMessage message) - { - MyLogger.Log($"Processing teleport request: Player {message.PlayerId}, Link: {message.TeleportLink}"); + public static void ServerProcessTeleportRequest(TeleportRequestMessage message) { + MyLogger.Log($"TPCore: ProcessTeleportRequest: Player {message.PlayerId}, Link {message.TeleportLink}"); + + List linkedGateways; + lock (_lock) { + if (!_TeleportLinks.TryGetValue(message.TeleportLink, out linkedGateways)) { + MyLogger.Log($"TPCore: ProcessTeleportRequest: No linked gateways found for link {message.TeleportLink}"); + return; + } + } var sourceGateway = MyAPIGateway.Entities.GetEntityById(message.SourceGatewayId) as IMyCollector; - if (sourceGateway == null) - { - MyLogger.Log($"Source gateway not found: {message.SourceGatewayId}"); + if (sourceGateway == null) { + MyLogger.Log($"TPCore: ProcessTeleportRequest: Source gateway {message.SourceGatewayId} not found"); return; } - // Assume the destination is valid without relying on client sync - var destGatewayId = GetDestinationGatewayId(message.TeleportLink, message.SourceGatewayId); - if (destGatewayId == 0) - { - MyLogger.Log($"No valid destination gateway found for link {message.TeleportLink}"); + var sourcePosition = sourceGateway.GetPosition(); + long nearestGatewayId = 0; + double nearestDistance = double.MaxValue; + + foreach (var gatewayId in linkedGateways) { + if (gatewayId == message.SourceGatewayId) continue; + + var candidateGateway = MyAPIGateway.Entities.GetEntityById(gatewayId) as IMyCollector; + if (candidateGateway == null) continue; + + var distance = Vector3D.Distance(sourcePosition, candidateGateway.GetPosition()); + if (distance < nearestDistance) { + nearestDistance = distance; + nearestGatewayId = gatewayId; + } + } + + if (nearestGatewayId == 0) { + MyLogger.Log($"TPCore: ProcessTeleportRequest: No valid destination gateway found for link {message.TeleportLink}"); return; } - var destGateway = MyAPIGateway.Entities.GetEntityById(destGatewayId) as IMyCollector; - if (destGateway == null) - { - MyLogger.Log($"Destination gateway not found: {destGatewayId}"); + var destGateway = MyAPIGateway.Entities.GetEntityById(nearestGatewayId) as IMyCollector; + if (destGateway == null) { + MyLogger.Log($"TPCore: ProcessTeleportRequest: Destination gateway {nearestGatewayId} not found"); return; } - // Process teleportation var player = GetPlayerById((long)message.PlayerId); - if (player?.Character != null) - { - TeleportEntity(player.Character, sourceGateway, destGateway); - MyLogger.Log($"Player {message.PlayerId} teleported."); + if (player == null || player.Character == null) { + MyLogger.Log($"TPCore: ProcessTeleportRequest: Player {message.PlayerId} or their character not found"); + return; + } + + var sourceGatewayLogic = sourceGateway.GameLogic.GetAs(); + if (sourceGatewayLogic == null) { + MyLogger.Log($"TPCore: ProcessTeleportRequest: Could not retrieve TeleportGateway for source gateway {sourceGateway.EntityId}"); + return; + } + + var sourceGatewaySettings = sourceGatewayLogic.Settings; + if (!sourceGatewaySettings.AllowPlayers) { + MyLogger.Log($"TPCore: ProcessTeleportRequest: Player teleportation is not allowed for source gateway {sourceGateway.EntityId}"); + return; } - else - { - MyLogger.Log($"Player {message.PlayerId} or their character not found."); + + var isShip = player.Controller.ControlledEntity is IMyCubeBlock; + if (isShip && !sourceGatewaySettings.AllowShips) { + MyLogger.Log($"TPCore: ProcessTeleportRequest: Ship teleportation is not allowed for source gateway {sourceGateway.EntityId}"); + return; + } + + TeleportEntity(player.Character, sourceGateway, destGateway); + + var grid = player.Controller.ControlledEntity?.Entity.GetTopMostParent() as IMyCubeGrid; + if (grid != null) { + if (grid.IsStatic) { + MyLogger.Log($"TPCore: ProcessTeleportRequest: Grid {grid.DisplayName} is static, teleportation aborted"); + return; + } + if (HasLockedLandingGear(grid)) { + MyLogger.Log($"TPCore: ProcessTeleportRequest: Grid {grid.DisplayName} has locked landing gear, teleportation aborted"); + return; + } + TeleportEntity(grid, sourceGateway, destGateway); } } @@ -210,26 +275,42 @@ private static void TeleportGrid(IMyCubeGrid mainGrid, MatrixD newOrientation, M MyLogger.Log($"TPCore: TeleportGrid: Teleportation complete for main grid {mainGrid.DisplayName} (EntityId: {mainGrid.EntityId}) and its {subgrids.Count} subgrids"); } - public static void ClientApplyTeleportResponse(TeleportResponseMessage message) - { - MyLogger.Log($"Applying teleport response: Player {message.PlayerId}, Success: {message.Success}"); - - if (!message.Success) - { - MyLogger.Log($"Teleport unsuccessful for player {message.PlayerId}"); + public static void ClientApplyTeleportResponse(TeleportResponseMessage message) { + MyLogger.Log($"TPCore: ApplyTeleport: Player {message.PlayerId}, Success {message.Success}"); + if (!message.Success) { + MyLogger.Log($"TPCore: ApplyTeleport: Teleport unsuccessful for player {message.PlayerId}"); return; } var player = GetPlayerById((long)message.PlayerId); - if (player?.Character == null) - { - MyLogger.Log($"Player {message.PlayerId} or their character not found."); + if (player == null || player.Character == null) { + MyLogger.Log($"TPCore: ApplyTeleport: Player {message.PlayerId} or their character not found during teleport"); return; } - // Teleport directly without checking linkage - player.Character.Teleport(message.NewOrientation); - MyLogger.Log($"Player {message.PlayerId} teleported to {message.NewPosition}"); + // Teleport the player's controlled grid, if any + var controlledEntity = player.Controller.ControlledEntity; + if (controlledEntity != null) { + var topMostParent = controlledEntity.Entity.GetTopMostParent(); + var grid = topMostParent as IMyCubeGrid; + if (grid != null) { + MyLogger.Log($"TPCore: ApplyTeleport: Attempting to teleport ship: {grid.DisplayName}"); + var shipRelativeOrientation = grid.WorldMatrix * MatrixD.Invert(player.Character.WorldMatrix); + var newShipOrientation = shipRelativeOrientation * message.NewOrientation; + + // Use the new TeleportGrid method with source and destination gateway orientations + TeleportGrid(grid, newShipOrientation, message.SourceGatewayMatrix, message.DestinationGatewayMatrix); + + MyLogger.Log($"TPCore: ApplyTeleport: Ship {grid.DisplayName} teleported"); + + } + } + else { + // Teleport the player's character + player.Character.Teleport(message.NewOrientation); + player.Character.SetWorldMatrix(message.NewOrientation); + MyLogger.Log($"TPCore: ApplyTeleport: Player {message.PlayerId} teleported to {message.NewPosition}"); + } } public static long GetDestinationGatewayId(string link, long sourceGatewayId) { diff --git a/Ringway/Data/Scripts/TeleportGateway/TeleportGateway.cs b/Ringway/Data/Scripts/TeleportGateway/TeleportGateway.cs index c2dec30e..9571a964 100644 --- a/Ringway/Data/Scripts/TeleportGateway/TeleportGateway.cs +++ b/Ringway/Data/Scripts/TeleportGateway/TeleportGateway.cs @@ -100,17 +100,108 @@ private float ComputeRequiredPower() { return powerPerSecond * 1000f; // Convert to watts } - private void AppendingCustomInfo(IMyTerminalBlock block, StringBuilder sb) - { - sb.Append("--- Teleport Gateway Status ---\n"); + private void AppendingCustomInfo(IMyTerminalBlock block, StringBuilder sb) { + try { + if (!block.IsWorking) { + sb.Append("--- Gateway Offline ---\n"); + sb.Append("The gateway is not functional. Check power and block integrity.\n"); + return; + } + + sb.Append("--- Teleport Gateway Status ---\n"); + + if (Sink != null) { + float currentStoredPower = (float)Settings.StoredPower; + float maxStoredPower = Settings.MaxStoredPower; + float chargePercentage = (currentStoredPower / maxStoredPower) * 100f; + + // Display power level + sb.Append($"Charge: {chargePercentage:F1}% ({currentStoredPower:F2}/{maxStoredPower:F2} MWh)\n"); + sb.Append($"Minimum Charge for Teleport: {MIN_TELEPORT_CHARGE_PERCENTAGE * 100}%\n"); + + // Status based on charging and power availability + if (_isTeleporting) { + sb.Append("Status: Teleporting...\n"); + } + else if (Settings.StoredPower >= maxStoredPower) { + sb.Append("Status: Fully Charged - Ready to Jump\n"); + } + else if (Sink.IsPowerAvailable(MyResourceDistributorComponent.ElectricityId, CHARGE_RATE * 1000f)) { + sb.Append("Status: Charging...\n"); + + float remainingPower = maxStoredPower - currentStoredPower; + float timeToFullCharge = remainingPower / CHARGE_RATE; // in seconds + sb.Append($"Time to Full Charge: {timeToFullCharge:F1} seconds\n"); + } + else { + sb.Append("Status: Insufficient Power for Charging\n"); + sb.Append("Check reactor output or power supply.\n"); + } + + // Warning if power level is low and teleport cannot proceed + if (Settings.StoredPower < maxStoredPower * POWER_THRESHOLD && !_isTeleporting) { + sb.Append("Warning: Power below safe teleport threshold\n"); + sb.Append("Charge to at least 10% to ensure successful teleport.\n"); + } + } + + // Display linked gateways info (unchanged) + var linkedGateways = TeleportCore._TeleportLinks.ContainsKey(Settings.GatewayName) + ? TeleportCore._TeleportLinks[Settings.GatewayName] + : new List(); + int linkedCount = linkedGateways.Count; + sb.Append($"Linked Gateways: {linkedCount}\n"); + + if (linkedCount > 2) { + sb.Append($"WARNING: More than two gateways on channel '{Settings.GatewayName}'.\n"); + sb.Append(" Only the nearest gateway will be used.\n"); + } + + if (linkedCount > 0) { + sb.Append("Linked To:\n"); + var sourcePosition = RingwayBlock.GetPosition(); + + IMyCollector nearestGateway = null; + double nearestDistance = double.MaxValue; + + foreach (var gatewayId in linkedGateways) { + if (gatewayId != RingwayBlock.EntityId) { + var linkedGateway = MyAPIGateway.Entities.GetEntityById(gatewayId) as IMyCollector; + if (linkedGateway != null) { + var distance = Vector3D.Distance(sourcePosition, linkedGateway.GetPosition()); + string distanceStr = $"{distance / 1000:F1} km"; + + if (distance < nearestDistance) { + nearestDistance = distance; + nearestGateway = linkedGateway; + } + + sb.Append($" - {linkedGateway.CustomName}: {distanceStr}\n"); + } + else { + sb.Append($" - Unknown (ID: {gatewayId})\n"); + } + } + } - // Always show linked destinations, assuming server knows best - sb.Append($"Gateway Name: {Settings.GatewayName}\n"); - sb.Append($"Linked Gateways: {TeleportCore._TeleportLinks[Settings.GatewayName]?.Count ?? 0}\n"); - sb.Append("Status: Ready to Jump\n"); + if (nearestGateway != null && linkedCount > 1) { + sb.Append($"Active Destination: {nearestGateway.CustomName}\n"); + } + } + else { + sb.Append("Status: Not linked to any other gateways\n"); + } - sb.Append($"Allow Players: {(Settings.AllowPlayers ? "Yes" : "No")}\n"); - sb.Append($"Allow Ships: {(Settings.AllowShips ? "Yes" : "No")}\n"); + // Settings Info (unchanged) + sb.Append($"Allow Players: {(Settings.AllowPlayers ? "Yes" : "No")}\n"); + sb.Append($"Allow Ships: {(Settings.AllowShips ? "Yes" : "No")}\n"); + sb.Append($"Show Sphere: {(Settings.ShowSphere ? "Yes" : "No")}\n"); + sb.Append($"Sphere Diameter: {Settings.SphereDiameter} m\n"); + + } + catch (Exception e) { + MyLog.Default.WriteLineAndConsole($"Error in AppendingCustomInfo: {e}"); + } } public override void UpdateOnceBeforeFrame() { @@ -665,19 +756,70 @@ private float CalculatePowerRequired(double distanceInMeters) private void JumpAction(IMyCollector block) { - MyLogger.Log($"JumpAction: Triggered by client for Gateway {block.EntityId}"); + MyLogger.Log($"TPGate: JumpAction: Jump action triggered for EntityId: {block.EntityId}"); - // Send a jump request to the server with no client-side validation - var message = new JumpRequestMessage + var link = Settings.GatewayName; + if (string.IsNullOrEmpty(link)) { - GatewayId = block.EntityId, - Link = Settings.GatewayName - }; + MyLogger.Log($"TPGate: JumpAction: No valid link set"); + return; + } - var data = MyAPIGateway.Utilities.SerializeToBinary(message); - MyAPIGateway.Multiplayer.SendMessageToServer(NetworkHandler.JumpRequestId, data); + var destGatewayId = TeleportCore.GetDestinationGatewayId(link, block.EntityId); + if (destGatewayId == 0) + { + MyLogger.Log($"TPGate: JumpAction: No valid destination gateway found"); + return; + } + + // Calculate distance to destination + var destGateway = MyAPIGateway.Entities.GetEntityById(destGatewayId) as IMyCollector; + if (destGateway == null) return; + + _jumpDistance = Vector3D.Distance(block.GetPosition(), destGateway.GetPosition()); + + // Enforce the maximum distance restriction + if (_jumpDistance > MAX_TELEPORT_DISTANCE) + { + MyLogger.Log($"TPGate: JumpAction: Jump distance {_jumpDistance / 1000:F1}km exceeds maximum allowed distance {MAX_TELEPORT_DISTANCE / 1000:F1}km."); + NotifyPlayersInRange( + $"Jump distance {_jumpDistance / 1000:F1}km exceeds maximum allowed range of {MAX_TELEPORT_DISTANCE / 1000:F1}km.", + block.GetPosition(), + 100, + "Red" + ); + return; + } + + float powerRequired = CalculatePowerRequired(_jumpDistance); + MyLogger.Log( + $"TPGate: JumpAction: Distance: {_jumpDistance / 1000:F1}km, Power Required: {powerRequired:F1}MWh"); + + if (Settings.StoredPower < powerRequired) + { + MyLogger.Log( + $"TPGate: JumpAction: Not enough power for jump. Required: {powerRequired:F1}MWh, Available: {Settings.StoredPower:F1}MWh"); + NotifyPlayersInRange( + $"Insufficient power for {_jumpDistance / 1000:F1}km jump. Need {powerRequired:F1}MWh", + block.GetPosition(), + 100, + "Red" + ); + return; + } - MyLogger.Log($"JumpAction: Request sent to server for Gateway {block.EntityId}"); + // Start teleport sequence + _isTeleporting = true; + _teleportCountdown = CalculateCountdown(_jumpDistance); // Apply calculated countdown + _initialPower = Settings.StoredPower; + + float totalSeconds = _teleportCountdown / 60f; + NotifyPlayersInRange( + $"Initiating {_jumpDistance / 1000:F1}km jump - {totalSeconds:F1} seconds", + block.GetPosition(), + 100, + "White" + ); } private static void NotifyPlayersInRange(string text, Vector3D position, double radius, string font = "White") { From 2797c8543b8c5e76631360648860c339949e265b Mon Sep 17 00:00:00 2001 From: InvalidArgument3 Date: Sat, 7 Dec 2024 08:24:40 -0600 Subject: [PATCH 4/4] it was fucking jumpaction --- .../TeleportGateway/TeleportGateway.cs | 55 ++++++++++++------- 1 file changed, 34 insertions(+), 21 deletions(-) diff --git a/Ringway/Data/Scripts/TeleportGateway/TeleportGateway.cs b/Ringway/Data/Scripts/TeleportGateway/TeleportGateway.cs index 9571a964..e1efcf0e 100644 --- a/Ringway/Data/Scripts/TeleportGateway/TeleportGateway.cs +++ b/Ringway/Data/Scripts/TeleportGateway/TeleportGateway.cs @@ -761,27 +761,33 @@ private void JumpAction(IMyCollector block) var link = Settings.GatewayName; if (string.IsNullOrEmpty(link)) { - MyLogger.Log($"TPGate: JumpAction: No valid link set"); - return; + MyLogger.Log($"TPGate: JumpAction: No valid link set. Proceeding with request to server."); } + // Use server-calculated destination if available + _jumpDistance = 0; // Default value if destination is not directly visible + float powerRequired = 0; + + // Check for destination gateway locally (optional) var destGatewayId = TeleportCore.GetDestinationGatewayId(link, block.EntityId); - if (destGatewayId == 0) + if (destGatewayId != 0) { - MyLogger.Log($"TPGate: JumpAction: No valid destination gateway found"); - return; + var destGateway = MyAPIGateway.Entities.GetEntityById(destGatewayId) as IMyCollector; + if (destGateway != null) + { + _jumpDistance = Vector3D.Distance(block.GetPosition(), destGateway.GetPosition()); + powerRequired = CalculatePowerRequired(_jumpDistance); + } + else + { + MyLogger.Log($"TPGate: JumpAction: Destination gateway not found on client side. Server will handle validation."); + } } - // Calculate distance to destination - var destGateway = MyAPIGateway.Entities.GetEntityById(destGatewayId) as IMyCollector; - if (destGateway == null) return; - - _jumpDistance = Vector3D.Distance(block.GetPosition(), destGateway.GetPosition()); - // Enforce the maximum distance restriction - if (_jumpDistance > MAX_TELEPORT_DISTANCE) + if (_jumpDistance > MAX_TELEPORT_DISTANCE && destGatewayId != 0) { - MyLogger.Log($"TPGate: JumpAction: Jump distance {_jumpDistance / 1000:F1}km exceeds maximum allowed distance {MAX_TELEPORT_DISTANCE / 1000:F1}km."); + MyLogger.Log($"TPGate: JumpAction: Jump distance {_jumpDistance / 1000:F1}km exceeds maximum allowed range of {MAX_TELEPORT_DISTANCE / 1000:F1}km."); NotifyPlayersInRange( $"Jump distance {_jumpDistance / 1000:F1}km exceeds maximum allowed range of {MAX_TELEPORT_DISTANCE / 1000:F1}km.", block.GetPosition(), @@ -791,14 +797,10 @@ private void JumpAction(IMyCollector block) return; } - float powerRequired = CalculatePowerRequired(_jumpDistance); - MyLogger.Log( - $"TPGate: JumpAction: Distance: {_jumpDistance / 1000:F1}km, Power Required: {powerRequired:F1}MWh"); - + // Check power availability if (Settings.StoredPower < powerRequired) { - MyLogger.Log( - $"TPGate: JumpAction: Not enough power for jump. Required: {powerRequired:F1}MWh, Available: {Settings.StoredPower:F1}MWh"); + MyLogger.Log($"TPGate: JumpAction: Insufficient power for jump. Required: {powerRequired:F1}MWh, Available: {Settings.StoredPower:F1}MWh"); NotifyPlayersInRange( $"Insufficient power for {_jumpDistance / 1000:F1}km jump. Need {powerRequired:F1}MWh", block.GetPosition(), @@ -808,11 +810,17 @@ private void JumpAction(IMyCollector block) return; } - // Start teleport sequence + // Deduct power and start teleport sequence _isTeleporting = true; - _teleportCountdown = CalculateCountdown(_jumpDistance); // Apply calculated countdown + _teleportCountdown = CalculateCountdown(_jumpDistance); // Calculate countdown _initialPower = Settings.StoredPower; + Settings.StoredPower = Math.Max(0, Settings.StoredPower - powerRequired); + Settings.Changed = true; + + MyLogger.Log($"TPGate: JumpAction: Teleport sequence initiated. Power deducted: {powerRequired:F1}MWh. Remaining: {Settings.StoredPower:F1}MWh"); + + // Notify players of jump initiation float totalSeconds = _teleportCountdown / 60f; NotifyPlayersInRange( $"Initiating {_jumpDistance / 1000:F1}km jump - {totalSeconds:F1} seconds", @@ -820,6 +828,11 @@ private void JumpAction(IMyCollector block) 100, "White" ); + + // Update per simulation tick + NeedsUpdate |= MyEntityUpdateEnum.EACH_FRAME; // Start update loop + + // Countdown will decrement in `UpdateAfterSimulation` } private static void NotifyPlayersInRange(string text, Vector3D position, double radius, string font = "White") {