Support for jar mods on desktop
This commit is contained in:
@@ -1 +1 @@
|
|||||||
{fields:[{name:collided,type:arc.struct.IntSeq,size:-1},{name:damage,type:float,size:4},{name:data,type:java.lang.Object,size:-1},{name:lifetime,type:float,size:4},{name:owner,type:Entityc,size:-1},{name:team,type:mindustry.game.Team,size:-1},{name:time,type:float,size:4},{name:type,type:mindustry.entities.bullet.BulletType,size:-1},{name:x,type:float,size:4},{name:y,type:float,size:4}]}
|
{fields:[{name:collided,type:arc.struct.IntSeq,size:-1},{name:damage,type:float,size:4},{name:data,type:java.lang.Object,size:-1},{name:lifetime,type:float,size:4},{name:owner,type:mindustry.gen.Entityc,size:-1},{name:team,type:mindustry.game.Team,size:-1},{name:time,type:float,size:4},{name:type,type:mindustry.entities.bullet.BulletType,size:-1},{name:x,type:float,size:4},{name:y,type:float,size:4}]}
|
||||||
@@ -1 +0,0 @@
|
|||||||
{version:1,fields:[{name:collided,type:arc.struct.IntSeq,size:-1},{name:damage,type:float,size:4},{name:data,type:java.lang.Object,size:-1},{name:lifetime,type:float,size:4},{name:owner,type:mindustry.gen.Entityc,size:-1},{name:team,type:mindustry.game.Team,size:-1},{name:time,type:float,size:4},{name:type,type:mindustry.entities.bullet.BulletType,size:-1},{name:x,type:float,size:4},{name:y,type:float,size:4}]}
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
{version:2,fields:[{name:collided,type:arc.struct.IntSeq,size:-1},{name:damage,type:float,size:4},{name:data,type:java.lang.Object,size:-1},{name:lifetime,type:float,size:4},{name:owner,type:Entityc,size:-1},{name:team,type:mindustry.game.Team,size:-1},{name:time,type:float,size:4},{name:type,type:mindustry.entities.bullet.BulletType,size:-1},{name:x,type:float,size:4},{name:y,type:float,size:4}]}
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
{version:3,fields:[{name:collided,type:arc.struct.IntSeq,size:-1},{name:damage,type:float,size:4},{name:data,type:java.lang.Object,size:-1},{name:lifetime,type:float,size:4},{name:owner,type:mindustry.gen.Entityc,size:-1},{name:team,type:mindustry.game.Team,size:-1},{name:time,type:float,size:4},{name:type,type:mindustry.entities.bullet.BulletType,size:-1},{name:x,type:float,size:4},{name:y,type:float,size:4}]}
|
|
||||||
@@ -1 +1 @@
|
|||||||
{fields:[{name:color,type:arc.graphics.Color,size:-1},{name:data,type:java.lang.Object,size:-1},{name:effect,type:mindustry.entities.Effect,size:-1},{name:lifetime,type:float,size:4},{name:offsetX,type:float,size:4},{name:offsetY,type:float,size:4},{name:parent,type:Posc,size:-1},{name:rotation,type:float,size:4},{name:time,type:float,size:4},{name:x,type:float,size:4},{name:y,type:float,size:4}]}
|
{fields:[{name:color,type:arc.graphics.Color,size:-1},{name:data,type:java.lang.Object,size:-1},{name:effect,type:mindustry.entities.Effect,size:-1},{name:lifetime,type:float,size:4},{name:offsetX,type:float,size:4},{name:offsetY,type:float,size:4},{name:parent,type:mindustry.gen.Posc,size:-1},{name:rotation,type:float,size:4},{name:time,type:float,size:4},{name:x,type:float,size:4},{name:y,type:float,size:4}]}
|
||||||
@@ -1 +0,0 @@
|
|||||||
{version:1,fields:[{name:color,type:arc.graphics.Color,size:-1},{name:data,type:java.lang.Object,size:-1},{name:effect,type:mindustry.entities.Effect,size:-1},{name:lifetime,type:float,size:4},{name:offsetX,type:float,size:4},{name:offsetY,type:float,size:4},{name:parent,type:mindustry.gen.Posc,size:-1},{name:rotation,type:float,size:4},{name:time,type:float,size:4},{name:x,type:float,size:4},{name:y,type:float,size:4}]}
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
{version:2,fields:[{name:color,type:arc.graphics.Color,size:-1},{name:data,type:java.lang.Object,size:-1},{name:effect,type:mindustry.entities.Effect,size:-1},{name:lifetime,type:float,size:4},{name:offsetX,type:float,size:4},{name:offsetY,type:float,size:4},{name:parent,type:Posc,size:-1},{name:rotation,type:float,size:4},{name:time,type:float,size:4},{name:x,type:float,size:4},{name:y,type:float,size:4}]}
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
{version:3,fields:[{name:color,type:arc.graphics.Color,size:-1},{name:data,type:java.lang.Object,size:-1},{name:effect,type:mindustry.entities.Effect,size:-1},{name:lifetime,type:float,size:4},{name:offsetX,type:float,size:4},{name:offsetY,type:float,size:4},{name:parent,type:mindustry.gen.Posc,size:-1},{name:rotation,type:float,size:4},{name:time,type:float,size:4},{name:x,type:float,size:4},{name:y,type:float,size:4}]}
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
{fields:[{name:ammo,type:int,size:4},{name:armor,type:float,size:4},{name:controller,type:mindustry.entities.units.UnitController,size:-1},{name:elevation,type:float,size:4},{name:health,type:float,size:4},{name:isShooting,type:boolean,size:1},{name:mineTile,type:mindustry.world.Tile,size:-1},{name:mounts,type:"mindustry.entities.units.WeaponMount[]",size:-1},{name:rotation,type:float,size:4},{name:shield,type:float,size:4},{name:spawnedByCore,type:boolean,size:1},{name:stack,type:mindustry.type.ItemStack,size:-1},{name:statuses,type:arc.struct.Seq<mindustry.entities.units.StatusEntry>,size:-1},{name:team,type:mindustry.game.Team,size:-1},{name:type,type:mindustry.type.UnitType,size:-1},{name:x,type:float,size:4},{name:y,type:float,size:4}]}
|
|
||||||
@@ -125,6 +125,7 @@ mod.reloadrequired = [scarlet]Restart Required
|
|||||||
mod.import = Import Mod
|
mod.import = Import Mod
|
||||||
mod.import.file = Import File
|
mod.import.file = Import File
|
||||||
mod.import.github = Import From GitHub
|
mod.import.github = Import From GitHub
|
||||||
|
mod.jarwarn = [scarlet]JAR mods are inherently unsafe.[]\nMake sure you're importing this mod from a trustworthy source!
|
||||||
mod.item.remove = This item is part of the[accent] '{0}'[] mod. To remove it, uninstall that mod.
|
mod.item.remove = This item is part of the[accent] '{0}'[] mod. To remove it, uninstall that mod.
|
||||||
mod.remove.confirm = This mod will be deleted.
|
mod.remove.confirm = This mod will be deleted.
|
||||||
mod.author = [lightgray]Author:[] {0}
|
mod.author = [lightgray]Author:[] {0}
|
||||||
@@ -197,8 +198,8 @@ server.admins.none = No admins found!
|
|||||||
server.add = Add Server
|
server.add = Add Server
|
||||||
server.delete = Are you sure you want to delete this server?
|
server.delete = Are you sure you want to delete this server?
|
||||||
server.edit = Edit Server
|
server.edit = Edit Server
|
||||||
server.outdated = [crimson]Outdated Server![]
|
server.outdated = [scarlet]Outdated Server![]
|
||||||
server.outdated.client = [crimson]Outdated Client![]
|
server.outdated.client = [scarlet]Outdated Client![]
|
||||||
server.version = [gray]v{0} {1}
|
server.version = [gray]v{0} {1}
|
||||||
server.custombuild = [accent]Custom Build
|
server.custombuild = [accent]Custom Build
|
||||||
confirmban = Are you sure you want to ban "{0}[white]"?
|
confirmban = Are you sure you want to ban "{0}[white]"?
|
||||||
@@ -220,7 +221,7 @@ connecting.data = [accent]Loading world data...
|
|||||||
server.port = Port:
|
server.port = Port:
|
||||||
server.addressinuse = Address already in use!
|
server.addressinuse = Address already in use!
|
||||||
server.invalidport = Invalid port number!
|
server.invalidport = Invalid port number!
|
||||||
server.error = [crimson]Error hosting server.
|
server.error = [scarlet]Error hosting server.
|
||||||
save.new = New Save
|
save.new = New Save
|
||||||
save.overwrite = Are you sure you want to overwrite\nthis save slot?
|
save.overwrite = Are you sure you want to overwrite\nthis save slot?
|
||||||
overwrite = Overwrite
|
overwrite = Overwrite
|
||||||
@@ -230,8 +231,8 @@ save.delete.confirm = Are you sure you want to delete this save?
|
|||||||
save.delete = Delete
|
save.delete = Delete
|
||||||
save.export = Export Save
|
save.export = Export Save
|
||||||
save.import.invalid = [accent]This save is invalid!
|
save.import.invalid = [accent]This save is invalid!
|
||||||
save.import.fail = [crimson]Failed to import save: [accent]{0}
|
save.import.fail = [scarlet]Failed to import save: [accent]{0}
|
||||||
save.export.fail = [crimson]Failed to export save: [accent]{0}
|
save.export.fail = [scarlet]Failed to export save: [accent]{0}
|
||||||
save.import = Import Save
|
save.import = Import Save
|
||||||
save.newslot = Save name:
|
save.newslot = Save name:
|
||||||
save.rename = Rename
|
save.rename = Rename
|
||||||
@@ -486,7 +487,7 @@ zone.objective.attack = Destroy Enemy Core
|
|||||||
add = Add...
|
add = Add...
|
||||||
boss.health = Boss Health
|
boss.health = Boss Health
|
||||||
|
|
||||||
connectfail = [crimson]Connection error:\n\n[accent]{0}
|
connectfail = [scarlet]Connection error:\n\n[accent]{0}
|
||||||
error.unreachable = Server unreachable.\nIs the address spelled correctly?
|
error.unreachable = Server unreachable.\nIs the address spelled correctly?
|
||||||
error.invalidaddress = Invalid address.
|
error.invalidaddress = Invalid address.
|
||||||
error.timedout = Timed out!\nMake sure the host has port forwarding set up, and that the address is correct!
|
error.timedout = Timed out!\nMake sure the host has port forwarding set up, and that the address is correct!
|
||||||
@@ -545,7 +546,7 @@ unplaceable.sectorcaptured = [scarlet]Requires captured sector
|
|||||||
yes = Yes
|
yes = Yes
|
||||||
no = No
|
no = No
|
||||||
info.title = Info
|
info.title = Info
|
||||||
error.title = [crimson]An error has occured
|
error.title = [scarlet]An error has occured
|
||||||
error.crashtitle = An error has occured
|
error.crashtitle = An error has occured
|
||||||
unit.nobuild = [scarlet]Unit can't build
|
unit.nobuild = [scarlet]Unit can't build
|
||||||
blocks.input = Input
|
blocks.input = Input
|
||||||
|
|||||||
@@ -136,7 +136,7 @@ public interface Platform{
|
|||||||
* @param extension File extension to filter
|
* @param extension File extension to filter
|
||||||
*/
|
*/
|
||||||
default void showFileChooser(boolean open, String extension, Cons<Fi> cons){
|
default void showFileChooser(boolean open, String extension, Cons<Fi> cons){
|
||||||
new FileChooser(open ? "$open" : "$save", file -> file.extension().toLowerCase().equals(extension), open, file -> {
|
new FileChooser(open ? "$open" : "$save", file -> file.extEquals(extension), open, file -> {
|
||||||
if(!open){
|
if(!open){
|
||||||
cons.get(file.parent().child(file.nameWithoutExtension() + "." + extension));
|
cons.get(file.parent().child(file.nameWithoutExtension() + "." + extension));
|
||||||
}else{
|
}else{
|
||||||
@@ -145,6 +145,19 @@ public interface Platform{
|
|||||||
}).show();
|
}).show();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show a file chooser for multiple file types. Only supported on desktop.
|
||||||
|
* @param cons Selection listener
|
||||||
|
* @param extensions File extensions to filter
|
||||||
|
*/
|
||||||
|
default void showMultiFileChooser(Cons<Fi> cons, String... extensions){
|
||||||
|
if(mobile){
|
||||||
|
showFileChooser(true, extensions[0], cons);
|
||||||
|
}else{
|
||||||
|
new FileChooser("$open", file -> Structs.contains(extensions, file.extension().toLowerCase()), true, cons).show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** Hide the app. Android only. */
|
/** Hide the app. Android only. */
|
||||||
default void hide(){
|
default void hide(){
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -141,6 +141,8 @@ public class Universe{
|
|||||||
//TODO events
|
//TODO events
|
||||||
|
|
||||||
Events.fire(new TurnEvent());
|
Events.fire(new TurnEvent());
|
||||||
|
|
||||||
|
save();
|
||||||
}
|
}
|
||||||
|
|
||||||
public float secondsMod(float mod, float scale){
|
public float secondsMod(float mod, float scale){
|
||||||
|
|||||||
@@ -74,7 +74,6 @@ public abstract class SaveVersion extends SaveFileReader{
|
|||||||
//prepare campaign data for writing
|
//prepare campaign data for writing
|
||||||
if(state.isCampaign()){
|
if(state.isCampaign()){
|
||||||
state.secinfo.prepare();
|
state.secinfo.prepare();
|
||||||
state.getSector().setLastSecond(universe.seconds());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//flush tech node progress
|
//flush tech node progress
|
||||||
|
|||||||
@@ -15,6 +15,11 @@ public class Mod{
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Called on clientside mods. Load content here. */
|
||||||
|
public void loadContent(){
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/** Register any commands to be used on the server side, e.g. from the console. */
|
/** Register any commands to be used on the server side, e.g. from the console. */
|
||||||
public void registerServerCommands(CommandHandler handler){
|
public void registerServerCommands(CommandHandler handler){
|
||||||
|
|
||||||
|
|||||||
@@ -460,6 +460,17 @@ public class Mods implements Loadable{
|
|||||||
/** Creates all the content found in mod files. */
|
/** Creates all the content found in mod files. */
|
||||||
public void loadContent(){
|
public void loadContent(){
|
||||||
|
|
||||||
|
//load class mod content first
|
||||||
|
for(LoadedMod mod : orderedMods()){
|
||||||
|
//hidden mods can't load content
|
||||||
|
if(mod.main != null && !mod.meta.hidden){
|
||||||
|
content.setCurrentMod(mod);
|
||||||
|
mod.main.loadContent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
content.setCurrentMod(null);
|
||||||
|
|
||||||
class LoadRun implements Comparable<LoadRun>{
|
class LoadRun implements Comparable<LoadRun>{
|
||||||
final ContentType type;
|
final ContentType type;
|
||||||
final Fi file;
|
final Fi file;
|
||||||
@@ -583,7 +594,7 @@ public class Mods implements Loadable{
|
|||||||
Fi metaf = zip.child("mod.json").exists() ? zip.child("mod.json") : zip.child("mod.hjson").exists() ? zip.child("mod.hjson") : zip.child("plugin.json");
|
Fi metaf = zip.child("mod.json").exists() ? zip.child("mod.json") : zip.child("mod.hjson").exists() ? zip.child("mod.hjson") : zip.child("plugin.json");
|
||||||
if(!metaf.exists()){
|
if(!metaf.exists()){
|
||||||
Log.warn("Mod @ doesn't have a 'mod.json'/'mod.hjson'/'plugin.json' file, skipping.", sourceFile);
|
Log.warn("Mod @ doesn't have a 'mod.json'/'mod.hjson'/'plugin.json' file, skipping.", sourceFile);
|
||||||
throw new IllegalArgumentException("No mod.json found.");
|
throw new IllegalArgumentException("Invalid file: No mod.json found.");
|
||||||
}
|
}
|
||||||
|
|
||||||
ModMeta meta = json.fromJson(ModMeta.class, Jval.read(metaf.readString()).toString(Jformat.plain));
|
ModMeta meta = json.fromJson(ModMeta.class, Jval.read(metaf.readString()).toString(Jformat.plain));
|
||||||
@@ -607,9 +618,9 @@ public class Mods implements Loadable{
|
|||||||
|
|
||||||
//make sure the main class exists before loading it; if it doesn't just don't put it there
|
//make sure the main class exists before loading it; if it doesn't just don't put it there
|
||||||
if(mainFile.exists()){
|
if(mainFile.exists()){
|
||||||
//other platforms don't have standard java class loaders
|
//mobile versions don't support class mods
|
||||||
if(!headless && Version.build != -1){
|
if(mobile){
|
||||||
throw new IllegalArgumentException("Java class mods are currently unsupported outside of custom builds.");
|
throw new IllegalArgumentException("Java class mods are not supported on mobile.");
|
||||||
}
|
}
|
||||||
|
|
||||||
URLClassLoader classLoader = new URLClassLoader(new URL[]{sourceFile.file().toURI().toURL()}, ClassLoader.getSystemClassLoader());
|
URLClassLoader classLoader = new URLClassLoader(new URL[]{sourceFile.file().toURI().toURL()}, ClassLoader.getSystemClassLoader());
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import arc.struct.*;
|
|||||||
import arc.util.ArcAnnotate.*;
|
import arc.util.ArcAnnotate.*;
|
||||||
import arc.util.*;
|
import arc.util.*;
|
||||||
import arc.util.io.*;
|
import arc.util.io.*;
|
||||||
import arc.util.noise.*;
|
|
||||||
import mindustry.*;
|
import mindustry.*;
|
||||||
import mindustry.ctype.*;
|
import mindustry.ctype.*;
|
||||||
import mindustry.game.Saves.*;
|
import mindustry.game.Saves.*;
|
||||||
@@ -29,7 +28,7 @@ public class Sector{
|
|||||||
public @Nullable SectorPreset preset;
|
public @Nullable SectorPreset preset;
|
||||||
|
|
||||||
/** Sector enemy hostility from 0 to 1 */
|
/** Sector enemy hostility from 0 to 1 */
|
||||||
public float hostility;
|
//public float hostility;
|
||||||
|
|
||||||
//TODO implement a dynamic launch period
|
//TODO implement a dynamic launch period
|
||||||
public int launchPeriod = 10;
|
public int launchPeriod = 10;
|
||||||
@@ -57,7 +56,7 @@ public class Sector{
|
|||||||
|
|
||||||
/** @return whether the enemy has a generated base here. */
|
/** @return whether the enemy has a generated base here. */
|
||||||
public boolean hasEnemyBase(){
|
public boolean hasEnemyBase(){
|
||||||
return hostility >= 0.02f && (save == null || save.meta.rules.waves);
|
return is(SectorAttribute.base) && (save == null || save.meta.rules.waves);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isBeingPlayed(){
|
public boolean isBeingPlayed(){
|
||||||
@@ -80,7 +79,7 @@ public class Sector{
|
|||||||
|
|
||||||
public void generate(){
|
public void generate(){
|
||||||
//TODO use simplex and a seed
|
//TODO use simplex and a seed
|
||||||
hostility = Math.max(Noise.snoise3(tile.v.x, tile.v.y, tile.v.z, 0.5f, 0.4f), 0);
|
//hostility = Math.max(Noise.snoise3(tile.v.x, tile.v.y, tile.v.z, 0.5f, 0.4f), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean locked(){
|
public boolean locked(){
|
||||||
@@ -156,7 +155,8 @@ public class Sector{
|
|||||||
return (seconds / 60) + ":" + (sf < 10 ? "0" : "") + sf;
|
return (seconds / 60) + ":" + (sf < 10 ? "0" : "") + sf;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return the stored amount of time spent in this sector this turn in ticks. */
|
/** @return the stored amount of time spent in this sector this turn in ticks.
|
||||||
|
* Do not use unless you know what you're doing. */
|
||||||
public float getStoredTimeSpent(){
|
public float getStoredTimeSpent(){
|
||||||
return Core.settings.getFloat(key("time-spent"));
|
return Core.settings.getFloat(key("time-spent"));
|
||||||
}
|
}
|
||||||
@@ -165,6 +165,8 @@ public class Sector{
|
|||||||
put("seconds-passed", number);
|
put("seconds-passed", number);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @return how much time has passed in this sector without the player resuming here.
|
||||||
|
* Used for resource production calculations. */
|
||||||
public long getSecondsPassed(){
|
public long getSecondsPassed(){
|
||||||
return Core.settings.getLong(key("seconds-passed"));
|
return Core.settings.getLong(key("seconds-passed"));
|
||||||
}
|
}
|
||||||
@@ -284,6 +286,8 @@ public class Sector{
|
|||||||
/** Has snow. */
|
/** Has snow. */
|
||||||
snowy,
|
snowy,
|
||||||
/** Has sandstorms. */
|
/** Has sandstorms. */
|
||||||
desert
|
desert,
|
||||||
|
/** Has an enemy base. */
|
||||||
|
base
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -77,15 +77,24 @@ public class ModsDialog extends BaseDialog{
|
|||||||
t.button("$mod.import.file", Icon.file, bstyle, () -> {
|
t.button("$mod.import.file", Icon.file, bstyle, () -> {
|
||||||
dialog.hide();
|
dialog.hide();
|
||||||
|
|
||||||
platform.showFileChooser(true, "zip", file -> {
|
platform.showMultiFileChooser(file -> {
|
||||||
try{
|
Runnable go = () -> {
|
||||||
mods.importMod(file);
|
try{
|
||||||
setup();
|
mods.importMod(file);
|
||||||
}catch(IOException e){
|
setup();
|
||||||
ui.showException(e);
|
}catch(IOException e){
|
||||||
e.printStackTrace();
|
ui.showException(e);
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//show unsafe jar file warning
|
||||||
|
if(file.extEquals("jar")){
|
||||||
|
ui.showConfirm("$warning", "$mod.jarwarn", go);
|
||||||
|
}else{
|
||||||
|
go.run();
|
||||||
}
|
}
|
||||||
});
|
}, "zip", "jar");
|
||||||
}).margin(12f);
|
}).margin(12f);
|
||||||
|
|
||||||
t.row();
|
t.row();
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
org.gradle.daemon=true
|
org.gradle.daemon=true
|
||||||
org.gradle.jvmargs=-Xms256m -Xmx1024m
|
org.gradle.jvmargs=-Xms256m -Xmx1024m
|
||||||
archash=6ed1b560047eaaf9ae83176526de51e5a49cadc3
|
archash=b877b22de07db3cd2843a59eb92f5dfe1c61ae78
|
||||||
|
|||||||
Reference in New Issue
Block a user