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:
Anuken
2019-12-24 12:40:23 -05:00
269 changed files with 16452 additions and 13926 deletions

View File

@@ -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);
}
}

View File

@@ -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")){

View File

@@ -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;

View File

@@ -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;

View File

@@ -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 -> {

View File

@@ -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;
}};
}

View File

@@ -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);
}

View File

@@ -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();
}

View File

@@ -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);
}
}

View File

@@ -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()){

View File

@@ -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);

View File

@@ -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){

View File

@@ -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));

View File

@@ -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()));

View File

@@ -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);
}

View File

@@ -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;
}
}
}

View File

@@ -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;
}
}

View File

@@ -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();

View File

@@ -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);
}

View File

@@ -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);

View File

@@ -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);
}

View File

@@ -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;

View File

@@ -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.*;

View File

@@ -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);

View File

@@ -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){

View File

@@ -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));
}

View File

@@ -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;

View File

@@ -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);
}
}

View File

@@ -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! */

View File

@@ -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)){

View File

@@ -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);

View File

@@ -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;
}

View File

@@ -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(){

View File

@@ -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()){

View File

@@ -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);

View File

@@ -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);

View File

@@ -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.*;

View File

@@ -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.*/

View File

@@ -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.");
}

View File

@@ -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){

View File

@@ -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;
}

View File

@@ -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));
}

View File

@@ -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.*;

View File

@@ -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);
}

View File

@@ -157,5 +157,4 @@ public class OverlayRenderer{
}
}
}
}

View File

@@ -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;

View File

@@ -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;

View File

@@ -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){

View File

@@ -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));
}

View File

@@ -1,5 +1,5 @@
package io.anuke.mindustry.input;
enum PlaceMode{
public enum PlaceMode{
none, breaking, placing, schematicSelect
}

View File

@@ -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.*;

View File

@@ -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

View File

@@ -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){

View File

@@ -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{

View File

@@ -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){

View File

@@ -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(

View File

@@ -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;

View File

@@ -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,

View File

@@ -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.*;

View File

@@ -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();
}

View File

@@ -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));
}

View File

@@ -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){

View File

@@ -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);

File diff suppressed because one or more lines are too long

View File

@@ -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() + ")");

View File

@@ -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){

View File

@@ -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);
}
}
}

View File

@@ -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,
}
}

View 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();
}
}

View File

@@ -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);
}
}

View File

@@ -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;

View File

@@ -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));
}
}
}
}

View File

@@ -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{
}

View 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;
}
}

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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;
}
}

View File

@@ -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);

View File

@@ -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);
});
}
}

View File

@@ -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{

View File

@@ -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();

View File

@@ -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;

View File

@@ -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();

View File

@@ -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;

View File

@@ -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();
}
}

View File

@@ -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")),

View File

@@ -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);
}
}

View File

@@ -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;

View File

@@ -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){

View File

@@ -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());

View File

@@ -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() + "]]");

View File

@@ -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){

View File

@@ -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++;
}

View File

@@ -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();

View File

@@ -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);

View File

@@ -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){

View File

@@ -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();

View File

@@ -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();

View File

@@ -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