From 965550ab0da908f3514967308b15e339735a21a6 Mon Sep 17 00:00:00 2001 From: Anuken Date: Wed, 15 Jul 2026 12:04:34 -0400 Subject: [PATCH 1/9] Antialiasing cleanup --- tools/build.gradle | 78 +++++----------------------------------------- 1 file changed, 7 insertions(+), 71 deletions(-) diff --git a/tools/build.gradle b/tools/build.gradle index 7ea0f843ea..9552180560 100644 --- a/tools/build.gradle +++ b/tools/build.gradle @@ -1,10 +1,12 @@ sourceSets.main.java.srcDirs = ["src/"] + + import arc.files.Fi import arc.files.ZipFi import arc.func.Func2 -import arc.graphics.Color import arc.graphics.Pixmap +import arc.graphics.Pixmaps import arc.packer.TexturePacker import arc.struct.IntMap import arc.struct.ObjectMap @@ -30,76 +32,10 @@ static int getRGB(Pixmap image, int ix, int iy) { @groovy.transform.CompileStatic static void antialias(File file){ - Pixmap image = new Pixmap(new Fi(file)) - Pixmap out = image.copy() - - Color color = new Color() - Color sum = new Color() - Color suma = new Color() - int[] p = new int[9] - - for(int x = 0; x < image.width; x++){ - for(int y = 0; y < image.height; y++){ - int A = getRGB(image, x - 1, y + 1), - B = getRGB(image, x, y + 1), - C = getRGB(image, x + 1, y + 1), - D = getRGB(image, x - 1, y), - E = getRGB(image, x, y), - F = getRGB(image, x + 1, y), - G = getRGB(image, x - 1, y - 1), - H = getRGB(image, x, y - 1), - I = getRGB(image, x + 1, y - 1) - - Arrays.fill(p, E) - - if(D == B && D != H && B != F) p[0] = D - if((D == B && D != H && B != F && E != C) || (B == F && B != D && F != H && E != A)) p[1] = B - if(B == F && B != D && F != H) p[2] = F - if((H == D && H != F && D != B && E != A) || (D == B && D != H && B != F && E != G)) p[3] = D - if((B == F && B != D && F != H && E != I) || (F == H && F != B && H != D && E != C)) p[5] = F - if(H == D && H != F && D != B) p[6] = D - if((F == H && F != B && H != D && E != G) || (H == D && H != F && D != B && E != I)) p[7] = H - if(F == H && F != B && H != D) p[8] = F - - suma.set(0) - - for(int val : p){ - color.rgba8888(val) - color.premultiplyAlpha() - suma.r(suma.r + color.r) - suma.g(suma.g + color.g) - suma.b(suma.b + color.b) - suma.a(suma.a + color.a) - } - - float fm = suma.a <= 0.001f ? 0f : (float)(1f / suma.a) - suma.mul(fm, fm, fm, fm) - - float total = 0 - sum.set(0) - - for(int val : p){ - color.rgba8888(val) - float a = color.a - color.lerp(suma, (float) (1f - a)) - sum.r(sum.r + color.r) - sum.g(sum.g + color.g) - sum.b(sum.b + color.b) - sum.a(sum.a + a) - total += 1f - } - - fm = (float)(1f / total) - sum.mul(fm, fm, fm, fm) - out.setRaw(x, y, sum.rgba8888()) - sum.set(0) - } - } - - image.dispose() - out.dispose() - - new Fi(file).writePng(out) + Pixmap result = new Pixmap(new Fi(file)) + Pixmaps.antialias(result) + new Fi(file).writePng(result) + result.dispose() } tasks.register('antialiasImages'){ From cef447356b06337240b3c9ddb5ffed9dbf7f9051 Mon Sep 17 00:00:00 2001 From: Anuken Date: Wed, 15 Jul 2026 12:07:18 -0400 Subject: [PATCH 2/9] Cleanup 2 --- gradle.properties | 2 +- tools/build.gradle | 35 ++++++++++------------------------- 2 files changed, 11 insertions(+), 26 deletions(-) diff --git a/gradle.properties b/gradle.properties index fdc69199ee..76302350a4 100644 --- a/gradle.properties +++ b/gradle.properties @@ -26,4 +26,4 @@ org.gradle.caching=true org.gradle.internal.http.socketTimeout=100000 org.gradle.internal.http.connectionTimeout=100000 android.enableR8.fullMode=false -archash=0137716a3c +archash=208a754044 diff --git a/tools/build.gradle b/tools/build.gradle index 9552180560..dc1eef7930 100644 --- a/tools/build.gradle +++ b/tools/build.gradle @@ -1,36 +1,21 @@ sourceSets.main.java.srcDirs = ["src/"] +import arc.files.* +import arc.func.* +import arc.graphics.* +import arc.packer.* +import arc.struct.* +import arc.util.* +import arc.util.io.* +import groovy.transform.* -import arc.files.Fi -import arc.files.ZipFi -import arc.func.Func2 -import arc.graphics.Pixmap -import arc.graphics.Pixmaps -import arc.packer.TexturePacker -import arc.struct.IntMap -import arc.struct.ObjectMap -import arc.struct.OrderedMap -import arc.struct.Seq -import arc.util.Http -import arc.util.Log -import arc.util.OS -import arc.util.Threads -import arc.util.io.PropertiesUtils -import arc.util.io.Streams - -import java.util.concurrent.ExecutorService -import java.util.concurrent.Executors +import java.util.concurrent.* def genFolder = "../core/assets-raw/sprites_out/generated/" def enableAA = true -@groovy.transform.CompileStatic -static int getRGB(Pixmap image, int ix, int iy) { - return image.getRaw(Math.max(Math.min(ix, image.width - 1), 0), Math.max(Math.min(iy, image.height - 1), 0)) -} - -@groovy.transform.CompileStatic +@CompileStatic static void antialias(File file){ Pixmap result = new Pixmap(new Fi(file)) Pixmaps.antialias(result) From 91c3e507717b7d844d9df2392372bc6859183e60 Mon Sep 17 00:00:00 2001 From: Anuken Date: Wed, 15 Jul 2026 14:21:38 -0400 Subject: [PATCH 3/9] Android file chooser fixes & support for save loading from file browser --- android/AndroidManifest.xml | 20 +++++ .../mindustry/android/AndroidLauncher.java | 82 +++++++++-------- core/src/mindustry/io/SaveMeta.java | 4 + core/src/mindustry/maps/Maps.java | 6 +- core/src/mindustry/ui/FileChooser.java | 2 +- .../ui/dialogs/EditorMapsDialog.java | 88 ++++++++++--------- 6 files changed, 117 insertions(+), 85 deletions(-) diff --git a/android/AndroidManifest.xml b/android/AndroidManifest.xml index 60e0dbc1d8..78c3080541 100644 --- a/android/AndroidManifest.xml +++ b/android/AndroidManifest.xml @@ -25,6 +25,7 @@ android:label="@string/app_name" android:screenOrientation="user" android:exported="true" + android:launchMode="singleTask" android:configChanges="keyboard|keyboardHidden|orientation|screenSize|screenLayout"> @@ -39,6 +40,25 @@ + + + + + + + + + + + + + + + + + + + diff --git a/android/src/mindustry/android/AndroidLauncher.java b/android/src/mindustry/android/AndroidLauncher.java index 652f494796..ea9fdc8a4d 100644 --- a/android/src/mindustry/android/AndroidLauncher.java +++ b/android/src/mindustry/android/AndroidLauncher.java @@ -16,6 +16,7 @@ import arc.struct.*; import arc.util.*; import dalvik.system.*; import mindustry.*; +import mindustry.game.EventType.*; import mindustry.game.Saves.*; import mindustry.io.*; import mindustry.net.*; @@ -222,7 +223,9 @@ public class AndroidLauncher extends AndroidApplication{ hideStatusBar = true; useGL30 = true; }}); - checkFiles(getIntent()); + + var intent = getIntent(); + Events.on(ClientLoadEvent.class, u -> handleFiles(intent)); try{ //new external folder @@ -280,54 +283,49 @@ public class AndroidLauncher extends AndroidApplication{ } } - private void checkFiles(Intent intent){ + @Override + protected void onNewIntent(Intent intent){ + super.onNewIntent(intent); + + handleFiles(intent); + } + + private void handleFiles(Intent intent){ + if(intent == null) return; + try{ Uri uri = intent.getData(); if(uri != null){ - File myFile = null; - String scheme = uri.getScheme(); - if(scheme.equals("file")){ - String fileName = uri.getEncodedPath(); - myFile = new File(fileName); - }else if(!scheme.equals("content")){ - //error - return; - } - boolean save = uri.getPath().endsWith(saveExtension); - boolean map = uri.getPath().endsWith(mapExtension); - InputStream inStream; - if(myFile != null) inStream = new FileInputStream(myFile); - else inStream = getContentResolver().openInputStream(uri); - Core.app.post(() -> Core.app.post(() -> { - if(save){ //open save - System.out.println("Opening save."); - Fi file = Core.files.local("temp-save." + saveExtension); - file.write(inStream, false); - if(SaveIO.isSaveValid(file)){ - try{ - SaveSlot slot = control.saves.importSave(file); - ui.load.runLoadSave(slot); - }catch(IOException e){ - ui.showException("@save.import.fail", e); + + Fi file = Core.files.cache("temp-save." + saveExtension); + file.write(getContentResolver().openInputStream(uri), false); + //TODO: how to check if it's a server URL? e.g: mindustry://myserver.com or mindustry://127.0.0.1 + + //may run on a different thread + Core.app.post(() -> { + try{ + SaveMeta meta = SaveIO.getMeta(file); + if(!meta.isMap()){ //open save + SaveSlot slot = control.saves.importSave(file); + ui.load.runLoadSave(slot); + }else{ //open map + if(!ui.maps.isShown()){ + ui.maps.show(); } - }else{ - ui.showErrorMessage("@save.import.invalid"); + ui.maps.tryImportMap(file, result -> ui.maps.showMap(result)); } - }else if(map){ //open map - Fi file = Core.files.local("temp-map." + mapExtension); - file.write(inStream, false); - Core.app.post(() -> { - System.out.println("Opening map."); - if(!ui.editor.isShown()){ - ui.editor.show(); - } - ui.editor.beginEditMap(file); - }); + }catch(Throwable e){ + Log.err("Failed to load save", e); + ui.showException("@save.import.invalid", e); } - })); + }); + + //clear data (not sure if necessary?) + intent.setAction(Intent.ACTION_MAIN); + intent.setData(null); } - }catch(IOException e){ - e.printStackTrace(); + }catch(Throwable e){ + Log.err(e); } } diff --git a/core/src/mindustry/io/SaveMeta.java b/core/src/mindustry/io/SaveMeta.java index 46b94ff978..30e536d228 100644 --- a/core/src/mindustry/io/SaveMeta.java +++ b/core/src/mindustry/io/SaveMeta.java @@ -28,4 +28,8 @@ public class SaveMeta{ this.tags = tags; this.mods = JsonIO.read(String[].class, tags.get("mods", "[]")); } + + public boolean isMap(){ + return tags.containsKey("name"); + } } diff --git a/core/src/mindustry/maps/Maps.java b/core/src/mindustry/maps/Maps.java index 12859cc2c4..93b0e1fe92 100644 --- a/core/src/mindustry/maps/Maps.java +++ b/core/src/mindustry/maps/Maps.java @@ -267,8 +267,8 @@ public class Maps{ } } - /** Import a map, then save it. This updates all values and stored data necessary. */ - public void importMap(Fi file) throws IOException{ + /** Imports a map, then saves it. This updates all values and stored data necessary. */ + public Map importMap(Fi file) throws IOException{ Fi dest = findFile(file.name()); file.copyTo(dest); @@ -288,6 +288,8 @@ public class Maps{ if(error[0] != null){ throw new IOException(error[0]); } + + return map; } /** Attempts to run the following code; diff --git a/core/src/mindustry/ui/FileChooser.java b/core/src/mindustry/ui/FileChooser.java index a76fb241d7..4dd1482210 100644 --- a/core/src/mindustry/ui/FileChooser.java +++ b/core/src/mindustry/ui/FileChooser.java @@ -14,7 +14,7 @@ public class FileChooser{ public static void export(String name, String extension, FileWriter writer){ if(!ios){ - FileChooser.save(extension).name(name).submit(file -> { + FileChooser.save(extension).name(name.endsWith("." + extension) ? name : name + "." + extension).submit(file -> { ui.loadAnd(() -> { try{ writer.write(file); diff --git a/core/src/mindustry/ui/dialogs/EditorMapsDialog.java b/core/src/mindustry/ui/dialogs/EditorMapsDialog.java index 017381f263..b1ece85c3d 100644 --- a/core/src/mindustry/ui/dialogs/EditorMapsDialog.java +++ b/core/src/mindustry/ui/dialogs/EditorMapsDialog.java @@ -2,6 +2,7 @@ package mindustry.ui.dialogs; import arc.*; import arc.files.*; +import arc.func.*; import arc.graphics.*; import arc.scene.ui.*; import arc.scene.ui.layout.*; @@ -44,53 +45,60 @@ public class EditorMapsDialog extends MapListDialog{ FileChooser.open(mapExtension).submitMulti(files -> { ui.loadAnd(() -> { for(Fi file : files){ - maps.tryCatchMapError(() -> { - if(MapIO.isImage(file)){ - ui.showErrorMessage("@editor.errorimage"); - return; - } - - Map map = MapIO.createMap(file, true); - - //when you attempt to import a save, it will have no name, so generate one - String name = map.tags.get("name", () -> { - String result = "unknown"; - int number = 0; - while(maps.byName(result + number++) != null) ; - return result + number; - }); - - //this will never actually get called, but it remains just in case - if(name == null){ - ui.showErrorMessage("@editor.errorname"); - return; - } - - Map conflict = maps.all().find(m -> m.name().equalsIgnoreCase(name)); - - if(conflict != null && !conflict.custom){ - ui.showInfo(Core.bundle.format("editor.import.exists", name)); - }else if(conflict != null){ - ui.showConfirm("@confirm", Core.bundle.format("editor.overwrite.confirm", map.name()), () -> { - maps.tryCatchMapError(() -> { - maps.removeMap(conflict); - maps.importMap(map.file); - setup(); - }); - }); - }else{ - maps.importMap(map.file); - setup(); - } - }); + tryImportMap(file, null); } }); }); }).size(210f, 64f); } + public void tryImportMap(Fi file, @Nullable Cons success){ + maps.tryCatchMapError(() -> { + if(MapIO.isImage(file)){ + ui.showErrorMessage("@editor.errorimage"); + return; + } + + Map map = MapIO.createMap(file, true); + + //when you attempt to import a save, it will have no name, so generate one + String name = map.tags.get("name", () -> { + String result = "unknown"; + int number = 0; + while(maps.byName(result + number++) != null) ; + return result + number; + }); + + //this will never actually get called, but it remains just in case + if(name == null){ + ui.showErrorMessage("@editor.errorname"); + return; + } + + Map conflict = maps.all().find(m -> m.name().equalsIgnoreCase(name)); + + if(conflict != null && !conflict.custom){ + ui.showInfo(Core.bundle.format("editor.import.exists", name)); + }else if(conflict != null){ + ui.showConfirm("@confirm", Core.bundle.format("editor.overwrite.confirm", map.name()), () -> { + maps.tryCatchMapError(() -> { + maps.removeMap(conflict); + var imported = maps.importMap(map.file); + setup(); + + if(success != null) success.get(imported); + }); + }); + }else{ + var imported = maps.importMap(map.file); + setup(); + if(success != null) success.get(imported); + } + }); + } + @Override - void showMap(Map map){ + public void showMap(Map map){ BaseDialog dialog = activeDialog = new BaseDialog("@editor.mapinfo"); dialog.addCloseButton(); From 5e426a60c1f79b756188856554cedea6e21342f9 Mon Sep 17 00:00:00 2001 From: Anuken Date: Wed, 15 Jul 2026 14:41:28 -0400 Subject: [PATCH 4/9] Support for mindustry:// URLs for joining servers on Android --- .../mindustry/android/AndroidLauncher.java | 58 +++++++++++-------- core/assets/bundles/bundle.properties | 1 + 2 files changed, 36 insertions(+), 23 deletions(-) diff --git a/android/src/mindustry/android/AndroidLauncher.java b/android/src/mindustry/android/AndroidLauncher.java index ea9fdc8a4d..74c9df8ae3 100644 --- a/android/src/mindustry/android/AndroidLauncher.java +++ b/android/src/mindustry/android/AndroidLauncher.java @@ -225,7 +225,7 @@ public class AndroidLauncher extends AndroidApplication{ }}); var intent = getIntent(); - Events.on(ClientLoadEvent.class, u -> handleFiles(intent)); + Events.on(ClientLoadEvent.class, u -> handleIntent(intent)); try{ //new external folder @@ -287,38 +287,50 @@ public class AndroidLauncher extends AndroidApplication{ protected void onNewIntent(Intent intent){ super.onNewIntent(intent); - handleFiles(intent); + handleIntent(intent); } - private void handleFiles(Intent intent){ + private void handleIntent(Intent intent){ if(intent == null) return; try{ Uri uri = intent.getData(); if(uri != null){ + String scheme = uri.getScheme(); - Fi file = Core.files.cache("temp-save." + saveExtension); - file.write(getContentResolver().openInputStream(uri), false); - //TODO: how to check if it's a server URL? e.g: mindustry://myserver.com or mindustry://127.0.0.1 + if("mindustry".equalsIgnoreCase(scheme)){ //open a server URL - //may run on a different thread - Core.app.post(() -> { - try{ - SaveMeta meta = SaveIO.getMeta(file); - if(!meta.isMap()){ //open save - SaveSlot slot = control.saves.importSave(file); - ui.load.runLoadSave(slot); - }else{ //open map - if(!ui.maps.isShown()){ - ui.maps.show(); - } - ui.maps.tryImportMap(file, result -> ui.maps.showMap(result)); - } - }catch(Throwable e){ - Log.err("Failed to load save", e); - ui.showException("@save.import.invalid", e); + String host = uri.getHost(); + int port = uri.getPort(); + + if(host != null && !host.isEmpty()){ + Core.app.post(() -> { + ui.showConfirm(Core.bundle.format("servers.connect.confirm", host), () -> ui.join.connect(host, port != -1 ? port : 6567)); + }); } - }); + }else{ //open a save file + Fi file = Core.files.cache("temp-save." + saveExtension); + file.write(getContentResolver().openInputStream(uri), false); + + //may run on a different thread + Core.app.post(() -> { + try{ + SaveMeta meta = SaveIO.getMeta(file); + if(!meta.isMap()){ //open save + SaveSlot slot = control.saves.importSave(file); + ui.load.runLoadSave(slot); + }else{ //open map + if(!ui.maps.isShown()){ + ui.maps.show(); + } + ui.maps.tryImportMap(file, result -> ui.maps.showMap(result)); + } + }catch(Throwable e){ + Log.err("Failed to load save", e); + ui.showException("@save.import.invalid", e); + } + }); + } //clear data (not sure if necessary?) intent.setAction(Intent.ACTION_MAIN); diff --git a/core/assets/bundles/bundle.properties b/core/assets/bundles/bundle.properties index f4a666b9ab..d83e7b5564 100644 --- a/core/assets/bundles/bundle.properties +++ b/core/assets/bundles/bundle.properties @@ -283,6 +283,7 @@ servers.remote = Remote Servers servers.global = Community Servers servers.disclaimer = Community servers are [accent]not[] owned or controlled by the developer.\n\nServers may contain user-generated content that is not appropriate for all ages. +servers.connect.confirm = Join the following server?\n\n[accent]{0}[]\n\nOnly connect to servers you trust! servers.showhidden = Show Hidden Servers server.shown = Shown server.hidden = Hidden From 23fb20abe3cf003b94360ef904b6f0773a6a749d Mon Sep 17 00:00:00 2001 From: Github Actions Date: Wed, 15 Jul 2026 18:42:10 +0000 Subject: [PATCH 5/9] Automatic bundle update --- core/assets/bundles/bundle_be.properties | 1 + core/assets/bundles/bundle_bg.properties | 1 + core/assets/bundles/bundle_ca.properties | 1 + core/assets/bundles/bundle_cs.properties | 1 + core/assets/bundles/bundle_da.properties | 1 + core/assets/bundles/bundle_de.properties | 1 + core/assets/bundles/bundle_es.properties | 1 + core/assets/bundles/bundle_et.properties | 1 + core/assets/bundles/bundle_eu.properties | 1 + core/assets/bundles/bundle_fi.properties | 1 + core/assets/bundles/bundle_fil.properties | 1 + core/assets/bundles/bundle_fr.properties | 1 + core/assets/bundles/bundle_hu.properties | 1 + core/assets/bundles/bundle_id_ID.properties | 1 + core/assets/bundles/bundle_it.properties | 1 + core/assets/bundles/bundle_ja.properties | 1 + core/assets/bundles/bundle_ko.properties | 1 + core/assets/bundles/bundle_lt.properties | 1 + core/assets/bundles/bundle_nl.properties | 1 + core/assets/bundles/bundle_nl_BE.properties | 1 + core/assets/bundles/bundle_pl.properties | 1 + core/assets/bundles/bundle_pt_BR.properties | 1 + core/assets/bundles/bundle_pt_PT.properties | 1 + core/assets/bundles/bundle_ro.properties | 1 + core/assets/bundles/bundle_ru.properties | 1 + core/assets/bundles/bundle_sr.properties | 1 + core/assets/bundles/bundle_sv.properties | 1 + core/assets/bundles/bundle_th.properties | 1 + core/assets/bundles/bundle_tk.properties | 1 + core/assets/bundles/bundle_tr.properties | 1 + core/assets/bundles/bundle_uk_UA.properties | 1 + core/assets/bundles/bundle_vi.properties | 1 + core/assets/bundles/bundle_zh_CN.properties | 1 + core/assets/bundles/bundle_zh_TW.properties | 1 + 34 files changed, 34 insertions(+) diff --git a/core/assets/bundles/bundle_be.properties b/core/assets/bundles/bundle_be.properties index a2af38b13e..cf19c1da0d 100644 --- a/core/assets/bundles/bundle_be.properties +++ b/core/assets/bundles/bundle_be.properties @@ -281,6 +281,7 @@ servers.remote = Выдаленыя серверы servers.global = Глабальныя серверы servers.disclaimer = Супольныя Серверы [accent]не[] звязаны або не кантралююцца распрацоўшчыкам.\n\nГэтыя серверы могуць утрымліваць згенераваны карыстальнікамі кантэнт які можа падыйсці не да усіх узростаў. +servers.connect.confirm = Join the following server?\n\n[accent]{0}[]\n\nOnly connect to servers you trust! servers.showhidden = Паказаць Схаваныя Серверы server.shown = Бачныя server.hidden = Схаваныя diff --git a/core/assets/bundles/bundle_bg.properties b/core/assets/bundles/bundle_bg.properties index b484fc3b26..0fde40eaed 100644 --- a/core/assets/bundles/bundle_bg.properties +++ b/core/assets/bundles/bundle_bg.properties @@ -281,6 +281,7 @@ servers.remote = Отдалечени Сървъри servers.global = Публични Сървъри servers.disclaimer = Публичните сървъри [accent]не[] са притежавани от разработчика.\n\nТе може да имат потребителско съдържание неподходящо за всички възрасти. +servers.connect.confirm = Join the following server?\n\n[accent]{0}[]\n\nOnly connect to servers you trust! servers.showhidden = Покажи Скритите Сървъри server.shown = Показан server.hidden = Скрит diff --git a/core/assets/bundles/bundle_ca.properties b/core/assets/bundles/bundle_ca.properties index 3b6e418273..e3afe53b6f 100644 --- a/core/assets/bundles/bundle_ca.properties +++ b/core/assets/bundles/bundle_ca.properties @@ -281,6 +281,7 @@ servers.remote = Servidors remots servers.global = Servidors de la comunitat servers.disclaimer = Els servidors de la comunitat [accent]no[] són ni els controla el desenvolupador.\n\nEls servidors poden tenir continguts generats per usuaris que no són adequats per a totes les edats. +servers.connect.confirm = Join the following server?\n\n[accent]{0}[]\n\nOnly connect to servers you trust! servers.showhidden = Mostra els servidors ocults server.shown = Mostra server.hidden = Amaga diff --git a/core/assets/bundles/bundle_cs.properties b/core/assets/bundles/bundle_cs.properties index 0303e15270..e763a26d48 100644 --- a/core/assets/bundles/bundle_cs.properties +++ b/core/assets/bundles/bundle_cs.properties @@ -281,6 +281,7 @@ servers.remote = Vzdálené servery servers.global = Komunitní servery servers.disclaimer = Komunitní servery [accent]nejsou[] vlastněny ani kontrolovány vývojářem této hry.\n\nServery mohou obsahovat obsah vytvořený uživateli, který může na některé uživatele působit nepatřičně či nevhodně. +servers.connect.confirm = Join the following server?\n\n[accent]{0}[]\n\nOnly connect to servers you trust! servers.showhidden = Zobraz skryté servery server.shown = Zobrazené server.hidden = Skryté diff --git a/core/assets/bundles/bundle_da.properties b/core/assets/bundles/bundle_da.properties index c5febaa466..edbebcab15 100644 --- a/core/assets/bundles/bundle_da.properties +++ b/core/assets/bundles/bundle_da.properties @@ -281,6 +281,7 @@ servers.remote = Afsides Servere servers.global = Globale Servere servers.disclaimer = Community servers are [accent]not[] owned or controlled by the developer.\n\nServers may contain user-generated content that is not appropriate for all ages. +servers.connect.confirm = Join the following server?\n\n[accent]{0}[]\n\nOnly connect to servers you trust! servers.showhidden = Show Hidden Servers server.shown = Shown server.hidden = Hidden diff --git a/core/assets/bundles/bundle_de.properties b/core/assets/bundles/bundle_de.properties index 6ad1fae4ee..e0b0c68c46 100644 --- a/core/assets/bundles/bundle_de.properties +++ b/core/assets/bundles/bundle_de.properties @@ -281,6 +281,7 @@ servers.remote = Andere Server servers.global = Community-Server servers.disclaimer = Community-Server werden vom Entwickler [accent]nicht[] geprüft.\nSie können Inhalte, die nicht für jedes Alter geeignet sind, enthalten. +servers.connect.confirm = Join the following server?\n\n[accent]{0}[]\n\nOnly connect to servers you trust! servers.showhidden = Versteckte Server anzeigen server.shown = Angezeigt server.hidden = Versteckt diff --git a/core/assets/bundles/bundle_es.properties b/core/assets/bundles/bundle_es.properties index fc0ab22138..1b5e49fc43 100644 --- a/core/assets/bundles/bundle_es.properties +++ b/core/assets/bundles/bundle_es.properties @@ -281,6 +281,7 @@ servers.remote = Servidores remotos servers.global = Servidores de la comunidad servers.disclaimer = Los servidores de la comunidad [accent]no[] son propiedad del desarrollador, ni administrados por el mismo.\n\nLos servidores podrían tener contenido generado por los usuarios no apropiado para todas las edades. +servers.connect.confirm = Join the following server?\n\n[accent]{0}[]\n\nOnly connect to servers you trust! servers.showhidden = Mostrar servidores ocultos server.shown = Visibles server.hidden = Ocultos diff --git a/core/assets/bundles/bundle_et.properties b/core/assets/bundles/bundle_et.properties index 4f739cc385..b6bbd51cef 100644 --- a/core/assets/bundles/bundle_et.properties +++ b/core/assets/bundles/bundle_et.properties @@ -281,6 +281,7 @@ servers.remote = Remote Servers servers.global = Community Servers servers.disclaimer = Community servers are [accent]not[] owned or controlled by the developer.\n\nServers may contain user-generated content that is not appropriate for all ages. +servers.connect.confirm = Join the following server?\n\n[accent]{0}[]\n\nOnly connect to servers you trust! servers.showhidden = Show Hidden Servers server.shown = Shown server.hidden = Hidden diff --git a/core/assets/bundles/bundle_eu.properties b/core/assets/bundles/bundle_eu.properties index 8f96f8b18c..34ab9b2cdb 100644 --- a/core/assets/bundles/bundle_eu.properties +++ b/core/assets/bundles/bundle_eu.properties @@ -281,6 +281,7 @@ servers.remote = Urruneko zerbitzariak servers.global = Komunitatearen zerbitzariak servers.disclaimer = Komunitatearen zerbitzariak [accent]ez[] ditu garatzaileak kontrolatzen.\n\nZerbitzari hauek erabiltzaileek sortutako edukia izan dezakete, eta ez du zertan adin guztientzat egokia izan behar. +servers.connect.confirm = Join the following server?\n\n[accent]{0}[]\n\nOnly connect to servers you trust! servers.showhidden = Erakutsi ezkutatutako zerbitzariak server.shown = Erakutsita server.hidden = Ezkutatuta diff --git a/core/assets/bundles/bundle_fi.properties b/core/assets/bundles/bundle_fi.properties index 765c5feade..68826b6e8a 100644 --- a/core/assets/bundles/bundle_fi.properties +++ b/core/assets/bundles/bundle_fi.properties @@ -281,6 +281,7 @@ servers.remote = Etäpalvelimet servers.global = Yhteisön palvelimet servers.disclaimer = Yhteisön palvelimet [accent]eivät ole[] kehittäjän omistuksessa tai hallinnassa.\n\nPalvelimet voivat sisältää käyttäjien luomaa sisältöä, joka ei sovellu kaikille ikäluokille. +servers.connect.confirm = Join the following server?\n\n[accent]{0}[]\n\nOnly connect to servers you trust! servers.showhidden = Näytä piilotetut palvelimet server.shown = Näytetty server.hidden = Piilotettu diff --git a/core/assets/bundles/bundle_fil.properties b/core/assets/bundles/bundle_fil.properties index d549f0d3e4..48b08a688a 100644 --- a/core/assets/bundles/bundle_fil.properties +++ b/core/assets/bundles/bundle_fil.properties @@ -281,6 +281,7 @@ servers.remote = Remote Servers servers.global = Server ng Komunidad servers.disclaimer = Ang mga server ng komunidad ay [accent]hindi pagmamay-ari o kinokontrol[] ng developer.\n\nAng mga Server ay may merong content na user-generated hindi bagay sa lahat ng taon. +servers.connect.confirm = Join the following server?\n\n[accent]{0}[]\n\nOnly connect to servers you trust! servers.showhidden = Ipakita ang mga tinagong server server.shown = Ipinapakita server.hidden = Tinatago diff --git a/core/assets/bundles/bundle_fr.properties b/core/assets/bundles/bundle_fr.properties index ce548d6b85..500bbd23bc 100644 --- a/core/assets/bundles/bundle_fr.properties +++ b/core/assets/bundles/bundle_fr.properties @@ -281,6 +281,7 @@ servers.remote = Serveurs distants servers.global = Serveurs communautaires servers.disclaimer = Les serveurs communautaires ne sont [accent]pas[] gérés, ni contrôlés par le développeur.\n\nCes serveurs peuvent contenir du contenu qui ne convient pas à tous les âges. +servers.connect.confirm = Join the following server?\n\n[accent]{0}[]\n\nOnly connect to servers you trust! servers.showhidden = Montrer les serveurs cachés server.shown = Visible server.hidden = Caché diff --git a/core/assets/bundles/bundle_hu.properties b/core/assets/bundles/bundle_hu.properties index 869ee6ecf6..d9eaf9807f 100644 --- a/core/assets/bundles/bundle_hu.properties +++ b/core/assets/bundles/bundle_hu.properties @@ -281,6 +281,7 @@ servers.remote = Távoli kiszolgálók servers.global = Közösségi kiszolgálók servers.disclaimer = A közösségi kiszolgálókat [accent]nem[] a fejlesztő birtokolja és ellenőrzi.\n\nA kiszolgálók tartalmazhatnak olyan felhasználók által létrehozott tartalmat, amely nem minden korosztály számára megfelelő. +servers.connect.confirm = Join the following server?\n\n[accent]{0}[]\n\nOnly connect to servers you trust! servers.showhidden = Rejtett kiszolgálók megjelenítése server.shown = Látható server.hidden = Rejtett diff --git a/core/assets/bundles/bundle_id_ID.properties b/core/assets/bundles/bundle_id_ID.properties index eea401e01b..008fcc8f48 100644 --- a/core/assets/bundles/bundle_id_ID.properties +++ b/core/assets/bundles/bundle_id_ID.properties @@ -281,6 +281,7 @@ servers.remote = Server Jarak Jauh servers.global = Server Komunitas servers.disclaimer = Server komunitas [accent]tidak[] dimiliki atau diatur oleh pengembang.\n\nServer dapat berisi konten buatan pemain lain yang mungkin tidak sesuai untuk semua umur. +servers.connect.confirm = Join the following server?\n\n[accent]{0}[]\n\nOnly connect to servers you trust! servers.showhidden = Tampilkan Server Tersembunyi server.shown = Ditampilkan server.hidden = Disembunyikan diff --git a/core/assets/bundles/bundle_it.properties b/core/assets/bundles/bundle_it.properties index f90fafd59a..06715e0808 100644 --- a/core/assets/bundles/bundle_it.properties +++ b/core/assets/bundles/bundle_it.properties @@ -281,6 +281,7 @@ servers.remote = Server Remoti servers.global = Server Community servers.disclaimer = I server della Community [accent]non[] appartengono o sono controllati dallo sviluppatore.\n\nI servers potrebbero contenere del contenuto generato dall'utente che non è appropriato per tutte le età. +servers.connect.confirm = Join the following server?\n\n[accent]{0}[]\n\nOnly connect to servers you trust! servers.showhidden = Mostra Server Nascosti server.shown = Visibile server.hidden = Nascosto diff --git a/core/assets/bundles/bundle_ja.properties b/core/assets/bundles/bundle_ja.properties index 4ee43c05e7..3bfec1c64d 100644 --- a/core/assets/bundles/bundle_ja.properties +++ b/core/assets/bundles/bundle_ja.properties @@ -281,6 +281,7 @@ servers.remote = リモートサーバー servers.global = コミュニティサーバー servers.disclaimer = コミュニティサーバーは、[accent]開発者が所有、管理していません。[] \n\nサーバーには全ての年齢層に適さないコンテンツが存在する可能性があります。 +servers.connect.confirm = Join the following server?\n\n[accent]{0}[]\n\nOnly connect to servers you trust! servers.showhidden = 非表示のサーバーを表示する server.shown = 表示 server.hidden = 非表示 diff --git a/core/assets/bundles/bundle_ko.properties b/core/assets/bundles/bundle_ko.properties index ff03d1a031..0f4997a725 100644 --- a/core/assets/bundles/bundle_ko.properties +++ b/core/assets/bundles/bundle_ko.properties @@ -281,6 +281,7 @@ servers.remote = 원격 서버 servers.global = 커뮤니티 서버 servers.disclaimer = 커뮤니티 서버는 개발자가 소유하거나 제어하지 [accent]않습니다[].\n\n일부 서버는 전연령대에 적합하지 않은 사용자 지정 콘텐츠를 보유할 수도 있습니다. +servers.connect.confirm = Join the following server?\n\n[accent]{0}[]\n\nOnly connect to servers you trust! servers.showhidden = 숨겨진 서버 보이기/숨기기 server.shown = 서버 숨기기 server.hidden = 서버 보이기 diff --git a/core/assets/bundles/bundle_lt.properties b/core/assets/bundles/bundle_lt.properties index 8625caec0b..8a28f93e3e 100644 --- a/core/assets/bundles/bundle_lt.properties +++ b/core/assets/bundles/bundle_lt.properties @@ -281,6 +281,7 @@ servers.remote = Nuotoliniai Serveriai servers.global = Globalūs Serveriai servers.disclaimer = Community servers are [accent]not[] owned or controlled by the developer.\n\nServers may contain user-generated content that is not appropriate for all ages. +servers.connect.confirm = Join the following server?\n\n[accent]{0}[]\n\nOnly connect to servers you trust! servers.showhidden = Rodyti paslėtus serverius server.shown = Rodoma server.hidden = Paslėpta diff --git a/core/assets/bundles/bundle_nl.properties b/core/assets/bundles/bundle_nl.properties index 60b81dcab8..d6590dd694 100644 --- a/core/assets/bundles/bundle_nl.properties +++ b/core/assets/bundles/bundle_nl.properties @@ -281,6 +281,7 @@ servers.remote = Externe servers servers.global = Community Servers servers.disclaimer = Community servers zijn [accent]niet[] in bezit of worden controlleerd door de ontwikkelaar.\n\nServers kunnen door gebruikers gegenereerde inhoud bevatten die niet geschikt is voor alle leeftijden. +servers.connect.confirm = Join the following server?\n\n[accent]{0}[]\n\nOnly connect to servers you trust! servers.showhidden = Toon Verborgen Servers server.shown = Weergegeven server.hidden = Verborgen diff --git a/core/assets/bundles/bundle_nl_BE.properties b/core/assets/bundles/bundle_nl_BE.properties index 05915519f7..d3c9a48db7 100644 --- a/core/assets/bundles/bundle_nl_BE.properties +++ b/core/assets/bundles/bundle_nl_BE.properties @@ -281,6 +281,7 @@ servers.remote = Remote Servers servers.global = Community Servers servers.disclaimer = Community servers are [accent]not[] owned or controlled by the developer.\n\nServers may contain user-generated content that is not appropriate for all ages. +servers.connect.confirm = Join the following server?\n\n[accent]{0}[]\n\nOnly connect to servers you trust! servers.showhidden = Show Hidden Servers server.shown = Shown server.hidden = Hidden diff --git a/core/assets/bundles/bundle_pl.properties b/core/assets/bundles/bundle_pl.properties index a1fcdf47db..eac7689a74 100644 --- a/core/assets/bundles/bundle_pl.properties +++ b/core/assets/bundles/bundle_pl.properties @@ -281,6 +281,7 @@ servers.remote = Serwery Zdalne servers.global = Serwery Publiczne servers.disclaimer = Serwery społeczności [accent]nie są[] w posiadaniu ani nie moderuje nimi twórca gry.\n\nSerwery mogą posiadać zawartość stworzoną przez graczy, która może być nieodpowiednia dla wszystkich grup wiekowych. +servers.connect.confirm = Join the following server?\n\n[accent]{0}[]\n\nOnly connect to servers you trust! servers.showhidden = Pokaż Ukryte Serwery server.shown = Pokazane server.hidden = Ukryte diff --git a/core/assets/bundles/bundle_pt_BR.properties b/core/assets/bundles/bundle_pt_BR.properties index a86c47e5f7..27e2330869 100644 --- a/core/assets/bundles/bundle_pt_BR.properties +++ b/core/assets/bundles/bundle_pt_BR.properties @@ -281,6 +281,7 @@ servers.remote = Servidores Remotos servers.global = Servidores da Comunidade servers.disclaimer = Servidores da comunidade [accent]não[] controlados pelo desenvolvedor.\n\nOs servidores podem conter conteúdo não apropriado para todas as idades. +servers.connect.confirm = Join the following server?\n\n[accent]{0}[]\n\nOnly connect to servers you trust! servers.showhidden = Mostrar servidores ocultos server.shown = Mostrar server.hidden = Ocultar diff --git a/core/assets/bundles/bundle_pt_PT.properties b/core/assets/bundles/bundle_pt_PT.properties index ad9240e6c7..7e810b1dfd 100644 --- a/core/assets/bundles/bundle_pt_PT.properties +++ b/core/assets/bundles/bundle_pt_PT.properties @@ -281,6 +281,7 @@ servers.remote = Servidores Remotos servers.global = Servidores da Comunidade servers.disclaimer = Servidores da comunidade [accent]não[] são controlados pelo desenvolvedor.\n\nOs servidores podem conter conteúdo não apropriado para todas as idades. +servers.connect.confirm = Join the following server?\n\n[accent]{0}[]\n\nOnly connect to servers you trust! servers.showhidden = Mostrar servidores escondidos server.shown = Mostrar server.hidden = Esconder diff --git a/core/assets/bundles/bundle_ro.properties b/core/assets/bundles/bundle_ro.properties index f2f9b07f27..5676ddfeb2 100644 --- a/core/assets/bundles/bundle_ro.properties +++ b/core/assets/bundles/bundle_ro.properties @@ -281,6 +281,7 @@ servers.remote = Servere de la Distanță servers.global = Servere ale Comunității servers.disclaimer = Serverele comunității [accent]nu[] sunt deținute sau controlate de către dezvoltator.\n\nServerele pot prezenta conținut generat de utilizatori care nu este potrivit tuturor vârstelor. +servers.connect.confirm = Join the following server?\n\n[accent]{0}[]\n\nOnly connect to servers you trust! servers.showhidden = Vezi Serverele Ascunse server.shown = Afișate server.hidden = Ascunse diff --git a/core/assets/bundles/bundle_ru.properties b/core/assets/bundles/bundle_ru.properties index c9b56650ca..ee8aa8efea 100644 --- a/core/assets/bundles/bundle_ru.properties +++ b/core/assets/bundles/bundle_ru.properties @@ -281,6 +281,7 @@ servers.remote = Удалённые серверы servers.global = Серверы сообщества servers.disclaimer = Серверы сообщества [accent]не[] принадлежат разработчику и [accent]не[] контролируются им.\n\nСерверы могут содержать пользовательский контент, который не подходит для всех возрастов. +servers.connect.confirm = Join the following server?\n\n[accent]{0}[]\n\nOnly connect to servers you trust! servers.showhidden = Отображать скрытые серверы server.shown = Отображается server.hidden = Скрыт diff --git a/core/assets/bundles/bundle_sr.properties b/core/assets/bundles/bundle_sr.properties index 6de8ecbc1c..381b516871 100644 --- a/core/assets/bundles/bundle_sr.properties +++ b/core/assets/bundles/bundle_sr.properties @@ -281,6 +281,7 @@ servers.remote = Dalji Serveri servers.global = Zadružni Serveri servers.disclaimer = Zadružni serveri [accent]nisu[] pod vlasništvom ili upravljani od strane tvorca igre.\n\nServeri mogu da sadrže sadržaj napravljen od strane korisnika koji nisu prikladni za svakog. +servers.connect.confirm = Join the following server?\n\n[accent]{0}[]\n\nOnly connect to servers you trust! servers.showhidden = Prikaži Skrivene Servere server.shown = Prikazano server.hidden = Skriveno diff --git a/core/assets/bundles/bundle_sv.properties b/core/assets/bundles/bundle_sv.properties index 6b3d8c22d9..7094825a36 100644 --- a/core/assets/bundles/bundle_sv.properties +++ b/core/assets/bundles/bundle_sv.properties @@ -281,6 +281,7 @@ servers.remote = Fjärr Servrar servers.global = Gemenskaps Servrar servers.disclaimer = Gemenskaps servrar är [accent]inte[] ägda eller kontrollerade av utvecklaren.\n\nServrar kan innehålla användargenererat innehåll som inte är lämpligt för alla åldrar. +servers.connect.confirm = Join the following server?\n\n[accent]{0}[]\n\nOnly connect to servers you trust! servers.showhidden = Visa Dolda Servrar server.shown = Visade server.hidden = Dolda diff --git a/core/assets/bundles/bundle_th.properties b/core/assets/bundles/bundle_th.properties index 1e4d08eea1..5fc71a1e51 100644 --- a/core/assets/bundles/bundle_th.properties +++ b/core/assets/bundles/bundle_th.properties @@ -281,6 +281,7 @@ servers.remote = เซิร์ฟเวอร์ทางไกล servers.global = เซิร์ฟเวอร์ของชุมชน servers.disclaimer = ผู้พัฒนา[accent]ไม่ได้[]เป็นเจ้าของหรือควบคุมเซิร์ฟเวอร์ของชุมชน\n\nในเซิร์ฟเวอร์อาจมีเนื้อหาของผู้เล่นที่ไม่เหมาะกับทุกเพศทุกวัย +servers.connect.confirm = Join the following server?\n\n[accent]{0}[]\n\nOnly connect to servers you trust! servers.showhidden = แสดงเซิร์ฟเวอร์ที่ซ่อนไว้ server.shown = แสดง server.hidden = ซ่อน diff --git a/core/assets/bundles/bundle_tk.properties b/core/assets/bundles/bundle_tk.properties index eeb9860837..6158adcbca 100644 --- a/core/assets/bundles/bundle_tk.properties +++ b/core/assets/bundles/bundle_tk.properties @@ -281,6 +281,7 @@ servers.remote = Remote Servers servers.global = Community Servers servers.disclaimer = Community servers are [accent]not[] owned or controlled by the developer.\n\nServers may contain user-generated content that is not appropriate for all ages. +servers.connect.confirm = Join the following server?\n\n[accent]{0}[]\n\nOnly connect to servers you trust! servers.showhidden = Show Hidden Servers server.shown = Shown server.hidden = Hidden diff --git a/core/assets/bundles/bundle_tr.properties b/core/assets/bundles/bundle_tr.properties index 1a8fdf4a84..d49c8fc947 100644 --- a/core/assets/bundles/bundle_tr.properties +++ b/core/assets/bundles/bundle_tr.properties @@ -281,6 +281,7 @@ servers.remote = Uzak Sunucular servers.global = Topluluk Sunucuları servers.disclaimer = Topluluk Sunucuları, [accent]Yapımcı tarafından yönetilmiyor!\n\nSunucularda, her yaşa uygun olmayan yapı ve içerikler içerebilir! +servers.connect.confirm = Join the following server?\n\n[accent]{0}[]\n\nOnly connect to servers you trust! servers.showhidden = Gizli Sunucuları Göster server.shown = Görünür server.hidden = Gizli diff --git a/core/assets/bundles/bundle_uk_UA.properties b/core/assets/bundles/bundle_uk_UA.properties index a2216f21dd..c0abf60f3d 100644 --- a/core/assets/bundles/bundle_uk_UA.properties +++ b/core/assets/bundles/bundle_uk_UA.properties @@ -281,6 +281,7 @@ servers.remote = Віддалені сервери servers.global = Глобальні сервери servers.disclaimer = Сервери спільноти [accent]не[] належать чи контролюються власником.\n\nСервери можуть містити користувацький вміст, що не підходить для якогось віку. +servers.connect.confirm = Join the following server?\n\n[accent]{0}[]\n\nOnly connect to servers you trust! servers.showhidden = Показати приховані сервери server.shown = Показано server.hidden = Приховано diff --git a/core/assets/bundles/bundle_vi.properties b/core/assets/bundles/bundle_vi.properties index 604cac1902..b89d541a76 100644 --- a/core/assets/bundles/bundle_vi.properties +++ b/core/assets/bundles/bundle_vi.properties @@ -281,6 +281,7 @@ servers.remote = Máy chủ từ xa servers.global = Máy chủ cộng đồng servers.disclaimer = Các máy chủ cộng đồng [accent]không[] được sở hữu và kiểm soát bởi nhà phát triển.\n\nMáy chủ có thể chứa nội dung do người dùng tạo và không phù hợp với mọi lứa tuổi. +servers.connect.confirm = Join the following server?\n\n[accent]{0}[]\n\nOnly connect to servers you trust! servers.showhidden = Hiện máy chủ ẩn server.shown = Đã hiện server.hidden = Đã ẩn diff --git a/core/assets/bundles/bundle_zh_CN.properties b/core/assets/bundles/bundle_zh_CN.properties index c1f271721b..9f702ef122 100644 --- a/core/assets/bundles/bundle_zh_CN.properties +++ b/core/assets/bundles/bundle_zh_CN.properties @@ -281,6 +281,7 @@ servers.remote = 远程服务器 servers.global = 社区服务器 servers.disclaimer = 社区服务器[accent]不由开发者拥有或管理[]。\n\n这些服务器可能包含并不适合所有年龄段的玩家生成内容。 +servers.connect.confirm = Join the following server?\n\n[accent]{0}[]\n\nOnly connect to servers you trust! servers.showhidden = 显示隐藏服务器 server.shown = 已显示 server.hidden = 已隐藏 diff --git a/core/assets/bundles/bundle_zh_TW.properties b/core/assets/bundles/bundle_zh_TW.properties index 8440728d53..6806733c46 100644 --- a/core/assets/bundles/bundle_zh_TW.properties +++ b/core/assets/bundles/bundle_zh_TW.properties @@ -281,6 +281,7 @@ servers.remote = 遠端伺服器 servers.global = 社群伺服器 servers.disclaimer = 社群伺服器[accent]不是[]由開發者擁有或管理。\n\n伺服器可能會出現由其他玩家製作的不適當內容。 +servers.connect.confirm = Join the following server?\n\n[accent]{0}[]\n\nOnly connect to servers you trust! servers.showhidden = 顯示被隱藏的伺服器 server.shown = 已顯示 server.hidden = 已隱藏 From 786194b0b95071a379f118f6d7424891835ab7b1 Mon Sep 17 00:00:00 2001 From: Anuken Date: Wed, 15 Jul 2026 15:29:57 -0400 Subject: [PATCH 6/9] Fixed #12370 --- core/src/mindustry/logic/LCanvas.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/mindustry/logic/LCanvas.java b/core/src/mindustry/logic/LCanvas.java index 56f52b1bb9..320b8e59ca 100644 --- a/core/src/mindustry/logic/LCanvas.java +++ b/core/src/mindustry/logic/LCanvas.java @@ -212,7 +212,7 @@ public class LCanvas extends Table{ seq.clear(); float totalHeight = getChildren().sumf(e -> e.getPrefHeight() + space); - if(height != totalHeight || width != Scl.scl(targetWidth)){ + if(!Mathf.equal(height, totalHeight, 1f) || !Mathf.equal(width, Scl.scl(targetWidth), 1f)){ height = prefHeight = totalHeight; width = prefWidth = Scl.scl(targetWidth); invalidateHierarchy(); From 09a45ee2fb4f4babdc6ec4a1c875af891b4897a0 Mon Sep 17 00:00:00 2001 From: Anuken Date: Wed, 15 Jul 2026 15:44:37 -0400 Subject: [PATCH 7/9] Fixed mysterious missing conveyors in schematics / Better schematics import handling --- .../mindustry/android/AndroidLauncher.java | 32 ++------- core/src/mindustry/ClientLauncher.java | 67 ++++++++++++------- core/src/mindustry/game/Schematics.java | 29 +++++++- .../ui/dialogs/SchematicsDialog.java | 16 ++++- ios/src/mindustry/ios/IOSLauncher.java | 41 +++--------- 5 files changed, 98 insertions(+), 87 deletions(-) diff --git a/android/src/mindustry/android/AndroidLauncher.java b/android/src/mindustry/android/AndroidLauncher.java index 74c9df8ae3..cceb0e9148 100644 --- a/android/src/mindustry/android/AndroidLauncher.java +++ b/android/src/mindustry/android/AndroidLauncher.java @@ -17,8 +17,6 @@ import arc.util.*; import dalvik.system.*; import mindustry.*; import mindustry.game.EventType.*; -import mindustry.game.Saves.*; -import mindustry.io.*; import mindustry.net.*; import mindustry.ui.*; import mindustry.ui.FileChooser.*; @@ -298,6 +296,11 @@ public class AndroidLauncher extends AndroidApplication{ if(uri != null){ String scheme = uri.getScheme(); + //clear data (not sure if necessary?) + intent.setAction(Intent.ACTION_MAIN); + intent.setData(null); + setIntent(intent); + if("mindustry".equalsIgnoreCase(scheme)){ //open a server URL String host = uri.getHost(); @@ -309,32 +312,11 @@ public class AndroidLauncher extends AndroidApplication{ }); } }else{ //open a save file - Fi file = Core.files.cache("temp-save." + saveExtension); + Fi file = Core.files.cache("imported"); file.write(getContentResolver().openInputStream(uri), false); - //may run on a different thread - Core.app.post(() -> { - try{ - SaveMeta meta = SaveIO.getMeta(file); - if(!meta.isMap()){ //open save - SaveSlot slot = control.saves.importSave(file); - ui.load.runLoadSave(slot); - }else{ //open map - if(!ui.maps.isShown()){ - ui.maps.show(); - } - ui.maps.tryImportMap(file, result -> ui.maps.showMap(result)); - } - }catch(Throwable e){ - Log.err("Failed to load save", e); - ui.showException("@save.import.invalid", e); - } - }); + ClientLauncher.handleFileImport(file); } - - //clear data (not sure if necessary?) - intent.setAction(Intent.ACTION_MAIN); - intent.setData(null); } }catch(Throwable e){ Log.err(e); diff --git a/core/src/mindustry/ClientLauncher.java b/core/src/mindustry/ClientLauncher.java index 6ae3090410..6f0a8ea55f 100644 --- a/core/src/mindustry/ClientLauncher.java +++ b/core/src/mindustry/ClientLauncher.java @@ -6,17 +6,17 @@ import arc.assets.loaders.*; import arc.audio.*; import arc.files.*; import arc.graphics.*; +import arc.graphics.Texture.*; import arc.graphics.g2d.*; import arc.math.*; import arc.util.*; -import arc.util.io.*; import mindustry.ai.*; import mindustry.audio.*; import mindustry.core.*; import mindustry.ctype.*; import mindustry.game.EventType.*; -import mindustry.game.*; import mindustry.game.Saves.*; +import mindustry.game.*; import mindustry.gen.*; import mindustry.graphics.*; import mindustry.io.*; @@ -25,9 +25,6 @@ import mindustry.mod.*; import mindustry.net.*; import mindustry.ui.*; -import java.io.*; -import java.util.zip.*; - import static arc.Core.*; import static mindustry.Vars.*; @@ -189,6 +186,8 @@ public abstract class ClientLauncher extends ApplicationCore implements Platform assets.loadRun("contentinit", ContentLoader.class, () -> content.init(), () -> content.load()); assets.loadRun("baseparts", BaseRegistry.class, () -> {}, () -> bases.load()); + + Core.assets.load("sprites/schematic-background.png", Texture.class).loaded = t -> t.setWrap(TextureWrap.repeat); } @Override @@ -314,32 +313,48 @@ public abstract class ClientLauncher extends ApplicationCore implements Platform @Override public void fileDropped(Fi file){ - if(OS.isIos) return; + if(OS.isIos || OS.isAndroid) return; - if(file.extension().equalsIgnoreCase(saveExtension)){ //open save + if(file.extension().equalsIgnoreCase(saveExtension) || file.extension().equalsIgnoreCase(schematicExtension)){ + handleFileImport(file); + } + } + + public static void runOnClientLoad(Runnable run){ + if(clientLoaded){ + run.run(); + }else{ + Events.on(ClientLoadEvent.class, e -> run.run()); + } + } + + /** Can be called from any thread. The file must exist and not have any permission nonsense guarding it. */ + public static void handleFileImport(Fi file){ + Core.app.post(() -> { try{ - if(SaveIO.isSaveValid(file)){ - SaveMeta meta = SaveIO.getMeta(new DataInputStream(new InflaterInputStream(file.read(Streams.defaultBufferSize)))); - if(meta.tags.containsKey("name")){ - //is map - if(!ui.editor.isShown()){ - ui.editor.show(); - } - - ui.editor.beginEditMap(file); - }else if(meta.rules.sector == null){ //don't allow importing campaign saves, they are broken - SaveSlot slot = control.saves.importSave(file); - ui.load.runLoadSave(slot); - }else{ - ui.showErrorMessage("@save.nocampaign"); - } + if(Schematics.isSchematic(file)){ + ui.schematics.show(); + ui.schematics.importAndShow(file); }else{ - ui.showErrorMessage("@save.import.invalid"); + SaveMeta meta = SaveIO.getMeta(file); + if(!meta.isMap()){ //open save + if(meta.rules.sector == null){ + SaveSlot slot = control.saves.importSave(file); + ui.load.runLoadSave(slot); + }else{ + ui.showErrorMessage("@save.nocampaign"); + } + }else{ //open map + if(!ui.maps.isShown()){ + ui.maps.show(); + } + ui.maps.tryImportMap(file, result -> ui.maps.showMap(result)); + } } }catch(Throwable e){ - ui.showException("@save.import.fail", e); + Log.err("Failed to import file", e); + ui.showException("@save.import.invalid", e); } - } - + }); } } diff --git a/core/src/mindustry/game/Schematics.java b/core/src/mindustry/game/Schematics.java index f7e2193588..b5ddcf8b3e 100644 --- a/core/src/mindustry/game/Schematics.java +++ b/core/src/mindustry/game/Schematics.java @@ -247,7 +247,15 @@ public class Schematics implements Loadable{ Draw.rect(Tmp.tr1, buffer.getWidth()/2f, buffer.getHeight()/2f, buffer.getWidth(), -buffer.getHeight()); Draw.color(); - Seq plans = schematic.tiles.map(t -> new BuildPlan(t.x, t.y, t.rotation, t.block, t.config)); + Seq plans = schematic.tiles.map(t -> new BuildPlan(t.x, t.y, t.rotation, t.block, t.config){ + @Override + public Tile tile(){ + //fake tile to return for previews to work properly + emptyTile.x = (short)x; + emptyTile.y = (short)y; + return emptyTile; + } + }); Draw.flush(); //scale each plan to fit schematic @@ -264,6 +272,10 @@ public class Schematics implements Loadable{ plans.each(req -> req.block.drawPlanConfigTop(req, eachPlans)); + //reset state + emptyTile.x = 0; + emptyTile.y = 0; + Draw.flush(); Draw.trans().idt(); @@ -522,6 +534,21 @@ public class Schematics implements Loadable{ //region IO methods + public static boolean isSchematic(Fi file){ + try{ + try(InputStream input = file.read()){ + for(byte b : header){ + if(input.read() != b){ + return false; + } + } + } + return true; + }catch(Throwable t){ + return false; + } + } + /** Loads a schematic from base64. May throw an exception. */ public static Schematic readBase64(String schematic){ try{ diff --git a/core/src/mindustry/ui/dialogs/SchematicsDialog.java b/core/src/mindustry/ui/dialogs/SchematicsDialog.java index 6e0fe6a1b9..657d385e1f 100644 --- a/core/src/mindustry/ui/dialogs/SchematicsDialog.java +++ b/core/src/mindustry/ui/dialogs/SchematicsDialog.java @@ -4,7 +4,6 @@ import arc.*; import arc.files.*; import arc.func.*; import arc.graphics.*; -import arc.graphics.Texture.*; import arc.graphics.g2d.*; import arc.input.*; import arc.math.*; @@ -41,7 +40,6 @@ public class SchematicsDialog extends BaseDialog{ public SchematicsDialog(){ super("@schematics"); - Core.assets.load("sprites/schematic-background.png", Texture.class).loaded = t -> t.setWrap(TextureWrap.repeat); tags = Core.settings.getJson("schematic-tags", Seq.class, String.class, Seq::new); @@ -284,6 +282,20 @@ public class SchematicsDialog extends BaseDialog{ dialog.show(); } + public void importAndShow(Fi file){ + try{ + Schematic s = Schematics.read(file); + s.removeSteamID(); + schematics.add(s); + checkTags(s); + + setup(); + showInfo(s); + }catch(Exception e){ + ui.showException(e); + } + } + public void showExport(Schematic s){ BaseDialog dialog = new BaseDialog("@editor.export"); dialog.cont.pane(p -> { diff --git a/ios/src/mindustry/ios/IOSLauncher.java b/ios/src/mindustry/ios/IOSLauncher.java index 6aa59234a4..10dbcb2bfb 100644 --- a/ios/src/mindustry/ios/IOSLauncher.java +++ b/ios/src/mindustry/ios/IOSLauncher.java @@ -7,11 +7,8 @@ import arc.files.*; import arc.scene.ui.layout.*; import arc.struct.*; import arc.util.*; -import arc.util.io.*; import mindustry.*; import mindustry.game.EventType.*; -import mindustry.game.Saves.*; -import mindustry.io.*; import mindustry.net.*; import mindustry.ui.FileChooser.*; import mindustry.ui.*; @@ -21,9 +18,7 @@ import org.robovm.apple.uikit.*; import org.robovm.objc.block.*; import rhino.*; -import java.io.*; import java.util.*; -import java.util.zip.*; import static mindustry.Vars.*; import static org.robovm.apple.foundation.NSPathUtilities.*; @@ -224,35 +219,15 @@ public class IOSLauncher extends IOSApplication.Delegate{ } void openURL(NSURL url){ + if(url == null) return; + try{ + Fi file = new Fi(getDocumentsDirectory()).child(url.getLastPathComponent()); + new Fi(url.getPath()).copyTo(file); - Core.app.post(() -> Core.app.post(() -> { - Fi file = Core.files.absolute(getDocumentsDirectory()).child(url.getLastPathComponent()); - Core.files.absolute(url.getPath()).copyTo(file); - - if(file.extension().equalsIgnoreCase(saveExtension)){ //open save - - try{ - if(SaveIO.isSaveValid(file)){ - SaveMeta meta = SaveIO.getMeta(new DataInputStream(new InflaterInputStream(file.read(Streams.defaultBufferSize)))); - if(meta.tags.containsKey("name")){ - //is map - if(!ui.editor.isShown()){ - ui.editor.show(); - } - - ui.editor.beginEditMap(file); - }else{ - SaveSlot slot = control.saves.importSave(file); - ui.load.runLoadSave(slot); - } - }else{ - ui.showErrorMessage("@save.import.invalid"); - } - }catch(Throwable e){ - ui.showException("@save.import.fail", e); - } - } - })); + ClientLauncher.runOnClientLoad(() -> ClientLauncher.handleFileImport(file)); + }catch(Exception e){ + Log.err(e); + } } public static void main(String[] argv){ From 2e742615667caf734562b97b31cb2838036a9044 Mon Sep 17 00:00:00 2001 From: Anuken Date: Wed, 15 Jul 2026 16:21:32 -0400 Subject: [PATCH 8/9] Removed redundant URL handling in iOS --- ios/src/mindustry/ios/IOSLauncher.java | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/ios/src/mindustry/ios/IOSLauncher.java b/ios/src/mindustry/ios/IOSLauncher.java index 10dbcb2bfb..e24cfbb93a 100644 --- a/ios/src/mindustry/ios/IOSLauncher.java +++ b/ios/src/mindustry/ios/IOSLauncher.java @@ -193,7 +193,7 @@ public class IOSLauncher extends IOSApplication.Delegate{ @Override public boolean openURL(UIApplication app, NSURL url, UIApplicationOpenURLOptions options){ - openURL(url); + handleAppURL(url); return false; } @@ -201,10 +201,6 @@ public class IOSLauncher extends IOSApplication.Delegate{ public boolean didFinishLaunching(UIApplication application, UIApplicationLaunchOptions options){ boolean b = super.didFinishLaunching(application, options); - if(options != null && options.has(UIApplicationLaunchOptions.Keys.URL())){ - openURL(((NSURL)options.get(UIApplicationLaunchOptions.Keys.URL()))); - } - Events.on(ClientLoadEvent.class, e -> Core.app.post(() -> Core.app.post(() -> Core.scene.table(Styles.black9, t -> { t.visible(() -> { if(!forced) return false; @@ -218,7 +214,7 @@ public class IOSLauncher extends IOSApplication.Delegate{ return b; } - void openURL(NSURL url){ + void handleAppURL(NSURL url){ if(url == null) return; try{ Fi file = new Fi(getDocumentsDirectory()).child(url.getLastPathComponent()); From fb34738d60fe61001a3a404b9b9fd58edd7a6d8c Mon Sep 17 00:00:00 2001 From: Anuken Date: Wed, 15 Jul 2026 16:37:35 -0400 Subject: [PATCH 9/9] Cleanup --- core/src/mindustry/ClientLauncher.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/core/src/mindustry/ClientLauncher.java b/core/src/mindustry/ClientLauncher.java index 6f0a8ea55f..a3c6fcca96 100644 --- a/core/src/mindustry/ClientLauncher.java +++ b/core/src/mindustry/ClientLauncher.java @@ -315,7 +315,7 @@ public abstract class ClientLauncher extends ApplicationCore implements Platform public void fileDropped(Fi file){ if(OS.isIos || OS.isAndroid) return; - if(file.extension().equalsIgnoreCase(saveExtension) || file.extension().equalsIgnoreCase(schematicExtension)){ + if(file.extEquals(saveExtension) || file.extEquals(schematicExtension)){ handleFileImport(file); } } @@ -338,6 +338,9 @@ public abstract class ClientLauncher extends ApplicationCore implements Platform }else{ SaveMeta meta = SaveIO.getMeta(file); if(!meta.isMap()){ //open save + //not sure if this is a great idea but leaving the editor open would lead to catastrophic bugs + if(ui.editor.isShown()) ui.editor.hide(); + if(meta.rules.sector == null){ SaveSlot slot = control.saves.importSave(file); ui.load.runLoadSave(slot); @@ -345,9 +348,7 @@ public abstract class ClientLauncher extends ApplicationCore implements Platform ui.showErrorMessage("@save.nocampaign"); } }else{ //open map - if(!ui.maps.isShown()){ - ui.maps.show(); - } + if(!ui.maps.isShown()) ui.maps.show(); ui.maps.tryImportMap(file, result -> ui.maps.showMap(result)); } }