Merge branch 'master' of https://github.com/Anuken/Mindustry into mech-rework
# Conflicts: # core/assets/sprites/sprites.atlas # core/assets/sprites/sprites.png
This commit is contained in:
BIN
core/assets-raw/sprites/blocks/storage/unloader-center.png
Normal file
BIN
core/assets-raw/sprites/blocks/storage/unloader-center.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.5 KiB |
@@ -16,6 +16,7 @@ screenshot.invalid = Map too large, potentially not enough memory for screenshot
|
|||||||
gameover = Game Over
|
gameover = Game Over
|
||||||
gameover.pvp = The[accent] {0}[] team is victorious!
|
gameover.pvp = The[accent] {0}[] team is victorious!
|
||||||
highscore = [accent]New highscore!
|
highscore = [accent]New highscore!
|
||||||
|
copied = Copied.
|
||||||
|
|
||||||
load.sound = Sounds
|
load.sound = Sounds
|
||||||
load.map = Maps
|
load.map = Maps
|
||||||
@@ -24,6 +25,22 @@ load.content = Content
|
|||||||
load.system = System
|
load.system = System
|
||||||
load.mod = Mods
|
load.mod = Mods
|
||||||
|
|
||||||
|
schematic = Schematic
|
||||||
|
schematic.add = Save Schematic...
|
||||||
|
schematics = Schematics
|
||||||
|
schematic.import = Import Schematic...
|
||||||
|
schematic.exportfile = Export File
|
||||||
|
schematic.importfile = Import File
|
||||||
|
schematic.browseworkshop = Browse Workshop
|
||||||
|
schematic.copy = Copy to Clipboard
|
||||||
|
schematic.copy.import = Import from Clipboard
|
||||||
|
schematic.shareworkshop = Share on Workshop
|
||||||
|
schematic.flip = [accent][[{0}][]/[accent][[{1}][]: Flip Schematic
|
||||||
|
schematic.saved = Schematic saved.
|
||||||
|
schematic.delete.confirm = This schematic will be utterly eradicated.
|
||||||
|
schematic.rename = Rename Schematic
|
||||||
|
schematic.info = {0}x{1}, {2} blocks
|
||||||
|
|
||||||
stat.wave = Waves Defeated:[accent] {0}
|
stat.wave = Waves Defeated:[accent] {0}
|
||||||
stat.enemiesDestroyed = Enemies Destroyed:[accent] {0}
|
stat.enemiesDestroyed = Enemies Destroyed:[accent] {0}
|
||||||
stat.built = Buildings Built:[accent] {0}
|
stat.built = Buildings Built:[accent] {0}
|
||||||
@@ -83,6 +100,8 @@ mod.import.github = Import Github Mod
|
|||||||
mod.remove.confirm = This mod will be deleted.
|
mod.remove.confirm = This mod will be deleted.
|
||||||
mod.author = [LIGHT_GRAY]Author:[] {0}
|
mod.author = [LIGHT_GRAY]Author:[] {0}
|
||||||
mod.missing = This save contains mods that you have recently updated or no longer have installed. Save corruption may occur. Are you sure you want to load it?\n[lightgray]Mods:\n{0}
|
mod.missing = This save contains mods that you have recently updated or no longer have installed. Save corruption may occur. Are you sure you want to load it?\n[lightgray]Mods:\n{0}
|
||||||
|
mod.preview.missing = Before publishing this mod in the workshop, you must add an image preview.\nPlace an image named[accent] preview.png[] into the mod's folder and try again.
|
||||||
|
mod.folder.missing = Only mods in folder form can be published on the workshop.\nTo convert any mod into a folder, simply unzip its file into a folder and delete the old zip, then restart your game or reload your mods.
|
||||||
|
|
||||||
about.button = About
|
about.button = About
|
||||||
name = Name:
|
name = Name:
|
||||||
@@ -218,6 +237,7 @@ loading = [accent]Loading...
|
|||||||
reloading = [accent]Reloading Mods...
|
reloading = [accent]Reloading Mods...
|
||||||
saving = [accent]Saving...
|
saving = [accent]Saving...
|
||||||
cancelbuilding = [accent][[{0}][] to clear plan
|
cancelbuilding = [accent][[{0}][] to clear plan
|
||||||
|
selectschematic = [accent][[{0}][] to select+copy
|
||||||
pausebuilding = [accent][[{0}][] to pause building
|
pausebuilding = [accent][[{0}][] to pause building
|
||||||
resumebuilding = [scarlet][[{0}][] to resume building
|
resumebuilding = [scarlet][[{0}][] to resume building
|
||||||
wave = [accent]Wave {0}
|
wave = [accent]Wave {0}
|
||||||
@@ -238,16 +258,17 @@ map.nospawn = This map does not have any cores for the player to spawn in! Add a
|
|||||||
map.nospawn.pvp = This map does not have any enemy cores for player to spawn into! Add[SCARLET] non-orange[] cores to this map in the editor.
|
map.nospawn.pvp = This map does not have any enemy cores for player to spawn into! Add[SCARLET] non-orange[] cores to this map in the editor.
|
||||||
map.nospawn.attack = This map does not have any enemy cores for player to attack! Add[SCARLET] red[] cores to this map in the editor.
|
map.nospawn.attack = This map does not have any enemy cores for player to attack! Add[SCARLET] red[] cores to this map in the editor.
|
||||||
map.invalid = Error loading map: corrupted or invalid map file.
|
map.invalid = Error loading map: corrupted or invalid map file.
|
||||||
map.publish.error = Error publishing map: {0}
|
workshop.update = Update Item
|
||||||
map.update = Update Map
|
workshop.error = Error fetching workshop details: {0}
|
||||||
map.load.error = Error fetching workshop details: {0}
|
|
||||||
map.missing = This map has been deleted or moved.\n[lightgray]The workshop listing has now been automatically un-linked from the map.
|
|
||||||
map.publish.confirm = Are you sure you want to publish this map?\n\n[lightgray]Make sure you agree to the Workshop EULA first, or your maps will not show up!
|
map.publish.confirm = Are you sure you want to publish this map?\n\n[lightgray]Make sure you agree to the Workshop EULA first, or your maps will not show up!
|
||||||
map.menu = Select what you would like to do with this map.
|
map.menu = Select what you would like to do with this map.
|
||||||
map.changelog = Changelog (optional):
|
changelog = Changelog (optional):
|
||||||
eula = Steam EULA
|
eula = Steam EULA
|
||||||
map.publish = Map published.
|
missing = This item has been deleted or moved.\n[lightgray]The workshop listing has now been automatically un-linked.
|
||||||
map.publishing = [accent]Publishing map...
|
publishing = [accent]Publishing...
|
||||||
|
publish.confirm = Are you sure you want to publish this?\n\n[lightgray]Make sure you agree to the Workshop EULA first, or your items will not show up!
|
||||||
|
publish.error = Error publishing item: {0}
|
||||||
|
|
||||||
editor.brush = Brush
|
editor.brush = Brush
|
||||||
editor.openin = Open In Editor
|
editor.openin = Open In Editor
|
||||||
editor.oregen = Ore Generation
|
editor.oregen = Ore Generation
|
||||||
@@ -627,6 +648,10 @@ keybind.press.axis = Press an axis or key...
|
|||||||
keybind.screenshot.name = Map Screenshot
|
keybind.screenshot.name = Map Screenshot
|
||||||
keybind.move_x.name = Move x
|
keybind.move_x.name = Move x
|
||||||
keybind.move_y.name = Move y
|
keybind.move_y.name = Move y
|
||||||
|
keybind.schematic_select.name = Select Region
|
||||||
|
keybind.schematic_menu.name = Schematic Menu
|
||||||
|
keybind.schematic_flip_x.name = Flip Schematic X
|
||||||
|
keybind.schematic_flip_y.name = Flip Schematic Y
|
||||||
keybind.fullscreen.name = Toggle Fullscreen
|
keybind.fullscreen.name = Toggle Fullscreen
|
||||||
keybind.select.name = Select/Shoot
|
keybind.select.name = Select/Shoot
|
||||||
keybind.diagonal_placement.name = Diagonal Placement
|
keybind.diagonal_placement.name = Diagonal Placement
|
||||||
|
|||||||
BIN
core/assets/sprites/schematic-background.png
Normal file
BIN
core/assets/sprites/schematic-background.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.2 KiB |
@@ -1348,6 +1348,13 @@ spore-press-top
|
|||||||
orig: 64, 64
|
orig: 64, 64
|
||||||
offset: 0, 0
|
offset: 0, 0
|
||||||
index: -1
|
index: -1
|
||||||
|
unloader-center
|
||||||
|
rotate: false
|
||||||
|
xy: 1735, 855
|
||||||
|
size: 32, 32
|
||||||
|
orig: 32, 32
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
arc-heat
|
arc-heat
|
||||||
rotate: false
|
rotate: false
|
||||||
xy: 609, 1262
|
xy: 609, 1262
|
||||||
@@ -1770,14 +1777,14 @@ scale_marker
|
|||||||
index: -1
|
index: -1
|
||||||
scorch1
|
scorch1
|
||||||
rotate: false
|
rotate: false
|
||||||
xy: 1735, 787
|
xy: 1735, 753
|
||||||
size: 28, 100
|
size: 28, 100
|
||||||
orig: 28, 100
|
orig: 28, 100
|
||||||
offset: 0, 0
|
offset: 0, 0
|
||||||
index: -1
|
index: -1
|
||||||
scorch2
|
scorch2
|
||||||
rotate: false
|
rotate: false
|
||||||
xy: 1765, 787
|
xy: 1765, 753
|
||||||
size: 28, 100
|
size: 28, 100
|
||||||
orig: 28, 100
|
orig: 28, 100
|
||||||
offset: 0, 0
|
offset: 0, 0
|
||||||
@@ -4332,7 +4339,7 @@ item-copper-small
|
|||||||
index: -1
|
index: -1
|
||||||
item-copper-tiny
|
item-copper-tiny
|
||||||
rotate: false
|
rotate: false
|
||||||
xy: 1735, 769
|
xy: 1017, 691
|
||||||
size: 16, 16
|
size: 16, 16
|
||||||
orig: 16, 16
|
orig: 16, 16
|
||||||
offset: 0, 0
|
offset: 0, 0
|
||||||
@@ -4367,7 +4374,7 @@ item-graphite-small
|
|||||||
index: -1
|
index: -1
|
||||||
item-graphite-tiny
|
item-graphite-tiny
|
||||||
rotate: false
|
rotate: false
|
||||||
xy: 1017, 691
|
xy: 1533, 777
|
||||||
size: 16, 16
|
size: 16, 16
|
||||||
orig: 16, 16
|
orig: 16, 16
|
||||||
offset: 0, 0
|
offset: 0, 0
|
||||||
@@ -4402,7 +4409,7 @@ item-lead-small
|
|||||||
index: -1
|
index: -1
|
||||||
item-lead-tiny
|
item-lead-tiny
|
||||||
rotate: false
|
rotate: false
|
||||||
xy: 1533, 777
|
xy: 1769, 879
|
||||||
size: 16, 16
|
size: 16, 16
|
||||||
orig: 16, 16
|
orig: 16, 16
|
||||||
offset: 0, 0
|
offset: 0, 0
|
||||||
@@ -4752,7 +4759,7 @@ item-thorium-small
|
|||||||
index: -1
|
index: -1
|
||||||
item-thorium-tiny
|
item-thorium-tiny
|
||||||
rotate: false
|
rotate: false
|
||||||
xy: 1753, 769
|
xy: 1035, 683
|
||||||
size: 16, 16
|
size: 16, 16
|
||||||
orig: 16, 16
|
orig: 16, 16
|
||||||
offset: 0, 0
|
offset: 0, 0
|
||||||
@@ -4787,7 +4794,7 @@ item-titanium-small
|
|||||||
index: -1
|
index: -1
|
||||||
item-titanium-tiny
|
item-titanium-tiny
|
||||||
rotate: false
|
rotate: false
|
||||||
xy: 1035, 683
|
xy: 1769, 861
|
||||||
size: 16, 16
|
size: 16, 16
|
||||||
orig: 16, 16
|
orig: 16, 16
|
||||||
offset: 0, 0
|
offset: 0, 0
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 717 KiB After Width: | Height: | Size: 717 KiB |
@@ -9,6 +9,7 @@ import io.anuke.arc.graphics.g2d.*;
|
|||||||
import io.anuke.arc.math.*;
|
import io.anuke.arc.math.*;
|
||||||
import io.anuke.arc.scene.ui.layout.*;
|
import io.anuke.arc.scene.ui.layout.*;
|
||||||
import io.anuke.arc.util.*;
|
import io.anuke.arc.util.*;
|
||||||
|
import io.anuke.arc.util.async.*;
|
||||||
import io.anuke.mindustry.core.*;
|
import io.anuke.mindustry.core.*;
|
||||||
import io.anuke.mindustry.game.*;
|
import io.anuke.mindustry.game.*;
|
||||||
import io.anuke.mindustry.game.EventType.*;
|
import io.anuke.mindustry.game.EventType.*;
|
||||||
@@ -81,6 +82,7 @@ public abstract class ClientLauncher extends ApplicationCore implements Platform
|
|||||||
add(netClient = new NetClient());
|
add(netClient = new NetClient());
|
||||||
|
|
||||||
assets.load(mods);
|
assets.load(mods);
|
||||||
|
assets.load(schematics);
|
||||||
|
|
||||||
assets.loadRun("contentinit", ContentLoader.class, () -> {
|
assets.loadRun("contentinit", ContentLoader.class, () -> {
|
||||||
content.init();
|
content.init();
|
||||||
@@ -118,10 +120,11 @@ public abstract class ClientLauncher extends ApplicationCore implements Platform
|
|||||||
for(ApplicationListener listener : modules){
|
for(ApplicationListener listener : modules){
|
||||||
listener.init();
|
listener.init();
|
||||||
}
|
}
|
||||||
super.resize(graphics.getWidth(), graphics.getHeight());
|
|
||||||
mods.each(Mod::init);
|
mods.each(Mod::init);
|
||||||
finished = true;
|
finished = true;
|
||||||
Events.fire(new ClientLoadEvent());
|
Events.fire(new ClientLoadEvent());
|
||||||
|
super.resize(graphics.getWidth(), graphics.getHeight());
|
||||||
|
app.post(() -> app.post(() -> app.post(() -> app.post(() -> super.resize(graphics.getWidth(), graphics.getHeight())))));
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
super.update();
|
super.update();
|
||||||
@@ -133,11 +136,7 @@ public abstract class ClientLauncher extends ApplicationCore implements Platform
|
|||||||
long target = (1000 * 1000000) / targetfps; //target in nanos
|
long target = (1000 * 1000000) / targetfps; //target in nanos
|
||||||
long elapsed = Time.timeSinceNanos(lastTime);
|
long elapsed = Time.timeSinceNanos(lastTime);
|
||||||
if(elapsed < target){
|
if(elapsed < target){
|
||||||
try{
|
Threads.sleep((target - elapsed) / 1000000, (int)((target - elapsed) % 1000000));
|
||||||
Thread.sleep((target - elapsed) / 1000000, (int)((target - elapsed) % 1000000));
|
|
||||||
}catch(InterruptedException ignored){
|
|
||||||
//ignore
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -33,6 +33,10 @@ public class Vars implements Loadable{
|
|||||||
public static boolean loadLocales = true;
|
public static boolean loadLocales = true;
|
||||||
/** Maximum number of broken blocks. TODO implement or remove.*/
|
/** Maximum number of broken blocks. TODO implement or remove.*/
|
||||||
public static final int maxBrokenBlocks = 256;
|
public static final int maxBrokenBlocks = 256;
|
||||||
|
/** Maximum schematic size.*/
|
||||||
|
public static final int maxSchematicSize = 32;
|
||||||
|
/** All schematic base64 starts with this string.*/
|
||||||
|
public static final String schematicBaseStart ="bXNjaAB";
|
||||||
/** IO buffer size. */
|
/** IO buffer size. */
|
||||||
public static final int bufferSize = 8192;
|
public static final int bufferSize = 8192;
|
||||||
/** global charset, since Android doesn't support the Charsets class */
|
/** global charset, since Android doesn't support the Charsets class */
|
||||||
@@ -128,10 +132,14 @@ public class Vars implements Loadable{
|
|||||||
public static FileHandle saveDirectory;
|
public static FileHandle saveDirectory;
|
||||||
/** data subdirectory used for mods */
|
/** data subdirectory used for mods */
|
||||||
public static FileHandle modDirectory;
|
public static FileHandle modDirectory;
|
||||||
|
/** data subdirectory used for schematics */
|
||||||
|
public static FileHandle schematicDirectory;
|
||||||
/** map file extension */
|
/** map file extension */
|
||||||
public static final String mapExtension = "msav";
|
public static final String mapExtension = "msav";
|
||||||
/** save file extension */
|
/** save file extension */
|
||||||
public static final String saveExtension = "msav";
|
public static final String saveExtension = "msav";
|
||||||
|
/** schematic file extension */
|
||||||
|
public static final String schematicExtension = "msch";
|
||||||
|
|
||||||
/** list of all locales that can be switched to */
|
/** list of all locales that can be switched to */
|
||||||
public static Locale[] locales;
|
public static Locale[] locales;
|
||||||
@@ -146,6 +154,7 @@ public class Vars implements Loadable{
|
|||||||
public static LoopControl loops;
|
public static LoopControl loops;
|
||||||
public static Platform platform = new Platform(){};
|
public static Platform platform = new Platform(){};
|
||||||
public static Mods mods;
|
public static Mods mods;
|
||||||
|
public static Schematics schematics = new Schematics();
|
||||||
|
|
||||||
public static World world;
|
public static World world;
|
||||||
public static Maps maps;
|
public static Maps maps;
|
||||||
@@ -251,6 +260,7 @@ public class Vars implements Loadable{
|
|||||||
saveDirectory = dataDirectory.child("saves/");
|
saveDirectory = dataDirectory.child("saves/");
|
||||||
tmpDirectory = dataDirectory.child("tmp/");
|
tmpDirectory = dataDirectory.child("tmp/");
|
||||||
modDirectory = dataDirectory.child("mods/");
|
modDirectory = dataDirectory.child("mods/");
|
||||||
|
schematicDirectory = dataDirectory.child("schematics/");
|
||||||
|
|
||||||
modDirectory.mkdirs();
|
modDirectory.mkdirs();
|
||||||
|
|
||||||
|
|||||||
@@ -1344,7 +1344,8 @@ public class Blocks implements ContentList{
|
|||||||
Items.pyratite, Bullets.pyraFlame
|
Items.pyratite, Bullets.pyraFlame
|
||||||
);
|
);
|
||||||
recoil = 0f;
|
recoil = 0f;
|
||||||
reload = 4f;
|
reload = 5f;
|
||||||
|
coolantMultiplier = 2f;
|
||||||
range = 60f;
|
range = 60f;
|
||||||
shootCone = 50f;
|
shootCone = 50f;
|
||||||
targetAir = false;
|
targetAir = false;
|
||||||
|
|||||||
@@ -99,8 +99,7 @@ public class Bullets implements ContentList{
|
|||||||
collidesTiles = false;
|
collidesTiles = false;
|
||||||
splashDamageRadius = 25f;
|
splashDamageRadius = 25f;
|
||||||
splashDamage = 30f;
|
splashDamage = 30f;
|
||||||
incendAmount = 4;
|
status = StatusEffects.burning;
|
||||||
incendSpread = 11f;
|
|
||||||
frontColor = Pal.lightishOrange;
|
frontColor = Pal.lightishOrange;
|
||||||
backColor = Pal.lightOrange;
|
backColor = Pal.lightOrange;
|
||||||
trailEffect = Fx.incendTrail;
|
trailEffect = Fx.incendTrail;
|
||||||
@@ -228,8 +227,7 @@ public class Bullets implements ContentList{
|
|||||||
splashDamage = 10f;
|
splashDamage = 10f;
|
||||||
lifetime = 160f;
|
lifetime = 160f;
|
||||||
hitEffect = Fx.blastExplosion;
|
hitEffect = Fx.blastExplosion;
|
||||||
incendSpread = 10f;
|
status = StatusEffects.burning;
|
||||||
incendAmount = 3;
|
|
||||||
}};
|
}};
|
||||||
|
|
||||||
missileSurge = new MissileBulletType(4.4f, 15, "bullet"){{
|
missileSurge = new MissileBulletType(4.4f, 15, "bullet"){{
|
||||||
@@ -342,9 +340,7 @@ public class Bullets implements ContentList{
|
|||||||
bulletHeight = 12f;
|
bulletHeight = 12f;
|
||||||
frontColor = Pal.lightishOrange;
|
frontColor = Pal.lightishOrange;
|
||||||
backColor = Pal.lightOrange;
|
backColor = Pal.lightOrange;
|
||||||
incendSpread = 3f;
|
status = StatusEffects.burning;
|
||||||
incendAmount = 1;
|
|
||||||
incendChance = 0.3f;
|
|
||||||
inaccuracy = 3f;
|
inaccuracy = 3f;
|
||||||
lifetime = 60f;
|
lifetime = 60f;
|
||||||
}};
|
}};
|
||||||
@@ -354,9 +350,7 @@ public class Bullets implements ContentList{
|
|||||||
bulletHeight = 12f;
|
bulletHeight = 12f;
|
||||||
frontColor = Color.valueOf("feb380");
|
frontColor = Color.valueOf("feb380");
|
||||||
backColor = Color.valueOf("ea8878");
|
backColor = Color.valueOf("ea8878");
|
||||||
incendSpread = 3f;
|
status = StatusEffects.burning;
|
||||||
incendAmount = 1;
|
|
||||||
incendChance = 0.3f;
|
|
||||||
lifetime = 60f;
|
lifetime = 60f;
|
||||||
}};
|
}};
|
||||||
|
|
||||||
@@ -385,9 +379,7 @@ public class Bullets implements ContentList{
|
|||||||
bulletHeight = 21f;
|
bulletHeight = 21f;
|
||||||
frontColor = Pal.lightishOrange;
|
frontColor = Pal.lightishOrange;
|
||||||
backColor = Pal.lightOrange;
|
backColor = Pal.lightOrange;
|
||||||
incendSpread = 3f;
|
status = StatusEffects.burning;
|
||||||
incendAmount = 2;
|
|
||||||
incendChance = 0.3f;
|
|
||||||
shootEffect = Fx.shootBig;
|
shootEffect = Fx.shootBig;
|
||||||
}};
|
}};
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ public class StatusEffects implements ContentList{
|
|||||||
none = new StatusEffect();
|
none = new StatusEffect();
|
||||||
|
|
||||||
burning = new StatusEffect(){{
|
burning = new StatusEffect(){{
|
||||||
damage = 0.04f;
|
damage = 0.06f;
|
||||||
effect = Fx.burning;
|
effect = Fx.burning;
|
||||||
|
|
||||||
opposite(() -> wet, () -> freezing);
|
opposite(() -> wet, () -> freezing);
|
||||||
|
|||||||
@@ -317,9 +317,9 @@ public class TechTree implements ContentList{
|
|||||||
return node(block, () -> {});
|
return node(block, () -> {});
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void create(Block parent, Block block){
|
public static TechNode create(Block parent, Block block){
|
||||||
TechNode.context = all.find(t -> t.block == parent);
|
TechNode.context = all.find(t -> t.block == parent);
|
||||||
node(block, () -> {});
|
return node(block, () -> {});
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class TechNode{
|
public static class TechNode{
|
||||||
|
|||||||
@@ -8,9 +8,9 @@ import io.anuke.arc.function.*;
|
|||||||
import io.anuke.arc.math.*;
|
import io.anuke.arc.math.*;
|
||||||
import io.anuke.arc.scene.ui.*;
|
import io.anuke.arc.scene.ui.*;
|
||||||
import io.anuke.arc.util.serialization.*;
|
import io.anuke.arc.util.serialization.*;
|
||||||
import io.anuke.mindustry.maps.*;
|
|
||||||
import io.anuke.mindustry.net.*;
|
import io.anuke.mindustry.net.*;
|
||||||
import io.anuke.mindustry.net.Net.*;
|
import io.anuke.mindustry.net.Net.*;
|
||||||
|
import io.anuke.mindustry.type.*;
|
||||||
import io.anuke.mindustry.ui.dialogs.*;
|
import io.anuke.mindustry.ui.dialogs.*;
|
||||||
|
|
||||||
import static io.anuke.mindustry.Vars.mobile;
|
import static io.anuke.mindustry.Vars.mobile;
|
||||||
@@ -24,27 +24,18 @@ public interface Platform{
|
|||||||
default void inviteFriends(){}
|
default void inviteFriends(){}
|
||||||
|
|
||||||
/** Steam: Share a map on the workshop.*/
|
/** Steam: Share a map on the workshop.*/
|
||||||
default void publishMap(Map map){}
|
default void publish(Publishable pub){}
|
||||||
|
|
||||||
/** Steam: Return external workshop maps to be loaded.*/
|
|
||||||
default Array<FileHandle> getExternalMaps(){
|
|
||||||
return Array.with();
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Steam: Return external workshop mods to be loaded.*/
|
|
||||||
default Array<FileHandle> getExternalMods(){
|
|
||||||
return Array.with();
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Steam: View a map listing on the workshop.*/
|
|
||||||
default void viewMapListing(Map map){}
|
|
||||||
|
|
||||||
/** Steam: View a listing on the workshop.*/
|
/** Steam: View a listing on the workshop.*/
|
||||||
default void viewListing(String mapid){}
|
default void viewListing(Publishable pub){}
|
||||||
|
|
||||||
/** Steam: View map workshop info, removing the map ID tag if its listing is deleted.
|
/** Steam: View a listing on the workshop by an ID.*/
|
||||||
* Also presents the option to update the map. */
|
default void viewListingID(String mapid){}
|
||||||
default void viewMapListingInfo(Map map){}
|
|
||||||
|
/** Steam: Return external workshop maps to be loaded.*/
|
||||||
|
default Array<FileHandle> getWorkshopContent(Class<? extends Publishable> type){
|
||||||
|
return new Array<>(0);
|
||||||
|
}
|
||||||
|
|
||||||
/** Steam: Open workshop for maps.*/
|
/** Steam: Open workshop for maps.*/
|
||||||
default void openWorkshop(){}
|
default void openWorkshop(){}
|
||||||
|
|||||||
@@ -68,6 +68,7 @@ public class UI implements ApplicationListener, Loadable{
|
|||||||
public DeployDialog deploy;
|
public DeployDialog deploy;
|
||||||
public TechTreeDialog tech;
|
public TechTreeDialog tech;
|
||||||
public MinimapDialog minimap;
|
public MinimapDialog minimap;
|
||||||
|
public SchematicsDialog schematics;
|
||||||
public ModsDialog mods;
|
public ModsDialog mods;
|
||||||
|
|
||||||
public Cursor drillCursor, unloadCursor;
|
public Cursor drillCursor, unloadCursor;
|
||||||
@@ -185,6 +186,13 @@ public class UI implements ApplicationListener, Loadable{
|
|||||||
Core.scene.act();
|
Core.scene.act();
|
||||||
Core.scene.draw();
|
Core.scene.draw();
|
||||||
|
|
||||||
|
if(Core.input.keyTap(KeyCode.MOUSE_LEFT) && Core.scene.getKeyboardFocus() instanceof TextField){
|
||||||
|
Element e = Core.scene.hit(Core.input.mouseX(), Core.input.mouseY(), true);
|
||||||
|
if(!(e instanceof TextField)){
|
||||||
|
Core.scene.setKeyboardFocus(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//draw overlay for buttons
|
//draw overlay for buttons
|
||||||
if(state.rules.tutorial){
|
if(state.rules.tutorial){
|
||||||
control.tutorial.draw();
|
control.tutorial.draw();
|
||||||
@@ -225,6 +233,7 @@ public class UI implements ApplicationListener, Loadable{
|
|||||||
tech = new TechTreeDialog();
|
tech = new TechTreeDialog();
|
||||||
minimap = new MinimapDialog();
|
minimap = new MinimapDialog();
|
||||||
mods = new ModsDialog();
|
mods = new ModsDialog();
|
||||||
|
schematics = new SchematicsDialog();
|
||||||
|
|
||||||
Group group = Core.scene.root;
|
Group group = Core.scene.root;
|
||||||
|
|
||||||
@@ -296,7 +305,7 @@ public class UI implements ApplicationListener, Loadable{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void showTextInput(String title, String text, String def, Consumer<String> confirmed){
|
public void showTextInput(String title, String text, String def, Consumer<String> confirmed){
|
||||||
showTextInput(title, text, 24, def, confirmed);
|
showTextInput(title, text, 32, def, confirmed);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void showTextInput(String titleText, String text, int textLength, String def, Consumer<String> confirmed){
|
public void showTextInput(String titleText, String text, int textLength, String def, Consumer<String> confirmed){
|
||||||
@@ -307,7 +316,7 @@ public class UI implements ApplicationListener, Loadable{
|
|||||||
Table table = new Table();
|
Table table = new Table();
|
||||||
table.setFillParent(true);
|
table.setFillParent(true);
|
||||||
table.actions(Actions.fadeOut(7f, Interpolation.fade), Actions.remove());
|
table.actions(Actions.fadeOut(7f, Interpolation.fade), Actions.remove());
|
||||||
table.top().add(info).padTop(10);
|
table.top().add(info).style(Styles.outlineLabel).padTop(10);
|
||||||
Core.scene.add(table);
|
Core.scene.add(table);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -149,15 +149,16 @@ public class MapEditorDialog extends Dialog implements Disposable{
|
|||||||
if(steam){
|
if(steam){
|
||||||
menu.cont.addImageTextButton("$editor.publish.workshop", Icon.linkSmall, () -> {
|
menu.cont.addImageTextButton("$editor.publish.workshop", Icon.linkSmall, () -> {
|
||||||
Map builtin = maps.all().find(m -> m.name().equals(editor.getTags().get("name", "").trim()));
|
Map builtin = maps.all().find(m -> m.name().equals(editor.getTags().get("name", "").trim()));
|
||||||
|
|
||||||
if(editor.getTags().containsKey("steamid") && builtin != null && !builtin.custom){
|
if(editor.getTags().containsKey("steamid") && builtin != null && !builtin.custom){
|
||||||
platform.viewListing(editor.getTags().get("steamid"));
|
platform.viewListingID(editor.getTags().get("steamid"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Map map = save();
|
Map map = save();
|
||||||
|
|
||||||
if(editor.getTags().containsKey("steamid") && map != null){
|
if(editor.getTags().containsKey("steamid") && map != null){
|
||||||
platform.viewMapListingInfo(map);
|
platform.viewListing(map);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -173,7 +174,7 @@ public class MapEditorDialog extends Dialog implements Disposable{
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
platform.publishMap(map);
|
platform.publish(map);
|
||||||
}).padTop(-3).size(swidth * 2f + 10, 60f).update(b -> b.setText(editor.getTags().containsKey("steamid") ? editor.getTags().get("author").equals(player.name) ? "$workshop.listing" : "$view.workshop" : "$editor.publish.workshop"));
|
}).padTop(-3).size(swidth * 2f + 10, 60f).update(b -> b.setText(editor.getTags().containsKey("steamid") ? editor.getTags().get("author").equals(player.name) ? "$workshop.listing" : "$view.workshop" : "$editor.publish.workshop"));
|
||||||
|
|
||||||
menu.cont.row();
|
menu.cont.row();
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ public abstract class BulletType extends Content{
|
|||||||
/** Status effect applied on hit. */
|
/** Status effect applied on hit. */
|
||||||
public StatusEffect status = StatusEffects.none;
|
public StatusEffect status = StatusEffects.none;
|
||||||
/** Intensity of applied status effect in terms of duration. */
|
/** Intensity of applied status effect in terms of duration. */
|
||||||
public float statusDuration = 60 * 1f;
|
public float statusDuration = 60 * 10f;
|
||||||
/** Whether this bullet type collides with tiles. */
|
/** Whether this bullet type collides with tiles. */
|
||||||
public boolean collidesTiles = true;
|
public boolean collidesTiles = true;
|
||||||
/** Whether this bullet type collides with tiles that are of the same team. */
|
/** Whether this bullet type collides with tiles that are of the same team. */
|
||||||
|
|||||||
@@ -104,7 +104,7 @@ public interface BuilderTrait extends Entity, TeamTrait{
|
|||||||
if(current.breaking){
|
if(current.breaking){
|
||||||
entity.deconstruct(unit, core, 1f / entity.buildCost * Time.delta() * getBuildPower(tile) * state.rules.buildSpeedMultiplier);
|
entity.deconstruct(unit, core, 1f / entity.buildCost * Time.delta() * getBuildPower(tile) * state.rules.buildSpeedMultiplier);
|
||||||
}else{
|
}else{
|
||||||
if(entity.construct(unit, core, 1f / entity.buildCost * Time.delta() * getBuildPower(tile) * state.rules.buildSpeedMultiplier)){
|
if(entity.construct(unit, core, 1f / entity.buildCost * Time.delta() * getBuildPower(tile) * state.rules.buildSpeedMultiplier, current.hasConfig)){
|
||||||
if(current.hasConfig){
|
if(current.hasConfig){
|
||||||
Call.onTileConfig(null, tile, current.config);
|
Call.onTileConfig(null, tile, current.config);
|
||||||
}
|
}
|
||||||
@@ -267,18 +267,26 @@ public interface BuilderTrait extends Entity, TeamTrait{
|
|||||||
|
|
||||||
/** Class for storing build requests. Can be either a place or remove request. */
|
/** Class for storing build requests. Can be either a place or remove request. */
|
||||||
class BuildRequest{
|
class BuildRequest{
|
||||||
|
/** Position and rotation of this request. */
|
||||||
public int x, y, rotation;
|
public int x, y, rotation;
|
||||||
|
/** Block being placed. If null, this is a breaking request.*/
|
||||||
public @Nullable Block block;
|
public @Nullable Block block;
|
||||||
|
/** Whether this is a break request.*/
|
||||||
public boolean breaking;
|
public boolean breaking;
|
||||||
|
/** Whether this request comes with a config int. If yes, any blocks placed with this request will not call playerPlaced.*/
|
||||||
public boolean hasConfig;
|
public boolean hasConfig;
|
||||||
|
/** Config int. Not used unless hasConfig is true.*/
|
||||||
public int config;
|
public int config;
|
||||||
|
/** Original position, only used in schematics.*/
|
||||||
|
public int originalX, originalY, originalWidth, originalHeight;
|
||||||
|
|
||||||
|
/** Last progress.*/
|
||||||
public float progress;
|
public float progress;
|
||||||
|
/** Whether construction has started for this request.*/
|
||||||
public boolean initialized;
|
public boolean initialized;
|
||||||
|
|
||||||
//animation variables
|
/** Visual scale. Used only for rendering.*/
|
||||||
public float animScale = 0f;
|
public float animScale = 0f;
|
||||||
public float animInvalid;
|
|
||||||
|
|
||||||
/** This creates a build request. */
|
/** This creates a build request. */
|
||||||
public BuildRequest(int x, int y, int rotation, Block block){
|
public BuildRequest(int x, int y, int rotation, Block block){
|
||||||
@@ -302,6 +310,31 @@ public interface BuilderTrait extends Entity, TeamTrait{
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public BuildRequest copy(){
|
||||||
|
BuildRequest copy = new BuildRequest();
|
||||||
|
copy.x = x;
|
||||||
|
copy.y = y;
|
||||||
|
copy.rotation = rotation;
|
||||||
|
copy.block = block;
|
||||||
|
copy.breaking = breaking;
|
||||||
|
copy.hasConfig = hasConfig;
|
||||||
|
copy.config = config;
|
||||||
|
copy.originalX = originalX;
|
||||||
|
copy.originalY = originalY;
|
||||||
|
copy.progress = progress;
|
||||||
|
copy.initialized = initialized;
|
||||||
|
copy.animScale = animScale;
|
||||||
|
return copy;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BuildRequest original(int x, int y, int originalWidth, int originalHeight){
|
||||||
|
originalX = x;
|
||||||
|
originalY = y;
|
||||||
|
this.originalWidth = originalWidth;
|
||||||
|
this.originalHeight = originalHeight;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
public Rectangle bounds(Rectangle rect){
|
public Rectangle bounds(Rectangle rect){
|
||||||
if(breaking){
|
if(breaking){
|
||||||
return rect.set(-100f, -100f, 0f, 0f);
|
return rect.set(-100f, -100f, 0f, 0f);
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package io.anuke.mindustry.entities.type;
|
package io.anuke.mindustry.entities.type;
|
||||||
|
|
||||||
|
import io.anuke.mindustry.*;
|
||||||
import io.anuke.mindustry.entities.EntityGroup;
|
import io.anuke.mindustry.entities.EntityGroup;
|
||||||
import io.anuke.mindustry.entities.traits.Entity;
|
import io.anuke.mindustry.entities.traits.Entity;
|
||||||
|
|
||||||
@@ -14,6 +15,14 @@ public abstract class BaseEntity implements Entity{
|
|||||||
id = lastid++;
|
id = lastid++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int tileX(){
|
||||||
|
return Vars.world.toTile(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int tileY(){
|
||||||
|
return Vars.world.toTile(y);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getID(){
|
public int getID(){
|
||||||
return id;
|
return id;
|
||||||
|
|||||||
@@ -801,6 +801,7 @@ public class Player extends Unit implements BuilderMinerTrait, ShooterTrait{
|
|||||||
textFadeTime = 0f;
|
textFadeTime = 0f;
|
||||||
target = null;
|
target = null;
|
||||||
moveTarget = null;
|
moveTarget = null;
|
||||||
|
isShooting = isBoosting = isTransferring = isTyping = false;
|
||||||
spawner = lastSpawner = null;
|
spawner = lastSpawner = null;
|
||||||
health = maxHealth();
|
health = maxHealth();
|
||||||
mining = null;
|
mining = null;
|
||||||
|
|||||||
@@ -39,6 +39,9 @@ public class GlobalData{
|
|||||||
files.add(Core.settings.getSettingsFile());
|
files.add(Core.settings.getSettingsFile());
|
||||||
files.addAll(customMapDirectory.list());
|
files.addAll(customMapDirectory.list());
|
||||||
files.addAll(saveDirectory.list());
|
files.addAll(saveDirectory.list());
|
||||||
|
files.addAll(screenshotDirectory.list());
|
||||||
|
files.addAll(modDirectory.list());
|
||||||
|
files.addAll(schematicDirectory.list());
|
||||||
String base = Core.settings.getDataDirectory().path();
|
String base = Core.settings.getDataDirectory().path();
|
||||||
|
|
||||||
try(OutputStream fos = file.write(false, 2048); ZipOutputStream zos = new ZipOutputStream(fos)){
|
try(OutputStream fos = file.write(false, 2048); ZipOutputStream zos = new ZipOutputStream(fos)){
|
||||||
|
|||||||
111
core/src/io/anuke/mindustry/game/Schematic.java
Normal file
111
core/src/io/anuke/mindustry/game/Schematic.java
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
package io.anuke.mindustry.game;
|
||||||
|
|
||||||
|
import io.anuke.arc.collection.*;
|
||||||
|
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.game.Schematics.*;
|
||||||
|
import io.anuke.mindustry.type.*;
|
||||||
|
import io.anuke.mindustry.world.*;
|
||||||
|
|
||||||
|
import static io.anuke.mindustry.Vars.*;
|
||||||
|
|
||||||
|
public class Schematic implements Publishable{
|
||||||
|
public final Array<Stile> tiles;
|
||||||
|
public StringMap tags;
|
||||||
|
public int width, height;
|
||||||
|
public @Nullable FileHandle file;
|
||||||
|
|
||||||
|
public Schematic(Array<Stile> tiles, StringMap tags, int width, int height){
|
||||||
|
this.tiles = tiles;
|
||||||
|
this.tags = tags;
|
||||||
|
this.width = width;
|
||||||
|
this.height = height;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Array<ItemStack> requirements(){
|
||||||
|
IntIntMap amounts = new IntIntMap();
|
||||||
|
|
||||||
|
tiles.each(t -> {
|
||||||
|
for(ItemStack stack : t.block.requirements){
|
||||||
|
amounts.getAndIncrement(stack.item.id, 0, stack.amount);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
Array<ItemStack> stacks = new Array<>();
|
||||||
|
for(Entry ent : amounts.entries()){
|
||||||
|
stacks.add(new ItemStack(Vars.content.item(ent.key), ent.value));
|
||||||
|
}
|
||||||
|
stacks.sort();
|
||||||
|
return stacks;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String name(){
|
||||||
|
return tags.get("name", "unknown");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void save(){
|
||||||
|
schematics.saveChanges(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getSteamID(){
|
||||||
|
return tags.get("steamid");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addSteamID(String id){
|
||||||
|
tags.put("steamid", id);
|
||||||
|
save();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void removeSteamID(){
|
||||||
|
tags.remove("steamid");
|
||||||
|
save();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String steamTitle(){
|
||||||
|
return name();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String steamDescription(){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String steamTag(){
|
||||||
|
return "schematic";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FileHandle createSteamFolder(String id){
|
||||||
|
FileHandle 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");
|
||||||
|
schematics.savePreview(this, PreviewRes.high, preview);
|
||||||
|
return preview;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Stile{
|
||||||
|
public @NonNull Block block;
|
||||||
|
public short x, y;
|
||||||
|
public int config;
|
||||||
|
public byte rotation;
|
||||||
|
|
||||||
|
public Stile(Block block, int x, int y, int config, byte rotation){
|
||||||
|
this.block = block;
|
||||||
|
this.x = (short)x;
|
||||||
|
this.y = (short)y;
|
||||||
|
this.config = config;
|
||||||
|
this.rotation = rotation;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
380
core/src/io/anuke/mindustry/game/Schematics.java
Normal file
380
core/src/io/anuke/mindustry/game/Schematics.java
Normal file
@@ -0,0 +1,380 @@
|
|||||||
|
package io.anuke.mindustry.game;
|
||||||
|
|
||||||
|
import io.anuke.arc.*;
|
||||||
|
import io.anuke.arc.assets.*;
|
||||||
|
import io.anuke.arc.collection.*;
|
||||||
|
import io.anuke.arc.files.*;
|
||||||
|
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.io.Streams.*;
|
||||||
|
import io.anuke.arc.util.serialization.*;
|
||||||
|
import io.anuke.mindustry.*;
|
||||||
|
import io.anuke.mindustry.content.*;
|
||||||
|
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.PlaceUtils.*;
|
||||||
|
import io.anuke.mindustry.type.*;
|
||||||
|
import io.anuke.mindustry.world.*;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
import java.util.zip.*;
|
||||||
|
|
||||||
|
import static io.anuke.mindustry.Vars.*;
|
||||||
|
|
||||||
|
/** Handles schematics.*/
|
||||||
|
public class Schematics implements Loadable{
|
||||||
|
private static final byte[] header = {'m', 's', 'c', 'h'};
|
||||||
|
private static final byte version = 0;
|
||||||
|
|
||||||
|
private static final int padding = 2;
|
||||||
|
|
||||||
|
private OptimizedByteArrayOutputStream out = new OptimizedByteArrayOutputStream(1024);
|
||||||
|
private Array<Schematic> all = new Array<>();
|
||||||
|
private OrderedMap<Schematic, ObjectMap<PreviewRes, FrameBuffer>> previews = new OrderedMap<>();
|
||||||
|
private FrameBuffer shadowBuffer;
|
||||||
|
|
||||||
|
public Schematics(){
|
||||||
|
Events.on(DisposeEvent.class, e -> {
|
||||||
|
previews.each((schem, m) -> m.each((res, buffer) -> buffer.dispose()));
|
||||||
|
previews.clear();
|
||||||
|
shadowBuffer.dispose();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void loadSync(){
|
||||||
|
load();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Load all schematics in the folder immediately.*/
|
||||||
|
public void load(){
|
||||||
|
all.clear();
|
||||||
|
|
||||||
|
for(FileHandle file : schematicDirectory.list()){
|
||||||
|
loadFile(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
platform.getWorkshopContent(Schematic.class).each(this::loadFile);
|
||||||
|
|
||||||
|
Core.app.post(() -> {
|
||||||
|
shadowBuffer = new FrameBuffer(maxSchematicSize + padding + 2, maxSchematicSize + padding + 2);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void loadFile(FileHandle file){
|
||||||
|
if(!file.extension().equals(schematicExtension)) return;
|
||||||
|
|
||||||
|
try{
|
||||||
|
Schematic s = read(file);
|
||||||
|
all.add(s);
|
||||||
|
|
||||||
|
//external file from workshop
|
||||||
|
if(!s.file.parent().equals(schematicDirectory)){
|
||||||
|
s.tags.put("steamid", s.file.parent().name());
|
||||||
|
}
|
||||||
|
}catch(IOException e){
|
||||||
|
Log.err(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Array<Schematic> all(){
|
||||||
|
return all;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void saveChanges(Schematic s){
|
||||||
|
if(s.file != null){
|
||||||
|
try{
|
||||||
|
write(s, s.file);
|
||||||
|
}catch(Exception e){
|
||||||
|
ui.showException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void savePreview(Schematic schematic, PreviewRes res, FileHandle file){
|
||||||
|
FrameBuffer buffer = getBuffer(schematic, res);
|
||||||
|
Draw.flush();
|
||||||
|
buffer.begin();
|
||||||
|
Pixmap pixmap = ScreenUtils.getFrameBufferPixmap(0, 0, buffer.getWidth(), buffer.getHeight());
|
||||||
|
file.writePNG(pixmap);
|
||||||
|
buffer.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Texture getPreview(Schematic schematic, PreviewRes res){
|
||||||
|
return getBuffer(schematic, res).getTexture();
|
||||||
|
}
|
||||||
|
|
||||||
|
public FrameBuffer getBuffer(Schematic schematic, PreviewRes res){
|
||||||
|
if(!previews.getOr(schematic, ObjectMap::new).containsKey(res)){
|
||||||
|
int resolution = res.resolution;
|
||||||
|
Draw.blend();
|
||||||
|
Draw.reset();
|
||||||
|
Time.mark();
|
||||||
|
Tmp.m1.set(Draw.proj());
|
||||||
|
Tmp.m2.set(Draw.trans());
|
||||||
|
FrameBuffer buffer = new FrameBuffer((schematic.width + padding) * resolution, (schematic.height + padding) * resolution);
|
||||||
|
|
||||||
|
shadowBuffer.beginDraw(Color.clear);
|
||||||
|
|
||||||
|
Draw.trans().idt();
|
||||||
|
Draw.proj().setOrtho(0, 0, shadowBuffer.getWidth(), shadowBuffer.getHeight());
|
||||||
|
|
||||||
|
Draw.color();
|
||||||
|
schematic.tiles.each(t -> {
|
||||||
|
int size = t.block.size;
|
||||||
|
int offsetx = -(size - 1) / 2;
|
||||||
|
int offsety = -(size - 1) / 2;
|
||||||
|
for(int dx = 0; dx < size; dx++){
|
||||||
|
for(int dy = 0; dy < size; dy++){
|
||||||
|
int wx = t.x + dx + offsetx;
|
||||||
|
int wy = t.y + dy + offsety;
|
||||||
|
Fill.square(padding/2f + wx + 0.5f, padding/2f + wy + 0.5f, 0.5f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
shadowBuffer.endDraw();
|
||||||
|
|
||||||
|
buffer.beginDraw(Color.clear);
|
||||||
|
|
||||||
|
Draw.proj().setOrtho(0, buffer.getHeight(), buffer.getWidth(), -buffer.getHeight());
|
||||||
|
|
||||||
|
Tmp.tr1.set(shadowBuffer.getTexture(), 0, 0, schematic.width + padding, schematic.height + padding);
|
||||||
|
Draw.color(0f, 0f, 0f, 1f);
|
||||||
|
Draw.rect(Tmp.tr1, buffer.getWidth()/2f, buffer.getHeight()/2f, buffer.getWidth(), -buffer.getHeight());
|
||||||
|
Draw.color();
|
||||||
|
|
||||||
|
Array<BuildRequest> requests = schematic.tiles.map(t -> new BuildRequest(t.x, t.y, t.rotation, t.block).configure(t.config));
|
||||||
|
|
||||||
|
Draw.flush();
|
||||||
|
//scale each request to fit schematic
|
||||||
|
Draw.trans().scale(resolution / tilesize, resolution / tilesize).translate(tilesize*1.5f, tilesize*1.5f);
|
||||||
|
|
||||||
|
//draw requests
|
||||||
|
requests.each(req -> {
|
||||||
|
req.animScale = 1f;
|
||||||
|
req.block.drawRequestRegion(req, requests::each);
|
||||||
|
});
|
||||||
|
|
||||||
|
requests.each(req -> req.block.drawRequestConfigTop(req, requests::each));
|
||||||
|
|
||||||
|
Draw.flush();
|
||||||
|
Draw.trans().idt();
|
||||||
|
|
||||||
|
buffer.endDraw();
|
||||||
|
|
||||||
|
Draw.proj(Tmp.m1);
|
||||||
|
Draw.trans(Tmp.m2);
|
||||||
|
|
||||||
|
previews.getOr(schematic, ObjectMap::new).put(res, buffer);
|
||||||
|
Log.info("Time taken: {0}", Time.elapsed());
|
||||||
|
}
|
||||||
|
|
||||||
|
return previews.get(schematic).get(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Creates an array of build requests from a schematic's data, centered on the provided x+y coordinates. */
|
||||||
|
public Array<BuildRequest> toRequests(Schematic schem, int x, int y){
|
||||||
|
return schem.tiles.map(t -> new BuildRequest(t.x + x - schem.width/2, t.y + y - schem.height/2, t.rotation, t.block).original(t.x, t.y, schem.width, schem.height).configure(t.config)).removeAll(s -> !s.block.isVisible());
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Adds a schematic to the list, also copying it into the files.*/
|
||||||
|
public void add(Schematic schematic){
|
||||||
|
all.add(schematic);
|
||||||
|
try{
|
||||||
|
write(schematic, schematicDirectory.child(Time.millis() + "." + schematicExtension));
|
||||||
|
}catch(IOException e){
|
||||||
|
Log.err(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void remove(Schematic s){
|
||||||
|
all.remove(s);
|
||||||
|
if(s.file != null){
|
||||||
|
s.file.delete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Creates a schematic from a world selection. */
|
||||||
|
public Schematic create(int x, int y, int x2, int y2){
|
||||||
|
NormalizeResult result = PlaceUtils.normalizeArea(x, y, x2, y2, 0, false, maxSchematicSize);
|
||||||
|
x = result.x;
|
||||||
|
y = result.y;
|
||||||
|
x2 = result.x2;
|
||||||
|
y2 = result.y2;
|
||||||
|
|
||||||
|
Array<Stile> tiles = new Array<>();
|
||||||
|
|
||||||
|
int minx = x2, miny = y2, maxx = x, maxy = y;
|
||||||
|
boolean found = false;
|
||||||
|
for(int cx = x; cx <= x2; cx++){
|
||||||
|
for(int cy = y; cy <= y2; cy++){
|
||||||
|
Tile linked = world.ltile(cx, cy);
|
||||||
|
|
||||||
|
if(linked != null && linked.entity != null && linked.entity.block.isVisible()){
|
||||||
|
int top = linked.block().size/2;
|
||||||
|
int bot = linked.block().size % 2 == 1 ? -linked.block().size/2 : -(linked.block().size - 1)/2;
|
||||||
|
minx = Math.min(linked.x + bot, minx);
|
||||||
|
miny = Math.min(linked.y + bot, miny);
|
||||||
|
maxx = Math.max(linked.x + top, maxx);
|
||||||
|
maxy = Math.max(linked.y + top, maxy);
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(found){
|
||||||
|
x = minx;
|
||||||
|
y = miny;
|
||||||
|
x2 = maxx;
|
||||||
|
y2 = maxy;
|
||||||
|
}else{
|
||||||
|
return new Schematic(new Array<>(), new StringMap(), 1, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int width = x2 - x + 1, height = y2 - y + 1;
|
||||||
|
int offsetX = -x, offsetY = -y;
|
||||||
|
for(int cx = x; cx <= x2; cx++){
|
||||||
|
for(int cy = y; cy <= y2; cy++){
|
||||||
|
Tile tile = world.tile(cx, cy);
|
||||||
|
|
||||||
|
if(tile != null && tile.entity != null){
|
||||||
|
int config = tile.entity.config();
|
||||||
|
if(tile.block().posConfig){
|
||||||
|
config = Pos.get(Pos.x(config) + offsetX, Pos.y(config) + offsetY);
|
||||||
|
}
|
||||||
|
|
||||||
|
tiles.add(new Stile(tile.block(), cx + offsetX, cy + offsetY, config, tile.rotation()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Schematic(tiles, new StringMap(), width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Converts a schematic to base64. Note that the result of this will always start with 'bXNjaAB'.*/
|
||||||
|
public String writeBase64(Schematic schematic){
|
||||||
|
try{
|
||||||
|
out.reset();
|
||||||
|
write(schematic, out);
|
||||||
|
return new String(Base64Coder.encode(out.getBuffer(), out.size()));
|
||||||
|
}catch(IOException e){
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Loads a schematic from base64. May throw an exception. */
|
||||||
|
public Schematic readBase64(String schematic) throws IOException{
|
||||||
|
return read(new ByteArrayInputStream(Base64Coder.decode(schematic)));
|
||||||
|
}
|
||||||
|
|
||||||
|
//region IO methods
|
||||||
|
|
||||||
|
public static Schematic read(FileHandle file) throws IOException{
|
||||||
|
Schematic s = read(new DataInputStream(file.read(1024)));
|
||||||
|
if(!s.tags.containsKey("name")){
|
||||||
|
s.tags.put("name", file.nameWithoutExtension());
|
||||||
|
}
|
||||||
|
s.file = file;
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Schematic read(InputStream input) throws IOException{
|
||||||
|
for(byte b : header){
|
||||||
|
if(input.read() != b){
|
||||||
|
throw new IOException("Not a schematic file (missing header).");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int ver;
|
||||||
|
if((ver = input.read()) != version){
|
||||||
|
throw new IOException("Unknown version: " + ver);
|
||||||
|
}
|
||||||
|
|
||||||
|
try(DataInputStream stream = new DataInputStream(new InflaterInputStream(input))){
|
||||||
|
short width = stream.readShort(), height = stream.readShort();
|
||||||
|
|
||||||
|
StringMap map = new StringMap();
|
||||||
|
byte tags = stream.readByte();
|
||||||
|
for(int i = 0; i < tags; i++){
|
||||||
|
map.put(stream.readUTF(), stream.readUTF());
|
||||||
|
}
|
||||||
|
|
||||||
|
IntMap<Block> blocks = new IntMap<>();
|
||||||
|
byte length = stream.readByte();
|
||||||
|
for(int i = 0; i < length; i++){
|
||||||
|
Block block = Vars.content.getByName(ContentType.block, stream.readUTF());
|
||||||
|
blocks.put(i, block == null ? Blocks.air : block);
|
||||||
|
}
|
||||||
|
|
||||||
|
int total = stream.readInt();
|
||||||
|
Array<Stile> tiles = new Array<>(total);
|
||||||
|
for(int i = 0; i < total; i++){
|
||||||
|
Block block = blocks.get(stream.readByte());
|
||||||
|
int position = stream.readInt();
|
||||||
|
int config = stream.readInt();
|
||||||
|
byte rotation = stream.readByte();
|
||||||
|
if(block != Blocks.air){
|
||||||
|
tiles.add(new Stile(block, Pos.x(position), Pos.y(position), config, rotation));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Schematic(tiles, map, width, height);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void write(Schematic schematic, FileHandle file) throws IOException{
|
||||||
|
write(schematic, file.write(false, 1024));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void write(Schematic schematic, OutputStream output) throws IOException{
|
||||||
|
output.write(header);
|
||||||
|
output.write(version);
|
||||||
|
|
||||||
|
try(DataOutputStream stream = new DataOutputStream(new DeflaterOutputStream(output))){
|
||||||
|
|
||||||
|
stream.writeShort(schematic.width);
|
||||||
|
stream.writeShort(schematic.height);
|
||||||
|
|
||||||
|
stream.writeByte(schematic.tags.size);
|
||||||
|
for(ObjectMap.Entry<String, String> e : schematic.tags.entries()){
|
||||||
|
stream.writeUTF(e.key);
|
||||||
|
stream.writeUTF(e.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
OrderedSet<Block> blocks = new OrderedSet<>();
|
||||||
|
schematic.tiles.each(t -> blocks.add(t.block));
|
||||||
|
|
||||||
|
//create dictionary
|
||||||
|
stream.writeByte(blocks.size);
|
||||||
|
for(int i = 0; i < blocks.size; i++){
|
||||||
|
stream.writeUTF(blocks.orderedItems().get(i).name);
|
||||||
|
}
|
||||||
|
|
||||||
|
stream.writeInt(schematic.tiles.size);
|
||||||
|
//write each tile
|
||||||
|
for(Stile tile : schematic.tiles){
|
||||||
|
stream.writeByte(blocks.orderedItems().indexOf(tile.block));
|
||||||
|
stream.writeInt(Pos.get(tile.x, tile.y));
|
||||||
|
stream.writeInt(tile.config);
|
||||||
|
stream.writeByte(tile.rotation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
public enum PreviewRes{
|
||||||
|
low(8), med(8), high(32);
|
||||||
|
|
||||||
|
public final int resolution;
|
||||||
|
|
||||||
|
PreviewRes(int resolution){
|
||||||
|
this.resolution = resolution;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -40,6 +40,10 @@ public class Tutorial{
|
|||||||
Events.on(BlockInfoEvent.class, event -> events.add("blockinfo"));
|
Events.on(BlockInfoEvent.class, event -> events.add("blockinfo"));
|
||||||
Events.on(DepositEvent.class, event -> events.add("deposit"));
|
Events.on(DepositEvent.class, event -> events.add("deposit"));
|
||||||
Events.on(WithdrawEvent.class, event -> events.add("withdraw"));
|
Events.on(WithdrawEvent.class, event -> events.add("withdraw"));
|
||||||
|
|
||||||
|
for(TutorialStage stage : TutorialStage.values()){
|
||||||
|
stage.load();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** update tutorial state, transition if needed */
|
/** update tutorial state, transition if needed */
|
||||||
@@ -204,13 +208,17 @@ public class Tutorial{
|
|||||||
/** displayed tutorial stage text.*/
|
/** displayed tutorial stage text.*/
|
||||||
public String text(){
|
public String text(){
|
||||||
if(sentences == null){
|
if(sentences == null){
|
||||||
this.line = Core.bundle.has("tutorial." + name() + ".mobile") && mobile ? "tutorial." + name() + ".mobile" : "tutorial." + name();
|
load();
|
||||||
this.sentences = Array.select(Core.bundle.get(line).split("\n"), s -> !s.isEmpty());
|
|
||||||
}
|
}
|
||||||
String line = sentences.get(control.tutorial.sentence);
|
String line = sentences.get(control.tutorial.sentence);
|
||||||
return line.contains("{") ? text.get(line) : line;
|
return line.contains("{") ? text.get(line) : line;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void load(){
|
||||||
|
this.line = Core.bundle.has("tutorial." + name() + ".mobile") && mobile ? "tutorial." + name() + ".mobile" : "tutorial." + name();
|
||||||
|
this.sentences = Array.select(Core.bundle.get(line).split("\n"), s -> !s.isEmpty());
|
||||||
|
}
|
||||||
|
|
||||||
/** called every frame when this stage is active.*/
|
/** called every frame when this stage is active.*/
|
||||||
void update(){
|
void update(){
|
||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,10 @@ public enum Binding implements KeyBind{
|
|||||||
rotateplaced(KeyCode.R),
|
rotateplaced(KeyCode.R),
|
||||||
diagonal_placement(KeyCode.CONTROL_LEFT),
|
diagonal_placement(KeyCode.CONTROL_LEFT),
|
||||||
pick(KeyCode.MOUSE_MIDDLE),
|
pick(KeyCode.MOUSE_MIDDLE),
|
||||||
|
schematic_select(KeyCode.F),
|
||||||
|
schematic_flip_x(KeyCode.Z),
|
||||||
|
schematic_flip_y(KeyCode.X),
|
||||||
|
schematic_menu(KeyCode.T),
|
||||||
dash(KeyCode.SHIFT_LEFT),
|
dash(KeyCode.SHIFT_LEFT),
|
||||||
gridMode(KeyCode.BACKTICK),
|
gridMode(KeyCode.BACKTICK),
|
||||||
gridModeShift(KeyCode.ALT_LEFT),
|
gridModeShift(KeyCode.ALT_LEFT),
|
||||||
|
|||||||
@@ -6,11 +6,15 @@ import io.anuke.arc.Graphics.Cursor.*;
|
|||||||
import io.anuke.arc.graphics.g2d.*;
|
import io.anuke.arc.graphics.g2d.*;
|
||||||
import io.anuke.arc.math.*;
|
import io.anuke.arc.math.*;
|
||||||
import io.anuke.arc.scene.*;
|
import io.anuke.arc.scene.*;
|
||||||
|
import io.anuke.arc.scene.event.*;
|
||||||
import io.anuke.arc.scene.ui.*;
|
import io.anuke.arc.scene.ui.*;
|
||||||
|
import io.anuke.arc.scene.ui.layout.*;
|
||||||
import io.anuke.arc.util.ArcAnnotate.*;
|
import io.anuke.arc.util.ArcAnnotate.*;
|
||||||
|
import io.anuke.mindustry.*;
|
||||||
import io.anuke.mindustry.core.GameState.*;
|
import io.anuke.mindustry.core.GameState.*;
|
||||||
import io.anuke.mindustry.entities.traits.BuilderTrait.*;
|
import io.anuke.mindustry.entities.traits.BuilderTrait.*;
|
||||||
import io.anuke.mindustry.game.EventType.*;
|
import io.anuke.mindustry.game.EventType.*;
|
||||||
|
import io.anuke.mindustry.game.*;
|
||||||
import io.anuke.mindustry.gen.*;
|
import io.anuke.mindustry.gen.*;
|
||||||
import io.anuke.mindustry.graphics.*;
|
import io.anuke.mindustry.graphics.*;
|
||||||
import io.anuke.mindustry.ui.*;
|
import io.anuke.mindustry.ui.*;
|
||||||
@@ -24,9 +28,9 @@ public class DesktopInput extends InputHandler{
|
|||||||
/** Current cursor type. */
|
/** Current cursor type. */
|
||||||
private Cursor cursorType = SystemCursor.arrow;
|
private Cursor cursorType = SystemCursor.arrow;
|
||||||
/** Position where the player started dragging a line. */
|
/** Position where the player started dragging a line. */
|
||||||
private int selectX, selectY;
|
private int selectX, selectY, schemX, schemY;
|
||||||
/** Last known line positions.*/
|
/** Last known line positions.*/
|
||||||
private int lastLineX, lastLineY;
|
private int lastLineX, lastLineY, schematicX, schematicY;
|
||||||
/** Whether selecting mode is active. */
|
/** Whether selecting mode is active. */
|
||||||
private PlaceMode mode;
|
private PlaceMode mode;
|
||||||
/** Animation scale for line. */
|
/** Animation scale for line. */
|
||||||
@@ -40,14 +44,39 @@ public class DesktopInput extends InputHandler{
|
|||||||
public void buildUI(Group group){
|
public void buildUI(Group group){
|
||||||
group.fill(t -> {
|
group.fill(t -> {
|
||||||
t.bottom().update(() -> t.getColor().a = Mathf.lerpDelta(t.getColor().a, player.isBuilding() ? 1f : 0f, 0.15f));
|
t.bottom().update(() -> t.getColor().a = Mathf.lerpDelta(t.getColor().a, player.isBuilding() ? 1f : 0f, 0.15f));
|
||||||
t.visible(() -> Core.settings.getBool("hints"));
|
t.visible(() -> Core.settings.getBool("hints") && selectRequests.isEmpty());
|
||||||
t.table(Styles.black6, b -> {
|
t.table(Styles.black6, b -> {
|
||||||
b.defaults().left();
|
b.defaults().left();
|
||||||
b.label(() -> Core.bundle.format(!player.isBuilding ? "resumebuilding" : "pausebuilding", Core.keybinds.get(Binding.pause_building).key.name())).style(Styles.outlineLabel);
|
b.label(() -> Core.bundle.format(!player.isBuilding ? "resumebuilding" : "pausebuilding", Core.keybinds.get(Binding.pause_building).key.name())).style(Styles.outlineLabel);
|
||||||
b.row();
|
b.row();
|
||||||
b.add(Core.bundle.format("cancelbuilding", Core.keybinds.get(Binding.clear_building).key.name())).style(Styles.outlineLabel);
|
b.add(Core.bundle.format("cancelbuilding", Core.keybinds.get(Binding.clear_building).key.name())).style(Styles.outlineLabel);
|
||||||
|
b.row();
|
||||||
|
b.add(Core.bundle.format("selectschematic", Core.keybinds.get(Binding.schematic_select).key.name())).style(Styles.outlineLabel);
|
||||||
}).margin(10f);
|
}).margin(10f);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
group.fill(t -> {
|
||||||
|
t.visible(() -> lastSchematic != null && !selectRequests.isEmpty());
|
||||||
|
t.bottom();
|
||||||
|
t.table(Styles.black6, b -> {
|
||||||
|
b.touchable(Touchable.enabled);
|
||||||
|
b.defaults().left();
|
||||||
|
b.add(Core.bundle.format("schematic.flip",
|
||||||
|
Core.keybinds.get(Binding.schematic_flip_x).key.name(),
|
||||||
|
Core.keybinds.get(Binding.schematic_flip_y).key.name())).style(Styles.outlineLabel);
|
||||||
|
b.row();
|
||||||
|
b.table(a -> {
|
||||||
|
a.addImageTextButton("$schematic.add", Icon.saveSmall, () -> {
|
||||||
|
ui.showTextInput("$schematic.add", "$name", "", text -> {
|
||||||
|
lastSchematic.tags.put("name", text);
|
||||||
|
schematics.add(lastSchematic);
|
||||||
|
ui.showInfoFade("$schematic.saved");
|
||||||
|
ui.schematics.showInfo(lastSchematic);
|
||||||
|
});
|
||||||
|
}).colspan(2).size(250f, 50f);
|
||||||
|
});
|
||||||
|
}).margin(6f);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -66,7 +95,7 @@ public class DesktopInput extends InputHandler{
|
|||||||
drawRequest(lineRequests.get(i));
|
drawRequest(lineRequests.get(i));
|
||||||
}
|
}
|
||||||
}else if(mode == breaking){
|
}else if(mode == breaking){
|
||||||
drawSelection(selectX, selectY, cursorX, cursorY);
|
drawBreakSelection(selectX, selectY, cursorX, cursorY);
|
||||||
}else if(isPlacing()){
|
}else if(isPlacing()){
|
||||||
if(block.rotate){
|
if(block.rotate){
|
||||||
drawArrow(block, cursorX, cursorY, rotation);
|
drawArrow(block, cursorX, cursorY, rotation);
|
||||||
@@ -83,6 +112,12 @@ public class DesktopInput extends InputHandler{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//draw schematic requests
|
||||||
|
for(BuildRequest request : selectRequests){
|
||||||
|
request.animScale = 1f;
|
||||||
|
drawRequest(request);
|
||||||
|
}
|
||||||
|
|
||||||
if(sreq != null){
|
if(sreq != null){
|
||||||
boolean valid = validPlace(sreq.x, sreq.y, sreq.block, sreq.rotation, sreq);
|
boolean valid = validPlace(sreq.x, sreq.y, sreq.block, sreq.rotation, sreq);
|
||||||
if(sreq.block.rotate){
|
if(sreq.block.rotate){
|
||||||
@@ -94,6 +129,10 @@ 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);
|
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)){
|
||||||
|
drawSelection(schemX, schemY, cursorX, cursorY, Vars.maxSchematicSize);
|
||||||
|
}
|
||||||
|
|
||||||
Draw.reset();
|
Draw.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -118,7 +157,7 @@ public class DesktopInput extends InputHandler{
|
|||||||
if(state.is(State.menu) || Core.scene.hasDialog()) return;
|
if(state.is(State.menu) || Core.scene.hasDialog()) return;
|
||||||
|
|
||||||
//zoom things
|
//zoom things
|
||||||
if(Math.abs(Core.input.axisTap(Binding.zoom)) > 0 && (Core.input.keyDown(Binding.zoom_hold))){
|
if(Math.abs(Core.input.axisTap(Binding.zoom)) > 0 && Core.input.keyDown(Binding.zoom_hold)){
|
||||||
renderer.scaleCamera(Core.input.axisTap(Binding.zoom));
|
renderer.scaleCamera(Core.input.axisTap(Binding.zoom));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -134,6 +173,10 @@ public class DesktopInput extends InputHandler{
|
|||||||
mode = none;
|
mode = none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(mode != none){
|
||||||
|
selectRequests.clear();
|
||||||
|
}
|
||||||
|
|
||||||
if(player.isShooting && !canShoot()){
|
if(player.isShooting && !canShoot()){
|
||||||
player.isShooting = false;
|
player.isShooting = false;
|
||||||
}
|
}
|
||||||
@@ -151,8 +194,12 @@ public class DesktopInput extends InputHandler{
|
|||||||
sreq.rotation = Mathf.mod(sreq.rotation + (int)Core.input.axisTap(Binding.rotate), 4);
|
sreq.rotation = Mathf.mod(sreq.rotation + (int)Core.input.axisTap(Binding.rotate), 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(Math.abs((int)Core.input.axisTap(Binding.rotate)) > 0 && isPlacing() && mode == placing){
|
if(!Core.input.keyDown(Binding.zoom_hold) && Math.abs((int)Core.input.axisTap(Binding.rotate)) > 0){
|
||||||
updateLine(selectX, selectY);
|
if(isPlacing() && mode == placing){
|
||||||
|
updateLine(selectX, selectY);
|
||||||
|
}else if(!selectRequests.isEmpty()){
|
||||||
|
rotateRequests(selectRequests, (int)Core.input.axisTap(Binding.rotate));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Tile cursor = tileAt(Core.input.mouseX(), Core.input.mouseY());
|
Tile cursor = tileAt(Core.input.mouseX(), Core.input.mouseY());
|
||||||
@@ -162,7 +209,7 @@ public class DesktopInput extends InputHandler{
|
|||||||
|
|
||||||
cursorType = cursor.block().getCursor(cursor);
|
cursorType = cursor.block().getCursor(cursor);
|
||||||
|
|
||||||
if(isPlacing()){
|
if(isPlacing() || !selectRequests.isEmpty()){
|
||||||
cursorType = SystemCursor.hand;
|
cursorType = SystemCursor.hand;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -190,15 +237,49 @@ public class DesktopInput extends InputHandler{
|
|||||||
cursorType = SystemCursor.arrow;
|
cursorType = SystemCursor.arrow;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void useSchematic(Schematic schem){
|
||||||
|
block = null;
|
||||||
|
schematicX = tileX(getMouseX());
|
||||||
|
schematicY = tileY(getMouseY());
|
||||||
|
|
||||||
|
selectRequests.addAll(schematics.toRequests(schem, schematicX, schematicY));
|
||||||
|
mode = none;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isBreaking(){
|
public boolean isBreaking(){
|
||||||
return mode == breaking;
|
return mode == breaking;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void buildPlacementUI(Table table){
|
||||||
|
table.addImage().color(Pal.gray).height(4f).colspan(4).growX();
|
||||||
|
table.row();
|
||||||
|
table.left().margin(0f).defaults().size(48f).left();
|
||||||
|
|
||||||
|
table.addImageButton(Icon.wikiSmall, Styles.clearPartiali, () -> {
|
||||||
|
ui.schematics.show();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
void pollInput(){
|
void pollInput(){
|
||||||
Tile selected = tileAt(Core.input.mouseX(), Core.input.mouseY());
|
Tile selected = tileAt(Core.input.mouseX(), Core.input.mouseY());
|
||||||
int cursorX = tileX(Core.input.mouseX());
|
int cursorX = tileX(Core.input.mouseX());
|
||||||
int cursorY = tileY(Core.input.mouseY());
|
int cursorY = tileY(Core.input.mouseY());
|
||||||
|
int rawCursorX = world.toTile(Core.input.mouseWorld().x), rawCursorY = world.toTile(Core.input.mouseWorld().y);
|
||||||
|
|
||||||
|
if(!selectRequests.isEmpty()){
|
||||||
|
int shiftX = rawCursorX - schematicX, shiftY = rawCursorY - schematicY;
|
||||||
|
|
||||||
|
selectRequests.each(s -> {
|
||||||
|
s.x += shiftX;
|
||||||
|
s.y += shiftY;
|
||||||
|
});
|
||||||
|
|
||||||
|
schematicX += shiftX;
|
||||||
|
schematicY += shiftY;
|
||||||
|
}
|
||||||
|
|
||||||
if(Core.input.keyTap(Binding.deselect)){
|
if(Core.input.keyTap(Binding.deselect)){
|
||||||
player.setMineTile(null);
|
player.setMineTile(null);
|
||||||
@@ -208,6 +289,38 @@ public class DesktopInput extends InputHandler{
|
|||||||
player.clearBuilding();
|
player.clearBuilding();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(Core.input.keyTap(Binding.schematic_select)){
|
||||||
|
schemX = rawCursorX;
|
||||||
|
schemY = rawCursorY;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(Core.input.keyTap(Binding.schematic_menu)){
|
||||||
|
ui.schematics.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(Core.input.keyTap(Binding.clear_building)){
|
||||||
|
lastSchematic = null;
|
||||||
|
selectRequests.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(Core.input.keyRelease(Binding.schematic_select)){
|
||||||
|
lastSchematic = schematics.create(schemX, schemY, rawCursorX, rawCursorY);
|
||||||
|
useSchematic(lastSchematic);
|
||||||
|
if(selectRequests.isEmpty()){
|
||||||
|
lastSchematic = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!selectRequests.isEmpty()){
|
||||||
|
if(Core.input.keyTap(Binding.schematic_flip_x)){
|
||||||
|
flipRequests(selectRequests, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(Core.input.keyTap(Binding.schematic_flip_y)){
|
||||||
|
flipRequests(selectRequests, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if(sreq != null){
|
if(sreq != null){
|
||||||
float offset = ((sreq.block.size + 2) % 2) * tilesize / 2f;
|
float offset = ((sreq.block.size + 2) % 2) * tilesize / 2f;
|
||||||
float x = Core.input.mouseWorld().x + offset;
|
float x = Core.input.mouseWorld().x + offset;
|
||||||
@@ -233,7 +346,10 @@ public class DesktopInput extends InputHandler{
|
|||||||
if(Core.input.keyTap(Binding.select) && !Core.scene.hasMouse()){
|
if(Core.input.keyTap(Binding.select) && !Core.scene.hasMouse()){
|
||||||
BuildRequest req = getRequest(cursorX, cursorY);
|
BuildRequest req = getRequest(cursorX, cursorY);
|
||||||
|
|
||||||
if(isPlacing()){
|
if(!selectRequests.isEmpty()){
|
||||||
|
flushRequests(selectRequests);
|
||||||
|
//selectRequests.clear();
|
||||||
|
}else if(isPlacing()){
|
||||||
selectX = cursorX;
|
selectX = cursorX;
|
||||||
selectY = cursorY;
|
selectY = cursorY;
|
||||||
lastLineX = cursorX;
|
lastLineX = cursorX;
|
||||||
@@ -329,6 +445,7 @@ public class DesktopInput extends InputHandler{
|
|||||||
mode = none;
|
mode = none;
|
||||||
block = null;
|
block = null;
|
||||||
sreq = null;
|
sreq = null;
|
||||||
|
selectRequests.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,12 +14,14 @@ import io.anuke.arc.scene.*;
|
|||||||
import io.anuke.arc.scene.event.*;
|
import io.anuke.arc.scene.event.*;
|
||||||
import io.anuke.arc.scene.ui.layout.*;
|
import io.anuke.arc.scene.ui.layout.*;
|
||||||
import io.anuke.arc.util.*;
|
import io.anuke.arc.util.*;
|
||||||
|
import io.anuke.arc.util.ArcAnnotate.*;
|
||||||
import io.anuke.mindustry.content.*;
|
import io.anuke.mindustry.content.*;
|
||||||
import io.anuke.mindustry.entities.*;
|
import io.anuke.mindustry.entities.*;
|
||||||
import io.anuke.mindustry.entities.effect.*;
|
import io.anuke.mindustry.entities.effect.*;
|
||||||
import io.anuke.mindustry.entities.traits.BuilderTrait.*;
|
import io.anuke.mindustry.entities.traits.BuilderTrait.*;
|
||||||
import io.anuke.mindustry.entities.type.*;
|
import io.anuke.mindustry.entities.type.*;
|
||||||
import io.anuke.mindustry.game.EventType.*;
|
import io.anuke.mindustry.game.EventType.*;
|
||||||
|
import io.anuke.mindustry.game.*;
|
||||||
import io.anuke.mindustry.game.Teams.*;
|
import io.anuke.mindustry.game.Teams.*;
|
||||||
import io.anuke.mindustry.gen.*;
|
import io.anuke.mindustry.gen.*;
|
||||||
import io.anuke.mindustry.graphics.*;
|
import io.anuke.mindustry.graphics.*;
|
||||||
@@ -51,6 +53,7 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
|
|||||||
public boolean droppingItem;
|
public boolean droppingItem;
|
||||||
public Group uiGroup;
|
public Group uiGroup;
|
||||||
|
|
||||||
|
protected @Nullable Schematic lastSchematic;
|
||||||
protected GestureDetector detector;
|
protected GestureDetector detector;
|
||||||
protected PlaceLine line = new PlaceLine();
|
protected PlaceLine line = new PlaceLine();
|
||||||
protected BuildRequest resultreq;
|
protected BuildRequest resultreq;
|
||||||
@@ -207,7 +210,7 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
|
|||||||
if(request.breaking){
|
if(request.breaking){
|
||||||
drawBreaking(request.x, request.y);
|
drawBreaking(request.x, request.y);
|
||||||
}else{
|
}else{
|
||||||
drawSelected(request.x, request.y, request.tile().block(), Pal.remove);
|
drawSelected(request.x, request.y, request.block, Pal.remove);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -219,6 +222,76 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
|
|||||||
drawSelected(x, y, block, Pal.remove);
|
drawSelected(x, y, block, Pal.remove);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void useSchematic(Schematic schem){
|
||||||
|
selectRequests.addAll(schematics.toRequests(schem, world.toTile(player.x), world.toTile(player.y)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void rotateRequests(Array<BuildRequest> requests, int direction){
|
||||||
|
int ox = rawTileX(), oy = rawTileY();
|
||||||
|
|
||||||
|
requests.each(req -> {
|
||||||
|
//rotate config position
|
||||||
|
if(req.block.posConfig){
|
||||||
|
int cx = Pos.x(req.config) - req.originalX, cy = Pos.y(req.config) - req.originalY;
|
||||||
|
int lx = cx;
|
||||||
|
|
||||||
|
if(direction >= 0){
|
||||||
|
cx = -cy;
|
||||||
|
cy = lx;
|
||||||
|
}else{
|
||||||
|
cx = cy;
|
||||||
|
cy = -lx;
|
||||||
|
}
|
||||||
|
req.config = Pos.get(cx + req.originalX, cy + req.originalY);
|
||||||
|
}
|
||||||
|
|
||||||
|
//rotate actual request, centered on its multiblock position
|
||||||
|
float wx = (req.x - ox) * tilesize + req.block.offset(), wy = (req.y - oy) * tilesize + req.block.offset();
|
||||||
|
float x = wx;
|
||||||
|
if(direction >= 0){
|
||||||
|
wx = -wy;
|
||||||
|
wy = x;
|
||||||
|
}else{
|
||||||
|
wx = wy;
|
||||||
|
wy = -x;
|
||||||
|
}
|
||||||
|
req.x = world.toTile(wx - req.block.offset()) + ox;
|
||||||
|
req.y = world.toTile(wy - req.block.offset()) + oy;
|
||||||
|
req.rotation = Mathf.mod(req.rotation + direction, 4);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void flipRequests(Array<BuildRequest> requests, boolean x){
|
||||||
|
int origin = x ? rawTileX() : rawTileY();
|
||||||
|
|
||||||
|
requests.each(req -> {
|
||||||
|
int value = -((x ? req.x : req.y) - origin) + origin;
|
||||||
|
|
||||||
|
if(x){
|
||||||
|
req.x = value;
|
||||||
|
}else{
|
||||||
|
req.y = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(req.block.posConfig){
|
||||||
|
int corigin = x ? req.originalWidth/2 : req.originalHeight/2;
|
||||||
|
int nvalue = -((x ? Pos.x(req.config) : Pos.y(req.config)) - corigin) + corigin;
|
||||||
|
if(x){
|
||||||
|
req.originalX = -(req.originalX - corigin) + corigin;
|
||||||
|
req.config = Pos.get(nvalue, Pos.y(req.config));
|
||||||
|
}else{
|
||||||
|
req.originalY = -(req.originalY - corigin) + corigin;
|
||||||
|
req.config = Pos.get(Pos.x(req.config), nvalue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//flip rotation
|
||||||
|
if(x == (req.rotation % 2 == 0)){
|
||||||
|
req.rotation = Mathf.mod(req.rotation + 2, 4);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/** Returns the selection request that overlaps this position, or null. */
|
/** Returns the selection request that overlaps this position, or null. */
|
||||||
protected BuildRequest getRequest(int x, int y){
|
protected BuildRequest getRequest(int x, int y){
|
||||||
return getRequest(x, y, 1, null);
|
return getRequest(x, y, 1, null);
|
||||||
@@ -259,7 +332,7 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void drawSelection(int x1, int y1, int x2, int y2){
|
protected void drawBreakSelection(int x1, int y1, int x2, int y2){
|
||||||
NormalizeDrawResult result = PlaceUtils.normalizeDrawArea(Blocks.air, x1, y1, x2, y2, false, maxLength, 1f);
|
NormalizeDrawResult result = PlaceUtils.normalizeDrawArea(Blocks.air, x1, y1, x2, y2, false, maxLength, 1f);
|
||||||
NormalizeResult dresult = PlaceUtils.normalizeArea(x1, y1, x2, y2, rotation, false, maxLength);
|
NormalizeResult dresult = PlaceUtils.normalizeArea(x1, y1, x2, y2, rotation, false, maxLength);
|
||||||
|
|
||||||
@@ -307,10 +380,21 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
|
|||||||
Lines.rect(result.x, result.y, result.x2 - result.x, result.y2 - result.y);
|
Lines.rect(result.x, result.y, result.x2 - result.x, result.y2 - result.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void drawSelection(int x1, int y1, int x2, int y2, int maxLength){
|
||||||
|
NormalizeDrawResult result = PlaceUtils.normalizeDrawArea(Blocks.air, x1, y1, x2, y2, false, maxLength, 1f);
|
||||||
|
|
||||||
|
Lines.stroke(2f);
|
||||||
|
|
||||||
|
Draw.color(Pal.accentBack);
|
||||||
|
Lines.rect(result.x, result.y - 1, result.x2 - result.x, result.y2 - result.y);
|
||||||
|
Draw.color(Pal.accent);
|
||||||
|
Lines.rect(result.x, result.y, result.x2 - result.x, result.y2 - result.y);
|
||||||
|
}
|
||||||
|
|
||||||
protected void flushSelectRequests(Array<BuildRequest> requests){
|
protected void flushSelectRequests(Array<BuildRequest> requests){
|
||||||
for(BuildRequest req : requests){
|
for(BuildRequest req : requests){
|
||||||
if(req.block != null && validPlace(req.x, req.y, req.block, req.rotation)){
|
if(req.block != null && validPlace(req.x, req.y, req.block, req.rotation)){
|
||||||
selectRequests.add(req);
|
selectRequests.add(req.copy());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -318,7 +402,11 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
|
|||||||
protected void flushRequests(Array<BuildRequest> requests){
|
protected void flushRequests(Array<BuildRequest> requests){
|
||||||
for(BuildRequest req : requests){
|
for(BuildRequest req : requests){
|
||||||
if(req.block != null && validPlace(req.x, req.y, req.block, req.rotation)){
|
if(req.block != null && validPlace(req.x, req.y, req.block, req.rotation)){
|
||||||
player.addBuildRequest(req);
|
BuildRequest copy = req.copy();
|
||||||
|
if(copy.hasConfig && copy.block.posConfig){
|
||||||
|
copy.config = Pos.get(Pos.x(copy.config) + copy.x - copy.originalX, Pos.y(copy.config) + copy.y - copy.originalY);
|
||||||
|
}
|
||||||
|
player.addBuildRequest(copy);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -448,14 +536,6 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
//clear when the player taps on something else
|
|
||||||
if(!consumed && !mobile && player.isBuilding() && block == null){
|
|
||||||
//player.clearBuilding();
|
|
||||||
block = null;
|
|
||||||
return true;
|
|
||||||
}*/
|
|
||||||
|
|
||||||
if(!showedInventory){
|
if(!showedInventory){
|
||||||
frag.inv.hide();
|
frag.inv.hide();
|
||||||
}
|
}
|
||||||
@@ -499,6 +579,14 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
|
|||||||
return world.tile(tileX(x), tileY(y));
|
return world.tile(tileX(x), tileY(y));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int rawTileX(){
|
||||||
|
return world.toTile(Core.input.mouseWorld().x);
|
||||||
|
}
|
||||||
|
|
||||||
|
int rawTileY(){
|
||||||
|
return world.toTile(Core.input.mouseWorld().y);
|
||||||
|
}
|
||||||
|
|
||||||
int tileX(float cursorX){
|
int tileX(float cursorX){
|
||||||
Vector2 vec = Core.input.mouseWorld(cursorX, 0);
|
Vector2 vec = Core.input.mouseWorld(cursorX, 0);
|
||||||
if(selectedBlock()){
|
if(selectedBlock()){
|
||||||
|
|||||||
@@ -208,7 +208,7 @@ public class MobileInput extends InputHandler implements GestureListener{
|
|||||||
}
|
}
|
||||||
|
|
||||||
//move all current requests to removal array so they fade out
|
//move all current requests to removal array so they fade out
|
||||||
removals.addAll(selectRequests.find(r -> !r.breaking));
|
removals.addAll(selectRequests.select(r -> !r.breaking));
|
||||||
selectRequests.clear();
|
selectRequests.clear();
|
||||||
selecting = false;
|
selecting = false;
|
||||||
}).visible(() -> !selectRequests.isEmpty()).name("confirmplace");
|
}).visible(() -> !selectRequests.isEmpty()).name("confirmplace");
|
||||||
@@ -243,7 +243,6 @@ public class MobileInput extends InputHandler implements GestureListener{
|
|||||||
if(tile == null) continue;
|
if(tile == null) continue;
|
||||||
|
|
||||||
request.animScale = Mathf.lerpDelta(request.animScale, 0f, 0.2f);
|
request.animScale = Mathf.lerpDelta(request.animScale, 0f, 0.2f);
|
||||||
request.animInvalid = Mathf.lerpDelta(request.animInvalid, 0f, 0.2f);
|
|
||||||
|
|
||||||
if(request.breaking){
|
if(request.breaking){
|
||||||
drawSelected(request.x, request.y, tile.block(), Pal.remove);
|
drawSelected(request.x, request.y, tile.block(), Pal.remove);
|
||||||
@@ -263,10 +262,8 @@ public class MobileInput extends InputHandler implements GestureListener{
|
|||||||
if((!request.breaking && validPlace(tile.x, tile.y, request.block, request.rotation))
|
if((!request.breaking && validPlace(tile.x, tile.y, request.block, request.rotation))
|
||||||
|| (request.breaking && validBreak(tile.x, tile.y))){
|
|| (request.breaking && validBreak(tile.x, tile.y))){
|
||||||
request.animScale = Mathf.lerpDelta(request.animScale, 1f, 0.2f);
|
request.animScale = Mathf.lerpDelta(request.animScale, 1f, 0.2f);
|
||||||
request.animInvalid = Mathf.lerpDelta(request.animInvalid, 0f, 0.2f);
|
|
||||||
}else{
|
}else{
|
||||||
request.animScale = Mathf.lerpDelta(request.animScale, 0.6f, 0.1f);
|
request.animScale = Mathf.lerpDelta(request.animScale, 0.6f, 0.1f);
|
||||||
request.animInvalid = Mathf.lerpDelta(request.animInvalid, 0.9f, 0.2f);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Tmp.c1.set(Draw.getMixColor());
|
Tmp.c1.set(Draw.getMixColor());
|
||||||
@@ -305,7 +302,7 @@ public class MobileInput extends InputHandler implements GestureListener{
|
|||||||
drawRequest(lineRequests.get(i));
|
drawRequest(lineRequests.get(i));
|
||||||
}
|
}
|
||||||
}else if(mode == breaking){
|
}else if(mode == breaking){
|
||||||
drawSelection(lineStartX, lineStartY, tileX, tileY);
|
drawBreakSelection(lineStartX, lineStartY, tileX, tileY);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -340,7 +337,7 @@ public class MobileInput extends InputHandler implements GestureListener{
|
|||||||
if(request.breaking){
|
if(request.breaking){
|
||||||
drawSelected(request.x, request.y, request.tile().block(), Pal.remove);
|
drawSelected(request.x, request.y, request.tile().block(), Pal.remove);
|
||||||
}else{
|
}else{
|
||||||
drawRequest(request.x, request.y, request.block, request.rotation);
|
request.block.drawRequest(request, allRequests(), validPlace(request.x, request.y, request.block, request.rotation));
|
||||||
drawSelected(request.x, request.y, request.block, Pal.accent);
|
drawSelected(request.x, request.y, request.block, Pal.accent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -95,14 +95,14 @@ public class PlaceUtils{
|
|||||||
}else{
|
}else{
|
||||||
endx = tilex;
|
endx = tilex;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if(Math.abs(endx - tilex) > maxLength){
|
if(Math.abs(endx - tilex) > maxLength){
|
||||||
endx = Mathf.sign(endx - tilex) * maxLength + tilex;
|
endx = Mathf.sign(endx - tilex) * maxLength + tilex;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(Math.abs(endy - tiley) > maxLength){
|
if(Math.abs(endy - tiley) > maxLength){
|
||||||
endy = Mathf.sign(endy - tiley) * maxLength + tiley;
|
endy = Mathf.sign(endy - tiley) * maxLength + tiley;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int dx = endx - tilex, dy = endy - tiley;
|
int dx = endx - tilex, dy = endy - tiley;
|
||||||
@@ -141,12 +141,12 @@ public class PlaceUtils{
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static class NormalizeDrawResult{
|
public static class NormalizeDrawResult{
|
||||||
float x, y, x2, y2;
|
float x, y, x2, y2;
|
||||||
}
|
}
|
||||||
|
|
||||||
static class NormalizeResult{
|
public static class NormalizeResult{
|
||||||
int x, y, x2, y2, rotation;
|
public int x, y, x2, y2, rotation;
|
||||||
|
|
||||||
boolean isX(){
|
boolean isX(){
|
||||||
return Math.abs(x2 - x) > Math.abs(y2 - y);
|
return Math.abs(x2 - x) > Math.abs(y2 - y);
|
||||||
|
|||||||
@@ -4,14 +4,17 @@ import io.anuke.arc.*;
|
|||||||
import io.anuke.arc.collection.*;
|
import io.anuke.arc.collection.*;
|
||||||
import io.anuke.arc.files.*;
|
import io.anuke.arc.files.*;
|
||||||
import io.anuke.arc.graphics.*;
|
import io.anuke.arc.graphics.*;
|
||||||
|
import io.anuke.arc.util.*;
|
||||||
import io.anuke.mindustry.*;
|
import io.anuke.mindustry.*;
|
||||||
|
import io.anuke.mindustry.game.EventType.*;
|
||||||
import io.anuke.mindustry.game.*;
|
import io.anuke.mindustry.game.*;
|
||||||
import io.anuke.mindustry.io.*;
|
import io.anuke.mindustry.io.*;
|
||||||
import io.anuke.mindustry.maps.filters.*;
|
import io.anuke.mindustry.maps.filters.*;
|
||||||
|
import io.anuke.mindustry.type.*;
|
||||||
|
|
||||||
import static io.anuke.mindustry.Vars.maps;
|
import static io.anuke.mindustry.Vars.*;
|
||||||
|
|
||||||
public class Map implements Comparable<Map>{
|
public class Map implements Comparable<Map>, Publishable{
|
||||||
/** Whether this is a custom map. */
|
/** Whether this is a custom map. */
|
||||||
public final boolean custom;
|
public final boolean custom;
|
||||||
/** Metadata. Author description, display name, etc. */
|
/** Metadata. Author description, display name, etc. */
|
||||||
@@ -131,6 +134,76 @@ public class Map implements Comparable<Map>{
|
|||||||
return tags.containsKey(name);
|
return tags.containsKey(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getSteamID(){
|
||||||
|
return tags.get("steamid");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addSteamID(String id){
|
||||||
|
tags.put("steamid", id);
|
||||||
|
|
||||||
|
ui.editor.editor.getTags().put("steamid", id);
|
||||||
|
try{
|
||||||
|
ui.editor.save();
|
||||||
|
}catch(Exception e){
|
||||||
|
Log.err(e);
|
||||||
|
}
|
||||||
|
Events.fire(new MapPublishEvent());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void removeSteamID(){
|
||||||
|
tags.remove("steamid");
|
||||||
|
|
||||||
|
ui.editor.editor.getTags().remove("steamid");
|
||||||
|
try{
|
||||||
|
ui.editor.save();
|
||||||
|
}catch(Exception e){
|
||||||
|
Log.err(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String steamTitle(){
|
||||||
|
return name();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String steamDescription(){
|
||||||
|
return description();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String steamTag(){
|
||||||
|
return "map";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FileHandle createSteamFolder(String id){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FileHandle createSteamPreview(String id){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Array<String> extraTags(){
|
||||||
|
Gamemode mode = Gamemode.attack.valid(this) ? Gamemode.attack : Gamemode.survival;
|
||||||
|
return Array.with(mode.name());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean prePublish(){
|
||||||
|
tags.put("author", player.name);
|
||||||
|
ui.editor.editor.getTags().put("author", tags.get("author"));
|
||||||
|
ui.editor.save();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int compareTo(Map map){
|
public int compareTo(Map map){
|
||||||
int work = -Boolean.compare(workshop, map.workshop);
|
int work = -Boolean.compare(workshop, map.workshop);
|
||||||
|
|||||||
@@ -104,7 +104,7 @@ public class Maps{
|
|||||||
}
|
}
|
||||||
|
|
||||||
//workshop
|
//workshop
|
||||||
for(FileHandle file : platform.getExternalMaps()){
|
for(FileHandle file : platform.getWorkshopContent(Map.class)){
|
||||||
try{
|
try{
|
||||||
Map map = loadMap(file, false);
|
Map map = loadMap(file, false);
|
||||||
map.workshop = true;
|
map.workshop = true;
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import io.anuke.arc.util.serialization.*;
|
|||||||
import io.anuke.arc.util.serialization.Json.*;
|
import io.anuke.arc.util.serialization.Json.*;
|
||||||
import io.anuke.mindustry.*;
|
import io.anuke.mindustry.*;
|
||||||
import io.anuke.mindustry.content.*;
|
import io.anuke.mindustry.content.*;
|
||||||
|
import io.anuke.mindustry.content.TechTree.*;
|
||||||
import io.anuke.mindustry.entities.Effects.*;
|
import io.anuke.mindustry.entities.Effects.*;
|
||||||
import io.anuke.mindustry.entities.bullet.*;
|
import io.anuke.mindustry.entities.bullet.*;
|
||||||
import io.anuke.mindustry.entities.type.*;
|
import io.anuke.mindustry.entities.type.*;
|
||||||
@@ -42,21 +43,12 @@ public class ContentParser{
|
|||||||
if(data.isString()){
|
if(data.isString()){
|
||||||
return field(Bullets.class, data);
|
return field(Bullets.class, data);
|
||||||
}
|
}
|
||||||
Class<? extends BulletType> bc = data.has("type") ? resolve(data.getString("type"), "io.anuke.mindustry.entities.bullets") : BasicBulletType.class;
|
Class<? extends BulletType> bc = data.has("type") ? resolve(data.getString("type"), "io.anuke.mindustry.entities.bullet") : BasicBulletType.class;
|
||||||
data.remove("type");
|
data.remove("type");
|
||||||
BulletType result = make(bc);
|
BulletType result = make(bc);
|
||||||
readFields(result, data);
|
readFields(result, data);
|
||||||
return result;
|
return result;
|
||||||
});
|
});
|
||||||
/*
|
|
||||||
put(Music.class, (type, data) -> {
|
|
||||||
if(fieldOpt(Musics.class, data) != null) return fieldOpt(Musics.class, data);
|
|
||||||
|
|
||||||
String path = "music/" + data.asString() + (Vars.ios ? ".mp3" : ".ogg");
|
|
||||||
Core.assets.load(path, Music.class);
|
|
||||||
Core.assets.finishLoadingAsset(path);
|
|
||||||
return Core.assets.get(path);
|
|
||||||
});*/
|
|
||||||
put(Sound.class, (type, data) -> {
|
put(Sound.class, (type, data) -> {
|
||||||
if(fieldOpt(Sounds.class, data) != null) return fieldOpt(Sounds.class, data);
|
if(fieldOpt(Sounds.class, data) != null) return fieldOpt(Sounds.class, data);
|
||||||
|
|
||||||
@@ -78,6 +70,7 @@ public class ContentParser{
|
|||||||
/** Stores things that need to be parsed fully, e.g. reading fields of content.
|
/** Stores things that need to be parsed fully, e.g. reading fields of content.
|
||||||
* This is done to accomodate binding of content names first.*/
|
* This is done to accomodate binding of content names first.*/
|
||||||
private Array<Runnable> reads = new Array<>();
|
private Array<Runnable> reads = new Array<>();
|
||||||
|
private Array<Runnable> postreads = new Array<>();
|
||||||
private LoadedMod currentMod;
|
private LoadedMod currentMod;
|
||||||
private Content currentContent;
|
private Content currentContent;
|
||||||
|
|
||||||
@@ -147,6 +140,15 @@ public class ContentParser{
|
|||||||
}
|
}
|
||||||
|
|
||||||
currentContent = block;
|
currentContent = block;
|
||||||
|
|
||||||
|
String[] research = {null};
|
||||||
|
|
||||||
|
//add research tech node
|
||||||
|
if(value.has("research")){
|
||||||
|
research[0] = value.get("research").asString();
|
||||||
|
value.remove("research");
|
||||||
|
}
|
||||||
|
|
||||||
read(() -> {
|
read(() -> {
|
||||||
if(value.has("consumes")){
|
if(value.has("consumes")){
|
||||||
for(JsonValue child : value.get("consumes")){
|
for(JsonValue child : value.get("consumes")){
|
||||||
@@ -174,8 +176,16 @@ public class ContentParser{
|
|||||||
readFields(block, value, true);
|
readFields(block, value, true);
|
||||||
|
|
||||||
//add research tech node
|
//add research tech node
|
||||||
if(value.has("research")){
|
if(research[0] != null){
|
||||||
TechTree.create(find(ContentType.block, value.get("research").asString()), block);
|
Block parent = find(ContentType.block, research[0]);
|
||||||
|
TechNode baseNode = TechTree.create(parent, block);
|
||||||
|
|
||||||
|
postreads.add(() -> {
|
||||||
|
TechNode parnode = TechTree.all.find(t -> t.block == parent);
|
||||||
|
if(!parnode.children.contains(baseNode)){
|
||||||
|
parnode.children.add(baseNode);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
//make block visible by default if there are requirements and no visibility set
|
//make block visible by default if there are requirements and no visibility set
|
||||||
@@ -275,10 +285,12 @@ public class ContentParser{
|
|||||||
public void finishParsing(){
|
public void finishParsing(){
|
||||||
try{
|
try{
|
||||||
reads.each(Runnable::run);
|
reads.each(Runnable::run);
|
||||||
|
postreads.each(Runnable::run);
|
||||||
}catch(Exception e){
|
}catch(Exception e){
|
||||||
Vars.mods.handleError(new ModLoadException("Error occurred parsing content: " + currentContent, currentContent, e), currentMod);
|
Vars.mods.handleError(new ModLoadException("Error occurred parsing content: " + currentContent, currentContent, e), currentMod);
|
||||||
}
|
}
|
||||||
reads.clear();
|
reads.clear();
|
||||||
|
postreads.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -395,9 +407,7 @@ public class ContentParser{
|
|||||||
FieldMetadata metadata = fields.get(child.name().replace(" ", "_"));
|
FieldMetadata metadata = fields.get(child.name().replace(" ", "_"));
|
||||||
if(metadata == null){
|
if(metadata == null){
|
||||||
if(ignoreUnknownFields){
|
if(ignoreUnknownFields){
|
||||||
if(!child.name.equals("research")){
|
Log.err("{0}: Ignoring unknown field: " + child.name + " (" + type.getName() + ")", object);
|
||||||
Log.err("{0}: Ignoring unknown field: " + child.name + " (" + type.getName() + ")", object);
|
|
||||||
}
|
|
||||||
continue;
|
continue;
|
||||||
}else{
|
}else{
|
||||||
SerializationException ex = new SerializationException("Field not found: " + child.name + " (" + type.getName() + ")");
|
SerializationException ex = new SerializationException("Field not found: " + child.name + " (" + type.getName() + ")");
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ public class Mods implements Loadable{
|
|||||||
|
|
||||||
file.copyTo(dest);
|
file.copyTo(dest);
|
||||||
try{
|
try{
|
||||||
loaded.add(loadMod(file, false));
|
loaded.add(loadMod(dest, false));
|
||||||
requiresReload = true;
|
requiresReload = true;
|
||||||
}catch(IOException e){
|
}catch(IOException e){
|
||||||
dest.delete();
|
dest.delete();
|
||||||
@@ -180,7 +180,7 @@ public class Mods implements Loadable{
|
|||||||
}
|
}
|
||||||
|
|
||||||
//load workshop mods now
|
//load workshop mods now
|
||||||
for(FileHandle file : platform.getExternalMods()){
|
for(FileHandle file : platform.getWorkshopContent(LoadedMod.class)){
|
||||||
try{
|
try{
|
||||||
LoadedMod mod = loadMod(file, true);
|
LoadedMod mod = loadMod(file, true);
|
||||||
if(mod.enabled()){
|
if(mod.enabled()){
|
||||||
@@ -442,7 +442,7 @@ public class Mods implements Loadable{
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Represents a plugin that has been loaded from a jar file.*/
|
/** Represents a plugin that has been loaded from a jar file.*/
|
||||||
public static class LoadedMod{
|
public static class LoadedMod implements Publishable{
|
||||||
/** The location of this mod's zip file/folder on the disk. */
|
/** The location of this mod's zip file/folder on the disk. */
|
||||||
public final FileHandle file;
|
public final FileHandle 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. */
|
/** 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. */
|
||||||
@@ -453,8 +453,6 @@ public class Mods implements Loadable{
|
|||||||
public final String name;
|
public final String name;
|
||||||
/** This mod's metadata. */
|
/** This mod's metadata. */
|
||||||
public final ModMeta meta;
|
public final ModMeta meta;
|
||||||
/** The ID of this mod in the workshop.*/
|
|
||||||
public @Nullable String workshopID;
|
|
||||||
|
|
||||||
public LoadedMod(FileHandle file, FileHandle root, Mod mod, ModMeta meta){
|
public LoadedMod(FileHandle file, FileHandle root, Mod mod, ModMeta meta){
|
||||||
this.root = root;
|
this.root = root;
|
||||||
@@ -468,6 +466,63 @@ public class Mods implements Loadable{
|
|||||||
return Core.settings.getBool(name + "-enabled", true);
|
return Core.settings.getBool(name + "-enabled", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getSteamID(){
|
||||||
|
return Core.settings.getString(name + "-steamid", null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addSteamID(String id){
|
||||||
|
Core.settings.put(name + "-steamid", id);
|
||||||
|
Core.settings.save();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void removeSteamID(){
|
||||||
|
Core.settings.remove(name + "-steamid");
|
||||||
|
Core.settings.save();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String steamTitle(){
|
||||||
|
return meta.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String steamDescription(){
|
||||||
|
return meta.description;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String steamTag(){
|
||||||
|
return "mod";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FileHandle createSteamFolder(String id){
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FileHandle createSteamPreview(String id){
|
||||||
|
return file.child("preview.png");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean prePublish(){
|
||||||
|
if(!file.isDirectory()){
|
||||||
|
ui.showErrorMessage("$mod.folder.missing");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!file.child("preview.png").exists()){
|
||||||
|
ui.showErrorMessage("$mod.preview.missing");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString(){
|
public String toString(){
|
||||||
return "LoadedMod{" +
|
return "LoadedMod{" +
|
||||||
|
|||||||
40
core/src/io/anuke/mindustry/type/Publishable.java
Normal file
40
core/src/io/anuke/mindustry/type/Publishable.java
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
package io.anuke.mindustry.type;
|
||||||
|
|
||||||
|
import io.anuke.arc.collection.*;
|
||||||
|
import io.anuke.arc.files.*;
|
||||||
|
import io.anuke.arc.util.ArcAnnotate.*;
|
||||||
|
import io.anuke.mindustry.*;
|
||||||
|
|
||||||
|
/** Defines a piece of content that can be published on the Workshop. */
|
||||||
|
public interface Publishable{
|
||||||
|
/** @return workshop item ID, or null if this isn't on the workshop. */
|
||||||
|
@Nullable String getSteamID();
|
||||||
|
/** adds a steam ID to this item once it's published. should save the item to make sure this change is persisted. */
|
||||||
|
void addSteamID(String id);
|
||||||
|
/** removes the item ID; called when the item isn't found. */
|
||||||
|
void removeSteamID();
|
||||||
|
/** @return default title of the listing. */
|
||||||
|
String steamTitle();
|
||||||
|
/** @return standard steam listing description, may be null. this is editable by users after release.*/
|
||||||
|
@Nullable String steamDescription();
|
||||||
|
/** @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);
|
||||||
|
/** @return a preview file PNG. */
|
||||||
|
FileHandle createSteamPreview(String id);
|
||||||
|
/** @return any extra tags to add to this item.*/
|
||||||
|
default Array<String> extraTags(){
|
||||||
|
return new Array<>(0);
|
||||||
|
}
|
||||||
|
/** @return whether this item is or was once on the workshop.*/
|
||||||
|
default boolean hasSteamID(){
|
||||||
|
return getSteamID() != null && Vars.steam;
|
||||||
|
}
|
||||||
|
/** called before this item is published.
|
||||||
|
* @return true to signify that everything is cool and good, or false to significy that the user has done something wrong.
|
||||||
|
* if false is returned, make sure to show a dialog explaining the error. */
|
||||||
|
default boolean prePublish(){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -55,6 +55,7 @@ public class FloatingDialog extends Dialog{
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addCloseButton(){
|
public void addCloseButton(){
|
||||||
|
buttons.defaults().size(210f, 64f);
|
||||||
buttons.addImageTextButton("$back", Icon.arrowLeft, this::hide).size(210f, 64f);
|
buttons.addImageTextButton("$back", Icon.arrowLeft, this::hide).size(210f, 64f);
|
||||||
|
|
||||||
keyDown(key -> {
|
keyDown(key -> {
|
||||||
|
|||||||
@@ -205,7 +205,7 @@ public class MapsDialog extends FloatingDialog{
|
|||||||
|
|
||||||
table.addImageTextButton(map.workshop && steam ? "$view.workshop" : "$delete", map.workshop && steam ? Icon.linkSmall : Icon.trash16Small, () -> {
|
table.addImageTextButton(map.workshop && steam ? "$view.workshop" : "$delete", map.workshop && steam ? Icon.linkSmall : Icon.trash16Small, () -> {
|
||||||
if(map.workshop && steam){
|
if(map.workshop && steam){
|
||||||
platform.viewMapListing(map);
|
platform.viewListing(map);
|
||||||
}else{
|
}else{
|
||||||
ui.showConfirm("$confirm", Core.bundle.format("map.delete", map.name()), () -> {
|
ui.showConfirm("$confirm", Core.bundle.format("map.delete", map.name()), () -> {
|
||||||
maps.removeMap(map);
|
maps.removeMap(map);
|
||||||
|
|||||||
@@ -41,11 +41,11 @@ public class ModsDialog extends FloatingDialog{
|
|||||||
mods.reloadContent();
|
mods.reloadContent();
|
||||||
setup();
|
setup();
|
||||||
ui.loadfrag.hide();
|
ui.loadfrag.hide();
|
||||||
}catch(Exception e){
|
}catch(Throwable e){
|
||||||
ui.showException(e);
|
ui.showException(e);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}catch(Exception e){
|
}catch(Throwable e){
|
||||||
ui.showException(e);
|
ui.showException(e);
|
||||||
}
|
}
|
||||||
}, t -> Core.app.post(() -> ui.showException(t)));
|
}, t -> Core.app.post(() -> ui.showException(t)));
|
||||||
@@ -101,14 +101,20 @@ public class ModsDialog extends FloatingDialog{
|
|||||||
setup();
|
setup();
|
||||||
}).height(50f).margin(8f).width(130f);
|
}).height(50f).margin(8f).width(130f);
|
||||||
|
|
||||||
title.addImageButton(mod.workshopID != null ? Icon.linkSmall : Icon.trash16Small, Styles.cleari, () -> {
|
if(steam && !mod.hasSteamID()){
|
||||||
if(mod.workshopID == null){
|
title.addImageButton(Icon.loadMapSmall, Styles.cleari, () -> {
|
||||||
|
platform.publish(mod);
|
||||||
|
}).size(50f);
|
||||||
|
}
|
||||||
|
|
||||||
|
title.addImageButton(mod.hasSteamID() ? Icon.linkSmall : Icon.trash16Small, Styles.cleari, () -> {
|
||||||
|
if(!mod.hasSteamID()){
|
||||||
ui.showConfirm("$confirm", "$mod.remove.confirm", () -> {
|
ui.showConfirm("$confirm", "$mod.remove.confirm", () -> {
|
||||||
mods.removeMod(mod);
|
mods.removeMod(mod);
|
||||||
setup();
|
setup();
|
||||||
});
|
});
|
||||||
}else{
|
}else{
|
||||||
platform.viewListing(mod.workshopID);
|
platform.viewListing(mod);
|
||||||
}
|
}
|
||||||
}).size(50f);
|
}).size(50f);
|
||||||
}).growX().left().padTop(-14f).padRight(-14f);
|
}).growX().left().padTop(-14f).padRight(-14f);
|
||||||
|
|||||||
287
core/src/io/anuke/mindustry/ui/dialogs/SchematicsDialog.java
Normal file
287
core/src/io/anuke/mindustry/ui/dialogs/SchematicsDialog.java
Normal file
@@ -0,0 +1,287 @@
|
|||||||
|
package io.anuke.mindustry.ui.dialogs;
|
||||||
|
|
||||||
|
import io.anuke.arc.*;
|
||||||
|
import io.anuke.arc.collection.*;
|
||||||
|
import io.anuke.arc.graphics.*;
|
||||||
|
import io.anuke.arc.graphics.Texture.*;
|
||||||
|
import io.anuke.arc.graphics.g2d.*;
|
||||||
|
import io.anuke.arc.scene.ui.*;
|
||||||
|
import io.anuke.arc.scene.ui.ImageButton.*;
|
||||||
|
import io.anuke.arc.scene.ui.TextButton.*;
|
||||||
|
import io.anuke.arc.scene.ui.layout.*;
|
||||||
|
import io.anuke.arc.util.*;
|
||||||
|
import io.anuke.mindustry.game.*;
|
||||||
|
import io.anuke.mindustry.game.Schematics.*;
|
||||||
|
import io.anuke.mindustry.gen.*;
|
||||||
|
import io.anuke.mindustry.graphics.*;
|
||||||
|
import io.anuke.mindustry.type.*;
|
||||||
|
import io.anuke.mindustry.ui.*;
|
||||||
|
|
||||||
|
import static io.anuke.mindustry.Vars.*;
|
||||||
|
|
||||||
|
public class SchematicsDialog extends FloatingDialog{
|
||||||
|
private SchematicInfoDialog info = new SchematicInfoDialog();
|
||||||
|
private String search = "";
|
||||||
|
|
||||||
|
public SchematicsDialog(){
|
||||||
|
super("$schematics");
|
||||||
|
Core.assets.load("sprites/schematic-background.png", Texture.class).loaded = t -> {
|
||||||
|
((Texture)t).setWrap(TextureWrap.Repeat);
|
||||||
|
};
|
||||||
|
|
||||||
|
shouldPause = true;
|
||||||
|
addCloseButton();
|
||||||
|
buttons.addImageTextButton("$schematic.import", Icon.loadMapSmall, this::showImport);
|
||||||
|
shown(this::setup);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup(){
|
||||||
|
search = "";
|
||||||
|
Runnable[] rebuildPane = {null};
|
||||||
|
|
||||||
|
cont.top();
|
||||||
|
cont.clear();
|
||||||
|
|
||||||
|
cont.table(s -> {
|
||||||
|
s.left();
|
||||||
|
s.addImage(Icon.zoom);
|
||||||
|
s.addField(search, res -> {
|
||||||
|
search = res;
|
||||||
|
rebuildPane[0].run();
|
||||||
|
}).growX();
|
||||||
|
}).fillX().padBottom(4);
|
||||||
|
|
||||||
|
cont.row();
|
||||||
|
|
||||||
|
cont.pane(t -> {
|
||||||
|
t.top();
|
||||||
|
t.margin(20f);
|
||||||
|
rebuildPane[0] = () -> {
|
||||||
|
t.clear();
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
if(!schematics.all().contains(s -> search.isEmpty() || s.name().contains(search))){
|
||||||
|
t.add("$none");
|
||||||
|
}
|
||||||
|
|
||||||
|
for(Schematic s : schematics.all()){
|
||||||
|
if(!search.isEmpty() && !s.name().contains(search)) continue;
|
||||||
|
|
||||||
|
Button[] sel = {null};
|
||||||
|
sel[0] = t.addButton(b -> {
|
||||||
|
b.top();
|
||||||
|
b.margin(0f);
|
||||||
|
b.table(buttons -> {
|
||||||
|
buttons.left();
|
||||||
|
buttons.defaults().size(50f);
|
||||||
|
|
||||||
|
ImageButtonStyle style = Styles.clearPartiali;
|
||||||
|
|
||||||
|
buttons.addImageButton(Icon.infoSmall, style, () -> {
|
||||||
|
showInfo(s);
|
||||||
|
});
|
||||||
|
|
||||||
|
buttons.addImageButton(Icon.loadMapSmall, style, () -> {
|
||||||
|
showExport(s);
|
||||||
|
});
|
||||||
|
|
||||||
|
buttons.addImageButton(Icon.pencilSmall, style, () -> {
|
||||||
|
ui.showTextInput("$schematic.rename", "$name", s.name(), res -> {
|
||||||
|
s.tags.put("name", res);
|
||||||
|
s.save();
|
||||||
|
rebuildPane[0].run();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
if(s.hasSteamID()){
|
||||||
|
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();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}).growX().height(50f);
|
||||||
|
b.row();
|
||||||
|
b.stack(new SchematicImage(s).setScaling(Scaling.fit), new Table(n -> {
|
||||||
|
n.top();
|
||||||
|
n.table(Styles.black3, c -> {
|
||||||
|
Label label = c.add(s.name()).style(Styles.outlineLabel).color(Color.white).top().growX().get();
|
||||||
|
label.setEllipsis(true);
|
||||||
|
label.setAlignment(Align.center);
|
||||||
|
}).growX().margin(1).pad(4).padBottom(0);
|
||||||
|
})).size(200f);
|
||||||
|
}, () -> {
|
||||||
|
if(sel[0].childrenPressed()) return;
|
||||||
|
control.input.useSchematic(s);
|
||||||
|
hide();
|
||||||
|
}).pad(4).style(Styles.cleari).get();
|
||||||
|
|
||||||
|
sel[0].getStyle().up = Tex.pane;
|
||||||
|
|
||||||
|
if(++i % 4 == 0){
|
||||||
|
t.row();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
rebuildPane[0].run();
|
||||||
|
}).get().setScrollingDisabled(true, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void showInfo(Schematic schematic){
|
||||||
|
info.show(schematic);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void showImport(){
|
||||||
|
FloatingDialog dialog = new FloatingDialog("$editor.export");
|
||||||
|
dialog.cont.pane(p -> {
|
||||||
|
p.margin(10f);
|
||||||
|
p.table(Tex.button, t -> {
|
||||||
|
TextButtonStyle style = Styles.cleart;
|
||||||
|
t.defaults().size(280f, 60f).left();
|
||||||
|
t.row();
|
||||||
|
t.addImageTextButton("$schematic.copy.import", Icon.copySmall, style, () -> {
|
||||||
|
dialog.hide();
|
||||||
|
try{
|
||||||
|
Schematic s = schematics.readBase64(Core.app.getClipboardText());
|
||||||
|
schematics.add(s);
|
||||||
|
setup();
|
||||||
|
ui.showInfoFade("$schematic.saved");
|
||||||
|
showInfo(s);
|
||||||
|
}catch(Exception e){
|
||||||
|
ui.showException(e);
|
||||||
|
}
|
||||||
|
}).marginLeft(12f).disabled(b -> Core.app.getClipboardText() == null || !Core.app.getClipboardText().startsWith(schematicBaseStart));
|
||||||
|
t.row();
|
||||||
|
t.addImageTextButton("$schematic.importfile", Icon.saveMapSmall, style, () -> platform.showFileChooser(true, schematicExtension, file -> {
|
||||||
|
dialog.hide();
|
||||||
|
|
||||||
|
try{
|
||||||
|
Schematic s = Schematics.read(file);
|
||||||
|
schematics.add(s);
|
||||||
|
setup();
|
||||||
|
showInfo(s);
|
||||||
|
}catch(Exception e){
|
||||||
|
ui.showException(e);
|
||||||
|
}
|
||||||
|
})).marginLeft(12f);
|
||||||
|
t.row();
|
||||||
|
if(steam){
|
||||||
|
t.addImageTextButton("$schematic.browseworkshop", Icon.wikiSmall, style, () -> {
|
||||||
|
dialog.hide();
|
||||||
|
platform.openWorkshop();
|
||||||
|
}).marginLeft(12f);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
dialog.addCloseButton();
|
||||||
|
dialog.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void showExport(Schematic s){
|
||||||
|
FloatingDialog dialog = new FloatingDialog("$editor.export");
|
||||||
|
dialog.cont.pane(p -> {
|
||||||
|
p.margin(10f);
|
||||||
|
p.table(Tex.button, t -> {
|
||||||
|
TextButtonStyle style = Styles.cleart;
|
||||||
|
t.defaults().size(280f, 60f).left();
|
||||||
|
if(steam && !s.hasSteamID()){
|
||||||
|
t.addImageTextButton("$schematic.shareworkshop", Icon.wikiSmall, style,
|
||||||
|
() -> platform.publish(s)).marginLeft(12f);
|
||||||
|
t.row();
|
||||||
|
}
|
||||||
|
t.addImageTextButton("$schematic.copy", Icon.copySmall, style, () -> {
|
||||||
|
dialog.hide();
|
||||||
|
ui.showInfoFade("$copied");
|
||||||
|
Core.app.setClipboardText(schematics.writeBase64(s));
|
||||||
|
}).marginLeft(12f);
|
||||||
|
t.row();
|
||||||
|
t.addImageTextButton("$schematic.exportfile", Icon.saveMapSmall, style, () -> platform.showFileChooser(false, schematicExtension, file -> {
|
||||||
|
dialog.hide();
|
||||||
|
try{
|
||||||
|
Schematics.write(s, file);
|
||||||
|
}catch(Exception e){
|
||||||
|
ui.showException(e);
|
||||||
|
}
|
||||||
|
})).marginLeft(12f);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
dialog.addCloseButton();
|
||||||
|
dialog.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class SchematicImage extends Image{
|
||||||
|
public float scaling = 16f;
|
||||||
|
public float thickness = 4f;
|
||||||
|
public Color borderColor = Pal.gray;
|
||||||
|
|
||||||
|
public SchematicImage(Schematic s){
|
||||||
|
super(schematics.getPreview(s, PreviewRes.high));
|
||||||
|
setScaling(Scaling.fit);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void draw(){
|
||||||
|
boolean checked = getParent().getParent() instanceof Button
|
||||||
|
&& ((Button)getParent().getParent()).isOver();
|
||||||
|
|
||||||
|
Texture background = Core.assets.get("sprites/schematic-background.png", Texture.class);
|
||||||
|
TextureRegion region = Draw.wrap(background);
|
||||||
|
float xr = width / scaling;
|
||||||
|
float yr = height / scaling;
|
||||||
|
region.setU2(xr);
|
||||||
|
region.setV2(yr);
|
||||||
|
Draw.color();
|
||||||
|
Draw.alpha(parentAlpha);
|
||||||
|
Draw.rect(region, x + width/2f, y + height/2f, width, height);
|
||||||
|
|
||||||
|
super.draw();
|
||||||
|
|
||||||
|
Draw.color(checked ? Pal.accent : borderColor);
|
||||||
|
Draw.alpha(parentAlpha);
|
||||||
|
Lines.stroke(Scl.scl(thickness));
|
||||||
|
Lines.rect(x, y, width, height);
|
||||||
|
Draw.reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class SchematicInfoDialog extends FloatingDialog{
|
||||||
|
|
||||||
|
SchematicInfoDialog(){
|
||||||
|
super("");
|
||||||
|
setFillParent(true);
|
||||||
|
addCloseButton();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void show(Schematic schem){
|
||||||
|
cont.clear();
|
||||||
|
title.setText("[[" + Core.bundle.get("schematic") + "] " +schem.name());
|
||||||
|
|
||||||
|
cont.add(Core.bundle.format("schematic.info", schem.width, schem.height, schem.tiles.size)).color(Color.lightGray);
|
||||||
|
cont.row();
|
||||||
|
cont.add(new SchematicImage(schem)).maxSize(800f);
|
||||||
|
cont.row();
|
||||||
|
|
||||||
|
Array<ItemStack> arr = schem.requirements();
|
||||||
|
cont.table(r -> {
|
||||||
|
int i = 0;
|
||||||
|
for(ItemStack s : arr){
|
||||||
|
r.addImage(s.item.icon(Cicon.small)).left();
|
||||||
|
r.add(s.amount + "").padLeft(2).left().color(Color.lightGray).padRight(4);
|
||||||
|
|
||||||
|
if(++i % 4 == 0){
|
||||||
|
r.row();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -42,6 +42,10 @@ public class TechTreeDialog extends FloatingDialog{
|
|||||||
margin(0f).marginBottom(8);
|
margin(0f).marginBottom(8);
|
||||||
cont.stack(view = new View(), items = new ItemsDisplay()).grow();
|
cont.stack(view = new View(), items = new ItemsDisplay()).grow();
|
||||||
|
|
||||||
|
Events.on(ContentReloadEvent.class, e -> {
|
||||||
|
root = new TechTreeNode(TechTree.root, null);
|
||||||
|
});
|
||||||
|
|
||||||
shown(() -> {
|
shown(() -> {
|
||||||
checkNodes(root);
|
checkNodes(root);
|
||||||
treeLayout();
|
treeLayout();
|
||||||
@@ -105,8 +109,18 @@ public class TechTreeDialog extends FloatingDialog{
|
|||||||
RadialTreeLayout layout = new RadialTreeLayout();
|
RadialTreeLayout layout = new RadialTreeLayout();
|
||||||
LayoutNode node = new LayoutNode(root, null);
|
LayoutNode node = new LayoutNode(root, null);
|
||||||
layout.layout(node);
|
layout.layout(node);
|
||||||
//bounds.y += nodeSize*1.5f;
|
float minx = 0f, miny = 0f, maxx = 0f, maxy = 0f;
|
||||||
copyInfo(node);
|
copyInfo(node);
|
||||||
|
|
||||||
|
for(TechTreeNode n : nodes){
|
||||||
|
if(!n.visible) continue;
|
||||||
|
minx = Math.min(n.x - n.width/2f, minx);
|
||||||
|
maxx = Math.max(n.x + n.width/2f, maxx);
|
||||||
|
miny = Math.min(n.y - n.height/2f, miny);
|
||||||
|
maxy = Math.max(n.y + n.height/2f, maxy);
|
||||||
|
}
|
||||||
|
bounds = new Rectangle(minx, miny, maxx - minx, maxy - miny);
|
||||||
|
bounds.y += nodeSize*1.5f;
|
||||||
}
|
}
|
||||||
|
|
||||||
void copyInfo(LayoutNode node){
|
void copyInfo(LayoutNode node){
|
||||||
@@ -262,7 +276,7 @@ public class TechTreeDialog extends FloatingDialog{
|
|||||||
float rx = bounds.x + panX + ox, ry = panY + oy + bounds.y;
|
float rx = bounds.x + panX + ox, ry = panY + oy + bounds.y;
|
||||||
float rw = bounds.width, rh = bounds.height;
|
float rw = bounds.width, rh = bounds.height;
|
||||||
rx = Mathf.clamp(rx, -rw + pad, Core.graphics.getWidth() - pad);
|
rx = Mathf.clamp(rx, -rw + pad, Core.graphics.getWidth() - pad);
|
||||||
ry = Mathf.clamp(ry, pad, Core.graphics.getHeight() - rh - pad);
|
ry = Mathf.clamp(ry, -rh + pad, Core.graphics.getHeight() - pad);
|
||||||
panX = rx - bounds.x - ox;
|
panX = rx - bounds.x - ox;
|
||||||
panY = ry - bounds.y - oy;
|
panY = ry - bounds.y - oy;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -250,8 +250,9 @@ public class HudFragment extends Fragment{
|
|||||||
});
|
});
|
||||||
|
|
||||||
parent.fill(t -> {
|
parent.fill(t -> {
|
||||||
|
t.visible(() -> Core.settings.getBool("minimap") && !state.rules.tutorial);
|
||||||
//minimap
|
//minimap
|
||||||
t.add(new Minimap().visible(() -> Core.settings.getBool("minimap") && !state.rules.tutorial));
|
t.add(new Minimap());
|
||||||
t.row();
|
t.row();
|
||||||
//position
|
//position
|
||||||
t.label(() -> world.toTile(player.x) + "," + world.toTile(player.y)).style(Styles.outlineLabel)
|
t.label(() -> world.toTile(player.x) + "," + world.toTile(player.y)).style(Styles.outlineLabel)
|
||||||
|
|||||||
@@ -22,7 +22,6 @@ public class LoadingFragment extends Fragment{
|
|||||||
t.visible(false);
|
t.visible(false);
|
||||||
t.touchable(Touchable.enabled);
|
t.touchable(Touchable.enabled);
|
||||||
t.add().height(133f).row();
|
t.add().height(133f).row();
|
||||||
|
|
||||||
t.addImage().growX().height(3f).pad(4f).growX().get().setColor(Pal.accent);
|
t.addImage().growX().height(3f).pad(4f).growX().get().setColor(Pal.accent);
|
||||||
t.row();
|
t.row();
|
||||||
t.add("$loading").name("namelabel").pad(10f);
|
t.add("$loading").name("namelabel").pad(10f);
|
||||||
|
|||||||
@@ -87,6 +87,8 @@ public class Block extends BlockStorage{
|
|||||||
public boolean configurable;
|
public boolean configurable;
|
||||||
/** Whether this block consumes touchDown events when tapped. */
|
/** Whether this block consumes touchDown events when tapped. */
|
||||||
public boolean consumesTap;
|
public boolean consumesTap;
|
||||||
|
/** Whether the config is positional and needs to be shifted. */
|
||||||
|
public boolean posConfig;
|
||||||
/**
|
/**
|
||||||
* The color of this block when displayed on the minimap or map preview.
|
* The color of this block when displayed on the minimap or map preview.
|
||||||
* Do not set manually! This is overriden when loading for most blocks.
|
* Do not set manually! This is overriden when loading for most blocks.
|
||||||
@@ -116,7 +118,7 @@ public class Block extends BlockStorage{
|
|||||||
public float idleSoundVolume = 0.5f;
|
public float idleSoundVolume = 0.5f;
|
||||||
|
|
||||||
/** Cost of constructing this block. */
|
/** Cost of constructing this block. */
|
||||||
public ItemStack[] requirements = new ItemStack[]{};
|
public ItemStack[] requirements = {};
|
||||||
/** Category in place menu. */
|
/** Category in place menu. */
|
||||||
public Category category = Category.distribution;
|
public Category category = Category.distribution;
|
||||||
/** Cost of building this block; do not modify directly! */
|
/** Cost of building this block; do not modify directly! */
|
||||||
@@ -676,8 +678,32 @@ public class Block extends BlockStorage{
|
|||||||
public void drawRequestRegion(BuildRequest req, Eachable<BuildRequest> list){
|
public void drawRequestRegion(BuildRequest req, Eachable<BuildRequest> list){
|
||||||
TextureRegion reg = icon(Cicon.full);
|
TextureRegion reg = icon(Cicon.full);
|
||||||
Draw.rect(icon(Cicon.full), req.drawx(), req.drawy(),
|
Draw.rect(icon(Cicon.full), req.drawx(), req.drawy(),
|
||||||
reg.getWidth() * req.animScale * Draw.scl, reg.getHeight() * req.animScale * Draw.scl,
|
reg.getWidth() * req.animScale * Draw.scl,
|
||||||
!rotate ? 0 : req.rotation * 90);
|
reg.getHeight() * req.animScale * Draw.scl,
|
||||||
|
!rotate ? 0 : req.rotation * 90);
|
||||||
|
|
||||||
|
if(req.hasConfig){
|
||||||
|
drawRequestConfig(req, list);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void drawRequestConfig(BuildRequest req, Eachable<BuildRequest> list){
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void drawRequestConfigCenter(BuildRequest req, Content content, String region){
|
||||||
|
Color color = content instanceof Item ? ((Item)content).color : content instanceof Liquid ? ((Liquid)content).color : null;
|
||||||
|
if(color == null) return;
|
||||||
|
|
||||||
|
Draw.color(color);
|
||||||
|
Draw.scl *= req.animScale;
|
||||||
|
Draw.rect(region, req.drawx(), req.drawy());
|
||||||
|
Draw.scl /= req.animScale;
|
||||||
|
Draw.color();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void drawRequestConfigTop(BuildRequest req, Eachable<BuildRequest> list){
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ public class BuildBlock extends Block{
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Remote(called = Loc.server)
|
@Remote(called = Loc.server)
|
||||||
public static void onConstructFinish(Tile tile, Block block, int builderID, byte rotation, Team team){
|
public static void onConstructFinish(Tile tile, Block block, int builderID, byte rotation, Team team, boolean skipConfig){
|
||||||
if(tile == null) return;
|
if(tile == null) return;
|
||||||
float healthf = tile.entity == null ? 1f : tile.entity.healthf();
|
float healthf = tile.entity == null ? 1f : tile.entity.healthf();
|
||||||
world.setBlock(tile, block, team, rotation);
|
world.setBlock(tile, block, team, rotation);
|
||||||
@@ -70,7 +70,9 @@ public class BuildBlock extends Block{
|
|||||||
if(!headless && builderID == player.id){
|
if(!headless && builderID == player.id){
|
||||||
//this is run delayed, since if this is called on the server, all clients need to recieve the onBuildFinish()
|
//this is run delayed, since if this is called on the server, all clients need to recieve the onBuildFinish()
|
||||||
//event first before they can recieve the placed() event modification results
|
//event first before they can recieve the placed() event modification results
|
||||||
Core.app.post(() -> tile.block().playerPlaced(tile));
|
if(!skipConfig){
|
||||||
|
Core.app.post(() -> tile.block().playerPlaced(tile));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Core.app.post(() -> Events.fire(new BlockBuildEndEvent(tile, playerGroup.getByID(builderID), team, false)));
|
Core.app.post(() -> Events.fire(new BlockBuildEndEvent(tile, playerGroup.getByID(builderID), team, false)));
|
||||||
Sounds.place.at(tile, Mathf.random(0.7f, 1.4f));
|
Sounds.place.at(tile, Mathf.random(0.7f, 1.4f));
|
||||||
@@ -185,7 +187,7 @@ public class BuildBlock extends Block{
|
|||||||
private float[] accumulator;
|
private float[] accumulator;
|
||||||
private float[] totalAccumulator;
|
private float[] totalAccumulator;
|
||||||
|
|
||||||
public boolean construct(Unit builder, @Nullable TileEntity core, float amount){
|
public boolean construct(Unit builder, @Nullable TileEntity core, float amount, boolean configured){
|
||||||
if(cblock == null){
|
if(cblock == null){
|
||||||
kill();
|
kill();
|
||||||
return false;
|
return false;
|
||||||
@@ -208,7 +210,7 @@ public class BuildBlock extends Block{
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(progress >= 1f || state.rules.infiniteResources){
|
if(progress >= 1f || state.rules.infiniteResources){
|
||||||
Call.onConstructFinish(tile, cblock, builderID, tile.rotation(), builder.getTeam());
|
Call.onConstructFinish(tile, cblock, builderID, tile.rotation(), builder.getTeam(), configured);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -52,11 +52,13 @@ public class Conduit extends LiquidBlock implements Autotiler{
|
|||||||
|
|
||||||
Draw.colorl(0.34f);
|
Draw.colorl(0.34f);
|
||||||
Draw.alpha(0.5f);
|
Draw.alpha(0.5f);
|
||||||
Draw.rect(botRegions[bits[0]], req.drawx(), req.drawy(), req.rotation * 90);
|
Draw.rect(botRegions[bits[0]], req.drawx(), req.drawy(),
|
||||||
|
botRegions[bits[0]].getWidth() * Draw.scl * req.animScale, botRegions[bits[0]].getHeight() * Draw.scl * req.animScale,
|
||||||
|
req.rotation * 90);
|
||||||
Draw.color();
|
Draw.color();
|
||||||
|
|
||||||
|
|
||||||
Draw.rect(topRegions[bits[0]], req.drawx(), req.drawy(), req.rotation * 90);
|
Draw.rect(topRegions[bits[0]], req.drawx(), req.drawy(), topRegions[bits[0]].getWidth() * Draw.scl * req.animScale, topRegions[bits[0]].getHeight() * Draw.scl * req.animScale, req.rotation * 90);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -107,7 +107,7 @@ public class Conveyor extends Block implements Autotiler{
|
|||||||
if(bits == null) return;
|
if(bits == null) return;
|
||||||
|
|
||||||
TextureRegion region = regions[bits[0]][0];
|
TextureRegion region = regions[bits[0]][0];
|
||||||
Draw.rect(region, req.drawx(), req.drawy(), region.getWidth() * bits[1] * Draw.scl, region.getHeight() * bits[2] * Draw.scl, req.rotation * 90);
|
Draw.rect(region, req.drawx(), req.drawy(), region.getWidth() * bits[1] * Draw.scl * req.animScale, region.getHeight() * bits[2] * Draw.scl * req.animScale, req.rotation * 90);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -3,11 +3,13 @@ package io.anuke.mindustry.world.blocks.distribution;
|
|||||||
import io.anuke.arc.*;
|
import io.anuke.arc.*;
|
||||||
import io.anuke.arc.collection.*;
|
import io.anuke.arc.collection.*;
|
||||||
import io.anuke.arc.collection.IntSet.*;
|
import io.anuke.arc.collection.IntSet.*;
|
||||||
|
import io.anuke.arc.function.*;
|
||||||
import io.anuke.arc.graphics.*;
|
import io.anuke.arc.graphics.*;
|
||||||
import io.anuke.arc.graphics.g2d.*;
|
import io.anuke.arc.graphics.g2d.*;
|
||||||
import io.anuke.arc.math.*;
|
import io.anuke.arc.math.*;
|
||||||
import io.anuke.arc.math.geom.*;
|
import io.anuke.arc.math.geom.*;
|
||||||
import io.anuke.arc.util.*;
|
import io.anuke.arc.util.*;
|
||||||
|
import io.anuke.mindustry.entities.traits.BuilderTrait.*;
|
||||||
import io.anuke.mindustry.entities.type.*;
|
import io.anuke.mindustry.entities.type.*;
|
||||||
import io.anuke.mindustry.graphics.*;
|
import io.anuke.mindustry.graphics.*;
|
||||||
import io.anuke.mindustry.type.*;
|
import io.anuke.mindustry.type.*;
|
||||||
@@ -23,6 +25,7 @@ public class ItemBridge extends Block{
|
|||||||
protected int range;
|
protected int range;
|
||||||
protected float transportTime = 2f;
|
protected float transportTime = 2f;
|
||||||
protected TextureRegion endRegion, bridgeRegion, arrowRegion;
|
protected TextureRegion endRegion, bridgeRegion, arrowRegion;
|
||||||
|
protected BuildRequest otherReq;
|
||||||
|
|
||||||
private static int lastPlaced = Pos.invalid;
|
private static int lastPlaced = Pos.invalid;
|
||||||
|
|
||||||
@@ -34,6 +37,7 @@ public class ItemBridge extends Block{
|
|||||||
layer = Layer.power;
|
layer = Layer.power;
|
||||||
expanded = true;
|
expanded = true;
|
||||||
itemCapacity = 10;
|
itemCapacity = 10;
|
||||||
|
posConfig = true;
|
||||||
configurable = true;
|
configurable = true;
|
||||||
hasItems = true;
|
hasItems = true;
|
||||||
unloadable = false;
|
unloadable = false;
|
||||||
@@ -65,6 +69,27 @@ public class ItemBridge extends Block{
|
|||||||
arrowRegion = Core.atlas.find(name + "-arrow");
|
arrowRegion = Core.atlas.find(name + "-arrow");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void drawRequestConfigTop(BuildRequest req, Eachable<BuildRequest> list){
|
||||||
|
otherReq = null;
|
||||||
|
list.each(other -> {
|
||||||
|
if(other.block == this && req.config == Pos.get(other.x, other.y)){
|
||||||
|
otherReq = other;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if(otherReq == null) return;
|
||||||
|
|
||||||
|
Lines.stroke(8f);
|
||||||
|
Lines.line(bridgeRegion,
|
||||||
|
req.drawx(),
|
||||||
|
req.drawy(),
|
||||||
|
otherReq.drawx(),
|
||||||
|
otherReq.drawy(), CapStyle.none, -tilesize / 2f);
|
||||||
|
Draw.rect(arrowRegion, (req.drawx() + otherReq.drawx()) / 2f, (req.drawy() + otherReq.drawy()) / 2f,
|
||||||
|
Angles.angle(req.drawx(), req.drawy(), otherReq.drawx(), otherReq.drawy()));
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void playerPlaced(Tile tile){
|
public void playerPlaced(Tile tile){
|
||||||
Tile link = findLink(tile.x, tile.y);
|
Tile link = findLink(tile.x, tile.y);
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ public class MassDriver extends Block{
|
|||||||
super(name);
|
super(name);
|
||||||
update = true;
|
update = true;
|
||||||
solid = true;
|
solid = true;
|
||||||
|
posConfig = true;
|
||||||
configurable = true;
|
configurable = true;
|
||||||
hasItems = true;
|
hasItems = true;
|
||||||
layer = Layer.turret;
|
layer = Layer.turret;
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
package io.anuke.mindustry.world.blocks.distribution;
|
package io.anuke.mindustry.world.blocks.distribution;
|
||||||
|
|
||||||
import io.anuke.arc.*;
|
import io.anuke.arc.*;
|
||||||
|
import io.anuke.arc.function.*;
|
||||||
import io.anuke.arc.graphics.g2d.*;
|
import io.anuke.arc.graphics.g2d.*;
|
||||||
import io.anuke.arc.math.*;
|
import io.anuke.arc.math.*;
|
||||||
import io.anuke.arc.scene.ui.layout.*;
|
import io.anuke.arc.scene.ui.layout.*;
|
||||||
import io.anuke.arc.util.ArcAnnotate.*;
|
import io.anuke.arc.util.ArcAnnotate.*;
|
||||||
|
import io.anuke.mindustry.entities.traits.BuilderTrait.*;
|
||||||
import io.anuke.mindustry.entities.type.*;
|
import io.anuke.mindustry.entities.type.*;
|
||||||
import io.anuke.mindustry.type.*;
|
import io.anuke.mindustry.type.*;
|
||||||
import io.anuke.mindustry.world.*;
|
import io.anuke.mindustry.world.*;
|
||||||
@@ -46,6 +48,11 @@ public class Sorter extends Block{
|
|||||||
tile.<SorterEntity>entity().sortItem = content.item(value);
|
tile.<SorterEntity>entity().sortItem = content.item(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void drawRequestConfig(BuildRequest req, Eachable<BuildRequest> list){
|
||||||
|
drawRequestConfigCenter(req, content.item(req.config), "center");
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void draw(Tile tile){
|
public void draw(Tile tile){
|
||||||
super.draw(tile);
|
super.draw(tile);
|
||||||
|
|||||||
@@ -33,53 +33,6 @@ public class PowerNode extends PowerBlock{
|
|||||||
consumesPower = false;
|
consumesPower = false;
|
||||||
outputsPower = false;
|
outputsPower = false;
|
||||||
}
|
}
|
||||||
/*
|
|
||||||
@Remote(targets = Loc.both, called = Loc.server, forward = true)
|
|
||||||
public static void linkPowerNodes(Player player, Tile tile, Tile other){
|
|
||||||
if(tile.entity == null || other == null || tile.entity.power == null || !((PowerNode)tile.block()).linkValid(tile, other)
|
|
||||||
|| tile.entity.power.links.size >= ((PowerNode)tile.block()).maxNodes) return;
|
|
||||||
if(!Units.canInteract(player, tile)) return;
|
|
||||||
|
|
||||||
TileEntity entity = tile.entity();
|
|
||||||
|
|
||||||
if(!entity.power.links.contains(other.pos())){
|
|
||||||
entity.power.links.add(other.pos());
|
|
||||||
}
|
|
||||||
|
|
||||||
if(other.getTeamID() == tile.getTeamID()){
|
|
||||||
|
|
||||||
if(!other.entity.power.links.contains(tile.pos())){
|
|
||||||
other.entity.power.links.add(tile.pos());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
entity.power.graph.add(other.entity.power.graph);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Remote(targets = Loc.both, called = Loc.server, forward = true)
|
|
||||||
public static void unlinkPowerNodes(Player player, Tile tile, Tile other){
|
|
||||||
if(tile.entity.power == null || other.entity == null || other.entity.power == null) return;
|
|
||||||
if(!Units.canInteract(player, tile)) return;
|
|
||||||
|
|
||||||
TileEntity entity = tile.entity();
|
|
||||||
|
|
||||||
entity.power.links.removeValue(other.pos());
|
|
||||||
other.entity.power.links.removeValue(tile.pos());
|
|
||||||
|
|
||||||
PowerGraph newgraph = new PowerGraph();
|
|
||||||
|
|
||||||
//reflow from this point, covering all tiles on this side
|
|
||||||
newgraph.reflow(tile);
|
|
||||||
|
|
||||||
if(other.entity.power.graph != newgraph){
|
|
||||||
//create new graph for other end
|
|
||||||
PowerGraph og = new PowerGraph();
|
|
||||||
//reflow from other end
|
|
||||||
og.reflow(other);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void configured(Tile tile, Player player, int value){
|
public void configured(Tile tile, Player player, int value){
|
||||||
|
|||||||
@@ -34,6 +34,11 @@ public class Fracker extends SolidPump{
|
|||||||
topRegion = Core.atlas.find(name + "-top");
|
topRegion = Core.atlas.find(name + "-top");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean outputsItems(){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void drawCracks(Tile tile){}
|
public void drawCracks(Tile tile){}
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
package io.anuke.mindustry.world.blocks.sandbox;
|
package io.anuke.mindustry.world.blocks.sandbox;
|
||||||
|
|
||||||
import io.anuke.arc.*;
|
import io.anuke.arc.*;
|
||||||
|
import io.anuke.arc.function.*;
|
||||||
import io.anuke.arc.graphics.g2d.*;
|
import io.anuke.arc.graphics.g2d.*;
|
||||||
import io.anuke.arc.scene.ui.layout.*;
|
import io.anuke.arc.scene.ui.layout.*;
|
||||||
|
import io.anuke.mindustry.entities.traits.BuilderTrait.*;
|
||||||
import io.anuke.mindustry.entities.type.*;
|
import io.anuke.mindustry.entities.type.*;
|
||||||
import io.anuke.mindustry.type.*;
|
import io.anuke.mindustry.type.*;
|
||||||
import io.anuke.mindustry.world.*;
|
import io.anuke.mindustry.world.*;
|
||||||
@@ -43,6 +45,11 @@ public class ItemSource extends Block{
|
|||||||
bars.remove("items");
|
bars.remove("items");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void drawRequestConfig(BuildRequest req, Eachable<BuildRequest> list){
|
||||||
|
drawRequestConfigCenter(req, content.item(req.config), "center");
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean outputsItems(){
|
public boolean outputsItems(){
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -2,11 +2,13 @@ package io.anuke.mindustry.world.blocks.sandbox;
|
|||||||
|
|
||||||
import io.anuke.arc.*;
|
import io.anuke.arc.*;
|
||||||
import io.anuke.arc.collection.*;
|
import io.anuke.arc.collection.*;
|
||||||
|
import io.anuke.arc.function.*;
|
||||||
import io.anuke.arc.graphics.g2d.*;
|
import io.anuke.arc.graphics.g2d.*;
|
||||||
import io.anuke.arc.scene.style.*;
|
import io.anuke.arc.scene.style.*;
|
||||||
import io.anuke.arc.scene.ui.*;
|
import io.anuke.arc.scene.ui.*;
|
||||||
import io.anuke.arc.scene.ui.layout.*;
|
import io.anuke.arc.scene.ui.layout.*;
|
||||||
import io.anuke.arc.util.ArcAnnotate.*;
|
import io.anuke.arc.util.ArcAnnotate.*;
|
||||||
|
import io.anuke.mindustry.entities.traits.BuilderTrait.*;
|
||||||
import io.anuke.mindustry.entities.type.*;
|
import io.anuke.mindustry.entities.type.*;
|
||||||
import io.anuke.mindustry.game.*;
|
import io.anuke.mindustry.game.*;
|
||||||
import io.anuke.mindustry.gen.*;
|
import io.anuke.mindustry.gen.*;
|
||||||
@@ -57,6 +59,11 @@ public class LiquidSource extends Block{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void drawRequestConfig(BuildRequest req, Eachable<BuildRequest> list){
|
||||||
|
drawRequestConfigCenter(req, content.liquid(req.config), "center");
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void draw(Tile tile){
|
public void draw(Tile tile){
|
||||||
super.draw(tile);
|
super.draw(tile);
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
package io.anuke.mindustry.world.blocks.storage;
|
package io.anuke.mindustry.world.blocks.storage;
|
||||||
|
|
||||||
import io.anuke.arc.*;
|
import io.anuke.arc.*;
|
||||||
|
import io.anuke.arc.function.*;
|
||||||
import io.anuke.arc.graphics.*;
|
import io.anuke.arc.graphics.*;
|
||||||
import io.anuke.arc.graphics.g2d.*;
|
import io.anuke.arc.graphics.g2d.*;
|
||||||
import io.anuke.arc.scene.ui.layout.*;
|
import io.anuke.arc.scene.ui.layout.*;
|
||||||
|
import io.anuke.mindustry.entities.traits.BuilderTrait.*;
|
||||||
import io.anuke.mindustry.entities.type.*;
|
import io.anuke.mindustry.entities.type.*;
|
||||||
import io.anuke.mindustry.type.*;
|
import io.anuke.mindustry.type.*;
|
||||||
import io.anuke.mindustry.world.*;
|
import io.anuke.mindustry.world.*;
|
||||||
@@ -28,6 +30,11 @@ public class Unloader extends Block{
|
|||||||
configurable = true;
|
configurable = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void drawRequestConfig(BuildRequest req, Eachable<BuildRequest> list){
|
||||||
|
drawRequestConfigCenter(req, content.item(req.config), "unloader-center");
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean canDump(Tile tile, Tile to, Item item){
|
public boolean canDump(Tile tile, Tile to, Item item){
|
||||||
return !(to.block() instanceof StorageBlock);
|
return !(to.block() instanceof StorageBlock);
|
||||||
@@ -109,7 +116,7 @@ public class Unloader extends Block{
|
|||||||
UnloaderEntity entity = tile.entity();
|
UnloaderEntity entity = tile.entity();
|
||||||
|
|
||||||
Draw.color(entity.sortItem == null ? Color.clear : entity.sortItem.color);
|
Draw.color(entity.sortItem == null ? Color.clear : entity.sortItem.color);
|
||||||
Fill.square(tile.worldx(), tile.worldy(), 1f);
|
Draw.rect("unloader-center", tile.worldx(), tile.worldy());
|
||||||
Draw.color();
|
Draw.color();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -22,10 +22,10 @@ import io.anuke.mindustry.core.GameState.*;
|
|||||||
import io.anuke.mindustry.desktop.steam.*;
|
import io.anuke.mindustry.desktop.steam.*;
|
||||||
import io.anuke.mindustry.game.EventType.*;
|
import io.anuke.mindustry.game.EventType.*;
|
||||||
import io.anuke.mindustry.game.Version;
|
import io.anuke.mindustry.game.Version;
|
||||||
import io.anuke.mindustry.maps.Map;
|
|
||||||
import io.anuke.mindustry.mod.Mods.*;
|
import io.anuke.mindustry.mod.Mods.*;
|
||||||
import io.anuke.mindustry.net.*;
|
import io.anuke.mindustry.net.*;
|
||||||
import io.anuke.mindustry.net.Net.*;
|
import io.anuke.mindustry.net.Net.*;
|
||||||
|
import io.anuke.mindustry.type.*;
|
||||||
import io.anuke.mindustry.ui.*;
|
import io.anuke.mindustry.ui.*;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
@@ -249,28 +249,18 @@ public class DesktopLauncher extends ClientLauncher{
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Array<FileHandle> getExternalMaps(){
|
public Array<FileHandle> getWorkshopContent(Class<? extends Publishable> type){
|
||||||
return !steam ? super.getExternalMaps() : SVars.workshop.getMapFiles();
|
return !steam ? super.getWorkshopContent(type) : SVars.workshop.getWorkshopFiles(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Array<FileHandle> getExternalMods(){
|
public void viewListing(Publishable pub){
|
||||||
return !steam ? super.getExternalMods() : SVars.workshop.getModFiles();
|
SVars.workshop.viewListing(pub);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void viewMapListing(Map map){
|
public void viewListingID(String id){
|
||||||
viewListing(map.file.parent().name());
|
SVars.net.friends.activateGameOverlayToWebPage("steam://url/CommunityFilePage/" + id);
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void viewListing(String mapid){
|
|
||||||
SVars.net.friends.activateGameOverlayToWebPage("steam://url/CommunityFilePage/" + mapid);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void viewMapListingInfo(Map map){
|
|
||||||
SVars.workshop.viewMapListingInfo(map);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -284,8 +274,8 @@ public class DesktopLauncher extends ClientLauncher{
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void publishMap(Map map){
|
public void publish(Publishable pub){
|
||||||
SVars.workshop.publishMap(map);
|
SVars.workshop.publish(pub);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -9,10 +9,11 @@ import io.anuke.arc.files.*;
|
|||||||
import io.anuke.arc.function.*;
|
import io.anuke.arc.function.*;
|
||||||
import io.anuke.arc.scene.ui.*;
|
import io.anuke.arc.scene.ui.*;
|
||||||
import io.anuke.arc.util.*;
|
import io.anuke.arc.util.*;
|
||||||
import io.anuke.mindustry.game.EventType.*;
|
|
||||||
import io.anuke.mindustry.game.*;
|
import io.anuke.mindustry.game.*;
|
||||||
import io.anuke.mindustry.gen.*;
|
import io.anuke.mindustry.gen.*;
|
||||||
import io.anuke.mindustry.maps.*;
|
import io.anuke.mindustry.maps.*;
|
||||||
|
import io.anuke.mindustry.mod.Mods.*;
|
||||||
|
import io.anuke.mindustry.type.*;
|
||||||
import io.anuke.mindustry.ui.dialogs.*;
|
import io.anuke.mindustry.ui.dialogs.*;
|
||||||
|
|
||||||
import static io.anuke.mindustry.Vars.*;
|
import static io.anuke.mindustry.Vars.*;
|
||||||
@@ -20,10 +21,10 @@ import static io.anuke.mindustry.Vars.*;
|
|||||||
public class SWorkshop implements SteamUGCCallback{
|
public class SWorkshop implements SteamUGCCallback{
|
||||||
public final SteamUGC ugc = new SteamUGC(this);
|
public final SteamUGC ugc = new SteamUGC(this);
|
||||||
|
|
||||||
private Map lastMap;
|
private ObjectMap<Class<? extends Publishable>, Array<FileHandle>> workshopFiles = new ObjectMap<>();
|
||||||
private Array<FileHandle> mapFiles;
|
|
||||||
private Array<FileHandle> modFiles;
|
|
||||||
private ObjectMap<SteamUGCQuery, BiConsumer<Array<SteamUGCDetails>, SteamResult>> detailHandlers = new ObjectMap<>();
|
private ObjectMap<SteamUGCQuery, BiConsumer<Array<SteamUGCDetails>, SteamResult>> detailHandlers = new ObjectMap<>();
|
||||||
|
private Array<Consumer<SteamPublishedFileID>> itemHandlers = new Array<>();
|
||||||
|
private ObjectMap<SteamPublishedFileID, Runnable> updatedHandlers = new ObjectMap<>();
|
||||||
|
|
||||||
public SWorkshop(){
|
public SWorkshop(){
|
||||||
int items = ugc.getNumSubscribedItems();
|
int items = ugc.getNumSubscribedItems();
|
||||||
@@ -36,71 +37,56 @@ public class SWorkshop implements SteamUGCCallback{
|
|||||||
return new FileHandle(info.getFolder());
|
return new FileHandle(info.getFolder());
|
||||||
}).select(f -> f != null && f.list().length > 0);
|
}).select(f -> f != null && f.list().length > 0);
|
||||||
|
|
||||||
mapFiles = folders.select(f -> f.list().length == 1 && f.list()[0].extension().equals(mapExtension)).map(f -> f.list()[0]);
|
workshopFiles.put(Map.class, folders.select(f -> f.list().length == 1 && f.list()[0].extension().equals(mapExtension)).map(f -> f.list()[0]));
|
||||||
modFiles = folders.select(f -> f.child("mod.json").exists());
|
workshopFiles.put(Schematic.class, folders.select(f -> f.list().length == 1 && f.list()[0].extension().equals(schematicExtension)).map(f -> f.list()[0]));
|
||||||
|
workshopFiles.put(LoadedMod.class, folders.select(f -> f.child("mod.json").exists()));
|
||||||
|
|
||||||
if(!mapFiles.isEmpty()){
|
if(!workshopFiles.get(Map.class).isEmpty()){
|
||||||
SAchievement.downloadMapWorkshop.complete();
|
SAchievement.downloadMapWorkshop.complete();
|
||||||
}
|
}
|
||||||
|
|
||||||
Log.info("Fetching {0} subscribed maps.", mapFiles.size);
|
workshopFiles.each((type, list) -> {
|
||||||
Log.info("Fetching {0} subscribed mods.", modFiles.size);
|
Log.info("Fetched content ({0}): {1}", type.getSimpleName(), list.size);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public Array<FileHandle> getMapFiles(){
|
public Array<FileHandle> getWorkshopFiles(Class<? extends Publishable> type){
|
||||||
return mapFiles;
|
return workshopFiles.getOr(type, () -> new Array<>(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
public Array<FileHandle> getModFiles(){
|
/** Publish a new item and submit an update for it.
|
||||||
return modFiles;
|
* If it is already published, redirects to its page.*/
|
||||||
}
|
public void publish(Publishable p){
|
||||||
|
if(p.hasSteamID()){
|
||||||
public void publishMap(Map map){
|
Log.info("Content already published, redirecting to ID.");
|
||||||
if(map.tags.containsKey("steamid")){
|
viewListing(p);
|
||||||
Log.info("Map already published, redirecting to ID.");
|
|
||||||
SVars.net.friends.activateGameOverlayToWebPage("steam://url/CommunityFilePage/" + map.tags.get("steamid"));
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//update author name when publishing
|
if(!p.prePublish()){
|
||||||
map.tags.put("author", SVars.net.friends.getPersonaName());
|
return;
|
||||||
ui.editor.editor.getTags().put("author", map.tags.get("author"));
|
}
|
||||||
ui.editor.save();
|
|
||||||
|
|
||||||
FloatingDialog dialog = new FloatingDialog("$confirm");
|
showPublish(id -> update(p, id, null));
|
||||||
dialog.setFillParent(false);
|
|
||||||
dialog.cont.add("$map.publish.confirm").width(600f).wrap();
|
|
||||||
dialog.addCloseButton();
|
|
||||||
dialog.buttons.addImageTextButton("$eula", Icon.linkSmall, () -> {
|
|
||||||
SVars.net.friends.activateGameOverlayToWebPage("https://steamcommunity.com/sharedfiles/workshoplegalagreement");
|
|
||||||
}).size(210f, 64f);
|
|
||||||
|
|
||||||
dialog.buttons.addImageTextButton("$ok", Icon.checkSmall, () -> {
|
|
||||||
this.lastMap = map;
|
|
||||||
ugc.createItem(SVars.steamID, WorkshopFileType.Community);
|
|
||||||
ui.loadfrag.show("$map.publishing");
|
|
||||||
Log.info("Publish map " + map.name());
|
|
||||||
dialog.hide();
|
|
||||||
}).size(170f, 64f);
|
|
||||||
dialog.show();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void viewMapListingInfo(Map map){
|
/** Update an existing item with a changelog. */
|
||||||
String id = map.tags.get("steamid");
|
public void updateItem(Publishable p, String changelog){
|
||||||
|
String id = p.getSteamID();
|
||||||
long handle = Strings.parseLong(id, -1);
|
long handle = Strings.parseLong(id, -1);
|
||||||
SteamPublishedFileID fid = new SteamPublishedFileID(handle);
|
SteamPublishedFileID fid = new SteamPublishedFileID(handle);
|
||||||
|
update(p, fid, changelog);
|
||||||
|
}
|
||||||
|
|
||||||
Log.info("Requesting map listing view; id = " + id);
|
/** Fetches info for an item, checking to make sure that it exists.*/
|
||||||
|
public void viewListing(Publishable p){
|
||||||
|
long handle = Strings.parseLong(p.getSteamID(), -1);
|
||||||
|
SteamPublishedFileID id = new SteamPublishedFileID(handle);
|
||||||
|
|
||||||
ui.loadfrag.show();
|
ui.loadfrag.show();
|
||||||
SteamUGCQuery query = ugc.createQueryUGCDetailsRequest(fid);
|
query(ugc.createQueryUGCDetailsRequest(id), (detailsList, result) -> {
|
||||||
Log.info("POST " + query);
|
|
||||||
|
|
||||||
detailHandlers.put(query, (detailsList, result) -> {
|
|
||||||
ui.loadfrag.hide();
|
ui.loadfrag.hide();
|
||||||
|
|
||||||
Log.info("Map listing result: " + result + " " + detailsList);
|
|
||||||
|
|
||||||
if(result == SteamResult.OK){
|
if(result == SteamResult.OK){
|
||||||
SteamUGCDetails details = detailsList.first();
|
SteamUGCDetails details = detailsList.first();
|
||||||
if(details.getResult() == SteamResult.OK){
|
if(details.getResult() == SteamResult.OK){
|
||||||
@@ -112,54 +98,114 @@ public class SWorkshop implements SteamUGCCallback{
|
|||||||
dialog.addCloseButton();
|
dialog.addCloseButton();
|
||||||
|
|
||||||
dialog.buttons.addImageTextButton("$view.workshop", Icon.linkSmall, () -> {
|
dialog.buttons.addImageTextButton("$view.workshop", Icon.linkSmall, () -> {
|
||||||
platform.viewListing(id);
|
viewListingID(id);
|
||||||
dialog.hide();
|
dialog.hide();
|
||||||
}).size(210f, 64f);
|
}).size(210f, 64f);
|
||||||
|
|
||||||
dialog.buttons.addImageTextButton("$map.update", Icon.upgradeSmall, () -> {
|
dialog.buttons.addImageTextButton("$workshop.update", Icon.upgradeSmall, () -> {
|
||||||
new FloatingDialog("$map.update"){{
|
new FloatingDialog("$workshop.update"){{
|
||||||
setFillParent(false);
|
setFillParent(false);
|
||||||
cont.margin(10).add("$map.changelog").padRight(6f);
|
cont.margin(10).add("$changelog").padRight(6f);
|
||||||
cont.row();
|
cont.row();
|
||||||
TextArea field = cont.addArea("", t -> {}).size(500f, 160f).get();
|
TextArea field = cont.addArea("", t -> {}).size(500f, 160f).get();
|
||||||
field.setMaxLength(400);
|
field.setMaxLength(400);
|
||||||
buttons.defaults().size(120, 54).pad(4);
|
buttons.defaults().size(120, 54).pad(4);
|
||||||
buttons.addButton("$ok", () -> {
|
buttons.addButton("$ok", () -> {
|
||||||
ui.loadfrag.show("$map.publishing");
|
ui.loadfrag.show("$publishing");
|
||||||
lastMap = map;
|
updateItem(p, field.getText().replace("\r", "\n"));
|
||||||
updateMap(map, details.getPublishedFileID(), field.getText().replace("\r", "\n"));
|
|
||||||
dialog.hide();
|
dialog.hide();
|
||||||
hide();
|
hide();
|
||||||
|
|
||||||
Log.info("Update map " + map.name());
|
|
||||||
});
|
});
|
||||||
buttons.addButton("$cancel", this::hide);
|
buttons.addButton("$cancel", this::hide);
|
||||||
}}.show();
|
}}.show();
|
||||||
|
|
||||||
}).size(210f, 64f);
|
}).size(210f, 64f);
|
||||||
dialog.show();
|
dialog.show();
|
||||||
|
|
||||||
}else{
|
}else{
|
||||||
SVars.net.friends.activateGameOverlayToWebPage("steam://url/CommunityFilePage/" + SteamNativeHandle.getNativeHandle(details.getPublishedFileID()));
|
SVars.net.friends.activateGameOverlayToWebPage("steam://url/CommunityFilePage/" + SteamNativeHandle.getNativeHandle(details.getPublishedFileID()));
|
||||||
}
|
}
|
||||||
}else if(details.getResult() == SteamResult.FileNotFound){
|
}else if(details.getResult() == SteamResult.FileNotFound){
|
||||||
//force-remove tags
|
p.removeSteamID();
|
||||||
ui.editor.editor.getTags().remove("steamid");
|
ui.showErrorMessage("$missing");
|
||||||
map.tags.remove("steamid");
|
|
||||||
ui.editor.save();
|
|
||||||
|
|
||||||
ui.showErrorMessage("$map.missing");
|
|
||||||
}else{
|
}else{
|
||||||
ui.showErrorMessage(Core.bundle.format("map.load.error", result.name()));
|
ui.showErrorMessage(Core.bundle.format("workshop.error", result.name()));
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
ui.showErrorMessage(Core.bundle.format("map.load.error", result.name()));
|
ui.showErrorMessage(Core.bundle.format("workshop.error", result.name()));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void viewListingID(SteamPublishedFileID id){
|
||||||
|
SVars.net.friends.activateGameOverlayToWebPage("steam://url/CommunityFilePage/" + SteamNativeHandle.getNativeHandle(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
void update(Publishable p, SteamPublishedFileID id, String changelog){
|
||||||
|
String sid = SteamNativeHandle.getNativeHandle(id) + "";
|
||||||
|
|
||||||
|
updateItem(id, h -> {
|
||||||
|
if(p.steamDescription() != null){
|
||||||
|
ugc.setItemDescription(h, p.steamDescription());
|
||||||
|
}
|
||||||
|
|
||||||
|
Array<String> tags = p.extraTags();
|
||||||
|
tags.add(p.steamTag());
|
||||||
|
|
||||||
|
ugc.setItemTitle(h, p.steamTitle());
|
||||||
|
ugc.setItemTags(h, tags.toArray(String.class));
|
||||||
|
ugc.setItemPreview(h, p.createSteamPreview(sid).absolutePath());
|
||||||
|
ugc.setItemContent(h, p.createSteamFolder(sid).absolutePath());
|
||||||
|
if(changelog == null){
|
||||||
|
ugc.setItemVisibility(h, PublishedFileVisibility.Private);
|
||||||
|
}
|
||||||
|
ugc.submitItemUpdate(h, changelog == null ? "<Created>" : changelog);
|
||||||
|
}, () -> p.addSteamID(sid));
|
||||||
|
}
|
||||||
|
|
||||||
|
void showPublish(Consumer<SteamPublishedFileID> published){
|
||||||
|
FloatingDialog dialog = new FloatingDialog("$confirm");
|
||||||
|
dialog.setFillParent(false);
|
||||||
|
dialog.cont.add("$publish.confirm").width(600f).wrap();
|
||||||
|
dialog.addCloseButton();
|
||||||
|
dialog.buttons.addImageTextButton("$eula", Icon.linkSmall,
|
||||||
|
() -> SVars.net.friends.activateGameOverlayToWebPage("https://steamcommunity.com/sharedfiles/workshoplegalagreement"))
|
||||||
|
.size(210f, 64f);
|
||||||
|
|
||||||
|
dialog.buttons.addImageTextButton("$ok", Icon.checkSmall, () -> {
|
||||||
|
ugc.createItem(SVars.steamID, WorkshopFileType.Community);
|
||||||
|
ui.loadfrag.show("$publishing");
|
||||||
|
dialog.hide();
|
||||||
|
itemHandlers.add(published);
|
||||||
|
}).size(170f, 64f);
|
||||||
|
dialog.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
void query(SteamUGCQuery query, BiConsumer<Array<SteamUGCDetails>, SteamResult> handler){
|
||||||
|
Log.info("POST QUERY " + query);
|
||||||
|
detailHandlers.put(query, handler);
|
||||||
ugc.sendQueryUGCRequest(query);
|
ugc.sendQueryUGCRequest(query);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void updateItem(SteamPublishedFileID publishedFileID, Consumer<SteamUGCUpdateHandle> tagger, Runnable updated){
|
||||||
|
SteamUGCUpdateHandle h = ugc.startItemUpdate(SVars.steamID, publishedFileID);
|
||||||
|
|
||||||
|
tagger.accept(h);
|
||||||
|
|
||||||
|
ItemUpdateInfo info = new ItemUpdateInfo();
|
||||||
|
|
||||||
|
ui.loadfrag.setProgress(() -> {
|
||||||
|
ItemUpdateStatus status = ugc.getItemUpdateProgress(h, info);
|
||||||
|
ui.loadfrag.setText("$" + status.name().toLowerCase());
|
||||||
|
if(status == ItemUpdateStatus.Invalid){
|
||||||
|
ui.loadfrag.setText("$done");
|
||||||
|
return 1f;
|
||||||
|
}
|
||||||
|
return (float)status.ordinal() / (float)ItemUpdateStatus.values().length;
|
||||||
|
});
|
||||||
|
|
||||||
|
updatedHandlers.put(publishedFileID, updated);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onRequestUGCDetails(SteamUGCDetails details, SteamResult result){
|
public void onRequestUGCDetails(SteamUGCDetails details, SteamResult result){
|
||||||
|
|
||||||
@@ -167,7 +213,7 @@ public class SWorkshop implements SteamUGCCallback{
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onUGCQueryCompleted(SteamUGCQuery query, int numResultsReturned, int totalMatchingResults, boolean isCachedData, SteamResult result){
|
public void onUGCQueryCompleted(SteamUGCQuery query, int numResultsReturned, int totalMatchingResults, boolean isCachedData, SteamResult result){
|
||||||
Log.info("GET " + query);
|
Log.info("GET QUERY " + query);
|
||||||
|
|
||||||
if(detailHandlers.containsKey(query)){
|
if(detailHandlers.containsKey(query)){
|
||||||
if(numResultsReturned > 0){
|
if(numResultsReturned > 0){
|
||||||
@@ -202,55 +248,15 @@ public class SWorkshop implements SteamUGCCallback{
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreateItem(SteamPublishedFileID publishedFileID, boolean needsToAcceptWLA, SteamResult result){
|
public void onCreateItem(SteamPublishedFileID publishedFileID, boolean needsToAcceptWLA, SteamResult result){
|
||||||
if(lastMap == null){
|
if(!itemHandlers.isEmpty()){
|
||||||
Log.err("No map to publish?");
|
if(result == SteamResult.OK){
|
||||||
return;
|
itemHandlers.first().accept(publishedFileID);
|
||||||
}
|
}else{
|
||||||
|
ui.showErrorMessage(Core.bundle.format("publish.error ", result.name()));
|
||||||
//SVars.net.friends.activateGameOverlayToWebPage("steam://url/CommunityFilePage/" + publishedFileID.toString());
|
|
||||||
|
|
||||||
Map map = lastMap;
|
|
||||||
Log.info("Create item {0} result {1} {2}", SteamNativeHandle.getNativeHandle(publishedFileID), result, needsToAcceptWLA);
|
|
||||||
|
|
||||||
if(result == SteamResult.OK){
|
|
||||||
updateMap(map, publishedFileID, "<Map Created>");
|
|
||||||
}else{
|
|
||||||
ui.showErrorMessage(Core.bundle.format("map.publish.error ", result.name()));
|
|
||||||
}
|
|
||||||
|
|
||||||
lastMap = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
void updateMap(Map map, SteamPublishedFileID publishedFileID, String changelog){
|
|
||||||
SteamUGCUpdateHandle h = ugc.startItemUpdate(SVars.steamID, publishedFileID);
|
|
||||||
|
|
||||||
Gamemode mode = Gamemode.attack.valid(map) ? Gamemode.attack : Gamemode.survival;
|
|
||||||
FileHandle mapFile = tmpDirectory.child("map_" + publishedFileID.toString()).child("map.msav");
|
|
||||||
lastMap.file.copyTo(mapFile);
|
|
||||||
|
|
||||||
Log.info(mapFile.parent().absolutePath());
|
|
||||||
Log.info(map.previewFile().absolutePath());
|
|
||||||
|
|
||||||
ugc.setItemTitle(h, map.name());
|
|
||||||
ugc.setItemDescription(h, map.description());
|
|
||||||
ugc.setItemTags(h, new String[]{"map", mode.name()});
|
|
||||||
ugc.setItemVisibility(h, PublishedFileVisibility.Private);
|
|
||||||
ugc.setItemPreview(h, map.previewFile().absolutePath());
|
|
||||||
ugc.setItemContent(h, mapFile.parent().absolutePath());
|
|
||||||
ugc.addItemKeyValueTag(h, "mode", mode.name());
|
|
||||||
ugc.submitItemUpdate(h, changelog);
|
|
||||||
|
|
||||||
ItemUpdateInfo info = new ItemUpdateInfo();
|
|
||||||
|
|
||||||
ui.loadfrag.setProgress(() -> {
|
|
||||||
ItemUpdateStatus status = ugc.getItemUpdateProgress(h, info);
|
|
||||||
ui.loadfrag.setText("$" + status.name().toLowerCase());
|
|
||||||
if(status == ItemUpdateStatus.Invalid){
|
|
||||||
ui.loadfrag.setText("$done");
|
|
||||||
return 1f;
|
|
||||||
}
|
}
|
||||||
return (float)status.ordinal() / (float)ItemUpdateStatus.values().length;
|
|
||||||
});
|
itemHandlers.remove(0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -263,15 +269,12 @@ public class SWorkshop implements SteamUGCCallback{
|
|||||||
if(needsToAcceptWLA){
|
if(needsToAcceptWLA){
|
||||||
SVars.net.friends.activateGameOverlayToWebPage("https://steamcommunity.com/sharedfiles/workshoplegalagreement");
|
SVars.net.friends.activateGameOverlayToWebPage("https://steamcommunity.com/sharedfiles/workshoplegalagreement");
|
||||||
}
|
}
|
||||||
ui.editor.editor.getTags().put("steamid", SteamNativeHandle.getNativeHandle(publishedFileID) + "");
|
|
||||||
try{
|
if(updatedHandlers.containsKey(publishedFileID)){
|
||||||
ui.editor.save();
|
updatedHandlers.get(publishedFileID).run();
|
||||||
}catch(Exception e){
|
|
||||||
Log.err(e);
|
|
||||||
}
|
}
|
||||||
Events.fire(new MapPublishEvent());
|
|
||||||
}else{
|
}else{
|
||||||
ui.showErrorMessage(Core.bundle.format("map.publish.error ", result.name()));
|
ui.showErrorMessage(Core.bundle.format("publish.error ", result.name()));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
org.gradle.daemon=true
|
org.gradle.daemon=true
|
||||||
org.gradle.jvmargs=-Xms256m -Xmx1024m
|
org.gradle.jvmargs=-Xms256m -Xmx1024m
|
||||||
archash=983942d521c1e1714fac3ddfc54ee7248734b2ed
|
archash=e82f446a81abba5d6f712b9053c1b84ec9a73156
|
||||||
|
|||||||
Reference in New Issue
Block a user