Added Mac and Windows32 support, better placing, bundle crashfixes

This commit is contained in:
Anuken 2017-12-28 15:26:11 -05:00
parent b25c611c33
commit 6774ea67ce
14 changed files with 200 additions and 44 deletions

View File

@ -323,7 +323,7 @@ block.junction.name=junction
block.junction.fulldescription=Acts as a bridge for two crossing conveyor belts. Useful in situations with two different conveyors carrying different materials to different locations. block.junction.fulldescription=Acts as a bridge for two crossing conveyor belts. Useful in situations with two different conveyors carrying different materials to different locations.
block.junction.description=Serves as a conveyor junction. block.junction.description=Serves as a conveyor junction.
block.conveyortunnel.name=conveyor tunnel block.conveyortunnel.name=conveyor tunnel
block.conveyortunnel.fulldescription=Transports item under blocks. To use, place one tunnel leading into the block to be tunneled under, and one on the other side. block.conveyortunnel.fulldescription=Transports item under blocks. To use, place one tunnel leading into the block to be tunneled under, and one on the other side. Make sure both tunnels face opposite directions, which is towards the blocks they are inputting or outputting to.
block.conveyortunnel.description=Transports items under blocks. block.conveyortunnel.description=Transports items under blocks.
block.liquidjunction.name=liquid junction block.liquidjunction.name=liquid junction
block.liquidjunction.fulldescription=Acts as a bridge for two crossing conduits. Useful in situations with two different conduits carrying different liquids to different locations. block.liquidjunction.fulldescription=Acts as a bridge for two crossing conduits. Useful in situations with two different conduits carrying different liquids to different locations.

Binary file not shown.

View File

@ -4,7 +4,7 @@
<source path="io/anuke/mindustry" /> <source path="io/anuke/mindustry" />
<extend-configuration-property name="gdx.reflect.include" value="io.anuke.mindustry.entities.enemies" /> <extend-configuration-property name="gdx.reflect.include" value="io.anuke.mindustry.entities.enemies" />
<extend-configuration-property name="gdx.reflect.include" value="io.anuke.mindustry.world.Tile" /> <extend-configuration-property name="gdx.reflect.include" value="io.anuke.mindustry.world.Tile" />
<extend-configuration-property name="gdx.reflect.include" value="io.anuke.mindustry.world.Maps" /> <extend-configuration-property name="gdx.reflect.include" value="io.anuke.mindustry.io.Maps" />
<extend-configuration-property name="gdx.reflect.include" value="io.anuke.mindustry.world.Map" /> <extend-configuration-property name="gdx.reflect.include" value="io.anuke.mindustry.world.Map" />
<extend-configuration-property name="gdx.reflect.include" value="io.anuke.mindustry.entities.EnemySpawn" /> <extend-configuration-property name="gdx.reflect.include" value="io.anuke.mindustry.entities.EnemySpawn" />
</module> </module>

View File

@ -10,7 +10,7 @@ import io.anuke.mindustry.entities.Player;
import io.anuke.ucore.scene.ui.layout.Unit; import io.anuke.ucore.scene.ui.layout.Unit;
public class Vars{ public class Vars{
public static final boolean testAndroid = true; public static final boolean testAndroid = false;
//shorthand for whether or not this is running on android //shorthand for whether or not this is running on android
public static final boolean android = (Gdx.app.getType() == ApplicationType.Android) || testAndroid; public static final boolean android = (Gdx.app.getType() == ApplicationType.Android) || testAndroid;
//shorthand for whether or not this is running on GWT //shorthand for whether or not this is running on GWT

View File

@ -20,6 +20,7 @@ import io.anuke.mindustry.entities.enemies.Enemy;
import io.anuke.mindustry.graphics.BlockRenderer; import io.anuke.mindustry.graphics.BlockRenderer;
import io.anuke.mindustry.graphics.Shaders; import io.anuke.mindustry.graphics.Shaders;
import io.anuke.mindustry.input.PlaceMode; import io.anuke.mindustry.input.PlaceMode;
import io.anuke.mindustry.ui.fragments.ToolFragment;
import io.anuke.mindustry.world.SpawnPoint; import io.anuke.mindustry.world.SpawnPoint;
import io.anuke.mindustry.world.Tile; import io.anuke.mindustry.world.Tile;
import io.anuke.mindustry.world.blocks.Blocks; import io.anuke.mindustry.world.blocks.Blocks;
@ -384,6 +385,11 @@ public class Renderer extends RendererModule{
player.breakMode.draw(control.input.getBlockX(), control.input.getBlockY(), player.breakMode.draw(control.input.getBlockX(), control.input.getBlockY(),
control.input.getBlockEndX(), control.input.getBlockEndY()); control.input.getBlockEndX(), control.input.getBlockEndY());
} }
if(Vars.ui.getTools().confirming){
ToolFragment t = Vars.ui.getTools();
PlaceMode.areaDelete.draw(t.px, t.py, t.px2, t.py2);
}
Draw.reset(); Draw.reset();

View File

@ -45,6 +45,8 @@ import io.anuke.ucore.scene.ui.layout.Table;
import io.anuke.ucore.scene.ui.layout.Unit; import io.anuke.ucore.scene.ui.layout.Unit;
import io.anuke.ucore.util.Bundles; import io.anuke.ucore.util.Bundles;
import javax.tools.Tool;
public class UI extends SceneModule{ public class UI extends SceneModule{
Table loadingtable, desctable, configtable; Table loadingtable, desctable, configtable;
MindustrySettingsDialog prefs; MindustrySettingsDialog prefs;
@ -460,6 +462,10 @@ public class UI extends SceneModule{
public MapEditorDialog getEditorDialog(){ public MapEditorDialog getEditorDialog(){
return editorDialog; return editorDialog;
} }
public ToolFragment getTools(){
return (ToolFragment)toolfrag;
}
public MapEditor getEditor(){ public MapEditor getEditor(){
return editor; return editor;

View File

@ -11,6 +11,7 @@ import io.anuke.mindustry.Vars;
import io.anuke.mindustry.ai.Pathfind; import io.anuke.mindustry.ai.Pathfind;
import io.anuke.mindustry.core.GameState.State; import io.anuke.mindustry.core.GameState.State;
import io.anuke.mindustry.entities.TileEntity; import io.anuke.mindustry.entities.TileEntity;
import io.anuke.mindustry.io.Maps;
import io.anuke.mindustry.world.*; import io.anuke.mindustry.world.*;
import io.anuke.mindustry.world.blocks.*; import io.anuke.mindustry.world.blocks.*;
import io.anuke.ucore.entities.Entities; import io.anuke.ucore.entities.Entities;
@ -26,7 +27,7 @@ public class World extends Module{
private Tile[][] tiles; private Tile[][] tiles;
private Tile[] temptiles = new Tile[4]; private Tile[] temptiles = new Tile[4];
private Pathfind pathfind = new Pathfind(); private Pathfind pathfind = new Pathfind();
private Maps maps = new Maps(); private io.anuke.mindustry.io.Maps maps = new io.anuke.mindustry.io.Maps();
public World(){ public World(){
maps.loadMaps(); maps.loadMaps();

View File

@ -10,6 +10,7 @@ import com.badlogic.gdx.math.MathUtils;
import com.badlogic.gdx.math.Vector2; import com.badlogic.gdx.math.Vector2;
import io.anuke.mindustry.Vars; import io.anuke.mindustry.Vars;
import io.anuke.mindustry.ui.fragments.ToolFragment;
import io.anuke.mindustry.world.Block; import io.anuke.mindustry.world.Block;
import io.anuke.mindustry.world.Tile; import io.anuke.mindustry.world.Tile;
import io.anuke.ucore.core.Draw; import io.anuke.ucore.core.Draw;
@ -19,6 +20,8 @@ import io.anuke.ucore.scene.utils.Cursors;
import io.anuke.ucore.util.Mathf; import io.anuke.ucore.util.Mathf;
import io.anuke.ucore.util.Tmp; import io.anuke.ucore.util.Tmp;
import javax.tools.Tool;
public enum PlaceMode{ public enum PlaceMode{
cursor{ cursor{
{ {
@ -77,12 +80,14 @@ public enum PlaceMode{
{ {
delete = true; delete = true;
shown = true; shown = true;
both = true;
} }
}, },
holdDelete{ holdDelete{
{ {
delete = true; delete = true;
shown = true; shown = true;
both = true;
} }
public void draw(int tilex, int tiley, int endx, int endy){ public void draw(int tilex, int tiley, int endx, int endy){
@ -175,9 +180,22 @@ public enum PlaceMode{
} }
public void released(int tilex, int tiley, int endx, int endy){ public void released(int tilex, int tiley, int endx, int endy){
process(tilex, tiley, endx, endy); process(tilex, tiley, endx, endy);
tilex = this.tilex; tiley = this.tiley; tilex = this.tilex; tiley = this.tiley;
endx = this.endx; endy = this.endy; endx = this.endx; endy = this.endy;
if(Vars.android){
ToolFragment t = Vars.ui.getTools();
if(!t.confirming || t.px != tilex || t.py != tiley || t.px2 != endx || t.py2 != endy) {
t.confirming = true;
t.px = tilex;
t.py = tiley;
t.px2 = endx;
t.py2 = endy;
return;
}
}
boolean first = true; boolean first = true;
@ -365,6 +383,7 @@ public enum PlaceMode{
public boolean showRotate; public boolean showRotate;
public boolean showCancel; public boolean showCancel;
public boolean delete = false; public boolean delete = false;
public boolean both = false;
public void draw(int tilex, int tiley, int endx, int endy){ public void draw(int tilex, int tiley, int endx, int endy){

View File

@ -1,4 +1,4 @@
package io.anuke.mindustry.world; package io.anuke.mindustry.io;
import com.badlogic.gdx.Gdx; import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.files.FileHandle; import com.badlogic.gdx.files.FileHandle;
@ -10,6 +10,7 @@ import com.badlogic.gdx.utils.Json.Serializer;
import com.badlogic.gdx.utils.JsonWriter.OutputType; import com.badlogic.gdx.utils.JsonWriter.OutputType;
import io.anuke.mindustry.Vars; import io.anuke.mindustry.Vars;
import io.anuke.mindustry.world.Map;
import io.anuke.ucore.core.Settings; import io.anuke.ucore.core.Settings;
import io.anuke.ucore.graphics.Pixmaps; import io.anuke.ucore.graphics.Pixmaps;

View File

@ -0,0 +1,10 @@
package io.anuke.mindustry.io;
import com.badlogic.gdx.utils.IntArray;
import java.lang.reflect.Array;
public class Saves {
private int lastSlot;
private IntArray saves;
}

View File

@ -9,6 +9,7 @@ import com.badlogic.gdx.utils.Align;
import io.anuke.mindustry.core.GameState; import io.anuke.mindustry.core.GameState;
import io.anuke.mindustry.core.GameState.State; import io.anuke.mindustry.core.GameState.State;
import io.anuke.mindustry.input.PlaceMode; import io.anuke.mindustry.input.PlaceMode;
import io.anuke.ucore.core.Core;
import io.anuke.ucore.core.Timers; import io.anuke.ucore.core.Timers;
import io.anuke.ucore.scene.actions.Actions; import io.anuke.ucore.scene.actions.Actions;
import io.anuke.ucore.scene.builders.*; import io.anuke.ucore.scene.builders.*;
@ -18,13 +19,14 @@ import io.anuke.ucore.scene.ui.ImageButton;
import io.anuke.ucore.scene.ui.layout.Table; import io.anuke.ucore.scene.ui.layout.Table;
import io.anuke.ucore.util.Mathf; import io.anuke.ucore.util.Mathf;
import javax.xml.soap.Text;
public class PlacementFragment implements Fragment{ public class PlacementFragment implements Fragment{
boolean shown = false; boolean shown = false;
Table breaktable, next; Table breaktable, next;
public void build(){ public void build(){
if(android){ if(android){
//placement table
float s = 50f; float s = 50f;
@ -34,15 +36,46 @@ public class PlacementFragment implements Fragment{
abottom(); abottom();
aleft(); aleft();
ButtonGroup<ImageButton> group = new ButtonGroup<>(); ButtonGroup<ImageButton> placeGroup = new ButtonGroup<>();
ButtonGroup<ImageButton> breakGroup = new ButtonGroup<>();
update(t -> {
if(!player.placeMode.delete){
placeGroup.setMinCheckCount(1);
for(ImageButton button : placeGroup.getButtons()){
if(button.getName().equals(player.placeMode.name())){
button.setChecked(true);
break;
}
}
}else{
placeGroup.setMinCheckCount(0);
for(ImageButton button : placeGroup.getButtons())
button.setChecked(false);
}
if(player.placeMode.delete || player.breakMode.both){
PlaceMode mode = player.breakMode;
breakGroup.setMinCheckCount(1);
for(ImageButton button : breakGroup.getButtons()){
if(button.getName().equals(mode.name())){
button.setChecked(true);
break;
}
}
}else{
breakGroup.setMinCheckCount(0);
for(ImageButton button : breakGroup.getButtons())
button.setChecked(false);
}
});
new table(){{ new table(){{
visible(() -> player.recipe != null); visible(() -> player.recipe != null);
touchable(Touchable.enabled); touchable(Touchable.enabled);
aleft(); aleft();
new label("$text.placemode");
row();
new table("pane"){{ new table("pane"){{
margin(5f); margin(5f);
@ -63,7 +96,7 @@ public class PlacementFragment implements Fragment{
new imagebutton("icon-" + mode.name(), "toggle", 10*3, ()->{ new imagebutton("icon-" + mode.name(), "toggle", 10*3, ()->{
control.getInput().resetCursor(); control.getInput().resetCursor();
player.placeMode = mode; player.placeMode = mode;
}).group(group); }).group(placeGroup).get().setName(mode.name());
} }
new imagebutton("icon-arrow", 14*3, ()->{ new imagebutton("icon-arrow", 14*3, ()->{
@ -90,19 +123,8 @@ public class PlacementFragment implements Fragment{
defaults().padBottom(-5.5f); defaults().padBottom(-5.5f);
new imagebutton("icon-arrow-right", 10 * 3, () -> { new imagebutton("icon-arrow-right", 10 * 3, () -> {
float dur = 0.3f; toggle(!shown);
Interpolation in = Interpolation.pow3Out; }).update(l -> l.getStyle().imageUp = Core.skin.getDrawable(shown ? "icon-arrow-left" : "icon-" + player.breakMode.name())).size(s, s+4);
if(breaktable.getActions().size != 0) return;
breaktable.getParent().swapActor(breaktable, next);
if(shown){
breaktable.actions(Actions.translateBy(-breaktable.getWidth() - 5, 0, dur, in), Actions.call(() -> shown = false));
}else{
shown = true;
breaktable.actions(Actions.translateBy(-breaktable.getTranslation().x - 5, 0, dur, in));
}
}).size(s, s+4);
}}.end().get(); }}.end().get();
@ -123,8 +145,8 @@ public class PlacementFragment implements Fragment{
new imagebutton("icon-" + mode.name(), "toggle", 10*3, ()->{ new imagebutton("icon-" + mode.name(), "toggle", 10*3, ()->{
control.getInput().resetCursor(); control.getInput().resetCursor();
player.breakMode = mode; player.breakMode = mode;
player.placeMode = mode; if(!mode.both) player.placeMode = mode;
}).group(group); }).group(breakGroup).get().setName(mode.name());
} }
}}.end().get(); }}.end().get();
@ -135,9 +157,23 @@ public class PlacementFragment implements Fragment{
}}.end().get(); }}.end().get();
//one.getParent().swapActor(one, two);
}}.end(); }}.end();
} }
} }
private void toggle(boolean show){
float dur = 0.3f;
Interpolation in = Interpolation.pow3Out;
if(breaktable.getActions().size != 0 || shown == show) return;
breaktable.getParent().swapActor(breaktable, next);
if(!show){
breaktable.actions(Actions.translateBy(-breaktable.getWidth() - 5, 0, dur, in), Actions.call(() -> shown = false));
}else{
shown = true;
breaktable.actions(Actions.translateBy(-breaktable.getTranslation().x - 5, 0, dur, in));
}
}
} }

View File

@ -3,44 +3,69 @@ package io.anuke.mindustry.ui.fragments;
import static io.anuke.mindustry.Vars.*; import static io.anuke.mindustry.Vars.*;
import com.badlogic.gdx.Gdx; import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.utils.Align; import com.badlogic.gdx.utils.Align;
import io.anuke.mindustry.Vars;
import io.anuke.mindustry.core.GameState; import io.anuke.mindustry.core.GameState;
import io.anuke.mindustry.core.GameState.State; import io.anuke.mindustry.core.GameState.State;
import io.anuke.mindustry.input.PlaceMode; import io.anuke.mindustry.input.PlaceMode;
import io.anuke.ucore.core.Core; import io.anuke.ucore.core.Core;
import io.anuke.ucore.core.Graphics;
import io.anuke.ucore.scene.ui.layout.Table; import io.anuke.ucore.scene.ui.layout.Table;
public class ToolFragment implements Fragment{ public class ToolFragment implements Fragment{
private Table tools; private Table tools;
public int px, py, px2, py2;
public boolean confirming;
public void build(){ public void build(){
float isize = 14*3; float isize = 14*3;
tools = new Table(); tools = new Table();
tools.addIButton("icon-cancel", isize, ()->{ tools.addIButton("icon-cancel", isize, () -> {
player.recipe = null; if(player.placeMode == PlaceMode.areaDelete && confirming){
confirming = false;
}else{
player.recipe = null;
}
}); });
tools.addIButton("icon-rotate", isize, ()->{ tools.addIButton("icon-rotate", isize, () -> {
player.rotation ++; player.rotation ++;
player.rotation %= 4; player.rotation %= 4;
}); });
tools.addIButton("icon-check", isize, ()->{ tools.addIButton("icon-check", isize, () -> {
player.placeMode.tapped(control.getInput().getBlockX(), control.getInput().getBlockY()); if(player.placeMode == PlaceMode.areaDelete && confirming){
player.placeMode.released(px, py, px2, py2);
confirming = false;
}else{
player.placeMode.tapped(control.getInput().getBlockX(), control.getInput().getBlockY());
}
}); });
Core.scene.add(tools); Core.scene.add(tools);
tools.setVisible(()-> tools.setVisible(() ->
!GameState.is(State.menu) && android && player.recipe != null && control.hasItems(player.recipe.requirements) && !GameState.is(State.menu) && android && ((player.recipe != null && control.hasItems(player.recipe.requirements) &&
player.placeMode == PlaceMode.cursor player.placeMode == PlaceMode.cursor) || confirming)
); );
tools.update(()->{ tools.update(() -> {
tools.setPosition(control.getInput().getCursorX(), Gdx.graphics.getHeight() - control.getInput().getCursorY() - 15*Core.cameraScale, Align.top); if(confirming){
Vector2 v = Graphics.screen((px + px2)/2f * Vars.tilesize, Math.min(py, py2) * Vars.tilesize - Vars.tilesize*1.5f);
tools.setPosition(v.x, v.y, Align.top);
}else{
tools.setPosition(control.getInput().getCursorX(),
Gdx.graphics.getHeight() - control.getInput().getCursorY() - 15*Core.cameraScale, Align.top);
}
if(player.placeMode != PlaceMode.areaDelete){
confirming = false;
}
}); });
} }
} }

View File

@ -23,7 +23,7 @@ public class TunnelConveyor extends Block{
@Override @Override
public void handleItem(Item item, Tile tile, Tile source){ public void handleItem(Item item, Tile tile, Tile source){
Tile tunnel = getDestTunnel(tile); Tile tunnel = getDestTunnel(tile, item);
if(tunnel == null) return; //TODO how is this possible? HOW DID THEY ACHIEVE SUCH A FEAT?! if(tunnel == null) return; //TODO how is this possible? HOW DID THEY ACHIEVE SUCH A FEAT?!
Tile to = tunnel.getNearby()[tunnel.getRotation()]; Tile to = tunnel.getNearby()[tunnel.getRotation()];
@ -37,7 +37,8 @@ public class TunnelConveyor extends Block{
public boolean acceptItem(Item item, Tile dest, Tile source){ public boolean acceptItem(Item item, Tile dest, Tile source){
int rot = source.relativeTo(dest.x, dest.y); int rot = source.relativeTo(dest.x, dest.y);
if(rot != (dest.getRotation() + 2)%4) return false; if(rot != (dest.getRotation() + 2)%4) return false;
Tile tunnel = getDestTunnel(dest); Tile tunnel = getDestTunnel(dest, item);
if(tunnel != null){ if(tunnel != null){
Tile to = tunnel.getNearby()[tunnel.getRotation()]; Tile to = tunnel.getNearby()[tunnel.getRotation()];
return to != null && !(to.block() instanceof TunnelConveyor) && to.block().acceptItem(item, to, tunnel); return to != null && !(to.block() instanceof TunnelConveyor) && to.block().acceptItem(item, to, tunnel);
@ -46,12 +47,14 @@ public class TunnelConveyor extends Block{
} }
} }
Tile getDestTunnel(Tile tile){ Tile getDestTunnel(Tile tile, Item item){
Tile dest = tile; Tile dest = tile;
int rel = (tile.getRotation() + 2)%4; int rel = (tile.getRotation() + 2)%4;
for(int i = 0; i < maxdist; i ++){ for(int i = 0; i < maxdist; i ++){
dest = dest.getNearby()[rel]; dest = dest.getNearby()[rel];
if(dest != null && dest.block() instanceof TunnelConveyor && dest.getRotation() == rel){ if(dest != null && dest.block() instanceof TunnelConveyor && dest.getRotation() == rel
&& dest.getNearby()[rel] != null
&& dest.getNearby()[rel].block().acceptItem(item, dest.getNearby()[rel], dest)){
return dest; return dest;
} }
} }

View File

@ -7,6 +7,7 @@ project.ext.mainClassName = "io.anuke.mindustry.desktop.DesktopLauncher"
project.ext.assetsDir = new File("../core/assets"); project.ext.assetsDir = new File("../core/assets");
def PACKR_DIR = "/home/anuke/Documents/Packr/" def PACKR_DIR = "/home/anuke/Documents/Packr/"
def ICON_DIR = new File("core/assets/sprites/icon.icns")
task run(dependsOn: classes, type: JavaExec) { task run(dependsOn: classes, type: JavaExec) {
main = project.mainClassName main = project.mainClassName
@ -66,6 +67,10 @@ ext.getPlatform = {
} }
} }
ext.getPackage = {
return project.ext.mainClassName.substring(0, project.ext.mainClassName.indexOf("desktop") - 1)
}
//note: call desktop:dist beforehand //note: call desktop:dist beforehand
task packrCmd(type: Exec) { task packrCmd(type: Exec) {
@ -74,15 +79,59 @@ task packrCmd(type: Exec) {
from "build/libs/desktop-release.jar" from "build/libs/desktop-release.jar"
} }
commandLine "java", "-jar", PACKR_DIR+"packr.jar", "--verbose", /*"--resources", project.ext.assetsDir,*/ "--platform", getPlatform(), "--executable", appName, "--output", "packr-out/", "--mainclass", project.ext.mainClassName, "--jdk", PACKR_DIR+"jdk-"+getPlatform()+".zip", "--classpath", commandLine "java", "-jar", PACKR_DIR+"packr.jar",
"--", PACKR_DIR+"config.json" "--verbose",
"--bundle", getPackage(),
"--platform", getPlatform(),
"--executable", appName,
"--output", "packr-out/",
"--mainclass", project.ext.mainClassName,
"--jdk", PACKR_DIR+"jdk-"+getPlatform()+".zip",
"--icon", ICON_DIR.getAbsolutePath(),
"--classpath", "--", PACKR_DIR+"config.json"
} }
task fixMac (type: Copy){
dependsOn "packrCmd"
into "packr-out/" + appName + ".app/Contents/"
from "packr-out/Contents/"
doLast{
delete{
delete "packr-out/Contents/"
}
}
}
task fixWindows32 (type: Copy){
dependsOn "packrCmd"
into "packr-out/jre/bin/"
from PACKR_DIR + "zip.dll"
rename ("zip.dll", "ojdkbuild_zlib.dll")
doLast{
copy{
into "packr-out/jre/bin/"
from PACKR_DIR + "zip.dll"
}
}
}
task packrZip(type: Zip) { task packrZip(type: Zip) {
dependsOn "packrCmd" dependsOn "packrCmd"
finalizedBy "clearOut" finalizedBy "clearOut"
if(getPlatform().equals("mac")){
dependsOn "fixMac"
}
if(getPlatform().equals("windows32")){
dependsOn "fixWindows32"
}
from "packr-out/" from "packr-out/"
archiveName appName + "-" + getPlatform() + ".zip" archiveName appName + "-" + getPlatform() + ".zip"
destinationDir(file("packr-export")) destinationDir(file("packr-export"))