From 7892560c147c3f8a035fb30ae7001c3d0358b7cc Mon Sep 17 00:00:00 2001 From: Smyler Date: Mon, 15 Jan 2024 00:44:33 +0100 Subject: [PATCH] Make map save state restoration more forgiving of invalid save files --- .../terramap/gui/widgets/map/MapWidget.java | 24 ++++++++++++++----- .../saving/client/ClientSaveManager.java | 4 +++- .../gui/widgets/map/MapWidgetTest.java | 18 ++++++++++++++ 3 files changed, 39 insertions(+), 7 deletions(-) diff --git a/src/main/java/fr/thesmyler/terramap/gui/widgets/map/MapWidget.java b/src/main/java/fr/thesmyler/terramap/gui/widgets/map/MapWidget.java index 8656a009..bc3ea150 100644 --- a/src/main/java/fr/thesmyler/terramap/gui/widgets/map/MapWidget.java +++ b/src/main/java/fr/thesmyler/terramap/gui/widgets/map/MapWidget.java @@ -139,7 +139,7 @@ public boolean isVisible(WidgetContainer parent) { this.errorText = new TextWidget(Integer.MAX_VALUE, font) { @Override public boolean isVisible(WidgetContainer parent) { - return MapWidget.this.reportedErrors.size() > 0 && MapWidget.this.context == MapContext.FULLSCREEN; + return !MapWidget.this.reportedErrors.isEmpty() && MapWidget.this.context == MapContext.FULLSCREEN; } }; this.errorText.setBackgroundColor(Color.ERROR_OVERLAY).setPadding(5).setAlignment(TextAlignment.CENTER).setShadow(false).setBaseColor(Color.WHITE); @@ -312,7 +312,7 @@ public void onUpdate(float mouseX, float mouseY, WidgetContainer parent) { this.scale.setX(15).setY(this.copyright.getAnchorY() - 15); this.errorText.setAnchorX(this.getWidth() / 2).setAnchorY(0).setMaxWidth(this.getWidth() - 40); if(!this.rightClickMenu.isVisible(this)) this.updateMouseGeoPos(mouseX, mouseY); - if(this.reportedErrors.size() > 0) { + if(!this.reportedErrors.isEmpty()) { String errorText = SmyLibGui.getTranslator().format("terramap.mapwidget.error.header") + "\n" + this.reportedErrors.get((int) ((System.currentTimeMillis() / 3000)%this.reportedErrors.size())).message; this.errorText.setText(new TextComponentString(errorText)); } @@ -396,12 +396,12 @@ public void updateCopyright() { ITextComponent component = new TextComponentString(""); for(IWidget widget: this.widgets) if(widget instanceof CopyrightHolder){ - if(component.getFormattedText().length() > 0) component.appendText(" | "); + if(!component.getFormattedText().isEmpty()) component.appendText(" | "); ITextComponent copyright = ((CopyrightHolder)widget).getCopyright(SmyLibGui.getGameContext().getLanguage()); component.appendSibling(copyright); } this.copyright.setText(component); - this.copyright.setVisibility(component.getFormattedText().length() > 0); + this.copyright.setVisibility(!component.getFormattedText().isEmpty()); } private void updateMouseGeoPos(float mouseX, float mouseY) { @@ -734,14 +734,26 @@ public void restore(SavedMapState state) { new ArrayList<>(this.layers) // Avoid co-modification problems .forEach(this::removeLayer); for (SavedLayerState layerState: state.layers) { - MapLayer layer = this.createLayer(layerState.type); + MapLayer layer; + try { + layer = this.createLayer(layerState.type); + } catch (IllegalArgumentException e) { + TerramapMod.logger.warn("Could not restore a map layer. Did someone mess with the save file?"); + TerramapMod.logger.catching(e); + continue; + } this.setLayerZ(layer, layerState.z); layer.setVisibility(layerState.visible); layer.setAlpha(layerState.alpha); layer.setRenderingOffset(layerState.cartesianOffset); layer.setRotationOffset(layerState.rotationOffset); layer.setIsUserLayer(layerState.setByUser); - layer.loadSettings(layerState.settings); + try { + layer.loadSettings(layerState.settings); + } catch (Exception e) { + TerramapMod.logger.error("Caught exception when loading layer settings. Did someone mess with the save file?"); + TerramapMod.logger.catching(e); + } } Map controllers = this.getVisibilityControllers(); for (String key: state.visibilitySettings.keySet()) { diff --git a/src/main/java/fr/thesmyler/terramap/saving/client/ClientSaveManager.java b/src/main/java/fr/thesmyler/terramap/saving/client/ClientSaveManager.java index 01894600..d04cc9f2 100644 --- a/src/main/java/fr/thesmyler/terramap/saving/client/ClientSaveManager.java +++ b/src/main/java/fr/thesmyler/terramap/saving/client/ClientSaveManager.java @@ -148,11 +148,13 @@ public void createDirectoryIfNecessary() throws IOException { private SavedClientState loadFromPath(Path path) { try (FileReader reader = new FileReader(path.toFile())) { return GSON.fromJson(reader, SavedClientState.class); + } catch (FileNotFoundException ignored) { + // Let's not spam the console when it's just a new save. } catch (IOException e) { TerramapMod.logger.error("Failed to read a saved client state, will fallback to a new one"); TerramapMod.logger.catching(e); - return this.getDefaultState(); } + return this.getDefaultState(); } private void saveStateToPath(Path path, SavedClientState state) { diff --git a/src/test/java/fr/thesmyler/terramap/gui/widgets/map/MapWidgetTest.java b/src/test/java/fr/thesmyler/terramap/gui/widgets/map/MapWidgetTest.java index a7a791bd..14c8dfa8 100644 --- a/src/test/java/fr/thesmyler/terramap/gui/widgets/map/MapWidgetTest.java +++ b/src/test/java/fr/thesmyler/terramap/gui/widgets/map/MapWidgetTest.java @@ -113,6 +113,24 @@ public void canRestoreMapState() throws InterruptedException { } + @Test + public void canRestoreMapStateWithInvalidLayerId() throws InterruptedException { + + TestingWidgetContainer screen = new TestingWidgetContainer(60, 500f, 500f); + MapWidget map = new MapWidget(0f, 0f, 0, 500f, 500f, FULLSCREEN, 1f); + screen.moveMouse(750, 750, 1000); + screen.addWidget(map); + + SavedMapState state = new SavedMapState(); + SavedLayerState layerState = new SavedLayerState(); + layerState.type = "This is not a valid layer type"; + state.layers.add(layerState); + + map.restore(state); + screen.doTick(); + + } + @Test public void layersViewportsAreProperlyUpdatedWhenMapResizes() { MapWidget map = new MapWidget(0f, 0f, 0, 100f, 100F, FULLSCREEN, 1d);