Merge branch 'master' into v9

# Conflicts:
#	gradle.properties
This commit is contained in:
Anuken
2026-07-15 16:38:10 -04:00
48 changed files with 257 additions and 248 deletions
+20
View File
@@ -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">
<intent-filter>
@@ -39,6 +40,25 @@
<data android:scheme="mindustry"/>
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="content" />
<data android:mimeType="application/octet-stream" />
<data android:mimeType="application/x-msav" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="file" />
<data android:host="*" />
<data android:mimeType="*/*" />
<data android:pathPattern=".*\\.msav" />
</intent-filter>
</activity>
</application>
@@ -16,8 +16,7 @@ import arc.struct.*;
import arc.util.*;
import dalvik.system.*;
import mindustry.*;
import mindustry.game.Saves.*;
import mindustry.io.*;
import mindustry.game.EventType.*;
import mindustry.net.*;
import mindustry.ui.*;
import mindustry.ui.FileChooser.*;
@@ -221,7 +220,9 @@ public class AndroidLauncher extends AndroidApplication{
useImmersiveMode = true;
hideStatusBar = true;
}});
checkFiles(getIntent());
var intent = getIntent();
Events.on(ClientLoadEvent.class, u -> handleIntent(intent));
try{
//new external folder
@@ -279,54 +280,45 @@ public class AndroidLauncher extends AndroidApplication{
}
}
private void checkFiles(Intent intent){
@Override
protected void onNewIntent(Intent intent){
super.onNewIntent(intent);
handleIntent(intent);
}
private void handleIntent(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);
}
}else{
ui.showErrorMessage("@save.import.invalid");
}
}else if(map){ //open map
Fi file = Core.files.local("temp-map." + mapExtension);
file.write(inStream, false);
//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();
int port = uri.getPort();
if(host != null && !host.isEmpty()){
Core.app.post(() -> {
System.out.println("Opening map.");
if(!ui.editor.isShown()){
ui.editor.show();
}
ui.editor.beginEditMap(file);
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("imported");
file.write(getContentResolver().openInputStream(uri), false);
ClientLauncher.handleFileImport(file);
}
}
}catch(IOException e){
e.printStackTrace();
}catch(Throwable e){
Log.err(e);
}
}
+1
View File
@@ -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
+1
View File
@@ -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 = Схаваныя
+1
View File
@@ -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 = Скрит
+1
View File
@@ -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
+1
View File
@@ -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é
+1
View File
@@ -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
+1
View File
@@ -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
+1
View File
@@ -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
+1
View File
@@ -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
+1
View File
@@ -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
+1
View File
@@ -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
@@ -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
+1
View File
@@ -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é
+1
View File
@@ -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
@@ -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
+1
View File
@@ -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
+1
View File
@@ -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 = 非表示
+1
View File
@@ -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 = 서버 보이기
+1
View File
@@ -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
+1
View File
@@ -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
@@ -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
+1
View File
@@ -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
@@ -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
@@ -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
+1
View File
@@ -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
+1
View File
@@ -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 = Скрыт
+1
View File
@@ -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
+1
View File
@@ -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
+1
View File
@@ -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 = ซ่อน
+1
View File
@@ -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
+1
View File
@@ -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
@@ -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 = Приховано
+1
View File
@@ -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
@@ -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 = 已隐藏
@@ -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 = 已隱藏
+41 -25
View File
@@ -6,11 +6,11 @@ import arc.assets.loaders.*;
import arc.audio.*;
import arc.files.*;
import arc.graphics.*;
import arc.graphics.Texture.*;
import arc.graphics.g2d.*;
import arc.graphics.gl.*;
import arc.math.*;
import arc.util.*;
import arc.util.io.*;
import mindustry.ai.*;
import mindustry.audio.*;
import mindustry.core.*;
@@ -26,9 +26,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.*;
@@ -182,6 +179,8 @@ public abstract class ClientLauncher extends ApplicationCore implements Platform
Fonts.loadModContentIcons();
});
assets.loadRun("baseparts", BaseRegistry.class, () -> {}, () -> bases.load());
Core.assets.load("sprites/schematic-background.png", Texture.class).loaded = t -> t.setWrap(TextureWrap.repeat);
}
@Override
@@ -307,32 +306,49 @@ 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.extEquals(saveExtension) || file.extEquals(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
//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);
}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);
}
}
});
}
}
+28 -1
View File
@@ -246,7 +246,15 @@ public class Schematics implements Loadable{
Draw.rect(Tmp.tr1, buffer.width /2f, buffer.height /2f, buffer.width, -buffer.height);
Draw.color();
Seq<BuildPlan> plans = schematic.tiles.map(t -> new BuildPlan(t.x, t.y, t.rotation, t.block, t.config));
Seq<BuildPlan> 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
@@ -263,6 +271,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();
@@ -521,6 +533,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{
+4
View File
@@ -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");
}
}
+1 -1
View File
@@ -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();
+4 -2
View File
@@ -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;
+1 -1
View File
@@ -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);
@@ -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<Map> 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();
@@ -40,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);
@@ -283,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 -> {
+1 -1
View File
@@ -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=7e89c6d449
archash=72c602f00c
+10 -39
View File
@@ -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.*;
@@ -196,7 +191,7 @@ public class IOSLauncher extends IOSApplication.Delegate{
@Override
public boolean openURL(UIApplication app, NSURL url, UIApplicationOpenURLOptions options){
openURL(url);
handleAppURL(url);
return false;
}
@@ -204,10 +199,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;
@@ -221,36 +212,16 @@ 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());
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){
+15 -94
View File
@@ -1,105 +1,26 @@
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.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 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 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 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'){