Save file drop support for desktop

This commit is contained in:
Anuken
2026-02-04 12:36:40 -05:00
parent 5a9e8cbcac
commit 4497e34bbb
6 changed files with 73 additions and 8 deletions

View File

@@ -32,13 +32,6 @@
<category android:name="android.intent.category.LAUNCHER"/> <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter> </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:mimeType="application/octet-stream" />
<data android:scheme="file" android:host="*" android:pathPattern=".*\\.msav"/>
</intent-filter>
</activity> </activity>
</application> </application>

View File

@@ -9,19 +9,25 @@ import arc.graphics.*;
import arc.graphics.g2d.*; import arc.graphics.g2d.*;
import arc.math.*; import arc.math.*;
import arc.util.*; import arc.util.*;
import arc.util.io.*;
import mindustry.ai.*; import mindustry.ai.*;
import mindustry.audio.*; import mindustry.audio.*;
import mindustry.core.*; import mindustry.core.*;
import mindustry.ctype.*; import mindustry.ctype.*;
import mindustry.game.EventType.*; import mindustry.game.EventType.*;
import mindustry.game.*; import mindustry.game.*;
import mindustry.game.Saves.*;
import mindustry.gen.*; import mindustry.gen.*;
import mindustry.graphics.*; import mindustry.graphics.*;
import mindustry.io.*;
import mindustry.maps.*; import mindustry.maps.*;
import mindustry.mod.*; import mindustry.mod.*;
import mindustry.net.*; import mindustry.net.*;
import mindustry.ui.*; import mindustry.ui.*;
import java.io.*;
import java.util.zip.*;
import static arc.Core.*; import static arc.Core.*;
import static mindustry.Vars.*; import static mindustry.Vars.*;
@@ -303,4 +309,34 @@ public abstract class ClientLauncher extends ApplicationCore implements Platform
super.pause(); super.pause();
} }
} }
@Override
public void fileDropped(Fi file){
if(!OS.isIos){
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 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");
}
}else{
ui.showErrorMessage("@save.import.invalid");
}
}catch(Throwable e){
ui.showException("@save.import.fail", e);
}
}
}
}
} }

View File

@@ -43,6 +43,7 @@ import mindustry.type.*;
import mindustry.type.ammo.*; import mindustry.type.ammo.*;
import mindustry.type.weather.*; import mindustry.type.weather.*;
import mindustry.world.*; import mindustry.world.*;
import mindustry.world.blocks.*;
import mindustry.world.blocks.units.*; import mindustry.world.blocks.units.*;
import mindustry.world.blocks.units.UnitFactory.*; import mindustry.world.blocks.units.UnitFactory.*;
import mindustry.world.consumers.*; import mindustry.world.consumers.*;
@@ -89,6 +90,14 @@ public class ContentParser{
if(Attribute.exists(attr)) return Attribute.get(attr); if(Attribute.exists(attr)) return Attribute.get(attr);
return Attribute.add(attr); return Attribute.add(attr);
}); });
put(Attributes.class, (type, data) -> {
Attributes attr = new Attributes();
for(var child : data){
Attribute value = Attribute.exists(child.name) ? Attribute.get(child.name) : Attribute.add(child.name);
attr.set(value, child.asFloat());
}
return attr;
});
put(BuildVisibility.class, (type, data) -> field(BuildVisibility.class, data)); put(BuildVisibility.class, (type, data) -> field(BuildVisibility.class, data));
put(Schematic.class, (type, data) -> { put(Schematic.class, (type, data) -> {
Object result = fieldOpt(Loadouts.class, data); Object result = fieldOpt(Loadouts.class, data);

View File

@@ -77,6 +77,13 @@ public class DataPatcher{
contentLoader = Vars.content.copy(); contentLoader = Vars.content.copy();
patches.clear(); patches.clear();
Attribute[] oldAttributes = Attribute.all.clone();
var oldAttributeMap = Attribute.map.copy();
reset(() -> {
Attribute.all = oldAttributes;
Attribute.map = oldAttributeMap;
});
for(String patch : patchArray){ for(String patch : patchArray){
PatchSet set = new PatchSet(patch, new JsonValue("error")); PatchSet set = new PatchSet(patch, new JsonValue("error"));
patches.add(set); patches.add(set);

View File

@@ -26,4 +26,4 @@ org.gradle.caching=true
org.gradle.internal.http.socketTimeout=100000 org.gradle.internal.http.socketTimeout=100000
org.gradle.internal.http.connectionTimeout=100000 org.gradle.internal.http.connectionTimeout=100000
android.enableR8.fullMode=false android.enableR8.fullMode=false
archash=d670ef7b3d archash=3e5d2eb442

View File

@@ -524,6 +524,26 @@ public class PatcherTests{
assertEquals(oldDamage, UnitTypes.dagger.weapons.first().bullet.damage); assertEquals(oldDamage, UnitTypes.dagger.weapons.first().bullet.damage);
} }
@Test
void customAttribute() throws Exception{
int amount = Attribute.all.length;
Vars.state.patcher.apply(Seq.with("""
block.grass.attributes: {
frogs: 10
}
"""));
assertTrue(Attribute.exists("frogs"));
assertEquals(amount + 1, Attribute.all.length);
assertEquals(10f, Blocks.grass.asFloor().attributes.get(Attribute.get("frogs")), 0.0001f);
Vars.logic.reset();
assertFalse(Attribute.exists("frogs"));
assertEquals(amount, Attribute.all.length);
}
@Test @Test
void addWeapon() throws Exception{ void addWeapon() throws Exception{
int oldSize = UnitTypes.flare.weapons.size; int oldSize = UnitTypes.flare.weapons.size;