Compare commits
27 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a5cec84be1 | ||
|
|
a299c39d7b | ||
|
|
685c41ebf5 | ||
|
|
1ec09a4679 | ||
|
|
9e4e58baf9 | ||
|
|
bd5c98cc0d | ||
|
|
ef2817513a | ||
|
|
d28ae1b304 | ||
|
|
101f5351bd | ||
|
|
e103d62b75 | ||
|
|
d969741f90 | ||
|
|
8a1ea7fd19 | ||
|
|
34db321577 | ||
|
|
cc57f0b19b | ||
|
|
4e946ae52b | ||
|
|
236ed74cae | ||
|
|
cd07d3b13d | ||
|
|
b582c79593 | ||
|
|
df0d81db7c | ||
|
|
a628134a89 | ||
|
|
708acdfe95 | ||
|
|
f84a7e7661 | ||
|
|
5fde533bcc | ||
|
|
16e57f6f24 | ||
|
|
44dc250a2b | ||
|
|
742fb3dece | ||
|
|
bd0a6636e6 |
8
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@@ -3,10 +3,10 @@ name: Bug report
|
|||||||
about: Create a report to help fix an issue.
|
about: Create a report to help fix an issue.
|
||||||
---
|
---
|
||||||
|
|
||||||
**Platform**: (Android/iOS/Mac/Windows/Linux)
|
**Platform**: *Android/iOS/Mac/Windows/Linux*
|
||||||
|
|
||||||
**Build**: (The build number under the title in the main menu. Required.)
|
**Build**: *The build number under the title in the main menu. Required.*
|
||||||
|
|
||||||
**Issue**: (Explain your issue in detail.)
|
**Issue**: *Explain your issue in detail.*
|
||||||
|
|
||||||
**Steps to reproduce**: (How you happened across the issue, and what you were doing at the time.)
|
**Steps to reproduce**: *How you happened across the issue, and what you were doing at the time.*
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ script:
|
|||||||
- git clone --depth=1 --branch=master https://github.com/Anuken/MindustryBuilds ../MindustryBuilds
|
- git clone --depth=1 --branch=master https://github.com/Anuken/MindustryBuilds ../MindustryBuilds
|
||||||
- cd ../MindustryBuilds
|
- cd ../MindustryBuilds
|
||||||
- echo ${TRAVIS_TAG}
|
- echo ${TRAVIS_TAG}
|
||||||
- if [ -n "$TRAVIS_TAG" ]; then echo versionName=4-fdroid-${TRAVIS_TAG:1}$'\n'versionCode=${TRAVIS_TAG:1} > version_fdroid.txt; git add .; git commit -m "Updating to build ${TRAVIS_TAG}"; fi
|
- if [ -n "$TRAVIS_TAG" ]; then echo versionName=5-fdroid-${TRAVIS_TAG:1}$'\n'versionCode=${TRAVIS_TAG:1} > version_fdroid.txt; git add .; git commit -m "Updating to build ${TRAVIS_TAG}"; fi
|
||||||
- git tag ${TRAVIS_BUILD_NUMBER}
|
- git tag ${TRAVIS_BUILD_NUMBER}
|
||||||
- git config --global user.name "Build Uploader"
|
- git config --global user.name "Build Uploader"
|
||||||
- if [ "$TRAVIS_PULL_REQUEST" = "false" ]; then git push https://Anuken:${GH_PUSH_TOKEN}@github.com/Anuken/MindustryBuilds ${TRAVIS_BUILD_NUMBER}; git push https://Anuken:${GH_PUSH_TOKEN}@github.com/Anuken/MindustryBuilds; fi
|
- if [ "$TRAVIS_PULL_REQUEST" = "false" ]; then git push https://Anuken:${GH_PUSH_TOKEN}@github.com/Anuken/MindustryBuilds ${TRAVIS_BUILD_NUMBER}; git push https://Anuken:${GH_PUSH_TOKEN}@github.com/Anuken/MindustryBuilds; fi
|
||||||
|
|||||||
@@ -14,7 +14,6 @@
|
|||||||
android:roundIcon="@mipmap/ic_launcher_round"
|
android:roundIcon="@mipmap/ic_launcher_round"
|
||||||
android:isGame="true"
|
android:isGame="true"
|
||||||
android:appCategory="game"
|
android:appCategory="game"
|
||||||
android:usesCleartextTraffic="true"
|
|
||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
android:theme="@style/GdxTheme" android:fullBackupContent="@xml/backup_rules">
|
android:theme="@style/GdxTheme" android:fullBackupContent="@xml/backup_rules">
|
||||||
<meta-data android:name="android.max_aspect" android:value="2.1"/>
|
<meta-data android:name="android.max_aspect" android:value="2.1"/>
|
||||||
|
|||||||
BIN
core/assets-raw/sprites/blocks/walls/insulator-wall-large.png
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
BIN
core/assets-raw/sprites/blocks/walls/insulator-wall.png
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
core/assets-raw/sprites/blocks/walls/plastanium-wall-large.png
Normal file
|
After Width: | Height: | Size: 3.7 KiB |
BIN
core/assets-raw/sprites/blocks/walls/plastanium-wall.png
Normal file
|
After Width: | Height: | Size: 1.5 KiB |
BIN
core/assets-raw/sprites/ui/scroll-knob-vertical-thin.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
@@ -94,6 +94,8 @@ mods.report = Report Bug
|
|||||||
mod.enabled = [lightgray]Enabled
|
mod.enabled = [lightgray]Enabled
|
||||||
mod.disabled = [scarlet]Disabled
|
mod.disabled = [scarlet]Disabled
|
||||||
mod.disable = Disable
|
mod.disable = Disable
|
||||||
|
mod.missingdependencies = [scarlet]Missing dependencies: {0}
|
||||||
|
mod.nowdisabled = [scarlet]Mod '{0}' is missing dependencies:[accent] {1}\n[lightgray]These mods need to be downloaded first.\nThis mod will be automatically disabled.
|
||||||
mod.enable = Enable
|
mod.enable = Enable
|
||||||
mod.requiresrestart = The game will now close to apply the mod changes.
|
mod.requiresrestart = The game will now close to apply the mod changes.
|
||||||
mod.reloadrequired = [scarlet]Reload Required
|
mod.reloadrequired = [scarlet]Reload Required
|
||||||
@@ -230,7 +232,7 @@ data.export = Export Data
|
|||||||
data.import = Import Data
|
data.import = Import Data
|
||||||
data.exported = Data exported.
|
data.exported = Data exported.
|
||||||
data.invalid = This isn't valid game data.
|
data.invalid = This isn't valid game data.
|
||||||
data.import.confirm = Importing external data will erase[scarlet] all[] your current game data.\n[accent]This cannot be undone![]\n\nOnce the data is imported, your game will exit immediately.
|
data.import.confirm = Importing external data will overwrite[scarlet] all[] your current game data.\n[accent]This cannot be undone![]\n\nOnce the data is imported, your game will exit immediately.
|
||||||
classic.export = Export Classic Data
|
classic.export = Export Classic Data
|
||||||
classic.export.text = [accent]Mindustry[] has just had a major update.\nClassic (v3.5 build 40) save or map data has been detected. Would you like to export these saves to your phone's home folder, for use in the Mindustry Classic app?
|
classic.export.text = [accent]Mindustry[] has just had a major update.\nClassic (v3.5 build 40) save or map data has been detected. Would you like to export these saves to your phone's home folder, for use in the Mindustry Classic app?
|
||||||
quit.confirm = Are you sure you want to quit?
|
quit.confirm = Are you sure you want to quit?
|
||||||
@@ -853,6 +855,8 @@ block.copper-wall.name = Copper Wall
|
|||||||
block.copper-wall-large.name = Large Copper Wall
|
block.copper-wall-large.name = Large Copper Wall
|
||||||
block.titanium-wall.name = Titanium Wall
|
block.titanium-wall.name = Titanium Wall
|
||||||
block.titanium-wall-large.name = Large Titanium Wall
|
block.titanium-wall-large.name = Large Titanium Wall
|
||||||
|
block.plastanium-wall.name = Plastanium Wall
|
||||||
|
block.plastanium-wall-large.name = Large Plastanium Wall
|
||||||
block.phase-wall.name = Phase Wall
|
block.phase-wall.name = Phase Wall
|
||||||
block.phase-wall-large.name = Large Phase Wall
|
block.phase-wall-large.name = Large Phase Wall
|
||||||
block.thorium-wall.name = Thorium Wall
|
block.thorium-wall.name = Thorium Wall
|
||||||
@@ -991,6 +995,7 @@ unit.lich.name = Lich
|
|||||||
unit.reaper.name = Reaper
|
unit.reaper.name = Reaper
|
||||||
tutorial.next = [lightgray]<Tap to continue>
|
tutorial.next = [lightgray]<Tap to continue>
|
||||||
tutorial.intro = You have entered the[scarlet] Mindustry Tutorial.[]\nUse [[WASD] to move.\n[accent] Hold [[Ctrl] while scrolling[] to zoom in and out.\nBegin by[accent] mining copper[]. Move close to it, then tap a copper ore vein near your core to do this.\n\n[accent]{0}/{1} copper
|
tutorial.intro = You have entered the[scarlet] Mindustry Tutorial.[]\nUse [[WASD] to move.\n[accent] Hold [[Ctrl] while scrolling[] to zoom in and out.\nBegin by[accent] mining copper[]. Move close to it, then tap a copper ore vein near your core to do this.\n\n[accent]{0}/{1} copper
|
||||||
|
tutorial.intro.mobile = You have entered the[scarlet] Mindustry Tutorial.[]\nSwipe the screen to move.\n[accent] Pinch with 2 fingers [] to zoom in and out.\nBegin by[accent] mining copper[]. Move close to it, then tap a copper ore vein near your core to do this.\n\n[accent]{0}/{1} copper
|
||||||
tutorial.drill = Mining manually is inefficient.\n[accent]Drills []can mine automatically.\nClick the drill tab in the bottom right.\nSelect the[accent] mechanical drill[]. Place it on a copper vein by clicking.\n[accent]Right-click[] to stop building.
|
tutorial.drill = Mining manually is inefficient.\n[accent]Drills []can mine automatically.\nClick the drill tab in the bottom right.\nSelect the[accent] mechanical drill[]. Place it on a copper vein by clicking.\n[accent]Right-click[] to stop building.
|
||||||
tutorial.drill.mobile = Mining manually is inefficient.\n[accent]Drills []can mine automatically.\nTap the drill tab in the bottom right.\nSelect the[accent] mechanical drill[].\nPlace it on a copper vein by tapping, then press the[accent] checkmark[] below to confirm your selection.\nPress the[accent] X button[] to cancel placement.
|
tutorial.drill.mobile = Mining manually is inefficient.\n[accent]Drills []can mine automatically.\nTap the drill tab in the bottom right.\nSelect the[accent] mechanical drill[].\nPlace it on a copper vein by tapping, then press the[accent] checkmark[] below to confirm your selection.\nPress the[accent] X button[] to cancel placement.
|
||||||
tutorial.blockinfo = Each block has different stats. Each drill can only mine certain ores.\nTo check a block's info and stats,[accent] tap the "?" button while selecting it in the build menu.[]\n\n[accent]Access the Mechanical Drill's stats now.[]
|
tutorial.blockinfo = Each block has different stats. Each drill can only mine certain ores.\nTo check a block's info and stats,[accent] tap the "?" button while selecting it in the build menu.[]\n\n[accent]Access the Mechanical Drill's stats now.[]
|
||||||
@@ -1075,6 +1080,8 @@ block.copper-wall.description = A cheap defensive block.\nUseful for protecting
|
|||||||
block.copper-wall-large.description = A cheap defensive block.\nUseful for protecting the core and turrets in the first few waves.\nSpans multiple tiles.
|
block.copper-wall-large.description = A cheap defensive block.\nUseful for protecting the core and turrets in the first few waves.\nSpans multiple tiles.
|
||||||
block.titanium-wall.description = A moderately strong defensive block.\nProvides moderate protection from enemies.
|
block.titanium-wall.description = A moderately strong defensive block.\nProvides moderate protection from enemies.
|
||||||
block.titanium-wall-large.description = A moderately strong defensive block.\nProvides moderate protection from enemies.\nSpans multiple tiles.
|
block.titanium-wall-large.description = A moderately strong defensive block.\nProvides moderate protection from enemies.\nSpans multiple tiles.
|
||||||
|
block.plastanium-wall.description = A special type of wall that absorbs electric arcs and blocks automatic power node connections.
|
||||||
|
block.plastanium-wall-large.description = A special type of wall that absorbs electric arcs and blocks automatic power node connections.\nSpans multiple tiles.
|
||||||
block.thorium-wall.description = A strong defensive block.\nDecent protection from enemies.
|
block.thorium-wall.description = A strong defensive block.\nDecent protection from enemies.
|
||||||
block.thorium-wall-large.description = A strong defensive block.\nDecent protection from enemies.\nSpans multiple tiles.
|
block.thorium-wall-large.description = A strong defensive block.\nDecent protection from enemies.\nSpans multiple tiles.
|
||||||
block.phase-wall.description = A wall coated with special phase-based reflective compound. Deflects most bullets upon impact.
|
block.phase-wall.description = A wall coated with special phase-based reflective compound. Deflects most bullets upon impact.
|
||||||
|
|||||||
@@ -82,3 +82,4 @@ AzariasB
|
|||||||
amrsoll
|
amrsoll
|
||||||
ねらひかだ
|
ねらひかだ
|
||||||
Draco
|
Draco
|
||||||
|
Quezler
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 727 B After Width: | Height: | Size: 737 B |
|
Before Width: | Height: | Size: 719 KiB After Width: | Height: | Size: 930 KiB |
|
Before Width: | Height: | Size: 278 KiB After Width: | Height: | Size: 304 KiB |
|
Before Width: | Height: | Size: 259 KiB After Width: | Height: | Size: 1.0 MiB |
|
Before Width: | Height: | Size: 134 KiB After Width: | Height: | Size: 187 KiB |
|
Before Width: | Height: | Size: 882 KiB After Width: | Height: | Size: 331 KiB |
@@ -52,7 +52,7 @@ public class Blocks implements ContentList{
|
|||||||
|
|
||||||
//defense
|
//defense
|
||||||
scrapWall, scrapWallLarge, scrapWallHuge, scrapWallGigantic, thruster, //ok, these names are getting ridiculous, but at least I don't have humongous walls yet
|
scrapWall, scrapWallLarge, scrapWallHuge, scrapWallGigantic, thruster, //ok, these names are getting ridiculous, but at least I don't have humongous walls yet
|
||||||
copperWall, copperWallLarge, titaniumWall, titaniumWallLarge, thoriumWall, thoriumWallLarge, door, doorLarge,
|
copperWall, copperWallLarge, titaniumWall, titaniumWallLarge, plastaniumWall, plastaniumWallLarge, thoriumWall, thoriumWallLarge, door, doorLarge,
|
||||||
phaseWall, phaseWallLarge, surgeWall, surgeWallLarge, mender, mendProjector, overdriveProjector, forceProjector, shockMine,
|
phaseWall, phaseWallLarge, surgeWall, surgeWallLarge, mender, mendProjector, overdriveProjector, forceProjector, shockMine,
|
||||||
|
|
||||||
//transport
|
//transport
|
||||||
@@ -795,6 +795,19 @@ public class Blocks implements ContentList{
|
|||||||
size = 2;
|
size = 2;
|
||||||
}};
|
}};
|
||||||
|
|
||||||
|
plastaniumWall = new Wall("plastanium-wall"){{
|
||||||
|
requirements(Category.defense, ItemStack.with(Items.plastanium, 5, Items.metaglass, 2));
|
||||||
|
health = 190 * wallHealthMultiplier;
|
||||||
|
insulated = true;
|
||||||
|
}};
|
||||||
|
|
||||||
|
plastaniumWallLarge = new Wall("plastanium-wall-large"){{
|
||||||
|
requirements(Category.defense, ItemStack.mult(plastaniumWall.requirements, 4));
|
||||||
|
health = 190 * wallHealthMultiplier * 4;
|
||||||
|
size = 2;
|
||||||
|
insulated = true;
|
||||||
|
}};
|
||||||
|
|
||||||
thoriumWall = new Wall("thorium-wall"){{
|
thoriumWall = new Wall("thorium-wall"){{
|
||||||
requirements(Category.defense, ItemStack.with(Items.thorium, 6));
|
requirements(Category.defense, ItemStack.with(Items.thorium, 6));
|
||||||
health = 200 * wallHealthMultiplier;
|
health = 200 * wallHealthMultiplier;
|
||||||
|
|||||||
@@ -104,6 +104,11 @@ public class TechTree implements ContentList{
|
|||||||
node(door, () -> {
|
node(door, () -> {
|
||||||
node(doorLarge);
|
node(doorLarge);
|
||||||
});
|
});
|
||||||
|
node(plastaniumWall, () -> {
|
||||||
|
node(plastaniumWallLarge, () -> {
|
||||||
|
|
||||||
|
});
|
||||||
|
});
|
||||||
node(titaniumWallLarge);
|
node(titaniumWallLarge);
|
||||||
node(thoriumWall, () -> {
|
node(thoriumWall, () -> {
|
||||||
node(thoriumWallLarge);
|
node(thoriumWallLarge);
|
||||||
|
|||||||
@@ -205,8 +205,7 @@ public class NetClient implements ApplicationListener{
|
|||||||
state.set(State.menu);
|
state.set(State.menu);
|
||||||
logic.reset();
|
logic.reset();
|
||||||
|
|
||||||
Vars.netClient.beginConnecting();
|
ui.join.connect(ip, port);
|
||||||
net.connect(ip, port, () -> {});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Remote(targets = Loc.client)
|
@Remote(targets = Loc.client)
|
||||||
|
|||||||
@@ -331,6 +331,8 @@ public class NetServer implements ApplicationListener{
|
|||||||
player.sendMessage("[scarlet]Did you really expect to be able to kick an admin?");
|
player.sendMessage("[scarlet]Did you really expect to be able to kick an admin?");
|
||||||
}else if(found.isLocal){
|
}else if(found.isLocal){
|
||||||
player.sendMessage("[scarlet]Local players cannot be kicked.");
|
player.sendMessage("[scarlet]Local players cannot be kicked.");
|
||||||
|
}else if(found.getTeam() != player.getTeam()){
|
||||||
|
player.sendMessage("[scarlet]Only players on your team can be kicked.");
|
||||||
}else{
|
}else{
|
||||||
if(!vtime.get()){
|
if(!vtime.get()){
|
||||||
player.sendMessage("[scarlet]You must wait " + voteTime/60 + " minutes between votekicks.");
|
player.sendMessage("[scarlet]You must wait " + voteTime/60 + " minutes between votekicks.");
|
||||||
|
|||||||
@@ -185,6 +185,10 @@ public class World{
|
|||||||
Events.fire(new WorldLoadEvent());
|
Events.fire(new WorldLoadEvent());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setGenerating(boolean gen){
|
||||||
|
this.generating = gen;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isGenerating(){
|
public boolean isGenerating(){
|
||||||
return generating;
|
return generating;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,8 +20,9 @@ import io.anuke.mindustry.entities.type.Unit;
|
|||||||
import io.anuke.mindustry.game.Team;
|
import io.anuke.mindustry.game.Team;
|
||||||
import io.anuke.mindustry.gen.Call;
|
import io.anuke.mindustry.gen.Call;
|
||||||
import io.anuke.mindustry.graphics.Pal;
|
import io.anuke.mindustry.graphics.Pal;
|
||||||
|
import io.anuke.mindustry.world.Tile;
|
||||||
|
|
||||||
import static io.anuke.mindustry.Vars.bulletGroup;
|
import static io.anuke.mindustry.Vars.*;
|
||||||
|
|
||||||
public class Lightning extends TimedEntity implements DrawTrait, TimeTrait{
|
public class Lightning extends TimedEntity implements DrawTrait, TimeTrait{
|
||||||
public static final float lifetime = 10f;
|
public static final float lifetime = 10f;
|
||||||
@@ -34,7 +35,7 @@ public class Lightning extends TimedEntity implements DrawTrait, TimeTrait{
|
|||||||
private static final float hitRange = 30f;
|
private static final float hitRange = 30f;
|
||||||
private static int lastSeed = 0;
|
private static int lastSeed = 0;
|
||||||
|
|
||||||
private Array<Position> lines = new Array<>();
|
private Array<Vector2> lines = new Array<>();
|
||||||
private Color color = Pal.lancerLaser;
|
private Color color = Pal.lancerLaser;
|
||||||
|
|
||||||
/** For pooling use only. Do not call directly! */
|
/** For pooling use only. Do not call directly! */
|
||||||
@@ -61,10 +62,30 @@ public class Lightning extends TimedEntity implements DrawTrait, TimeTrait{
|
|||||||
random.setSeed(seed);
|
random.setSeed(seed);
|
||||||
hit.clear();
|
hit.clear();
|
||||||
|
|
||||||
|
boolean[] bhit = {false};
|
||||||
|
|
||||||
for(int i = 0; i < length / 2; i++){
|
for(int i = 0; i < length / 2; i++){
|
||||||
Bullet.create(Bullets.damageLightning, l, team, x, y, 0f, 1f, 1f, dmg);
|
Bullet.create(Bullets.damageLightning, l, team, x, y, 0f, 1f, 1f, dmg);
|
||||||
l.lines.add(new Vector2(x + Mathf.range(3f), y + Mathf.range(3f)));
|
l.lines.add(new Vector2(x + Mathf.range(3f), y + Mathf.range(3f)));
|
||||||
|
|
||||||
|
if(l.lines.size > 1){
|
||||||
|
bhit[0] = false;
|
||||||
|
Position from = l.lines.get(l.lines.size - 2);
|
||||||
|
Position to = l.lines.get(l.lines.size - 1);
|
||||||
|
world.raycastEach(world.toTile(from.getX()), world.toTile(from.getY()), world.toTile(to.getX()), world.toTile(to.getY()), (wx, wy) -> {
|
||||||
|
|
||||||
|
Tile tile = world.ltile(wx, wy);
|
||||||
|
if(tile != null && tile.block().insulated){
|
||||||
|
bhit[0] = true;
|
||||||
|
//snap it instead of removing
|
||||||
|
l.lines.get(l.lines.size -1).set(wx * tilesize, wy * tilesize);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
if(bhit[0]) break;
|
||||||
|
}
|
||||||
|
|
||||||
rect.setSize(hitRange).setCenter(x, y);
|
rect.setSize(hitRange).setCenter(x, y);
|
||||||
entities.clear();
|
entities.clear();
|
||||||
if(hit.size < maxChain){
|
if(hit.size < maxChain){
|
||||||
@@ -83,6 +104,7 @@ public class Lightning extends TimedEntity implements DrawTrait, TimeTrait{
|
|||||||
y = furthest.y;
|
y = furthest.y;
|
||||||
}else{
|
}else{
|
||||||
rotation += random.range(20f);
|
rotation += random.range(20f);
|
||||||
|
|
||||||
x += Angles.trnsx(rotation, hitRange / 2f);
|
x += Angles.trnsx(rotation, hitRange / 2f);
|
||||||
y += Angles.trnsy(rotation, hitRange / 2f);
|
y += Angles.trnsy(rotation, hitRange / 2f);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -357,8 +357,8 @@ public class Player extends Unit implements BuilderMinerTrait, ShooterTrait{
|
|||||||
public void drawOver(){
|
public void drawOver(){
|
||||||
if(dead) return;
|
if(dead) return;
|
||||||
|
|
||||||
if(isBuilding()){
|
if(isBuilding() && isBuilding){
|
||||||
if(!state.isPaused() && isBuilding){
|
if(!state.isPaused()){
|
||||||
drawBuilding();
|
drawBuilding();
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
@@ -458,7 +458,7 @@ public class Player extends Unit implements BuilderMinerTrait, ShooterTrait{
|
|||||||
}
|
}
|
||||||
|
|
||||||
//mine only when not building
|
//mine only when not building
|
||||||
if(buildRequest() == null){
|
if(buildRequest() == null || !isBuilding){
|
||||||
updateMining();
|
updateMining();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -66,14 +66,8 @@ public class GlobalData{
|
|||||||
throw new IllegalArgumentException("Not valid save data.");
|
throw new IllegalArgumentException("Not valid save data.");
|
||||||
}
|
}
|
||||||
|
|
||||||
//purge existing data
|
//purge existing tmp data, keep everything else
|
||||||
for(FileHandle f : base.list()){
|
tmpDirectory.deleteDirectory();
|
||||||
if(f.isDirectory()){
|
|
||||||
f.deleteDirectory();
|
|
||||||
}else if(!f.name().equals("zipdata.zip")){
|
|
||||||
f.delete();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
zipped.walk(f -> f.copyTo(base.child(f.path())));
|
zipped.walk(f -> f.copyTo(base.child(f.path())));
|
||||||
dest.delete();
|
dest.delete();
|
||||||
|
|||||||
@@ -22,14 +22,12 @@ public class MusicControl{
|
|||||||
public Array<Music> darkMusic = Array.with();
|
public Array<Music> darkMusic = Array.with();
|
||||||
private Music lastRandomPlayed;
|
private Music lastRandomPlayed;
|
||||||
private Interval timer = new Interval();
|
private Interval timer = new Interval();
|
||||||
private @Nullable
|
private @Nullable Music current;
|
||||||
Music current;
|
|
||||||
private float fade;
|
private float fade;
|
||||||
private boolean silenced;
|
private boolean silenced;
|
||||||
|
|
||||||
public MusicControl(){
|
public MusicControl(){
|
||||||
Events.on(ClientLoadEvent.class, e -> reload());
|
Events.on(ClientLoadEvent.class, e -> reload());
|
||||||
Events.on(ContentReloadEvent.class, e -> reload());
|
|
||||||
|
|
||||||
//only run music 10 seconds after a wave spawns
|
//only run music 10 seconds after a wave spawns
|
||||||
Events.on(WaveEvent.class, e -> Time.run(60f * 10f, () -> {
|
Events.on(WaveEvent.class, e -> Time.run(60f * 10f, () -> {
|
||||||
|
|||||||
@@ -22,13 +22,12 @@ import java.util.*;
|
|||||||
import static io.anuke.mindustry.Vars.*;
|
import static io.anuke.mindustry.Vars.*;
|
||||||
|
|
||||||
public class Saves{
|
public class Saves{
|
||||||
private int nextSlot;
|
|
||||||
private Array<SaveSlot> saves = new Array<>();
|
private Array<SaveSlot> saves = new Array<>();
|
||||||
private IntMap<SaveSlot> saveMap = new IntMap<>();
|
|
||||||
private SaveSlot current;
|
private SaveSlot current;
|
||||||
private AsyncExecutor previewExecutor = new AsyncExecutor(1);
|
private AsyncExecutor previewExecutor = new AsyncExecutor(1);
|
||||||
private boolean saving;
|
private boolean saving;
|
||||||
private float time;
|
private float time;
|
||||||
|
private FileHandle zoneFile;
|
||||||
|
|
||||||
private long totalPlaytime;
|
private long totalPlaytime;
|
||||||
private long lastTimestamp;
|
private long lastTimestamp;
|
||||||
@@ -47,16 +46,13 @@ public class Saves{
|
|||||||
|
|
||||||
public void load(){
|
public void load(){
|
||||||
saves.clear();
|
saves.clear();
|
||||||
IntArray slots = Core.settings.getObject("save-slots", IntArray.class, IntArray::new);
|
zoneFile = saveDirectory.child("-1.msav");
|
||||||
|
|
||||||
for(int i = 0; i < slots.size; i++){
|
for(FileHandle file : saveDirectory.list()){
|
||||||
int index = slots.get(i);
|
if(!file.name().contains("backup") && SaveIO.isSaveValid(file)){
|
||||||
if(SaveIO.isSaveValid(index)){
|
SaveSlot slot = new SaveSlot(file);
|
||||||
SaveSlot slot = new SaveSlot(index);
|
|
||||||
saves.add(slot);
|
saves.add(slot);
|
||||||
saveMap.put(slot.index, slot);
|
slot.meta = SaveIO.getMeta(file);
|
||||||
slot.meta = SaveIO.getMeta(index);
|
|
||||||
nextSlot = Math.max(index + 1, nextSlot);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -110,73 +106,63 @@ public class Saves{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void zoneSave(){
|
public void zoneSave(){
|
||||||
SaveSlot slot = new SaveSlot(-1);
|
SaveSlot slot = new SaveSlot(zoneFile);
|
||||||
slot.setName("zone");
|
slot.setName("zone");
|
||||||
saves.remove(s -> s.index == -1);
|
saves.remove(s -> s.file.equals(zoneFile));
|
||||||
saves.add(slot);
|
saves.add(slot);
|
||||||
saveMap.put(slot.index, slot);
|
|
||||||
slot.save();
|
slot.save();
|
||||||
saveSlots();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public SaveSlot addSave(String name){
|
public SaveSlot addSave(String name){
|
||||||
SaveSlot slot = new SaveSlot(nextSlot);
|
SaveSlot slot = new SaveSlot(getNextSlotFile());
|
||||||
nextSlot++;
|
|
||||||
slot.setName(name);
|
slot.setName(name);
|
||||||
saves.add(slot);
|
saves.add(slot);
|
||||||
saveMap.put(slot.index, slot);
|
|
||||||
slot.save();
|
slot.save();
|
||||||
saveSlots();
|
|
||||||
return slot;
|
return slot;
|
||||||
}
|
}
|
||||||
|
|
||||||
public SaveSlot importSave(FileHandle file) throws IOException{
|
public SaveSlot importSave(FileHandle file) throws IOException{
|
||||||
SaveSlot slot = new SaveSlot(nextSlot);
|
SaveSlot slot = new SaveSlot(getNextSlotFile());
|
||||||
slot.importFile(file);
|
slot.importFile(file);
|
||||||
nextSlot++;
|
|
||||||
slot.setName(file.nameWithoutExtension());
|
slot.setName(file.nameWithoutExtension());
|
||||||
saves.add(slot);
|
saves.add(slot);
|
||||||
saveMap.put(slot.index, slot);
|
slot.meta = SaveIO.getMeta(slot.file);
|
||||||
slot.meta = SaveIO.getMeta(slot.index);
|
|
||||||
current = slot;
|
current = slot;
|
||||||
saveSlots();
|
|
||||||
return slot;
|
return slot;
|
||||||
}
|
}
|
||||||
|
|
||||||
public SaveSlot getZoneSlot(){
|
public SaveSlot getZoneSlot(){
|
||||||
SaveSlot slot = getByID(-1);
|
SaveSlot slot = getSaveSlots().find(s -> s.file.equals(zoneFile));
|
||||||
return slot == null || slot.getZone() == null ? null : slot;
|
return slot == null || slot.getZone() == null ? null : slot;
|
||||||
}
|
}
|
||||||
|
|
||||||
public SaveSlot getByID(int id){
|
public FileHandle getNextSlotFile(){
|
||||||
return saveMap.get(id);
|
int i = 0;
|
||||||
|
FileHandle file;
|
||||||
|
while((file = saveDirectory.child(i + "." + saveExtension)).exists()){
|
||||||
|
i ++;
|
||||||
|
}
|
||||||
|
return file;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Array<SaveSlot> getSaveSlots(){
|
public Array<SaveSlot> getSaveSlots(){
|
||||||
return saves;
|
return saves;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void saveSlots(){
|
|
||||||
IntArray result = new IntArray(saves.size);
|
|
||||||
for(int i = 0; i < saves.size; i++) result.add(saves.get(i).index);
|
|
||||||
|
|
||||||
Core.settings.putObject("save-slots", result);
|
|
||||||
Core.settings.save();
|
|
||||||
}
|
|
||||||
|
|
||||||
public class SaveSlot{
|
public class SaveSlot{
|
||||||
public final int index;
|
//public final int index;
|
||||||
|
public final FileHandle file;
|
||||||
boolean requestedPreview;
|
boolean requestedPreview;
|
||||||
SaveMeta meta;
|
SaveMeta meta;
|
||||||
|
|
||||||
public SaveSlot(int index){
|
public SaveSlot(FileHandle file){
|
||||||
this.index = index;
|
this.file = file;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void load() throws SaveException{
|
public void load() throws SaveException{
|
||||||
try{
|
try{
|
||||||
SaveIO.loadFromSlot(index);
|
SaveIO.load(file);
|
||||||
meta = SaveIO.getMeta(index);
|
meta = SaveIO.getMeta(file);
|
||||||
current = this;
|
current = this;
|
||||||
totalPlaytime = meta.timePlayed;
|
totalPlaytime = meta.timePlayed;
|
||||||
savePreview();
|
savePreview();
|
||||||
@@ -190,8 +176,8 @@ public class Saves{
|
|||||||
long prev = totalPlaytime;
|
long prev = totalPlaytime;
|
||||||
totalPlaytime = time;
|
totalPlaytime = time;
|
||||||
|
|
||||||
SaveIO.saveToSlot(index);
|
SaveIO.save(file);
|
||||||
meta = SaveIO.getMeta(index);
|
meta = SaveIO.getMeta(file);
|
||||||
if(!state.is(State.menu)){
|
if(!state.is(State.menu)){
|
||||||
current = this;
|
current = this;
|
||||||
}
|
}
|
||||||
@@ -226,8 +212,12 @@ public class Saves{
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String index(){
|
||||||
|
return file.nameWithoutExtension();
|
||||||
|
}
|
||||||
|
|
||||||
private FileHandle previewFile(){
|
private FileHandle previewFile(){
|
||||||
return mapPreviewDirectory.child("save_slot_" + index + ".png");
|
return mapPreviewDirectory.child("save_slot_" + index() + ".png");
|
||||||
}
|
}
|
||||||
|
|
||||||
private FileHandle loadPreviewFile(){
|
private FileHandle loadPreviewFile(){
|
||||||
@@ -266,11 +256,11 @@ public class Saves{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public String getName(){
|
public String getName(){
|
||||||
return Core.settings.getString("save-" + index + "-name", "untitled");
|
return Core.settings.getString("save-" + index() + "-name", "untitled");
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setName(String name){
|
public void setName(String name){
|
||||||
Core.settings.put("save-" + index + "-name", name);
|
Core.settings.put("save-" + index() + "-name", name);
|
||||||
Core.settings.save();
|
Core.settings.save();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -295,34 +285,33 @@ public class Saves{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public boolean isAutosave(){
|
public boolean isAutosave(){
|
||||||
return Core.settings.getBool("save-" + index + "-autosave", true);
|
return Core.settings.getBool("save-" + index() + "-autosave", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setAutosave(boolean save){
|
public void setAutosave(boolean save){
|
||||||
Core.settings.put("save-" + index + "-autosave", save);
|
Core.settings.put("save-" + index() + "-autosave", save);
|
||||||
Core.settings.save();
|
Core.settings.save();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void importFile(FileHandle file) throws IOException{
|
public void importFile(FileHandle from) throws IOException{
|
||||||
try{
|
try{
|
||||||
file.copyTo(SaveIO.fileFor(index));
|
from.copyTo(file);
|
||||||
}catch(Exception e){
|
}catch(Exception e){
|
||||||
throw new IOException(e);
|
throw new IOException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void exportFile(FileHandle file) throws IOException{
|
public void exportFile(FileHandle to) throws IOException{
|
||||||
try{
|
try{
|
||||||
SaveIO.fileFor(index).copyTo(file);
|
file.copyTo(to);
|
||||||
}catch(Exception e){
|
}catch(Exception e){
|
||||||
throw new IOException(e);
|
throw new IOException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void delete(){
|
public void delete(){
|
||||||
SaveIO.fileFor(index).delete();
|
file.delete();
|
||||||
saves.removeValue(this, true);
|
saves.removeValue(this, true);
|
||||||
saveMap.remove(index);
|
|
||||||
if(this == current){
|
if(this == current){
|
||||||
current = null;
|
current = null;
|
||||||
}
|
}
|
||||||
@@ -330,8 +319,6 @@ public class Saves{
|
|||||||
if(Core.assets.isLoaded(loadPreviewFile().path())){
|
if(Core.assets.isLoaded(loadPreviewFile().path())){
|
||||||
Core.assets.unload(loadPreviewFile().path());
|
Core.assets.unload(loadPreviewFile().path());
|
||||||
}
|
}
|
||||||
|
|
||||||
saveSlots();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ import io.anuke.mindustry.input.*;
|
|||||||
import io.anuke.mindustry.input.PlaceUtils.*;
|
import io.anuke.mindustry.input.PlaceUtils.*;
|
||||||
import io.anuke.mindustry.type.*;
|
import io.anuke.mindustry.type.*;
|
||||||
import io.anuke.mindustry.world.*;
|
import io.anuke.mindustry.world.*;
|
||||||
|
import io.anuke.mindustry.world.blocks.*;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.util.zip.*;
|
import java.util.zip.*;
|
||||||
@@ -44,6 +45,12 @@ public class Schematics implements Loadable{
|
|||||||
previews.clear();
|
previews.clear();
|
||||||
shadowBuffer.dispose();
|
shadowBuffer.dispose();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Events.on(ContentReloadEvent.class, event -> {
|
||||||
|
previews.each((schem, m) -> m.dispose());
|
||||||
|
previews.clear();
|
||||||
|
load();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -63,9 +70,9 @@ public class Schematics implements Loadable{
|
|||||||
|
|
||||||
all.sort();
|
all.sort();
|
||||||
|
|
||||||
Core.app.post(() -> {
|
if(shadowBuffer == null){
|
||||||
shadowBuffer = new FrameBuffer(maxSchematicSize + padding + 8, maxSchematicSize + padding + 8);
|
Core.app.post(() -> shadowBuffer = new FrameBuffer(maxSchematicSize + padding + 8, maxSchematicSize + padding + 8));
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void overwrite(Schematic target, Schematic newSchematic){
|
public void overwrite(Schematic target, Schematic newSchematic){
|
||||||
@@ -205,7 +212,7 @@ public class Schematics implements Loadable{
|
|||||||
|
|
||||||
/** Creates an array of build requests from a schematic's data, centered on the provided x+y coordinates. */
|
/** 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){
|
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());
|
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() || !s.block.unlocked());
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Adds a schematic to the list, also copying it into the files.*/
|
/** Adds a schematic to the list, also copying it into the files.*/
|
||||||
@@ -251,7 +258,7 @@ public class Schematics implements Loadable{
|
|||||||
for(int cy = y; cy <= y2; cy++){
|
for(int cy = y; cy <= y2; cy++){
|
||||||
Tile linked = world.ltile(cx, cy);
|
Tile linked = world.ltile(cx, cy);
|
||||||
|
|
||||||
if(linked != null && linked.entity != null && linked.entity.block.isVisible()){
|
if(linked != null && linked.entity != null && linked.entity.block.isVisible() && !(linked.block() instanceof BuildBlock)){
|
||||||
int top = linked.block().size/2;
|
int top = linked.block().size/2;
|
||||||
int bot = linked.block().size % 2 == 1 ? -linked.block().size/2 : -(linked.block().size - 1)/2;
|
int bot = linked.block().size % 2 == 1 ? -linked.block().size/2 : -(linked.block().size - 1)/2;
|
||||||
minx = Math.min(linked.x + bot, minx);
|
minx = Math.min(linked.x + bot, minx);
|
||||||
@@ -279,7 +286,7 @@ public class Schematics implements Loadable{
|
|||||||
for(int cy = oy; cy <= oy2; cy++){
|
for(int cy = oy; cy <= oy2; cy++){
|
||||||
Tile tile = world.ltile(cx, cy);
|
Tile tile = world.ltile(cx, cy);
|
||||||
|
|
||||||
if(tile != null && tile.entity != null && !counted.contains(tile.pos())){
|
if(tile != null && tile.entity != null && !counted.contains(tile.pos()) && !(tile.block() instanceof BuildBlock) && tile.entity.block.isVisible()){
|
||||||
int config = tile.entity.config();
|
int config = tile.entity.config();
|
||||||
if(tile.block().posConfig){
|
if(tile.block().posConfig){
|
||||||
config = Pos.get(Pos.x(config) + offsetX, Pos.y(config) + offsetY);
|
config = Pos.get(Pos.x(config) + offsetX, Pos.y(config) + offsetY);
|
||||||
|
|||||||
@@ -75,6 +75,8 @@ public class Pal{
|
|||||||
|
|
||||||
surge = Color.valueOf("f3e979"),
|
surge = Color.valueOf("f3e979"),
|
||||||
|
|
||||||
|
plastanium = Color.valueOf("a1b46e"),
|
||||||
|
|
||||||
redSpark = Color.valueOf("fbb97f"),
|
redSpark = Color.valueOf("fbb97f"),
|
||||||
orangeSpark = Color.valueOf("d2b29c"),
|
orangeSpark = Color.valueOf("d2b29c"),
|
||||||
|
|
||||||
|
|||||||
@@ -182,7 +182,7 @@ public class DesktopInput extends InputHandler{
|
|||||||
mode = none;
|
mode = none;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(mode != none){
|
if(mode == placing || isPlacing()){
|
||||||
selectRequests.clear();
|
selectRequests.clear();
|
||||||
lastSchematic = null;
|
lastSchematic = null;
|
||||||
}
|
}
|
||||||
@@ -379,7 +379,7 @@ public class DesktopInput extends InputHandler{
|
|||||||
deleting = true;
|
deleting = true;
|
||||||
}else if(selected != null){
|
}else if(selected != null){
|
||||||
//only begin shooting if there's no cursor event
|
//only begin shooting if there's no cursor event
|
||||||
if(!tileTapped(selected) && !tryTapPlayer(Core.input.mouseWorld().x, Core.input.mouseWorld().y) && player.buildQueue().size == 0 && !droppingItem &&
|
if(!tileTapped(selected) && !tryTapPlayer(Core.input.mouseWorld().x, Core.input.mouseWorld().y) && (player.buildQueue().size == 0 || !player.isBuilding) && !droppingItem &&
|
||||||
!tryBeginMine(selected) && player.getMineTile() == null && !ui.chatfrag.chatOpen()){
|
!tryBeginMine(selected) && player.getMineTile() == null && !ui.chatfrag.chatOpen()){
|
||||||
player.isShooting = true;
|
player.isShooting = true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -153,8 +153,10 @@ public class MobileInput extends InputHandler implements GestureListener{
|
|||||||
|
|
||||||
void removeRequest(BuildRequest request){
|
void removeRequest(BuildRequest request){
|
||||||
selectRequests.removeValue(request, true);
|
selectRequests.removeValue(request, true);
|
||||||
|
if(!request.breaking){
|
||||||
removals.add(request);
|
removals.add(request);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
boolean isLinePlacing(){
|
boolean isLinePlacing(){
|
||||||
return mode == placing && lineMode && Mathf.dst(lineStartX * tilesize, lineStartY * tilesize, Core.input.mouseWorld().x, Core.input.mouseWorld().y) >= 3 * tilesize;
|
return mode == placing && lineMode && Mathf.dst(lineStartX * tilesize, lineStartY * tilesize, Core.input.mouseWorld().x, Core.input.mouseWorld().y) >= 3 * tilesize;
|
||||||
|
|||||||
@@ -34,37 +34,23 @@ public class SaveIO{
|
|||||||
return versions.get(version);
|
return versions.get(version);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void saveToSlot(int slot){
|
public static void save(FileHandle file){
|
||||||
FileHandle file = fileFor(slot);
|
|
||||||
boolean exists = file.exists();
|
boolean exists = file.exists();
|
||||||
if(exists) file.moveTo(backupFileFor(file));
|
if(exists) file.moveTo(backupFileFor(file));
|
||||||
try{
|
try{
|
||||||
write(fileFor(slot));
|
write(file);
|
||||||
}catch(Exception e){
|
}catch(Exception e){
|
||||||
if(exists) backupFileFor(file).moveTo(file);
|
if(exists) backupFileFor(file).moveTo(file);
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void loadFromSlot(int slot) throws SaveException{
|
public static DataInputStream getStream(FileHandle file){
|
||||||
load(fileFor(slot));
|
return new DataInputStream(new InflaterInputStream(file.read(bufferSize)));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static DataInputStream getSlotStream(int slot){
|
public static DataInputStream getBackupStream(FileHandle file){
|
||||||
return new DataInputStream(new InflaterInputStream(fileFor(slot).read(bufferSize)));
|
return new DataInputStream(new InflaterInputStream(backupFileFor(file).read(bufferSize)));
|
||||||
}
|
|
||||||
|
|
||||||
public static DataInputStream getBackupSlotStream(int slot){
|
|
||||||
return new DataInputStream(new InflaterInputStream(backupFileFor(fileFor(slot)).read(bufferSize)));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean isSaveValid(int slot){
|
|
||||||
try{
|
|
||||||
getMeta(slot);
|
|
||||||
return true;
|
|
||||||
}catch(Exception e){
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isSaveValid(FileHandle file){
|
public static boolean isSaveValid(FileHandle file){
|
||||||
@@ -85,11 +71,11 @@ public class SaveIO{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static SaveMeta getMeta(int slot){
|
public static SaveMeta getMeta(FileHandle file){
|
||||||
try{
|
try{
|
||||||
return getMeta(getSlotStream(slot));
|
return getMeta(getStream(file));
|
||||||
}catch(Exception e){
|
}catch(Exception e){
|
||||||
return getMeta(getBackupSlotStream(slot));
|
return getMeta(getBackupStream(file));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -167,6 +153,7 @@ public class SaveIO{
|
|||||||
}catch(Exception e){
|
}catch(Exception e){
|
||||||
throw new SaveException(e);
|
throw new SaveException(e);
|
||||||
}finally{
|
}finally{
|
||||||
|
world.setGenerating(false);
|
||||||
content.setTemporaryMapper(null);
|
content.setTemporaryMapper(null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package io.anuke.mindustry.io;
|
|||||||
import io.anuke.arc.collection.*;
|
import io.anuke.arc.collection.*;
|
||||||
import io.anuke.arc.util.*;
|
import io.anuke.arc.util.*;
|
||||||
import io.anuke.arc.util.io.*;
|
import io.anuke.arc.util.io.*;
|
||||||
|
import io.anuke.mindustry.content.*;
|
||||||
import io.anuke.mindustry.core.*;
|
import io.anuke.mindustry.core.*;
|
||||||
import io.anuke.mindustry.ctype.*;
|
import io.anuke.mindustry.ctype.*;
|
||||||
import io.anuke.mindustry.entities.*;
|
import io.anuke.mindustry.entities.*;
|
||||||
@@ -166,6 +167,7 @@ public abstract class SaveVersion extends SaveFileReader{
|
|||||||
short floorid = stream.readShort();
|
short floorid = stream.readShort();
|
||||||
short oreid = stream.readShort();
|
short oreid = stream.readShort();
|
||||||
int consecutives = stream.readUnsignedByte();
|
int consecutives = stream.readUnsignedByte();
|
||||||
|
if(content.block(floorid) == Blocks.air) floorid = Blocks.stone.id;
|
||||||
|
|
||||||
context.create(x, y, floorid, oreid, (short)0);
|
context.create(x, y, floorid, oreid, (short)0);
|
||||||
|
|
||||||
@@ -182,6 +184,7 @@ public abstract class SaveVersion extends SaveFileReader{
|
|||||||
int x = i % width, y = i / width;
|
int x = i % width, y = i / width;
|
||||||
Block block = content.block(stream.readShort());
|
Block block = content.block(stream.readShort());
|
||||||
Tile tile = context.tile(x, y);
|
Tile tile = context.tile(x, y);
|
||||||
|
if(block == null) block = Blocks.air;
|
||||||
tile.setBlock(block);
|
tile.setBlock(block);
|
||||||
|
|
||||||
if(tile.entity != null){
|
if(tile.entity != null){
|
||||||
|
|||||||
@@ -181,12 +181,14 @@ public class Map implements Comparable<Map>, Publishable{
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public FileHandle createSteamFolder(String id){
|
public FileHandle createSteamFolder(String id){
|
||||||
return null;
|
FileHandle mapFile = tmpDirectory.child("map_" + id).child("map.msav");
|
||||||
|
file.copyTo(mapFile);
|
||||||
|
return mapFile.parent();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public FileHandle createSteamPreview(String id){
|
public FileHandle createSteamPreview(String id){
|
||||||
return null;
|
return previewFile();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -164,7 +164,7 @@ public class Mods implements Loadable{
|
|||||||
return requiresReload;
|
return requiresReload;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Loads all mods from the folder, but does call any methods on them.*/
|
/** Loads all mods from the folder, but does not call any methods on them.*/
|
||||||
public void load(){
|
public void load(){
|
||||||
for(FileHandle file : modDirectory.list()){
|
for(FileHandle file : modDirectory.list()){
|
||||||
if(!file.extension().equals("jar") && !file.extension().equals("zip") && !(file.isDirectory() && file.child("mod.json").exists())) continue;
|
if(!file.extension().equals("jar") && !file.extension().equals("zip") && !(file.isDirectory() && file.child("mod.json").exists())) continue;
|
||||||
@@ -200,14 +200,61 @@ public class Mods implements Loadable{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
resolveDependencies();
|
||||||
//sort mods to make sure servers handle them properly.
|
//sort mods to make sure servers handle them properly.
|
||||||
loaded.sort(Structs.comparing(m -> m.name));
|
loaded.sort(Structs.comparing(m -> m.name));
|
||||||
|
|
||||||
buildFiles();
|
buildFiles();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void buildFiles(){
|
private void resolveDependencies(){
|
||||||
|
for(LoadedMod mod : Array.<LoadedMod>withArrays(loaded, disabled)){
|
||||||
|
updateDependencies(mod);
|
||||||
|
}
|
||||||
|
|
||||||
|
disabled.addAll(loaded.select(LoadedMod::hasUnmetDependencies));
|
||||||
|
loaded.removeAll(LoadedMod::hasUnmetDependencies);
|
||||||
|
disabled.each(mod -> setEnabled(mod, false));
|
||||||
|
disabled.distinct();
|
||||||
|
loaded.distinct();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateDependencies(LoadedMod mod){
|
||||||
|
mod.dependencies.clear();
|
||||||
|
mod.missingDependencies.clear();
|
||||||
|
mod.dependencies = mod.meta.dependencies.map(this::locateMod);
|
||||||
|
|
||||||
|
for(int i = 0; i < mod.dependencies.size; i++){
|
||||||
|
if(mod.dependencies.get(i) == null){
|
||||||
|
mod.missingDependencies.add(mod.meta.dependencies.get(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void topoSort(LoadedMod mod, Array<LoadedMod> stack, ObjectSet<LoadedMod> visited){
|
||||||
|
visited.add(mod);
|
||||||
|
mod.dependencies.each(m -> !visited.contains(m), m -> topoSort(m, stack, visited));
|
||||||
|
stack.add(mod);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @return mods ordered in the correct way needed for dependencies. */
|
||||||
|
private Array<LoadedMod> orderedMods(){
|
||||||
|
ObjectSet<LoadedMod> visited = new ObjectSet<>();
|
||||||
|
Array<LoadedMod> result = new Array<>();
|
||||||
for(LoadedMod mod : loaded){
|
for(LoadedMod mod : loaded){
|
||||||
|
if(!visited.contains(mod)){
|
||||||
|
topoSort(mod, result, visited);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private LoadedMod locateMod(String name){
|
||||||
|
return loaded.find(mod -> mod.name.equals(name));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void buildFiles(){
|
||||||
|
for(LoadedMod mod : orderedMods()){
|
||||||
boolean zipFolder = !mod.file.isDirectory() && mod.root.parent() != null;
|
boolean zipFolder = !mod.file.isDirectory() && mod.root.parent() != null;
|
||||||
String parentName = zipFolder ? mod.root.name() : null;
|
String parentName = zipFolder ? mod.root.name() : null;
|
||||||
for(FileHandle file : mod.root.list()){
|
for(FileHandle file : mod.root.list()){
|
||||||
@@ -256,10 +303,7 @@ public class Mods implements Loadable{
|
|||||||
loaded.clear();
|
loaded.clear();
|
||||||
disabled.clear();
|
disabled.clear();
|
||||||
load();
|
load();
|
||||||
buildFiles();
|
|
||||||
Musics.dispose();
|
|
||||||
Sounds.dispose();
|
Sounds.dispose();
|
||||||
Musics.load();
|
|
||||||
Sounds.load();
|
Sounds.load();
|
||||||
Core.assets.finishLoading();
|
Core.assets.finishLoading();
|
||||||
content.clear();
|
content.clear();
|
||||||
@@ -277,7 +321,7 @@ public class Mods implements Loadable{
|
|||||||
|
|
||||||
/** Creates all the content found in mod files. */
|
/** Creates all the content found in mod files. */
|
||||||
public void loadContent(){
|
public void loadContent(){
|
||||||
for(LoadedMod mod : loaded){
|
for(LoadedMod mod : orderedMods()){
|
||||||
safeRun(mod, () -> {
|
safeRun(mod, () -> {
|
||||||
if(mod.root.child("content").exists()){
|
if(mod.root.child("content").exists()){
|
||||||
FileHandle contentRoot = mod.root.child("content");
|
FileHandle contentRoot = mod.root.child("content");
|
||||||
@@ -337,11 +381,13 @@ public class Mods implements Loadable{
|
|||||||
requiresReload = true;
|
requiresReload = true;
|
||||||
if(!enabled){
|
if(!enabled){
|
||||||
loaded.remove(mod);
|
loaded.remove(mod);
|
||||||
disabled.add(mod);
|
if(!disabled.contains(mod)) disabled.add(mod);
|
||||||
}else{
|
}else{
|
||||||
loaded.add(mod);
|
if(!loaded.contains(mod)) loaded.add(mod);
|
||||||
disabled.remove(mod);
|
disabled.remove(mod);
|
||||||
}
|
}
|
||||||
|
loaded.each(this::updateDependencies);
|
||||||
|
disabled.each(this::updateDependencies);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -466,6 +512,10 @@ 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;
|
||||||
|
/** This mod's dependencies as already-loaded mods. */
|
||||||
|
public Array<LoadedMod> dependencies = new Array<>();
|
||||||
|
/** All missing dependencies of this mod as strings. */
|
||||||
|
public Array<String> missingDependencies = new Array<>();
|
||||||
|
|
||||||
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;
|
||||||
@@ -479,6 +529,10 @@ public class Mods implements Loadable{
|
|||||||
return Core.settings.getBool("mod-" + name + "-enabled", true);
|
return Core.settings.getBool("mod-" + name + "-enabled", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean hasUnmetDependencies(){
|
||||||
|
return !missingDependencies.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getSteamID(){
|
public String getSteamID(){
|
||||||
return Core.settings.getString(name + "-steamid", null);
|
return Core.settings.getString(name + "-steamid", null);
|
||||||
@@ -549,7 +603,7 @@ public class Mods implements Loadable{
|
|||||||
/** Plugin metadata information.*/
|
/** Plugin metadata information.*/
|
||||||
public static class ModMeta{
|
public static class ModMeta{
|
||||||
public String name, author, description, version, main;
|
public String name, author, description, version, main;
|
||||||
public String[] dependencies = {}; //TODO implement
|
public Array<String> dependencies = Array.with();
|
||||||
/** Hidden mods are only server-side or client-side, and do not support adding new content. */
|
/** Hidden mods are only server-side or client-side, and do not support adding new content. */
|
||||||
public boolean hidden;
|
public boolean hidden;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ public class NetworkIO{
|
|||||||
stream.writeInt(player.id);
|
stream.writeInt(player.id);
|
||||||
player.write(stream);
|
player.write(stream);
|
||||||
|
|
||||||
|
SaveIO.getSaveWriter().writeContentHeader(stream);
|
||||||
SaveIO.getSaveWriter().writeMap(stream);
|
SaveIO.getSaveWriter().writeMap(stream);
|
||||||
}catch(IOException e){
|
}catch(IOException e){
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
@@ -51,9 +52,12 @@ public class NetworkIO{
|
|||||||
player.resetID(id);
|
player.resetID(id);
|
||||||
player.add();
|
player.add();
|
||||||
|
|
||||||
|
SaveIO.getSaveWriter().readContentHeader(stream);
|
||||||
SaveIO.getSaveWriter().readMap(stream, world.context);
|
SaveIO.getSaveWriter().readMap(stream, world.context);
|
||||||
}catch(IOException e){
|
}catch(IOException e){
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
|
}finally{
|
||||||
|
content.setTemporaryMapper(null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ public class Styles{
|
|||||||
public static ButtonStyle defaultb, waveb;
|
public static ButtonStyle defaultb, waveb;
|
||||||
public static TextButtonStyle defaultt, squaret, nodet, cleart, discordt, infot, clearPartialt, clearTogglet, clearToggleMenut, togglet;
|
public static TextButtonStyle defaultt, squaret, nodet, cleart, discordt, infot, clearPartialt, clearTogglet, clearToggleMenut, togglet;
|
||||||
public static ImageButtonStyle defaulti, nodei, righti, emptyi, emptytogglei, selecti, cleari, clearFulli, clearPartiali, clearPartial2i, clearTogglei, clearTransi, clearToggleTransi, clearTogglePartiali;
|
public static ImageButtonStyle defaulti, nodei, righti, emptyi, emptytogglei, selecti, cleari, clearFulli, clearPartiali, clearPartial2i, clearTogglei, clearTransi, clearToggleTransi, clearTogglePartiali;
|
||||||
public static ScrollPaneStyle defaultPane, horizontalPane;
|
public static ScrollPaneStyle defaultPane, horizontalPane, smallPane;
|
||||||
public static KeybindDialogStyle defaultKeybindDialog;
|
public static KeybindDialogStyle defaultKeybindDialog;
|
||||||
public static SliderStyle defaultSlider, vSlider;
|
public static SliderStyle defaultSlider, vSlider;
|
||||||
public static LabelStyle defaultLabel, outlineLabel;
|
public static LabelStyle defaultLabel, outlineLabel;
|
||||||
@@ -225,6 +225,10 @@ public class Styles{
|
|||||||
hScroll = scrollHorizontal;
|
hScroll = scrollHorizontal;
|
||||||
hScrollKnob = scrollKnobHorizontalBlack;
|
hScrollKnob = scrollKnobHorizontalBlack;
|
||||||
}};
|
}};
|
||||||
|
smallPane = new ScrollPaneStyle(){{
|
||||||
|
vScroll = clear;
|
||||||
|
vScrollKnob = scrollKnobVerticalThin;
|
||||||
|
}};
|
||||||
|
|
||||||
defaultKeybindDialog = new KeybindDialogStyle(){{
|
defaultKeybindDialog = new KeybindDialogStyle(){{
|
||||||
keyColor = Pal.accent;
|
keyColor = Pal.accent;
|
||||||
|
|||||||
@@ -29,8 +29,9 @@ public class ModsDialog extends FloatingDialog{
|
|||||||
|
|
||||||
buttons.addImageTextButton("$mods.guide", Icon.wiki,
|
buttons.addImageTextButton("$mods.guide", Icon.wiki,
|
||||||
() -> Core.net.openURI(modGuideURL))
|
() -> Core.net.openURI(modGuideURL))
|
||||||
.size(210f, 64f);
|
.size(android ? 210f + 250f + 10f : 210, 64f).colspan(android ? 2 : 1);
|
||||||
|
|
||||||
|
if(!android){
|
||||||
buttons.addImageTextButton("$mod.import.github", Icon.github, () -> {
|
buttons.addImageTextButton("$mod.import.github", Icon.github, () -> {
|
||||||
ui.showTextInput("$mod.import.github", "", 64, "Anuken/ExampleMod", text -> {
|
ui.showTextInput("$mod.import.github", "", 64, "Anuken/ExampleMod", text -> {
|
||||||
ui.loadfrag.show();
|
ui.loadfrag.show();
|
||||||
@@ -62,12 +63,18 @@ public class ModsDialog extends FloatingDialog{
|
|||||||
}, t -> Core.app.post(() -> ui.showException(t)));
|
}, t -> Core.app.post(() -> ui.showException(t)));
|
||||||
});
|
});
|
||||||
}).size(250f, 64f);
|
}).size(250f, 64f);
|
||||||
|
}
|
||||||
|
|
||||||
shown(this::setup);
|
shown(this::setup);
|
||||||
|
|
||||||
hidden(() -> {
|
hidden(() -> {
|
||||||
if(mods.requiresReload()){
|
if(mods.requiresReload()){
|
||||||
ui.loadAnd("$reloading", () -> {
|
ui.loadAnd("$reloading", () -> {
|
||||||
|
mods.all().each(mod -> {
|
||||||
|
if(mod.hasUnmetDependencies()){
|
||||||
|
ui.showErrorMessage(Core.bundle.format("mod.nowdisabled", mod.name, mod.missingDependencies.toString(", ")));
|
||||||
|
}
|
||||||
|
});
|
||||||
mods.reloadContent();
|
mods.reloadContent();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -96,6 +103,7 @@ public class ModsDialog extends FloatingDialog{
|
|||||||
anyDisabled = true;
|
anyDisabled = true;
|
||||||
table.row();
|
table.row();
|
||||||
table.addImage().growX().height(4f).pad(6f).color(Pal.gray);
|
table.addImage().growX().height(4f).pad(6f).color(Pal.gray);
|
||||||
|
table.row();
|
||||||
}
|
}
|
||||||
|
|
||||||
table.table(Styles.black6, t -> {
|
table.table(Styles.black6, t -> {
|
||||||
@@ -138,7 +146,10 @@ public class ModsDialog extends FloatingDialog{
|
|||||||
t.labelWrap("[lightgray]" + mod.meta.description).growX();
|
t.labelWrap("[lightgray]" + mod.meta.description).growX();
|
||||||
t.row();
|
t.row();
|
||||||
}
|
}
|
||||||
|
if(mod.hasUnmetDependencies()){
|
||||||
|
t.labelWrap(Core.bundle.format("mod.missingdependencies", mod.missingDependencies.toString(", "))).growX();
|
||||||
|
t.row();
|
||||||
|
}
|
||||||
}).width(500f);
|
}).width(500f);
|
||||||
table.row();
|
table.row();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -107,6 +107,7 @@ public class MenuFragment extends Fragment{
|
|||||||
container.add(join);
|
container.add(join);
|
||||||
container.add(custom);
|
container.add(custom);
|
||||||
container.add(maps);
|
container.add(maps);
|
||||||
|
container.row();
|
||||||
|
|
||||||
container.table(table -> {
|
container.table(table -> {
|
||||||
table.defaults().set(container.defaults());
|
table.defaults().set(container.defaults());
|
||||||
|
|||||||
@@ -232,7 +232,7 @@ public class PlacementFragment extends Fragment{
|
|||||||
frame.row();
|
frame.row();
|
||||||
frame.table(Tex.pane2, blocksSelect -> {
|
frame.table(Tex.pane2, blocksSelect -> {
|
||||||
blocksSelect.margin(4).marginTop(0);
|
blocksSelect.margin(4).marginTop(0);
|
||||||
blocksSelect.table(blocks -> blockTable = blocks).grow();
|
blocksSelect.pane(blocks -> blockTable = blocks).height(194f).grow().get().setStyle(Styles.smallPane);
|
||||||
blocksSelect.row();
|
blocksSelect.row();
|
||||||
blocksSelect.table(control.input::buildPlacementUI).name("inputTable").growX();
|
blocksSelect.table(control.input::buildPlacementUI).name("inputTable").growX();
|
||||||
}).fillY().bottom().touchable(Touchable.enabled);
|
}).fillY().bottom().touchable(Touchable.enabled);
|
||||||
|
|||||||
@@ -55,6 +55,8 @@ public class Block extends BlockStorage{
|
|||||||
public boolean breakable;
|
public boolean breakable;
|
||||||
/** whether this floor can be placed on. */
|
/** whether this floor can be placed on. */
|
||||||
public boolean placeableOn = true;
|
public boolean placeableOn = true;
|
||||||
|
/** whether this block has insulating properties. */
|
||||||
|
public boolean insulated = false;
|
||||||
/** tile entity health */
|
/** tile entity health */
|
||||||
public int health = -1;
|
public int health = -1;
|
||||||
/** base block explosiveness */
|
/** base block explosiveness */
|
||||||
@@ -241,7 +243,7 @@ public class Block extends BlockStorage{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void drawCracks(Tile tile){
|
public void drawCracks(Tile tile){
|
||||||
if(!tile.entity.damaged()) return;
|
if(!tile.entity.damaged() || size > maxCrackSize) return;
|
||||||
int id = tile.pos();
|
int id = tile.pos();
|
||||||
TextureRegion region = cracks[size - 1][Mathf.clamp((int)((1f - tile.entity.healthf()) * crackRegions), 0, crackRegions-1)];
|
TextureRegion region = cracks[size - 1][Mathf.clamp((int)((1f - tile.entity.healthf()) * crackRegions), 0, crackRegions-1)];
|
||||||
Draw.colorl(0.2f, 0.1f + (1f - tile.entity.healthf())* 0.6f);
|
Draw.colorl(0.2f, 0.1f + (1f - tile.entity.healthf())* 0.6f);
|
||||||
@@ -313,7 +315,7 @@ public class Block extends BlockStorage{
|
|||||||
tempTiles.clear();
|
tempTiles.clear();
|
||||||
Geometry.circle(tile.x, tile.y, range, (x, y) -> {
|
Geometry.circle(tile.x, tile.y, range, (x, y) -> {
|
||||||
Tile other = world.ltile(x, y);
|
Tile other = world.ltile(x, y);
|
||||||
if(other != null && other.block instanceof PowerNode && ((PowerNode)other.block).linkValid(other, tile) && !other.entity.proximity().contains(tile) &&
|
if(other != null && other.block instanceof PowerNode && ((PowerNode)other.block).linkValid(other, tile) && !PowerNode.insulated(other, tile) && !other.entity.proximity().contains(tile) &&
|
||||||
!(outputsPower && tile.entity.proximity().contains(p -> p.entity != null && p.entity.power != null && p.entity.power.graph == other.entity.power.graph))){
|
!(outputsPower && tile.entity.proximity().contains(p -> p.entity != null && p.entity.power != null && p.entity.power.graph == other.entity.power.graph))){
|
||||||
tempTiles.add(other);
|
tempTiles.add(other);
|
||||||
}
|
}
|
||||||
@@ -322,7 +324,7 @@ public class Block extends BlockStorage{
|
|||||||
if(!tempTiles.isEmpty()){
|
if(!tempTiles.isEmpty()){
|
||||||
Tile toLink = tempTiles.first();
|
Tile toLink = tempTiles.first();
|
||||||
if(!toLink.entity.power.links.contains(tile.pos())){
|
if(!toLink.entity.power.links.contains(tile.pos())){
|
||||||
toLink.configure(tile.pos());
|
toLink.configureAny(tile.pos());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import io.anuke.arc.collection.*;
|
|||||||
import io.anuke.arc.function.*;
|
import io.anuke.arc.function.*;
|
||||||
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.ArcAnnotate.*;
|
||||||
import io.anuke.mindustry.content.*;
|
import io.anuke.mindustry.content.*;
|
||||||
import io.anuke.mindustry.entities.traits.*;
|
import io.anuke.mindustry.entities.traits.*;
|
||||||
import io.anuke.mindustry.entities.type.*;
|
import io.anuke.mindustry.entities.type.*;
|
||||||
@@ -93,6 +94,10 @@ public class Tile implements Position, TargetTrait{
|
|||||||
Call.onTileConfig(player, this, value);
|
Call.onTileConfig(player, this, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void configureAny(int value){
|
||||||
|
Call.onTileConfig(null, this, value);
|
||||||
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public <T extends TileEntity> T entity(){
|
public <T extends TileEntity> T entity(){
|
||||||
return (T)entity;
|
return (T)entity;
|
||||||
@@ -148,7 +153,7 @@ public class Tile implements Position, TargetTrait{
|
|||||||
return team;
|
return team;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setBlock(Block type, Team team, int rotation){
|
public void setBlock(@NonNull Block type, Team team, int rotation){
|
||||||
preChanged();
|
preChanged();
|
||||||
this.block = type;
|
this.block = type;
|
||||||
this.team = (byte)team.ordinal();
|
this.team = (byte)team.ordinal();
|
||||||
@@ -156,11 +161,12 @@ public class Tile implements Position, TargetTrait{
|
|||||||
changed();
|
changed();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setBlock(Block type, Team team){
|
public void setBlock(@NonNull Block type, Team team){
|
||||||
setBlock(type, team, 0);
|
setBlock(type, team, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setBlock(Block type){
|
public void setBlock(@NonNull Block type){
|
||||||
|
if(type == null) throw new IllegalArgumentException("Block cannot be null.");
|
||||||
preChanged();
|
preChanged();
|
||||||
this.block = type;
|
this.block = type;
|
||||||
this.rotation = 0;
|
this.rotation = 0;
|
||||||
@@ -168,13 +174,13 @@ public class Tile implements Position, TargetTrait{
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**This resets the overlay!*/
|
/**This resets the overlay!*/
|
||||||
public void setFloor(Floor type){
|
public void setFloor(@NonNull Floor type){
|
||||||
this.floor = type;
|
this.floor = type;
|
||||||
this.overlay = (Floor)Blocks.air;
|
this.overlay = (Floor)Blocks.air;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Sets the floor, preserving overlay.*/
|
/** Sets the floor, preserving overlay.*/
|
||||||
public void setFloorUnder(Floor floor){
|
public void setFloorUnder(@NonNull Floor floor){
|
||||||
Block overlay = this.overlay;
|
Block overlay = this.overlay;
|
||||||
setFloor(floor);
|
setFloor(floor);
|
||||||
setOverlay(overlay);
|
setOverlay(overlay);
|
||||||
|
|||||||
@@ -51,5 +51,4 @@ public class Wall extends Block{
|
|||||||
public boolean canReplace(Block other){
|
public boolean canReplace(Block other){
|
||||||
return super.canReplace(other) && health > other.health;
|
return super.canReplace(other) && health > other.health;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ public class ArmoredConveyor extends Conveyor{
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean blends(Tile tile, int rotation, int otherx, int othery, int otherrot, Block otherblock){
|
public boolean blends(Tile tile, int rotation, int otherx, int othery, int otherrot, Block otherblock){
|
||||||
return otherblock.outputsItems() && (Point2.equals(tile.x + Geometry.d4(rotation).x, tile.y + Geometry.d4(rotation).y, otherx, othery)
|
return otherblock.outputsItems() && otherblock instanceof Conveyor && (Point2.equals(tile.x + Geometry.d4(rotation).x, tile.y + Geometry.d4(rotation).y, otherx, othery)
|
||||||
|| ((!otherblock.rotate && Edges.getFacingEdge(otherblock, otherx, othery, tile) != null &&
|
|| ((!otherblock.rotate && Edges.getFacingEdge(otherblock, otherx, othery, tile) != null &&
|
||||||
Edges.getFacingEdge(otherblock, otherx, othery, tile).relativeTo(tile) == tile.rotation()) || Point2.equals(otherx + Geometry.d4(otherrot).x, othery + Geometry.d4(otherrot).y, tile.x, tile.y)));
|
Edges.getFacingEdge(otherblock, otherx, othery, tile).relativeTo(tile) == tile.rotation()) || Point2.equals(otherx + Geometry.d4(otherrot).x, othery + Geometry.d4(otherrot).y, tile.x, tile.y)));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -413,12 +413,12 @@ public class Conveyor extends Block implements Autotiler{
|
|||||||
static long toLong(int value){
|
static long toLong(int value){
|
||||||
byte[] values = Pack.bytes(value, writeByte);
|
byte[] values = Pack.bytes(value, writeByte);
|
||||||
|
|
||||||
byte itemid = values[0];
|
short itemid = content.item(values[0]).id;
|
||||||
float x = values[1] / 127f;
|
float x = values[1] / 127f;
|
||||||
float y = ((int)values[2] + 128) / 255f;
|
float y = ((int)values[2] + 128) / 255f;
|
||||||
|
|
||||||
short[] shorts = writeShort;
|
short[] shorts = writeShort;
|
||||||
shorts[0] = (short)itemid;
|
shorts[0] = itemid;
|
||||||
shorts[1] = (short)(x * Short.MAX_VALUE);
|
shorts[1] = (short)(x * Short.MAX_VALUE);
|
||||||
shorts[2] = (short)((y - 1f) * Short.MAX_VALUE);
|
shorts[2] = (short)((y - 1f) * Short.MAX_VALUE);
|
||||||
return Pack.longShorts(shorts);
|
return Pack.longShorts(shorts);
|
||||||
|
|||||||
@@ -108,14 +108,16 @@ public class PowerNode extends PowerBlock{
|
|||||||
Geometry.circle(tile.x, tile.y, (int)(laserRange + 1), (x, y) -> {
|
Geometry.circle(tile.x, tile.y, (int)(laserRange + 1), (x, y) -> {
|
||||||
Tile other = world.ltile(x, y);
|
Tile other = world.ltile(x, y);
|
||||||
if(valid.test(other)){
|
if(valid.test(other)){
|
||||||
|
if(!insulated(tile, other)) {
|
||||||
tempTiles.add(other);
|
tempTiles.add(other);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
tempTiles.sort(Structs.comparingFloat(t -> t.dst2(tile)));
|
tempTiles.sort(Structs.comparingFloat(t -> t.dst2(tile)));
|
||||||
tempTiles.each(valid, other -> {
|
tempTiles.each(valid, other -> {
|
||||||
if(!tile.entity.power.links.contains(other.pos())){
|
if(!tile.entity.power.links.contains(other.pos())){
|
||||||
tile.configure(other.pos());
|
tile.configureAny(other.pos());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -167,6 +169,18 @@ public class PowerNode extends PowerBlock{
|
|||||||
tile.configure(other.pos());
|
tile.configure(other.pos());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(tile == other){
|
||||||
|
if (other.entity.power.links.size == 0){
|
||||||
|
getPotentialLinks(tile, link -> tile.configure(link.pos()));
|
||||||
|
} else {
|
||||||
|
while (entity.power.links.size > 0){
|
||||||
|
tile.configure(entity.power.links.get(0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -221,7 +235,13 @@ public class PowerNode extends PowerBlock{
|
|||||||
Draw.color(Pal.placing);
|
Draw.color(Pal.placing);
|
||||||
Drawf.circles(x * tilesize + offset(), y * tilesize + offset(), laserRange * tilesize);
|
Drawf.circles(x * tilesize + offset(), y * tilesize + offset(), laserRange * tilesize);
|
||||||
|
|
||||||
getPotentialLinks(tile, other -> Drawf.square(other.drawx(), other.drawy(), other.block().size * tilesize / 2f + 2f, Pal.place));
|
getPotentialLinks(tile, other -> {
|
||||||
|
Drawf.square(other.drawx(), other.drawy(), other.block().size * tilesize / 2f + 2f, Pal.place);
|
||||||
|
|
||||||
|
insulators(tile.x, tile.y, other.x, other.y, cause -> {
|
||||||
|
Drawf.square(cause.drawx(), cause.drawy(), cause.block().size * tilesize / 2f + 2f, Pal.plastanium);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
Draw.reset();
|
Draw.reset();
|
||||||
}
|
}
|
||||||
@@ -299,4 +319,27 @@ public class PowerNode extends PowerBlock{
|
|||||||
Draw.color();
|
Draw.color();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean insulated(Tile tile, Tile other){
|
||||||
|
return insulated(tile.x, tile.y, other.x, other.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean insulated(int x, int y, int x2, int y2){
|
||||||
|
final Boolean[] bool = {false};
|
||||||
|
insulators(x, y, x2, y2, cause -> {
|
||||||
|
bool[0] = true;
|
||||||
|
});
|
||||||
|
return bool[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void insulators(int x, int y, int x2, int y2, Consumer<Tile> iterator){
|
||||||
|
world.raycastEach(x, y, x2, y2, (wx, wy) -> {
|
||||||
|
|
||||||
|
Tile tile = world.ltile(wx, wy);
|
||||||
|
if(tile != null && tile.block() != null && tile.block().insulated){
|
||||||
|
iterator.accept(tile);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -194,7 +194,9 @@ public class Drill extends Block{
|
|||||||
});
|
});
|
||||||
|
|
||||||
stats.add(BlockStat.drillSpeed, 60f / drillTime * size * size, StatUnit.itemsSecond);
|
stats.add(BlockStat.drillSpeed, 60f / drillTime * size * size, StatUnit.itemsSecond);
|
||||||
stats.add(BlockStat.boostEffect, liquidBoostIntensity, StatUnit.timesSpeed);
|
if(liquidBoostIntensity > 0){
|
||||||
|
stats.add(BlockStat.boostEffect, liquidBoostIntensity * liquidBoostIntensity, StatUnit.timesSpeed);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void countOre(Tile tile){
|
void countOre(Tile tile){
|
||||||
|
|||||||
@@ -114,7 +114,7 @@ public class MechPad extends Block{
|
|||||||
MechFactoryEntity entity = tile.entity();
|
MechFactoryEntity entity = tile.entity();
|
||||||
|
|
||||||
if(entity.player != null){
|
if(entity.player != null){
|
||||||
RespawnBlock.drawRespawn(tile, entity.heat, entity.progress, entity.time, entity.player, (!entity.sameMech && entity.player.mech == mech ? Mechs.starter : mech));
|
RespawnBlock.drawRespawn(tile, entity.heat, entity.progress, entity.time, entity.player, (!entity.sameMech && entity.player.mech == mech ? mech : Mechs.starter));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import io.anuke.arc.collection.*;
|
|||||||
import io.anuke.arc.function.*;
|
import io.anuke.arc.function.*;
|
||||||
import io.anuke.arc.util.*;
|
import io.anuke.arc.util.*;
|
||||||
import io.anuke.arc.util.pooling.*;
|
import io.anuke.arc.util.pooling.*;
|
||||||
|
import io.anuke.mindustry.core.GameState.*;
|
||||||
import io.anuke.mindustry.core.Version;
|
import io.anuke.mindustry.core.Version;
|
||||||
import io.anuke.mindustry.game.EventType.*;
|
import io.anuke.mindustry.game.EventType.*;
|
||||||
import io.anuke.mindustry.game.*;
|
import io.anuke.mindustry.game.*;
|
||||||
@@ -245,6 +246,13 @@ public class SNet implements SteamNetworkingCallback, SteamMatchmakingCallback,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(net.active()){
|
||||||
|
net.disconnect();
|
||||||
|
net.closeServer();
|
||||||
|
logic.reset();
|
||||||
|
state.set(State.menu);
|
||||||
|
}
|
||||||
|
|
||||||
currentLobby = steamIDLobby;
|
currentLobby = steamIDLobby;
|
||||||
currentServer = smat.getLobbyOwner(steamIDLobby);
|
currentServer = smat.getLobbyOwner(steamIDLobby);
|
||||||
|
|
||||||
|
|||||||
@@ -162,6 +162,10 @@ public class SWorkshop implements SteamUGCCallback{
|
|||||||
ugc.setItemVisibility(h, PublishedFileVisibility.Private);
|
ugc.setItemVisibility(h, PublishedFileVisibility.Private);
|
||||||
}
|
}
|
||||||
ugc.submitItemUpdate(h, changelog == null ? "<Created>" : changelog);
|
ugc.submitItemUpdate(h, changelog == null ? "<Created>" : changelog);
|
||||||
|
|
||||||
|
if(p instanceof Map){
|
||||||
|
SAchievement.publishMap.complete();
|
||||||
|
}
|
||||||
}, () -> p.addSteamID(sid));
|
}, () -> p.addSteamID(sid));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -670,28 +670,25 @@ public class ServerControl implements ApplicationListener{
|
|||||||
if(state.is(State.playing)){
|
if(state.is(State.playing)){
|
||||||
err("Already hosting. Type 'stop' to stop hosting first.");
|
err("Already hosting. Type 'stop' to stop hosting first.");
|
||||||
return;
|
return;
|
||||||
}else if(!Strings.canParseInt(arg[0])){
|
|
||||||
err("Invalid save slot '{0}'.", arg[0]);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int slot = Strings.parseInt(arg[0]);
|
FileHandle file = saveDirectory.child(arg[0] + "." + saveExtension);
|
||||||
|
|
||||||
if(!SaveIO.isSaveValid(slot)){
|
if(!SaveIO.isSaveValid(file)){
|
||||||
err("No (valid) save data found for slot.");
|
err("No (valid) save data found for slot.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Core.app.post(() -> {
|
Core.app.post(() -> {
|
||||||
try{
|
try{
|
||||||
SaveIO.loadFromSlot(slot);
|
SaveIO.load(file);
|
||||||
state.rules.zone = null;
|
state.rules.zone = null;
|
||||||
}catch(Throwable t){
|
|
||||||
err("Failed to load save. Outdated or corrupt file.");
|
|
||||||
}
|
|
||||||
info("Save loaded.");
|
info("Save loaded.");
|
||||||
host();
|
host();
|
||||||
state.set(State.playing);
|
state.set(State.playing);
|
||||||
|
}catch(Throwable t){
|
||||||
|
err("Failed to load save. Outdated or corrupt file.");
|
||||||
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -699,18 +696,25 @@ public class ServerControl implements ApplicationListener{
|
|||||||
if(!state.is(State.playing)){
|
if(!state.is(State.playing)){
|
||||||
err("Not hosting. Host a game first.");
|
err("Not hosting. Host a game first.");
|
||||||
return;
|
return;
|
||||||
}else if(!Strings.canParseInt(arg[0])){
|
|
||||||
err("Invalid save slot '{0}'.", arg[0]);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FileHandle file = saveDirectory.child(arg[0] + "." + saveExtension);
|
||||||
|
|
||||||
Core.app.post(() -> {
|
Core.app.post(() -> {
|
||||||
int slot = Strings.parseInt(arg[0]);
|
SaveIO.save(file);
|
||||||
SaveIO.saveToSlot(slot);
|
info("Saved to {0}.", file);
|
||||||
info("Saved to slot {0}.", slot);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
handler.register("saves", "List all saves in the save directory.", arg -> {
|
||||||
|
info("Save files: ");
|
||||||
|
for(FileHandle file : saveDirectory.list()){
|
||||||
|
if(file.extension().equals(saveExtension)){
|
||||||
|
info("| &ly{0}", file.nameWithoutExtension());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
handler.register("gameover", "Force a game over.", arg -> {
|
handler.register("gameover", "Force a game over.", arg -> {
|
||||||
if(state.is(State.menu)){
|
if(state.is(State.menu)){
|
||||||
info("Not playing a map.");
|
info("Not playing a map.");
|
||||||
|
|||||||
@@ -198,7 +198,7 @@ public class ApplicationTests{
|
|||||||
void save(){
|
void save(){
|
||||||
world.loadMap(testMap);
|
world.loadMap(testMap);
|
||||||
assertTrue(state.teams.get(defaultTeam).cores.size > 0);
|
assertTrue(state.teams.get(defaultTeam).cores.size > 0);
|
||||||
SaveIO.saveToSlot(0);
|
SaveIO.save(saveDirectory.child("0.msav"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -206,9 +206,9 @@ public class ApplicationTests{
|
|||||||
world.loadMap(testMap);
|
world.loadMap(testMap);
|
||||||
Map map = world.getMap();
|
Map map = world.getMap();
|
||||||
|
|
||||||
SaveIO.saveToSlot(0);
|
SaveIO.save(saveDirectory.child("0.msav"));
|
||||||
resetWorld();
|
resetWorld();
|
||||||
SaveIO.loadFromSlot(0);
|
SaveIO.load(saveDirectory.child("0.msav"));
|
||||||
|
|
||||||
assertEquals(world.width(), map.width);
|
assertEquals(world.width(), map.width);
|
||||||
assertEquals(world.height(), map.height);
|
assertEquals(world.height(), map.height);
|
||||||
|
|||||||