Merge branch 'master' into patch-1

This commit is contained in:
Anuken
2019-08-23 18:12:20 -04:00
committed by GitHub
118 changed files with 1372 additions and 1226 deletions
+2 -2
View File
@@ -21,8 +21,6 @@ logs/
/server/build/
/test_files/
/annotations/build/
/desktop-sdl/build/
desktop-sdl/build/
/android/assets/mindustry-maps/
/android/assets/mindustry-saves/
/core/assets/gifexport/
@@ -33,7 +31,9 @@ desktop-sdl/build/
ios/robovm.properties
packr-out/
config/
changelog
*.gif
/core/assets/saves/
version.properties
+1 -1
View File
@@ -13,7 +13,7 @@ deploy:
api_key:
secure: Cv5wFtWt62/A24EvSEQvMow7gKPbZ3oATEFPuSghhB2TQz1dA40Zee3Qvk4LFlpLrhYo4K0ZSczCZRGpR+hCd8+Dpww52bheYEvWuh3ZQfvu/fXtEx2j5PwP1qMpmIgSxETV/gkD7l9FImdh0VzktYiAvQfmi0bEocG9/D4QwjFpNat7iwBdcMiw1MvAygpdIWRsjiw0RKlB2mWarmoHhQ7Gu7qlU3j50uaEvcrtmU0pBUPggNQwQRv32i9NPvNFxrqqlUjDLIS8JFea99zCkp8BwYqbEvBIMzd+Qip1/stLJJA3+cDUClbsDtg8rAVetzpOrdLEEBmqShFe5MDl2yEHcsgpN9CFsyTaUfvB3P3rVjizvycMm42IsUkXQiarm5xTQ/TIA8Rd8AHiSKuweNCg1Fd5SFaRtKy8JVLXuxyfUccmyje6hhz2L4lS2Wfj3mAG7sqZUCXhWP79EKdGkiPOjKv4CwXEKmuH3BMVqPlNUZJr9Eg3sV1FG0h2l+MVOOnR635qdUbb49sYojYxVruMLX0BH1c4ZCu230m8CUoWA1Em1QNI75ya7+9Y5T6AsgWDVpBvdUo9fWNbdp+VQ0GskFQsJD5wtnxbcbHeFiERAgGBm7z6qt9u9LrQpBH+dsW52ADvYsu3L4nQEa+sdMHwTTwmGY+iUvsxu0DqxGg=
file:
- desktop/build/libs/desktop-release.jar
- desktop/build/libs/Mindustry.jar
- server/build/libs/server-release.jar
on:
repo: Anuken/Mindustry
+1 -1
View File
@@ -36,7 +36,7 @@ If the terminal returns `Permission denied` or `Command not found` on Mac/Linux,
---
Gradle may take up to several minutes to download files. Be patient. <br>
After building, the output .JAR file should be in `/desktop/build/libs/desktop-release.jar` for desktop builds, and in `/server/build/libs/server-release.jar` for server builds.
After building, the output .JAR file should be in `/desktop/build/libs/Mindustry.jar` for desktop builds, and in `/server/build/libs/server-release.jar` for server builds.
### Downloads
-3
View File
@@ -1,8 +1,5 @@
## Translating for Mindustry
**DISCLAIMER:** *Currently, 4.0 is far from done, which means that things such as block names, descriptions, and core text will be changing often. If you begin translating now, you might have to re-do large chunks of the bundle before final release.*
To begin, log in to your GitHub account, or if you don't have one yet, create it [here](https://github.com/).
Consult [this list](https://www.science.co.il/language/Locale-codes.php) to find the locale code for your language. Once you've found it,
+1 -1
View File
@@ -8,7 +8,7 @@ buildscript{
}
dependencies{
classpath 'com.android.tools.build:gradle:3.4.2'
classpath 'com.android.tools.build:gradle:3.4.1'
}
}
@@ -129,8 +129,8 @@ public class AndroidLauncher extends AndroidApplication{
}
config.hideStatusBar = true;
Net.setClientProvider(new ArcNetClient());
Net.setServerProvider(new ArcNetServer());
Net.setClientProvider(new MClient());
Net.setServerProvider(new MServer());
initialize(new Mindustry(), config);
checkFiles(getIntent());
}
@@ -80,7 +80,7 @@ public class AssetsAnnotationProcessor extends AbstractProcessor{
}
load.addStatement(name + " = io.anuke.arc.Core.audio."+loadMethod+"(io.anuke.arc.Core.files.internal(io.anuke.arc.Core.app.getType() != io.anuke.arc.Application.ApplicationType.iOS ? $S : $S))",
path.substring(path.lastIndexOf("/") + 1) + "/" + fname, (path.substring(path.lastIndexOf("/") + 1) + "/" + fname).replace(".ogg", ".caf"));
path.substring(path.lastIndexOf("/") + 1) + "/" + fname, (path.substring(path.lastIndexOf("/") + 1) + "/" + fname).replace(".ogg", ".mp3"));
dispose.addStatement(name + ".dispose()");
dispose.addStatement(name + " = null");
type.addField(FieldSpec.builder(ClassName.bestGuess(rtype), name, Modifier.STATIC, Modifier.PUBLIC).initializer("new io.anuke.arc.audio.mock.Mock" + rtype.substring(rtype.lastIndexOf(".") + 1)+ "()").build());
+24 -20
View File
@@ -67,7 +67,7 @@ allprojects{
platform = "${platform.substring(0, platform.length() - 2)}-${platform.substring(platform.length() - 2)}bit"
}
return "[${platform}]${getModifierString()}[${getNeatVersionString()}]${appName}.zip"
return "[${platform}]${getModifierString()}[${getNeatVersionString()}]${appName}"
}
getVersionString = {
@@ -145,23 +145,6 @@ allprojects{
project(":desktop"){
apply plugin: "java"
dependencies{
compile project(":core")
compile project(":net")
if(debugged()) compile project(":debug")
compile "com.badlogicgames.gdx:gdx-platform:$gdxVersion:natives-desktop"
compile "com.badlogicgames.gdx:gdx-freetype-platform:$gdxVersion:natives-desktop"
compile arcModule("backends:backend-lwjgl3")
compile 'com.github.MinnDevelopment:java-discord-rpc:v2.0.2'
}
}
project(":desktop-sdl"){
apply plugin: "java"
dependencies{
compile project(":core")
compile project(":net")
@@ -246,9 +229,11 @@ project(":core"){
compileJava.dependsOn(preGen)
compile "org.lz4:lz4-java:1.4.1"
compile arcModule("arc-core")
compile arcModule("extensions:freetype")
compile arcModule("extensions:arcnet")
compile arcModule("extensions:mnet")
if(localArc() && debugged()) compile arcModule("extensions:recorder")
compileOnly project(":annotations")
@@ -311,7 +296,26 @@ project(":net"){
dependencies{
compile project(":core")
compile "org.lz4:lz4-java:1.4.1"
compile 'com.github.Anuken:WaifUPnP:05eb46bc577fd7674596946ba288c96c0cedd893'
}
}
task deployAll{
task cleanDeployOutput{
doFirst{
if("${getBuildVersion()}" == "custom build" || "${getBuildVersion()}" == "") throw new IllegalArgumentException("----\n\nSET A BUILD NUMBER FIRST!\n\n----")
if(!project.hasProperty("release")) throw new IllegalArgumentException("----\n\nSET THE RELEASE PROJECT PROPERTY FIRST!\n\n----")
delete{
delete "deploy/"
}
}
}
dependsOn cleanDeployOutput
dependsOn "desktop:packrLinux64"
dependsOn "desktop:packrWindows64"
dependsOn "desktop:packrWindows32"
dependsOn "desktop:packrMacOS"
dependsOn "server:deploy"
dependsOn "android:deploy"
}
+3 -2
View File
@@ -75,6 +75,7 @@ server.kicked.nameEmpty = Your chosen name is invalid.
server.kicked.idInUse = You are already on this server! Connecting with two accounts is not permitted.
server.kicked.customClient = This server does not support custom builds. Download an official version.
server.kicked.gameover = Game over!
server.versions = Your version:[accent] {0}[]\nServer version:[accent] {1}[]
host.info = The [accent]host[] button hosts a server on port [scarlet]6567[]. \nAnybody on the same [lightgray]wifi or local network[] should be able to see your server in their server list.\n\nIf you want people to be able to connect from anywhere by IP, [accent]port forwarding[] is required.\n\n[lightgray]Note: If someone is experiencing trouble connecting to your LAN game, make sure you have allowed Mindustry access to your local network in your firewall settings. Note that public networks sometimes do not allow server discovery.
join.info = Here, you can enter a [accent]server IP[] to connect to, or discover [accent]local network[] servers to connect to.\nBoth LAN and WAN multiplayer is supported.\n\n[lightgray]Note: There is no automatic global server list; if you want to connect to someone by IP, you would need to ask the host for their IP.
hostserver = Host Multiplayer Game
@@ -124,7 +125,7 @@ save.new = New Save
save.overwrite = Are you sure you want to overwrite\nthis save slot?
overwrite = Overwrite
save.none = No saves found!
saveload = [accent]Saving...
saveload = Saving...
savefail = Failed to save game!
save.delete.confirm = Are you sure you want to delete this save?
save.delete = Delete
@@ -371,7 +372,7 @@ zone.crags.name = Crags
zone.fungalPass.name = Fungal Pass
zone.groundZero.description = The optimal location to begin once more. Low enemy threat. Few resources.\nGather as much lead and copper as possible.\nMove on.
zone.frozenForest.description = Even here, closer to mountains, the spores have spread. The fridgid temperatures cannot contain them forever.\n\nBegin the venture into power. Build combustion generators. Learn to use menders.
zone.frozenForest.description = Even here, closer to mountains, the spores have spread. The frigid temperatures cannot contain them forever.\n\nBegin the venture into power. Build combustion generators. Learn to use menders.
zone.desertWastes.description = These wastes are vast, unpredictable, and criss-crossed with derelict sector structures.\nCoal is present in the region. Burn it for power, or synthesize graphite.\n\n[lightgray]This landing location cannot be guaranteed.
zone.saltFlats.description = On the outskirts of the desert lie the Salt Flats. Few resources can be found in this location.\n\nThe enemy has erected a resource storage complex here. Eradicate their core. Leave nothing standing.
zone.craters.description = Water has accumulated in this crater, relic of the old wars. Reclaim the area. Collect sand. Smelt metaglass. Pump water to cool turrets and drills.
File diff suppressed because it is too large Load Diff
+2
View File
@@ -46,6 +46,7 @@ newgame = 새 게임
none = <없음>
minimap = 미니맵
close = 닫기
website = 웹사이트
quit = 나가기
maps =
continue = 계속하기
@@ -514,6 +515,7 @@ setting.lasers.name = 전력 노드 레이저 표시
setting.pixelate.name = 픽셀화[LIGHT_GRAY] (애니메이션 효과가 꺼집니다)
setting.minimap.name = 미니맵 보기
setting.musicvol.name = 음악 크기
setting.ambientvol.name = 배경음 크기
setting.mutemusic.name = 음소거
setting.sfxvol.name = 효과음 크기
setting.mutesound.name = 소리 끄기
+23 -23
View File
@@ -172,7 +172,7 @@ saveimage = 保存图片
unknown = 未知
custom = 自定义
builtin = 内建的
map.delete.confirm = 你确定你想要删除这张地图吗?这个操作无法取消
map.delete.confirm = 你确定你想要删除这张地图吗?这个操作无法撤销
map.random = [accent]随机地图
map.nospawn = 这个地图没有核心!请在编辑器中添加一个[ROYAL]蓝色[]的核心。
map.nospawn.pvp = 这个地图没有敌人的核心!请在编辑器中添加一个[ROYAL]红色[]的核心。
@@ -349,13 +349,13 @@ error.any = 未知网络错误。
error.bloom = 未能初始化特效。\n您的设备可能不支持它。
zone.groundZero.name = 零号地区
zone.desertWastes.name = 沙漠废物
zone.desertWastes.name = 荒芜沙漠
zone.craters.name = 陨石带
zone.frozenForest.name = 冰冻森林
zone.ruinousShores.name = 毁灭海岸
zone.ruinousShores.name = 遗迹海岸
zone.stainedMountains.name = 绵延群山
zone.desolateRift.name = 荒芜裂谷
zone.nuclearComplex.name = 核裂
zone.nuclearComplex.name = 核裂
zone.overgrowth.name = 增生区
zone.tarFields.name = 石油田
zone.saltFlats.name = 盐碱荒滩
@@ -498,9 +498,9 @@ setting.sensitivity.name = 控制器灵敏度
setting.saveinterval.name = 自动保存间隔
setting.seconds = {0} 秒
setting.fullscreen.name = 全屏
setting.borderlesswindow.name = 全屏化[LIGHT_GRAY] (可能需要重启)
setting.borderlesswindow.name = 无边框窗口[LIGHT_GRAY] (可能需要重启)
setting.fps.name = 显示 FPS
setting.vsync.name = 同步
setting.vsync.name = 垂直同步
setting.lasers.name = 显示能量射线
setting.pixelate.name = 像素画面 [LIGHT_GRAY](可能会降低性能)
setting.minimap.name = 显示小地图
@@ -736,7 +736,7 @@ block.duo.name = 双管炮
block.scorch.name = 火焰炮
block.scatter.name = 分裂炮
block.hail.name = 冰雹炮
block.lancer.name = 蓝瑟炮
block.lancer.name = 激光矛
block.conveyor.name = 传送带
block.titanium-conveyor.name = 钛传送带
block.junction.name = 连接点
@@ -825,7 +825,7 @@ block.surge-wall.name = 波动墙
block.surge-wall-large.name = 大型波动墙
block.cyclone.name = 气旋炮
block.fuse.name = 融合炮
block.shock-mine.name = 休克地雷
block.shock-mine.name = 脉冲地雷
block.overdrive-projector.name = 超速投影器
block.force-projector.name = 力墙投影器
block.arc.name = 电弧
@@ -955,7 +955,7 @@ block.surge-wall-large.description = 强大的防御区块。\n有很小的机
block.door.description = 一扇小门,可以通过点击打开和关闭。\n如果打开,敌人可以射击并穿过。
block.door-large.description = 一扇大门,可以通过点击打开和关闭。\n如果打开,敌人可以射击并穿过。\n跨越多个区块。
block.mender.description = 定期修理附近的方块,使防御系统在波与波之间得到修复。\n通常使用硅来提高范围和效率。
block.mend-projector.description = 定期修复附近的建筑物。
block.mend-projector.description = 修理者的升级。定期修复附近的建筑物。
block.overdrive-projector.description = 提高附近建筑物的速度,如钻头和传送带。
block.force-projector.description = 自身周围创建一个六边形力场,使建筑物和内部单位免受子弹的伤害。
block.shock-mine.description = 伤害踩到它的敌人。敌人几乎看不到它。
@@ -1008,20 +1008,20 @@ block.container.description = 存储少量物品。当存在非恒定的材料
block.vault.description = 存储大量物品。当存在非恒定的材料需求时,使用它来创建缓冲区。 [LIGHT_GRAY]卸载器[]可用于从仓库中获取物品。
block.launch-pad.description = 不通过核心发射物体。
block.launch-pad-large.description = 发射台的改进版。存储更多物体。启动频率更高。
block.duo.description = 小而便宜的炮塔。
block.scatter.description = 中型防空炮塔,向空中单位发射铅或废料。
block.scorch.description = 小型炮塔,燃烧任何靠近它的地面敌人。近距离效。
block.duo.description = 小而便宜的炮塔。对地高效。
block.scatter.description = 不可或缺的防空炮塔,向空中单位发射铅或废料。
block.scorch.description = 小型炮塔,燃烧任何靠近它的地面敌人。近距离非常有效。
block.arc.description = 小型炮塔,发射电弧。
block.hail.description = 小型炮兵炮台。
block.lancer.description = 中型炮塔,发射带电的电子束。
block.wave.description = 中型快速炮塔,射出液体泡泡。
block.salvo.description = 中型炮塔,齐射射击。
block.swarmer.description = 中型炮塔,发射爆炸导弹。
block.ripple.description = 大型炮兵炮塔,可同时向多个目标开火
block.cyclone.description = 大型快速炮塔。
block.fuse.description = 大型炮塔,发射强大的短程光束。
block.spectre.description = 大型炮塔,一次射出两颗强大的子弹。
block.meltdown.description = 发射强大的远程光束的大型炮塔
block.hail.description = 小型,远程炮台。
block.lancer.description = 中型对地炮塔。遇敌时会充能并发射强有力的的能量束。
block.wave.description = 中型快速炮塔,射出液体泡泡。有液体输入时自动灭火。
block.salvo.description = 双管炮的升级。中型,齐射射击。
block.swarmer.description = 中型炮塔,对空对地,发射跟踪爆炸导弹。
block.ripple.description = 大型远程炮台,非常强力,向远处的敌人投射一簇弹药
block.cyclone.description = 大型快速炮塔,对空对地,向周围敌人发射爆炸弹
block.fuse.description = 大型炮塔,发射三道刺穿敌人的短程光束。
block.spectre.description = 大型炮塔,对空对地,一次射出两颗强大的穿甲子弹。
block.meltdown.description = 超大型激光炮塔,充能之后持续发射光束,需要冷却剂
block.crawler-factory.description = 生产快速自毁单元。
block.draug-factory.description = 生产德鲁格釆矿机。
block.spirit-factory.description = 生产幽灵修理机。
@@ -1039,4 +1039,4 @@ block.javelin-ship-pad.description = 离开你当前的装置,换成一个强
block.glaive-ship-pad.description = 离开现有的装置,换成装甲良好的大型武装直升机。\n站在上面时双击切换。
block.tau-mech-pad.description = 离开你当前的装置并换成一个可以治愈友方建筑物和单位的支撑机械。\n站在上面时双击切换。
block.delta-mech-pad.description = 离开你当前的装置并换成一个快速,轻装甲的机械装置,用于快速攻击。\n站在上面时双击切换。
block.omega-mech-pad.description = 离开你当前的装置并换成一个笨重且装甲良好的机甲,用于前线攻击。\n站在上面时双击切换。
block.omega-mech-pad.description = 离开你当前的装置并换成一个笨重且装甲良好的机甲,用于前线攻击。\n站在上面时双击切换。
+2 -1
View File
@@ -26,7 +26,7 @@ beito
BeefEX
Lorex
laohuaji233
CrazyBearTR
Spico The Spirit Guy
Zachary
Fenr1r
Jaiun Lee
@@ -71,3 +71,4 @@ Paul T
Dominik
Arkanic
Potion
Markus G
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+2 -1
View File
@@ -188,7 +188,8 @@
up: button,
over: button-over,
imageDisabledColor: gray,
imageUpColor: white
imageUpColor: white,
disabled: button-disabled
},
node: {
up: button-over,
+1 -1
View File
@@ -67,6 +67,6 @@ public class Mindustry extends ApplicationCore{
super.init();
Log.info("Time to load [total]: {0}", Time.elapsed());
Events.fire(new GameLoadEvent());
Events.fire(new ClientLoadEvent());
}
}
+4 -1
View File
@@ -1,7 +1,7 @@
package io.anuke.mindustry;
import io.anuke.arc.*;
import io.anuke.arc.Application.ApplicationType;
import io.anuke.arc.Core;
import io.anuke.arc.files.FileHandle;
import io.anuke.arc.graphics.Color;
import io.anuke.arc.util.Structs;
@@ -15,6 +15,7 @@ import io.anuke.mindustry.entities.traits.DrawTrait;
import io.anuke.mindustry.entities.traits.SyncTrait;
import io.anuke.mindustry.entities.type.*;
import io.anuke.mindustry.game.*;
import io.anuke.mindustry.game.EventType.*;
import io.anuke.mindustry.gen.Serialization;
import io.anuke.mindustry.net.Net;
import io.anuke.mindustry.world.blocks.defense.ForceProjector.ShieldEntity;
@@ -222,5 +223,7 @@ public class Vars{
customMapDirectory = dataDirectory.child("maps/");
saveDirectory = dataDirectory.child("saves/");
tmpDirectory = dataDirectory.child("tmp/");
Events.fire(new AppLoadEvent());
}
}
@@ -119,7 +119,7 @@ public class BlockIndexer{
ObjectSet<Tile> set = damagedTiles[team.ordinal()];
for(Tile tile : set){
if((tile.entity == null || tile.entity.getTeam() != team || !tile.entity.damaged()) && !(tile.block() instanceof BuildBlock)){
if((tile.entity == null || tile.entity.getTeam() != team || !tile.entity.damaged()) || tile.block() instanceof BuildBlock){
returnArray.add(tile);
}
}
@@ -267,7 +267,7 @@ public class Bullets implements ContentList{
keepVelocity = false;
splashDamageRadius = 25f;
splashDamage = 10f;
lifetime = 50f;
lifetime = 60f;
trailColor = Pal.unitBack;
backColor = Pal.unitBack;
frontColor = Pal.unitFront;
@@ -227,12 +227,14 @@ public class TechTree implements ContentList{
node(turbineGenerator, () -> {
node(thermalGenerator, () -> {
node(rtgGenerator, () -> {
node(differentialGenerator, () -> {
node(thoriumReactor, () -> {
node(impactReactor, () -> {
node(differentialGenerator, () -> {
node(thoriumReactor, () -> {
node(impactReactor, () -> {
});
node(rtgGenerator, () -> {
});
});
});
});
@@ -330,9 +330,9 @@ public class UnitTypes implements ContentList{
baseRotateSpeed = 0.04f;
weapon = new Weapon("lich-missiles"){{
length = 4f;
reload = 180f;
reload = 160f;
width = 22f;
shots = 22;
shots = 16;
shootCone = 100f;
shotDelay = 2;
inaccuracy = 10f;
@@ -341,7 +341,7 @@ public class UnitTypes implements ContentList{
velocityRnd = 0.2f;
spacing = 1f;
bullet = Bullets.missileRevenant;
shootSound = Sounds.missile;
shootSound = Sounds.artillery;
}};
}};
@@ -371,7 +371,18 @@ public class UnitTypes implements ContentList{
inaccuracy = 3f;
roundrobin = true;
ejectEffect = Fx.none;
bullet = Bullets.standardDenseBig;
bullet = new BasicBulletType(7f, 42, "bullet"){
{
bulletWidth = 15f;
bulletHeight = 21f;
shootEffect = Fx.shootBig;
}
@Override
public float range(){
return 165f;
}
};
shootSound = Sounds.shootBig;
}};
}};
+28 -26
View File
@@ -84,7 +84,7 @@ public class Control implements ApplicationListener{
});
Events.on(PlayEvent.class, event -> {
player.setTeam(defaultTeam);
player.setTeam(state.rules.pvp ? netServer.assignTeam(player, playerGroup.all()) : defaultTeam);
player.setDead(true);
player.add();
@@ -237,7 +237,7 @@ public class Control implements ApplicationListener{
public void playMap(Map map, Rules rules){
ui.loadAnd(() -> {
logic.reset();
world.loadMap(map);
world.loadMap(map, rules);
state.rules = rules;
logic.play();
});
@@ -350,35 +350,37 @@ public class Control implements ApplicationListener{
//display UI scale changed dialog
if(Core.settings.getBool("uiscalechanged", false)){
FloatingDialog dialog = new FloatingDialog("$confirm");
Core.app.post(() -> Core.app.post(() -> {
FloatingDialog dialog = new FloatingDialog("$confirm");
dialog.setFillParent(true);
float[] countdown = {60 * 11};
Runnable exit = () -> {
Core.settings.put("uiscale", 100);
Core.settings.put("uiscalechanged", false);
settings.save();
dialog.hide();
Core.app.exit();
};
float[] countdown = {60 * 11};
Runnable exit = () -> {
Core.settings.put("uiscale", 100);
Core.settings.put("uiscalechanged", false);
settings.save();
dialog.hide();
Core.app.exit();
};
dialog.setFillParent(false);
dialog.cont.label(() -> {
if(countdown[0] <= 0){
exit.run();
}
return Core.bundle.format("uiscale.reset", (int)((countdown[0] -= Time.delta()) / 60f));
}).pad(10f).expand().left();
dialog.cont.label(() -> {
if(countdown[0] <= 0){
exit.run();
}
return Core.bundle.format("uiscale.reset", (int)((countdown[0] -= Time.delta()) / 60f));
}).pad(10f).expand().center();
dialog.buttons.defaults().size(200f, 60f);
dialog.buttons.addButton("$uiscale.cancel", exit);
dialog.buttons.defaults().size(200f, 60f);
dialog.buttons.addButton("$uiscale.cancel", exit);
dialog.buttons.addButton("$ok", () -> {
Core.settings.put("uiscalechanged", false);
settings.save();
dialog.hide();
});
dialog.buttons.addButton("$ok", () -> {
Core.settings.put("uiscalechanged", false);
settings.save();
dialog.hide();
});
Core.app.post(dialog::show);
dialog.show();
}));
}
}
@@ -40,7 +40,7 @@ import static io.anuke.mindustry.Vars.*;
public class NetServer implements ApplicationListener{
public final static int maxSnapshotSize = 430;
private final static float serverSyncTime = 15, kickDuration = 30 * 1000;
private final static float serverSyncTime = 12, kickDuration = 30 * 1000;
private final static Vector2 vector = new Vector2();
private final static Rectangle viewport = new Rectangle();
/** If a player goes away of their server-side coordinates by this distance, they get teleported back. */
@@ -176,7 +176,7 @@ public class NetServer implements ApplicationListener{
//playing in pvp mode automatically assigns players to teams
if(state.rules.pvp){
player.setTeam(assignTeam(playerGroup.all()));
player.setTeam(assignTeam(player, playerGroup.all()));
Log.info("Auto-assigned player {0} to team {1}.", player.name, player.getTeam());
}
@@ -194,13 +194,13 @@ public class NetServer implements ApplicationListener{
});
}
public Team assignTeam(Iterable<Player> players){
public Team assignTeam(Player current, Iterable<Player> players){
//find team with minimum amount of players and auto-assign player to that.
return Structs.findMin(Team.all, team -> {
if(state.teams.isActive(team) && !state.teams.get(team).cores.isEmpty()){
int count = 0;
for(Player other : players){
if(other.getTeam() == team){
if(other.getTeam() == team && other != current){
count++;
}
}
@@ -256,7 +256,7 @@ public class Renderer implements ApplicationListener{
draw(playerGroup, p -> true, Player::drawBuildRequests);
if(Entities.countInBounds(shieldGroup) > 0){
if(settings.getBool("animatedshields")){
if(settings.getBool("animatedshields") && Shaders.shield != null){
Draw.flush();
shieldBuffer.begin();
graphics.clear(Color.CLEAR);
+12 -7
View File
@@ -220,6 +220,10 @@ public class World implements ApplicationListener{
}
public void loadMap(Map map){
loadMap(map, new Rules());
}
public void loadMap(Map map, Rules checkRules){
try{
SaveIO.load(map.file, new FilterContext(map));
}catch(Exception e){
@@ -238,20 +242,21 @@ public class World implements ApplicationListener{
invalidMap = false;
if(!headless){
if(state.teams.get(defaultTeam).cores.size == 0){
if(state.teams.get(defaultTeam).cores.size == 0 && !checkRules.pvp){
ui.showError("$map.nospawn");
invalidMap = true;
}else if(state.rules.pvp){ //pvp maps need two cores to be valid
invalidMap = true;
}else if(checkRules.pvp){ //pvp maps need two cores to be valid
int teams = 0;
for(Team team : Team.all){
if(state.teams.get(team).cores.size != 0 && team != defaultTeam){
invalidMap = false;
if(state.teams.get(team).cores.size != 0){
teams ++;
}
}
if(invalidMap){
if(teams < 2){
invalidMap = true;
ui.showError("$map.nospawn.pvp");
}
}else if(state.rules.attackMode){ //pvp maps need two cores to be valid
}else if(checkRules.attackMode){ //attack maps need two cores to be valid
invalidMap = state.teams.get(waveTeam).cores.isEmpty();
if(invalidMap){
ui.showError("$map.nospawn.attack");
@@ -55,7 +55,7 @@ public class Predict{
* See {@link #intercept(float, float, float, float, float, float, float)}.
*/
public static Vector2 intercept(TargetTrait src, TargetTrait dst, float v){
return intercept(src.getX(), src.getY(), dst.getX(), dst.getY(), dst.getTargetVelocityX() - src.getTargetVelocityX(), dst.getTargetVelocityY() - src.getTargetVelocityY(), v);
return intercept(src.getX(), src.getY(), dst.getX(), dst.getY(), dst.getTargetVelocityX() - src.getTargetVelocityX()/2f, dst.getTargetVelocityY() - src.getTargetVelocityY()/2f, v);
}
private static Vector2 quad(float a, float b, float c){
@@ -5,6 +5,7 @@ import io.anuke.arc.math.Mathf;
import io.anuke.arc.util.Time;
import io.anuke.mindustry.content.Fx;
import io.anuke.mindustry.entities.Effects;
import io.anuke.mindustry.gen.*;
import io.anuke.mindustry.graphics.Pal;
public class MissileBulletType extends BasicBulletType{
@@ -18,6 +19,7 @@ public class MissileBulletType extends BasicBulletType{
backColor = Pal.missileYellowBack;
frontColor = Pal.missileYellow;
homingPower = 7f;
hitSound = Sounds.explosion;
}
@Override
@@ -1,33 +1,28 @@
package io.anuke.mindustry.entities.traits;
import io.anuke.annotations.Annotations.*;
import io.anuke.arc.Core;
import io.anuke.arc.Events;
import io.anuke.arc.collection.Array;
import io.anuke.arc.*;
import io.anuke.arc.collection.Queue;
import io.anuke.arc.collection.*;
import io.anuke.arc.graphics.g2d.*;
import io.anuke.arc.math.Angles;
import io.anuke.arc.math.Mathf;
import io.anuke.arc.math.geom.Vector2;
import io.anuke.arc.util.Time;
import io.anuke.mindustry.Vars;
import io.anuke.mindustry.content.Blocks;
import io.anuke.mindustry.entities.type.TileEntity;
import io.anuke.mindustry.entities.type.Unit;
import io.anuke.mindustry.game.EventType.BuildSelectEvent;
import io.anuke.mindustry.gen.Call;
import io.anuke.mindustry.graphics.Pal;
import io.anuke.mindustry.net.Net;
import io.anuke.arc.math.*;
import io.anuke.arc.math.geom.*;
import io.anuke.arc.util.*;
import io.anuke.mindustry.*;
import io.anuke.mindustry.content.*;
import io.anuke.mindustry.entities.type.*;
import io.anuke.mindustry.game.EventType.*;
import io.anuke.mindustry.gen.*;
import io.anuke.mindustry.graphics.*;
import io.anuke.mindustry.world.*;
import io.anuke.mindustry.world.blocks.BuildBlock;
import io.anuke.mindustry.world.blocks.BuildBlock.BuildEntity;
import io.anuke.mindustry.world.blocks.*;
import io.anuke.mindustry.world.blocks.BuildBlock.*;
import java.io.*;
import java.util.Arrays;
import java.util.*;
import static io.anuke.mindustry.Vars.*;
import static io.anuke.mindustry.entities.traits.BuilderTrait.BuildDataStatic.removal;
import static io.anuke.mindustry.entities.traits.BuilderTrait.BuildDataStatic.tmptr;
import static io.anuke.mindustry.entities.traits.BuilderTrait.BuildDataStatic.*;
/** Interface for units that build things.*/
public interface BuilderTrait extends Entity, TeamTrait{
@@ -106,19 +101,14 @@ public interface BuilderTrait extends Entity, TeamTrait{
unit.rotation = Mathf.slerpDelta(unit.rotation, unit.angleTo(entity), 0.4f);
}
//progress is synced, thus not updated clientside
if(!Net.client()){
//deconstructing is 2x as fast
if(current.breaking){
entity.deconstruct(unit, core, 2f / entity.buildCost * Time.delta() * getBuildPower(tile) * state.rules.buildSpeedMultiplier);
}else{
entity.construct(unit, core, 1f / entity.buildCost * Time.delta() * getBuildPower(tile) * state.rules.buildSpeedMultiplier);
}
current.progress = entity.progress();
//deconstructing is 2x as fast
if(current.breaking){
entity.deconstruct(unit, core, 2f / entity.buildCost * Time.delta() * getBuildPower(tile) * state.rules.buildSpeedMultiplier);
}else{
entity.progress = current.progress;
entity.construct(unit, core, 1f / entity.buildCost * Time.delta() * getBuildPower(tile) * state.rules.buildSpeedMultiplier);
}
current.progress = entity.progress;
}
/** Returns the queue for storing build requests. */
@@ -135,7 +125,7 @@ public interface BuilderTrait extends Entity, TeamTrait{
default void writeBuilding(DataOutput output) throws IOException{
BuildRequest request = buildRequest();
if(request != null){
if(request != null && (request.block != null || request.breaking)){
output.writeByte(request.breaking ? 1 : 0);
output.writeInt(Pos.get(request.x, request.y));
output.writeFloat(request.progress);
@@ -174,7 +164,11 @@ public interface BuilderTrait extends Entity, TeamTrait{
if(applyChanges){
buildQueue().addLast(request);
}else if(isBuilding()){
buildRequest().progress = progress;
BuildRequest last = buildRequest();
last.progress = progress;
if(last.tile() != null && last.tile().entity instanceof BuildEntity){
((BuildEntity)last.tile().entity).progress = progress;
}
}
}
}
@@ -285,6 +279,10 @@ public interface BuilderTrait extends Entity, TeamTrait{
this.breaking = true;
}
public Tile tile(){
return world.tile(x, y);
}
@Override
public String toString(){
return "BuildRequest{" +
@@ -70,7 +70,6 @@ public class Player extends Unit implements BuilderMinerTrait, ShooterTrait{
private Tile mining;
private Vector2 movement = new Vector2();
private boolean moved;
private SoundLoop buildSound = new SoundLoop(Sounds.build, 0.75f);
//endregion
@@ -131,11 +130,6 @@ public class Player extends Unit implements BuilderMinerTrait, ShooterTrait{
}
}
@Override
public void removed(){
buildSound.stop();
}
@Override
public float drag(){
return mech.drag;
@@ -514,11 +508,13 @@ public class Player extends Unit implements BuilderMinerTrait, ShooterTrait{
}
if(!isDead() && isFlying()){
loops.play(Sounds.thruster, this, Mathf.clamp(velocity.len() * 2f) * 0.4f);
loops.play(Sounds.thruster, this, Mathf.clamp(velocity.len() * 2f) * 0.3f);
}
BuildRequest request = buildRequest();
buildSound.update(request == null ? x : request.x * tilesize, request == null ? y : request.y * tilesize, isBuilding() && (Mathf.within(request.x * tilesize, request.y * tilesize, x, y, placeDistance) || state.isEditor()));
if(isBuilding() && request.tile() != null && (request.tile().withinDst(x, y, placeDistance) || state.isEditor())){
loops.play(Sounds.build, request.tile(), 0.75f);
}
if(isDead()){
isBoosting = false;
@@ -531,7 +527,9 @@ public class Player extends Unit implements BuilderMinerTrait, ShooterTrait{
spawner = null;
}
avoidOthers();
if(isLocal || Net.server()){
avoidOthers();
}
Tile tile = world.tileWorld(x, y);
@@ -5,6 +5,7 @@ import io.anuke.mindustry.entities.type.TileEntity;
import io.anuke.mindustry.entities.units.UnitState;
import io.anuke.mindustry.world.Pos;
import io.anuke.mindustry.world.Tile;
import io.anuke.mindustry.world.blocks.*;
import java.io.*;
@@ -23,6 +24,10 @@ public class RepairDrone extends BaseDrone{
target = Units.findDamagedTile(team, x, y);
}
if(target instanceof TileEntity && ((TileEntity)target).block instanceof BuildBlock){
target = null;
}
if(target != null){
if(target.dst(RepairDrone.this) > type.range){
circle(type.range * 0.9f);
@@ -27,8 +27,13 @@ public class EventType{
}
}
/** Called when the game is first loaded. */
public static class GameLoadEvent{
/** Called when the client game is first loaded. */
public static class ClientLoadEvent{
}
/** Called when the core app is first loaded. */
public static class AppLoadEvent{
}
@@ -14,7 +14,7 @@ import static io.anuke.mindustry.Vars.*;
/** Controls playback of multiple music tracks.*/
public class MusicControl{
private static final float finTime = 120f, foutTime = 120f, musicInterval = 60 * 60 * 3f, musicChance = 0.3f, musicWaveChance = 0.24f;
private static final float finTime = 120f, foutTime = 120f, musicInterval = 60 * 60 * 3f, musicChance = 0.45f, musicWaveChance = 0.35f;
/** normal, ambient music, plays at any time */
public final Array<Music> ambientMusic = Array.with(Musics.game1, Musics.game3, Musics.game4, Musics.game6);
+4 -2
View File
@@ -26,8 +26,10 @@ public class Stats{
public RankResult calculateRank(Zone zone, boolean launched){
float score = 0;
//each new launch period adds onto the rank 'points'
if(wavesLasted >= zone.conditionWave){
if(launched && zone.getRules().attackMode){
score += 3f;
}else if(wavesLasted >= zone.conditionWave){
//each new launch period adds onto the rank 'points'
score += (float)((wavesLasted - zone.conditionWave) / zone.launchPeriod + 1) * 1.2f;
}
@@ -1,5 +1,6 @@
package io.anuke.mindustry.graphics;
import io.anuke.annotations.Annotations.*;
import io.anuke.arc.Core;
import io.anuke.arc.graphics.Color;
import io.anuke.arc.graphics.g2d.TextureRegion;
@@ -10,7 +11,7 @@ import io.anuke.arc.util.Time;
public class Shaders{
public static Shadow shadow;
public static BlockBuild blockbuild;
public static Shield shield;
public static @Nullable Shield shield;
public static UnitBuild build;
public static FogShader fog;
public static MenuShader menu;
@@ -19,7 +20,13 @@ public class Shaders{
public static void init(){
shadow = new Shadow();
blockbuild = new BlockBuild();
shield = new Shield();
try{
shield = new Shield();
}catch(Throwable t){
//don't load shield shader
shield = null;
t.printStackTrace();
}
build = new UnitBuild();
fog = new FogShader();
menu = new MenuShader();
@@ -131,7 +131,7 @@ public class DesktopInput extends InputHandler{
player.isShooting = false;
}
if(!state.is(State.menu) && Core.input.keyTap(Binding.minimap) && !ui.chatfrag.chatOpen() && !(scene.getKeyboardFocus() instanceof TextField)){
if(!state.is(State.menu) && Core.input.keyTap(Binding.minimap) && (scene.getKeyboardFocus() == ui.minimap || !scene.hasDialog()) && !ui.chatfrag.chatOpen() && !(scene.getKeyboardFocus() instanceof TextField)){
if(!ui.minimap.isShown()){
ui.minimap.show();
}else{
+6 -1
View File
@@ -214,7 +214,12 @@ public class Maps implements Disposable{
return filters;
}else{
return JsonIO.read(Array.class, str);
try{
return JsonIO.read(Array.class, str.replace("mindustrz", "mindustry"));
}catch(Exception e){
e.printStackTrace();
return readFilters("");
}
}
}
@@ -17,7 +17,6 @@ public class MirrorFilter extends GenerateFilter{
{
options(new SliderOption("angle", () -> angle, f -> angle = (int)f, 0, 360, 45));
buffered = true;
}
@Override
@@ -1,14 +1,15 @@
package io.anuke.mindustry.net;
import io.anuke.arc.math.Mathf;
import io.anuke.arc.math.geom.Vector2;
import io.anuke.arc.util.Time;
import io.anuke.arc.math.*;
import io.anuke.arc.math.geom.*;
import io.anuke.arc.util.*;
public class Interpolator{
//used for movement
public Vector2 target = new Vector2();
public Vector2 last = new Vector2();
public float[] targets = {};
public float[] lasts = {};
public long lastUpdated, updateSpacing;
//current state
@@ -21,6 +22,12 @@ public class Interpolator{
lastUpdated = Time.millis();
targets = target1ds;
if(lasts.length != values.length){
lasts = new float[values.length];
}
for(int i = 0; i < values.length; i++){
lasts[i] = values[i];
}
last.set(cx, cy);
target.set(x, y);
}
@@ -46,8 +53,12 @@ public class Interpolator{
values = new float[targets.length];
}
if(lasts.length != targets.length){
lasts = new float[targets.length];
}
for(int i = 0; i < values.length; i++){
values[i] = Mathf.slerp(values[i], targets[i], alpha);
values[i] = Mathf.slerp(lasts[i], targets[i], alpha);
}
}else{
pos.set(target);
+61 -32
View File
@@ -1,19 +1,18 @@
package io.anuke.mindustry.net;
import io.anuke.arc.Core;
import io.anuke.arc.*;
import io.anuke.arc.collection.*;
import io.anuke.arc.function.BiConsumer;
import io.anuke.arc.function.Consumer;
import io.anuke.arc.function.*;
import io.anuke.arc.util.*;
import io.anuke.arc.util.pooling.Pools;
import io.anuke.mindustry.core.Platform;
import io.anuke.mindustry.gen.Call;
import io.anuke.arc.util.pooling.*;
import io.anuke.mindustry.core.*;
import io.anuke.mindustry.gen.*;
import io.anuke.mindustry.net.Packets.*;
import io.anuke.mindustry.net.Streamable.StreamBuilder;
import io.anuke.mindustry.net.Streamable.*;
import net.jpountz.lz4.*;
import java.io.IOException;
import java.nio.BufferOverflowException;
import java.nio.BufferUnderflowException;
import java.io.*;
import java.nio.*;
import static io.anuke.mindustry.Vars.*;
@@ -28,6 +27,8 @@ public class Net{
private static ClientProvider clientProvider;
private static ServerProvider serverProvider;
private static IntMap<StreamBuilder> streams = new IntMap<>();
private static final LZ4FastDecompressor decompressor = LZ4Factory.fastestInstance().fastDecompressor();
private static final LZ4Compressor compressor = LZ4Factory.fastestInstance().fastCompressor();
/** Display a network error. Call on the graphics thread. */
public static void showError(Throwable e){
@@ -144,11 +145,11 @@ public class Net{
}
public static byte[] compressSnapshot(byte[] input){
return serverProvider.compressSnapshot(input);
return compressor.compress(input);
}
public static byte[] decompressSnapshot(byte[] input, int size){
return clientProvider.decompressSnapshot(input, size);
return decompressor.decompress(input, size);
}
/**
@@ -162,8 +163,8 @@ public class Net{
/**
* Returns a list of all connections IDs.
*/
public static Array<NetConnection> getConnections(){
return (Array<NetConnection>)serverProvider.getConnections();
public static Iterable<NetConnection> getConnections(){
return (Iterable<NetConnection>)serverProvider.getConnections();
}
/**
@@ -326,7 +327,7 @@ public class Net{
public static void dispose(){
if(clientProvider != null) clientProvider.dispose();
if(serverProvider != null) serverProvider.dispose();
if(serverProvider != null) serverProvider.close();
clientProvider = null;
serverProvider = null;
server = false;
@@ -354,9 +355,6 @@ public class Net{
/** Disconnect from the server. */
void disconnect();
/** Decompress an input snapshot byte array. */
byte[] decompressSnapshot(byte[] input, int size);
/**
* Discover servers. This should run the callback regardless of whether any servers are found. Should not block.
* Callback should be run on libGDX main thread.
@@ -377,30 +375,61 @@ public class Net{
void host(int port) throws IOException;
/** Sends a large stream of data to a specific client. */
void sendStream(int id, Streamable stream);
default void sendStream(int id, Streamable stream){
NetConnection connection = getByID(id);
if(connection == null) return;
try{
int cid;
StreamBegin begin = new StreamBegin();
begin.total = stream.stream.available();
begin.type = Registrator.getID(stream.getClass());
connection.send(begin, SendMode.tcp);
cid = begin.id;
/** Send an object to everyone connected. */
void send(Object object, SendMode mode);
while(stream.stream.available() > 0){
byte[] bytes = new byte[Math.min(512, stream.stream.available())];
stream.stream.read(bytes);
/** Send an object to a specific client ID. */
void sendTo(int id, Object object, SendMode mode);
StreamChunk chunk = new StreamChunk();
chunk.id = cid;
chunk.data = bytes;
connection.send(chunk, SendMode.tcp);
}
}catch(IOException e){
throw new RuntimeException(e);
}
}
/** Send an object to everyone <i>except</i> a client ID. */
void sendExcept(int id, Object object, SendMode mode);
default void send(Object object, SendMode mode){
for(NetConnection con : getConnections()){
con.send(object, mode);
}
}
default void sendTo(int id, Object object, SendMode mode){
NetConnection conn = getByID(id);
if(conn == null){
Log.err("Failed to find connection with ID {0}.", id);
return;
}
conn.send(object, mode);
}
default void sendExcept(int id, Object object, SendMode mode){
for(NetConnection con : getConnections()){
if(con.id != id){
con.send(object, mode);
}
}
}
/** Close the server connection. */
void close();
/** Compress an input snapshot byte array. */
byte[] compressSnapshot(byte[] input);
/** Return all connected users. */
Array<? extends NetConnection> getConnections();
Iterable<? extends NetConnection> getConnections();
/** Returns a connection by ID. */
NetConnection getByID(int id);
/** Close all connections. */
void dispose();
}
}
@@ -3,6 +3,8 @@ package io.anuke.mindustry.net;
import io.anuke.mindustry.net.Net.SendMode;
public abstract class NetConnection{
private static int lastID;
public final int id;
public final String address;
@@ -18,8 +20,9 @@ public abstract class NetConnection{
public boolean hasBegunConnecting = false;
public float viewWidth, viewHeight, viewX, viewY;
public NetConnection(int id, String address){
this.id = id;
/** Assigns this connection a unique ID. No two connections will ever have the same ID.*/
public NetConnection(String address){
this.id = lastID++;
this.address = address;
}
@@ -31,7 +31,6 @@ public class FileChooser extends FloatingDialog{
private Predicate<FileHandle> filter;
private Consumer<FileHandle> selectListener;
private boolean open;
private int lastWidth = Core.graphics.getWidth(), lastHeight = Core.graphics.getHeight();
public static final Predicate<String> pngFiles = str -> str.equals("png");
public static final Predicate<String> anyMapFiles = str -> str.equals(oldMapExtension) || str.equals(mapExtension);
@@ -44,12 +43,14 @@ public class FileChooser extends FloatingDialog{
this.filter = filter;
this.selectListener = result;
update(() -> {
if(Core.graphics.getWidth() != lastWidth || Core.graphics.getHeight() != lastHeight){
updateFiles(false);
lastHeight = Core.graphics.getHeight();
lastWidth = Core.graphics.getWidth();
}
onResize(() -> {
cont.clear();
setupWidgets();
});
shown(() -> {
cont.clear();
setupWidgets();
});
}
@@ -121,8 +122,9 @@ public class FileChooser extends FloatingDialog{
forward.resizeImage(isize);
forward.clicked(() -> stack.forward());
back.clicked(() -> stack.back());
forward.setDisabled(() -> !stack.canForward());
back.setDisabled(() -> !stack.canBack());
ImageButton home = new ImageButton("icon-home");
home.resizeImage(isize);
@@ -206,7 +208,7 @@ public class FileChooser extends FloatingDialog{
//macs are confined to the Downloads/ directory
if(!OS.isMac){
Image upimage = new Image("icon-folder-parent");
Image upimage = new Image("icon-folder-parent-small");
TextButton upbutton = new TextButton(".." + directory.toString(), "clear-toggle");
upbutton.clicked(() -> {
directory = directory.parent();
@@ -214,7 +216,7 @@ public class FileChooser extends FloatingDialog{
updateFiles(true);
});
upbutton.left().add(upimage).padRight(4f).size(iconsize);
upbutton.left().add(upimage).padRight(4f).size(iconsizesmall).padLeft(4);
upbutton.getLabel().setAlignment(Align.left);
upbutton.getCells().reverse();
@@ -248,9 +250,9 @@ public class FileChooser extends FloatingDialog{
button.setChecked(filename.equals(filefield.getText()));
});
Image image = new Image(file.isDirectory() ? "icon-folder" : "icon-file-text");
Image image = new Image(file.isDirectory() ? "icon-folder-small" : "icon-file-text-small");
button.add(image).padRight(4f).size(iconsize);
button.add(image).padRight(4f).padLeft(4).size(iconsizesmall);
button.getCells().reverse();
files.top().left().add(button).align(Align.topLeft).fillX().expandX()
.height(50).pad(2).padTop(0).padBottom(0).colspan(2);
@@ -273,17 +275,6 @@ public class FileChooser extends FloatingDialog{
}
}
@Override
public Dialog show(){
Time.runTask(2f, () -> {
cont.clear();
setupWidgets();
super.show();
Core.scene.setScrollFocus(pane);
});
return this;
}
public class FileHistory{
private Array<FileHandle> history = new Array<>();
private int index;
@@ -39,18 +39,6 @@ public class FloatingDialog extends Dialog{
state.set(State.paused);
}
});
boolean[] done = {false};
shown(() -> Core.app.post(() ->
forEach(child -> {
if(done[0]) return;
if(child instanceof ScrollPane){
Core.scene.setScrollFocus(child);
done[0] = true;
}
})));
}
public FloatingDialog(String title){
@@ -59,8 +47,9 @@ public class FloatingDialog extends Dialog{
protected void onResize(Runnable run){
Events.on(ResizeEvent.class, event -> {
if(isShown()){
if(isShown() && Core.scene.getDialog() == this){
run.run();
updateScrollFocus();
}
});
}
@@ -1,11 +1,11 @@
package io.anuke.mindustry.ui.dialogs;
import io.anuke.arc.Core;
import io.anuke.mindustry.core.GameState.State;
import io.anuke.mindustry.game.Stats.RankResult;
import io.anuke.mindustry.game.Team;
import io.anuke.mindustry.type.Item;
import io.anuke.mindustry.type.Item.Icon;
import io.anuke.arc.*;
import io.anuke.mindustry.core.GameState.*;
import io.anuke.mindustry.game.Stats.*;
import io.anuke.mindustry.game.*;
import io.anuke.mindustry.type.*;
import io.anuke.mindustry.type.Item.*;
import static io.anuke.mindustry.Vars.*;
@@ -1,21 +1,20 @@
package io.anuke.mindustry.ui.dialogs;
import io.anuke.annotations.Annotations.Serialize;
import io.anuke.arc.Core;
import io.anuke.arc.collection.Array;
import io.anuke.arc.graphics.Color;
import io.anuke.arc.math.Mathf;
import io.anuke.arc.scene.style.Drawable;
import io.anuke.annotations.Annotations.*;
import io.anuke.arc.*;
import io.anuke.arc.collection.*;
import io.anuke.arc.graphics.*;
import io.anuke.arc.math.*;
import io.anuke.arc.scene.style.*;
import io.anuke.arc.scene.ui.*;
import io.anuke.arc.scene.ui.layout.Cell;
import io.anuke.arc.scene.ui.layout.Table;
import io.anuke.arc.util.Strings;
import io.anuke.arc.util.Time;
import io.anuke.mindustry.Vars;
import io.anuke.mindustry.core.Platform;
import io.anuke.mindustry.game.Version;
import io.anuke.mindustry.net.Host;
import io.anuke.arc.scene.ui.layout.*;
import io.anuke.arc.util.*;
import io.anuke.mindustry.*;
import io.anuke.mindustry.core.*;
import io.anuke.mindustry.game.*;
import io.anuke.mindustry.net.Net;
import io.anuke.mindustry.net.*;
import io.anuke.mindustry.net.Packets.*;
import static io.anuke.mindustry.Vars.*;
@@ -97,9 +96,14 @@ public class JoinDialog extends FloatingDialog{
TextButton button = buttons[0] = remote.addButton("[accent]" + server.displayIP(), "clear", () -> {
if(!buttons[0].childrenPressed()){
connect(server.ip, server.port);
if(server.lastHost != null && server.lastHost.version != Version.build && Version.build != -1 && server.lastHost.version != -1){
ui.showInfo("[scarlet]" + (server.lastHost.version > Version.build ? KickReason.clientOutdated : KickReason.serverOutdated).toString() + "\n[]" +
Core.bundle.format("server.versions", Version.build, server.lastHost.version));
}else{
connect(server.ip, server.port);
}
}
}).width(targetWidth()).height(130f).pad(4f).get();
}).width(targetWidth()).pad(4f).get();
button.getLabel().setWrap(true);
@@ -106,7 +106,7 @@ public class PausedDialog extends FloatingDialog{
return;
}
if(control.saves.getCurrent() == null || !control.saves.getCurrent().isAutosave() || state.rules.tutorial){
if(control.saves.getCurrent() == null || !control.saves.getCurrent().isAutosave() || state.rules.tutorial || wasClient){
state.set(State.menu);
logic.reset();
return;
@@ -241,7 +241,9 @@ public class SettingsMenuDialog extends SettingsDialog{
graphics.checkPref("fps", false);
graphics.checkPref("indicators", true);
graphics.checkPref("animatedwater", false);
graphics.checkPref("animatedshields", !mobile);
if(Shaders.shield != null){
graphics.checkPref("animatedshields", !mobile);
}
graphics.checkPref("bloom", false, val -> renderer.toggleBloom(val));
graphics.checkPref("lasers", true);
graphics.checkPref("pixelate", false);
@@ -113,9 +113,16 @@ public class ZoneInfoDialog extends FloatingDialog{
t.add("$zone.resources").padRight(6);
if(zone.resources.length > 0){
for(Item item : zone.resources){
t.addImage(item.icon(Item.Icon.medium)).size(8 * 3);
}
t.table(r -> {
t.left();
int i = 0;
for(Item item : zone.resources){
r.addImage(item.icon(Item.Icon.medium)).size(8 * 3);
if(++i % 4 == 0){
r.row();
}
}
});
}else{
t.add("$none");
}
@@ -242,9 +242,9 @@ public class HudFragment extends Fragment{
IntFormat fps = new IntFormat("fps");
IntFormat ping = new IntFormat("ping");
info.label(() -> fps.get(Core.graphics.getFramesPerSecond())).left();
info.label(() -> fps.get(Core.graphics.getFramesPerSecond())).left().style("outline");
info.row();
info.label(() -> ping.get(Net.getPing())).visible(Net::client).left();
info.label(() -> ping.get(Net.getPing())).visible(Net::client).left().style("outline");
}).top().left();
});
+1 -3
View File
@@ -294,9 +294,7 @@ public class Block extends BlockStorage{
/** Called after the block is placed by this client. */
@CallSuper
public void playerPlaced(Tile tile){
if(outputsPower && !consumesPower){
PowerNode.lastPlaced = tile.pos();
}
}
/** Called after the block is placed by anyone. */
@@ -2,6 +2,7 @@ package io.anuke.mindustry.world.blocks.power;
import io.anuke.annotations.Annotations.*;
import io.anuke.arc.*;
import io.anuke.arc.collection.*;
import io.anuke.arc.function.*;
import io.anuke.arc.graphics.*;
import io.anuke.arc.graphics.g2d.*;
@@ -20,9 +21,7 @@ import io.anuke.mindustry.world.meta.*;
import static io.anuke.mindustry.Vars.*;
public class PowerNode extends PowerBlock{
//last distribution block placed
public static int lastPlaced = -1;
protected ObjectSet<PowerGraph> graphs = new ObjectSet<>();
protected Vector2 t1 = new Vector2(), t2 = new Vector2();
protected TextureRegion laser, laserEnd;
@@ -99,23 +98,11 @@ public class PowerNode extends PowerBlock{
() -> Mathf.clamp(entity.power.graph.getPowerProduced() / entity.power.graph.getPowerNeeded())));
}
@Override
public void playerPlaced(Tile tile){
Tile before = world.tile(lastPlaced);
if(linkValid(tile, before) && !before.entity.proximity().contains(tile)){
Call.linkPowerNodes(null, tile, before);
}
lastPlaced = tile.pos();
super.playerPlaced(tile);
}
@Override
public void placed(Tile tile){
if(Net.client()) return;
Predicate<Tile> valid = other -> other != null && other != tile && ((!other.block().outputsPower && other.block().consumesPower) || (other.block().outputsPower && !other.block().consumesPower)) && linkValid(tile, other)
Predicate<Tile> valid = other -> other != null && other != tile && ((!other.block().outputsPower && other.block().consumesPower) || (other.block().outputsPower && !other.block().consumesPower) || other.block() instanceof PowerNode) && linkValid(tile, other)
&& !other.entity.proximity().contains(tile) && other.entity.power.graph != tile.entity.power.graph;
tempTiles.clear();
@@ -132,6 +119,28 @@ public class PowerNode extends PowerBlock{
super.placed(tile);
}
private void getPotentialLinks(Tile tile, Consumer<Tile> others){
Predicate<Tile> valid = other -> other != null && other != tile && other.entity != null && other.entity.power != null &&
((!other.block().outputsPower && other.block().consumesPower) || (other.block().outputsPower && !other.block().consumesPower) || other.block() instanceof PowerNode) &&
overlaps(tile.x * tilesize + offset(), tile.y *tilesize + offset(), other, laserRange * tilesize)
&& !other.entity.proximity().contains(tile) && !graphs.contains(other.entity.power.graph);
tempTiles.clear();
graphs.clear();
Geometry.circle(tile.x, tile.y, (int)(laserRange + 1), (x, y) -> {
Tile other = world.ltile(x, y);
if(valid.test(other)){
tempTiles.add(other);
}
});
tempTiles.sort(Structs.comparingFloat(t -> t.dst2(tile)));
tempTiles.each(valid, t -> {
graphs.add(t.entity.power.graph);
others.accept(t);
});
}
@Override
public void setStats(){
super.setStats();
@@ -213,6 +222,11 @@ public class PowerNode extends PowerBlock{
Draw.color(Pal.placing);
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);
});
/*
for(int cx = (int)(x - laserRange - 1); cx <= x + laserRange + 1; cx++){
for(int cy = (int)(y - laserRange - 1); cy <= y + laserRange + 1; cy++){
Tile link = world.ltile(cx, cy);
@@ -221,7 +235,7 @@ public class PowerNode extends PowerBlock{
Drawf.square(link.drawx(), link.drawy(), link.block().size * tilesize / 2f + 2f, link.pos() == lastPlaced ? Pal.place : Pal.accent);
}
}
}
}*/
Draw.reset();
}
@@ -67,7 +67,7 @@ public class Drill extends Block{
hasItems = true;
idleSound = Sounds.drill;
idleSoundVolume = 0.002f;
idleSoundVolume = 0.003f;
}
@Override
@@ -12,6 +12,11 @@ public class LiquidConverter extends GenericCrafter{
hasLiquids = true;
}
@Override
public boolean outputsItems(){
return false;
}
@Override
public void init(){
ConsumeLiquidBase cl = consumes.get(ConsumeType.liquid);
-87
View File
@@ -1,87 +0,0 @@
apply plugin: "java"
sourceCompatibility = 1.8
sourceSets.main.java.srcDirs = [ "src/" ]
project.ext.mainClassName = "io.anuke.mindustry.desktopsdl.DesktopLauncher"
project.ext.assetsDir = new File("../core/assets")
def IKVM_DIR = System.env.IKVM_HOME
def getTarget = { return project.hasProperty("target") ? project.properties["target"] : "windows" }
task run(dependsOn: classes, type: JavaExec){
main = project.mainClassName
classpath = sourceSets.main.runtimeClasspath
standardInput = System.in
workingDir = project.assetsDir
ignoreExitValue = true
if(System.getProperty("os.name").toLowerCase().contains("mac")){
jvmArgs("-XstartOnFirstThread", "-Djava.awt.headless=true")
}
if(project.hasProperty("args")){
args Eval.me(project.getProperties()["args"])
}
if(args.contains("debug")){
main = "io.anuke.mindustry.DebugLauncher"
}
}
task dist(type: Jar, dependsOn: classes){
from files(sourceSets.main.output.classesDirs)
from files(sourceSets.main.output.resourcesDir)
from {configurations.compile.collect {zipTree(it)}}
from files(project.assetsDir)
//use target = all for all platforms
def target = getTarget()
if(target.contains("windows")) exclude('**.so', "**.dylib")
if(target == "mac") exclude('**.so', "**.dll")
if(target == "linux") exclude('**.dll', "**.dylib")
archivesBaseName = appName + "-" + target
manifest{
attributes 'Main-Class': project.mainClassName
}
}
task ikZip(type: Zip){
def filename = "$appName-${getTarget()}-${version}"
from "build/libs/$filename"
archiveName = "${generateDeployName(getTarget())}.zip"
}
task ikdist{
dependsOn dist
finalizedBy ikZip
doLast{
def filename = "$appName-${getTarget()}-${version}"
def folder = "build/libs/$filename"
def baseArgs = System.properties['os.name'].toLowerCase().contains('windows') ? [] : ["mono"]
def args = baseArgs + ["$IKVM_DIR/ikvmc.exe", "-target:winexe", "-out:build/libs/${filename}.exe", "build/libs/${filename}.jar"]
if(file("../core/assets/sprites/icon.ico").exists()){
args += ["-win32icon:../core/assets/sprites/icon.ico"]
}else if(file("../core/assets/icons/icon.ico").exists()){
args += ["-win32icon:../core/assets/icons/icon.ico"]
}
exec{
commandLine args
}
copy{
from file("build/libs/${filename}.exe")
into file(folder)
}
copy{
from(getTarget().contains("32") ? "$IKVM_DIR/libraries_32" : "$IKVM_DIR/libraries")
into folder
}
}
}
@@ -1,30 +0,0 @@
package io.anuke.mindustry.desktopsdl;
import io.anuke.arc.Files.*;
import io.anuke.arc.backends.sdl.*;
import io.anuke.mindustry.*;
import io.anuke.mindustry.core.*;
import io.anuke.mindustry.net.*;
public class DesktopLauncher{
public static void main(String[] arg){
try{
Platform.instance = new DesktopPlatform(arg);
Net.setClientProvider(new ArcNetClient());
Net.setServerProvider(new ArcNetServer());
new SdlApplication(new Mindustry(), new SdlConfig(){{
title = "Mindustry";
maximized = true;
depth = 0;
stencil = 0;
width = 900;
height = 700;
setWindowIcon(FileType.Internal, "icons/icon_64.png");
}});
}catch(Throwable e){
DesktopPlatform.handleCrash(e);
}
}
}
@@ -1,138 +0,0 @@
package io.anuke.mindustry.desktopsdl;
import club.minnced.discord.rpc.*;
import io.anuke.arc.backends.sdl.jni.SDL;
import io.anuke.arc.collection.*;
import io.anuke.arc.files.*;
import io.anuke.arc.function.*;
import io.anuke.arc.util.*;
import io.anuke.arc.util.serialization.*;
import io.anuke.mindustry.core.GameState.*;
import io.anuke.mindustry.core.*;
import io.anuke.mindustry.net.*;
import io.anuke.mindustry.ui.dialogs.*;
import java.net.*;
import java.util.*;
import static io.anuke.mindustry.Vars.*;
public class DesktopPlatform extends Platform{
static boolean useDiscord = OS.is64Bit;
final static String applicationId = "610508934456934412";
String[] args;
public DesktopPlatform(String[] args){
this.args = args;
testMobile = Array.with(args).contains("-testMobile");
if(useDiscord){
try{
DiscordEventHandlers handlers = new DiscordEventHandlers();
DiscordRPC.INSTANCE.Discord_Initialize(applicationId, handlers, true, "");
Runtime.getRuntime().addShutdownHook(new Thread(DiscordRPC.INSTANCE::Discord_Shutdown));
}catch(Throwable t){
useDiscord = false;
Log.err("Failed to initialize discord.", t);
}
}
}
static void handleCrash(Throwable e){
Consumer<Runnable> dialog = Runnable::run;
boolean badGPU = false;
if(e.getMessage() != null && (e.getMessage().contains("Couldn't create window") || e.getMessage().contains("OpenGL 2.0 or higher"))){
dialog.accept(() -> message(
e.getMessage().contains("Couldn't create window") ? "A graphics initialization error has occured! Try to update your graphics drivers:\n" + e.getMessage() :
"Your graphics card does not support OpenGL 2.0!\n" +
"Try to update your graphics drivers.\n\n" +
"(If that doesn't work, your computer just doesn't support Mindustry.)"));
badGPU = true;
}
boolean fbgp = badGPU;
CrashSender.send(e, file -> {
if(!fbgp){
dialog.accept(() -> message("A crash has occured. It has been saved in:\n" + file.getAbsolutePath() + "\n" + (e.getMessage() == null ? "" : "\n" + e.getMessage())));
}
});
}
@Override
public void showFileChooser(String text, String content, Consumer<FileHandle> cons, boolean open, Predicate<String> filetype){
new FileChooser(text, file -> filetype.test(file.extension().toLowerCase()), open, cons).show();
}
@Override
public void updateRPC(){
if(!useDiscord) return;
DiscordRichPresence presence = new DiscordRichPresence();
if(!state.is(State.menu)){
String map = world.getMap() == null ? "Unknown Map" : world.isZone() ? world.getZone().localizedName : Strings.capitalize(world.getMap().name());
String mode = state.rules.pvp ? "PvP" : state.rules.attackMode ? "Attack" : "Survival";
String players = Net.active() && playerGroup.size() > 1 ? " | " + playerGroup.size() + " Players" : "";
presence.state = mode + players;
if(!state.rules.waves){
presence.details = map;
}else{
presence.details = map + " | Wave " + state.wave;
presence.largeImageText = "Wave " + state.wave;
}
}else{
if(ui.editor != null && ui.editor.isShown()){
presence.state = "In Editor";
}else if(ui.deploy != null && ui.deploy.isShown()){
presence.state = "In Launch Selection";
}else{
presence.state = "In Menu";
}
}
presence.largeImageKey = "logo";
DiscordRPC.INSTANCE.Discord_UpdatePresence(presence);
}
@Override
public String getUUID(){
try{
Enumeration<NetworkInterface> e = NetworkInterface.getNetworkInterfaces();
NetworkInterface out;
for(out = e.nextElement(); (out.getHardwareAddress() == null || !validAddress(out.getHardwareAddress())) && e.hasMoreElements(); out = e.nextElement());
byte[] bytes = out.getHardwareAddress();
byte[] result = new byte[8];
System.arraycopy(bytes, 0, result, 0, bytes.length);
String str = new String(Base64Coder.encode(result));
if(str.equals("AAAAAAAAAOA=") || str.equals("AAAAAAAAAAA=")) throw new RuntimeException("Bad UUID.");
return str;
}catch(Exception e){
return super.getUUID();
}
}
private static void message(String message){
SDL.SDL_ShowSimpleMessageBox(SDL.SDL_MESSAGEBOX_ERROR, "oh no", message);
}
private boolean validAddress(byte[] bytes){
if(bytes == null) return false;
byte[] result = new byte[8];
System.arraycopy(bytes, 0, result, 0, bytes.length);
return !new String(Base64Coder.encode(result)).equals("AAAAAAAAAOA=") && !new String(Base64Coder.encode(result)).equals("AAAAAAAAAAA=");
}
}
+99 -135
View File
@@ -1,43 +1,28 @@
import com.badlogicgames.packr.Packr
import com.badlogicgames.packr.PackrConfig
apply plugin: "java"
sourceCompatibility = 1.8
sourceSets.main.java.srcDirs = ["src/"]
sourceSets.main.java.srcDirs = [ "src/" ]
project.ext.mainClassName = "io.anuke.mindustry.desktop.DesktopLauncher"
project.ext.assetsDir = new File("../core/assets")
def IKVM_DIR = System.env.IKVM_HOME
import com.badlogicgames.packr.Packr
import com.badlogicgames.packr.PackrConfig
def JDK_DIR = "$System.env.PACKR_DIR"
def ICON_DIR = new File("core/assets/icons/icon.icns")
ext.getPlatform = {
def lc = project.hasProperty("platform") ? platform.toLowerCase() : ""
if(lc == "windows64"){
return PackrConfig.Platform.Windows64
}else if(lc == "windows32"){
return PackrConfig.Platform.Windows32
}else if(lc == "linux"){
return PackrConfig.Platform.Linux64
}else if(lc == "mac"){
return PackrConfig.Platform.MacOS
}else{
throw new InvalidUserDataException("Invalid platform. Set platform with -Pplatform=windows64/windows32/linux/mac")
}
}
task run(dependsOn: classes, type: JavaExec){
main = project.mainClassName
classpath = sourceSets.main.runtimeClasspath
standardInput = System.in
workingDir = project.assetsDir
if(System.getProperty("os.name").toLowerCase().contains("mac")){
jvmArgs "-XstartOnFirstThread"
}
ignoreExitValue = true
if(System.getProperty("os.name").toLowerCase().contains("mac")){
jvmArgs("-XstartOnFirstThread", "-Djava.awt.headless=true")
}
if(project.hasProperty("args")){
args Eval.me(project.getProperties()["args"])
}
@@ -47,132 +32,111 @@ task run(dependsOn: classes, type: JavaExec){
}
}
task debug(dependsOn: classes, type: JavaExec){
main = project.mainClassName
classpath = sourceSets.main.runtimeClasspath
standardInput = System.in
workingDir = project.assetsDir
ignoreExitValue = true
debug = true
}
task dist(type: Jar){
dependsOn classes
writeVersion()
task dist(type: Jar, dependsOn: classes){
from files(sourceSets.main.output.classesDirs)
from files(sourceSets.main.output.resourcesDir)
from{ configurations.compile.collect{ zipTree(it) } }
from {configurations.compile.collect {zipTree(it)}}
from files(project.assetsDir)
archiveName = "${appName}.jar"
manifest{
attributes 'Main-Class': project.mainClassName
}
}
//note: call desktop:dist beforehand
task packrCmd(){
doLast{
def config = new PackrConfig()
config.with{
config.executable = appName
verbose = true
platform = getPlatform()
bundleIdentifier = getPackage() + ".mac"
iconResource = ICON_DIR
outDir = file("packr-out/")
mainClass = project.ext.mainClassName
classpath = ["desktop/build/libs/desktop-release.jar"]
removePlatformLibs = ["desktop/build/libs/desktop-release.jar"]
PackrConfig.Platform.values().each{ platform ->
task "packr${platform.toString()}"{
def platformName = platform.toString().replace('64', '').replace('32', '').replace('MacOS', 'Mac')
vmArgs = ["Djava.net.preferIPv4Stack=true"]
minimizeJre = "desktop/packr_minimize.json"
jdk = JDK_DIR + "jdk-${getPlatform().toString().toLowerCase()}.zip"
if(getPlatform() == PackrConfig.Platform.MacOS){
vmArgs += "XstartOnFirstThread"
}
}
new Packr().pack(config)
}
}
task copyTemplate(){
doLast{
copy{
into "packr-out/"
from "${JDK_DIR}/templates/${getPlatform().toString().toLowerCase()}"
}
copy{
into "packr-out/"
from "build/libs/desktop-release.jar"
}
}
}
task packrZip(){
task clearOut(type: Delete){
doLast{
delete "packr-out/"
}
}
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 JDK_DIR + "zip.dll"
rename("zip.dll", "ojdkbuild_zlib.dll")
dependsOn dist
doLast{
copy{
into "packr-out/jre/bin/"
from JDK_DIR + "zip.dll"
into "build/packr/"
rename("${appName}.jar", "desktop.jar")
from "build/libs/${appName}.jar"
}
delete{
delete "build/packr/output/"
}
if(platform == PackrConfig.Platform.Windows32 || platform == PackrConfig.Platform.Windows64){
copy{
into "build/packr/output"
from "${JDK_DIR}/templates/${platform.toString().toLowerCase()}"
}
copy{
into "build/packr/output/jre"
rename("${appName}.jar", "desktop.jar")
from "build/libs/${appName}.jar"
}
}else{
def config = new PackrConfig()
config.with{
config.executable = appName
config.platform = platform
verbose = true
bundleIdentifier = getPackage() + ".mac"
iconResource = ICON_DIR
outDir = file("build/packr/output")
mainClass = project.ext.mainClassName
classpath = ["desktop/build/packr/desktop.jar"]
removePlatformLibs = ["desktop/build/packr/desktop.jar"]
vmArgs = ["Djava.net.preferIPv4Stack=true"]
minimizeJre = "desktop/packr_minimize.json"
jdk = JDK_DIR + "jdk-${platform.toString().toLowerCase()}.zip"
if(platform == PackrConfig.Platform.MacOS){
vmArgs += "XstartOnFirstThread"
}
}
new Packr().pack(config)
if(platform == PackrConfig.Platform.Linux64){
copy{
into "build/packr/output/jre/"
from "build/packr/output/desktop.jar"
}
delete{
delete "build/packr/output/desktop.jar"
}
file("build/packr/output/config.json").text = file("build/packr/output/config.json").text.replace("desktop.jar", "jre/desktop.jar")
}
if(platform == PackrConfig.Platform.MacOS){
copy{
into "build/packr/${appName}.app/Contents/"
from "build/packr/Contents/"
}
delete{
delete "build/packr/Contents/"
}
}
}
}
task "zip${platform.toString()}"(type: Zip){
from "build/packr/output"
archiveName "${generateDeployName(platform.toString())}.zip"
destinationDir(file("../deploy"))
doLast{
delete{
delete "build/packr/"
}
}
}
finalizedBy "zip${platform.toString()}"
}
finalizedBy "clearOut"
if(project.hasProperty("platform")){
def plat = getPlatform()
if(plat == PackrConfig.Platform.Windows32 || plat == PackrConfig.Platform.Windows64){
dependsOn "copyTemplate"
}else{
dependsOn "packrCmd"
if(getPlatform() == PackrConfig.Platform.MacOS){
dependsOn "fixMac"
}
if(getPlatform() == PackrConfig.Platform.Windows32){
dependsOn "fixWindows32"
}
}
task rzip(type: Zip){
from "packr-out/"
archiveName "${generateDeployName(getPlatform().toString())}.zip"
destinationDir(file("packr-export"))
}
finalizedBy 'rzip'
}
}
}
+13 -1
View File
@@ -27,13 +27,25 @@
"com/sun/jndi",
"com/sun/xml",
"com/sun/script",
"sum/awt",
"sun/awt",
"sun/java2d",
"sun/font",
"sun/rmi",
"sun/swing",
"java/util/stream",
"com/sun/media",
"sun/print",
"sun/awt",
"sun/instrument",
"sun/security/tools",
"sun/security/smartcardio",
"sun/audio",
"javax/xml",
"javax/sound",
"javax/script",
"java/beans",
"java/applet",
"java/rmi",
"com/sun/naming",
"java/awt",
"com/sun/org/apache/xpath",
@@ -1,27 +1,29 @@
package io.anuke.mindustry.desktop;
import io.anuke.arc.backends.lwjgl3.Lwjgl3Application;
import io.anuke.arc.backends.lwjgl3.Lwjgl3ApplicationConfiguration;
import io.anuke.mindustry.Mindustry;
import io.anuke.mindustry.core.Platform;
import io.anuke.arc.Files.*;
import io.anuke.arc.backends.sdl.*;
import io.anuke.mindustry.*;
import io.anuke.mindustry.core.*;
import io.anuke.mindustry.net.*;
public class DesktopLauncher{
public static void main(String[] arg){
try{
Lwjgl3ApplicationConfiguration config = new Lwjgl3ApplicationConfiguration();
config.setTitle("Mindustry");
config.setMaximized(true);
config.setBackBufferConfig(8, 8, 8, 8, 0, 0, 0);
config.setWindowedMode(900, 600);
config.setWindowIcon("icons/icon_64.png");
Platform.instance = new DesktopPlatform(arg);
Net.setClientProvider(new ArcNetClient());
Net.setServerProvider(new ArcNetServer());
new Lwjgl3Application(new Mindustry(), config);
Net.setClientProvider(new MClient());
Net.setServerProvider(new MServer());
new SdlApplication(new Mindustry(), new SdlConfig(){{
title = "Mindustry";
maximized = true;
depth = 0;
stencil = 0;
width = 900;
height = 700;
setWindowIcon(FileType.Internal, "icons/icon_64.png");
}});
}catch(Throwable e){
DesktopPlatform.handleCrash(e);
}
@@ -1,24 +1,23 @@
package io.anuke.mindustry.desktop;
import club.minnced.discord.rpc.*;
import io.anuke.arc.collection.Array;
import io.anuke.arc.files.FileHandle;
import io.anuke.arc.function.Consumer;
import io.anuke.arc.function.Predicate;
import io.anuke.arc.backends.sdl.jni.SDL;
import io.anuke.arc.collection.*;
import io.anuke.arc.files.*;
import io.anuke.arc.function.*;
import io.anuke.arc.util.*;
import io.anuke.arc.util.serialization.Base64Coder;
import io.anuke.mindustry.core.GameState.State;
import io.anuke.mindustry.core.Platform;
import io.anuke.mindustry.net.CrashSender;
import io.anuke.mindustry.net.Net;
import io.anuke.mindustry.ui.dialogs.FileChooser;
import org.lwjgl.util.tinyfd.TinyFileDialogs;
import io.anuke.arc.util.serialization.*;
import io.anuke.mindustry.core.GameState.*;
import io.anuke.mindustry.core.*;
import io.anuke.mindustry.net.*;
import io.anuke.mindustry.ui.dialogs.*;
import java.net.NetworkInterface;
import java.net.*;
import java.util.*;
import static io.anuke.mindustry.Vars.*;
public class DesktopPlatform extends Platform{
static boolean useDiscord = OS.is64Bit;
final static String applicationId = "610508934456934412";
@@ -32,7 +31,8 @@ public class DesktopPlatform extends Platform{
if(useDiscord){
try{
DiscordEventHandlers handlers = new DiscordEventHandlers();
DiscordRPC.INSTANCE.Discord_Initialize(applicationId, handlers, true, "");
DiscordRPC.INSTANCE.Discord_Initialize(applicationId, handlers, true, "1127400");
Log.info("Initialized Discord rich presence.");
Runtime.getRuntime().addShutdownHook(new Thread(DiscordRPC.INSTANCE::Discord_Shutdown));
}catch(Throwable t){
@@ -43,16 +43,16 @@ public class DesktopPlatform extends Platform{
}
static void handleCrash(Throwable e){
Consumer<Runnable> dialog = r -> new Thread(r).start();
Consumer<Runnable> dialog = Runnable::run;
boolean badGPU = false;
if(e.getMessage() != null && (e.getMessage().contains("Couldn't create window") || e.getMessage().contains("OpenGL 2.0 or higher"))){
dialog.accept(() -> TinyFileDialogs.tinyfd_messageBox("oh no",
dialog.accept(() -> message(
e.getMessage().contains("Couldn't create window") ? "A graphics initialization error has occured! Try to update your graphics drivers:\n" + e.getMessage() :
"Your graphics card does not support OpenGL 2.0!\n" +
"Try to update your graphics drivers.\n\n" +
"(If that doesn't work, your computer just doesn't support Mindustry.)", "ok", "error", true));
"(If that doesn't work, your computer just doesn't support Mindustry.)"));
badGPU = true;
}
@@ -60,7 +60,7 @@ public class DesktopPlatform extends Platform{
CrashSender.send(e, file -> {
if(!fbgp){
dialog.accept(() -> TinyFileDialogs.tinyfd_messageBox("oh no", "A crash has occured. It has been saved in:\n" + file.getAbsolutePath(), "ok", "error", true));
dialog.accept(() -> message("A crash has occured. It has been saved in:\n" + file.getAbsolutePath() + "\n" + (e.getMessage() == null ? "" : "\n" + e.getMessage())));
}
});
}
@@ -72,7 +72,6 @@ public class DesktopPlatform extends Platform{
@Override
public void updateRPC(){
if(!useDiscord) return;
DiscordRichPresence presence = new DiscordRichPresence();
@@ -118,7 +117,7 @@ public class DesktopPlatform extends Platform{
String str = new String(Base64Coder.encode(result));
if(str.equals("AAAAAAAAAOA=")) throw new RuntimeException("Bad UUID.");
if(str.equals("AAAAAAAAAOA=") || str.equals("AAAAAAAAAAA=")) throw new RuntimeException("Bad UUID.");
return str;
}catch(Exception e){
@@ -126,10 +125,14 @@ public class DesktopPlatform extends Platform{
}
}
private static void message(String message){
SDL.SDL_ShowSimpleMessageBox(SDL.SDL_MESSAGEBOX_ERROR, "oh no", message);
}
private boolean validAddress(byte[] bytes){
if(bytes == null) return false;
byte[] result = new byte[8];
System.arraycopy(bytes, 0, result, 0, bytes.length);
return !new String(Base64Coder.encode(result)).equals("AAAAAAAAAOA=");
return !new String(Base64Coder.encode(result)).equals("AAAAAAAAAOA=") && !new String(Base64Coder.encode(result)).equals("AAAAAAAAAAA=");
}
}
+2
View File
@@ -0,0 +1,2 @@
json_key_file(ENV["FASTLANE_KEY_FILE"])
package_name("io.anuke.mindustry")
+46
View File
@@ -0,0 +1,46 @@
# This file contains the fastlane.tools configuration
# You can find the documentation at https://docs.fastlane.tools
#
# For a list of all available actions, check out
#
# https://docs.fastlane.tools/actions
#
# For a list of all available plugins, check out
#
# https://docs.fastlane.tools/plugins/available-plugins
#
# Uncomment the line if you want fastlane to automatically update itself
# update_fastlane
default_platform(:android)
platform :android do
desc "Runs all the tests"
lane :test do
gradle(task: "test")
end
desc "Submit a new Beta Build to Crashlytics Beta"
lane :beta do
gradle(task: "clean assembleRelease")
crashlytics
# sh "your_script.sh"
# You can also use other beta testing services here
end
desc "Deploy a new version to the Google Play"
lane :deploy do
gradle(task: "clean assembleRelease")
upload_to_play_store
end
#lane :playstore do
# gradle(
# task: 'assemble',
# build_type: 'Release'
# )
# upload_to_play_store # Uploads the APK built in the gradle step above and releases it to all production users
#end
end
@@ -0,0 +1,3 @@
- Fixed incorrect attribution in credits; music was made by "A Drop A Day"
- Removed unneeded 3.5 upgrade dialog that sometimes showed up in main menu
- Added information dialog regarding v4 beta
@@ -0,0 +1,4 @@
- Fixed incorrect attribution in credits; music was made by "A Drop A Day"
- Removed unneeded 3.5 upgrade dialog that sometimes showed up in main menu
- Added information dialog regarding v4 beta
- Fixed Discord link
@@ -0,0 +1 @@
sound.
@@ -0,0 +1 @@
everything
@@ -0,0 +1 @@
Fixed some minor sound/multiplayer issues
@@ -0,0 +1 @@
Bugfixes
@@ -0,0 +1 @@
Added ambient sounds for machines.
@@ -0,0 +1,2 @@
The first release of version 4.0; an update that has been in the works for over a year.
Extensive changes, including new gamemodes, customizable rules, a new editor, new graphics, new enemies, unit production, new progression, a campaign, and more. See the in-game changelog link for specific details of what has been added and removed over the past year.
@@ -0,0 +1,2 @@
Fixed multiplayer not syncing positions and shots correctly on certain networks or situations.
Various other bugfixes.
@@ -0,0 +1,5 @@
- Fixed most formatted numbers being missing from Spanish translation
- Fixed wave timer being extremely slow at high TPS with multithreading enabled
- Fixed scrolling on player menu causing the whole screen to pan
- Updated Polish translation
- Updated Russian translation with new text (Thanks to @Prosta4okua)
@@ -0,0 +1,14 @@
Create elaborate supply chains of conveyor belts to feed ammo into your turrets, produce materials to use for building, and defend your structures from waves of enemies. Play with your friends in cross-platform multiplayer co-op games, or challenge them in team-based PvP matches.
Feature include:
- 24 built-in maps
- A campaign, complete with a tech tree and unlockable areas
- 4 powerful wave bosses to defeat
- Energy, liquid and item transportation systems
- 19 different types of drones, mechs and ships
- 120+ technology blocks to master
- 75+ different environmental blocks
- Cross-platform multiplayer via local networks or dedicated servers
- Custom game rules: Change block costs, enemy stats, starting items, wave timing and more
- A powerful editor, with tools to randomly generate ores, terrain, decoration and apply symmetry to maps
- Customizable map wave layouts
Binary file not shown.

After

Width:  |  Height:  |  Size: 649 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 583 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 709 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 952 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 642 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 260 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 570 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 890 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 952 KiB

@@ -0,0 +1 @@
A factory-based sandbox tower defense game.
@@ -0,0 +1 @@
Mindustry
@@ -0,0 +1,15 @@
Создавайте сложные логистические сети для переноса боеприпасов для турелей, добывайте ресурсы для строительства, и защищайте их от различных волн врагов.
Играйте с друзьями в кроссплатформенные кооперативные игры, или бросьте им вызов в командных PvP-матчах.
Особенности игры:
- 24 встроенные карты
- Кампания, с полноценным технологическим древом и прогрессией карт
- 4 вида мощных боссов
- Системы для транспорта электроэнергии, жидкостей и ресурсов
- 19 видов дронов, кораблей и наземных боевых единиц
- Более 120 блоков в техногическом древе
- Более 75 видов натуральных блоков
- Кроссплатформенный мультиплеер с поддержкой как и локальных сетей, так и серверов
- Пользовательские настройки игры — изменяйте цену блоков, силу врагов, количество стартовых ресурсов, интервал между волнами и т.д.
- Редактор карт с бесчисленными возможностями, инструментами для случайной генерации руд, рельефа, декораций, а также для симметрии карт
- Настраиваемые раскладки волн для карт
@@ -0,0 +1 @@
A factory-based sandbox tower defense game.
@@ -0,0 +1 @@
Mindustry
+12 -4
View File
@@ -1,7 +1,15 @@
#!/usr/bin/bash
#convert ogg to .caf files for iOS
for i in $1/*.ogg; do
cd $1
#convert ogg to .mp3 files for iOS
for i in *.ogg; do
echo $i
ffmpeg -i "$i" "${i%.*}.caf"
done
ffmpeg -i "$i" "OUT_${i%.*}.mp3"
done
find . -type f ! -name "OUT_*" -delete
for file in OUT_*; do mv "$file" "${file#OUT_}"; done;
cd ../../
Binary file not shown.

Before

Width:  |  Height:  |  Size: 996 KiB

After

Width:  |  Height:  |  Size: 706 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 MiB

After

Width:  |  Height:  |  Size: 905 KiB

Some files were not shown because too many files have changed in this diff Show More