diff --git a/core/src/mindustry/core/Control.java b/core/src/mindustry/core/Control.java index eb69d4e904..7a2574ccad 100644 --- a/core/src/mindustry/core/Control.java +++ b/core/src/mindustry/core/Control.java @@ -412,7 +412,8 @@ public class Control implements ApplicationListener, Loadable{ try{ boolean hadNoCore = !sector.info.hasCore; reloader.begin(); - slot.load(); + //pass in a sector context to make absolutely sure the correct sector is written; it may differ from what's in the meta due to remapping. + slot.load(world.makeSectorContext(sector)); slot.setAutosave(true); state.rules.sector = sector; state.rules.cloudColor = sector.planet.landCloudColor; diff --git a/core/src/mindustry/core/World.java b/core/src/mindustry/core/World.java index 8852976c90..1ad6f1176d 100644 --- a/core/src/mindustry/core/World.java +++ b/core/src/mindustry/core/World.java @@ -579,10 +579,19 @@ public class World{ } } + public WorldContext makeSectorContext(Sector sector){ + return new Context(sector); + } + private class Context implements WorldContext{ + private Sector sector; Context(){} + Context(Sector sector){ + this.sector = sector; + } + @Override public Tile tile(int index){ return tiles.geti(index); @@ -614,6 +623,12 @@ public class World{ public void end(){ endMapLoad(); } + + @Nullable + @Override + public Sector getSector(){ + return sector; + } } /** World context that applies filters after generation end. */ diff --git a/core/src/mindustry/game/Saves.java b/core/src/mindustry/game/Saves.java index b14dd4cd78..7cb008d520 100644 --- a/core/src/mindustry/game/Saves.java +++ b/core/src/mindustry/game/Saves.java @@ -13,6 +13,7 @@ import mindustry.io.*; import mindustry.io.SaveIO.*; import mindustry.maps.Map; import mindustry.type.*; +import mindustry.world.*; import java.io.*; import java.text.*; @@ -69,27 +70,72 @@ public class Saves{ } } - //clear saves from build <130 that had the new naval sectors. - saves.removeAll(s -> { - if(s.getSector() != null && (s.getSector().id == 108 || s.getSector().id == 216) && s.meta.build <= 130 && s.meta.build > 0){ - s.getSector().clearInfo(); - s.file.delete(); - return true; - } - return false; - }); - lastSectorSave = saves.find(s -> s.isSector() && s.getName().equals(Core.settings.getString("last-sector-save", ""))); + ObjectSet infoToClear = new ObjectSet<>(), remapped = new ObjectSet<>(); + //automatically assign sector save slots for(SaveSlot slot : saves){ if(slot.getSector() != null){ - if(slot.getSector().save != null){ - Log.warn("Sector @ has two corresponding saves: @ and @", slot.getSector(), slot.getSector().save.file, slot.file); + Sector sector = slot.getSector(); + + String name = slot.meta.tags.get("sectorPreset"); + Sector remapTarget = null; + + if(name != null){ + if(!name.isEmpty()){ //if this save had a preset defined... + SectorPreset preset = content.sector(name); + //...place it in the right sector according to its preset + if(preset != null && preset.sector != sector){ + remapTarget = preset.sector; + } + } + }else{ //there was no sector preset in the meta at all, which means this is a legacy save that may need mapping + SectorPreset target = content.sectors().find(s -> s.planet == sector.planet && s.originalPosition == sector.id); + if(target != null && target.sector != sector){ //there is indeed a sector preset that used to have this ID, and it needs remapping! + remapTarget = target.sector; + } + } + + if(remapTarget != null){ + //if the file name matches the destination of the remap, assume it has already been remapped, and skip the file movement procedure + if(!slot.file.equals(getSectorFile(remapTarget))){ + Log.info("Remapping sectors: @: @ -> @", sector.id, remapTarget.id); + + //overwrite the target sector's info with the save's info + Core.settings.putJson(remapTarget.planet.name + "-s-" + remapTarget.id + "-info", sector.info); + remapTarget.loadInfo(); + + //queue a clear of the sector that had its data moved + infoToClear.add(sector); + //add to the remapped list (if it was remapped, don't clear it!) + remapped.add(remapTarget); + + remapTarget.save = slot; + try{ + //move over save file + slot.file.moveTo(getSectorFile(remapTarget)); + }catch(Exception e){ + Log.err("Failed to move sector files when remapping: " + sector.id + " -> " + remapTarget.id, e); + } + } + + remapTarget.save = slot; + slot.meta.rules.sector = remapTarget; + }else{ + if(sector.save != null){ + Log.warn("Sector @ has two corresponding saves: @ and @", sector, sector.save.file, slot.file); + } + sector.save = slot; } - slot.getSector().save = slot; } } + + for(var sector : infoToClear){ + if(!remapped.contains(sector)){ + sector.clearInfo(); + } + } } public @Nullable SaveSlot getLastSector(){ @@ -207,8 +253,12 @@ public class Saves{ } public void load() throws SaveException{ + load(world.context); + } + + public void load(WorldContext context) throws SaveException{ try{ - SaveIO.load(file); + SaveIO.load(file, context); meta = SaveIO.getMeta(file); current = this; totalPlaytime = meta.timePlayed; @@ -313,6 +363,7 @@ public class Saves{ } public @Nullable Sector getSector(){ + //TODO remap sectors return meta == null || meta.rules == null ? null : meta.rules.sector; } diff --git a/core/src/mindustry/io/SaveVersion.java b/core/src/mindustry/io/SaveVersion.java index 558c915d1e..70cb4b3f46 100644 --- a/core/src/mindustry/io/SaveVersion.java +++ b/core/src/mindustry/io/SaveVersion.java @@ -140,6 +140,7 @@ public abstract class SaveVersion extends SaveFileReader{ "wavetime", state.wavetime, "stats", JsonIO.write(state.stats), "rules", JsonIO.write(state.rules), + "sectorPreset", state.rules.sector != null && state.rules.sector.preset != null ? state.rules.sector.preset.name : "", //empty string is a placeholder for null (null is possible but may be finicky) "locales", JsonIO.write(state.mapLocales), "mods", JsonIO.write(mods.getModStrings().toArray(String.class)), "controlGroups", headless || control == null ? "null" : JsonIO.write(control.input.controlGroups), diff --git a/core/src/mindustry/type/SectorPreset.java b/core/src/mindustry/type/SectorPreset.java index ea00349fa2..220ffc2ec2 100644 --- a/core/src/mindustry/type/SectorPreset.java +++ b/core/src/mindustry/type/SectorPreset.java @@ -34,6 +34,8 @@ public class SectorPreset extends UnlockableContent{ public boolean allowLaunchLoadout = false; /** If true, switches to attack mode after waves end. */ public boolean attackAfterWaves = false; + /** The original position of this sector; used for migration. Internal use for vanilla campaign only! */ + public int originalPosition; public SectorPreset(String name, Planet planet, int sector){ this(name, null, planet, sector); @@ -61,6 +63,7 @@ public class SectorPreset extends UnlockableContent{ public void initialize(Planet planet, int sector){ this.planet = planet; + this.originalPosition = sector; //auto remap based on data var data = planet.getData(); if(data != null){