From d5e9bd17d26e95df5a2ad495029995228f6dd4e1 Mon Sep 17 00:00:00 2001 From: SokyranTheDragon Date: Sun, 16 Nov 2025 19:13:06 +0100 Subject: [PATCH 1/3] Fix and improve world ping bugs - Prevent pinging invalid locations - This includes trying to ping space or planet locations that aren't part of playable world - When finding a tile under a mouse failed, attempt again but snap to expandable world objects - This will properly handle finding world objects in space - This doesn't allow pinging empty locations in space, as `GenWorld.MouseTile` cannot select those - Prevent drawing pings from planet layers that aren't currently active - When sending map location, use `PlanetTile.Invalid` rather than a surface tile with ID of 0. - When receiving pings, make sure that we received a valid ping location before accepting it --- Source/Client/UI/DrawPingPlanet.cs | 2 ++ Source/Client/UI/LocationPings.cs | 22 +++++++++++++++++++--- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/Source/Client/UI/DrawPingPlanet.cs b/Source/Client/UI/DrawPingPlanet.cs index f226cff7..4e32fe96 100644 --- a/Source/Client/UI/DrawPingPlanet.cs +++ b/Source/Client/UI/DrawPingPlanet.cs @@ -16,6 +16,8 @@ static void Postfix() { if (ping.mapId != -1) continue; if (ping.PlayerInfo is not { } player) continue; + // Only display pings on the current layer + if (ping.planetTile.Layer != Find.WorldSelector.SelectedLayer) continue; var tileCenter = GenWorldUI.WorldToUIPosition(Find.WorldGrid.GetTileCenter(ping.planetTile)); const float size = 30f; diff --git a/Source/Client/UI/LocationPings.cs b/Source/Client/UI/LocationPings.cs index f690b420..68179ff7 100644 --- a/Source/Client/UI/LocationPings.cs +++ b/Source/Client/UI/LocationPings.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Linq; using Multiplayer.Client.Util; using Multiplayer.Common.Networking.Packet; using RimWorld; @@ -23,9 +24,19 @@ public void UpdatePing() if (MultiplayerStatic.PingKeyDef.JustPressed || KeyDown(Multiplayer.settings.sendPingButton)) { if (WorldRendererUtility.WorldSelected) - PingLocation(-1, GenWorld.MouseTile(), Vector3.zero); + { + // Grab the tile under mouse + var tile = GenWorld.MouseTile(); + // If the tile is not valid, snap to expandable world objects (handles orbital locations) + if (!tile.Valid) + tile = GenWorld.MouseTile(true); + + // Make sure the tile is valid and that we didn't ping with the mouse outside of map bounds or in space + if (tile.Valid) + PingLocation(-1, tile, Vector3.zero); + } else if (Find.CurrentMap != null) - PingLocation(Find.CurrentMap.uniqueID, 0, UI.MouseMapPosition()); + PingLocation(Find.CurrentMap.uniqueID, PlanetTile.Invalid, UI.MouseMapPosition()); } for (int i = pings.Count - 1; i >= 0; i--) @@ -69,11 +80,16 @@ public void ReceivePing(ServerPingLocPacket packet) if (!Multiplayer.settings.enablePings) return; var data = packet.data; + var planetTile = new PlanetTile(data.planetTileId, data.planetTileLayer); + // Return early if both the map and planet tile are invalid + if (data.mapId == -1 && !planetTile.Valid) + return; + pings.RemoveAll(p => p.player == packet.playerId); pings.Add(new PingInfo { player = packet.playerId, mapId = data.mapId, - planetTile = new PlanetTile(data.planetTileId, data.planetTileLayer), + planetTile = planetTile, mapLoc = new Vector3(data.x, data.y, data.z) }); alertHidden = false; From e3a357528ff4edae2b846b4fef1ecd9ff5a6e503 Mon Sep 17 00:00:00 2001 From: SokyranTheDragon Date: Tue, 13 Jan 2026 18:22:23 +0100 Subject: [PATCH 2/3] Added an option to draw cross-layer pings Requires adding translations --- Source/Client/Settings/MpSettings.cs | 2 ++ Source/Client/Settings/MpSettingsUI.cs | 2 ++ Source/Client/UI/DrawPingPlanet.cs | 22 ++++++++++++++++++++-- 3 files changed, 24 insertions(+), 2 deletions(-) diff --git a/Source/Client/Settings/MpSettings.cs b/Source/Client/Settings/MpSettings.cs index f14bc67e..a101e064 100644 --- a/Source/Client/Settings/MpSettings.cs +++ b/Source/Client/Settings/MpSettings.cs @@ -23,6 +23,7 @@ public class MpSettings : ModSettings public bool showModCompatibility = true; public bool hideTranslationMods = true; public bool enablePings = true; + public bool enableCrossPlanetLayerPings = true; public KeyCode? sendPingButton = KeyCode.Mouse4; public KeyCode? jumpToPingButton = KeyCode.Mouse3; public Rect chatRect; @@ -66,6 +67,7 @@ public override void ExposeData() Scribe_Values.Look(ref showModCompatibility, "showModCompatibility", true); Scribe_Values.Look(ref hideTranslationMods, "hideTranslationMods", true); Scribe_Values.Look(ref enablePings, "enablePings", true); + Scribe_Values.Look(ref enableCrossPlanetLayerPings, "enableCrossPlanetLayerPings", true); Scribe_Values.Look(ref sendPingButton, "sendPingButton", KeyCode.Mouse4); Scribe_Values.Look(ref jumpToPingButton, "jumpToPingButton", KeyCode.Mouse3); Scribe_Custom.LookRect(ref chatRect, "chatRect"); diff --git a/Source/Client/Settings/MpSettingsUI.cs b/Source/Client/Settings/MpSettingsUI.cs index 1ad073a8..83c52068 100644 --- a/Source/Client/Settings/MpSettingsUI.cs +++ b/Source/Client/Settings/MpSettingsUI.cs @@ -73,6 +73,8 @@ public static void DoGeneralSettings(MpSettings settings, Rect inRect, Rect page listing.CheckboxLabeled("MpShowModCompat".Translate(), ref settings.showModCompatibility, "MpShowModCompatDesc".Translate()); listing.CheckboxLabeled("MpEnablePingsSetting".Translate(), ref settings.enablePings); + listing.CheckboxLabeled("MpEnableCrossPlanetLayerPings".Translate(), ref settings.enableCrossPlanetLayerPings, + "MpEnableCrossPlanetLayerPingsDesc".Translate()); listing.CheckboxLabeled("MpShowMainMenuAnimation".Translate(), ref settings.showMainMenuAnim); const string buttonOff = "Off"; diff --git a/Source/Client/UI/DrawPingPlanet.cs b/Source/Client/UI/DrawPingPlanet.cs index 4e32fe96..13bfbfe2 100644 --- a/Source/Client/UI/DrawPingPlanet.cs +++ b/Source/Client/UI/DrawPingPlanet.cs @@ -16,8 +16,26 @@ static void Postfix() { if (ping.mapId != -1) continue; if (ping.PlayerInfo is not { } player) continue; - // Only display pings on the current layer - if (ping.planetTile.Layer != Find.WorldSelector.SelectedLayer) continue; + + var layer = Find.WorldSelector.SelectedLayer; + // Only display pings on the current layer or (if enabled) on layers we can zoom to. + if (Multiplayer.settings.enableCrossPlanetLayerPings) + { + // We can either start with the ping layer, and keep zooming out, + // or start with the current player layer, and keep zooming in. + // Or both. This implementation tries to zoom in from the current player's layer. + + // Infinite loop prevention. + for (var i = 0; i < 25; i++) + { + // Either can't zoom in more, or we found our target + if (layer == null || layer == ping.planetTile.Layer) + break; + + layer = layer.zoomInToLayer; + } + } + if (ping.planetTile.Layer != layer) continue; var tileCenter = GenWorldUI.WorldToUIPosition(Find.WorldGrid.GetTileCenter(ping.planetTile)); const float size = 30f; From 6c7d8edbc7cd9817e28536cf35496851571ff851 Mon Sep 17 00:00:00 2001 From: SokyranTheDragon Date: Tue, 13 Jan 2026 18:34:06 +0100 Subject: [PATCH 3/3] Extra null planet layer check --- Source/Client/UI/DrawPingPlanet.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/Source/Client/UI/DrawPingPlanet.cs b/Source/Client/UI/DrawPingPlanet.cs index 13bfbfe2..3bd6233b 100644 --- a/Source/Client/UI/DrawPingPlanet.cs +++ b/Source/Client/UI/DrawPingPlanet.cs @@ -16,6 +16,7 @@ static void Postfix() { if (ping.mapId != -1) continue; if (ping.PlayerInfo is not { } player) continue; + if (ping.planetTile.Layer == null) continue; var layer = Find.WorldSelector.SelectedLayer; // Only display pings on the current layer or (if enabled) on layers we can zoom to.