Merge branches '6.0' and 'master' of https://github.com/Anuken/Mindustry into 6.0
# Conflicts: # core/assets/sprites/block_colors.png # core/assets/sprites/sprites.atlas # core/assets/sprites/sprites.png # core/assets/sprites/sprites2.png # core/assets/sprites/sprites3.png # core/assets/sprites/sprites5.png # core/src/io/anuke/mindustry/ctype/ContentType.java # core/src/io/anuke/mindustry/ctype/UnlockableContent.java # core/src/io/anuke/mindustry/io/LegacyMapIO.java # core/src/io/anuke/mindustry/type/WeatherEvent.java # gradle.properties
This commit is contained in:
@@ -32,8 +32,8 @@ public abstract class ClientLauncher extends ApplicationCore implements Platform
|
||||
|
||||
@Override
|
||||
public void setup(){
|
||||
Vars.loadLogger();
|
||||
Vars.platform = this;
|
||||
Log.setUseColors(false);
|
||||
beginTime = Time.millis();
|
||||
|
||||
Time.setDeltaProvider(() -> {
|
||||
@@ -70,8 +70,11 @@ public abstract class ClientLauncher extends ApplicationCore implements Platform
|
||||
Sounds.load();
|
||||
|
||||
assets.loadRun("contentcreate", Content.class, () -> {
|
||||
content.createContent();
|
||||
content.createBaseContent();
|
||||
content.loadColors();
|
||||
}, () -> {
|
||||
mods.loadScripts();
|
||||
content.createModContent();
|
||||
});
|
||||
|
||||
add(logic = new Logic());
|
||||
@@ -120,7 +123,7 @@ public abstract class ClientLauncher extends ApplicationCore implements Platform
|
||||
for(ApplicationListener listener : modules){
|
||||
listener.init();
|
||||
}
|
||||
mods.each(Mod::init);
|
||||
mods.eachClass(Mod::init);
|
||||
finished = true;
|
||||
Events.fire(new ClientLoadEvent());
|
||||
super.resize(graphics.getWidth(), graphics.getHeight());
|
||||
@@ -193,7 +196,8 @@ public abstract class ClientLauncher extends ApplicationCore implements Platform
|
||||
|
||||
if(assets.getCurrentLoading() != null){
|
||||
String name = assets.getCurrentLoading().fileName.toLowerCase();
|
||||
String key = name.contains("content") ? "content" : name.contains("mod") ? "mods" : name.contains("msav") || name.contains("maps") ? "map" : name.contains("ogg") || name.contains("mp3") ? "sound" : name.contains("png") ? "image" : "system";
|
||||
String key = name.contains("script") ? "scripts" : name.contains("content") ? "content" : name.contains("mod") ? "mods" : name.contains("msav") ||
|
||||
name.contains("maps") ? "map" : name.contains("ogg") || name.contains("mp3") ? "sound" : name.contains("png") ? "image" : "system";
|
||||
font.draw(bundle.get("load." + key, ""), graphics.getWidth() / 2f, graphics.getHeight() / 2f - height / 2f - Scl.scl(10f), Align.center);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import io.anuke.arc.files.*;
|
||||
import io.anuke.arc.graphics.*;
|
||||
import io.anuke.arc.scene.ui.layout.*;
|
||||
import io.anuke.arc.util.*;
|
||||
import io.anuke.arc.util.io.*;
|
||||
import io.anuke.mindustry.ai.*;
|
||||
import io.anuke.mindustry.core.*;
|
||||
import io.anuke.mindustry.entities.*;
|
||||
@@ -15,6 +16,7 @@ import io.anuke.mindustry.entities.effect.*;
|
||||
import io.anuke.mindustry.entities.traits.*;
|
||||
import io.anuke.mindustry.entities.type.*;
|
||||
import io.anuke.mindustry.game.*;
|
||||
import io.anuke.mindustry.game.EventType.*;
|
||||
import io.anuke.mindustry.gen.*;
|
||||
import io.anuke.mindustry.input.*;
|
||||
import io.anuke.mindustry.maps.*;
|
||||
@@ -32,6 +34,8 @@ import static io.anuke.arc.Core.settings;
|
||||
public class Vars implements Loadable{
|
||||
/** Whether to load locales.*/
|
||||
public static boolean loadLocales = true;
|
||||
/** Whether the logger is loaded. */
|
||||
public static boolean loadedLogger = false;
|
||||
/** Maximum schematic size.*/
|
||||
public static final int maxSchematicSize = 32;
|
||||
/** All schematic base64 starts with this string.*/
|
||||
@@ -119,22 +123,24 @@ public class Vars implements Loadable{
|
||||
public static boolean headless;
|
||||
/** whether steam is enabled for this game */
|
||||
public static boolean steam;
|
||||
/** whether typing into the console is enabled - developers only */
|
||||
public static boolean enableConsole = false;
|
||||
/** application data directory, equivalent to {@link io.anuke.arc.Settings#getDataDirectory()} */
|
||||
public static FileHandle dataDirectory;
|
||||
public static Fi dataDirectory;
|
||||
/** data subdirectory used for screenshots */
|
||||
public static FileHandle screenshotDirectory;
|
||||
public static Fi screenshotDirectory;
|
||||
/** data subdirectory used for custom mmaps */
|
||||
public static FileHandle customMapDirectory;
|
||||
public static Fi customMapDirectory;
|
||||
/** data subdirectory used for custom mmaps */
|
||||
public static FileHandle mapPreviewDirectory;
|
||||
public static Fi mapPreviewDirectory;
|
||||
/** tmp subdirectory for map conversion */
|
||||
public static FileHandle tmpDirectory;
|
||||
public static Fi tmpDirectory;
|
||||
/** data subdirectory used for saves */
|
||||
public static FileHandle saveDirectory;
|
||||
public static Fi saveDirectory;
|
||||
/** data subdirectory used for mods */
|
||||
public static FileHandle modDirectory;
|
||||
public static Fi modDirectory;
|
||||
/** data subdirectory used for schematics */
|
||||
public static FileHandle schematicDirectory;
|
||||
public static Fi schematicDirectory;
|
||||
/** map file extension */
|
||||
public static final String mapExtension = "msav";
|
||||
/** save file extension */
|
||||
@@ -192,6 +198,7 @@ public class Vars implements Loadable{
|
||||
|
||||
public static void init(){
|
||||
Serialization.init();
|
||||
DefaultSerializers.typeMappings.put("io.anuke.mindustry.type.ContentType", "io.anuke.mindustry.ctype.ContentType");
|
||||
|
||||
if(loadLocales){
|
||||
//load locales
|
||||
@@ -271,6 +278,31 @@ public class Vars implements Loadable{
|
||||
maps.load();
|
||||
}
|
||||
|
||||
public static void loadLogger(){
|
||||
if(loadedLogger) return;
|
||||
|
||||
String[] tags = {"[green][D][]", "[royal][I][]", "[yellow][W][]", "[scarlet][E][]", ""};
|
||||
String[] stags = {"&lc&fb[D]", "&lg&fb[I]", "&ly&fb[W]", "&lr&fb[E]", ""};
|
||||
|
||||
Array<String> logBuffer = new Array<>();
|
||||
Log.setLogger((level, text, args) -> {
|
||||
String result = Log.format(text, args);
|
||||
System.out.println(Log.format(stags[level.ordinal()] + "&fr " + text, args));
|
||||
|
||||
result = tags[level.ordinal()] + " " + result;
|
||||
|
||||
if(!headless && (ui == null || ui.scriptfrag == null)){
|
||||
logBuffer.add(result);
|
||||
}else if(!headless){
|
||||
ui.scriptfrag.addMessage(result);
|
||||
}
|
||||
});
|
||||
|
||||
Events.on(ClientLoadEvent.class, e -> logBuffer.each(ui.scriptfrag::addMessage));
|
||||
|
||||
loadedLogger = true;
|
||||
}
|
||||
|
||||
public static void loadSettings(){
|
||||
Core.settings.setAppName(appName);
|
||||
|
||||
@@ -278,7 +310,7 @@ public class Vars implements Loadable{
|
||||
Core.settings.setDataDirectory(Core.files.local("saves/"));
|
||||
}
|
||||
|
||||
Core.settings.defaults("locale", "default");
|
||||
Core.settings.defaults("locale", "default", "blocksync", true);
|
||||
Core.keybinds.setDefaults(Binding.values());
|
||||
Core.settings.load();
|
||||
|
||||
@@ -288,7 +320,7 @@ public class Vars implements Loadable{
|
||||
|
||||
try{
|
||||
//try loading external bundle
|
||||
FileHandle handle = Core.files.local("bundle");
|
||||
Fi handle = Core.files.local("bundle");
|
||||
|
||||
Locale locale = Locale.ENGLISH;
|
||||
Core.bundle = I18NBundle.createBundle(handle, locale);
|
||||
@@ -301,7 +333,7 @@ public class Vars implements Loadable{
|
||||
}catch(Throwable e){
|
||||
//no external bundle found
|
||||
|
||||
FileHandle handle = Core.files.internal("bundles/bundle");
|
||||
Fi handle = Core.files.internal("bundles/bundle");
|
||||
Locale locale;
|
||||
String loc = Core.settings.getString("locale");
|
||||
if(loc.equals("default")){
|
||||
|
||||
@@ -7,7 +7,7 @@ import io.anuke.arc.graphics.g2d.*;
|
||||
import io.anuke.arc.math.*;
|
||||
import io.anuke.arc.util.*;
|
||||
import io.anuke.mindustry.*;
|
||||
import io.anuke.mindustry.ctype.ContentList;
|
||||
import io.anuke.mindustry.ctype.*;
|
||||
import io.anuke.mindustry.entities.*;
|
||||
import io.anuke.mindustry.entities.bullet.*;
|
||||
import io.anuke.mindustry.entities.type.*;
|
||||
@@ -19,8 +19,7 @@ import io.anuke.mindustry.world.blocks.*;
|
||||
import io.anuke.mindustry.world.blocks.defense.*;
|
||||
import io.anuke.mindustry.world.blocks.defense.turrets.*;
|
||||
import io.anuke.mindustry.world.blocks.distribution.*;
|
||||
import io.anuke.mindustry.world.blocks.liquid.Conduit;
|
||||
import io.anuke.mindustry.world.blocks.liquid.LiquidTank;
|
||||
import io.anuke.mindustry.world.blocks.liquid.*;
|
||||
import io.anuke.mindustry.world.blocks.logic.*;
|
||||
import io.anuke.mindustry.world.blocks.power.*;
|
||||
import io.anuke.mindustry.world.blocks.production.*;
|
||||
@@ -496,7 +495,7 @@ public class Blocks implements ContentList{
|
||||
drawer = tile -> {
|
||||
Draw.rect(region, tile.drawx(), tile.drawy());
|
||||
|
||||
GenericCrafterEntity entity = tile.entity();
|
||||
GenericCrafterEntity entity = tile.ent();
|
||||
|
||||
Draw.alpha(Mathf.absin(entity.totalProgress, 3f, 0.9f) * entity.warmup);
|
||||
Draw.rect(reg(topRegion), tile.drawx(), tile.drawy());
|
||||
@@ -521,7 +520,7 @@ public class Blocks implements ContentList{
|
||||
drawIcons = () -> new TextureRegion[]{Core.atlas.find(name + "-bottom"), Core.atlas.find(name), Core.atlas.find(name + "-weave")};
|
||||
|
||||
drawer = tile -> {
|
||||
GenericCrafterEntity entity = tile.entity();
|
||||
GenericCrafterEntity entity = tile.ent();
|
||||
|
||||
Draw.rect(reg(bottomRegion), tile.drawx(), tile.drawy());
|
||||
Draw.rect(reg(weaveRegion), tile.drawx(), tile.drawy(), entity.totalProgress);
|
||||
@@ -671,7 +670,7 @@ public class Blocks implements ContentList{
|
||||
drawIcons = () -> new TextureRegion[]{Core.atlas.find(name), Core.atlas.find(name + "-top")};
|
||||
|
||||
drawer = tile -> {
|
||||
GenericCrafterEntity entity = tile.entity();
|
||||
GenericCrafterEntity entity = tile.ent();
|
||||
|
||||
Draw.rect(region, tile.drawx(), tile.drawy());
|
||||
Draw.rect(reg(frameRegions[(int)Mathf.absin(entity.totalProgress, 5f, 2.999f)]), tile.drawx(), tile.drawy());
|
||||
@@ -698,7 +697,7 @@ public class Blocks implements ContentList{
|
||||
drawIcons = () -> new TextureRegion[]{Core.atlas.find(name), Core.atlas.find(name + "-rotator")};
|
||||
|
||||
drawer = tile -> {
|
||||
GenericCrafterEntity entity = tile.entity();
|
||||
GenericCrafterEntity entity = tile.ent();
|
||||
|
||||
Draw.rect(region, tile.drawx(), tile.drawy());
|
||||
Draw.rect(reg(rotatorRegion), tile.drawx(), tile.drawy(), entity.totalProgress * 2f);
|
||||
@@ -926,6 +925,7 @@ public class Blocks implements ContentList{
|
||||
phaseConveyor = new ItemBridge("phase-conveyor"){{
|
||||
requirements(Category.distribution, ItemStack.with(Items.phasefabric, 5, Items.silicon, 7, Items.lead, 10, Items.graphite, 10));
|
||||
range = 12;
|
||||
canOverdrive = false;
|
||||
hasPower = true;
|
||||
consumes.power(0.30f);
|
||||
}};
|
||||
@@ -988,7 +988,7 @@ public class Blocks implements ContentList{
|
||||
size = 3;
|
||||
}};
|
||||
|
||||
conduit = new io.anuke.mindustry.world.blocks.liquid.Conduit("conduit"){{
|
||||
conduit = new Conduit("conduit"){{
|
||||
requirements(Category.liquid, ItemStack.with(Items.metaglass, 1));
|
||||
health = 45;
|
||||
}};
|
||||
@@ -1000,14 +1000,14 @@ public class Blocks implements ContentList{
|
||||
health = 90;
|
||||
}};
|
||||
|
||||
platedConduit = new io.anuke.mindustry.world.blocks.liquid.ArmoredConduit("plated-conduit"){{
|
||||
requirements(Category.liquid, ItemStack.with(Items.thorium, 2, Items.metaglass, 1));
|
||||
platedConduit = new ArmoredConduit("plated-conduit"){{
|
||||
requirements(Category.liquid, ItemStack.with(Items.thorium, 2, Items.metaglass, 1, Items.plastanium, 1));
|
||||
liquidCapacity = 16f;
|
||||
liquidPressure = 1.025f;
|
||||
health = 220;
|
||||
}};
|
||||
|
||||
liquidRouter = new io.anuke.mindustry.world.blocks.liquid.LiquidRouter("liquid-router"){{
|
||||
liquidRouter = new LiquidRouter("liquid-router"){{
|
||||
requirements(Category.liquid, ItemStack.with(Items.graphite, 4, Items.metaglass, 2));
|
||||
liquidCapacity = 20f;
|
||||
}};
|
||||
@@ -1019,20 +1019,21 @@ public class Blocks implements ContentList{
|
||||
health = 500;
|
||||
}};
|
||||
|
||||
liquidJunction = new io.anuke.mindustry.world.blocks.liquid.LiquidJunction("liquid-junction"){{
|
||||
liquidJunction = new LiquidJunction("liquid-junction"){{
|
||||
requirements(Category.liquid, ItemStack.with(Items.graphite, 2, Items.metaglass, 2));
|
||||
}};
|
||||
|
||||
bridgeConduit = new io.anuke.mindustry.world.blocks.liquid.LiquidExtendingBridge("bridge-conduit"){{
|
||||
bridgeConduit = new LiquidExtendingBridge("bridge-conduit"){{
|
||||
requirements(Category.liquid, ItemStack.with(Items.graphite, 4, Items.metaglass, 8));
|
||||
range = 4;
|
||||
hasPower = false;
|
||||
}};
|
||||
|
||||
phaseConduit = new io.anuke.mindustry.world.blocks.liquid.LiquidBridge("phase-conduit"){{
|
||||
phaseConduit = new LiquidBridge("phase-conduit"){{
|
||||
requirements(Category.liquid, ItemStack.with(Items.phasefabric, 5, Items.silicon, 7, Items.metaglass, 20, Items.titanium, 10));
|
||||
range = 12;
|
||||
hasPower = true;
|
||||
canOverdrive = false;
|
||||
consumes.power(0.30f);
|
||||
}};
|
||||
|
||||
@@ -1370,7 +1371,7 @@ public class Blocks implements ContentList{
|
||||
ammo(
|
||||
Items.graphite, Bullets.artilleryDense,
|
||||
Items.silicon, Bullets.artilleryHoming,
|
||||
Items.pyratite, Bullets.artlleryIncendiary
|
||||
Items.pyratite, Bullets.artilleryIncendiary
|
||||
);
|
||||
reload = 60f;
|
||||
recoil = 2f;
|
||||
@@ -1550,9 +1551,9 @@ public class Blocks implements ContentList{
|
||||
ammo(
|
||||
Items.graphite, Bullets.artilleryDense,
|
||||
Items.silicon, Bullets.artilleryHoming,
|
||||
Items.pyratite, Bullets.artlleryIncendiary,
|
||||
Items.pyratite, Bullets.artilleryIncendiary,
|
||||
Items.blastCompound, Bullets.artilleryExplosive,
|
||||
Items.plastanium, Bullets.arilleryPlastic
|
||||
Items.plastanium, Bullets.artilleryPlastic
|
||||
);
|
||||
size = 3;
|
||||
shots = 4;
|
||||
|
||||
@@ -18,7 +18,7 @@ public class Bullets implements ContentList{
|
||||
public static BulletType
|
||||
|
||||
//artillery
|
||||
artilleryDense, arilleryPlastic, artilleryPlasticFrag, artilleryHoming, artlleryIncendiary, artilleryExplosive, artilleryUnit,
|
||||
artilleryDense, artilleryPlastic, artilleryPlasticFrag, artilleryHoming, artilleryIncendiary, artilleryExplosive, artilleryUnit,
|
||||
|
||||
//flak
|
||||
flakScrap, flakLead, flakPlastic, flakExplosive, flakSurge, flakGlass, glassFrag,
|
||||
@@ -65,7 +65,7 @@ public class Bullets implements ContentList{
|
||||
despawnEffect = Fx.none;
|
||||
}};
|
||||
|
||||
arilleryPlastic = new ArtilleryBulletType(3.4f, 0, "shell"){{
|
||||
artilleryPlastic = new ArtilleryBulletType(3.4f, 0, "shell"){{
|
||||
hitEffect = Fx.plasticExplosion;
|
||||
knockback = 1f;
|
||||
lifetime = 55f;
|
||||
@@ -91,7 +91,7 @@ public class Bullets implements ContentList{
|
||||
homingRange = 50f;
|
||||
}};
|
||||
|
||||
artlleryIncendiary = new ArtilleryBulletType(3f, 0, "shell"){{
|
||||
artilleryIncendiary = new ArtilleryBulletType(3f, 0, "shell"){{
|
||||
hitEffect = Fx.blastExplosion;
|
||||
knockback = 0.8f;
|
||||
lifetime = 60f;
|
||||
|
||||
@@ -48,28 +48,24 @@ public class Fx implements ContentList{
|
||||
Draw.rect(unit.getIconRegion(), e.x, e.y,
|
||||
unit.getIconRegion().getWidth() * Draw.scl * scl, unit.getIconRegion().getWidth() * Draw.scl * scl, 180f);
|
||||
|
||||
Draw.reset();
|
||||
});
|
||||
|
||||
commandSend = new Effect(28, e -> {
|
||||
Draw.color(Pal.command);
|
||||
Lines.stroke(e.fout() * 2f);
|
||||
Lines.circle(e.x, e.y, 4f + e.finpow() * 120f);
|
||||
Draw.color();
|
||||
});
|
||||
|
||||
placeBlock = new Effect(16, e -> {
|
||||
Draw.color(Pal.accent);
|
||||
Lines.stroke(3f - e.fin() * 2f);
|
||||
Lines.square(e.x, e.y, tilesize / 2f * e.rotation + e.fin() * 3f);
|
||||
Draw.reset();
|
||||
});
|
||||
|
||||
tapBlock = new Effect(12, e -> {
|
||||
Draw.color(Pal.accent);
|
||||
Lines.stroke(3f - e.fin() * 2f);
|
||||
Lines.circle(e.x, e.y, 4f + (tilesize / 1.5f * e.rotation) * e.fin());
|
||||
Draw.reset();
|
||||
});
|
||||
|
||||
breakBlock = new Effect(12, e -> {
|
||||
@@ -80,41 +76,35 @@ public class Fx implements ContentList{
|
||||
Angles.randLenVectors(e.id, 3 + (int)(e.rotation * 3), e.rotation * 2f + (tilesize * e.rotation) * e.finpow(), (x, y) -> {
|
||||
Fill.square(e.x + x, e.y + y, 1f + e.fout() * (3f + e.rotation));
|
||||
});
|
||||
Draw.reset();
|
||||
});
|
||||
|
||||
select = new Effect(23, e -> {
|
||||
Draw.color(Pal.accent);
|
||||
Lines.stroke(e.fout() * 3f);
|
||||
Lines.circle(e.x, e.y, 3f + e.fin() * 14f);
|
||||
Draw.reset();
|
||||
});
|
||||
|
||||
smoke = new Effect(100, e -> {
|
||||
Draw.color(Color.gray, Pal.darkishGray, e.fin());
|
||||
float size = 7f - e.fin() * 7f;
|
||||
Draw.rect("circle", e.x, e.y, size, size);
|
||||
Draw.reset();
|
||||
});
|
||||
|
||||
magmasmoke = new Effect(110, e -> {
|
||||
Draw.color(Color.gray);
|
||||
Fill.circle(e.x, e.y, e.fslope() * 6f);
|
||||
Draw.reset();
|
||||
});
|
||||
|
||||
spawn = new Effect(30, e -> {
|
||||
Lines.stroke(2f * e.fout());
|
||||
Draw.color(Pal.accent);
|
||||
Lines.poly(e.x, e.y, 4, 5f + e.fin() * 12f);
|
||||
Draw.reset();
|
||||
});
|
||||
|
||||
padlaunch = new Effect(10, e -> {
|
||||
Lines.stroke(4f * e.fout());
|
||||
Draw.color(Pal.accent);
|
||||
Lines.poly(e.x, e.y, 4, 5f + e.fin() * 60f);
|
||||
Draw.reset();
|
||||
});
|
||||
|
||||
vtolHover = new Effect(40f, e -> {
|
||||
@@ -122,7 +112,6 @@ public class Fx implements ContentList{
|
||||
float ang = e.rotation + Mathf.randomSeedRange(e.id, 30f);
|
||||
Draw.color(Pal.lightFlame, Pal.lightOrange, e.fin());
|
||||
Fill.circle(e.x + Angles.trnsx(ang, len), e.y + Angles.trnsy(ang, len), 2f * e.fout());
|
||||
Draw.reset();
|
||||
});
|
||||
|
||||
unitDrop = new GroundEffect(30, e -> {
|
||||
@@ -130,7 +119,6 @@ public class Fx implements ContentList{
|
||||
Angles.randLenVectors(e.id, 9, 3 + 20f * e.finpow(), (x, y) -> {
|
||||
Fill.circle(e.x + x, e.y + y, e.fout() * 4f + 0.4f);
|
||||
});
|
||||
Draw.reset();
|
||||
});
|
||||
|
||||
unitLand = new GroundEffect(30, e -> {
|
||||
@@ -138,42 +126,36 @@ public class Fx implements ContentList{
|
||||
Angles.randLenVectors(e.id, 6, 17f * e.finpow(), (x, y) -> {
|
||||
Fill.circle(e.x + x, e.y + y, e.fout() * 4f + 0.3f);
|
||||
});
|
||||
Draw.reset();
|
||||
});
|
||||
|
||||
unitPickup = new GroundEffect(18, e -> {
|
||||
Draw.color(Pal.lightishGray);
|
||||
Lines.stroke(e.fin() * 2f);
|
||||
Lines.poly(e.x, e.y, 4, 13f * e.fout());
|
||||
Draw.reset();
|
||||
});
|
||||
|
||||
landShock = new GroundEffect(12, e -> {
|
||||
Draw.color(Pal.lancerLaser);
|
||||
Lines.stroke(e.fout() * 3f);
|
||||
Lines.poly(e.x, e.y, 12, 20f * e.fout());
|
||||
Draw.reset();
|
||||
});
|
||||
|
||||
pickup = new Effect(18, e -> {
|
||||
Draw.color(Pal.lightishGray);
|
||||
Lines.stroke(e.fout() * 2f);
|
||||
Lines.spikes(e.x, e.y, 1f + e.fin() * 6f, e.fout() * 4f, 6);
|
||||
Draw.reset();
|
||||
});
|
||||
|
||||
healWave = new Effect(22, e -> {
|
||||
Draw.color(Pal.heal);
|
||||
Lines.stroke(e.fout() * 2f);
|
||||
Lines.circle(e.x, e.y, 4f + e.finpow() * 60f);
|
||||
Draw.color();
|
||||
});
|
||||
|
||||
heal = new Effect(11, e -> {
|
||||
Draw.color(Pal.heal);
|
||||
Lines.stroke(e.fout() * 2f);
|
||||
Lines.circle(e.x, e.y, 2f + e.finpow() * 7f);
|
||||
Draw.color();
|
||||
});
|
||||
|
||||
|
||||
@@ -193,7 +175,6 @@ public class Fx implements ContentList{
|
||||
Lines.lineAngle(e.x + x, e.y + y, ang, e.fout() * 3 + 1f);
|
||||
});
|
||||
|
||||
Draw.reset();
|
||||
});
|
||||
|
||||
hitFuse = new Effect(14, e -> {
|
||||
@@ -212,7 +193,6 @@ public class Fx implements ContentList{
|
||||
Lines.lineAngle(e.x + x, e.y + y, ang, e.fout() * 3 + 1f);
|
||||
});
|
||||
|
||||
Draw.reset();
|
||||
});
|
||||
|
||||
hitBulletBig = new Effect(13, e -> {
|
||||
@@ -224,7 +204,6 @@ public class Fx implements ContentList{
|
||||
Lines.lineAngle(e.x + x, e.y + y, ang, e.fout() * 4 + 1.5f);
|
||||
});
|
||||
|
||||
Draw.reset();
|
||||
});
|
||||
|
||||
hitFlameSmall = new Effect(14, e -> {
|
||||
@@ -236,7 +215,6 @@ public class Fx implements ContentList{
|
||||
Lines.lineAngle(e.x + x, e.y + y, ang, e.fout() * 3 + 1f);
|
||||
});
|
||||
|
||||
Draw.reset();
|
||||
});
|
||||
|
||||
hitLiquid = new Effect(16, e -> {
|
||||
@@ -246,7 +224,6 @@ public class Fx implements ContentList{
|
||||
Fill.circle(e.x + x, e.y + y, e.fout() * 2f);
|
||||
});
|
||||
|
||||
Draw.reset();
|
||||
});
|
||||
|
||||
hitLancer = new Effect(12, e -> {
|
||||
@@ -258,7 +235,6 @@ public class Fx implements ContentList{
|
||||
Lines.lineAngle(e.x + x, e.y + y, ang, e.fout() * 4 + 1f);
|
||||
});
|
||||
|
||||
Draw.reset();
|
||||
});
|
||||
|
||||
hitMeltdown = new Effect(12, e -> {
|
||||
@@ -270,14 +246,12 @@ public class Fx implements ContentList{
|
||||
Lines.lineAngle(e.x + x, e.y + y, ang, e.fout() * 4 + 1f);
|
||||
});
|
||||
|
||||
Draw.reset();
|
||||
});
|
||||
|
||||
hitLaser = new Effect(8, e -> {
|
||||
Draw.color(Color.white, Pal.heal, e.fin());
|
||||
Lines.stroke(0.5f + e.fout());
|
||||
Lines.circle(e.x, e.y, e.fin() * 5f);
|
||||
Draw.reset();
|
||||
});
|
||||
|
||||
despawn = new Effect(12, e -> {
|
||||
@@ -289,7 +263,6 @@ public class Fx implements ContentList{
|
||||
Lines.lineAngle(e.x + x, e.y + y, ang, e.fout() * 2 + 1f);
|
||||
});
|
||||
|
||||
Draw.reset();
|
||||
});
|
||||
|
||||
flakExplosion = new Effect(20, e -> {
|
||||
@@ -313,7 +286,6 @@ public class Fx implements ContentList{
|
||||
Lines.lineAngle(e.x + x, e.y + y, Mathf.angle(x, y), 1f + e.fout() * 3f);
|
||||
});
|
||||
|
||||
Draw.reset();
|
||||
});
|
||||
|
||||
plasticExplosion = new Effect(24, e -> {
|
||||
@@ -337,7 +309,6 @@ public class Fx implements ContentList{
|
||||
Lines.lineAngle(e.x + x, e.y + y, Mathf.angle(x, y), 1f + e.fout() * 3f);
|
||||
});
|
||||
|
||||
Draw.reset();
|
||||
});
|
||||
|
||||
plasticExplosionFlak = new Effect(28, e -> {
|
||||
@@ -361,7 +332,6 @@ public class Fx implements ContentList{
|
||||
Lines.lineAngle(e.x + x, e.y + y, Mathf.angle(x, y), 1f + e.fout() * 3f);
|
||||
});
|
||||
|
||||
Draw.reset();
|
||||
});
|
||||
|
||||
blastExplosion = new Effect(22, e -> {
|
||||
@@ -385,32 +355,27 @@ public class Fx implements ContentList{
|
||||
Lines.lineAngle(e.x + x, e.y + y, Mathf.angle(x, y), 1f + e.fout() * 3f);
|
||||
});
|
||||
|
||||
Draw.reset();
|
||||
});
|
||||
|
||||
artilleryTrail = new Effect(50, e -> {
|
||||
Draw.color(e.color);
|
||||
Fill.circle(e.x, e.y, e.rotation * e.fout());
|
||||
Draw.reset();
|
||||
});
|
||||
|
||||
incendTrail = new Effect(50, e -> {
|
||||
Draw.color(Pal.lightOrange);
|
||||
Fill.circle(e.x, e.y, e.rotation * e.fout());
|
||||
Draw.reset();
|
||||
});
|
||||
|
||||
missileTrail = new Effect(50, e -> {
|
||||
Draw.color(e.color);
|
||||
Fill.circle(e.x, e.y, e.rotation * e.fout());
|
||||
Draw.reset();
|
||||
});
|
||||
|
||||
absorb = new Effect(12, e -> {
|
||||
Draw.color(Pal.accent);
|
||||
Lines.stroke(2f * e.fout());
|
||||
Lines.circle(e.x, e.y, 5f * e.fout());
|
||||
Draw.reset();
|
||||
});
|
||||
|
||||
flakExplosionBig = new Effect(30, e -> {
|
||||
@@ -434,7 +399,6 @@ public class Fx implements ContentList{
|
||||
Lines.lineAngle(e.x + x, e.y + y, Mathf.angle(x, y), 1f + e.fout() * 3f);
|
||||
});
|
||||
|
||||
Draw.reset();
|
||||
});
|
||||
|
||||
|
||||
@@ -445,7 +409,6 @@ public class Fx implements ContentList{
|
||||
Fill.circle(e.x + x, e.y + y, 0.1f + e.fout() * 1.4f);
|
||||
});
|
||||
|
||||
Draw.color();
|
||||
});
|
||||
|
||||
fire = new Effect(50f, e -> {
|
||||
@@ -467,7 +430,6 @@ public class Fx implements ContentList{
|
||||
Fill.circle(e.x + x, e.y + y, 0.2f + e.fslope() * 1.5f);
|
||||
});
|
||||
|
||||
Draw.color();
|
||||
});
|
||||
|
||||
steam = new Effect(35f, e -> {
|
||||
@@ -477,7 +439,6 @@ public class Fx implements ContentList{
|
||||
Fill.circle(e.x + x, e.y + y, 0.2f + e.fslope() * 1.5f);
|
||||
});
|
||||
|
||||
Draw.color();
|
||||
});
|
||||
|
||||
fireballsmoke = new Effect(25f, e -> {
|
||||
@@ -487,7 +448,6 @@ public class Fx implements ContentList{
|
||||
Fill.circle(e.x + x, e.y + y, 0.2f + e.fout() * 1.5f);
|
||||
});
|
||||
|
||||
Draw.color();
|
||||
});
|
||||
|
||||
ballfire = new Effect(25f, e -> {
|
||||
@@ -497,7 +457,6 @@ public class Fx implements ContentList{
|
||||
Fill.circle(e.x + x, e.y + y, 0.2f + e.fout() * 1.5f);
|
||||
});
|
||||
|
||||
Draw.color();
|
||||
});
|
||||
|
||||
freezing = new Effect(40f, e -> {
|
||||
@@ -507,7 +466,6 @@ public class Fx implements ContentList{
|
||||
Fill.circle(e.x + x, e.y + y, e.fout() * 1.2f);
|
||||
});
|
||||
|
||||
Draw.color();
|
||||
});
|
||||
|
||||
melting = new Effect(40f, e -> {
|
||||
@@ -517,7 +475,6 @@ public class Fx implements ContentList{
|
||||
Fill.circle(e.x + x, e.y + y, .2f + e.fout() * 1.2f);
|
||||
});
|
||||
|
||||
Draw.color();
|
||||
});
|
||||
|
||||
wet = new Effect(40f, e -> {
|
||||
@@ -527,7 +484,6 @@ public class Fx implements ContentList{
|
||||
Fill.circle(e.x + x, e.y + y, e.fout() * 1f);
|
||||
});
|
||||
|
||||
Draw.color();
|
||||
});
|
||||
|
||||
oily = new Effect(42f, e -> {
|
||||
@@ -537,7 +493,6 @@ public class Fx implements ContentList{
|
||||
Fill.circle(e.x + x, e.y + y, e.fout() * 1f);
|
||||
});
|
||||
|
||||
Draw.color();
|
||||
});
|
||||
|
||||
overdriven = new Effect(20f, e -> {
|
||||
@@ -547,7 +502,6 @@ public class Fx implements ContentList{
|
||||
Fill.square(e.x + x, e.y + y, e.fout() * 2.3f + 0.5f);
|
||||
});
|
||||
|
||||
Draw.color();
|
||||
});
|
||||
|
||||
dropItem = new Effect(20f, e -> {
|
||||
@@ -562,35 +516,30 @@ public class Fx implements ContentList{
|
||||
Draw.color(Color.white, Color.lightGray, e.fin());
|
||||
Lines.stroke(e.fout() * 2f + 0.2f);
|
||||
Lines.circle(e.x, e.y, e.fin() * 28f);
|
||||
Draw.reset();
|
||||
});
|
||||
|
||||
bigShockwave = new Effect(10f, 80f, e -> {
|
||||
Draw.color(Color.white, Color.lightGray, e.fin());
|
||||
Lines.stroke(e.fout() * 3f);
|
||||
Lines.circle(e.x, e.y, e.fin() * 50f);
|
||||
Draw.reset();
|
||||
});
|
||||
|
||||
nuclearShockwave = new Effect(10f, 200f, e -> {
|
||||
Draw.color(Color.white, Color.lightGray, e.fin());
|
||||
Lines.stroke(e.fout() * 3f + 0.2f);
|
||||
Lines.circle(e.x, e.y, e.fin() * 140f);
|
||||
Draw.reset();
|
||||
});
|
||||
|
||||
impactShockwave = new Effect(13f, 300f, e -> {
|
||||
Draw.color(Pal.lighterOrange, Color.lightGray, e.fin());
|
||||
Lines.stroke(e.fout() * 4f + 0.2f);
|
||||
Lines.circle(e.x, e.y, e.fin() * 200f);
|
||||
Draw.reset();
|
||||
});
|
||||
|
||||
spawnShockwave = new Effect(20f, 400f, e -> {
|
||||
Draw.color(Color.white, Color.lightGray, e.fin());
|
||||
Lines.stroke(e.fout() * 3f + 0.5f);
|
||||
Lines.circle(e.x, e.y, e.fin() * (e.rotation + 50f));
|
||||
Draw.reset();
|
||||
});
|
||||
|
||||
explosion = new Effect(30, e -> {
|
||||
@@ -613,7 +562,6 @@ public class Fx implements ContentList{
|
||||
Lines.lineAngle(e.x + x, e.y + y, Mathf.angle(x, y), 1f + e.fout() * 3f);
|
||||
});
|
||||
|
||||
Draw.reset();
|
||||
});
|
||||
|
||||
dynamicExplosion = new Effect(30, e -> {
|
||||
@@ -638,7 +586,6 @@ public class Fx implements ContentList{
|
||||
Lines.lineAngle(e.x + x, e.y + y, Mathf.angle(x, y), 1f + out * 4 * (3f + intensity));
|
||||
});
|
||||
|
||||
Draw.reset();
|
||||
});
|
||||
|
||||
blockExplosion = new Effect(30, e -> {
|
||||
@@ -661,7 +608,6 @@ public class Fx implements ContentList{
|
||||
Lines.lineAngle(e.x + x, e.y + y, Mathf.angle(x, y), 1f + e.fout() * 3f);
|
||||
});
|
||||
|
||||
Draw.reset();
|
||||
});
|
||||
|
||||
blockExplosionSmoke = new Effect(30, e -> {
|
||||
@@ -672,7 +618,6 @@ public class Fx implements ContentList{
|
||||
Fill.circle(e.x + x / 2f, e.y + y / 2f, e.fout() * 1f);
|
||||
});
|
||||
|
||||
Draw.reset();
|
||||
});
|
||||
|
||||
|
||||
@@ -681,7 +626,6 @@ public class Fx implements ContentList{
|
||||
float w = 1f + 5 * e.fout();
|
||||
Drawf.tri(e.x, e.y, w, 15f * e.fout(), e.rotation);
|
||||
Drawf.tri(e.x, e.y, w, 3f * e.fout(), e.rotation + 180f);
|
||||
Draw.reset();
|
||||
});
|
||||
|
||||
shootHeal = new Effect(8, e -> {
|
||||
@@ -689,7 +633,6 @@ public class Fx implements ContentList{
|
||||
float w = 1f + 5 * e.fout();
|
||||
Drawf.tri(e.x, e.y, w, 17f * e.fout(), e.rotation);
|
||||
Drawf.tri(e.x, e.y, w, 4f * e.fout(), e.rotation + 180f);
|
||||
Draw.reset();
|
||||
});
|
||||
|
||||
shootSmallSmoke = new Effect(20f, e -> {
|
||||
@@ -699,7 +642,6 @@ public class Fx implements ContentList{
|
||||
Fill.circle(e.x + x, e.y + y, e.fout() * 1.5f);
|
||||
});
|
||||
|
||||
Draw.reset();
|
||||
});
|
||||
|
||||
shootBig = new Effect(9, e -> {
|
||||
@@ -707,7 +649,6 @@ public class Fx implements ContentList{
|
||||
float w = 1.2f + 7 * e.fout();
|
||||
Drawf.tri(e.x, e.y, w, 25f * e.fout(), e.rotation);
|
||||
Drawf.tri(e.x, e.y, w, 4f * e.fout(), e.rotation + 180f);
|
||||
Draw.reset();
|
||||
});
|
||||
|
||||
shootBig2 = new Effect(10, e -> {
|
||||
@@ -715,7 +656,6 @@ public class Fx implements ContentList{
|
||||
float w = 1.2f + 8 * e.fout();
|
||||
Drawf.tri(e.x, e.y, w, 29f * e.fout(), e.rotation);
|
||||
Drawf.tri(e.x, e.y, w, 5f * e.fout(), e.rotation + 180f);
|
||||
Draw.reset();
|
||||
});
|
||||
|
||||
shootBigSmoke = new Effect(17f, e -> {
|
||||
@@ -725,7 +665,6 @@ public class Fx implements ContentList{
|
||||
Fill.circle(e.x + x, e.y + y, e.fout() * 2f + 0.2f);
|
||||
});
|
||||
|
||||
Draw.reset();
|
||||
});
|
||||
|
||||
shootBigSmoke2 = new Effect(18f, e -> {
|
||||
@@ -735,7 +674,6 @@ public class Fx implements ContentList{
|
||||
Fill.circle(e.x + x, e.y + y, e.fout() * 2.4f + 0.2f);
|
||||
});
|
||||
|
||||
Draw.reset();
|
||||
});
|
||||
|
||||
shootSmallFlame = new Effect(32f, e -> {
|
||||
@@ -745,7 +683,6 @@ public class Fx implements ContentList{
|
||||
Fill.circle(e.x + x, e.y + y, 0.65f + e.fout() * 1.5f);
|
||||
});
|
||||
|
||||
Draw.reset();
|
||||
});
|
||||
|
||||
shootPyraFlame = new Effect(33f, e -> {
|
||||
@@ -755,7 +692,6 @@ public class Fx implements ContentList{
|
||||
Fill.circle(e.x + x, e.y + y, 0.65f + e.fout() * 1.6f);
|
||||
});
|
||||
|
||||
Draw.reset();
|
||||
});
|
||||
|
||||
shootLiquid = new Effect(40f, e -> {
|
||||
@@ -765,7 +701,6 @@ public class Fx implements ContentList{
|
||||
Fill.circle(e.x + x, e.y + y, 0.5f + e.fout() * 2.5f);
|
||||
});
|
||||
|
||||
Draw.reset();
|
||||
});
|
||||
|
||||
shellEjectSmall = new GroundEffect(30f, 400f, e -> {
|
||||
@@ -780,7 +715,6 @@ public class Fx implements ContentList{
|
||||
e.y + Angles.trnsy(lr, len) + Mathf.randomSeedRange(e.id + i + 8, 3f * e.fin()),
|
||||
1f, 2f, rot + e.fin() * 50f * i);
|
||||
|
||||
Draw.color();
|
||||
});
|
||||
|
||||
shellEjectMedium = new GroundEffect(34f, 400f, e -> {
|
||||
@@ -804,7 +738,6 @@ public class Fx implements ContentList{
|
||||
});
|
||||
}
|
||||
|
||||
Draw.color();
|
||||
});
|
||||
|
||||
shellEjectBig = new GroundEffect(22f, 400f, e -> {
|
||||
@@ -829,7 +762,6 @@ public class Fx implements ContentList{
|
||||
});
|
||||
}
|
||||
|
||||
Draw.color();
|
||||
});
|
||||
|
||||
lancerLaserShoot = new Effect(21f, e -> {
|
||||
@@ -839,7 +771,6 @@ public class Fx implements ContentList{
|
||||
Drawf.tri(e.x, e.y, 4f * e.fout(), 29f, e.rotation + 90f * i);
|
||||
}
|
||||
|
||||
Draw.reset();
|
||||
});
|
||||
|
||||
lancerLaserShootSmoke = new Effect(26f, e -> {
|
||||
@@ -849,7 +780,6 @@ public class Fx implements ContentList{
|
||||
Lines.lineAngle(e.x + x, e.y + y, Mathf.angle(x, y), e.fout() * 9f);
|
||||
});
|
||||
|
||||
Draw.reset();
|
||||
});
|
||||
|
||||
lancerLaserCharge = new Effect(38f, e -> {
|
||||
@@ -859,7 +789,6 @@ public class Fx implements ContentList{
|
||||
Lines.lineAngle(e.x + x, e.y + y, Mathf.angle(x, y), e.fslope() * 3f + 1f);
|
||||
});
|
||||
|
||||
Draw.reset();
|
||||
});
|
||||
|
||||
lancerLaserChargeBegin = new Effect(71f, e -> {
|
||||
@@ -877,7 +806,6 @@ public class Fx implements ContentList{
|
||||
Drawf.tri(e.x + x, e.y + y, e.fslope() * 3f + 1, e.fslope() * 3f + 1, Mathf.angle(x, y));
|
||||
});
|
||||
|
||||
Draw.reset();
|
||||
});
|
||||
|
||||
lightningShoot = new Effect(12f, e -> {
|
||||
@@ -888,7 +816,6 @@ public class Fx implements ContentList{
|
||||
Lines.lineAngle(e.x + x, e.y + y, Mathf.angle(x, y), e.fin() * 5f + 2f);
|
||||
});
|
||||
|
||||
Draw.reset();
|
||||
});
|
||||
|
||||
|
||||
@@ -897,7 +824,6 @@ public class Fx implements ContentList{
|
||||
float size = 1f + e.fout() * 5f;
|
||||
Draw.color(Color.lightGray, Color.gray, e.fin());
|
||||
Draw.rect("circle", e.x + x, e.y + y, size, size);
|
||||
Draw.reset();
|
||||
});
|
||||
});
|
||||
nuclearsmoke = new Effect(40, e -> {
|
||||
@@ -905,7 +831,6 @@ public class Fx implements ContentList{
|
||||
float size = e.fslope() * 4f;
|
||||
Draw.color(Color.lightGray, Color.gray, e.fin());
|
||||
Draw.rect("circle", e.x + x, e.y + y, size, size);
|
||||
Draw.reset();
|
||||
});
|
||||
});
|
||||
nuclearcloud = new Effect(90, 200f, e -> {
|
||||
@@ -913,7 +838,6 @@ public class Fx implements ContentList{
|
||||
float size = e.fout() * 14f;
|
||||
Draw.color(Color.lime, Color.gray, e.fin());
|
||||
Draw.rect("circle", e.x + x, e.y + y, size, size);
|
||||
Draw.reset();
|
||||
});
|
||||
});
|
||||
impactsmoke = new Effect(60, e -> {
|
||||
@@ -921,7 +845,6 @@ public class Fx implements ContentList{
|
||||
float size = e.fslope() * 4f;
|
||||
Draw.color(Color.lightGray, Color.gray, e.fin());
|
||||
Draw.rect("circle", e.x + x, e.y + y, size, size);
|
||||
Draw.reset();
|
||||
});
|
||||
});
|
||||
impactcloud = new Effect(140, 400f, e -> {
|
||||
@@ -929,7 +852,6 @@ public class Fx implements ContentList{
|
||||
float size = e.fout() * 15f;
|
||||
Draw.color(Pal.lighterOrange, Color.lightGray, e.fin());
|
||||
Draw.rect("circle", e.x + x, e.y + y, size, size);
|
||||
Draw.reset();
|
||||
});
|
||||
});
|
||||
redgeneratespark = new Effect(18, e -> {
|
||||
@@ -937,7 +859,6 @@ public class Fx implements ContentList{
|
||||
float len = e.fout() * 4f;
|
||||
Draw.color(Pal.redSpark, Color.gray, e.fin());
|
||||
Draw.rect("circle", e.x + x, e.y + y, len, len);
|
||||
Draw.reset();
|
||||
});
|
||||
});
|
||||
generatespark = new Effect(18, e -> {
|
||||
@@ -945,7 +866,6 @@ public class Fx implements ContentList{
|
||||
float len = e.fout() * 4f;
|
||||
Draw.color(Pal.orangeSpark, Color.gray, e.fin());
|
||||
Draw.rect("circle", e.x + x, e.y + y, len, len);
|
||||
Draw.reset();
|
||||
});
|
||||
});
|
||||
fuelburn = new Effect(23, e -> {
|
||||
@@ -953,70 +873,60 @@ public class Fx implements ContentList{
|
||||
float len = e.fout() * 4f;
|
||||
Draw.color(Color.lightGray, Color.gray, e.fin());
|
||||
Draw.rect("circle", e.x + x, e.y + y, len, len);
|
||||
Draw.reset();
|
||||
});
|
||||
});
|
||||
plasticburn = new Effect(40, e -> {
|
||||
Angles.randLenVectors(e.id, 5, 3f + e.fin() * 5f, (x, y) -> {
|
||||
Draw.color(Color.valueOf("e9ead3"), Color.gray, e.fin());
|
||||
Fill.circle(e.x + x, e.y + y, e.fout() * 1f);
|
||||
Draw.reset();
|
||||
});
|
||||
});
|
||||
pulverize = new Effect(40, e -> {
|
||||
Angles.randLenVectors(e.id, 5, 3f + e.fin() * 8f, (x, y) -> {
|
||||
Draw.color(Pal.stoneGray);
|
||||
Fill.square(e.x + x, e.y + y, e.fout() * 2f + 0.5f, 45);
|
||||
Draw.reset();
|
||||
});
|
||||
});
|
||||
pulverizeRed = new Effect(40, e -> {
|
||||
Angles.randLenVectors(e.id, 5, 3f + e.fin() * 8f, (x, y) -> {
|
||||
Draw.color(Pal.redDust, Pal.stoneGray, e.fin());
|
||||
Fill.square(e.x + x, e.y + y, e.fout() * 2f + 0.5f, 45);
|
||||
Draw.reset();
|
||||
});
|
||||
});
|
||||
pulverizeRedder = new Effect(40, e -> {
|
||||
Angles.randLenVectors(e.id, 5, 3f + e.fin() * 9f, (x, y) -> {
|
||||
Draw.color(Pal.redderDust, Pal.stoneGray, e.fin());
|
||||
Fill.square(e.x + x, e.y + y, e.fout() * 2.5f + 0.5f, 45);
|
||||
Draw.reset();
|
||||
});
|
||||
});
|
||||
pulverizeSmall = new Effect(30, e -> {
|
||||
Angles.randLenVectors(e.id, 3, e.fin() * 5f, (x, y) -> {
|
||||
Draw.color(Pal.stoneGray);
|
||||
Fill.square(e.x + x, e.y + y, e.fout() * 1f + 0.5f, 45);
|
||||
Draw.reset();
|
||||
});
|
||||
});
|
||||
pulverizeMedium = new Effect(30, e -> {
|
||||
Angles.randLenVectors(e.id, 5, 3f + e.fin() * 8f, (x, y) -> {
|
||||
Draw.color(Pal.stoneGray);
|
||||
Fill.square(e.x + x, e.y + y, e.fout() * 1f + 0.5f, 45);
|
||||
Draw.reset();
|
||||
});
|
||||
});
|
||||
producesmoke = new Effect(12, e -> {
|
||||
Angles.randLenVectors(e.id, 8, 4f + e.fin() * 18f, (x, y) -> {
|
||||
Draw.color(Color.white, Pal.accent, e.fin());
|
||||
Fill.square(e.x + x, e.y + y, 1f + e.fout() * 3f, 45);
|
||||
Draw.reset();
|
||||
});
|
||||
});
|
||||
smeltsmoke = new Effect(15, e -> {
|
||||
Angles.randLenVectors(e.id, 6, 4f + e.fin() * 5f, (x, y) -> {
|
||||
Draw.color(Color.white, e.color, e.fin());
|
||||
Fill.square(e.x + x, e.y + y, 0.5f + e.fout() * 2f, 45);
|
||||
Draw.reset();
|
||||
});
|
||||
});
|
||||
formsmoke = new Effect(40, e -> {
|
||||
Angles.randLenVectors(e.id, 6, 5f + e.fin() * 8f, (x, y) -> {
|
||||
Draw.color(Pal.plasticSmoke, Color.lightGray, e.fin());
|
||||
Fill.square(e.x + x, e.y + y, 0.2f + e.fout() * 2f, 45);
|
||||
Draw.reset();
|
||||
});
|
||||
});
|
||||
blastsmoke = new Effect(26, e -> {
|
||||
@@ -1024,7 +934,6 @@ public class Fx implements ContentList{
|
||||
float size = 2f + e.fout() * 6f;
|
||||
Draw.color(Color.lightGray, Color.darkGray, e.fin());
|
||||
Draw.rect("circle", e.x + x, e.y + y, size, size);
|
||||
Draw.reset();
|
||||
});
|
||||
});
|
||||
lava = new Effect(18, e -> {
|
||||
@@ -1032,79 +941,66 @@ public class Fx implements ContentList{
|
||||
float size = e.fslope() * 4f;
|
||||
Draw.color(Color.orange, Color.gray, e.fin());
|
||||
Draw.rect("circle", e.x + x, e.y + y, size, size);
|
||||
Draw.reset();
|
||||
});
|
||||
});
|
||||
dooropen = new Effect(10, e -> {
|
||||
Lines.stroke(e.fout() * 1.6f);
|
||||
Lines.square(e.x, e.y, tilesize / 2f + e.fin() * 2f);
|
||||
Draw.reset();
|
||||
});
|
||||
doorclose = new Effect(10, e -> {
|
||||
Lines.stroke(e.fout() * 1.6f);
|
||||
Lines.square(e.x, e.y, tilesize / 2f + e.fout() * 2f);
|
||||
Draw.reset();
|
||||
});
|
||||
dooropenlarge = new Effect(10, e -> {
|
||||
Lines.stroke(e.fout() * 1.6f);
|
||||
Lines.square(e.x, e.y, tilesize + e.fin() * 2f);
|
||||
Draw.reset();
|
||||
});
|
||||
doorcloselarge = new Effect(10, e -> {
|
||||
Lines.stroke(e.fout() * 1.6f);
|
||||
Lines.square(e.x, e.y, tilesize + e.fout() * 2f);
|
||||
Draw.reset();
|
||||
});
|
||||
purify = new Effect(10, e -> {
|
||||
Draw.color(Color.royal, Color.gray, e.fin());
|
||||
Lines.stroke(2f);
|
||||
Lines.spikes(e.x, e.y, e.fin() * 4f, 2, 6);
|
||||
Draw.reset();
|
||||
});
|
||||
purifyoil = new Effect(10, e -> {
|
||||
Draw.color(Color.black, Color.gray, e.fin());
|
||||
Lines.stroke(2f);
|
||||
Lines.spikes(e.x, e.y, e.fin() * 4f, 2, 6);
|
||||
Draw.reset();
|
||||
});
|
||||
purifystone = new Effect(10, e -> {
|
||||
Draw.color(Color.orange, Color.gray, e.fin());
|
||||
Lines.stroke(2f);
|
||||
Lines.spikes(e.x, e.y, e.fin() * 4f, 2, 6);
|
||||
Draw.reset();
|
||||
});
|
||||
generate = new Effect(11, e -> {
|
||||
Draw.color(Color.orange, Color.yellow, e.fin());
|
||||
Lines.stroke(1f);
|
||||
Lines.spikes(e.x, e.y, e.fin() * 5f, 2, 8);
|
||||
Draw.reset();
|
||||
});
|
||||
mine = new Effect(20, e -> {
|
||||
Angles.randLenVectors(e.id, 6, 3f + e.fin() * 6f, (x, y) -> {
|
||||
Draw.color(e.color, Color.lightGray, e.fin());
|
||||
Fill.square(e.x + x, e.y + y, e.fout() * 2f, 45);
|
||||
Draw.reset();
|
||||
});
|
||||
});
|
||||
mineBig = new Effect(30, e -> {
|
||||
Angles.randLenVectors(e.id, 6, 4f + e.fin() * 8f, (x, y) -> {
|
||||
Draw.color(e.color, Color.lightGray, e.fin());
|
||||
Fill.square(e.x + x, e.y + y, e.fout() * 2f + 0.2f, 45);
|
||||
Draw.reset();
|
||||
});
|
||||
});
|
||||
mineHuge = new Effect(40, e -> {
|
||||
Angles.randLenVectors(e.id, 8, 5f + e.fin() * 10f, (x, y) -> {
|
||||
Draw.color(e.color, Color.lightGray, e.fin());
|
||||
Fill.square(e.x + x, e.y + y, e.fout() * 2f + 0.5f, 45);
|
||||
Draw.reset();
|
||||
});
|
||||
});
|
||||
smelt = new Effect(20, e -> {
|
||||
Angles.randLenVectors(e.id, 6, 2f + e.fin() * 5f, (x, y) -> {
|
||||
Draw.color(Color.white, e.color, e.fin());
|
||||
Fill.square(e.x + x, e.y + y, 0.5f + e.fout() * 2f, 45);
|
||||
Draw.reset();
|
||||
});
|
||||
});
|
||||
teleportActivate = new Effect(50, e -> {
|
||||
@@ -1121,7 +1017,6 @@ public class Fx implements ContentList{
|
||||
Lines.lineAngle(e.x + x, e.y + y, Mathf.angle(x, y), e.fin() * 4f + 1f);
|
||||
});
|
||||
|
||||
Draw.reset();
|
||||
});
|
||||
teleport = new Effect(60, e -> {
|
||||
Draw.color(e.color);
|
||||
@@ -1132,7 +1027,6 @@ public class Fx implements ContentList{
|
||||
Lines.lineAngle(e.x + x, e.y + y, Mathf.angle(x, y), e.fin() * 4f + 1f);
|
||||
});
|
||||
|
||||
Draw.reset();
|
||||
});
|
||||
teleportOut = new Effect(20, e -> {
|
||||
Draw.color(e.color);
|
||||
@@ -1143,13 +1037,11 @@ public class Fx implements ContentList{
|
||||
Lines.lineAngle(e.x + x, e.y + y, Mathf.angle(x, y), e.fslope() * 4f + 1f);
|
||||
});
|
||||
|
||||
Draw.reset();
|
||||
});
|
||||
ripple = new GroundEffect(false, 30, e -> {
|
||||
Draw.color(Tmp.c1.set(e.color).mul(1.2f));
|
||||
Lines.stroke(e.fout() + 0.4f);
|
||||
Lines.circle(e.x, e.y, 2f + e.fin() * 4f);
|
||||
Draw.reset();
|
||||
});
|
||||
|
||||
bubble = new Effect(20, e -> {
|
||||
@@ -1158,56 +1050,47 @@ public class Fx implements ContentList{
|
||||
Angles.randLenVectors(e.id, 2, 8f, (x, y) -> {
|
||||
Lines.circle(e.x + x, e.y + y, 1f + e.fin() * 3f);
|
||||
});
|
||||
Draw.reset();
|
||||
});
|
||||
|
||||
launch = new Effect(28, e -> {
|
||||
Draw.color(Pal.command);
|
||||
Lines.stroke(e.fout() * 2f);
|
||||
Lines.circle(e.x, e.y, 4f + e.finpow() * 120f);
|
||||
Draw.color();
|
||||
});
|
||||
|
||||
healWaveMend = new Effect(40, e -> {
|
||||
Draw.color(e.color);
|
||||
Lines.stroke(e.fout() * 2f);
|
||||
Lines.circle(e.x, e.y, e.finpow() * e.rotation);
|
||||
Draw.color();
|
||||
});
|
||||
|
||||
overdriveWave = new Effect(50, e -> {
|
||||
Draw.color(e.color);
|
||||
Lines.stroke(e.fout() * 1f);
|
||||
Lines.circle(e.x, e.y, e.finpow() * e.rotation);
|
||||
Draw.color();
|
||||
});
|
||||
|
||||
healBlock = new Effect(20, e -> {
|
||||
Draw.color(Pal.heal);
|
||||
Lines.stroke(2f * e.fout() + 0.5f);
|
||||
Lines.square(e.x, e.y, 1f + (e.fin() * e.rotation * tilesize / 2f - 1f));
|
||||
Draw.color();
|
||||
});
|
||||
|
||||
healBlockFull = new Effect(20, e -> {
|
||||
Draw.color(e.color);
|
||||
Draw.alpha(e.fout());
|
||||
Fill.square(e.x, e.y, e.rotation * tilesize / 2f);
|
||||
Draw.color();
|
||||
});
|
||||
|
||||
overdriveBlockFull = new Effect(60, e -> {
|
||||
Draw.color(e.color);
|
||||
Draw.alpha(e.fslope() * 0.4f);
|
||||
Fill.square(e.x, e.y, e.rotation * tilesize);
|
||||
Draw.color();
|
||||
});
|
||||
|
||||
shieldBreak = new Effect(40, e -> {
|
||||
Draw.color(Pal.accent);
|
||||
Lines.stroke(3f * e.fout());
|
||||
Lines.poly(e.x, e.y, 6, e.rotation + e.fin(), 90);
|
||||
Draw.reset();
|
||||
});
|
||||
|
||||
coreLand = new Effect(120f, e -> {
|
||||
|
||||
@@ -15,61 +15,71 @@ public class StatusEffects implements ContentList{
|
||||
@Override
|
||||
public void load(){
|
||||
|
||||
none = new StatusEffect();
|
||||
none = new StatusEffect("none");
|
||||
|
||||
burning = new StatusEffect(){{
|
||||
burning = new StatusEffect("burning"){{
|
||||
damage = 0.06f;
|
||||
effect = Fx.burning;
|
||||
|
||||
opposite(() -> wet, () -> freezing);
|
||||
trans(() -> tarred, ((unit, time, newTime, result) -> {
|
||||
unit.damage(1f);
|
||||
Effects.effect(Fx.burning, unit.x + Mathf.range(unit.getSize() / 2f), unit.y + Mathf.range(unit.getSize() / 2f));
|
||||
result.set(this, Math.min(time + newTime, 300f));
|
||||
}));
|
||||
init(() -> {
|
||||
opposite(wet,freezing);
|
||||
trans(tarred, ((unit, time, newTime, result) -> {
|
||||
unit.damage(1f);
|
||||
Effects.effect(Fx.burning, unit.x + Mathf.range(unit.getSize() / 2f), unit.y + Mathf.range(unit.getSize() / 2f));
|
||||
result.set(this, Math.min(time + newTime, 300f));
|
||||
}));
|
||||
});
|
||||
}};
|
||||
|
||||
freezing = new StatusEffect(){{
|
||||
freezing = new StatusEffect("freezing"){{
|
||||
speedMultiplier = 0.6f;
|
||||
armorMultiplier = 0.8f;
|
||||
effect = Fx.freezing;
|
||||
|
||||
opposite(() -> melting, () -> burning);
|
||||
init(() -> {
|
||||
opposite(melting, burning);
|
||||
});
|
||||
}};
|
||||
|
||||
wet = new StatusEffect(){{
|
||||
wet = new StatusEffect("wet"){{
|
||||
speedMultiplier = 0.9f;
|
||||
effect = Fx.wet;
|
||||
|
||||
trans(() -> shocked, ((unit, time, newTime, result) -> {
|
||||
unit.damage(20f);
|
||||
if(unit.getTeam() == waveTeam){
|
||||
Events.fire(Trigger.shock);
|
||||
}
|
||||
result.set(this, time);
|
||||
}));
|
||||
opposite(() -> burning);
|
||||
init(() -> {
|
||||
trans(shocked, ((unit, time, newTime, result) -> {
|
||||
unit.damage(20f);
|
||||
if(unit.getTeam() == waveTeam){
|
||||
Events.fire(Trigger.shock);
|
||||
}
|
||||
result.set(this, time);
|
||||
}));
|
||||
opposite(burning);
|
||||
});
|
||||
}};
|
||||
|
||||
melting = new StatusEffect(){{
|
||||
melting = new StatusEffect("melting"){{
|
||||
speedMultiplier = 0.8f;
|
||||
armorMultiplier = 0.8f;
|
||||
damage = 0.3f;
|
||||
effect = Fx.melting;
|
||||
|
||||
trans(() -> tarred, ((unit, time, newTime, result) -> result.set(this, Math.min(time + newTime / 2f, 140f))));
|
||||
opposite(() -> wet, () -> freezing);
|
||||
init(() -> {
|
||||
trans(tarred, ((unit, time, newTime, result) -> result.set(this, Math.min(time + newTime / 2f, 140f))));
|
||||
opposite(wet, freezing);
|
||||
});
|
||||
}};
|
||||
|
||||
tarred = new StatusEffect(){{
|
||||
tarred = new StatusEffect("tarred"){{
|
||||
speedMultiplier = 0.6f;
|
||||
effect = Fx.oily;
|
||||
|
||||
trans(() -> melting, ((unit, time, newTime, result) -> result.set(burning, newTime + time)));
|
||||
trans(() -> burning, ((unit, time, newTime, result) -> result.set(burning, newTime + time)));
|
||||
init(() -> {
|
||||
trans(melting, ((unit, time, newTime, result) -> result.set(burning, newTime + time)));
|
||||
trans(burning, ((unit, time, newTime, result) -> result.set(burning, newTime + time)));
|
||||
});
|
||||
}};
|
||||
|
||||
overdrive = new StatusEffect(){{
|
||||
overdrive = new StatusEffect("overdrive"){{
|
||||
armorMultiplier = 0.95f;
|
||||
speedMultiplier = 1.15f;
|
||||
damageMultiplier = 1.4f;
|
||||
@@ -77,20 +87,20 @@ public class StatusEffects implements ContentList{
|
||||
effect = Fx.overdriven;
|
||||
}};
|
||||
|
||||
shielded = new StatusEffect(){{
|
||||
shielded = new StatusEffect("shielded"){{
|
||||
armorMultiplier = 3f;
|
||||
}};
|
||||
|
||||
boss = new StatusEffect(){{
|
||||
boss = new StatusEffect("boss"){{
|
||||
armorMultiplier = 3f;
|
||||
damageMultiplier = 3f;
|
||||
speedMultiplier = 1.1f;
|
||||
}};
|
||||
|
||||
shocked = new StatusEffect();
|
||||
shocked = new StatusEffect("shocked");
|
||||
|
||||
//no effects, just small amounts of damage.
|
||||
corroded = new StatusEffect(){{
|
||||
corroded = new StatusEffect("corroded"){{
|
||||
damage = 0.1f;
|
||||
}};
|
||||
}
|
||||
|
||||
@@ -3,9 +3,11 @@ package io.anuke.mindustry.core;
|
||||
import io.anuke.arc.collection.*;
|
||||
import io.anuke.arc.func.*;
|
||||
import io.anuke.arc.graphics.*;
|
||||
import io.anuke.arc.util.ArcAnnotate.*;
|
||||
import io.anuke.arc.util.*;
|
||||
import io.anuke.mindustry.content.*;
|
||||
import io.anuke.mindustry.ctype.*;
|
||||
import io.anuke.mindustry.ctype.ContentType;
|
||||
import io.anuke.mindustry.entities.bullet.*;
|
||||
import io.anuke.mindustry.mod.Mods.*;
|
||||
import io.anuke.mindustry.type.*;
|
||||
@@ -20,10 +22,11 @@ import static io.anuke.mindustry.Vars.mods;
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public class ContentLoader{
|
||||
private boolean loaded = false;
|
||||
private ObjectMap<String, MappableContent>[] contentNameMap = new ObjectMap[ContentType.values().length];
|
||||
private Array<Content>[] contentMap = new Array[ContentType.values().length];
|
||||
private MappableContent[][] temporaryMapper;
|
||||
private @Nullable LoadedMod currentMod;
|
||||
private @Nullable Content lastAdded;
|
||||
private ObjectSet<Cons<Content>> initialization = new ObjectSet<>();
|
||||
private ContentList[] content = {
|
||||
new Fx(),
|
||||
@@ -45,35 +48,40 @@ public class ContentLoader{
|
||||
new LegacyColorMapper(),
|
||||
};
|
||||
|
||||
public ContentLoader(){
|
||||
clear();
|
||||
}
|
||||
|
||||
/** Clears all initialized content.*/
|
||||
public void clear(){
|
||||
contentNameMap = new ObjectMap[ContentType.values().length];
|
||||
contentMap = new Array[ContentType.values().length];
|
||||
initialization = new ObjectSet<>();
|
||||
loaded = false;
|
||||
}
|
||||
|
||||
/** Creates all content types. */
|
||||
public void createContent(){
|
||||
if(loaded){
|
||||
Log.info("Content already loaded, skipping.");
|
||||
return;
|
||||
}
|
||||
|
||||
for(ContentType type : ContentType.values()){
|
||||
contentMap[type.ordinal()] = new Array<>();
|
||||
contentNameMap[type.ordinal()] = new ObjectMap<>();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** Creates all base types. */
|
||||
public void createBaseContent(){
|
||||
for(ContentList list : content){
|
||||
list.load();
|
||||
}
|
||||
}
|
||||
|
||||
/** Creates mod content, if applicable. */
|
||||
public void createModContent(){
|
||||
if(mods != null){
|
||||
mods.loadContent();
|
||||
}
|
||||
}
|
||||
|
||||
//check up ID mapping, make sure it's linear
|
||||
/** Logs content statistics.*/
|
||||
public void logContent(){
|
||||
//check up ID mapping, make sure it's linear (debug only)
|
||||
for(Array<Content> arr : contentMap){
|
||||
for(int i = 0; i < arr.size; i++){
|
||||
int id = arr.get(i).id;
|
||||
@@ -83,17 +91,12 @@ public class ContentLoader{
|
||||
}
|
||||
}
|
||||
|
||||
loaded = true;
|
||||
}
|
||||
|
||||
/** Logs content statistics.*/
|
||||
public void logContent(){
|
||||
Log.info("--- CONTENT INFO ---");
|
||||
Log.debug("--- CONTENT INFO ---");
|
||||
for(int k = 0; k < contentMap.length; k++){
|
||||
Log.info("[{0}]: loaded {1}", ContentType.values()[k].name(), contentMap[k].size);
|
||||
Log.debug("[{0}]: loaded {1}", ContentType.values()[k].name(), contentMap[k].size);
|
||||
}
|
||||
Log.info("Total content loaded: {0}", Array.with(ContentType.values()).mapInt(c -> contentMap[c.ordinal()].size).sum());
|
||||
Log.info("-------------------");
|
||||
Log.debug("Total content loaded: {0}", Array.with(ContentType.values()).mapInt(c -> contentMap[c.ordinal()].size).sum());
|
||||
Log.debug("-------------------");
|
||||
}
|
||||
|
||||
/** Calls Content#init() on everything. Use only after all modules have been created.*/
|
||||
@@ -115,8 +118,8 @@ public class ContentLoader{
|
||||
try{
|
||||
callable.get(content);
|
||||
}catch(Throwable e){
|
||||
if(content.mod != null){
|
||||
mods.handleError(new ModLoadException(content, e), content.mod);
|
||||
if(content.minfo.mod != null){
|
||||
mods.handleContentError(content, e);
|
||||
}else{
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
@@ -147,15 +150,41 @@ public class ContentLoader{
|
||||
//clear all content, currently not used
|
||||
}
|
||||
|
||||
public void handleContent(Content content){
|
||||
contentMap[content.getContentType().ordinal()].add(content);
|
||||
/** Get last piece of content created for error-handling purposes. */
|
||||
public @Nullable Content getLastAdded(){
|
||||
return lastAdded;
|
||||
}
|
||||
|
||||
/** Remove last content added in case of an exception. */
|
||||
public void removeLast(){
|
||||
if(lastAdded != null && contentMap[lastAdded.getContentType().ordinal()].peek() == lastAdded){
|
||||
contentMap[lastAdded.getContentType().ordinal()].pop();
|
||||
if(lastAdded instanceof MappableContent){
|
||||
contentNameMap[lastAdded.getContentType().ordinal()].remove(((MappableContent)lastAdded).name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void handleContent(Content content){
|
||||
this.lastAdded = content;
|
||||
contentMap[content.getContentType().ordinal()].add(content);
|
||||
}
|
||||
|
||||
public void setCurrentMod(@Nullable LoadedMod mod){
|
||||
this.currentMod = mod;
|
||||
}
|
||||
|
||||
public String transformName(String name){
|
||||
return currentMod == null ? name : currentMod.name + "-" + name;
|
||||
}
|
||||
|
||||
public void handleMappableContent(MappableContent content){
|
||||
if(contentNameMap[content.getContentType().ordinal()].containsKey(content.name)){
|
||||
throw new IllegalArgumentException("Two content objects cannot have the same name! (issue: '" + content.name + "')");
|
||||
}
|
||||
if(currentMod != null){
|
||||
content.minfo.mod = currentMod;
|
||||
}
|
||||
contentNameMap[content.getContentType().ordinal()].put(content.name, content);
|
||||
}
|
||||
|
||||
|
||||
@@ -262,6 +262,7 @@ public class Control implements ApplicationListener, Loadable{
|
||||
}
|
||||
}
|
||||
state.set(State.playing);
|
||||
state.wavetime = state.rules.waveSpacing;
|
||||
control.saves.zoneSave();
|
||||
logic.play();
|
||||
Events.fire(Trigger.newGame);
|
||||
@@ -451,12 +452,12 @@ public class Control implements ApplicationListener, Loadable{
|
||||
platform.updateRPC();
|
||||
}
|
||||
|
||||
if(Core.input.keyTap(Binding.pause) && !scene.hasDialog() && !ui.restart.isShown() && (state.is(State.paused) || state.is(State.playing))){
|
||||
if(Core.input.keyTap(Binding.pause) && !scene.hasDialog() && !scene.hasKeyboard() && !ui.restart.isShown() && (state.is(State.paused) || state.is(State.playing))){
|
||||
state.set(state.is(State.playing) ? State.paused : State.playing);
|
||||
}
|
||||
|
||||
if(Core.input.keyTap(Binding.menu) && !ui.restart.isShown()){
|
||||
if(ui.chatfrag.chatOpen()){
|
||||
if(ui.chatfrag.shown()){
|
||||
ui.chatfrag.hide();
|
||||
}else if(!ui.paused.isShown() && !scene.hasDialog()){
|
||||
ui.paused.show();
|
||||
@@ -464,7 +465,7 @@ public class Control implements ApplicationListener, Loadable{
|
||||
}
|
||||
}
|
||||
|
||||
if(!mobile && Core.input.keyTap(Binding.screenshot) && !(scene.getKeyboardFocus() instanceof TextField) && !ui.chatfrag.chatOpen()){
|
||||
if(!mobile && Core.input.keyTap(Binding.screenshot) && !(scene.getKeyboardFocus() instanceof TextField) && !scene.hasKeyboard()){
|
||||
renderer.takeMapScreenshot();
|
||||
}
|
||||
|
||||
|
||||
@@ -7,16 +7,18 @@ import io.anuke.arc.files.*;
|
||||
|
||||
/** Handles files in a modded context. */
|
||||
public class FileTree implements FileHandleResolver{
|
||||
private ObjectMap<String, FileHandle> files = new ObjectMap<>();
|
||||
private ObjectMap<String, Fi> files = new ObjectMap<>();
|
||||
|
||||
public void addFile(String path, FileHandle f){
|
||||
public void addFile(String path, Fi f){
|
||||
files.put(path, f);
|
||||
}
|
||||
|
||||
/** Gets an asset file.*/
|
||||
public FileHandle get(String path){
|
||||
public Fi get(String path){
|
||||
if(files.containsKey(path)){
|
||||
return files.get(path);
|
||||
}else if(files.containsKey("/" + path)){
|
||||
return files.get("/" + path);
|
||||
}else{
|
||||
return Core.files.internal(path);
|
||||
}
|
||||
@@ -28,7 +30,7 @@ public class FileTree implements FileHandleResolver{
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileHandle resolve(String fileName){
|
||||
public Fi resolve(String fileName){
|
||||
return get(fileName);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,7 +52,7 @@ public class Logic implements ApplicationListener{
|
||||
|
||||
if(block instanceof BuildBlock){
|
||||
|
||||
BuildEntity entity = tile.entity();
|
||||
BuildEntity entity = tile.ent();
|
||||
|
||||
//update block to reflect the fact that something was being constructed
|
||||
if(entity.cblock != null && entity.cblock.synthetic()){
|
||||
|
||||
@@ -11,6 +11,7 @@ import io.anuke.arc.util.io.*;
|
||||
import io.anuke.arc.util.serialization.*;
|
||||
import io.anuke.mindustry.*;
|
||||
import io.anuke.mindustry.core.GameState.*;
|
||||
import io.anuke.mindustry.ctype.ContentType;
|
||||
import io.anuke.mindustry.entities.*;
|
||||
import io.anuke.mindustry.entities.traits.BuilderTrait.*;
|
||||
import io.anuke.mindustry.entities.traits.*;
|
||||
@@ -22,7 +23,6 @@ import io.anuke.mindustry.net.Administration.*;
|
||||
import io.anuke.mindustry.net.Net.*;
|
||||
import io.anuke.mindustry.net.*;
|
||||
import io.anuke.mindustry.net.Packets.*;
|
||||
import io.anuke.mindustry.type.*;
|
||||
import io.anuke.mindustry.type.TypeID;
|
||||
import io.anuke.mindustry.world.*;
|
||||
import io.anuke.mindustry.world.modules.*;
|
||||
@@ -342,6 +342,26 @@ public class NetClient implements ApplicationListener{
|
||||
}
|
||||
}
|
||||
|
||||
@Remote(variants = Variant.both, priority = PacketPriority.low, unreliable = true)
|
||||
public static void onBlockSnapshot(short amount, short dataLen, byte[] data){
|
||||
try{
|
||||
netClient.byteStream.setBytes(net.decompressSnapshot(data, dataLen));
|
||||
DataInputStream input = netClient.dataStream;
|
||||
|
||||
for(int i = 0; i < amount; i++){
|
||||
int pos = input.readInt();
|
||||
Tile tile = world.tile(pos);
|
||||
if(tile == null || tile.entity == null){
|
||||
Log.warn("Missing entity at {0}. Skipping block snapshot.", tile);
|
||||
break;
|
||||
}
|
||||
tile.entity.read(input, tile.entity.version());
|
||||
}
|
||||
}catch(Exception e){
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Remote(variants = Variant.one, priority = PacketPriority.low, unreliable = true)
|
||||
public static void onStateSnapshot(float waveTime, int wave, int enemies, short coreDataLen, byte[] coreData){
|
||||
try{
|
||||
@@ -471,7 +491,7 @@ public class NetClient implements ApplicationListener{
|
||||
player.pointerX, player.pointerY, player.rotation, player.baseRotation,
|
||||
player.velocity().x, player.velocity().y,
|
||||
player.getMineTile(),
|
||||
player.isBoosting, player.isShooting, ui.chatfrag.chatOpen(), player.isBuilding,
|
||||
player.isBoosting, player.isShooting, ui.chatfrag.shown(), player.isBuilding,
|
||||
requests,
|
||||
Core.camera.position.x, Core.camera.position.y,
|
||||
Core.camera.width * viewScale, Core.camera.height * viewScale);
|
||||
|
||||
@@ -30,8 +30,8 @@ import java.util.zip.*;
|
||||
import static io.anuke.mindustry.Vars.*;
|
||||
|
||||
public class NetServer implements ApplicationListener{
|
||||
public final static int maxSnapshotSize = 430;
|
||||
private final static float serverSyncTime = 12, kickDuration = 30 * 1000;
|
||||
private final static int maxSnapshotSize = 430, timerBlockSync = 0;
|
||||
private final static float serverSyncTime = 12, kickDuration = 30 * 1000, blockSyncTime = 60 * 10;
|
||||
private final static Vector2 vector = new Vector2();
|
||||
private final static Rectangle viewport = new Rectangle();
|
||||
/** If a player goes away of their server-side coordinates by this distance, they get teleported back. */
|
||||
@@ -41,6 +41,7 @@ public class NetServer implements ApplicationListener{
|
||||
public final CommandHandler clientCommands = new CommandHandler("/");
|
||||
|
||||
private boolean closing = false;
|
||||
private Interval timer = new Interval();
|
||||
|
||||
private ByteBuffer writeBuffer = ByteBuffer.allocate(127);
|
||||
private ByteBufferOutput outputBuffer = new ByteBufferOutput(writeBuffer);
|
||||
@@ -65,6 +66,10 @@ public class NetServer implements ApplicationListener{
|
||||
});
|
||||
|
||||
net.handleServer(ConnectPacket.class, (con, packet) -> {
|
||||
if(con.address.startsWith("steam:")){
|
||||
packet.uuid = con.address.substring("steam:".length());
|
||||
}
|
||||
|
||||
String uuid = packet.uuid;
|
||||
|
||||
if(admins.isIPBanned(con.address)) return;
|
||||
@@ -214,7 +219,7 @@ public class NetServer implements ApplicationListener{
|
||||
|
||||
@Override
|
||||
public void init(){
|
||||
mods.each(mod -> mod.registerClientCommands(clientCommands));
|
||||
mods.eachClass(mod -> mod.registerClientCommands(clientCommands));
|
||||
}
|
||||
|
||||
private void registerCommands(){
|
||||
@@ -612,7 +617,35 @@ public class NetServer implements ApplicationListener{
|
||||
}
|
||||
}
|
||||
|
||||
public void writeSnapshot(Player player) throws IOException{
|
||||
/** Sends a block snapshot to all players. */
|
||||
public void writeBlockSnapshots() throws IOException{
|
||||
syncStream.reset();
|
||||
|
||||
short sent = 0;
|
||||
for(TileEntity entity : tileGroup.all()){
|
||||
if(!entity.block.sync) continue;
|
||||
sent ++;
|
||||
|
||||
dataStream.writeInt(entity.tile.pos());
|
||||
entity.write(dataStream);
|
||||
|
||||
if(syncStream.size() > maxSnapshotSize){
|
||||
dataStream.close();
|
||||
byte[] stateBytes = syncStream.toByteArray();
|
||||
Call.onBlockSnapshot(sent, (short)stateBytes.length, net.compressSnapshot(stateBytes));
|
||||
sent = 0;
|
||||
syncStream.reset();
|
||||
}
|
||||
}
|
||||
|
||||
if(sent > 0){
|
||||
dataStream.close();
|
||||
byte[] stateBytes = syncStream.toByteArray();
|
||||
Call.onBlockSnapshot(sent, (short)stateBytes.length, net.compressSnapshot(stateBytes));
|
||||
}
|
||||
}
|
||||
|
||||
public void writeEntitySnapshot(Player player) throws IOException{
|
||||
syncStream.reset();
|
||||
ObjectSet<Tile> cores = state.teams.get(player.getTeam()).cores;
|
||||
|
||||
@@ -726,7 +759,6 @@ public class NetServer implements ApplicationListener{
|
||||
void sync(){
|
||||
|
||||
try{
|
||||
|
||||
//iterate through each player
|
||||
for(int i = 0; i < playerGroup.size(); i++){
|
||||
Player player = playerGroup.all().get(i);
|
||||
@@ -741,7 +773,11 @@ public class NetServer implements ApplicationListener{
|
||||
|
||||
if(!player.timer.get(Player.timerSync, serverSyncTime) || !connection.hasConnected) continue;
|
||||
|
||||
writeSnapshot(player);
|
||||
writeEntitySnapshot(player);
|
||||
}
|
||||
|
||||
if(playerGroup.size() > 0 && Core.settings.getBool("blocksync") && timer.get(timerBlockSync, blockSyncTime)){
|
||||
writeBlockSnapshots();
|
||||
}
|
||||
|
||||
}catch(IOException e){
|
||||
|
||||
@@ -8,10 +8,12 @@ import io.anuke.arc.func.*;
|
||||
import io.anuke.arc.math.*;
|
||||
import io.anuke.arc.scene.ui.*;
|
||||
import io.anuke.arc.util.serialization.*;
|
||||
import io.anuke.mindustry.mod.*;
|
||||
import io.anuke.mindustry.net.*;
|
||||
import io.anuke.mindustry.net.Net.*;
|
||||
import io.anuke.mindustry.type.*;
|
||||
import io.anuke.mindustry.ui.dialogs.*;
|
||||
import org.mozilla.javascript.*;
|
||||
|
||||
import static io.anuke.mindustry.Vars.mobile;
|
||||
|
||||
@@ -33,7 +35,7 @@ public interface Platform{
|
||||
default void viewListingID(String mapid){}
|
||||
|
||||
/** Steam: Return external workshop maps to be loaded.*/
|
||||
default Array<FileHandle> getWorkshopContent(Class<? extends Publishable> type){
|
||||
default Array<Fi> getWorkshopContent(Class<? extends Publishable> type){
|
||||
return new Array<>(0);
|
||||
}
|
||||
|
||||
@@ -42,7 +44,18 @@ public interface Platform{
|
||||
|
||||
/** Get the networking implementation.*/
|
||||
default NetProvider getNet(){
|
||||
return new ArcNetImpl();
|
||||
return new ArcNetProvider();
|
||||
}
|
||||
|
||||
/** Gets the scripting implementation. */
|
||||
default Scripts createScripts(){
|
||||
return new Scripts();
|
||||
}
|
||||
|
||||
default Context getScriptContext(){
|
||||
Context c = Context.enter();
|
||||
c.setOptimizationLevel(9);
|
||||
return c;
|
||||
}
|
||||
|
||||
/** Add a text input dialog that should show up after the field is tapped. */
|
||||
@@ -87,7 +100,7 @@ public interface Platform{
|
||||
}
|
||||
|
||||
/** Only used for iOS or android: open the share menu for a map or save. */
|
||||
default void shareFile(FileHandle file){
|
||||
default void shareFile(Fi file){
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -96,7 +109,7 @@ public interface Platform{
|
||||
* @param open Whether to open or save files
|
||||
* @param extension File extension to filter
|
||||
*/
|
||||
default void showFileChooser(boolean open, String extension, Cons<FileHandle> cons){
|
||||
default void showFileChooser(boolean open, String extension, Cons<Fi> cons){
|
||||
new FileChooser(open ? "$open" : "$save", file -> file.extension().toLowerCase().equals(extension), open, file -> {
|
||||
if(!open){
|
||||
cons.get(file.parent().child(file.nameWithoutExtension() + "." + extension));
|
||||
|
||||
@@ -456,7 +456,7 @@ public class Renderer implements ApplicationListener{
|
||||
buffer.end();
|
||||
Pixmap fullPixmap = new Pixmap(w, h, Pixmap.Format.RGBA8888);
|
||||
BufferUtils.copy(lines, 0, fullPixmap.getPixels(), lines.length);
|
||||
FileHandle file = screenshotDirectory.child("screenshot-" + Time.millis() + ".png");
|
||||
Fi file = screenshotDirectory.child("screenshot-" + Time.millis() + ".png");
|
||||
PixmapIO.writePNG(file, fullPixmap);
|
||||
fullPixmap.dispose();
|
||||
ui.showInfoFade(Core.bundle.format("screenshot", file.toString()));
|
||||
|
||||
@@ -42,6 +42,7 @@ public class UI implements ApplicationListener, Loadable{
|
||||
public MenuFragment menufrag;
|
||||
public HudFragment hudfrag;
|
||||
public ChatFragment chatfrag;
|
||||
public ScriptConsoleFragment scriptfrag;
|
||||
public PlayerListFragment listfrag;
|
||||
public LoadingFragment loadfrag;
|
||||
|
||||
@@ -137,7 +138,7 @@ public class UI implements ApplicationListener, Loadable{
|
||||
Core.assets.setLoader(FreeTypeFontGenerator.class, new FreeTypeFontGeneratorLoader(resolver));
|
||||
Core.assets.setLoader(BitmapFont.class, null, new FreetypeFontLoader(resolver){
|
||||
@Override
|
||||
public BitmapFont loadSync(AssetManager manager, String fileName, FileHandle file, FreeTypeFontLoaderParameter parameter){
|
||||
public BitmapFont loadSync(AssetManager manager, String fileName, Fi file, FreeTypeFontLoaderParameter parameter){
|
||||
if(fileName.equals("outline")){
|
||||
parameter.fontParameters.borderWidth = Scl.scl(2f);
|
||||
parameter.fontParameters.spaceX -= parameter.fontParameters.borderWidth;
|
||||
@@ -211,6 +212,7 @@ public class UI implements ApplicationListener, Loadable{
|
||||
chatfrag = new ChatFragment();
|
||||
listfrag = new PlayerListFragment();
|
||||
loadfrag = new LoadingFragment();
|
||||
scriptfrag = new ScriptConsoleFragment();
|
||||
|
||||
picker = new ColorPicker();
|
||||
editor = new MapEditorDialog();
|
||||
@@ -253,6 +255,7 @@ public class UI implements ApplicationListener, Loadable{
|
||||
menufrag.build(menuGroup);
|
||||
chatfrag.container().build(hudGroup);
|
||||
listfrag.build(hudGroup);
|
||||
scriptfrag.container().build(hudGroup);
|
||||
loadfrag.build(group);
|
||||
new FadeInFragment().build(group);
|
||||
}
|
||||
@@ -371,6 +374,37 @@ public class UI implements ApplicationListener, Loadable{
|
||||
}}.show();
|
||||
}
|
||||
|
||||
public void showExceptions(String text, String... messages){
|
||||
loadfrag.hide();
|
||||
new Dialog(""){{
|
||||
|
||||
setFillParent(true);
|
||||
cont.margin(15);
|
||||
cont.add("$error.title").colspan(2);
|
||||
cont.row();
|
||||
cont.addImage().width(300f).pad(2).colspan(2).height(4f).color(Color.scarlet);
|
||||
cont.row();
|
||||
cont.add(text).colspan(2).wrap().growX().center().get().setAlignment(Align.center);
|
||||
cont.row();
|
||||
|
||||
//cont.pane(p -> {
|
||||
for(int i = 0; i < messages.length; i += 2){
|
||||
String btext = messages[i];
|
||||
String details = messages[i + 1];
|
||||
Collapser col = new Collapser(base -> base.pane(t -> t.margin(14f).add(details).color(Color.lightGray).left()), true);
|
||||
|
||||
cont.add(btext).right();
|
||||
cont.addButton("$details", Styles.togglet, col::toggle).size(180f, 50f).checked(b -> !col.isCollapsed()).fillX().left();
|
||||
cont.row();
|
||||
cont.add(col).colspan(2).pad(2);
|
||||
cont.row();
|
||||
}
|
||||
//}).colspan(2);
|
||||
|
||||
cont.addButton("$ok", this::hide).size(300, 50).fillX().colspan(2);
|
||||
}}.show();
|
||||
}
|
||||
|
||||
public void showText(String titleText, String text){
|
||||
showText(titleText, text, Align.center);
|
||||
}
|
||||
|
||||
@@ -7,8 +7,6 @@ import io.anuke.arc.files.*;
|
||||
import io.anuke.arc.util.*;
|
||||
import io.anuke.arc.util.io.*;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
public class Version{
|
||||
/** Build type. 'official' for official releases; 'custom' or 'bleeding edge' are also used. */
|
||||
public static String type;
|
||||
@@ -26,29 +24,25 @@ public class Version{
|
||||
public static void init(){
|
||||
if(!enabled) return;
|
||||
|
||||
try{
|
||||
FileHandle file = OS.isAndroid || OS.isIos ? Core.files.internal("version.properties") : new FileHandle("version.properties", FileType.Internal);
|
||||
Fi file = OS.isAndroid || OS.isIos ? Core.files.internal("version.properties") : new Fi("version.properties", FileType.internal);
|
||||
|
||||
ObjectMap<String, String> map = new ObjectMap<>();
|
||||
PropertiesUtils.load(map, file.reader());
|
||||
ObjectMap<String, String> map = new ObjectMap<>();
|
||||
PropertiesUtils.load(map, file.reader());
|
||||
|
||||
type = map.get("type");
|
||||
number = Integer.parseInt(map.get("number", "4"));
|
||||
modifier = map.get("modifier");
|
||||
if(map.get("build").contains(".")){
|
||||
String[] split = map.get("build").split("\\.");
|
||||
try{
|
||||
build = Integer.parseInt(split[0]);
|
||||
revision = Integer.parseInt(split[1]);
|
||||
}catch(Throwable e){
|
||||
e.printStackTrace();
|
||||
build = -1;
|
||||
}
|
||||
}else{
|
||||
build = Strings.canParseInt(map.get("build")) ? Integer.parseInt(map.get("build")) : -1;
|
||||
type = map.get("type");
|
||||
number = Integer.parseInt(map.get("number", "4"));
|
||||
modifier = map.get("modifier");
|
||||
if(map.get("build").contains(".")){
|
||||
String[] split = map.get("build").split("\\.");
|
||||
try{
|
||||
build = Integer.parseInt(split[0]);
|
||||
revision = Integer.parseInt(split[1]);
|
||||
}catch(Throwable e){
|
||||
e.printStackTrace();
|
||||
build = -1;
|
||||
}
|
||||
}catch(IOException e){
|
||||
throw new RuntimeException(e);
|
||||
}else{
|
||||
build = Strings.canParseInt(map.get("build")) ? Integer.parseInt(map.get("build")) : -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,16 +4,14 @@ import io.anuke.arc.files.*;
|
||||
import io.anuke.arc.util.ArcAnnotate.*;
|
||||
import io.anuke.mindustry.*;
|
||||
import io.anuke.mindustry.mod.Mods.*;
|
||||
import io.anuke.mindustry.type.*;
|
||||
|
||||
|
||||
/** Base class for a content type that is loaded in {@link io.anuke.mindustry.core.ContentLoader}. */
|
||||
public abstract class Content implements Comparable<Content>{
|
||||
public final short id;
|
||||
/** The mod that loaded this piece of content. */
|
||||
public @Nullable LoadedMod mod;
|
||||
/** File that this content was loaded from. */
|
||||
public @Nullable FileHandle sourceFile;
|
||||
/** Info on which mod this content was loaded from. */
|
||||
public @NonNull ModContentInfo minfo = new ModContentInfo();
|
||||
|
||||
|
||||
public Content(){
|
||||
this.id = (short)Vars.content.getBy(getContentType()).size;
|
||||
@@ -37,6 +35,11 @@ public abstract class Content implements Comparable<Content>{
|
||||
public void load(){
|
||||
}
|
||||
|
||||
/** @return whether an error ocurred during mod loading. */
|
||||
public boolean hasErrored(){
|
||||
return minfo.error != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(Content c){
|
||||
return Integer.compare(id, c.id);
|
||||
@@ -46,4 +49,15 @@ public abstract class Content implements Comparable<Content>{
|
||||
public String toString(){
|
||||
return getContentType().name() + "#" + id;
|
||||
}
|
||||
|
||||
public static class ModContentInfo{
|
||||
/** The mod that loaded this piece of content. */
|
||||
public @Nullable LoadedMod mod;
|
||||
/** File that this content was loaded from. */
|
||||
public @Nullable Fi sourceFile;
|
||||
/** The error that occurred during loading, if applicable. Null if no error occurred. */
|
||||
public @Nullable String error;
|
||||
/** Base throwable that caused the error. */
|
||||
public @Nullable Throwable baseError;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package io.anuke.mindustry.type;
|
||||
package io.anuke.mindustry.ctype;
|
||||
|
||||
/** Do not rearrange, ever! */
|
||||
public enum ContentType{
|
||||
@@ -14,6 +14,7 @@ public enum ContentType{
|
||||
zone,
|
||||
loadout,
|
||||
typeid,
|
||||
error,
|
||||
planet;
|
||||
|
||||
public static final ContentType[] all = values();
|
||||
@@ -6,7 +6,7 @@ public abstract class MappableContent extends Content{
|
||||
public final String name;
|
||||
|
||||
public MappableContent(String name){
|
||||
this.name = name;
|
||||
this.name = Vars.content.transformName(name);
|
||||
Vars.content.handleMappableContent(this);
|
||||
}
|
||||
|
||||
|
||||
@@ -20,8 +20,8 @@ public abstract class UnlockableContent extends MappableContent{
|
||||
public UnlockableContent(String name){
|
||||
super(name);
|
||||
|
||||
this.localizedName = Core.bundle.get(getContentType() + "." + name + ".name", name);
|
||||
this.description = Core.bundle.getOrNull(getContentType() + "." + name + ".description");
|
||||
this.localizedName = Core.bundle.get(getContentType() + "." + this.name + ".name", this.name);
|
||||
this.description = Core.bundle.getOrNull(getContentType() + "." + this.name + ".description");
|
||||
}
|
||||
|
||||
/** Generate any special icons for this content. Called asynchronously.*/
|
||||
@@ -42,13 +42,6 @@ public abstract class UnlockableContent extends MappableContent{
|
||||
return cicons[icon.ordinal()];
|
||||
}
|
||||
|
||||
/** Returns the localized name of this content. */
|
||||
public String localizedName(){
|
||||
return localizedName;
|
||||
}
|
||||
|
||||
//public abstract TextureRegion getContentIcon();
|
||||
|
||||
/** This should show all necessary info about this content in the specified table. */
|
||||
public abstract void displayInfo(Table table);
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package io.anuke.mindustry.editor;
|
||||
|
||||
import io.anuke.arc.collection.StringMap;
|
||||
import io.anuke.arc.files.FileHandle;
|
||||
import io.anuke.arc.files.Fi;
|
||||
import io.anuke.arc.func.Cons;
|
||||
import io.anuke.arc.func.Boolf;
|
||||
import io.anuke.arc.graphics.Pixmap;
|
||||
@@ -107,7 +107,7 @@ public class MapEditor{
|
||||
}
|
||||
}
|
||||
|
||||
public Map createMap(FileHandle file){
|
||||
public Map createMap(Fi file){
|
||||
return new Map(file, width(), height(), new StringMap(tags), true);
|
||||
}
|
||||
|
||||
|
||||
@@ -133,7 +133,7 @@ public class MapEditorDialog extends Dialog implements Disposable{
|
||||
}else{
|
||||
ui.loadAnd(() -> {
|
||||
try{
|
||||
FileHandle result = Core.files.local(editor.getTags().get("name", "unknown") + "." + mapExtension);
|
||||
Fi result = Core.files.local(editor.getTags().get("name", "unknown") + "." + mapExtension);
|
||||
MapIO.writeMap(result, editor.createMap(result));
|
||||
platform.shareFile(result);
|
||||
}catch(Exception e){
|
||||
@@ -381,7 +381,7 @@ public class MapEditorDialog extends Dialog implements Disposable{
|
||||
editor.renderer().dispose();
|
||||
}
|
||||
|
||||
public void beginEditMap(FileHandle file){
|
||||
public void beginEditMap(Fi file){
|
||||
ui.loadAnd(() -> {
|
||||
try{
|
||||
shownWithMap = true;
|
||||
|
||||
@@ -12,6 +12,7 @@ import io.anuke.arc.scene.ui.layout.*;
|
||||
import io.anuke.arc.util.*;
|
||||
import io.anuke.mindustry.*;
|
||||
import io.anuke.mindustry.content.*;
|
||||
import io.anuke.mindustry.ctype.ContentType;
|
||||
import io.anuke.mindustry.game.*;
|
||||
import io.anuke.mindustry.gen.*;
|
||||
import io.anuke.mindustry.graphics.*;
|
||||
|
||||
@@ -38,7 +38,7 @@ public class Damage{
|
||||
}
|
||||
|
||||
for(int i = 0; i < Mathf.clamp(flammability / 4, 0, 30); i++){
|
||||
Time.run(i / 2f, () -> Call.createBullet(Bullets.fireball, x, y, Mathf.random(360f)));
|
||||
Time.run(i / 2f, () -> Call.createBullet(Bullets.fireball, Team.derelict, x, y, Mathf.random(360f), 1, 1));
|
||||
}
|
||||
|
||||
int waves = Mathf.clamp((int)(explosiveness / 4), 0, 30);
|
||||
|
||||
@@ -4,6 +4,7 @@ import io.anuke.arc.Core;
|
||||
import io.anuke.arc.collection.Array;
|
||||
import io.anuke.arc.func.Cons;
|
||||
import io.anuke.arc.graphics.Color;
|
||||
import io.anuke.arc.graphics.g2d.*;
|
||||
import io.anuke.arc.math.Mathf;
|
||||
import io.anuke.arc.math.geom.Position;
|
||||
import io.anuke.arc.util.pooling.Pools;
|
||||
@@ -36,6 +37,7 @@ public class Effects{
|
||||
public static void renderEffect(int id, Effect render, Color color, float life, float rotation, float x, float y, Object data){
|
||||
container.set(id, color, life, render.lifetime, rotation, x, y, data);
|
||||
render.draw.render(container);
|
||||
Draw.reset();
|
||||
}
|
||||
|
||||
public static Effect getEffect(int id){
|
||||
|
||||
@@ -4,6 +4,7 @@ import io.anuke.arc.audio.*;
|
||||
import io.anuke.arc.math.*;
|
||||
import io.anuke.mindustry.content.*;
|
||||
import io.anuke.mindustry.ctype.Content;
|
||||
import io.anuke.mindustry.ctype.ContentType;
|
||||
import io.anuke.mindustry.entities.*;
|
||||
import io.anuke.mindustry.entities.Effects.*;
|
||||
import io.anuke.mindustry.entities.effect.*;
|
||||
@@ -137,7 +138,7 @@ public abstract class BulletType extends Content{
|
||||
}
|
||||
|
||||
for(int i = 0; i < lightining; i++){
|
||||
Lightning.create(b.getTeam(), Pal.surge, damage, b.x, b.y, Mathf.random(360f), lightningLength);
|
||||
Lightning.createLighting(Lightning.nextSeed(), b.getTeam(), Pal.surge, damage, b.x, b.y, Mathf.random(360f), lightningLength);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -150,7 +151,7 @@ public abstract class BulletType extends Content{
|
||||
public void update(Bullet b){
|
||||
|
||||
if(homingPower > 0.0001f){
|
||||
TargetTrait target = Units.closestTarget(b.getTeam(), b.x, b.y, homingRange);
|
||||
TargetTrait target = Units.closestTarget(b.getTeam(), b.x, b.y, homingRange, e -> !e.isFlying() || collidesAir);
|
||||
if(target != null){
|
||||
b.velocity().setAngle(Mathf.slerpDelta(b.velocity().angle(), b.angleTo(target), 0.08f));
|
||||
}
|
||||
|
||||
@@ -14,7 +14,8 @@ import io.anuke.mindustry.world.*;
|
||||
import static io.anuke.mindustry.Vars.*;
|
||||
|
||||
public class LiquidBulletType extends BulletType{
|
||||
@NonNull Liquid liquid;
|
||||
public @NonNull Liquid liquid;
|
||||
public float puddleSize = 5f;
|
||||
|
||||
public LiquidBulletType(@Nullable Liquid liquid){
|
||||
super(3.5f, 0);
|
||||
@@ -67,7 +68,7 @@ public class LiquidBulletType extends BulletType{
|
||||
@Override
|
||||
public void hit(Bullet b, float hitx, float hity){
|
||||
Effects.effect(hitEffect, liquid.color, hitx, hity);
|
||||
Puddle.deposit(world.tileWorld(hitx, hity), liquid, 5f);
|
||||
Puddle.deposit(world.tileWorld(hitx, hity), liquid, puddleSize);
|
||||
|
||||
if(liquid.temperature <= 0.5f && liquid.flammability < 0.3f){
|
||||
float intensity = 400f;
|
||||
|
||||
@@ -10,10 +10,10 @@ import io.anuke.mindustry.content.*;
|
||||
import io.anuke.mindustry.entities.*;
|
||||
import io.anuke.mindustry.entities.traits.*;
|
||||
import io.anuke.mindustry.entities.type.*;
|
||||
import io.anuke.mindustry.entities.type.TimedEntity;
|
||||
import io.anuke.mindustry.game.EventType.*;
|
||||
import io.anuke.mindustry.game.*;
|
||||
import io.anuke.mindustry.gen.*;
|
||||
import io.anuke.mindustry.type.TypeID;
|
||||
import io.anuke.mindustry.type.*;
|
||||
import io.anuke.mindustry.world.*;
|
||||
|
||||
import java.io.*;
|
||||
@@ -144,7 +144,7 @@ public class Fire extends TimedEntity implements SaveTrait, SyncTrait{
|
||||
create(other);
|
||||
|
||||
if(Mathf.chance(fireballChance * Time.delta() * Mathf.clamp(flammability / 10f))){
|
||||
Call.createBullet(Bullets.fireball, x, y, Mathf.random(360f));
|
||||
Call.createBullet(Bullets.fireball, Team.derelict, x, y, Mathf.random(360f), 1, 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -44,7 +44,11 @@ public class Lightning extends TimedEntity implements DrawTrait, TimeTrait{
|
||||
|
||||
/** Create a lighting branch at a location. Use Team.none to damage everyone. */
|
||||
public static void create(Team team, Color color, float damage, float x, float y, float targetAngle, int length){
|
||||
Call.createLighting(lastSeed++, team, color, damage, x, y, targetAngle, length);
|
||||
Call.createLighting(nextSeed(), team, color, damage, x, y, targetAngle, length);
|
||||
}
|
||||
|
||||
public static int nextSeed(){
|
||||
return lastSeed++;
|
||||
}
|
||||
|
||||
/** Do not invoke! */
|
||||
|
||||
@@ -1,25 +1,22 @@
|
||||
package io.anuke.mindustry.entities.effect;
|
||||
|
||||
import io.anuke.annotations.Annotations.Loc;
|
||||
import io.anuke.annotations.Annotations.Remote;
|
||||
import io.anuke.arc.collection.IntMap;
|
||||
import io.anuke.arc.graphics.Color;
|
||||
import io.anuke.arc.graphics.g2d.Draw;
|
||||
import io.anuke.arc.graphics.g2d.Fill;
|
||||
import io.anuke.arc.math.Angles;
|
||||
import io.anuke.arc.math.Mathf;
|
||||
import io.anuke.annotations.Annotations.*;
|
||||
import io.anuke.arc.collection.*;
|
||||
import io.anuke.arc.graphics.*;
|
||||
import io.anuke.arc.graphics.g2d.*;
|
||||
import io.anuke.arc.math.*;
|
||||
import io.anuke.arc.math.geom.*;
|
||||
import io.anuke.arc.util.Time;
|
||||
import io.anuke.arc.util.pooling.Pool.Poolable;
|
||||
import io.anuke.arc.util.pooling.Pools;
|
||||
import io.anuke.arc.util.*;
|
||||
import io.anuke.arc.util.pooling.Pool.*;
|
||||
import io.anuke.arc.util.pooling.*;
|
||||
import io.anuke.mindustry.content.*;
|
||||
import io.anuke.mindustry.entities.*;
|
||||
import io.anuke.mindustry.entities.type.SolidEntity;
|
||||
import io.anuke.mindustry.entities.traits.*;
|
||||
import io.anuke.mindustry.type.TypeID;
|
||||
import io.anuke.mindustry.gen.Call;
|
||||
import io.anuke.mindustry.type.Liquid;
|
||||
import io.anuke.mindustry.world.Tile;
|
||||
import io.anuke.mindustry.entities.type.*;
|
||||
import io.anuke.mindustry.game.*;
|
||||
import io.anuke.mindustry.gen.*;
|
||||
import io.anuke.mindustry.type.*;
|
||||
import io.anuke.mindustry.world.*;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
@@ -118,7 +115,7 @@ public class Puddle extends SolidEntity implements SaveTrait, Poolable, DrawTrai
|
||||
(liquid.flammability > 0.3f && dest.temperature > 0.7f)){ //flammable liquid + hot liquid
|
||||
Fire.create(tile);
|
||||
if(Mathf.chance(0.006 * amount)){
|
||||
Call.createBullet(Bullets.fireball, x, y, Mathf.random(360f));
|
||||
Call.createBullet(Bullets.fireball, Team.derelict, x, y, Mathf.random(360f), 1f, 1f);
|
||||
}
|
||||
}else if(dest.temperature > 0.7f && liquid.temperature < 0.55f){ //cold liquid poured onto hot puddle
|
||||
if(Mathf.chance(0.5f * amount)){
|
||||
|
||||
@@ -2,7 +2,6 @@ package io.anuke.mindustry.entities.traits;
|
||||
|
||||
import io.anuke.arc.*;
|
||||
import io.anuke.arc.collection.Queue;
|
||||
import io.anuke.arc.collection.*;
|
||||
import io.anuke.arc.graphics.g2d.*;
|
||||
import io.anuke.arc.math.*;
|
||||
import io.anuke.arc.math.geom.*;
|
||||
@@ -88,7 +87,7 @@ public interface BuilderTrait extends Entity, TeamTrait{
|
||||
}
|
||||
|
||||
//otherwise, update it.
|
||||
BuildEntity entity = tile.entity();
|
||||
BuildEntity entity = tile.ent();
|
||||
|
||||
if(entity == null){
|
||||
return;
|
||||
@@ -210,7 +209,7 @@ public interface BuilderTrait extends Entity, TeamTrait{
|
||||
}
|
||||
Tile tile = world.tile(place.x, place.y);
|
||||
if(tile != null && tile.entity instanceof BuildEntity){
|
||||
place.progress = tile.<BuildEntity>entity().progress;
|
||||
place.progress = tile.<BuildEntity>ent().progress;
|
||||
}
|
||||
if(tail){
|
||||
buildQueue().addLast(place);
|
||||
|
||||
@@ -9,6 +9,7 @@ import io.anuke.arc.util.*;
|
||||
import io.anuke.arc.util.ArcAnnotate.*;
|
||||
import io.anuke.mindustry.*;
|
||||
import io.anuke.mindustry.content.*;
|
||||
import io.anuke.mindustry.ctype.ContentType;
|
||||
import io.anuke.mindustry.entities.*;
|
||||
import io.anuke.mindustry.entities.traits.*;
|
||||
import io.anuke.mindustry.entities.units.*;
|
||||
@@ -107,7 +108,7 @@ public abstract class BaseUnit extends Unit implements ShooterTrait{
|
||||
|
||||
public @Nullable UnitCommand getCommand(){
|
||||
if(isCommanded()){
|
||||
return indexer.getAllied(team, BlockFlag.comandCenter).first().<CommandCenterEntity>entity().command;
|
||||
return indexer.getAllied(team, BlockFlag.comandCenter).first().<CommandCenterEntity>ent().command;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -77,16 +77,9 @@ public class Bullet extends SolidEntity implements DamageTrait, ScaleTrait, Pool
|
||||
return create(type, parent.owner, parent.team, x, y, angle, velocityScl);
|
||||
}
|
||||
|
||||
/** Internal use only. */
|
||||
@Remote(called = Loc.server, unreliable = true)
|
||||
public static void createBullet(BulletType type, float x, float y, float angle){
|
||||
create(type, null, Team.derelict, x, y, angle);
|
||||
}
|
||||
|
||||
/** ok */
|
||||
@Remote(called = Loc.server, unreliable = true)
|
||||
public static void createBullet(BulletType type, Team team, float x, float y, float angle){
|
||||
create(type, null, team, x, y, angle);
|
||||
public static void createBullet(BulletType type, Team team, float x, float y, float angle, float velocityScl, float lifetimeScl){
|
||||
create(type, null, team, x, y, angle, velocityScl, lifetimeScl, null);
|
||||
}
|
||||
|
||||
public Entity getOwner(){
|
||||
|
||||
@@ -15,6 +15,7 @@ import io.anuke.arc.util.pooling.*;
|
||||
import io.anuke.mindustry.*;
|
||||
import io.anuke.mindustry.content.*;
|
||||
import io.anuke.mindustry.core.*;
|
||||
import io.anuke.mindustry.ctype.ContentType;
|
||||
import io.anuke.mindustry.entities.*;
|
||||
import io.anuke.mindustry.entities.traits.*;
|
||||
import io.anuke.mindustry.game.*;
|
||||
@@ -556,7 +557,7 @@ public class Player extends Unit implements BuilderMinerTrait, ShooterTrait{
|
||||
updateKeyboard();
|
||||
}
|
||||
|
||||
isTyping = ui.chatfrag.chatOpen();
|
||||
isTyping = ui.chatfrag.shown();
|
||||
|
||||
updateMechanics();
|
||||
|
||||
@@ -604,7 +605,7 @@ public class Player extends Unit implements BuilderMinerTrait, ShooterTrait{
|
||||
|
||||
movement.limit(speed).scl(Time.delta());
|
||||
|
||||
if(!ui.chatfrag.chatOpen()){
|
||||
if(!Core.scene.hasKeyboard()){
|
||||
velocity.add(movement.x, movement.y);
|
||||
}else{
|
||||
isShooting = false;
|
||||
@@ -613,7 +614,7 @@ public class Player extends Unit implements BuilderMinerTrait, ShooterTrait{
|
||||
updateVelocityStatus();
|
||||
moved = dst(prex, prey) > 0.001f;
|
||||
|
||||
if(!ui.chatfrag.chatOpen()){
|
||||
if(!Core.scene.hasKeyboard()){
|
||||
float baseLerp = mech.getRotationAlpha(this);
|
||||
if(!isShooting() || !mech.turnCursor){
|
||||
if(!movement.isZero()){
|
||||
|
||||
@@ -37,7 +37,7 @@ public class TileEntity extends BaseEntity implements TargetTrait, HealthTrait{
|
||||
public PowerModule power;
|
||||
public ItemModule items;
|
||||
public LiquidModule liquids;
|
||||
public ConsumeModule cons;
|
||||
public @Nullable ConsumeModule cons;
|
||||
|
||||
/** List of (cached) tiles with entities in proximity, used for outputting to */
|
||||
private Array<Tile> proximity = new Array<>(8);
|
||||
|
||||
@@ -24,6 +24,7 @@ public class BuilderDrone extends BaseDrone implements BuilderTrait{
|
||||
private static final IntIntMap totals = new IntIntMap();
|
||||
|
||||
protected Queue<BuildRequest> placeQueue = new Queue<>();
|
||||
protected BuildRequest lastFound;
|
||||
protected boolean isBreaking;
|
||||
protected Player playerTarget;
|
||||
|
||||
@@ -57,6 +58,9 @@ public class BuilderDrone extends BaseDrone implements BuilderTrait{
|
||||
buildQueue().addLast(new BuildRequest(entity.tile.x, entity.tile.y));
|
||||
}else{
|
||||
buildQueue().addLast(new BuildRequest(entity.tile.x, entity.tile.y, entity.tile.rotation(), entity.cblock));
|
||||
if(lastFound != null && lastFound.hasConfig){
|
||||
buildQueue().last().configure(lastFound.config);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -171,9 +175,10 @@ public class BuilderDrone extends BaseDrone implements BuilderTrait{
|
||||
BuildRequest req = player.buildRequest();
|
||||
Tile tile = world.tile(req.x, req.y);
|
||||
if(tile != null && tile.entity instanceof BuildEntity){
|
||||
BuildEntity b = tile.entity();
|
||||
BuildEntity b = tile.ent();
|
||||
float dist = Math.min(b.dst(x, y) - placeDistance, 0);
|
||||
if(dist / type.maxVelocity < b.buildCost * 0.9f){
|
||||
lastFound = req;
|
||||
target = b;
|
||||
this.isBreaking = req.breaking;
|
||||
setState(build);
|
||||
|
||||
@@ -6,6 +6,7 @@ import io.anuke.arc.graphics.*;
|
||||
import io.anuke.arc.util.*;
|
||||
import io.anuke.arc.util.pooling.*;
|
||||
import io.anuke.mindustry.content.*;
|
||||
import io.anuke.mindustry.ctype.ContentType;
|
||||
import io.anuke.mindustry.entities.traits.*;
|
||||
import io.anuke.mindustry.entities.type.*;
|
||||
import io.anuke.mindustry.type.*;
|
||||
|
||||
@@ -95,6 +95,10 @@ public class EventType{
|
||||
|
||||
}
|
||||
|
||||
public static class ServerLoadEvent{
|
||||
|
||||
}
|
||||
|
||||
public static class ContentReloadEvent{
|
||||
|
||||
}
|
||||
@@ -135,9 +139,19 @@ public class EventType{
|
||||
|
||||
}
|
||||
|
||||
/** Called when a player withdraws items from a block. Tutorial only.*/
|
||||
/** Called when the player withdraws items from a block. */
|
||||
public static class WithdrawEvent{
|
||||
public final Tile tile;
|
||||
public final Player player;
|
||||
public final Item item;
|
||||
public final int amount;
|
||||
|
||||
public WithdrawEvent(Tile tile, Player player, Item item, int amount){
|
||||
this.tile = tile;
|
||||
this.player = player;
|
||||
this.item = item;
|
||||
this.amount = amount;
|
||||
}
|
||||
}
|
||||
|
||||
/** Called when a player deposits items to a block.*/
|
||||
|
||||
@@ -6,7 +6,7 @@ import io.anuke.arc.files.*;
|
||||
import io.anuke.arc.util.io.*;
|
||||
import io.anuke.mindustry.*;
|
||||
import io.anuke.mindustry.content.*;
|
||||
import io.anuke.mindustry.ctype.UnlockableContent;
|
||||
import io.anuke.mindustry.ctype.*;
|
||||
import io.anuke.mindustry.game.EventType.*;
|
||||
import io.anuke.mindustry.type.*;
|
||||
|
||||
@@ -35,8 +35,8 @@ public class GlobalData{
|
||||
});
|
||||
}
|
||||
|
||||
public void exportData(FileHandle file) throws IOException{
|
||||
Array<FileHandle> files = new Array<>();
|
||||
public void exportData(Fi file) throws IOException{
|
||||
Array<Fi> files = new Array<>();
|
||||
files.add(Core.settings.getSettingsFile());
|
||||
files.addAll(customMapDirectory.list());
|
||||
files.addAll(saveDirectory.list());
|
||||
@@ -46,7 +46,7 @@ public class GlobalData{
|
||||
String base = Core.settings.getDataDirectory().path();
|
||||
|
||||
try(OutputStream fos = file.write(false, 2048); ZipOutputStream zos = new ZipOutputStream(fos)){
|
||||
for(FileHandle add : files){
|
||||
for(Fi add : files){
|
||||
if(add.isDirectory()) continue;
|
||||
zos.putNextEntry(new ZipEntry(add.path().substring(base.length())));
|
||||
Streams.copyStream(add.read(), zos);
|
||||
@@ -56,12 +56,12 @@ public class GlobalData{
|
||||
}
|
||||
}
|
||||
|
||||
public void importData(FileHandle file){
|
||||
FileHandle dest = Core.files.local("zipdata.zip");
|
||||
public void importData(Fi file){
|
||||
Fi dest = Core.files.local("zipdata.zip");
|
||||
file.copyTo(dest);
|
||||
FileHandle zipped = new ZipFileHandle(dest);
|
||||
Fi zipped = new ZipFi(dest);
|
||||
|
||||
FileHandle base = Core.settings.getDataDirectory();
|
||||
Fi base = Core.settings.getDataDirectory();
|
||||
if(!zipped.child("settings.bin").exists()){
|
||||
throw new IllegalArgumentException("Not valid save data.");
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ public class Saves{
|
||||
private AsyncExecutor previewExecutor = new AsyncExecutor(1);
|
||||
private boolean saving;
|
||||
private float time;
|
||||
private FileHandle zoneFile;
|
||||
private Fi zoneFile;
|
||||
|
||||
private long totalPlaytime;
|
||||
private long lastTimestamp;
|
||||
@@ -48,7 +48,7 @@ public class Saves{
|
||||
saves.clear();
|
||||
zoneFile = saveDirectory.child("-1.msav");
|
||||
|
||||
for(FileHandle file : saveDirectory.list()){
|
||||
for(Fi file : saveDirectory.list()){
|
||||
if(!file.name().contains("backup") && SaveIO.isSaveValid(file)){
|
||||
SaveSlot slot = new SaveSlot(file);
|
||||
saves.add(slot);
|
||||
@@ -121,7 +121,7 @@ public class Saves{
|
||||
return slot;
|
||||
}
|
||||
|
||||
public SaveSlot importSave(FileHandle file) throws IOException{
|
||||
public SaveSlot importSave(Fi file) throws IOException{
|
||||
SaveSlot slot = new SaveSlot(getNextSlotFile());
|
||||
slot.importFile(file);
|
||||
slot.setName(file.nameWithoutExtension());
|
||||
@@ -136,9 +136,9 @@ public class Saves{
|
||||
return slot == null || slot.getZone() == null ? null : slot;
|
||||
}
|
||||
|
||||
public FileHandle getNextSlotFile(){
|
||||
public Fi getNextSlotFile(){
|
||||
int i = 0;
|
||||
FileHandle file;
|
||||
Fi file;
|
||||
while((file = saveDirectory.child(i + "." + saveExtension)).exists()){
|
||||
i ++;
|
||||
}
|
||||
@@ -151,11 +151,11 @@ public class Saves{
|
||||
|
||||
public class SaveSlot{
|
||||
//public final int index;
|
||||
public final FileHandle file;
|
||||
public final Fi file;
|
||||
boolean requestedPreview;
|
||||
SaveMeta meta;
|
||||
|
||||
public SaveSlot(FileHandle file){
|
||||
public SaveSlot(Fi file){
|
||||
this.file = file;
|
||||
}
|
||||
|
||||
@@ -216,11 +216,11 @@ public class Saves{
|
||||
return file.nameWithoutExtension();
|
||||
}
|
||||
|
||||
private FileHandle previewFile(){
|
||||
private Fi previewFile(){
|
||||
return mapPreviewDirectory.child("save_slot_" + index() + ".png");
|
||||
}
|
||||
|
||||
private FileHandle loadPreviewFile(){
|
||||
private Fi loadPreviewFile(){
|
||||
return previewFile().sibling(previewFile().name() + ".spreview");
|
||||
}
|
||||
|
||||
@@ -293,7 +293,7 @@ public class Saves{
|
||||
Core.settings.save();
|
||||
}
|
||||
|
||||
public void importFile(FileHandle from) throws IOException{
|
||||
public void importFile(Fi from) throws IOException{
|
||||
try{
|
||||
from.copyTo(file);
|
||||
}catch(Exception e){
|
||||
@@ -301,7 +301,7 @@ public class Saves{
|
||||
}
|
||||
}
|
||||
|
||||
public void exportFile(FileHandle to) throws IOException{
|
||||
public void exportFile(Fi to) throws IOException{
|
||||
try{
|
||||
file.copyTo(to);
|
||||
}catch(Exception e){
|
||||
|
||||
@@ -5,6 +5,7 @@ import io.anuke.arc.collection.IntIntMap.*;
|
||||
import io.anuke.arc.files.*;
|
||||
import io.anuke.arc.util.ArcAnnotate.*;
|
||||
import io.anuke.mindustry.*;
|
||||
import io.anuke.mindustry.mod.Mods.*;
|
||||
import io.anuke.mindustry.type.*;
|
||||
import io.anuke.mindustry.world.*;
|
||||
import io.anuke.mindustry.world.blocks.storage.*;
|
||||
@@ -15,9 +16,12 @@ public class Schematic implements Publishable, Comparable<Schematic>{
|
||||
public final Array<Stile> tiles;
|
||||
public StringMap tags;
|
||||
public int width, height;
|
||||
public @Nullable FileHandle file;
|
||||
public @Nullable
|
||||
Fi file;
|
||||
/** Associated mod. If null, no mod is associated with this schematic. */
|
||||
public @Nullable LoadedMod mod;
|
||||
|
||||
public Schematic(Array<Stile> tiles, StringMap tags, int width, int height){
|
||||
public Schematic(Array<Stile> tiles, @NonNull StringMap tags, int width, int height){
|
||||
this.tiles = tiles;
|
||||
this.tags = tags;
|
||||
this.width = width;
|
||||
@@ -91,15 +95,15 @@ public class Schematic implements Publishable, Comparable<Schematic>{
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileHandle createSteamFolder(String id){
|
||||
FileHandle directory = tmpDirectory.child("schematic_" + id).child("schematic." + schematicExtension);
|
||||
public Fi createSteamFolder(String id){
|
||||
Fi directory = tmpDirectory.child("schematic_" + id).child("schematic." + schematicExtension);
|
||||
file.copyTo(directory);
|
||||
return directory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileHandle createSteamPreview(String id){
|
||||
FileHandle preview = tmpDirectory.child("schematic_preview_" + id + ".png");
|
||||
public Fi createSteamPreview(String id){
|
||||
Fi preview = tmpDirectory.child("schematic_preview_" + id + ".png");
|
||||
schematics.savePreview(this, preview);
|
||||
return preview;
|
||||
}
|
||||
|
||||
@@ -8,16 +8,17 @@ import io.anuke.arc.graphics.*;
|
||||
import io.anuke.arc.graphics.g2d.*;
|
||||
import io.anuke.arc.graphics.glutils.*;
|
||||
import io.anuke.arc.util.*;
|
||||
import io.anuke.arc.util.ArcAnnotate.*;
|
||||
import io.anuke.arc.util.io.Streams.*;
|
||||
import io.anuke.arc.util.serialization.*;
|
||||
import io.anuke.mindustry.*;
|
||||
import io.anuke.mindustry.content.*;
|
||||
import io.anuke.mindustry.ctype.ContentType;
|
||||
import io.anuke.mindustry.entities.traits.BuilderTrait.*;
|
||||
import io.anuke.mindustry.game.EventType.*;
|
||||
import io.anuke.mindustry.game.Schematic.*;
|
||||
import io.anuke.mindustry.input.*;
|
||||
import io.anuke.mindustry.input.Placement.*;
|
||||
import io.anuke.mindustry.type.*;
|
||||
import io.anuke.mindustry.world.*;
|
||||
import io.anuke.mindustry.world.blocks.*;
|
||||
import io.anuke.mindustry.world.blocks.production.*;
|
||||
@@ -68,12 +69,20 @@ public class Schematics implements Loadable{
|
||||
public void load(){
|
||||
all.clear();
|
||||
|
||||
for(FileHandle file : schematicDirectory.list()){
|
||||
for(Fi file : schematicDirectory.list()){
|
||||
loadFile(file);
|
||||
}
|
||||
|
||||
platform.getWorkshopContent(Schematic.class).each(this::loadFile);
|
||||
|
||||
//mod-specific schematics, cannot be removed
|
||||
mods.listFiles("schematics", (mod, file) -> {
|
||||
Schematic s = loadFile(file);
|
||||
if(s != null){
|
||||
s.mod = mod;
|
||||
}
|
||||
});
|
||||
|
||||
all.sort();
|
||||
|
||||
if(shadowBuffer == null){
|
||||
@@ -102,8 +111,8 @@ public class Schematics implements Loadable{
|
||||
}
|
||||
}
|
||||
|
||||
private void loadFile(FileHandle file){
|
||||
if(!file.extension().equals(schematicExtension)) return;
|
||||
private @Nullable Schematic loadFile(Fi file){
|
||||
if(!file.extension().equals(schematicExtension)) return null;
|
||||
|
||||
try{
|
||||
Schematic s = read(file);
|
||||
@@ -113,9 +122,12 @@ public class Schematics implements Loadable{
|
||||
if(!s.file.parent().equals(schematicDirectory)){
|
||||
s.tags.put("steamid", s.file.parent().name());
|
||||
}
|
||||
|
||||
return s;
|
||||
}catch(IOException e){
|
||||
Log.err(e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public Array<Schematic> all(){
|
||||
@@ -132,7 +144,7 @@ public class Schematics implements Loadable{
|
||||
}
|
||||
}
|
||||
|
||||
public void savePreview(Schematic schematic, FileHandle file){
|
||||
public void savePreview(Schematic schematic, Fi file){
|
||||
FrameBuffer buffer = getBuffer(schematic);
|
||||
Draw.flush();
|
||||
buffer.begin();
|
||||
@@ -260,7 +272,7 @@ public class Schematics implements Loadable{
|
||||
public void add(Schematic schematic){
|
||||
all.add(schematic);
|
||||
try{
|
||||
FileHandle file = schematicDirectory.child(Time.millis() + "." + schematicExtension);
|
||||
Fi file = schematicDirectory.child(Time.millis() + "." + schematicExtension);
|
||||
write(schematic, file);
|
||||
schematic.file = file;
|
||||
}catch(Exception e){
|
||||
@@ -360,7 +372,7 @@ public class Schematics implements Loadable{
|
||||
return read(new ByteArrayInputStream(Base64Coder.decode(schematic)));
|
||||
}
|
||||
|
||||
public static Schematic read(FileHandle file) throws IOException{
|
||||
public static Schematic read(Fi file) throws IOException{
|
||||
Schematic s = read(new DataInputStream(file.read(1024)));
|
||||
if(!s.tags.containsKey("name")){
|
||||
s.tags.put("name", file.nameWithoutExtension());
|
||||
@@ -413,7 +425,7 @@ public class Schematics implements Loadable{
|
||||
}
|
||||
}
|
||||
|
||||
public static void write(Schematic schematic, FileHandle file) throws IOException{
|
||||
public static void write(Schematic schematic, Fi file) throws IOException{
|
||||
write(schematic, file.write(false, 1024));
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ import io.anuke.arc.util.serialization.Json;
|
||||
import io.anuke.arc.util.serialization.Json.Serializable;
|
||||
import io.anuke.arc.util.serialization.JsonValue;
|
||||
import io.anuke.mindustry.content.*;
|
||||
import io.anuke.mindustry.ctype.ContentType;
|
||||
import io.anuke.mindustry.entities.type.BaseUnit;
|
||||
import io.anuke.mindustry.type.*;
|
||||
|
||||
|
||||
@@ -138,7 +138,7 @@ public class BlockRenderer implements Disposable{
|
||||
Block b = content.block(block.block);
|
||||
if(!camera.bounds(Tmp.r1).grow(tilesize * 2f).overlaps(Tmp.r2.setSize(b.size * tilesize).setCenter(block.x * tilesize + b.offset(), block.y * tilesize + b.offset()))) continue;
|
||||
|
||||
Draw.alpha(0.53f * brokenFade);
|
||||
Draw.alpha(0.33f * brokenFade);
|
||||
Draw.mixcol(Color.white, 0.2f + Mathf.absin(Time.globalTime(), 6f, 0.2f));
|
||||
Draw.rect(b.icon(Cicon.full), block.x * tilesize + b.offset(), block.y * tilesize + b.offset(), b.rotate ? block.rotation * 90 : 0f);
|
||||
}
|
||||
|
||||
@@ -157,5 +157,4 @@ public class OverlayRenderer{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -40,8 +40,7 @@ public enum Binding implements KeyBind{
|
||||
block_select_08(KeyCode.NUM_8),
|
||||
block_select_09(KeyCode.NUM_9),
|
||||
block_select_10(KeyCode.NUM_0),
|
||||
zoom_hold(KeyCode.CONTROL_LEFT, "view"),
|
||||
zoom(new Axis(KeyCode.SCROLL)),
|
||||
zoom(new Axis(KeyCode.SCROLL), "view"),
|
||||
menu(Core.app.getType() == ApplicationType.Android ? KeyCode.BACK : KeyCode.ESCAPE),
|
||||
fullscreen(KeyCode.F11),
|
||||
pause(KeyCode.SPACE),
|
||||
@@ -54,6 +53,7 @@ public enum Binding implements KeyBind{
|
||||
chat_history_prev(KeyCode.UP),
|
||||
chat_history_next(KeyCode.DOWN),
|
||||
chat_scroll(new Axis(KeyCode.SCROLL)),
|
||||
console(KeyCode.F8),
|
||||
;
|
||||
|
||||
private final KeybindValue defaultValue;
|
||||
|
||||
@@ -122,7 +122,7 @@ public class DesktopInput extends InputHandler{
|
||||
drawSelected(sreq.x, sreq.y, sreq.block, getRequest(sreq.x, sreq.y, sreq.block.size, sreq) != null ? Pal.remove : Pal.accent);
|
||||
}
|
||||
|
||||
if(Core.input.keyDown(Binding.schematic_select) && !ui.chatfrag.chatOpen()){
|
||||
if(Core.input.keyDown(Binding.schematic_select) && !Core.scene.hasKeyboard()){
|
||||
drawSelection(schemX, schemY, cursorX, cursorY, Vars.maxSchematicSize);
|
||||
}
|
||||
|
||||
@@ -139,7 +139,7 @@ public class DesktopInput extends InputHandler{
|
||||
player.isShooting = false;
|
||||
}
|
||||
|
||||
if(!state.is(State.menu) && Core.input.keyTap(Binding.minimap) && (scene.getKeyboardFocus() == ui.minimap || !scene.hasDialog()) && !ui.chatfrag.chatOpen() && !(scene.getKeyboardFocus() instanceof TextField)){
|
||||
if(!state.is(State.menu) && Core.input.keyTap(Binding.minimap) && (scene.getKeyboardFocus() == ui.minimap || !scene.hasDialog()) && !Core.scene.hasKeyboard() && !(scene.getKeyboardFocus() instanceof TextField)){
|
||||
if(!ui.minimap.isShown()){
|
||||
ui.minimap.show();
|
||||
}else{
|
||||
@@ -149,8 +149,8 @@ public class DesktopInput extends InputHandler{
|
||||
|
||||
if(state.is(State.menu) || Core.scene.hasDialog()) return;
|
||||
|
||||
//zoom things
|
||||
if(Math.abs(Core.input.axisTap(Binding.zoom)) > 0 && Core.input.keyDown(Binding.zoom_hold)){
|
||||
//zoom camera
|
||||
if(!Core.scene.hasScroll() && !ui.chatfrag.shown() && Math.abs(Core.input.axisTap(Binding.zoom)) > 0 && !Core.input.keyDown(Binding.rotateplaced) && (Core.input.keyDown(Binding.diagonal_placement) || ((!isPlacing() || !block.rotate) && selectRequests.isEmpty()))){
|
||||
renderer.scaleCamera(Core.input.axisTap(Binding.zoom));
|
||||
}
|
||||
|
||||
@@ -166,11 +166,6 @@ public class DesktopInput extends InputHandler{
|
||||
mode = none;
|
||||
}
|
||||
|
||||
if(mode != none || isPlacing()){
|
||||
selectRequests.clear();
|
||||
lastSchematic = null;
|
||||
}
|
||||
|
||||
if(player.isShooting && !canShoot()){
|
||||
player.isShooting = false;
|
||||
}
|
||||
@@ -182,8 +177,7 @@ public class DesktopInput extends InputHandler{
|
||||
selectScale = 0f;
|
||||
}
|
||||
|
||||
if(!Core.input.keyDown(Binding.zoom_hold) && Math.abs((int)Core.input.axisTap(Binding.rotate)) > 0){
|
||||
|
||||
if(!Core.input.keyDown(Binding.diagonal_placement) && Math.abs((int)Core.input.axisTap(Binding.rotate)) > 0){
|
||||
rotation = Mathf.mod(rotation + (int)Core.input.axisTap(Binding.rotate), 4);
|
||||
|
||||
if(sreq != null){
|
||||
@@ -293,12 +287,12 @@ public class DesktopInput extends InputHandler{
|
||||
player.clearBuilding();
|
||||
}
|
||||
|
||||
if(Core.input.keyTap(Binding.schematic_select) && !ui.chatfrag.chatOpen()){
|
||||
if(Core.input.keyTap(Binding.schematic_select) && !Core.scene.hasKeyboard()){
|
||||
schemX = rawCursorX;
|
||||
schemY = rawCursorY;
|
||||
}
|
||||
|
||||
if(Core.input.keyTap(Binding.schematic_menu) && !ui.chatfrag.chatOpen()){
|
||||
if(Core.input.keyTap(Binding.schematic_menu) && !Core.scene.hasKeyboard()){
|
||||
if(ui.schematics.isShown()){
|
||||
ui.schematics.hide();
|
||||
}else{
|
||||
@@ -311,7 +305,7 @@ public class DesktopInput extends InputHandler{
|
||||
selectRequests.clear();
|
||||
}
|
||||
|
||||
if(Core.input.keyRelease(Binding.schematic_select) && !ui.chatfrag.chatOpen()){
|
||||
if(Core.input.keyRelease(Binding.schematic_select) && !Core.scene.hasKeyboard()){
|
||||
lastSchematic = schematics.create(schemX, schemY, rawCursorX, rawCursorY);
|
||||
useSchematic(lastSchematic);
|
||||
if(selectRequests.isEmpty()){
|
||||
@@ -355,7 +349,9 @@ public class DesktopInput extends InputHandler{
|
||||
if(Core.input.keyTap(Binding.select) && !Core.scene.hasMouse()){
|
||||
BuildRequest req = getRequest(cursorX, cursorY);
|
||||
|
||||
if(!selectRequests.isEmpty()){
|
||||
if(Core.input.keyDown(Binding.break_block)){
|
||||
mode = none;
|
||||
}else if(!selectRequests.isEmpty()){
|
||||
flushRequests(selectRequests);
|
||||
}else if(isPlacing()){
|
||||
selectX = cursorX;
|
||||
@@ -371,15 +367,18 @@ public class DesktopInput extends InputHandler{
|
||||
}else if(selected != null){
|
||||
//only begin shooting if there's no cursor event
|
||||
if(!tileTapped(selected) && !tryTapPlayer(Core.input.mouseWorld().x, Core.input.mouseWorld().y) && (player.buildQueue().size == 0 || !player.isBuilding) && !droppingItem &&
|
||||
!tryBeginMine(selected) && player.getMineTile() == null && !ui.chatfrag.chatOpen()){
|
||||
!tryBeginMine(selected) && player.getMineTile() == null && !Core.scene.hasKeyboard()){
|
||||
player.isShooting = true;
|
||||
}
|
||||
}else if(!ui.chatfrag.chatOpen()){ //if it's out of bounds, shooting is just fine
|
||||
}else if(!Core.scene.hasKeyboard()){ //if it's out of bounds, shooting is just fine
|
||||
player.isShooting = true;
|
||||
}
|
||||
}else if(Core.input.keyTap(Binding.deselect) && block != null){
|
||||
}else if(Core.input.keyTap(Binding.deselect) && isPlacing()){
|
||||
block = null;
|
||||
mode = none;
|
||||
}else if(Core.input.keyTap(Binding.deselect) && !selectRequests.isEmpty()){
|
||||
selectRequests.clear();
|
||||
lastSchematic = null;
|
||||
}else if(Core.input.keyTap(Binding.break_block) && !Core.scene.hasMouse()){
|
||||
//is recalculated because setting the mode to breaking removes potential multiblock cursor offset
|
||||
deleting = false;
|
||||
|
||||
@@ -221,7 +221,7 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
|
||||
|
||||
public boolean requestMatches(BuildRequest request){
|
||||
Tile tile = world.tile(request.x, request.y);
|
||||
return tile != null && tile.block() instanceof BuildBlock && tile.<BuildEntity>entity().cblock == request.block;
|
||||
return tile != null && tile.block() instanceof BuildBlock && tile.<BuildEntity>ent().cblock == request.block;
|
||||
}
|
||||
|
||||
public void drawBreaking(int x, int y){
|
||||
|
||||
@@ -587,8 +587,8 @@ public class MobileInput extends InputHandler implements GestureListener{
|
||||
mode = none;
|
||||
}
|
||||
|
||||
//zoom things
|
||||
if(Math.abs(Core.input.axisTap(Binding.zoom)) > 0 && (Core.input.keyDown(Binding.zoom_hold))){
|
||||
//zoom camera
|
||||
if(Math.abs(Core.input.axisTap(Binding.zoom)) > 0 && !Core.input.keyDown(Binding.rotateplaced) && (Core.input.keyDown(Binding.diagonal_placement) || ((!isPlacing() || !block.rotate) && selectRequests.isEmpty()))){
|
||||
renderer.scaleCamera(Core.input.axisTap(Binding.zoom));
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
package io.anuke.mindustry.input;
|
||||
|
||||
enum PlaceMode{
|
||||
public enum PlaceMode{
|
||||
none, breaking, placing, schematicSelect
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import io.anuke.arc.util.serialization.Json.*;
|
||||
import io.anuke.mindustry.*;
|
||||
import io.anuke.mindustry.content.*;
|
||||
import io.anuke.mindustry.ctype.*;
|
||||
import io.anuke.mindustry.ctype.ContentType;
|
||||
import io.anuke.mindustry.game.*;
|
||||
import io.anuke.mindustry.type.*;
|
||||
import io.anuke.mindustry.world.*;
|
||||
|
||||
@@ -6,10 +6,10 @@ import io.anuke.arc.graphics.*;
|
||||
import io.anuke.arc.util.*;
|
||||
import io.anuke.arc.util.serialization.*;
|
||||
import io.anuke.mindustry.content.*;
|
||||
import io.anuke.mindustry.ctype.ContentType;
|
||||
import io.anuke.mindustry.game.*;
|
||||
import io.anuke.mindustry.io.MapIO.*;
|
||||
import io.anuke.mindustry.maps.*;
|
||||
import io.anuke.mindustry.type.*;
|
||||
import io.anuke.mindustry.world.*;
|
||||
import io.anuke.mindustry.world.LegacyColorMapper.*;
|
||||
import io.anuke.mindustry.world.blocks.*;
|
||||
@@ -25,7 +25,7 @@ public class LegacyMapIO{
|
||||
private static final ObjectMap<String, String> fallback = ObjectMap.of("alpha-dart-mech-pad", "dart-mech-pad");
|
||||
private static final Json json = new Json();
|
||||
|
||||
public static Map readMap(FileHandle file, boolean custom) throws IOException{
|
||||
public static Map readMap(Fi file, boolean custom) throws IOException{
|
||||
try(DataInputStream stream = new DataInputStream(file.read(1024))){
|
||||
StringMap tags = new StringMap();
|
||||
|
||||
@@ -56,11 +56,11 @@ public class LegacyMapIO{
|
||||
readTiles(map.file, map.width, map.height, tiles);
|
||||
}
|
||||
|
||||
private static void readTiles(FileHandle file, int width, int height, Tile[][] tiles) throws IOException{
|
||||
private static void readTiles(Fi file, int width, int height, Tile[][] tiles) throws IOException{
|
||||
readTiles(file, width, height, (x, y) -> tiles[x][y]);
|
||||
}
|
||||
|
||||
private static void readTiles(FileHandle file, int width, int height, TileProvider tiles) throws IOException{
|
||||
private static void readTiles(Fi file, int width, int height, TileProvider tiles) throws IOException{
|
||||
try(BufferedInputStream input = file.read(bufferSize)){
|
||||
|
||||
//read map
|
||||
|
||||
@@ -22,7 +22,7 @@ import static io.anuke.mindustry.Vars.*;
|
||||
public class MapIO{
|
||||
private static final int[] pngHeader = {0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A};
|
||||
|
||||
public static boolean isImage(FileHandle file){
|
||||
public static boolean isImage(Fi file){
|
||||
try(InputStream stream = file.read(32)){
|
||||
for(int i1 : pngHeader){
|
||||
if(stream.read() != i1){
|
||||
@@ -35,7 +35,7 @@ public class MapIO{
|
||||
}
|
||||
}
|
||||
|
||||
public static Map createMap(FileHandle file, boolean custom) throws IOException{
|
||||
public static Map createMap(Fi file, boolean custom) throws IOException{
|
||||
try(InputStream is = new InflaterInputStream(file.read(bufferSize)); CounterInputStream counter = new CounterInputStream(is); DataInputStream stream = new DataInputStream(counter)){
|
||||
SaveIO.readHeader(stream);
|
||||
int version = stream.readInt();
|
||||
@@ -46,7 +46,7 @@ public class MapIO{
|
||||
}
|
||||
}
|
||||
|
||||
public static void writeMap(FileHandle file, Map map) throws IOException{
|
||||
public static void writeMap(Fi file, Map map) throws IOException{
|
||||
try{
|
||||
SaveIO.write(file, map.tags);
|
||||
}catch(Exception e){
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package io.anuke.mindustry.io;
|
||||
|
||||
import io.anuke.arc.collection.*;
|
||||
import io.anuke.arc.files.FileHandle;
|
||||
import io.anuke.arc.files.Fi;
|
||||
import io.anuke.arc.util.io.CounterInputStream;
|
||||
import io.anuke.arc.util.io.FastDeflaterOutputStream;
|
||||
import io.anuke.mindustry.Vars;
|
||||
@@ -34,7 +34,7 @@ public class SaveIO{
|
||||
return versions.get(version);
|
||||
}
|
||||
|
||||
public static void save(FileHandle file){
|
||||
public static void save(Fi file){
|
||||
boolean exists = file.exists();
|
||||
if(exists) file.moveTo(backupFileFor(file));
|
||||
try{
|
||||
@@ -45,15 +45,15 @@ public class SaveIO{
|
||||
}
|
||||
}
|
||||
|
||||
public static DataInputStream getStream(FileHandle file){
|
||||
public static DataInputStream getStream(Fi file){
|
||||
return new DataInputStream(new InflaterInputStream(file.read(bufferSize)));
|
||||
}
|
||||
|
||||
public static DataInputStream getBackupStream(FileHandle file){
|
||||
public static DataInputStream getBackupStream(Fi file){
|
||||
return new DataInputStream(new InflaterInputStream(backupFileFor(file).read(bufferSize)));
|
||||
}
|
||||
|
||||
public static boolean isSaveValid(FileHandle file){
|
||||
public static boolean isSaveValid(Fi file){
|
||||
try{
|
||||
return isSaveValid(new DataInputStream(new InflaterInputStream(file.read(bufferSize))));
|
||||
}catch(Exception e){
|
||||
@@ -71,7 +71,7 @@ public class SaveIO{
|
||||
}
|
||||
}
|
||||
|
||||
public static SaveMeta getMeta(FileHandle file){
|
||||
public static SaveMeta getMeta(Fi file){
|
||||
try{
|
||||
return getMeta(getStream(file));
|
||||
}catch(Exception e){
|
||||
@@ -92,19 +92,19 @@ public class SaveIO{
|
||||
}
|
||||
}
|
||||
|
||||
public static FileHandle fileFor(int slot){
|
||||
public static Fi fileFor(int slot){
|
||||
return saveDirectory.child(slot + "." + Vars.saveExtension);
|
||||
}
|
||||
|
||||
public static FileHandle backupFileFor(FileHandle file){
|
||||
public static Fi backupFileFor(Fi file){
|
||||
return file.sibling(file.name() + "-backup." + file.extension());
|
||||
}
|
||||
|
||||
public static void write(FileHandle file, StringMap tags){
|
||||
public static void write(Fi file, StringMap tags){
|
||||
write(new FastDeflaterOutputStream(file.write(false, bufferSize)), tags);
|
||||
}
|
||||
|
||||
public static void write(FileHandle file){
|
||||
public static void write(Fi file){
|
||||
write(file, null);
|
||||
}
|
||||
|
||||
@@ -122,17 +122,17 @@ public class SaveIO{
|
||||
}
|
||||
}
|
||||
|
||||
public static void load(FileHandle file) throws SaveException{
|
||||
public static void load(Fi file) throws SaveException{
|
||||
load(file, world.context);
|
||||
}
|
||||
|
||||
public static void load(FileHandle file, WorldContext context) throws SaveException{
|
||||
public static void load(Fi file, WorldContext context) throws SaveException{
|
||||
try{
|
||||
//try and load; if any exception at all occurs
|
||||
load(new InflaterInputStream(file.read(bufferSize)), context);
|
||||
}catch(SaveException e){
|
||||
e.printStackTrace();
|
||||
FileHandle backup = file.sibling(file.name() + "-backup." + file.extension());
|
||||
Fi backup = file.sibling(file.name() + "-backup." + file.extension());
|
||||
if(backup.exists()){
|
||||
load(new InflaterInputStream(backup.read(bufferSize)), context);
|
||||
}else{
|
||||
|
||||
@@ -12,7 +12,7 @@ public class SavePreviewLoader extends TextureLoader{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadAsync(AssetManager manager, String fileName, FileHandle file, TextureParameter parameter){
|
||||
public void loadAsync(AssetManager manager, String fileName, Fi file, TextureParameter parameter){
|
||||
try{
|
||||
super.loadAsync(manager, fileName, file.sibling(file.nameWithoutExtension()), parameter);
|
||||
}catch(Exception e){
|
||||
|
||||
@@ -6,6 +6,7 @@ import io.anuke.arc.util.io.*;
|
||||
import io.anuke.mindustry.content.*;
|
||||
import io.anuke.mindustry.core.*;
|
||||
import io.anuke.mindustry.ctype.*;
|
||||
import io.anuke.mindustry.ctype.ContentType;
|
||||
import io.anuke.mindustry.entities.*;
|
||||
import io.anuke.mindustry.entities.traits.*;
|
||||
import io.anuke.mindustry.game.*;
|
||||
@@ -84,7 +85,6 @@ public abstract class SaveVersion extends SaveFileReader{
|
||||
state.rules = JsonIO.read(Rules.class, map.get("rules", "{}"));
|
||||
if(state.rules.spawns.isEmpty()) state.rules.spawns = defaultWaves.get();
|
||||
lastReadBuild = map.getInt("build", -1);
|
||||
String[] mods = JsonIO.read(String[].class, map.get("mods", "[]"));
|
||||
|
||||
Map worldmap = maps.byName(map.get("mapname", "\\\\\\"));
|
||||
world.setMap(worldmap == null ? new Map(StringMap.of(
|
||||
|
||||
@@ -3,6 +3,7 @@ package io.anuke.mindustry.io;
|
||||
import io.anuke.annotations.Annotations.ReadClass;
|
||||
import io.anuke.annotations.Annotations.WriteClass;
|
||||
import io.anuke.arc.graphics.Color;
|
||||
import io.anuke.mindustry.ctype.ContentType;
|
||||
import io.anuke.mindustry.entities.Effects;
|
||||
import io.anuke.mindustry.entities.Effects.Effect;
|
||||
import io.anuke.mindustry.entities.type.Bullet;
|
||||
|
||||
@@ -12,6 +12,60 @@ Latest data: [build 81]
|
||||
0 = Player
|
||||
1 = Fire
|
||||
2 = Puddle
|
||||
3 = MinerDrone
|
||||
4 = RepairDrone
|
||||
5 = BuilderDrone
|
||||
6 = GroundUnit
|
||||
7 = GroundUnit
|
||||
8 = GroundUnit
|
||||
9 = GroundUnit
|
||||
10 = GroundUnit
|
||||
11 = FlyingUnit
|
||||
12 = FlyingUnit
|
||||
13 = Revenant
|
||||
|
||||
Before removal of lightining/bullet: [build 80]
|
||||
|
||||
0 = Player
|
||||
1 = Fire
|
||||
2 = Puddle
|
||||
3 = Bullet
|
||||
4 = Lightning
|
||||
5 = MinerDrone
|
||||
6 = RepairDrone
|
||||
7 = BuilderDrone
|
||||
8 = GroundUnit
|
||||
9 = GroundUnit
|
||||
10 = GroundUnit
|
||||
11 = GroundUnit
|
||||
12 = GroundUnit
|
||||
13 = FlyingUnit
|
||||
14 = FlyingUnit
|
||||
15 = Revenant
|
||||
|
||||
Before addition of new units: [build 79 and below]
|
||||
|
||||
0 = Player
|
||||
1 = Fire
|
||||
2 = Puddle
|
||||
3 = Bullet
|
||||
4 = Lightning
|
||||
5 = RepairDrone
|
||||
6 = GroundUnit
|
||||
7 = GroundUnit
|
||||
8 = GroundUnit
|
||||
9 = GroundUnit
|
||||
10 = GroundUnit
|
||||
11 = FlyingUnit
|
||||
12 = FlyingUnit
|
||||
13 = BuilderDrone
|
||||
14 = Revenant
|
||||
*/
|
||||
public class LegacyTypeTable{
|
||||
/*
|
||||
0 = Player
|
||||
1 = Fire
|
||||
2 = Puddle
|
||||
3 = Draug
|
||||
4 = Spirit
|
||||
5 = Phantom
|
||||
@@ -23,45 +77,7 @@ Latest data: [build 81]
|
||||
11 = Wraith
|
||||
12 = Ghoul
|
||||
13 = Revenant
|
||||
|
||||
Before removal of lightining/bullet: [build 80]
|
||||
|
||||
0 = Player
|
||||
1 = Fire
|
||||
2 = Puddle
|
||||
3 = Bullet
|
||||
4 = Lightning
|
||||
5 = Draug
|
||||
6 = Spirit
|
||||
7 = Phantom
|
||||
8 = Dagger
|
||||
9 = Crawler
|
||||
10 = Titan
|
||||
11 = Fortress
|
||||
12 = Eruptor
|
||||
13 = Wraith
|
||||
14 = Ghoul
|
||||
15 = Revenant
|
||||
|
||||
Before addition of new units: [build 79 and below]
|
||||
|
||||
0 = Player
|
||||
1 = Fire
|
||||
2 = Puddle
|
||||
3 = Bullet
|
||||
4 = Lightning
|
||||
5 = Spirit
|
||||
6 = Dagger
|
||||
7 = Crawler
|
||||
8 = Titan
|
||||
9 = Fortress
|
||||
10 = Eruptor
|
||||
11 = Wraith
|
||||
12 = Ghoul
|
||||
13 = Phantom
|
||||
14 = Revenant
|
||||
*/
|
||||
public class LegacyTypeTable{
|
||||
*/
|
||||
private static final Prov[] build81Table = {
|
||||
Player::new,
|
||||
Fire::new,
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package io.anuke.mindustry.io.versions;
|
||||
|
||||
import io.anuke.mindustry.ctype.ContentType;
|
||||
import io.anuke.mindustry.entities.traits.*;
|
||||
import io.anuke.mindustry.io.*;
|
||||
import io.anuke.mindustry.type.*;
|
||||
import io.anuke.mindustry.type.TypeID;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
@@ -5,11 +5,13 @@ import io.anuke.arc.collection.*;
|
||||
import io.anuke.arc.files.*;
|
||||
import io.anuke.arc.graphics.*;
|
||||
import io.anuke.arc.util.*;
|
||||
import io.anuke.arc.util.ArcAnnotate.*;
|
||||
import io.anuke.mindustry.*;
|
||||
import io.anuke.mindustry.game.EventType.*;
|
||||
import io.anuke.mindustry.game.*;
|
||||
import io.anuke.mindustry.io.*;
|
||||
import io.anuke.mindustry.maps.filters.*;
|
||||
import io.anuke.mindustry.mod.Mods.*;
|
||||
import io.anuke.mindustry.type.*;
|
||||
|
||||
import static io.anuke.mindustry.Vars.*;
|
||||
@@ -20,7 +22,7 @@ public class Map implements Comparable<Map>, Publishable{
|
||||
/** Metadata. Author description, display name, etc. */
|
||||
public final StringMap tags;
|
||||
/** Base file of this map. File can be named anything at all. */
|
||||
public final FileHandle file;
|
||||
public final Fi file;
|
||||
/** Format version. */
|
||||
public final int version;
|
||||
/** Whether this map is managed, e.g. downloaded from the Steam workshop.*/
|
||||
@@ -35,8 +37,10 @@ public class Map implements Comparable<Map>, Publishable{
|
||||
public IntSet teams = new IntSet();
|
||||
/** Number of enemy spawns on this map.*/
|
||||
public int spawns = 0;
|
||||
/** Associated mod. If null, no mod is associated. */
|
||||
public @Nullable LoadedMod mod;
|
||||
|
||||
public Map(FileHandle file, int width, int height, StringMap tags, boolean custom, int version, int build){
|
||||
public Map(Fi file, int width, int height, StringMap tags, boolean custom, int version, int build){
|
||||
this.custom = custom;
|
||||
this.tags = tags;
|
||||
this.file = file;
|
||||
@@ -46,11 +50,11 @@ public class Map implements Comparable<Map>, Publishable{
|
||||
this.build = build;
|
||||
}
|
||||
|
||||
public Map(FileHandle file, int width, int height, StringMap tags, boolean custom, int version){
|
||||
public Map(Fi file, int width, int height, StringMap tags, boolean custom, int version){
|
||||
this(file, width, height, tags, custom, version, -1);
|
||||
}
|
||||
|
||||
public Map(FileHandle file, int width, int height, StringMap tags, boolean custom){
|
||||
public Map(Fi file, int width, int height, StringMap tags, boolean custom){
|
||||
this(file, width, height, tags, custom, -1);
|
||||
}
|
||||
|
||||
@@ -66,11 +70,11 @@ public class Map implements Comparable<Map>, Publishable{
|
||||
return texture == null ? Core.assets.get("sprites/error.png") : texture;
|
||||
}
|
||||
|
||||
public FileHandle previewFile(){
|
||||
public Fi previewFile(){
|
||||
return Vars.mapPreviewDirectory.child((workshop ? file.parent().name() : file.nameWithoutExtension()) + ".png");
|
||||
}
|
||||
|
||||
public FileHandle cacheFile(){
|
||||
public Fi cacheFile(){
|
||||
return Vars.mapPreviewDirectory.child(workshop ? file.parent().name() + "-workshop-cache.dat" : file.nameWithoutExtension() + "-cache.dat");
|
||||
}
|
||||
|
||||
@@ -180,14 +184,14 @@ public class Map implements Comparable<Map>, Publishable{
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileHandle createSteamFolder(String id){
|
||||
FileHandle mapFile = tmpDirectory.child("map_" + id).child("map.msav");
|
||||
public Fi createSteamFolder(String id){
|
||||
Fi mapFile = tmpDirectory.child("map_" + id).child("map.msav");
|
||||
file.copyTo(mapFile);
|
||||
return mapFile.parent();
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileHandle createSteamPreview(String id){
|
||||
public Fi createSteamPreview(String id){
|
||||
return previewFile();
|
||||
}
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ public class MapPreviewLoader extends TextureLoader{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadAsync(AssetManager manager, String fileName, FileHandle file, TextureParameter parameter){
|
||||
public void loadAsync(AssetManager manager, String fileName, Fi file, TextureParameter parameter){
|
||||
try{
|
||||
super.loadAsync(manager, fileName, file.sibling(file.nameWithoutExtension()), parameter);
|
||||
}catch(Exception e){
|
||||
@@ -28,7 +28,7 @@ public class MapPreviewLoader extends TextureLoader{
|
||||
}
|
||||
|
||||
@Override
|
||||
public Texture loadSync(AssetManager manager, String fileName, FileHandle file, TextureParameter parameter){
|
||||
public Texture loadSync(AssetManager manager, String fileName, Fi file, TextureParameter parameter){
|
||||
try{
|
||||
return super.loadSync(manager, fileName, file, parameter);
|
||||
}catch(Throwable e){
|
||||
@@ -43,7 +43,7 @@ public class MapPreviewLoader extends TextureLoader{
|
||||
}
|
||||
|
||||
@Override
|
||||
public Array<AssetDescriptor> getDependencies(String fileName, FileHandle file, TextureParameter parameter){
|
||||
public Array<AssetDescriptor> getDependencies(String fileName, Fi file, TextureParameter parameter){
|
||||
return Array.with(new AssetDescriptor<>("contentcreate", Content.class));
|
||||
}
|
||||
|
||||
|
||||
@@ -84,6 +84,18 @@ public class Maps{
|
||||
maps.sort();
|
||||
});
|
||||
|
||||
Events.on(ContentReloadEvent.class, event -> {
|
||||
reload();
|
||||
for(Map map : maps){
|
||||
try{
|
||||
map.texture = map.previewFile().exists() ? new Texture(map.previewFile()) : new Texture(MapIO.generatePreview(map));
|
||||
readCache(map);
|
||||
}catch(Exception e){
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if(Core.assets != null){
|
||||
((CustomLoader)Core.assets.getLoader(Content.class)).loaded = this::createAllPreviews;
|
||||
}
|
||||
@@ -94,7 +106,7 @@ public class Maps{
|
||||
* Does not add this map to the map list.
|
||||
*/
|
||||
public Map loadInternalMap(String name){
|
||||
FileHandle file = tree.get("maps/" + name + "." + mapExtension);
|
||||
Fi file = tree.get("maps/" + name + "." + mapExtension);
|
||||
|
||||
try{
|
||||
return MapIO.createMap(file, false);
|
||||
@@ -108,7 +120,7 @@ public class Maps{
|
||||
//defaults; must work
|
||||
try{
|
||||
for(String name : defaultMapNames){
|
||||
FileHandle file = Core.files.internal("maps/" + name + "." + mapExtension);
|
||||
Fi file = Core.files.internal("maps/" + name + "." + mapExtension);
|
||||
loadMap(file, false);
|
||||
}
|
||||
}catch(IOException e){
|
||||
@@ -116,7 +128,7 @@ public class Maps{
|
||||
}
|
||||
|
||||
//custom
|
||||
for(FileHandle file : customMapDirectory.list()){
|
||||
for(Fi file : customMapDirectory.list()){
|
||||
try{
|
||||
if(file.extension().equalsIgnoreCase(mapExtension)){
|
||||
loadMap(file, true);
|
||||
@@ -128,7 +140,7 @@ public class Maps{
|
||||
}
|
||||
|
||||
//workshop
|
||||
for(FileHandle file : platform.getWorkshopContent(Map.class)){
|
||||
for(Fi file : platform.getWorkshopContent(Map.class)){
|
||||
try{
|
||||
Map map = loadMap(file, false);
|
||||
map.workshop = true;
|
||||
@@ -138,6 +150,17 @@ public class Maps{
|
||||
Log.err(e);
|
||||
}
|
||||
}
|
||||
|
||||
//mod
|
||||
mods.listFiles("maps", (mod, file) -> {
|
||||
try{
|
||||
Map map = loadMap(file, false);
|
||||
map.mod = mod;
|
||||
}catch(Exception e){
|
||||
Log.err("Failed to load mod map file '{0}'!", file);
|
||||
Log.err(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void reload(){
|
||||
@@ -161,7 +184,7 @@ public class Maps{
|
||||
StringMap tags = new StringMap(baseTags);
|
||||
String name = tags.get("name");
|
||||
if(name == null) throw new IllegalArgumentException("Can't save a map with no name. How did this happen?");
|
||||
FileHandle file;
|
||||
Fi file;
|
||||
|
||||
//find map with the same exact display name
|
||||
Map other = maps.find(m -> m.name().equals(name));
|
||||
@@ -222,8 +245,8 @@ public class Maps{
|
||||
}
|
||||
|
||||
/** Import a map, then save it. This updates all values and stored data necessary. */
|
||||
public void importMap(FileHandle file) throws IOException{
|
||||
FileHandle dest = findFile();
|
||||
public void importMap(Fi file) throws IOException{
|
||||
Fi dest = findFile();
|
||||
file.copyTo(dest);
|
||||
|
||||
Map map = loadMap(dest, true);
|
||||
@@ -424,7 +447,7 @@ public class Maps{
|
||||
}
|
||||
|
||||
/** Find a new filename to put a map to. */
|
||||
private FileHandle findFile(){
|
||||
private Fi findFile(){
|
||||
//find a map name that isn't used.
|
||||
int i = maps.size;
|
||||
while(customMapDirectory.child("map_" + i + "." + mapExtension).exists()){
|
||||
@@ -433,7 +456,7 @@ public class Maps{
|
||||
return customMapDirectory.child("map_" + i + "." + mapExtension);
|
||||
}
|
||||
|
||||
private Map loadMap(FileHandle file, boolean custom) throws IOException{
|
||||
private Map loadMap(Fi file, boolean custom) throws IOException{
|
||||
Map map = MapIO.createMap(file, custom);
|
||||
|
||||
if(map.name() == null){
|
||||
|
||||
@@ -13,15 +13,15 @@ import io.anuke.mindustry.ui.dialogs.*;
|
||||
import io.anuke.mindustry.world.*;
|
||||
import io.anuke.mindustry.world.blocks.*;
|
||||
|
||||
import static io.anuke.mindustry.Vars.updateEditorOnChange;
|
||||
import static io.anuke.mindustry.Vars.*;
|
||||
|
||||
public abstract class FilterOption{
|
||||
public static final Boolf<Block> floorsOnly = b -> (b instanceof Floor && !(b instanceof OverlayFloor)) && Core.atlas.isFound(b.icon(io.anuke.mindustry.ui.Cicon.full));
|
||||
public static final Boolf<Block> wallsOnly = b -> (!b.synthetic() && !(b instanceof Floor)) && Core.atlas.isFound(b.icon(io.anuke.mindustry.ui.Cicon.full));
|
||||
public static final Boolf<Block> floorsOptional = b -> b == Blocks.air || ((b instanceof Floor && !(b instanceof OverlayFloor)) && Core.atlas.isFound(b.icon(io.anuke.mindustry.ui.Cicon.full)));
|
||||
public static final Boolf<Block> wallsOptional = b -> b == Blocks.air || ((!b.synthetic() && !(b instanceof Floor)) && Core.atlas.isFound(b.icon(io.anuke.mindustry.ui.Cicon.full)));
|
||||
public static final Boolf<Block> wallsOresOptional = b -> b == Blocks.air || (((!b.synthetic() && !(b instanceof Floor)) || (b instanceof OverlayFloor)) && Core.atlas.isFound(b.icon(io.anuke.mindustry.ui.Cicon.full)));
|
||||
public static final Boolf<Block> oresOnly = b -> b instanceof OverlayFloor && Core.atlas.isFound(b.icon(io.anuke.mindustry.ui.Cicon.full));
|
||||
public static final Boolf<Block> floorsOnly = b -> (b instanceof Floor && !(b instanceof OverlayFloor)) && !headless && Core.atlas.isFound(b.icon(io.anuke.mindustry.ui.Cicon.full));
|
||||
public static final Boolf<Block> wallsOnly = b -> (!b.synthetic() && !(b instanceof Floor)) && !headless && Core.atlas.isFound(b.icon(io.anuke.mindustry.ui.Cicon.full));
|
||||
public static final Boolf<Block> floorsOptional = b -> b == Blocks.air || ((b instanceof Floor && !(b instanceof OverlayFloor)) && !headless && Core.atlas.isFound(b.icon(io.anuke.mindustry.ui.Cicon.full)));
|
||||
public static final Boolf<Block> wallsOptional = b -> b == Blocks.air || ((!b.synthetic() && !(b instanceof Floor)) && !headless && Core.atlas.isFound(b.icon(io.anuke.mindustry.ui.Cicon.full)));
|
||||
public static final Boolf<Block> wallsOresOptional = b -> b == Blocks.air || (((!b.synthetic() && !(b instanceof Floor)) || (b instanceof OverlayFloor)) && !headless && Core.atlas.isFound(b.icon(io.anuke.mindustry.ui.Cicon.full)));
|
||||
public static final Boolf<Block> oresOnly = b -> b instanceof OverlayFloor && !headless && Core.atlas.isFound(b.icon(io.anuke.mindustry.ui.Cicon.full));
|
||||
public static final Boolf<Block> anyOptional = b -> floorsOnly.get(b) || wallsOnly.get(b) || oresOnly.get(b) || b == Blocks.air;
|
||||
|
||||
public abstract void build(Table table);
|
||||
|
||||
7
core/src/io/anuke/mindustry/mod/ClassAccess.java
Normal file
7
core/src/io/anuke/mindustry/mod/ClassAccess.java
Normal file
File diff suppressed because one or more lines are too long
@@ -36,9 +36,21 @@ import java.lang.reflect.*;
|
||||
public class ContentParser{
|
||||
private static final boolean ignoreUnknownFields = true;
|
||||
private ObjectMap<Class<?>, ContentType> contentTypes = new ObjectMap<>();
|
||||
private StringMap legacyUnitMap = StringMap.of(
|
||||
"Dagger", "GroundUnit",
|
||||
"Eruptor", "GroundUnit",
|
||||
"Titan", "GroundUnit",
|
||||
"Fortress", "GroundUnit",
|
||||
"Crawler", "GroundUnit",
|
||||
"Revenant", "HoverUnit",
|
||||
"Draug", "MinerDrone",
|
||||
"Phantom", "BuilderDrone",
|
||||
"Spirit", "RepairDrone",
|
||||
"Wraith", "FlyingUnit",
|
||||
"Ghoul", "FlyingUnit"
|
||||
);
|
||||
private ObjectMap<Class<?>, FieldParser> classParsers = new ObjectMap<Class<?>, FieldParser>(){{
|
||||
put(Effect.class, (type, data) -> field(Fx.class, data));
|
||||
put(StatusEffect.class, (type, data) -> field(StatusEffects.class, data));
|
||||
put(Schematic.class, (type, data) -> {
|
||||
Object result = fieldOpt(Loadouts.class, data);
|
||||
if(result != null){
|
||||
@@ -52,6 +64,15 @@ public class ContentParser{
|
||||
}
|
||||
}
|
||||
});
|
||||
put(StatusEffect.class, (type, data) -> {
|
||||
Object result = fieldOpt(StatusEffects.class, data);
|
||||
if(result != null){
|
||||
return result;
|
||||
}
|
||||
StatusEffect effect = new StatusEffect(currentMod.name + "-" + data.getString("name"));
|
||||
readFields(effect, data);
|
||||
return effect;
|
||||
});
|
||||
put(Color.class, (type, data) -> Color.valueOf(data.asString()));
|
||||
put(BulletType.class, (type, data) -> {
|
||||
if(data.isString()){
|
||||
@@ -116,26 +137,20 @@ public class ContentParser{
|
||||
}
|
||||
|
||||
//try to parse "item/amount" syntax
|
||||
try{
|
||||
if(type == ItemStack.class && jsonData.isString() && jsonData.asString().contains("/")){
|
||||
String[] split = jsonData.asString().split("/");
|
||||
if(type == ItemStack.class && jsonData.isString() && jsonData.asString().contains("/")){
|
||||
String[] split = jsonData.asString().split("/");
|
||||
|
||||
return (T)fromJson(ItemStack.class, "{item: " + split[0] + ", amount: " + split[1] + "}");
|
||||
}
|
||||
}catch(Throwable ignored){
|
||||
return (T)fromJson(ItemStack.class, "{item: " + split[0] + ", amount: " + split[1] + "}");
|
||||
}
|
||||
|
||||
//try to parse "liquid/amount" syntax
|
||||
try{
|
||||
if(jsonData.isString() && jsonData.asString().contains("/")){
|
||||
String[] split = jsonData.asString().split("/");
|
||||
if(type == LiquidStack.class){
|
||||
return (T)fromJson(LiquidStack.class, "{liquid: " + split[0] + ", amount: " + split[1] + "}");
|
||||
}else if(type == ConsumeLiquid.class){
|
||||
return (T)fromJson(ConsumeLiquid.class, "{liquid: " + split[0] + ", amount: " + split[1] + "}");
|
||||
}
|
||||
if(jsonData.isString() && jsonData.asString().contains("/")){
|
||||
String[] split = jsonData.asString().split("/");
|
||||
if(type == LiquidStack.class){
|
||||
return (T)fromJson(LiquidStack.class, "{liquid: " + split[0] + ", amount: " + split[1] + "}");
|
||||
}else if(type == ConsumeLiquid.class){
|
||||
return (T)fromJson(ConsumeLiquid.class, "{liquid: " + split[0] + ", amount: " + split[1] + "}");
|
||||
}
|
||||
}catch(Throwable ignored){
|
||||
}
|
||||
|
||||
if(Content.class.isAssignableFrom(type)){
|
||||
@@ -146,7 +161,7 @@ public class ContentParser{
|
||||
T two = (T)Vars.content.getByName(ctype, jsonData.asString());
|
||||
|
||||
if(two != null) return two;
|
||||
throw new IllegalArgumentException("\"" + jsonData.name + "\": No " + ctype + " found with name '" + jsonData.asString() + "'.");
|
||||
throw new IllegalArgumentException("\"" + jsonData.name + "\": No " + ctype + " found with name '" + jsonData.asString() + "'.\nMake sure '" + jsonData.asString() + "' is spelled correctly, and that it really exists!\nThis may also occur because its file failed to parse.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -160,28 +175,34 @@ public class ContentParser{
|
||||
|
||||
Block block;
|
||||
|
||||
if(Vars.content.getByName(ContentType.block, name) != null){
|
||||
block = Vars.content.getByName(ContentType.block, name);
|
||||
if(locate(ContentType.block, name) != null){
|
||||
block = locate(ContentType.block, name);
|
||||
|
||||
if(value.has("type")){
|
||||
throw new IllegalArgumentException("When overwriting an existing block, you must not re-declare its type. The original type will be used. Block: " + name);
|
||||
throw new IllegalArgumentException("When defining properties for an existing block, you must not re-declare its type. The original type will be used. Block: " + name);
|
||||
}
|
||||
}else{
|
||||
//TODO generate dynamically instead of doing.. this
|
||||
Class<? extends Block> type = resolve(getType(value),
|
||||
"io.anuke.mindustry.world",
|
||||
"io.anuke.mindustry.world.blocks",
|
||||
"io.anuke.mindustry.world.blocks.defense",
|
||||
"io.anuke.mindustry.world.blocks.defense.turrets",
|
||||
"io.anuke.mindustry.world.blocks.distribution",
|
||||
"io.anuke.mindustry.world.blocks.liquid",
|
||||
"io.anuke.mindustry.world.blocks.logic",
|
||||
"io.anuke.mindustry.world.blocks.power",
|
||||
"io.anuke.mindustry.world.blocks.production",
|
||||
"io.anuke.mindustry.world.blocks.sandbox",
|
||||
"io.anuke.mindustry.world.blocks.storage",
|
||||
"io.anuke.mindustry.world.blocks.units"
|
||||
);
|
||||
Class<? extends Block> type;
|
||||
|
||||
try{
|
||||
type = resolve(getType(value),
|
||||
"io.anuke.mindustry.world",
|
||||
"io.anuke.mindustry.world.blocks",
|
||||
"io.anuke.mindustry.world.blocks.defense",
|
||||
"io.anuke.mindustry.world.blocks.defense.turrets",
|
||||
"io.anuke.mindustry.world.blocks.distribution",
|
||||
"io.anuke.mindustry.world.blocks.liquid",
|
||||
"io.anuke.mindustry.world.blocks.logic",
|
||||
"io.anuke.mindustry.world.blocks.power",
|
||||
"io.anuke.mindustry.world.blocks.production",
|
||||
"io.anuke.mindustry.world.blocks.sandbox",
|
||||
"io.anuke.mindustry.world.blocks.storage",
|
||||
"io.anuke.mindustry.world.blocks.units"
|
||||
);
|
||||
}catch(IllegalArgumentException e){
|
||||
type = Block.class;
|
||||
}
|
||||
|
||||
block = make(type, mod + "-" + name);
|
||||
}
|
||||
@@ -222,15 +243,23 @@ public class ContentParser{
|
||||
|
||||
readFields(block, value, true);
|
||||
|
||||
if(block.size > 8){
|
||||
throw new IllegalArgumentException("Blocks cannot be larger than 8x8.");
|
||||
}
|
||||
|
||||
//add research tech node
|
||||
if(research[0] != null){
|
||||
Block parent = find(ContentType.block, research[0]);
|
||||
TechNode baseNode = TechTree.create(parent, block);
|
||||
LoadedMod cur = currentMod;
|
||||
|
||||
postreads.add(() -> {
|
||||
currentContent = block;
|
||||
currentMod = cur;
|
||||
|
||||
TechNode parnode = TechTree.all.find(t -> t.block == parent);
|
||||
if(parnode == null){
|
||||
throw new ModLoadException("Block '" + parent.name + "' isn't in the tech tree, but '" + block.name + "' requires it to be researched.", block);
|
||||
throw new IllegalArgumentException("Block '" + parent.name + "' isn't in the tech tree, but '" + block.name + "' requires it to be researched.");
|
||||
}
|
||||
if(!parnode.children.contains(baseNode)){
|
||||
parnode.children.add(baseNode);
|
||||
@@ -249,8 +278,14 @@ public class ContentParser{
|
||||
ContentType.unit, (TypeParser<UnitType>)(mod, name, value) -> {
|
||||
readBundle(ContentType.unit, name, value);
|
||||
|
||||
Class<BaseUnit> type = resolve(getType(value), "io.anuke.mindustry.entities.type.base");
|
||||
UnitType unit = new UnitType(mod + "-" + name, supply(type));
|
||||
UnitType unit;
|
||||
if(locate(ContentType.unit, name) == null){
|
||||
Class<BaseUnit> type = resolve(legacyUnitMap.get(Strings.capitalize(getType(value)), getType(value)), "io.anuke.mindustry.entities.type.base");
|
||||
unit = new UnitType(mod + "-" + name, supply(type));
|
||||
}else{
|
||||
unit = locate(ContentType.unit, name);
|
||||
}
|
||||
|
||||
currentContent = unit;
|
||||
read(() -> readFields(unit, value, true));
|
||||
|
||||
@@ -266,7 +301,7 @@ public class ContentParser{
|
||||
if(value.has(key)){
|
||||
return value.getString(key);
|
||||
}else{
|
||||
throw new IllegalArgumentException((currentContent == null ? "" : currentContent.sourceFile + ": ") + "You are missing a \"" + key + "\". It must be added before the file can be parsed.");
|
||||
throw new IllegalArgumentException("You are missing a \"" + key + "\". It must be added before the file can be parsed.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -344,13 +379,18 @@ public class ContentParser{
|
||||
}
|
||||
}
|
||||
|
||||
public void finishParsing(){
|
||||
private void attempt(Runnable run){
|
||||
try{
|
||||
reads.each(Runnable::run);
|
||||
postreads.each(Runnable::run);
|
||||
}catch(Exception e){
|
||||
Vars.mods.handleError(new ModLoadException("Error occurred parsing content: " + currentContent, currentContent, e), currentMod);
|
||||
run.run();
|
||||
}catch(Throwable t){
|
||||
//don't overwrite double errors
|
||||
markError(currentContent, t);
|
||||
}
|
||||
}
|
||||
|
||||
public void finishParsing(){
|
||||
reads.each(this::attempt);
|
||||
postreads.each(this::attempt);
|
||||
reads.clear();
|
||||
postreads.clear();
|
||||
toBeParsed.clear();
|
||||
@@ -364,7 +404,7 @@ public class ContentParser{
|
||||
* @param file file that this content is being parsed from
|
||||
* @return the content that was parsed
|
||||
*/
|
||||
public Content parse(LoadedMod mod, String name, String json, FileHandle file, ContentType type) throws Exception{
|
||||
public Content parse(LoadedMod mod, String name, String json, Fi file, ContentType type) throws Exception{
|
||||
if(contentTypes.isEmpty()){
|
||||
init();
|
||||
}
|
||||
@@ -381,16 +421,56 @@ public class ContentParser{
|
||||
}
|
||||
|
||||
currentMod = mod;
|
||||
boolean exists = Vars.content.getByName(type, name) != null;
|
||||
boolean located = locate(type, name) != null;
|
||||
Content c = parsers.get(type).parse(mod.name, name, value);
|
||||
c.minfo.sourceFile = file;
|
||||
toBeParsed.add(c);
|
||||
if(!exists){
|
||||
c.sourceFile = file;
|
||||
c.mod = mod;
|
||||
|
||||
if(!located){
|
||||
c.minfo.mod = mod;
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
public void markError(Content content, LoadedMod mod, Fi file, Throwable error){
|
||||
content.minfo.mod = mod;
|
||||
content.minfo.sourceFile = file;
|
||||
content.minfo.error = makeError(error, file);
|
||||
content.minfo.baseError = error;
|
||||
if(mod != null){
|
||||
mod.erroredContent.add(content);
|
||||
}
|
||||
}
|
||||
|
||||
public void markError(Content content, Throwable error){
|
||||
if(content.minfo != null && !content.hasErrored()){
|
||||
markError(content, content.minfo.mod, content.minfo.sourceFile, error);
|
||||
}
|
||||
}
|
||||
|
||||
private String makeError(Throwable t, Fi file){
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append("[lightgray]").append("File: ").append(file.name()).append("[]\n\n");
|
||||
|
||||
if(t.getMessage() != null && t instanceof JsonParseException){
|
||||
builder.append("[accent][[JsonParse][] ").append(":\n").append(t.getMessage());
|
||||
}else{
|
||||
Array<Throwable> causes = Strings.getCauses(t);
|
||||
for(Throwable e : causes){
|
||||
builder.append("[accent][[").append(e.getClass().getSimpleName().replace("Exception", ""))
|
||||
.append("][] ")
|
||||
.append(e.getMessage() != null ?
|
||||
e.getMessage().replace("io.anuke.mindustry.", "").replace("io.anuke.arc.", "") : "").append("\n");
|
||||
}
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
private <T extends MappableContent> T locate(ContentType type, String name){
|
||||
T first = Vars.content.getByName(type, name); //try vanilla replacement
|
||||
return first != null ? first : Vars.content.getByName(type, currentMod.name + "-" + name);
|
||||
}
|
||||
|
||||
private <T> T make(Class<T> type){
|
||||
try{
|
||||
Constructor<T> cons = type.getDeclaredConstructor();
|
||||
@@ -478,7 +558,7 @@ public class ContentParser{
|
||||
FieldMetadata metadata = fields.get(child.name().replace(" ", "_"));
|
||||
if(metadata == null){
|
||||
if(ignoreUnknownFields){
|
||||
Log.err("{0}: Ignoring unknown field: " + child.name + " (" + type.getName() + ")", object);
|
||||
Log.warn("{0}: Ignoring unknown field: " + child.name + " (" + type.getName() + ")", object);
|
||||
continue;
|
||||
}else{
|
||||
SerializationException ex = new SerializationException("Field not found: " + child.name + " (" + type.getName() + ")");
|
||||
|
||||
@@ -6,7 +6,7 @@ import io.anuke.mindustry.*;
|
||||
|
||||
public class Mod{
|
||||
/** @return the config file for this plugin, as the file 'mods/[plugin-name]/config.json'.*/
|
||||
public FileHandle getConfig(){
|
||||
public Fi getConfig(){
|
||||
return Vars.mods.getConfig(this);
|
||||
}
|
||||
|
||||
@@ -15,11 +15,6 @@ public class Mod{
|
||||
|
||||
}
|
||||
|
||||
/** Create any content needed here. */
|
||||
public void loadContent(){
|
||||
|
||||
}
|
||||
|
||||
/** Register any commands to be used on the server side, e.g. from the console. */
|
||||
public void registerServerCommands(CommandHandler handler){
|
||||
|
||||
|
||||
@@ -1,67 +0,0 @@
|
||||
package io.anuke.mindustry.mod;
|
||||
|
||||
import io.anuke.arc.*;
|
||||
import io.anuke.arc.collection.*;
|
||||
import io.anuke.arc.graphics.*;
|
||||
import io.anuke.arc.graphics.g2d.*;
|
||||
import io.anuke.arc.math.*;
|
||||
import io.anuke.arc.scene.ui.layout.*;
|
||||
import io.anuke.arc.util.*;
|
||||
import io.anuke.mindustry.graphics.*;
|
||||
import io.anuke.mindustry.mod.Mods.*;
|
||||
import io.anuke.mindustry.ui.*;
|
||||
|
||||
public class ModCrashHandler{
|
||||
|
||||
public static void handle(Throwable t){
|
||||
Array<Throwable> list = Strings.getCauses(t);
|
||||
Throwable modCause = list.find(e -> e instanceof ModLoadException);
|
||||
|
||||
if(modCause != null && Fonts.outline != null){
|
||||
String text = "[scarlet][[A fatal crash has occured while loading a mod!][]\n\nReason:[accent] " + modCause.getMessage();
|
||||
String bottom = "[scarlet]The associated mod has been disabled. Swipe out of the app and launch it again.";
|
||||
GlyphLayout layout = new GlyphLayout();
|
||||
Core.atlas = TextureAtlas.blankAtlas();
|
||||
Colors.put("accent", Pal.accent);
|
||||
|
||||
Core.app.addListener(new ApplicationListener(){
|
||||
@Override
|
||||
public void update(){
|
||||
Core.graphics.clear(0.1f, 0.1f, 0.1f, 1f);
|
||||
float rad = Math.min(Core.graphics.getWidth(), Core.graphics.getHeight()) / 2f / 1.3f;
|
||||
Draw.color(Color.scarlet, Color.black, Mathf.absin(Core.graphics.getFrameId(), 15f, 0.6f));
|
||||
Lines.stroke(Scl.scl(40f));
|
||||
//Lines.poly2(Core.graphics.getWidth()/2f, Core.graphics.getHeight()/2f, 3, rad, 0f);
|
||||
float cx = Core.graphics.getWidth()/2f, cy = Core.graphics.getHeight()/2f;
|
||||
for(int i = 0; i < 3; i++){
|
||||
float angle1 = i * 120f + 90f;
|
||||
float angle2 = (i + 1) * 120f + 90f;
|
||||
Tmp.v1.trnsExact(angle1, rad - Lines.getStroke()/2f).add(cx, cy);
|
||||
Tmp.v2.trnsExact(angle2, rad - Lines.getStroke()/2f).add(cx, cy);
|
||||
Tmp.v3.trnsExact(angle1, rad + Lines.getStroke()/2f).add(cx, cy);
|
||||
Tmp.v4.trnsExact(angle2, rad + Lines.getStroke()/2f).add(cx, cy);
|
||||
Fill.quad(Tmp.v1.x, Tmp.v1.y, Tmp.v2.x, Tmp.v2.y, Tmp.v4.x, Tmp.v4.y, Tmp.v3.x, Tmp.v3.y);
|
||||
}
|
||||
Lines.lineAngleCenter(Core.graphics.getWidth()/2f, Core.graphics.getHeight()/2f - Scl.scl(5f), 90f, rad/3.1f);
|
||||
Fill.square(Core.graphics.getWidth()/2f, Core.graphics.getHeight()/2f + rad/2f - Scl.scl(15f), Lines.getStroke()/2f);
|
||||
Draw.reset();
|
||||
|
||||
Fonts.outline.getData().markupEnabled = true;
|
||||
layout.setText(Fonts.outline, text, Color.white, Core.graphics.getWidth(), Align.left, true);
|
||||
Fonts.outline.draw(text, Core.graphics.getWidth()/2f - layout.width/2f, Core.graphics.getHeight() - Scl.scl(50f), Core.graphics.getWidth(), Align.left, true);
|
||||
|
||||
layout.setText(Fonts.outline, bottom, Color.white, Core.graphics.getWidth(), Align.left, true);
|
||||
Fonts.outline.draw(bottom, Core.graphics.getWidth()/2f - layout.width/2f, layout.height + Scl.scl(10f), Core.graphics.getWidth(), Align.left, true);
|
||||
Draw.flush();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resize(int width, int height){
|
||||
Draw.proj().setOrtho(0, 0, width, height);
|
||||
}
|
||||
});
|
||||
}else{
|
||||
throw new RuntimeException(t);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,8 +9,9 @@ import io.anuke.arc.graphics.*;
|
||||
import io.anuke.arc.graphics.Texture.*;
|
||||
import io.anuke.arc.graphics.g2d.*;
|
||||
import io.anuke.arc.graphics.g2d.TextureAtlas.*;
|
||||
import io.anuke.arc.util.ArcAnnotate.*;
|
||||
import io.anuke.arc.scene.ui.*;
|
||||
import io.anuke.arc.util.*;
|
||||
import io.anuke.arc.util.ArcAnnotate.*;
|
||||
import io.anuke.arc.util.io.*;
|
||||
import io.anuke.arc.util.serialization.*;
|
||||
import io.anuke.arc.util.serialization.Jval.*;
|
||||
@@ -22,6 +23,7 @@ import io.anuke.mindustry.graphics.*;
|
||||
import io.anuke.mindustry.graphics.MultiPacker.*;
|
||||
import io.anuke.mindustry.plugin.*;
|
||||
import io.anuke.mindustry.type.*;
|
||||
import io.anuke.mindustry.ui.*;
|
||||
|
||||
import java.io.*;
|
||||
import java.net.*;
|
||||
@@ -30,41 +32,58 @@ import static io.anuke.mindustry.Vars.*;
|
||||
|
||||
public class Mods implements Loadable{
|
||||
private Json json = new Json();
|
||||
private @Nullable Scripts scripts;
|
||||
private ContentParser parser = new ContentParser();
|
||||
private ObjectMap<String, Array<FileHandle>> bundles = new ObjectMap<>();
|
||||
private ObjectSet<String> specialFolders = ObjectSet.with("bundles", "sprites");
|
||||
private ObjectMap<String, Array<Fi>> bundles = new ObjectMap<>();
|
||||
private ObjectSet<String> specialFolders = ObjectSet.with("bundles", "sprites", "sprites-override");
|
||||
|
||||
private int totalSprites;
|
||||
private MultiPacker packer;
|
||||
|
||||
private Array<LoadedMod> loaded = new Array<>();
|
||||
private Array<LoadedMod> disabled = new Array<>();
|
||||
private Array<LoadedMod> mods = new Array<>();
|
||||
private ObjectMap<Class<?>, ModMeta> metas = new ObjectMap<>();
|
||||
private boolean requiresReload;
|
||||
|
||||
public Mods(){
|
||||
Events.on(ClientLoadEvent.class, e -> Core.app.post(this::checkWarnings));
|
||||
Events.on(ContentReloadEvent.class, e -> Core.app.post(this::checkWarnings));
|
||||
}
|
||||
|
||||
/** Returns a file named 'config.json' in a special folder for the specified plugin.
|
||||
* Call this in init(). */
|
||||
public FileHandle getConfig(Mod mod){
|
||||
public Fi getConfig(Mod mod){
|
||||
ModMeta load = metas.get(mod.getClass());
|
||||
if(load == null) throw new IllegalArgumentException("Mod is not loaded yet (or missing)!");
|
||||
return modDirectory.child(load.name).child("config.json");
|
||||
}
|
||||
|
||||
/** Returns a list of files per mod subdirectory. */
|
||||
public void listFiles(String directory, Cons2<LoadedMod, Fi> cons){
|
||||
eachEnabled(mod -> {
|
||||
Fi file = mod.root.child(directory);
|
||||
if(file.exists()){
|
||||
for(Fi child : file.list()){
|
||||
cons.get(mod, child);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/** @return the loaded mod found by class, or null if not found. */
|
||||
public @Nullable LoadedMod getMod(Class<? extends Mod> type){
|
||||
return loaded.find(l -> l.mod != null && l.mod.getClass() == type);
|
||||
return mods.find(m -> m.enabled() && m.main != null && m.main.getClass() == type);//loaded.find(l -> l.mod != null && l.mod.getClass() == type);
|
||||
}
|
||||
|
||||
/** Imports an external mod file.*/
|
||||
public void importMod(FileHandle file) throws IOException{
|
||||
FileHandle dest = modDirectory.child(file.name());
|
||||
public void importMod(Fi file) throws IOException{
|
||||
Fi dest = modDirectory.child(file.name());
|
||||
if(dest.exists()){
|
||||
throw new IOException("A mod with the same filename already exists!");
|
||||
}
|
||||
|
||||
file.copyTo(dest);
|
||||
try{
|
||||
loaded.add(loadMod(dest));
|
||||
mods.add(loadMod(dest));
|
||||
requiresReload = true;
|
||||
}catch(IOException e){
|
||||
dest.delete();
|
||||
@@ -78,19 +97,19 @@ public class Mods implements Loadable{
|
||||
/** Repacks all in-game sprites. */
|
||||
@Override
|
||||
public void loadAsync(){
|
||||
if(loaded.isEmpty()) return;
|
||||
if(!mods.contains(LoadedMod::enabled)) return;
|
||||
Time.mark();
|
||||
|
||||
packer = new MultiPacker();
|
||||
|
||||
for(LoadedMod mod : loaded){
|
||||
Array<FileHandle> sprites = mod.root.child("sprites").findAll(f -> f.extension().equals("png"));
|
||||
Array<FileHandle> overrides = mod.root.child("sprites-override").findAll(f -> f.extension().equals("png"));
|
||||
eachEnabled(mod -> {
|
||||
Array<Fi> sprites = mod.root.child("sprites").findAll(f -> f.extension().equals("png"));
|
||||
Array<Fi> overrides = mod.root.child("sprites-override").findAll(f -> f.extension().equals("png"));
|
||||
packSprites(sprites, mod, true);
|
||||
packSprites(overrides, mod, false);
|
||||
Log.info("Packed {0} images for mod '{1}'.", sprites.size + overrides.size, mod.meta.name);
|
||||
Log.debug("Packed {0} images for mod '{1}'.", sprites.size + overrides.size, mod.meta.name);
|
||||
totalSprites += sprites.size + overrides.size;
|
||||
}
|
||||
});
|
||||
|
||||
for(AtlasRegion region : Core.atlas.getRegions()){
|
||||
PageType type = getPage(region);
|
||||
@@ -99,11 +118,11 @@ public class Mods implements Loadable{
|
||||
}
|
||||
}
|
||||
|
||||
Log.info("Time to pack textures: {0}", Time.elapsed());
|
||||
Log.debug("Time to pack textures: {0}", Time.elapsed());
|
||||
}
|
||||
|
||||
private void packSprites(Array<FileHandle> sprites, LoadedMod mod, boolean prefix){
|
||||
for(FileHandle file : sprites){
|
||||
private void packSprites(Array<Fi> sprites, LoadedMod mod, boolean prefix){
|
||||
for(Fi file : sprites){
|
||||
try(InputStream stream = file.read()){
|
||||
byte[] bytes = Streams.copyStreamToByteArray(stream, Math.max((int)file.length(), 512));
|
||||
Pixmap pixmap = new Pixmap(bytes, 0, bytes.length);
|
||||
@@ -136,7 +155,7 @@ public class Mods implements Loadable{
|
||||
//generate new icons
|
||||
for(Array<Content> arr : content.getContentMap()){
|
||||
arr.each(c -> {
|
||||
if(c instanceof UnlockableContent && c.mod != null){
|
||||
if(c instanceof UnlockableContent && c.minfo.mod != null){
|
||||
UnlockableContent u = (UnlockableContent)c;
|
||||
u.createIcons(packer);
|
||||
}
|
||||
@@ -145,12 +164,12 @@ public class Mods implements Loadable{
|
||||
|
||||
Core.atlas = packer.flush(filter, new TextureAtlas());
|
||||
Core.atlas.setErrorRegion("error");
|
||||
Log.info("Total pages: {0}", Core.atlas.getTextures().size);
|
||||
Log.debug("Total pages: {0}", Core.atlas.getTextures().size);
|
||||
}
|
||||
|
||||
packer.dispose();
|
||||
packer = null;
|
||||
Log.info("Time to update textures: {0}", Time.elapsed());
|
||||
Log.debug("Time to update textures: {0}", Time.elapsed());
|
||||
}
|
||||
|
||||
private PageType getPage(AtlasRegion region){
|
||||
@@ -163,7 +182,7 @@ public class Mods implements Loadable{
|
||||
PageType.main;
|
||||
}
|
||||
|
||||
private PageType getPage(FileHandle file){
|
||||
private PageType getPage(Fi file){
|
||||
String parent = file.parent().name();
|
||||
return
|
||||
parent.equals("environment") ? PageType.environment :
|
||||
@@ -175,7 +194,7 @@ public class Mods implements Loadable{
|
||||
|
||||
/** Removes a mod file and marks it for requiring a restart. */
|
||||
public void removeMod(LoadedMod mod){
|
||||
if(mod.root instanceof ZipFileHandle){
|
||||
if(mod.root instanceof ZipFi){
|
||||
mod.root.delete();
|
||||
}
|
||||
|
||||
@@ -185,28 +204,33 @@ public class Mods implements Loadable{
|
||||
ui.showErrorMessage("$mod.delete.error");
|
||||
return;
|
||||
}
|
||||
loaded.remove(mod);
|
||||
disabled.remove(mod);
|
||||
mods.remove(mod);
|
||||
requiresReload = true;
|
||||
}
|
||||
|
||||
public Scripts getScripts(){
|
||||
if(scripts == null) scripts = platform.createScripts();
|
||||
return scripts;
|
||||
}
|
||||
|
||||
/** @return whether the scripting engine has been initialized. */
|
||||
public boolean hasScripts(){
|
||||
return scripts != null;
|
||||
}
|
||||
|
||||
public boolean requiresReload(){
|
||||
return requiresReload;
|
||||
}
|
||||
|
||||
/** Loads all mods from the folder, but does not call any methods on them.*/
|
||||
public void load(){
|
||||
for(FileHandle file : modDirectory.list()){
|
||||
for(Fi file : modDirectory.list()){
|
||||
if(!file.extension().equals("jar") && !file.extension().equals("zip") && !(file.isDirectory() && (file.child("mod.json").exists() || file.child("mod.hjson").exists()))) continue;
|
||||
|
||||
Log.debug("[Mods] Loading mod {0}", file);
|
||||
try{
|
||||
LoadedMod mod = loadMod(file);
|
||||
if(mod.enabled() || headless){
|
||||
loaded.add(mod);
|
||||
}else{
|
||||
disabled.add(mod);
|
||||
}
|
||||
mods.add(mod);
|
||||
}catch(Exception e){
|
||||
Log.err("Failed to load mod file {0}. Skipping.", file);
|
||||
Log.err(e);
|
||||
@@ -214,14 +238,10 @@ public class Mods implements Loadable{
|
||||
}
|
||||
|
||||
//load workshop mods now
|
||||
for(FileHandle file : platform.getWorkshopContent(LoadedMod.class)){
|
||||
for(Fi file : platform.getWorkshopContent(LoadedMod.class)){
|
||||
try{
|
||||
LoadedMod mod = loadMod(file);
|
||||
if(mod.enabled()){
|
||||
loaded.add(mod);
|
||||
}else{
|
||||
disabled.add(mod);
|
||||
}
|
||||
mods.add(mod);
|
||||
mod.addSteamID(file.name());
|
||||
}catch(Exception e){
|
||||
Log.err("Failed to load mod workshop file {0}. Skipping.", file);
|
||||
@@ -229,28 +249,27 @@ public class Mods implements Loadable{
|
||||
}
|
||||
}
|
||||
|
||||
resolveDependencies();
|
||||
|
||||
//sort mods to make sure servers handle them properly.
|
||||
loaded.sort(Structs.comparing(m -> m.name));
|
||||
resolveModState();
|
||||
sortMods();
|
||||
|
||||
buildFiles();
|
||||
}
|
||||
|
||||
private void resolveDependencies(){
|
||||
Array<LoadedMod> incompatible = loaded.select(m -> !m.isSupported());
|
||||
loaded.removeAll(incompatible);
|
||||
disabled.addAll(incompatible);
|
||||
private void sortMods(){
|
||||
//sort mods to make sure servers handle them properly and they appear correctly in the dialog
|
||||
mods.sort(Structs.comps(Structs.comparingInt(m -> m.state.ordinal()), Structs.comparing(m -> m.name)));
|
||||
}
|
||||
|
||||
for(LoadedMod mod : Array.<LoadedMod>withArrays(loaded, disabled)){
|
||||
updateDependencies(mod);
|
||||
private void resolveModState(){
|
||||
mods.each(this::updateDependencies);
|
||||
|
||||
for(LoadedMod mod : mods){
|
||||
mod.state =
|
||||
!mod.isSupported() ? ModState.unsupported :
|
||||
mod.hasUnmetDependencies() ? ModState.missingDependencies :
|
||||
!mod.shouldBeEnabled() ? ModState.disabled :
|
||||
ModState.enabled;
|
||||
}
|
||||
|
||||
disabled.addAll(loaded.select(LoadedMod::hasUnmetDependencies));
|
||||
loaded.removeAll(LoadedMod::hasUnmetDependencies);
|
||||
disabled.each(mod -> setEnabled(mod, false));
|
||||
disabled.distinct();
|
||||
loaded.distinct();
|
||||
}
|
||||
|
||||
private void updateDependencies(LoadedMod mod){
|
||||
@@ -275,23 +294,23 @@ public class Mods implements Loadable{
|
||||
private Array<LoadedMod> orderedMods(){
|
||||
ObjectSet<LoadedMod> visited = new ObjectSet<>();
|
||||
Array<LoadedMod> result = new Array<>();
|
||||
for(LoadedMod mod : loaded){
|
||||
eachEnabled(mod -> {
|
||||
if(!visited.contains(mod)){
|
||||
topoSort(mod, result, visited);
|
||||
}
|
||||
}
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
private LoadedMod locateMod(String name){
|
||||
return loaded.find(mod -> mod.name.equals(name));
|
||||
return mods.find(mod -> mod.enabled() && mod.name.equals(name));
|
||||
}
|
||||
|
||||
private void buildFiles(){
|
||||
for(LoadedMod mod : orderedMods()){
|
||||
boolean zipFolder = !mod.file.isDirectory() && mod.root.parent() != null;
|
||||
String parentName = zipFolder ? mod.root.name() : null;
|
||||
for(FileHandle file : mod.root.list()){
|
||||
for(Fi file : mod.root.list()){
|
||||
//ignore special folders like bundles or sprites
|
||||
if(file.isDirectory() && !specialFolders.contains(file.name())){
|
||||
//TODO calling child/parent on these files will give you gibberish; create wrapper class.
|
||||
@@ -301,9 +320,9 @@ public class Mods implements Loadable{
|
||||
}
|
||||
|
||||
//load up bundles.
|
||||
FileHandle folder = mod.root.child("bundles");
|
||||
Fi folder = mod.root.child("bundles");
|
||||
if(folder.exists()){
|
||||
for(FileHandle file : folder.list()){
|
||||
for(Fi file : folder.list()){
|
||||
if(file.name().startsWith("bundle") && file.extension().equals("properties")){
|
||||
String name = file.nameWithoutExtension();
|
||||
bundles.getOr(name, Array::new).add(file);
|
||||
@@ -317,50 +336,148 @@ public class Mods implements Loadable{
|
||||
while(bundle != null){
|
||||
String str = bundle.getLocale().toString();
|
||||
String locale = "bundle" + (str.isEmpty() ? "" : "_" + str);
|
||||
for(FileHandle file : bundles.getOr(locale, Array::new)){
|
||||
for(Fi file : bundles.getOr(locale, Array::new)){
|
||||
try{
|
||||
PropertiesUtils.load(bundle.getProperties(), file.reader());
|
||||
}catch(Exception e){
|
||||
throw new RuntimeException("Error loading bundle: " + file + "/" + locale, e);
|
||||
Log.err("Error loading bundle: " + file + "/" + locale, e);
|
||||
}
|
||||
}
|
||||
bundle = bundle.getParent();
|
||||
}
|
||||
}
|
||||
|
||||
/** Check all warnings related to content and show relevant dialogs. Client only. */
|
||||
private void checkWarnings(){
|
||||
//show 'scripts have errored' info
|
||||
if(scripts != null && scripts.hasErrored()){
|
||||
Core.settings.getBoolOnce("scripts-errored2", () -> ui.showErrorMessage("$mod.scripts.unsupported"));
|
||||
}
|
||||
|
||||
//show list of errored content
|
||||
if(mods.contains(LoadedMod::hasContentErrors)){
|
||||
ui.loadfrag.hide();
|
||||
new Dialog(""){{
|
||||
|
||||
setFillParent(true);
|
||||
cont.margin(15);
|
||||
cont.add("$error.title");
|
||||
cont.row();
|
||||
cont.addImage().width(300f).pad(2).colspan(2).height(4f).color(Color.scarlet);
|
||||
cont.row();
|
||||
cont.add("$mod.errors").wrap().growX().center().get().setAlignment(Align.center);
|
||||
cont.row();
|
||||
cont.pane(p -> {
|
||||
mods.each(m -> m.enabled() && m.hasContentErrors(), m -> {
|
||||
p.add(m.name).color(Pal.accent).left();
|
||||
p.row();
|
||||
p.addImage().fillX().pad(4).color(Pal.accent);
|
||||
p.row();
|
||||
p.table(d -> {
|
||||
d.left().marginLeft(15f);
|
||||
for(Content c : m.erroredContent){
|
||||
d.add(c.minfo.sourceFile.nameWithoutExtension()).left().padRight(10);
|
||||
d.addImageTextButton("$details", Icon.arrowDownSmall, Styles.transt, () -> {
|
||||
new Dialog(""){{
|
||||
setFillParent(true);
|
||||
cont.pane(e -> e.add(c.minfo.error)).grow();
|
||||
cont.row();
|
||||
cont.addImageTextButton("$ok", Icon.backSmall, this::hide).size(240f, 60f);
|
||||
}}.show();
|
||||
}).size(190f, 50f).left().marginLeft(6);
|
||||
d.row();
|
||||
}
|
||||
}).left();
|
||||
p.row();
|
||||
});
|
||||
});
|
||||
|
||||
cont.row();
|
||||
cont.addButton("$ok", this::hide).size(300, 50);
|
||||
}}.show();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean hasContentErrors(){
|
||||
return mods.contains(LoadedMod::hasContentErrors);
|
||||
}
|
||||
|
||||
/** Reloads all mod content. How does this even work? I refuse to believe that it functions correctly.*/
|
||||
public void reloadContent(){
|
||||
//epic memory leak
|
||||
//TODO make it less epic
|
||||
Core.atlas = new TextureAtlas(Core.files.internal("sprites/sprites.atlas"));
|
||||
|
||||
loaded.clear();
|
||||
disabled.clear();
|
||||
mods.clear();
|
||||
Core.bundle = I18NBundle.createBundle(Core.files.internal("bundles/bundle"), Core.bundle.getLocale());
|
||||
load();
|
||||
Sounds.dispose();
|
||||
Sounds.load();
|
||||
Core.assets.finishLoading();
|
||||
if(scripts != null){
|
||||
scripts.dispose();
|
||||
scripts = null;
|
||||
}
|
||||
content.clear();
|
||||
content.createContent();
|
||||
content.createBaseContent();
|
||||
content.loadColors();
|
||||
loadScripts();
|
||||
content.createModContent();
|
||||
loadAsync();
|
||||
loadSync();
|
||||
content.init();
|
||||
content.load();
|
||||
content.loadColors();
|
||||
data.load();
|
||||
Core.atlas.getTextures().each(t -> t.setFilter(Core.settings.getBool("linear") ? TextureFilter.Linear : TextureFilter.Nearest));
|
||||
requiresReload = false;
|
||||
|
||||
Events.fire(new ContentReloadEvent());
|
||||
}
|
||||
|
||||
/** This must be run on the main thread! */
|
||||
public void loadScripts(){
|
||||
Time.mark();
|
||||
|
||||
try{
|
||||
eachEnabled(mod -> {
|
||||
if(mod.root.child("scripts").exists()){
|
||||
content.setCurrentMod(mod);
|
||||
mod.scripts = mod.root.child("scripts").findAll(f -> f.extension().equals("js"));
|
||||
Log.debug("[{0}] Found {1} scripts.", mod.meta.name, mod.scripts.size);
|
||||
|
||||
for(Fi file : mod.scripts){
|
||||
try{
|
||||
if(scripts == null){
|
||||
scripts = platform.createScripts();
|
||||
}
|
||||
scripts.run(mod, file);
|
||||
}catch(Throwable e){
|
||||
Core.app.post(() -> {
|
||||
Log.err("Error loading script {0} for mod {1}.", file.name(), mod.meta.name);
|
||||
e.printStackTrace();
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}finally{
|
||||
content.setCurrentMod(null);
|
||||
}
|
||||
|
||||
Log.debug("Time to initialize modded scripts: {0}", Time.elapsed());
|
||||
}
|
||||
|
||||
/** Creates all the content found in mod files. */
|
||||
public void loadContent(){
|
||||
|
||||
class LoadRun implements Comparable<LoadRun>{
|
||||
final ContentType type;
|
||||
final FileHandle file;
|
||||
final Fi file;
|
||||
final LoadedMod mod;
|
||||
|
||||
public LoadRun(ContentType type, FileHandle file, LoadedMod mod){
|
||||
public LoadRun(ContentType type, Fi file, LoadedMod mod){
|
||||
this.type = type;
|
||||
this.file = file;
|
||||
this.mod = mod;
|
||||
@@ -378,11 +495,11 @@ public class Mods implements Loadable{
|
||||
|
||||
for(LoadedMod mod : orderedMods()){
|
||||
if(mod.root.child("content").exists()){
|
||||
FileHandle contentRoot = mod.root.child("content");
|
||||
Fi contentRoot = mod.root.child("content");
|
||||
for(ContentType type : ContentType.all){
|
||||
FileHandle folder = contentRoot.child(type.name().toLowerCase() + "s");
|
||||
Fi folder = contentRoot.child(type.name().toLowerCase() + "s");
|
||||
if(folder.exists()){
|
||||
for(FileHandle file : folder.list()){
|
||||
for(Fi file : folder.list()){
|
||||
if(file.extension().equals("json") || file.extension().equals("hjson")){
|
||||
runs.add(new LoadRun(type, file, mod));
|
||||
}
|
||||
@@ -394,59 +511,43 @@ public class Mods implements Loadable{
|
||||
|
||||
//make sure mod content is in proper order
|
||||
runs.sort();
|
||||
runs.each(l -> safeRun(l.mod, () -> {
|
||||
for(LoadRun l : runs){
|
||||
Content current = content.getLastAdded();
|
||||
try{
|
||||
//this binds the content but does not load it entirely
|
||||
Content loaded = parser.parse(l.mod, l.file.nameWithoutExtension(), l.file.readString("UTF-8"), l.file, l.type);
|
||||
Log.debug("[{0}] Loaded '{1}'.", l.mod.meta.name,
|
||||
(loaded instanceof UnlockableContent ? ((UnlockableContent)loaded).localizedName : loaded));
|
||||
}catch(Exception e){
|
||||
throw new RuntimeException("Failed to parse content file '" + l.file + "' for mod '" + l.mod.meta.name + "'.", e);
|
||||
Log.debug("[{0}] Loaded '{1}'.", l.mod.meta.name, (loaded instanceof UnlockableContent ? ((UnlockableContent)loaded).localizedName : loaded));
|
||||
}catch(Throwable e){
|
||||
if(current != content.getLastAdded() && content.getLastAdded() != null){
|
||||
parser.markError(content.getLastAdded(), l.mod, l.file, e);
|
||||
}else{
|
||||
ErrorContent error = new ErrorContent();
|
||||
parser.markError(error, l.mod, l.file, e);
|
||||
}
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
//this finishes parsing content fields
|
||||
parser.finishParsing();
|
||||
|
||||
//load content for code mods
|
||||
each(Mod::loadContent);
|
||||
}
|
||||
|
||||
/** @return all loaded mods. */
|
||||
public Array<LoadedMod> all(){
|
||||
return loaded;
|
||||
}
|
||||
|
||||
/** @return all disabled mods. */
|
||||
public Array<LoadedMod> disabled(){
|
||||
return disabled;
|
||||
}
|
||||
|
||||
/** @return a list of mod names only, without versions. */
|
||||
public Array<String> getModNames(){
|
||||
return loaded.select(l -> !l.meta.hidden).map(l -> l.name + ":" + l.meta.version);
|
||||
public void handleContentError(Content content, Throwable error){
|
||||
parser.markError(content, error);
|
||||
}
|
||||
|
||||
/** @return a list of mods and versions, in the format name:version. */
|
||||
public Array<String> getModStrings(){
|
||||
return loaded.select(l -> !l.meta.hidden).map(l -> l.name + ":" + l.meta.version);
|
||||
return mods.select(l -> !l.meta.hidden && l.enabled()).map(l -> l.name + ":" + l.meta.version);
|
||||
}
|
||||
|
||||
/** Makes a mod enabled or disabled. shifts it.*/
|
||||
public void setEnabled(LoadedMod mod, boolean enabled){
|
||||
if(mod.enabled() != enabled){
|
||||
Core.settings.putSave("mod-" + mod.name + "-enabled", enabled);
|
||||
Core.settings.save();
|
||||
requiresReload = true;
|
||||
if(!enabled){
|
||||
loaded.remove(mod);
|
||||
if(!disabled.contains(mod)) disabled.add(mod);
|
||||
}else{
|
||||
if(!loaded.contains(mod)) loaded.add(mod);
|
||||
disabled.remove(mod);
|
||||
}
|
||||
loaded.each(this::updateDependencies);
|
||||
disabled.each(this::updateDependencies);
|
||||
mod.state = enabled ? ModState.enabled : ModState.disabled;
|
||||
mods.each(this::updateDependencies);
|
||||
sortMods();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -463,55 +564,37 @@ public class Mods implements Loadable{
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Iterates through each mod with a main class.*/
|
||||
public void each(Cons<Mod> cons){
|
||||
loaded.each(p -> p.mod != null, p -> safeRun(p, () -> cons.get(p.mod)));
|
||||
public Array<LoadedMod> list(){
|
||||
return mods;
|
||||
}
|
||||
|
||||
public void handleError(Throwable t, LoadedMod mod){
|
||||
Array<Throwable> causes = Strings.getCauses(t);
|
||||
Content content = null;
|
||||
for(Throwable e : causes){
|
||||
if(e instanceof ModLoadException && ((ModLoadException) e).content != null){
|
||||
content = ((ModLoadException) e).content;
|
||||
}
|
||||
}
|
||||
|
||||
String realCause = "<???>";
|
||||
for(int i = causes.size -1 ; i >= 0; i--){
|
||||
if(causes.get(i).getMessage() != null){
|
||||
realCause = causes.get(i).getMessage();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
setEnabled(mod, false);
|
||||
|
||||
if(content != null){
|
||||
throw new ModLoadException(Strings.format("Error loading '{0}' from mod '{1}' ({2}):\n{3}",
|
||||
content, mod.meta.name, content.sourceFile == null ? "<unknown file>" : content.sourceFile.name(), realCause), content, t);
|
||||
}else{
|
||||
throw new ModLoadException("Error loading mod " + mod.meta.name, t);
|
||||
}
|
||||
/** Iterates through each mod with a main class. */
|
||||
public void eachClass(Cons<Mod> cons){
|
||||
mods.each(p -> p.main != null, p -> contextRun(p, () -> cons.get(p.main)));
|
||||
}
|
||||
|
||||
public void safeRun(LoadedMod mod, Runnable run){
|
||||
/** Iterates through each enabled mod. */
|
||||
public void eachEnabled(Cons<LoadedMod> cons){
|
||||
mods.each(LoadedMod::enabled, cons);
|
||||
}
|
||||
|
||||
public void contextRun(LoadedMod mod, Runnable run){
|
||||
try{
|
||||
run.run();
|
||||
}catch(Throwable t){
|
||||
handleError(t, mod);
|
||||
throw new RuntimeException("Error loading mod " + mod.meta.name, t);
|
||||
}
|
||||
}
|
||||
|
||||
/** Loads a mod file+meta, but does not add it to the list.
|
||||
* Note that directories can be loaded as mods.*/
|
||||
private LoadedMod loadMod(FileHandle sourceFile) throws Exception{
|
||||
FileHandle zip = sourceFile.isDirectory() ? sourceFile : new ZipFileHandle(sourceFile);
|
||||
private LoadedMod loadMod(Fi sourceFile) throws Exception{
|
||||
Fi zip = sourceFile.isDirectory() ? sourceFile : new ZipFi(sourceFile);
|
||||
if(zip.list().length == 1 && zip.list()[0].isDirectory()){
|
||||
zip = zip.list()[0];
|
||||
}
|
||||
|
||||
FileHandle 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()){
|
||||
Log.warn("Mod {0} doesn't have a 'mod.json'/'plugin.json'/'mod.js' file, skipping.", sourceFile);
|
||||
throw new IllegalArgumentException("No mod.json found.");
|
||||
@@ -522,13 +605,13 @@ public class Mods implements Loadable{
|
||||
String mainClass = meta.main == null ? camelized.toLowerCase() + "." + camelized + "Mod" : meta.main;
|
||||
String baseName = meta.name.toLowerCase().replace(" ", "-");
|
||||
|
||||
if(loaded.contains(m -> m.name.equals(baseName)) || disabled.contains(m -> m.name.equals(baseName))){
|
||||
if(mods.contains(m -> m.name.equals(baseName))){
|
||||
throw new IllegalArgumentException("A mod with the name '" + baseName + "' is already imported.");
|
||||
}
|
||||
|
||||
Mod mainMod;
|
||||
|
||||
FileHandle mainFile = zip;
|
||||
Fi mainFile = zip;
|
||||
String[] path = (mainClass.replace('.', '/') + ".class").split("/");
|
||||
for(String str : path){
|
||||
if(!str.isEmpty()){
|
||||
@@ -562,11 +645,11 @@ public class Mods implements Loadable{
|
||||
/** Represents a plugin that has been loaded from a jar file.*/
|
||||
public static class LoadedMod implements Publishable{
|
||||
/** The location of this mod's zip file/folder on the disk. */
|
||||
public final FileHandle file;
|
||||
public final Fi file;
|
||||
/** The root zip file; points to the contents of this mod. In the case of folders, this is the same as the mod's file. */
|
||||
public final FileHandle root;
|
||||
public final Fi root;
|
||||
/** The mod's main class; may be null. */
|
||||
public final @Nullable Mod mod;
|
||||
public final @Nullable Mod main;
|
||||
/** Internal mod name. Used for textures. */
|
||||
public final String name;
|
||||
/** This mod's metadata. */
|
||||
@@ -575,16 +658,26 @@ public class Mods implements Loadable{
|
||||
public Array<LoadedMod> dependencies = new Array<>();
|
||||
/** All missing dependencies of this mod as strings. */
|
||||
public Array<String> missingDependencies = new Array<>();
|
||||
/** Script files to run. */
|
||||
public Array<Fi> scripts = new Array<>();
|
||||
/** Content with intialization code. */
|
||||
public ObjectSet<Content> erroredContent = new ObjectSet<>();
|
||||
/** Current state of this mod. */
|
||||
public ModState state = ModState.enabled;
|
||||
|
||||
public LoadedMod(FileHandle file, FileHandle root, Mod mod, ModMeta meta){
|
||||
public LoadedMod(Fi file, Fi root, Mod main, ModMeta meta){
|
||||
this.root = root;
|
||||
this.file = file;
|
||||
this.mod = mod;
|
||||
this.main = main;
|
||||
this.meta = meta;
|
||||
this.name = meta.name.toLowerCase().replace(" ", "-");
|
||||
}
|
||||
|
||||
public boolean enabled(){
|
||||
return state == ModState.enabled || state == ModState.contentErrors;
|
||||
}
|
||||
|
||||
public boolean shouldBeEnabled(){
|
||||
return Core.settings.getBool("mod-" + name + "-enabled", true);
|
||||
}
|
||||
|
||||
@@ -592,6 +685,10 @@ public class Mods implements Loadable{
|
||||
return !missingDependencies.isEmpty();
|
||||
}
|
||||
|
||||
public boolean hasContentErrors(){
|
||||
return !erroredContent.isEmpty();
|
||||
}
|
||||
|
||||
/** @return whether this mod is supported by the game verison */
|
||||
public boolean isSupported(){
|
||||
if(Version.build <= 0 || meta.minGameVersion == null) return true;
|
||||
@@ -637,12 +734,12 @@ public class Mods implements Loadable{
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileHandle createSteamFolder(String id){
|
||||
public Fi createSteamFolder(String id){
|
||||
return file;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileHandle createSteamPreview(String id){
|
||||
public Fi createSteamPreview(String id){
|
||||
return file.child("preview.png");
|
||||
}
|
||||
|
||||
@@ -673,43 +770,21 @@ public class Mods implements Loadable{
|
||||
|
||||
/** Plugin metadata information.*/
|
||||
public static class ModMeta{
|
||||
public String name, author, description, version, main, minGameVersion;
|
||||
public String name, displayName, author, description, version, main, minGameVersion;
|
||||
public Array<String> dependencies = Array.with();
|
||||
/** Hidden mods are only server-side or client-side, and do not support adding new content. */
|
||||
public boolean hidden;
|
||||
|
||||
public String displayName(){
|
||||
return displayName == null ? name : displayName;
|
||||
}
|
||||
}
|
||||
|
||||
/** Thrown when an error occurs while loading a mod.*/
|
||||
public static class ModLoadException extends RuntimeException{
|
||||
public Content content;
|
||||
public LoadedMod mod;
|
||||
|
||||
public ModLoadException(String message, Throwable cause){
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
public ModLoadException(String message, @Nullable Content content, Throwable cause){
|
||||
super(message, cause);
|
||||
this.content = content;
|
||||
if(content != null){
|
||||
this.mod = content.mod;
|
||||
}
|
||||
}
|
||||
|
||||
public ModLoadException(@Nullable Content content, Throwable cause){
|
||||
super(cause);
|
||||
this.content = content;
|
||||
if(content != null){
|
||||
this.mod = content.mod;
|
||||
}
|
||||
}
|
||||
|
||||
public ModLoadException(String message, @Nullable Content content){
|
||||
super(message);
|
||||
this.content = content;
|
||||
if(content != null){
|
||||
this.mod = content.mod;
|
||||
}
|
||||
}
|
||||
public enum ModState{
|
||||
enabled,
|
||||
contentErrors,
|
||||
missingDependencies,
|
||||
unsupported,
|
||||
disabled,
|
||||
}
|
||||
}
|
||||
|
||||
84
core/src/io/anuke/mindustry/mod/Scripts.java
Normal file
84
core/src/io/anuke/mindustry/mod/Scripts.java
Normal file
@@ -0,0 +1,84 @@
|
||||
package io.anuke.mindustry.mod;
|
||||
|
||||
import io.anuke.arc.*;
|
||||
import io.anuke.arc.files.*;
|
||||
import io.anuke.arc.util.*;
|
||||
import io.anuke.arc.util.Log.*;
|
||||
import io.anuke.mindustry.*;
|
||||
import io.anuke.mindustry.mod.Mods.*;
|
||||
import org.mozilla.javascript.*;
|
||||
|
||||
public class Scripts implements Disposable{
|
||||
private final Context context;
|
||||
private final String wrapper;
|
||||
private Scriptable scope;
|
||||
private boolean errored;
|
||||
|
||||
public Scripts(){
|
||||
Time.mark();
|
||||
|
||||
context = Vars.platform.getScriptContext();
|
||||
context.setClassShutter(type -> (ClassAccess.allowedClassNames.contains(type) || type.startsWith("$Proxy") ||
|
||||
type.startsWith("adapter") || type.contains("PrintStream") ||
|
||||
type.startsWith("io.anuke.mindustry")) && !type.equals("io.anuke.mindustry.mod.ClassAccess"));
|
||||
|
||||
scope = new ImporterTopLevel(context);
|
||||
wrapper = Core.files.internal("scripts/wrapper.js").readString();
|
||||
|
||||
if(!run(Core.files.internal("scripts/global.js").readString(), "global.js")){
|
||||
errored = true;
|
||||
}
|
||||
Log.debug("Time to load script engine: {0}", Time.elapsed());
|
||||
}
|
||||
|
||||
public boolean hasErrored(){
|
||||
return errored;
|
||||
}
|
||||
|
||||
public String runConsole(String text){
|
||||
try{
|
||||
Object o = context.evaluateString(scope, text, "console.js", 1, null);
|
||||
if(o instanceof NativeJavaObject){
|
||||
o = ((NativeJavaObject)o).unwrap();
|
||||
}
|
||||
if(o instanceof Undefined){
|
||||
o = "undefined";
|
||||
}
|
||||
return String.valueOf(o);
|
||||
}catch(Throwable t){
|
||||
return getError(t);
|
||||
}
|
||||
}
|
||||
|
||||
private String getError(Throwable t){
|
||||
t.printStackTrace();
|
||||
return t.getClass().getSimpleName() + (t.getMessage() == null ? "" : ": " + t.getMessage());
|
||||
}
|
||||
|
||||
public void log(String source, String message){
|
||||
log(LogLevel.info, source, message);
|
||||
}
|
||||
|
||||
public void log(LogLevel level, String source, String message){
|
||||
Log.log(level, "[{0}]: {1}", source, message);
|
||||
}
|
||||
|
||||
public void run(LoadedMod mod, Fi file){
|
||||
run(wrapper.replace("$SCRIPT_NAME$", mod.name + "/" + file.nameWithoutExtension()).replace("$CODE$", file.readString()).replace("$MOD_NAME$", mod.name), file.name());
|
||||
}
|
||||
|
||||
private boolean run(String script, String file){
|
||||
try{
|
||||
context.evaluateString(scope, script, file, 1, null);
|
||||
return true;
|
||||
}catch(Throwable t){
|
||||
log(LogLevel.err, file, "" + getError(t));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose(){
|
||||
Context.exit();
|
||||
}
|
||||
}
|
||||
@@ -19,7 +19,7 @@ import java.util.concurrent.*;
|
||||
|
||||
import static io.anuke.mindustry.Vars.*;
|
||||
|
||||
public class ArcNetImpl implements NetProvider{
|
||||
public class ArcNetProvider implements NetProvider{
|
||||
final Client client;
|
||||
final Prov<DatagramPacket> packetSupplier = () -> new DatagramPacket(new byte[256], 256);
|
||||
|
||||
@@ -27,7 +27,7 @@ public class ArcNetImpl implements NetProvider{
|
||||
final CopyOnWriteArrayList<ArcConnection> connections = new CopyOnWriteArrayList<>();
|
||||
Thread serverThread;
|
||||
|
||||
public ArcNetImpl(){
|
||||
public ArcNetProvider(){
|
||||
client = new Client(8192, 4096, new PacketSerializer());
|
||||
client.setDiscoveryPacket(packetSupplier);
|
||||
client.addListener(new NetListener(){
|
||||
@@ -346,6 +346,19 @@ public class ArcNetImpl implements NetProvider{
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static class PacketSerializer implements NetSerializer{
|
||||
static Cons2<Packet, ByteBuffer> writer = Packet::write;
|
||||
|
||||
@Override
|
||||
public Object read(ByteBuffer byteBuffer){
|
||||
byte id = byteBuffer.get();
|
||||
if(id == -2){
|
||||
return readFramework(byteBuffer);
|
||||
}else{
|
||||
Packet packet = Pools.obtain((Class<Packet>)Registrator.getByID(id).type, (Prov<Packet>)Registrator.getByID(id).constructor);
|
||||
packet.read(byteBuffer);
|
||||
return packet;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(ByteBuffer byteBuffer, Object o){
|
||||
@@ -359,19 +372,7 @@ public class ArcNetImpl implements NetProvider{
|
||||
if(id == -1)
|
||||
throw new RuntimeException("Unregistered class: " + o.getClass());
|
||||
byteBuffer.put(id);
|
||||
((Packet)o).write(byteBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object read(ByteBuffer byteBuffer){
|
||||
byte id = byteBuffer.get();
|
||||
if(id == -2){
|
||||
return readFramework(byteBuffer);
|
||||
}else{
|
||||
Packet packet = Pools.obtain((Class<Packet>)Registrator.getByID(id).type, (Prov<Packet>)Registrator.getByID(id).constructor);
|
||||
packet.read(byteBuffer);
|
||||
return packet;
|
||||
writer.get((Packet)o, byteBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ import static io.anuke.mindustry.Vars.net;
|
||||
public class CrashSender{
|
||||
|
||||
public static void send(Throwable exception, Cons<File> writeListener){
|
||||
|
||||
try{
|
||||
exception.printStackTrace();
|
||||
|
||||
@@ -44,20 +45,19 @@ public class CrashSender{
|
||||
}else{
|
||||
Version.build = Strings.canParseInt(map.get("build")) ? Integer.parseInt(map.get("build")) : -1;
|
||||
}
|
||||
}catch(Throwable ignored){
|
||||
ignored.printStackTrace();
|
||||
}catch(Throwable e){
|
||||
e.printStackTrace();
|
||||
Log.err("Failed to parse version.");
|
||||
}
|
||||
}
|
||||
|
||||
try{
|
||||
File file = new File(OS.getAppDataDirectoryString(Vars.appName), "crashes/crash-report-" + new SimpleDateFormat("MM_dd_yyyy_HH_mm_ss").format(new Date()) + ".txt");
|
||||
new FileHandle(OS.getAppDataDirectoryString(Vars.appName)).child("crashes").mkdirs();
|
||||
new FileHandle(file).writeString(parseException(exception));
|
||||
new Fi(OS.getAppDataDirectoryString(Vars.appName)).child("crashes").mkdirs();
|
||||
new Fi(file).writeString(parseException(exception));
|
||||
writeListener.get(file);
|
||||
}catch(Throwable e){
|
||||
e.printStackTrace();
|
||||
Log.err("Failed to save local crash report.");
|
||||
Log.err("Failed to save local crash report.", e);
|
||||
}
|
||||
|
||||
try{
|
||||
@@ -69,6 +69,14 @@ public class CrashSender{
|
||||
//if there's no settings init we don't know what the user wants but chances are it's an important crash, so send it anyway
|
||||
}
|
||||
|
||||
try{
|
||||
//check any mods - if there are any, don't send reports
|
||||
if(Vars.mods != null && !Vars.mods.list().isEmpty()){
|
||||
return;
|
||||
}
|
||||
}catch(Throwable ignored){
|
||||
}
|
||||
|
||||
//do not send exceptions that occur for versions that can't be parsed
|
||||
if(Version.number == 0){
|
||||
return;
|
||||
|
||||
@@ -63,48 +63,6 @@ public class Packets{
|
||||
|
||||
}
|
||||
|
||||
public static class ConnectPacket implements Packet{
|
||||
public int version;
|
||||
public String versionType;
|
||||
public Array<String> mods;
|
||||
public String name, uuid, usid;
|
||||
public boolean mobile;
|
||||
public int color;
|
||||
|
||||
@Override
|
||||
public void write(ByteBuffer buffer){
|
||||
buffer.putInt(Version.build);
|
||||
TypeIO.writeString(buffer, versionType);
|
||||
TypeIO.writeString(buffer, name);
|
||||
TypeIO.writeString(buffer, usid);
|
||||
buffer.put(mobile ? (byte)1 : 0);
|
||||
buffer.putInt(color);
|
||||
buffer.put(Base64Coder.decode(uuid));
|
||||
buffer.put((byte)mods.size);
|
||||
for(int i = 0; i < mods.size; i++){
|
||||
TypeIO.writeString(buffer, mods.get(i));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(ByteBuffer buffer){
|
||||
version = buffer.getInt();
|
||||
versionType = TypeIO.readString(buffer);
|
||||
name = TypeIO.readString(buffer);
|
||||
usid = TypeIO.readString(buffer);
|
||||
mobile = buffer.get() == 1;
|
||||
color = buffer.getInt();
|
||||
byte[] idbytes = new byte[8];
|
||||
buffer.get(idbytes);
|
||||
uuid = new String(Base64Coder.encode(idbytes));
|
||||
int totalMods = buffer.get();
|
||||
mods = new Array<>(totalMods);
|
||||
for(int i = 0; i < totalMods; i++){
|
||||
mods.add(TypeIO.readString(buffer));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class InvokePacket implements Packet{
|
||||
public byte type, priority;
|
||||
|
||||
@@ -190,4 +148,46 @@ public class Packets{
|
||||
buffer.get(data);
|
||||
}
|
||||
}
|
||||
|
||||
public static class ConnectPacket implements Packet{
|
||||
public int version;
|
||||
public String versionType;
|
||||
public Array<String> mods;
|
||||
public String name, uuid, usid;
|
||||
public boolean mobile;
|
||||
public int color;
|
||||
|
||||
@Override
|
||||
public void write(ByteBuffer buffer){
|
||||
buffer.putInt(Version.build);
|
||||
TypeIO.writeString(buffer, versionType);
|
||||
TypeIO.writeString(buffer, name);
|
||||
TypeIO.writeString(buffer, usid);
|
||||
buffer.put(mobile ? (byte)1 : 0);
|
||||
buffer.put(Base64Coder.decode(uuid));
|
||||
buffer.put((byte)color);
|
||||
buffer.put((byte)mods.size);
|
||||
for(int i = 0; i < mods.size; i++){
|
||||
TypeIO.writeString(buffer, mods.get(i));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(ByteBuffer buffer){
|
||||
version = buffer.getInt();
|
||||
versionType = TypeIO.readString(buffer);
|
||||
name = TypeIO.readString(buffer);
|
||||
usid = TypeIO.readString(buffer);
|
||||
mobile = buffer.get() == 1;
|
||||
color = buffer.getInt();
|
||||
byte[] idbytes = new byte[8];
|
||||
buffer.get(idbytes);
|
||||
uuid = new String(Base64Coder.encode(idbytes));
|
||||
int totalMods = buffer.get();
|
||||
mods = new Array<>(totalMods);
|
||||
for(int i = 0; i < totalMods; i++){
|
||||
mods.add(TypeIO.readString(buffer));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package io.anuke.mindustry.plugin;
|
||||
|
||||
import io.anuke.mindustry.mod.*;
|
||||
|
||||
/** Defines a special type of mod that is always hidden. */
|
||||
public abstract class Plugin extends Mod{
|
||||
|
||||
}
|
||||
|
||||
12
core/src/io/anuke/mindustry/type/ErrorContent.java
Normal file
12
core/src/io/anuke/mindustry/type/ErrorContent.java
Normal file
@@ -0,0 +1,12 @@
|
||||
package io.anuke.mindustry.type;
|
||||
|
||||
import io.anuke.mindustry.ctype.*;
|
||||
import io.anuke.mindustry.ctype.ContentType;
|
||||
|
||||
/** Represents a blank type of content that has an error. Replaces anything that failed to parse. */
|
||||
public class ErrorContent extends Content{
|
||||
@Override
|
||||
public ContentType getContentType(){
|
||||
return ContentType.error;
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,10 @@
|
||||
package io.anuke.mindustry.type;
|
||||
|
||||
import io.anuke.arc.*;
|
||||
import io.anuke.arc.collection.*;
|
||||
import io.anuke.arc.graphics.*;
|
||||
import io.anuke.arc.scene.ui.layout.*;
|
||||
import io.anuke.mindustry.ctype.UnlockableContent;
|
||||
import io.anuke.mindustry.ctype.*;
|
||||
import io.anuke.mindustry.ctype.ContentType;
|
||||
import io.anuke.mindustry.ui.*;
|
||||
import io.anuke.mindustry.world.blocks.*;
|
||||
|
||||
@@ -34,7 +34,6 @@ public class Item extends UnlockableContent{
|
||||
public Item(String name, Color color){
|
||||
super(name);
|
||||
this.color = color;
|
||||
this.description = Core.bundle.getOrNull("item." + this.name + ".description");
|
||||
}
|
||||
|
||||
public Item(String name){
|
||||
@@ -51,14 +50,9 @@ public class Item extends UnlockableContent{
|
||||
ContentDisplay.displayItem(table, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String localizedName(){
|
||||
return Core.bundle.get("item." + this.name + ".name");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString(){
|
||||
return localizedName();
|
||||
return localizedName;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -38,7 +38,7 @@ public class ItemStack implements Comparable<ItemStack>{
|
||||
public static ItemStack[] with(Object... items){
|
||||
ItemStack[] stacks = new ItemStack[items.length / 2];
|
||||
for(int i = 0; i < items.length; i += 2){
|
||||
stacks[i / 2] = new ItemStack((Item)items[i], (Integer)items[i + 1]);
|
||||
stacks[i / 2] = new ItemStack((Item)items[i], ((Number)items[i + 1]).intValue());
|
||||
}
|
||||
return stacks;
|
||||
}
|
||||
@@ -46,7 +46,7 @@ public class ItemStack implements Comparable<ItemStack>{
|
||||
public static Array<ItemStack> list(Object... items){
|
||||
Array<ItemStack> stacks = new Array<>(items.length / 2);
|
||||
for(int i = 0; i < items.length; i += 2){
|
||||
stacks.add(new ItemStack((Item)items[i], (Integer)items[i + 1]));
|
||||
stacks.add(new ItemStack((Item)items[i], ((Number)items[i + 1]).intValue()));
|
||||
}
|
||||
return stacks;
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
package io.anuke.mindustry.type;
|
||||
|
||||
import io.anuke.arc.*;
|
||||
import io.anuke.arc.graphics.*;
|
||||
import io.anuke.arc.scene.ui.layout.*;
|
||||
import io.anuke.arc.util.ArcAnnotate.*;
|
||||
import io.anuke.mindustry.content.*;
|
||||
import io.anuke.mindustry.ctype.UnlockableContent;
|
||||
import io.anuke.mindustry.ctype.*;
|
||||
import io.anuke.mindustry.ctype.ContentType;
|
||||
import io.anuke.mindustry.ui.*;
|
||||
|
||||
public class Liquid extends UnlockableContent{
|
||||
@@ -31,7 +31,6 @@ public class Liquid extends UnlockableContent{
|
||||
public Liquid(String name, Color color){
|
||||
super(name);
|
||||
this.color = new Color(color);
|
||||
this.description = Core.bundle.getOrNull("liquid." + name + ".description");
|
||||
}
|
||||
|
||||
/** For modding only.*/
|
||||
@@ -52,14 +51,9 @@ public class Liquid extends UnlockableContent{
|
||||
ContentDisplay.displayLiquid(table, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String localizedName(){
|
||||
return Core.bundle.get("liquid." + this.name + ".name");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString(){
|
||||
return localizedName();
|
||||
return localizedName;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -5,6 +5,7 @@ import io.anuke.arc.graphics.Color;
|
||||
import io.anuke.arc.graphics.g2d.TextureRegion;
|
||||
import io.anuke.arc.scene.ui.layout.Table;
|
||||
import io.anuke.arc.util.ArcAnnotate.*;
|
||||
import io.anuke.mindustry.ctype.ContentType;
|
||||
import io.anuke.mindustry.entities.type.Player;
|
||||
import io.anuke.mindustry.ctype.UnlockableContent;
|
||||
import io.anuke.mindustry.graphics.Pal;
|
||||
@@ -39,17 +40,12 @@ public class Mech extends UnlockableContent{
|
||||
public Mech(String name, boolean flying){
|
||||
super(name);
|
||||
this.flying = flying;
|
||||
this.description = Core.bundle.get("mech." + name + ".description");
|
||||
}
|
||||
|
||||
public Mech(String name){
|
||||
this(name, false);
|
||||
}
|
||||
|
||||
public String localizedName(){
|
||||
return Core.bundle.get("mech." + name + ".name");
|
||||
}
|
||||
|
||||
public void updateAlt(Player player){
|
||||
}
|
||||
|
||||
@@ -113,6 +109,6 @@ public class Mech extends UnlockableContent{
|
||||
|
||||
@Override
|
||||
public String toString(){
|
||||
return localizedName();
|
||||
return localizedName;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,9 +20,9 @@ public interface Publishable{
|
||||
/** @return the tag that this content has. e.g. 'schematic' or 'map'. */
|
||||
String steamTag();
|
||||
/** @return a folder with everything needed for this piece of content in it; does not need to be a copy. */
|
||||
FileHandle createSteamFolder(String id);
|
||||
Fi createSteamFolder(String id);
|
||||
/** @return a preview file PNG. */
|
||||
FileHandle createSteamPreview(String id);
|
||||
Fi createSteamPreview(String id);
|
||||
/** @return any extra tags to add to this item.*/
|
||||
default Array<String> extraTags(){
|
||||
return new Array<>(0);
|
||||
|
||||
@@ -1,46 +1,46 @@
|
||||
package io.anuke.mindustry.type;
|
||||
|
||||
import io.anuke.arc.collection.Array;
|
||||
import io.anuke.arc.collection.ObjectMap;
|
||||
import io.anuke.arc.func.Prov;
|
||||
import io.anuke.arc.graphics.Color;
|
||||
import io.anuke.arc.math.Mathf;
|
||||
import io.anuke.arc.collection.*;
|
||||
import io.anuke.arc.graphics.*;
|
||||
import io.anuke.arc.math.*;
|
||||
import io.anuke.arc.util.*;
|
||||
import io.anuke.mindustry.content.Fx;
|
||||
import io.anuke.mindustry.entities.Effects;
|
||||
import io.anuke.mindustry.entities.Effects.Effect;
|
||||
import io.anuke.mindustry.entities.type.Unit;
|
||||
import io.anuke.mindustry.entities.units.Statuses.StatusEntry;
|
||||
import io.anuke.mindustry.ctype.Content;
|
||||
|
||||
public class StatusEffect extends Content{
|
||||
public float damageMultiplier = 1f; //damage dealt
|
||||
public float armorMultiplier = 1f; //armor points
|
||||
public float speedMultiplier = 1f; //speed
|
||||
public Color color = Color.white.cpy(); //tint color
|
||||
|
||||
/** Transition handler map. */
|
||||
private ObjectMap<StatusEffect, TransitionHandler> transitions = new ObjectMap<>();
|
||||
/**
|
||||
* Transition initializer array. Since provided effects are only available after init(), this handles putting things
|
||||
* in the transitions map.
|
||||
*/
|
||||
private Array<Object[]> transInit = new Array<>();
|
||||
import io.anuke.mindustry.content.*;
|
||||
import io.anuke.mindustry.ctype.*;
|
||||
import io.anuke.mindustry.ctype.ContentType;
|
||||
import io.anuke.mindustry.entities.*;
|
||||
import io.anuke.mindustry.entities.Effects.*;
|
||||
import io.anuke.mindustry.entities.type.*;
|
||||
import io.anuke.mindustry.entities.units.Statuses.*;
|
||||
|
||||
public class StatusEffect extends MappableContent{
|
||||
/** Damage dealt by the unit with the effect. */
|
||||
public float damageMultiplier = 1f;
|
||||
/** Unit armor multiplier. */
|
||||
public float armorMultiplier = 1f;
|
||||
/** Unit speed multiplier (buggy) */
|
||||
public float speedMultiplier = 1f;
|
||||
/** Damage per frame. */
|
||||
protected float damage;
|
||||
public float damage;
|
||||
/** Tint color of effect. */
|
||||
public Color color = Color.white.cpy();
|
||||
/** Effect that happens randomly on top of the affected unit. */
|
||||
protected Effect effect = Fx.none;
|
||||
public Effect effect = Fx.none;
|
||||
/** Transition handler map. */
|
||||
protected ObjectMap<StatusEffect, TransitionHandler> transitions = new ObjectMap<>();
|
||||
/** Called on init. */
|
||||
protected Runnable initblock = () -> {};
|
||||
|
||||
public StatusEffect(String name){
|
||||
super(name);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public void init(){
|
||||
for(Object[] pair : transInit){
|
||||
Prov<StatusEffect> sup = (Prov<StatusEffect>)pair[0];
|
||||
TransitionHandler handler = (TransitionHandler)pair[1];
|
||||
transitions.put(sup.get(), handler);
|
||||
}
|
||||
transInit.clear();
|
||||
initblock.run();
|
||||
}
|
||||
|
||||
public void init(Runnable run){
|
||||
this.initblock = run;
|
||||
}
|
||||
|
||||
/** Runs every tick on the affected unit while time is greater than 0. */
|
||||
@@ -56,20 +56,19 @@ public class StatusEffect extends Content{
|
||||
}
|
||||
}
|
||||
|
||||
protected void trans(Prov<StatusEffect> effect, TransitionHandler handler){
|
||||
transInit.add(new Object[]{effect, handler});
|
||||
protected void trans(StatusEffect effect, TransitionHandler handler){
|
||||
transitions.put(effect, handler);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
protected void opposite(Prov... effect){
|
||||
for(Prov<StatusEffect> sup : effect){
|
||||
protected void opposite(StatusEffect... effect){
|
||||
for(StatusEffect sup : effect){
|
||||
trans(sup, (unit, time, newTime, result) -> {
|
||||
time -= newTime * 0.5f;
|
||||
if(time > 0){
|
||||
result.set(this, time);
|
||||
return;
|
||||
}
|
||||
result.set(sup.get(), newTime);
|
||||
result.set(sup, newTime);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package io.anuke.mindustry.type;
|
||||
|
||||
import io.anuke.arc.func.*;
|
||||
import io.anuke.mindustry.ctype.*;
|
||||
import io.anuke.mindustry.ctype.ContentType;
|
||||
import io.anuke.mindustry.entities.traits.*;
|
||||
|
||||
public class TypeID extends MappableContent{
|
||||
|
||||
@@ -8,6 +8,7 @@ import io.anuke.arc.graphics.g2d.*;
|
||||
import io.anuke.arc.scene.ui.layout.*;
|
||||
import io.anuke.arc.util.ArcAnnotate.*;
|
||||
import io.anuke.mindustry.content.*;
|
||||
import io.anuke.mindustry.ctype.ContentType;
|
||||
import io.anuke.mindustry.ctype.UnlockableContent;
|
||||
import io.anuke.mindustry.entities.type.*;
|
||||
import io.anuke.mindustry.game.*;
|
||||
@@ -16,8 +17,7 @@ import io.anuke.mindustry.ui.*;
|
||||
|
||||
public class UnitType extends UnlockableContent{
|
||||
public @NonNull TypeID typeID;
|
||||
public @NonNull
|
||||
Prov<? extends BaseUnit> constructor;
|
||||
public @NonNull Prov<? extends BaseUnit> constructor;
|
||||
|
||||
public float health = 60;
|
||||
public float hitsize = 7f;
|
||||
@@ -49,9 +49,8 @@ public class UnitType extends UnlockableContent{
|
||||
create(mainConstructor);
|
||||
}
|
||||
|
||||
public <T extends BaseUnit> UnitType(String name){
|
||||
public UnitType(String name){
|
||||
super(name);
|
||||
this.description = Core.bundle.getOrNull("unit." + name + ".description");
|
||||
}
|
||||
|
||||
public <T extends BaseUnit> void create(Prov<T> mainConstructor){
|
||||
@@ -65,11 +64,6 @@ public class UnitType extends UnlockableContent{
|
||||
ContentDisplay.displayUnit(table, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String localizedName(){
|
||||
return Core.bundle.get("unit." + name + ".name");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load(){
|
||||
weapon.load();
|
||||
|
||||
@@ -7,6 +7,7 @@ import io.anuke.arc.graphics.g2d.*;
|
||||
import io.anuke.arc.scene.ui.layout.*;
|
||||
import io.anuke.arc.util.ArcAnnotate.*;
|
||||
import io.anuke.mindustry.content.*;
|
||||
import io.anuke.mindustry.ctype.ContentType;
|
||||
import io.anuke.mindustry.ctype.UnlockableContent;
|
||||
import io.anuke.mindustry.game.EventType.*;
|
||||
import io.anuke.mindustry.game.*;
|
||||
@@ -174,8 +175,8 @@ public class Zone extends UnlockableContent{
|
||||
|
||||
@Override
|
||||
public void init(){
|
||||
if(generator instanceof MapGenerator && mod != null){
|
||||
((MapGenerator)generator).removePrefix(mod.name);
|
||||
if(generator instanceof MapGenerator && minfo.mod != null){
|
||||
((MapGenerator)generator).removePrefix(minfo.mod.name);
|
||||
}
|
||||
|
||||
generator.init(loadout);
|
||||
@@ -207,11 +208,6 @@ public class Zone extends UnlockableContent{
|
||||
public void displayInfo(Table table){
|
||||
}
|
||||
|
||||
@Override
|
||||
public String localizedName(){
|
||||
return Core.bundle.get("zone." + name + ".name");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ContentType getContentType(){
|
||||
return ContentType.zone;
|
||||
|
||||
@@ -66,7 +66,7 @@ public class ContentDisplay{
|
||||
|
||||
table.table(title -> {
|
||||
title.addImage(item.icon(Cicon.xlarge)).size(8 * 6);
|
||||
title.add("[accent]" + item.localizedName()).padLeft(5);
|
||||
title.add("[accent]" + item.localizedName).padLeft(5);
|
||||
});
|
||||
|
||||
table.row();
|
||||
@@ -100,7 +100,7 @@ public class ContentDisplay{
|
||||
|
||||
table.table(title -> {
|
||||
title.addImage(liquid.icon(Cicon.xlarge)).size(8 * 6);
|
||||
title.add("[accent]" + liquid.localizedName()).padLeft(5);
|
||||
title.add("[accent]" + liquid.localizedName).padLeft(5);
|
||||
});
|
||||
|
||||
table.row();
|
||||
@@ -134,7 +134,7 @@ public class ContentDisplay{
|
||||
public static void displayMech(Table table, Mech mech){
|
||||
table.table(title -> {
|
||||
title.addImage(mech.icon(Cicon.xlarge)).size(8 * 6);
|
||||
title.add("[accent]" + mech.localizedName()).padLeft(5);
|
||||
title.add("[accent]" + mech.localizedName).padLeft(5);
|
||||
});
|
||||
table.left().defaults().left();
|
||||
|
||||
@@ -182,7 +182,7 @@ public class ContentDisplay{
|
||||
public static void displayUnit(Table table, UnitType unit){
|
||||
table.table(title -> {
|
||||
title.addImage(unit.icon(Cicon.xlarge)).size(8 * 6);
|
||||
title.add("[accent]" + unit.localizedName()).padLeft(5);
|
||||
title.add("[accent]" + unit.localizedName).padLeft(5);
|
||||
});
|
||||
|
||||
table.row();
|
||||
|
||||
@@ -15,7 +15,7 @@ public class ItemDisplay extends Table{
|
||||
|
||||
public ItemDisplay(Item item, int amount, boolean showName){
|
||||
add(new ItemImage(new ItemStack(item, amount))).size(8 * 4).padRight(amount > 99 ? 12 : 0);
|
||||
if(showName) add(item.localizedName()).padLeft(4 + amount > 99 ? 4 : 0);
|
||||
if(showName) add(item.localizedName).padLeft(4 + amount > 99 ? 4 : 0);
|
||||
|
||||
this.item = item;
|
||||
this.amount = amount;
|
||||
|
||||
@@ -29,7 +29,7 @@ public class ItemsDisplay extends Table{
|
||||
if(item.type == ItemType.material && data.isUnlocked(item)){
|
||||
t.label(() -> format(item)).left();
|
||||
t.addImage(item.icon(Cicon.small)).size(8 * 3).padLeft(4).padRight(4);
|
||||
t.add(item.localizedName()).color(Color.lightGray).left();
|
||||
t.add(item.localizedName).color(Color.lightGray).left();
|
||||
t.row();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ public class Links{
|
||||
new LinkEntry("changelog", "https://github.com/Anuken/Mindustry/releases", Pal.accent.cpy()),
|
||||
new LinkEntry("trello", "https://trello.com/b/aE2tcUwF", Color.valueOf("026aa7")),
|
||||
new LinkEntry("wiki", "https://mindustrygame.github.io/wiki/", Color.valueOf("0f142f")),
|
||||
new LinkEntry("feathub", "https://feathub.com/Anuken/Mindustry/", Color.valueOf("ebebeb")),
|
||||
new LinkEntry("reddit", "https://www.reddit.com/r/Mindustry/", Color.valueOf("ee593b")),
|
||||
new LinkEntry("itch.io", "https://anuke.itch.io/mindustry", Color.valueOf("fa5c5c")),
|
||||
new LinkEntry("google-play", "https://play.google.com/store/apps/details?id=io.anuke.mindustry", Color.valueOf("689f38")),
|
||||
|
||||
@@ -33,6 +33,6 @@ public class LiquidDisplay extends Table{
|
||||
add(StatUnit.perSecond.localized()).padLeft(2).padRight(5).color(Color.lightGray);
|
||||
}
|
||||
|
||||
add(liquid.localizedName());
|
||||
add(liquid.localizedName);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ import static io.anuke.mindustry.gen.Tex.*;
|
||||
public class Styles{
|
||||
public static Drawable black, black9, black8, black6, black3, none, flatDown, flatOver;
|
||||
public static ButtonStyle defaultb, waveb;
|
||||
public static TextButtonStyle defaultt, squaret, nodet, cleart, discordt, infot, clearPartialt, clearTogglet, clearToggleMenut, togglet;
|
||||
public static TextButtonStyle defaultt, squaret, nodet, cleart, discordt, infot, clearPartialt, clearTogglet, clearToggleMenut, togglet, transt;
|
||||
public static ImageButtonStyle defaulti, nodei, righti, emptyi, emptytogglei, selecti, cleari, clearFulli, clearPartiali, clearPartial2i, clearTogglei, clearTransi, clearToggleTransi, clearTogglePartiali;
|
||||
public static ScrollPaneStyle defaultPane, horizontalPane, smallPane;
|
||||
public static KeybindDialogStyle defaultKeybindDialog;
|
||||
@@ -110,6 +110,14 @@ public class Styles{
|
||||
fontColor = Color.white;
|
||||
disabledFontColor = Color.gray;
|
||||
}};
|
||||
transt = new TextButtonStyle(){{
|
||||
down = flatDown;
|
||||
up = none;
|
||||
over = flatOver;
|
||||
font = Fonts.def;
|
||||
fontColor = Color.white;
|
||||
disabledFontColor = Color.gray;
|
||||
}};
|
||||
clearTogglet = new TextButtonStyle(){{
|
||||
font = Fonts.def;
|
||||
fontColor = Color.white;
|
||||
@@ -201,6 +209,9 @@ public class Styles{
|
||||
down = flatDown;
|
||||
up = black6;
|
||||
over = flatOver;
|
||||
disabled = black8;
|
||||
imageDisabledColor = Color.lightGray;
|
||||
imageUpColor = Color.white;
|
||||
}};
|
||||
clearToggleTransi = new ImageButtonStyle(){{
|
||||
down = flatDown;
|
||||
|
||||
@@ -10,9 +10,9 @@ import io.anuke.arc.util.*;
|
||||
import io.anuke.mindustry.*;
|
||||
import io.anuke.mindustry.core.GameState.*;
|
||||
import io.anuke.mindustry.ctype.*;
|
||||
import io.anuke.mindustry.ctype.ContentType;
|
||||
import io.anuke.mindustry.gen.*;
|
||||
import io.anuke.mindustry.graphics.*;
|
||||
import io.anuke.mindustry.type.*;
|
||||
import io.anuke.mindustry.ui.*;
|
||||
|
||||
public class DatabaseDialog extends FloatingDialog{
|
||||
@@ -66,7 +66,7 @@ public class DatabaseDialog extends FloatingDialog{
|
||||
|
||||
if(unlocked(unlock)){
|
||||
image.clicked(() -> Vars.ui.content.show(unlock));
|
||||
image.addListener(new Tooltip(t -> t.background(Tex.button).add(unlock.localizedName())));
|
||||
image.addListener(new Tooltip(t -> t.background(Tex.button).add(unlock.localizedName)));
|
||||
}
|
||||
|
||||
if((++count) % maxWidth == 0){
|
||||
|
||||
@@ -155,7 +155,7 @@ public class DeployDialog extends FloatingDialog{
|
||||
}).color(Color.darkGray).grow()));
|
||||
}
|
||||
|
||||
TextButton button = Elements.newButton(Core.bundle.format("resume", slot.getZone().localizedName()), Styles.squaret, () -> {
|
||||
TextButton button = Elements.newButton(Core.bundle.format("resume", slot.getZone().localizedName), Styles.squaret, () -> {
|
||||
control.saves.getZoneSlot().cautiousLoad(() -> {
|
||||
hide();
|
||||
ui.loadAnd(() -> {
|
||||
@@ -232,7 +232,7 @@ public class DeployDialog extends FloatingDialog{
|
||||
});
|
||||
|
||||
if(zone.unlocked() && !hidden(zone)){
|
||||
button.labelWrap(zone.localizedName()).style(Styles.outlineLabel).width(140).growX().get().setAlignment(Align.center);
|
||||
button.labelWrap(zone.localizedName).style(Styles.outlineLabel).width(140).growX().get().setAlignment(Align.center);
|
||||
}else{
|
||||
Cons<Element> flasher = zone.canUnlock() && !hidden(zone) ? e -> e.update(() -> e.getColor().set(Color.white).lerp(Pal.accent, Mathf.absin(3f, 1f))) : e -> {};
|
||||
flasher.get(button.addImage(Icon.locked).get());
|
||||
|
||||
@@ -18,20 +18,20 @@ import java.util.*;
|
||||
import static io.anuke.mindustry.Vars.platform;
|
||||
|
||||
public class FileChooser extends FloatingDialog{
|
||||
private static final FileHandle homeDirectory = Core.files.absolute(Core.files.getExternalStoragePath());
|
||||
private static FileHandle lastDirectory = homeDirectory;
|
||||
private static final Fi homeDirectory = Core.files.absolute(Core.files.getExternalStoragePath());
|
||||
private static Fi lastDirectory = homeDirectory;
|
||||
|
||||
private Table files;
|
||||
private FileHandle directory = lastDirectory;
|
||||
private Fi directory = lastDirectory;
|
||||
private ScrollPane pane;
|
||||
private TextField navigation, filefield;
|
||||
private TextButton ok;
|
||||
private FileHistory stack = new FileHistory();
|
||||
private Boolf<FileHandle> filter;
|
||||
private Cons<FileHandle> selectListener;
|
||||
private Boolf<Fi> filter;
|
||||
private Cons<Fi> selectListener;
|
||||
private boolean open;
|
||||
|
||||
public FileChooser(String title, Boolf<FileHandle> filter, boolean open, Cons<FileHandle> result){
|
||||
public FileChooser(String title, Boolf<Fi> filter, boolean open, Cons<Fi> result){
|
||||
super(title);
|
||||
setFillParent(true);
|
||||
this.open = open;
|
||||
@@ -154,8 +154,8 @@ public class FileChooser extends FloatingDialog{
|
||||
}
|
||||
}
|
||||
|
||||
private FileHandle[] getFileNames(){
|
||||
FileHandle[] handles = directory.list(file -> !file.getName().startsWith("."));
|
||||
private Fi[] getFileNames(){
|
||||
Fi[] handles = directory.list(file -> !file.getName().startsWith("."));
|
||||
|
||||
Arrays.sort(handles, (a, b) -> {
|
||||
if(a.isDirectory() && !b.isDirectory()) return -1;
|
||||
@@ -183,7 +183,7 @@ public class FileChooser extends FloatingDialog{
|
||||
|
||||
files.clearChildren();
|
||||
files.top().left();
|
||||
FileHandle[] names = getFileNames();
|
||||
Fi[] names = getFileNames();
|
||||
|
||||
Image upimage = new Image(Icon.folderParentSmall);
|
||||
TextButton upbutton = new TextButton(".." + directory.toString(), Styles.clearTogglet);
|
||||
@@ -203,7 +203,7 @@ public class FileChooser extends FloatingDialog{
|
||||
ButtonGroup<TextButton> group = new ButtonGroup<>();
|
||||
group.setMinCheckCount(0);
|
||||
|
||||
for(FileHandle file : names){
|
||||
for(Fi file : names){
|
||||
if(!file.isDirectory() && !filter.get(file)) continue; //skip non-filtered files
|
||||
|
||||
String filename = file.name();
|
||||
@@ -254,14 +254,14 @@ public class FileChooser extends FloatingDialog{
|
||||
}
|
||||
|
||||
public class FileHistory{
|
||||
private Array<FileHandle> history = new Array<>();
|
||||
private Array<Fi> history = new Array<>();
|
||||
private int index;
|
||||
|
||||
public FileHistory(){
|
||||
|
||||
}
|
||||
|
||||
public void push(FileHandle file){
|
||||
public void push(Fi file){
|
||||
if(index != history.size) history.truncate(index);
|
||||
history.add(file);
|
||||
index++;
|
||||
@@ -295,7 +295,7 @@ public class FileChooser extends FloatingDialog{
|
||||
|
||||
System.out.println("\n\n\n\n\n\n");
|
||||
int i = 0;
|
||||
for(FileHandle file : history){
|
||||
for(Fi file : history){
|
||||
i++;
|
||||
if(index == i){
|
||||
System.out.println("[[" + file.toString() + "]]");
|
||||
|
||||
@@ -101,7 +101,7 @@ public class LoadDialog extends FloatingDialog{
|
||||
});
|
||||
}else{
|
||||
try{
|
||||
FileHandle file = Core.files.local("save-" + slot.getName() + "." + saveExtension);
|
||||
Fi file = Core.files.local("save-" + slot.getName() + "." + saveExtension);
|
||||
slot.exportFile(file);
|
||||
platform.shareFile(file);
|
||||
}catch(Exception e){
|
||||
|
||||
@@ -143,7 +143,7 @@ public class MapsDialog extends FloatingDialog{
|
||||
button.row();
|
||||
button.stack(new Image(map.safeTexture()).setScaling(Scaling.fit), new BorderImage(map.safeTexture()).setScaling(Scaling.fit)).size(mapsize - 20f);
|
||||
button.row();
|
||||
button.add(map.custom ? "$custom" : map.workshop ? "$workshop" : "$builtin").color(Color.gray).padTop(3);
|
||||
button.add(map.custom ? "$custom" : map.workshop ? "$workshop" : map.mod != null ? "[lightgray]" + map.mod.meta.displayName() : "$builtin").color(Color.gray).padTop(3);
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ package io.anuke.mindustry.ui.dialogs;
|
||||
|
||||
import io.anuke.arc.*;
|
||||
import io.anuke.arc.Net.*;
|
||||
import io.anuke.arc.collection.*;
|
||||
import io.anuke.arc.files.*;
|
||||
import io.anuke.arc.util.*;
|
||||
import io.anuke.arc.util.io.*;
|
||||
@@ -47,7 +46,7 @@ public class ModsDialog extends FloatingDialog{
|
||||
ui.loadfrag.hide();
|
||||
}else{
|
||||
try{
|
||||
FileHandle file = tmpDirectory.child(text.replace("/", "") + ".zip");
|
||||
Fi file = tmpDirectory.child(text.replace("/", "") + ".zip");
|
||||
Streams.copyStream(result.getResultAsStream(), file.write(false));
|
||||
mods.importMod(file);
|
||||
file.delete();
|
||||
@@ -75,7 +74,7 @@ public class ModsDialog extends FloatingDialog{
|
||||
hidden(() -> {
|
||||
if(mods.requiresReload()){
|
||||
ui.loadAnd("$reloading", () -> {
|
||||
mods.all().each(mod -> {
|
||||
mods.eachEnabled(mod -> {
|
||||
if(mod.hasUnmetDependencies()){
|
||||
ui.showErrorMessage(Core.bundle.format("mod.nowdisabled", mod.name, mod.missingDependencies.toString(", ")));
|
||||
}
|
||||
@@ -107,14 +106,13 @@ public class ModsDialog extends FloatingDialog{
|
||||
cont.defaults().width(mobile ? 500 : 560f).pad(4);
|
||||
cont.add("$mod.reloadrequired").visible(mods::requiresReload).center().get().setAlignment(Align.center);
|
||||
cont.row();
|
||||
if(!(mods.all().isEmpty() && mods.disabled().isEmpty())){
|
||||
if(!mods.list().isEmpty()){
|
||||
cont.pane(table -> {
|
||||
table.margin(10f).top();
|
||||
Array<LoadedMod> all = Array.withArrays(mods.all(), mods.disabled());
|
||||
|
||||
boolean anyDisabled = false;
|
||||
for(LoadedMod mod : all){
|
||||
if(!mod.enabled() && !anyDisabled && mods.all().size > 0){
|
||||
for(LoadedMod mod : mods.list()){
|
||||
if(!mod.enabled() && !anyDisabled && mods.list().size > 0){
|
||||
anyDisabled = true;
|
||||
table.row();
|
||||
table.addImage().growX().height(4f).pad(6f).color(Pal.gray);
|
||||
@@ -126,7 +124,7 @@ public class ModsDialog extends FloatingDialog{
|
||||
t.margin(14f).left();
|
||||
t.table(title -> {
|
||||
title.left();
|
||||
title.add("[accent]" + mod.meta.name + "[lightgray] v" + mod.meta.version + (mod.enabled() ? "" : "\n" + Core.bundle.get("mod.disabled") + "")).width(200f).wrap();
|
||||
title.add("[accent]" + mod.meta.displayName() + "[lightgray] v" + mod.meta.version + (mod.enabled() ? "" : "\n" + Core.bundle.get("mod.disabled") + "")).width(200f).wrap();
|
||||
title.add().growX();
|
||||
|
||||
title.addImageTextButton(mod.enabled() ? "$mod.disable" : "$mod.enable", mod.enabled() ? Icon.arrowDownSmall : Icon.arrowUpSmall, Styles.cleart, () -> {
|
||||
@@ -167,6 +165,9 @@ public class ModsDialog extends FloatingDialog{
|
||||
}else if(mod.hasUnmetDependencies()){
|
||||
t.labelWrap(Core.bundle.format("mod.missingdependencies", mod.missingDependencies.toString(", "))).growX();
|
||||
t.row();
|
||||
}else if(mod.hasContentErrors()){
|
||||
t.labelWrap("$mod.erroredcontent").growX();
|
||||
t.row();
|
||||
}
|
||||
}).width(mobile ? 430f : 500f);
|
||||
table.row();
|
||||
|
||||
@@ -99,10 +99,14 @@ public class SchematicsDialog extends FloatingDialog{
|
||||
buttons.addImageButton(Icon.linkSmall, style, () -> platform.viewListing(s));
|
||||
}else{
|
||||
buttons.addImageButton(Icon.trash16Small, style, () -> {
|
||||
ui.showConfirm("$confirm", "$schematic.delete.confirm", () -> {
|
||||
schematics.remove(s);
|
||||
rebuildPane[0].run();
|
||||
});
|
||||
if(s.mod != null){
|
||||
ui.showInfo(Core.bundle.format("mod.item.remove", s.mod.meta.displayName()));
|
||||
}else{
|
||||
ui.showConfirm("$confirm", "$schematic.delete.confirm", () -> {
|
||||
schematics.remove(s);
|
||||
rebuildPane[0].run();
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -154,6 +158,7 @@ public class SchematicsDialog extends FloatingDialog{
|
||||
dialog.hide();
|
||||
try{
|
||||
Schematic s = Schematics.readBase64(Core.app.getClipboardText());
|
||||
s.removeSteamID();
|
||||
schematics.add(s);
|
||||
setup();
|
||||
ui.showInfoFade("$schematic.saved");
|
||||
@@ -168,6 +173,7 @@ public class SchematicsDialog extends FloatingDialog{
|
||||
|
||||
try{
|
||||
Schematic s = Schematics.read(file);
|
||||
s.removeSteamID();
|
||||
schematics.add(s);
|
||||
setup();
|
||||
showInfo(s);
|
||||
|
||||
@@ -95,7 +95,7 @@ public class SettingsMenuDialog extends SettingsDialog{
|
||||
Core.settings.putAll(map);
|
||||
Core.settings.save();
|
||||
|
||||
for(FileHandle file : dataDirectory.list()){
|
||||
for(Fi file : dataDirectory.list()){
|
||||
file.deleteDirectory();
|
||||
}
|
||||
|
||||
@@ -106,7 +106,7 @@ public class SettingsMenuDialog extends SettingsDialog{
|
||||
|
||||
t.addButton("$data.export", style, () -> {
|
||||
if(ios){
|
||||
FileHandle file = Core.files.local("mindustry-data-export.zip");
|
||||
Fi file = Core.files.local("mindustry-data-export.zip");
|
||||
try{
|
||||
data.exportData(file);
|
||||
}catch(Exception e){
|
||||
|
||||
@@ -337,7 +337,7 @@ public class TechTreeDialog extends FloatingDialog{
|
||||
t.table(list -> {
|
||||
list.left();
|
||||
list.addImage(req.item.icon(Cicon.small)).size(8 * 3).padRight(3);
|
||||
list.add(req.item.localizedName()).color(Color.lightGray);
|
||||
list.add(req.item.localizedName).color(Color.lightGray);
|
||||
list.label(() -> " " + Math.min(data.getItem(req.item), req.amount) + " / " + req.amount)
|
||||
.update(l -> l.setColor(data.has(req.item, req.amount) ? Color.lightGray : Color.scarlet));
|
||||
}).fillX().left();
|
||||
|
||||
@@ -96,7 +96,7 @@ public class ZoneInfoDialog extends FloatingDialog{
|
||||
}).growX();
|
||||
|
||||
}else{
|
||||
cont.add(zone.localizedName()).color(Pal.accent).growX().center();
|
||||
cont.add(zone.localizedName).color(Pal.accent).growX().center();
|
||||
cont.row();
|
||||
cont.addImage().color(Pal.accent).height(3).pad(6).growX();
|
||||
cont.row();
|
||||
|
||||
@@ -50,7 +50,7 @@ public class BlockConfigFragment extends Fragment{
|
||||
|
||||
table.visible(true);
|
||||
table.clear();
|
||||
tile.block().buildTable(tile, table);
|
||||
tile.block().buildConfiguration(tile, table);
|
||||
table.pack();
|
||||
table.setTransform(true);
|
||||
table.actions(Actions.scaleTo(0f, 1f), Actions.visible(true),
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user