Skip to content

Commit af3bed5

Browse files
Fixes #447 Fix JumpPoint generation, add some error checking around jump points/systems as well
1 parent 9afb192 commit af3bed5

5 files changed

Lines changed: 110 additions & 7 deletions

File tree

Pulsar4X/GameEngine/Engine/Game.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
using Pulsar4X.Factions;
1414
using Pulsar4X.Galaxy;
1515
using Pulsar4X.Energy;
16+
using Pulsar4X.JumpPoints;
1617
using Pulsar4X.Sensors;
1718
using Pulsar4X.Logistics;
1819
using Pulsar4X.Messaging;
@@ -249,6 +250,9 @@ public static Game Load(string json)
249250

250251
public void PostNewGameInitialization()
251252
{
253+
// Link all JumpPoints between systems
254+
JPFactory.LinkAllJumpPoints(this);
255+
252256
// There are few DB's that need to run the processor when the game begins
253257
foreach(var system in Systems)
254258
{

Pulsar4X/GameEngine/Galaxy/StarSystemFactory.cs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,7 @@ public StarSystem CreateTestSystem(Game game, int x = 0, int y = 0)
191191
SensorTools.PlanetEmmisionSig(sensorProfile, halleysBodyDB, halleysMVDB);
192192

193193
JPSurveyFactory.GenerateJPSurveyPoints(sol);
194+
JPFactory.GenerateJumpPoints(this, sol, sun.GetDataBlob<PositionDB>().Root);
194195

195196
game.GameMasterFaction.GetDataBlob<FactionInfoDB>().KnownSystems.Add(sol.ID);
196197
return sol;
@@ -303,8 +304,8 @@ public StarSystem CreateSol(Game game)
303304
var halleysComet = SystemBodyFactory.Create(game, sol, sun, new System.DateTime(1994, 2, 17), new SensorProfileDB(), "Data/basemod/bodies/halleyscomet.json");
304305
_systemBodyFactory.MineralGeneration(game.StartingGameData.Minerals.Values.ToList(), sol, halleysComet);
305306

306-
// Clean up cached RNG:
307307
JPSurveyFactory.GenerateJPSurveyPoints(sol);
308+
JPFactory.GenerateJumpPoints(this, sol, sun.GetDataBlob<PositionDB>().Root);
308309

309310
// Go through all the created entities and set them to be neutral
310311
foreach(var entity in sol.GetAllEntites())
@@ -370,6 +371,11 @@ public StarSystem LoadSystemFromJson(Game game, string folder)
370371
JPSurveyFactory.GenerateJPSurveyPoints(system);
371372
}
372373

374+
if(rootStar != null)
375+
{
376+
JPFactory.GenerateJumpPoints(this, system, rootStar.GetDataBlob<PositionDB>().Root);
377+
}
378+
373379
// Go through all the created entities and set them to be neutral
374380
foreach(var entity in system.GetAllEntites())
375381
{
@@ -418,6 +424,11 @@ public static StarSystem LoadFromBlueprint(Game game, SystemBlueprint systemBlue
418424
JPSurveyFactory.GenerateJPSurveyPoints(system);
419425
}
420426

427+
if(rootStar != null)
428+
{
429+
JPFactory.GenerateJumpPoints(galaxyGen.StarSystemFactory, system, rootStar.GetDataBlob<PositionDB>().Root);
430+
}
431+
421432
// Go through all the created entities and set them to be neutral
422433
foreach(var entity in system.GetAllEntites())
423434
{

Pulsar4X/GameEngine/JumpPoints/JPFactory.cs

Lines changed: 79 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
1-
using Pulsar4X.Orbital;
1+
using System;
22
using System.Collections.Generic;
3+
using System.Linq;
34
using Pulsar4X.Datablobs;
45
using Pulsar4X.Engine;
5-
using Pulsar4X.Names;
6-
using Pulsar4X.Orbits;
76
using Pulsar4X.Galaxy;
87
using Pulsar4X.Movement;
8+
using Pulsar4X.Names;
9+
using Pulsar4X.Orbital;
10+
using Pulsar4X.Orbits;
911

1012
namespace Pulsar4X.JumpPoints
1113
{
@@ -102,6 +104,14 @@ public static void GenerateJumpPoints(StarSystemFactory ssf, StarSystem system,
102104
{
103105
int numJumpPoints = GetNumJPForSystem(system);
104106

107+
// Cap JumpPoints to maxSystems - 1 to ensure we don't create more than can be linked
108+
// In a 2-system game, each system should have at most 1 JP
109+
int maxSystems = system.Game.Settings.MaxSystems;
110+
if (maxSystems > 1 && numJumpPoints > maxSystems - 1)
111+
{
112+
numJumpPoints = maxSystems - 1;
113+
}
114+
105115
while (numJumpPoints > 0)
106116
{
107117
numJumpPoints--;
@@ -129,5 +139,71 @@ private static void LinkJumpPoints(Entity JP1, Entity JP2)
129139
jp1TransitableDB.DestinationId = JP2.Id;
130140
jp2TransitableDB.DestinationId = JP1.Id;
131141
}
142+
143+
/// <summary>
144+
/// Links all unlinked JumpPoints across all systems in the game.
145+
/// JumpPoints are paired between different systems to create inter-system connections.
146+
/// </summary>
147+
public static void LinkAllJumpPoints(Game game)
148+
{
149+
// Collect all unlinked JumpPoints grouped by system
150+
var unlinkedBySystem = new Dictionary<string, List<Entity>>();
151+
152+
foreach (var system in game.Systems)
153+
{
154+
var jumpPoints = system.GetAllEntitiesWithDataBlob<JumpPointDB>()
155+
.Where(jp => jp.GetDataBlob<JumpPointDB>().DestinationId <= 0)
156+
.ToList();
157+
158+
if (jumpPoints.Count > 0)
159+
{
160+
unlinkedBySystem[system.ID] = jumpPoints;
161+
}
162+
}
163+
164+
// If we have fewer than 2 systems with JumpPoints, nothing to link
165+
if (unlinkedBySystem.Count < 2)
166+
return;
167+
168+
var systemIds = unlinkedBySystem.Keys.ToList();
169+
var random = new Random(game.Settings.MasterSeed);
170+
171+
// Keep linking JumpPoints until we can't make any more pairs
172+
bool madeLink;
173+
do
174+
{
175+
madeLink = false;
176+
177+
// Find two systems that both have unlinked JumpPoints
178+
var systemsWithJPs = systemIds.Where(id => unlinkedBySystem[id].Count > 0).ToList();
179+
180+
if (systemsWithJPs.Count < 2)
181+
break;
182+
183+
// Pick two different systems randomly
184+
int idx1 = random.Next(systemsWithJPs.Count);
185+
string system1Id = systemsWithJPs[idx1];
186+
systemsWithJPs.RemoveAt(idx1);
187+
188+
int idx2 = random.Next(systemsWithJPs.Count);
189+
string system2Id = systemsWithJPs[idx2];
190+
191+
// Get one JumpPoint from each system
192+
var jp1List = unlinkedBySystem[system1Id];
193+
var jp2List = unlinkedBySystem[system2Id];
194+
195+
var jp1 = jp1List[random.Next(jp1List.Count)];
196+
var jp2 = jp2List[random.Next(jp2List.Count)];
197+
198+
// Link them
199+
LinkJumpPoints(jp1, jp2);
200+
201+
// Remove from unlinked lists
202+
jp1List.Remove(jp1);
203+
jp2List.Remove(jp2);
204+
205+
madeLink = true;
206+
} while (madeLink);
207+
}
132208
}
133209
}

Pulsar4X/GameEngine/JumpPoints/JPSurveyProcessor.cs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,12 @@ private void RollToDiscoverJumpPoint(DateTime atDateTime, Entity discoveringEnti
136136

137137
private void RevealOtherSide(JumpPointDB jumpPointDB, DateTime atDateTime, Entity discoveringEntity)
138138
{
139-
if(discoveringEntity.Manager.TryGetGlobalEntityById(jumpPointDB.DestinationId, out var destinationEntity))
139+
// Skip if no destination is linked (DestinationId defaults to 0 which could match an unrelated entity)
140+
if(jumpPointDB.DestinationId <= 0)
141+
return;
142+
143+
if(discoveringEntity.Manager.TryGetGlobalEntityById(jumpPointDB.DestinationId, out var destinationEntity)
144+
&& destinationEntity.HasDataBlob<JumpPointDB>())
140145
{
141146
var factionInfoDB = discoveringEntity.Manager.Game.Factions[discoveringEntity.FactionOwnerID].GetDataBlob<FactionInfoDB>();
142147

Pulsar4X/Pulsar4X.Client/State/GlobalUIState.cs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,8 @@ internal void SetFaction(Entity factionEntity, bool setAsPlayer = false)
221221
StarSystemStates = new SafeDictionary<string, SystemState>();
222222
foreach (var guid in factionInfo.KnownSystems)
223223
{
224-
var system = Game.Systems.First(s => s.ID.Equals(guid));
224+
var system = Game.Systems.FirstOrDefault(s => s.ID.Equals(guid));
225+
if(system == null) continue;
225226
StarSystemStates[guid] = new SystemState(system, factionEntity.Id);
226227
}
227228

@@ -242,7 +243,13 @@ await Task.Run(() => {
242243
if(message.SystemId != null)
243244
{
244245
if(!StarSystemStates.ContainsKey(message.SystemId)){
245-
StarSystemStates[message.SystemId] = new SystemState(Game.Systems.First(s => s.ID.Equals(message.SystemId)), Faction.Id);
246+
var system = Game.Systems.FirstOrDefault(s => s.ID.Equals(message.SystemId));
247+
if(system == null)
248+
{
249+
Console.WriteLine($"ERROR: {message.SystemId} was revealed but not found in the game systems.");
250+
return;
251+
}
252+
StarSystemStates[message.SystemId] = new SystemState(system, Faction.Id);
246253
}
247254
OnStarSystemAdded?.Invoke(this, message.SystemId);
248255
}

0 commit comments

Comments
 (0)