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/ /server/build/
/test_files/ /test_files/
/annotations/build/ /annotations/build/
/desktop-sdl/build/
desktop-sdl/build/
/android/assets/mindustry-maps/ /android/assets/mindustry-maps/
/android/assets/mindustry-saves/ /android/assets/mindustry-saves/
/core/assets/gifexport/ /core/assets/gifexport/
@@ -33,7 +31,9 @@ desktop-sdl/build/
ios/robovm.properties ios/robovm.properties
packr-out/ packr-out/
config/ config/
changelog
*.gif *.gif
/core/assets/saves/
version.properties version.properties
+1 -1
View File
@@ -13,7 +13,7 @@ deploy:
api_key: api_key:
secure: Cv5wFtWt62/A24EvSEQvMow7gKPbZ3oATEFPuSghhB2TQz1dA40Zee3Qvk4LFlpLrhYo4K0ZSczCZRGpR+hCd8+Dpww52bheYEvWuh3ZQfvu/fXtEx2j5PwP1qMpmIgSxETV/gkD7l9FImdh0VzktYiAvQfmi0bEocG9/D4QwjFpNat7iwBdcMiw1MvAygpdIWRsjiw0RKlB2mWarmoHhQ7Gu7qlU3j50uaEvcrtmU0pBUPggNQwQRv32i9NPvNFxrqqlUjDLIS8JFea99zCkp8BwYqbEvBIMzd+Qip1/stLJJA3+cDUClbsDtg8rAVetzpOrdLEEBmqShFe5MDl2yEHcsgpN9CFsyTaUfvB3P3rVjizvycMm42IsUkXQiarm5xTQ/TIA8Rd8AHiSKuweNCg1Fd5SFaRtKy8JVLXuxyfUccmyje6hhz2L4lS2Wfj3mAG7sqZUCXhWP79EKdGkiPOjKv4CwXEKmuH3BMVqPlNUZJr9Eg3sV1FG0h2l+MVOOnR635qdUbb49sYojYxVruMLX0BH1c4ZCu230m8CUoWA1Em1QNI75ya7+9Y5T6AsgWDVpBvdUo9fWNbdp+VQ0GskFQsJD5wtnxbcbHeFiERAgGBm7z6qt9u9LrQpBH+dsW52ADvYsu3L4nQEa+sdMHwTTwmGY+iUvsxu0DqxGg= secure: Cv5wFtWt62/A24EvSEQvMow7gKPbZ3oATEFPuSghhB2TQz1dA40Zee3Qvk4LFlpLrhYo4K0ZSczCZRGpR+hCd8+Dpww52bheYEvWuh3ZQfvu/fXtEx2j5PwP1qMpmIgSxETV/gkD7l9FImdh0VzktYiAvQfmi0bEocG9/D4QwjFpNat7iwBdcMiw1MvAygpdIWRsjiw0RKlB2mWarmoHhQ7Gu7qlU3j50uaEvcrtmU0pBUPggNQwQRv32i9NPvNFxrqqlUjDLIS8JFea99zCkp8BwYqbEvBIMzd+Qip1/stLJJA3+cDUClbsDtg8rAVetzpOrdLEEBmqShFe5MDl2yEHcsgpN9CFsyTaUfvB3P3rVjizvycMm42IsUkXQiarm5xTQ/TIA8Rd8AHiSKuweNCg1Fd5SFaRtKy8JVLXuxyfUccmyje6hhz2L4lS2Wfj3mAG7sqZUCXhWP79EKdGkiPOjKv4CwXEKmuH3BMVqPlNUZJr9Eg3sV1FG0h2l+MVOOnR635qdUbb49sYojYxVruMLX0BH1c4ZCu230m8CUoWA1Em1QNI75ya7+9Y5T6AsgWDVpBvdUo9fWNbdp+VQ0GskFQsJD5wtnxbcbHeFiERAgGBm7z6qt9u9LrQpBH+dsW52ADvYsu3L4nQEa+sdMHwTTwmGY+iUvsxu0DqxGg=
file: file:
- desktop/build/libs/desktop-release.jar - desktop/build/libs/Mindustry.jar
- server/build/libs/server-release.jar - server/build/libs/server-release.jar
on: on:
repo: Anuken/Mindustry 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> 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 ### Downloads
-3
View File
@@ -1,8 +1,5 @@
## Translating for Mindustry ## 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/). 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, 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{ 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; config.hideStatusBar = true;
Net.setClientProvider(new ArcNetClient()); Net.setClientProvider(new MClient());
Net.setServerProvider(new ArcNetServer()); Net.setServerProvider(new MServer());
initialize(new Mindustry(), config); initialize(new Mindustry(), config);
checkFiles(getIntent()); 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))", 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 + ".dispose()");
dispose.addStatement(name + " = null"); 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()); 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" 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 = { getVersionString = {
@@ -145,23 +145,6 @@ allprojects{
project(":desktop"){ project(":desktop"){
apply plugin: "java" 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{ dependencies{
compile project(":core") compile project(":core")
compile project(":net") compile project(":net")
@@ -246,9 +229,11 @@ project(":core"){
compileJava.dependsOn(preGen) compileJava.dependsOn(preGen)
compile "org.lz4:lz4-java:1.4.1"
compile arcModule("arc-core") compile arcModule("arc-core")
compile arcModule("extensions:freetype") compile arcModule("extensions:freetype")
compile arcModule("extensions:arcnet") compile arcModule("extensions:arcnet")
compile arcModule("extensions:mnet")
if(localArc() && debugged()) compile arcModule("extensions:recorder") if(localArc() && debugged()) compile arcModule("extensions:recorder")
compileOnly project(":annotations") compileOnly project(":annotations")
@@ -311,7 +296,26 @@ project(":net"){
dependencies{ dependencies{
compile project(":core") 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.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.customClient = This server does not support custom builds. Download an official version.
server.kicked.gameover = Game over! 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. 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. 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 hostserver = Host Multiplayer Game
@@ -124,7 +125,7 @@ save.new = New Save
save.overwrite = Are you sure you want to overwrite\nthis save slot? save.overwrite = Are you sure you want to overwrite\nthis save slot?
overwrite = Overwrite overwrite = Overwrite
save.none = No saves found! save.none = No saves found!
saveload = [accent]Saving... saveload = Saving...
savefail = Failed to save game! savefail = Failed to save game!
save.delete.confirm = Are you sure you want to delete this save? save.delete.confirm = Are you sure you want to delete this save?
save.delete = Delete save.delete = Delete
@@ -371,7 +372,7 @@ zone.crags.name = Crags
zone.fungalPass.name = Fungal Pass 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.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.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.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. 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 = <없음> none = <없음>
minimap = 미니맵 minimap = 미니맵
close = 닫기 close = 닫기
website = 웹사이트
quit = 나가기 quit = 나가기
maps = maps =
continue = 계속하기 continue = 계속하기
@@ -514,6 +515,7 @@ setting.lasers.name = 전력 노드 레이저 표시
setting.pixelate.name = 픽셀화[LIGHT_GRAY] (애니메이션 효과가 꺼집니다) setting.pixelate.name = 픽셀화[LIGHT_GRAY] (애니메이션 효과가 꺼집니다)
setting.minimap.name = 미니맵 보기 setting.minimap.name = 미니맵 보기
setting.musicvol.name = 음악 크기 setting.musicvol.name = 음악 크기
setting.ambientvol.name = 배경음 크기
setting.mutemusic.name = 음소거 setting.mutemusic.name = 음소거
setting.sfxvol.name = 효과음 크기 setting.sfxvol.name = 효과음 크기
setting.mutesound.name = 소리 끄기 setting.mutesound.name = 소리 끄기
+22 -22
View File
@@ -172,7 +172,7 @@ saveimage = 保存图片
unknown = 未知 unknown = 未知
custom = 自定义 custom = 自定义
builtin = 内建的 builtin = 内建的
map.delete.confirm = 你确定你想要删除这张地图吗?这个操作无法取消 map.delete.confirm = 你确定你想要删除这张地图吗?这个操作无法撤销
map.random = [accent]随机地图 map.random = [accent]随机地图
map.nospawn = 这个地图没有核心!请在编辑器中添加一个[ROYAL]蓝色[]的核心。 map.nospawn = 这个地图没有核心!请在编辑器中添加一个[ROYAL]蓝色[]的核心。
map.nospawn.pvp = 这个地图没有敌人的核心!请在编辑器中添加一个[ROYAL]红色[]的核心。 map.nospawn.pvp = 这个地图没有敌人的核心!请在编辑器中添加一个[ROYAL]红色[]的核心。
@@ -349,13 +349,13 @@ error.any = 未知网络错误。
error.bloom = 未能初始化特效。\n您的设备可能不支持它。 error.bloom = 未能初始化特效。\n您的设备可能不支持它。
zone.groundZero.name = 零号地区 zone.groundZero.name = 零号地区
zone.desertWastes.name = 沙漠废物 zone.desertWastes.name = 荒芜沙漠
zone.craters.name = 陨石带 zone.craters.name = 陨石带
zone.frozenForest.name = 冰冻森林 zone.frozenForest.name = 冰冻森林
zone.ruinousShores.name = 毁灭海岸 zone.ruinousShores.name = 遗迹海岸
zone.stainedMountains.name = 绵延群山 zone.stainedMountains.name = 绵延群山
zone.desolateRift.name = 荒芜裂谷 zone.desolateRift.name = 荒芜裂谷
zone.nuclearComplex.name = 核裂 zone.nuclearComplex.name = 核裂
zone.overgrowth.name = 增生区 zone.overgrowth.name = 增生区
zone.tarFields.name = 石油田 zone.tarFields.name = 石油田
zone.saltFlats.name = 盐碱荒滩 zone.saltFlats.name = 盐碱荒滩
@@ -498,9 +498,9 @@ setting.sensitivity.name = 控制器灵敏度
setting.saveinterval.name = 自动保存间隔 setting.saveinterval.name = 自动保存间隔
setting.seconds = {0} 秒 setting.seconds = {0} 秒
setting.fullscreen.name = 全屏 setting.fullscreen.name = 全屏
setting.borderlesswindow.name = 全屏化[LIGHT_GRAY] (可能需要重启) setting.borderlesswindow.name = 无边框窗口[LIGHT_GRAY] (可能需要重启)
setting.fps.name = 显示 FPS setting.fps.name = 显示 FPS
setting.vsync.name = 同步 setting.vsync.name = 垂直同步
setting.lasers.name = 显示能量射线 setting.lasers.name = 显示能量射线
setting.pixelate.name = 像素画面 [LIGHT_GRAY](可能会降低性能) setting.pixelate.name = 像素画面 [LIGHT_GRAY](可能会降低性能)
setting.minimap.name = 显示小地图 setting.minimap.name = 显示小地图
@@ -736,7 +736,7 @@ block.duo.name = 双管炮
block.scorch.name = 火焰炮 block.scorch.name = 火焰炮
block.scatter.name = 分裂炮 block.scatter.name = 分裂炮
block.hail.name = 冰雹炮 block.hail.name = 冰雹炮
block.lancer.name = 蓝瑟炮 block.lancer.name = 激光矛
block.conveyor.name = 传送带 block.conveyor.name = 传送带
block.titanium-conveyor.name = 钛传送带 block.titanium-conveyor.name = 钛传送带
block.junction.name = 连接点 block.junction.name = 连接点
@@ -825,7 +825,7 @@ block.surge-wall.name = 波动墙
block.surge-wall-large.name = 大型波动墙 block.surge-wall-large.name = 大型波动墙
block.cyclone.name = 气旋炮 block.cyclone.name = 气旋炮
block.fuse.name = 融合炮 block.fuse.name = 融合炮
block.shock-mine.name = 休克地雷 block.shock-mine.name = 脉冲地雷
block.overdrive-projector.name = 超速投影器 block.overdrive-projector.name = 超速投影器
block.force-projector.name = 力墙投影器 block.force-projector.name = 力墙投影器
block.arc.name = 电弧 block.arc.name = 电弧
@@ -955,7 +955,7 @@ block.surge-wall-large.description = 强大的防御区块。\n有很小的机
block.door.description = 一扇小门,可以通过点击打开和关闭。\n如果打开,敌人可以射击并穿过。 block.door.description = 一扇小门,可以通过点击打开和关闭。\n如果打开,敌人可以射击并穿过。
block.door-large.description = 一扇大门,可以通过点击打开和关闭。\n如果打开,敌人可以射击并穿过。\n跨越多个区块。 block.door-large.description = 一扇大门,可以通过点击打开和关闭。\n如果打开,敌人可以射击并穿过。\n跨越多个区块。
block.mender.description = 定期修理附近的方块,使防御系统在波与波之间得到修复。\n通常使用硅来提高范围和效率。 block.mender.description = 定期修理附近的方块,使防御系统在波与波之间得到修复。\n通常使用硅来提高范围和效率。
block.mend-projector.description = 定期修复附近的建筑物。 block.mend-projector.description = 修理者的升级。定期修复附近的建筑物。
block.overdrive-projector.description = 提高附近建筑物的速度,如钻头和传送带。 block.overdrive-projector.description = 提高附近建筑物的速度,如钻头和传送带。
block.force-projector.description = 自身周围创建一个六边形力场,使建筑物和内部单位免受子弹的伤害。 block.force-projector.description = 自身周围创建一个六边形力场,使建筑物和内部单位免受子弹的伤害。
block.shock-mine.description = 伤害踩到它的敌人。敌人几乎看不到它。 block.shock-mine.description = 伤害踩到它的敌人。敌人几乎看不到它。
@@ -1008,20 +1008,20 @@ block.container.description = 存储少量物品。当存在非恒定的材料
block.vault.description = 存储大量物品。当存在非恒定的材料需求时,使用它来创建缓冲区。 [LIGHT_GRAY]卸载器[]可用于从仓库中获取物品。 block.vault.description = 存储大量物品。当存在非恒定的材料需求时,使用它来创建缓冲区。 [LIGHT_GRAY]卸载器[]可用于从仓库中获取物品。
block.launch-pad.description = 不通过核心发射物体。 block.launch-pad.description = 不通过核心发射物体。
block.launch-pad-large.description = 发射台的改进版。存储更多物体。启动频率更高。 block.launch-pad-large.description = 发射台的改进版。存储更多物体。启动频率更高。
block.duo.description = 小而便宜的炮塔。 block.duo.description = 小而便宜的炮塔。对地高效。
block.scatter.description = 中型防空炮塔,向空中单位发射铅或废料。 block.scatter.description = 不可或缺的防空炮塔,向空中单位发射铅或废料。
block.scorch.description = 小型炮塔,燃烧任何靠近它的地面敌人。近距离效。 block.scorch.description = 小型炮塔,燃烧任何靠近它的地面敌人。近距离非常有效。
block.arc.description = 小型炮塔,发射电弧。 block.arc.description = 小型炮塔,发射电弧。
block.hail.description = 小型炮兵炮台。 block.hail.description = 小型,远程炮台。
block.lancer.description = 中型炮塔,发射带电的电子束。 block.lancer.description = 中型对地炮塔。遇敌时会充能并发射强有力的的能量束。
block.wave.description = 中型快速炮塔,射出液体泡泡。 block.wave.description = 中型快速炮塔,射出液体泡泡。有液体输入时自动灭火。
block.salvo.description = 中型炮塔,齐射射击。 block.salvo.description = 双管炮的升级。中型,齐射射击。
block.swarmer.description = 中型炮塔,发射爆炸导弹。 block.swarmer.description = 中型炮塔,对空对地,发射跟踪爆炸导弹。
block.ripple.description = 大型炮兵炮塔,可同时向多个目标开火 block.ripple.description = 大型远程炮台,非常强力,向远处的敌人投射一簇弹药
block.cyclone.description = 大型快速炮塔。 block.cyclone.description = 大型快速炮塔,对空对地,向周围敌人发射爆炸弹
block.fuse.description = 大型炮塔,发射强大的短程光束。 block.fuse.description = 大型炮塔,发射三道刺穿敌人的短程光束。
block.spectre.description = 大型炮塔,一次射出两颗强大的子弹。 block.spectre.description = 大型炮塔,对空对地,一次射出两颗强大的穿甲子弹。
block.meltdown.description = 发射强大的远程光束的大型炮塔 block.meltdown.description = 超大型激光炮塔,充能之后持续发射光束,需要冷却剂
block.crawler-factory.description = 生产快速自毁单元。 block.crawler-factory.description = 生产快速自毁单元。
block.draug-factory.description = 生产德鲁格釆矿机。 block.draug-factory.description = 生产德鲁格釆矿机。
block.spirit-factory.description = 生产幽灵修理机。 block.spirit-factory.description = 生产幽灵修理机。
+2 -1
View File
@@ -26,7 +26,7 @@ beito
BeefEX BeefEX
Lorex Lorex
laohuaji233 laohuaji233
CrazyBearTR Spico The Spirit Guy
Zachary Zachary
Fenr1r Fenr1r
Jaiun Lee Jaiun Lee
@@ -71,3 +71,4 @@ Paul T
Dominik Dominik
Arkanic Arkanic
Potion 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, up: button,
over: button-over, over: button-over,
imageDisabledColor: gray, imageDisabledColor: gray,
imageUpColor: white imageUpColor: white,
disabled: button-disabled
}, },
node: { node: {
up: button-over, up: button-over,
+1 -1
View File
@@ -67,6 +67,6 @@ public class Mindustry extends ApplicationCore{
super.init(); super.init();
Log.info("Time to load [total]: {0}", Time.elapsed()); 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; package io.anuke.mindustry;
import io.anuke.arc.*;
import io.anuke.arc.Application.ApplicationType; import io.anuke.arc.Application.ApplicationType;
import io.anuke.arc.Core;
import io.anuke.arc.files.FileHandle; import io.anuke.arc.files.FileHandle;
import io.anuke.arc.graphics.Color; import io.anuke.arc.graphics.Color;
import io.anuke.arc.util.Structs; 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.traits.SyncTrait;
import io.anuke.mindustry.entities.type.*; import io.anuke.mindustry.entities.type.*;
import io.anuke.mindustry.game.*; import io.anuke.mindustry.game.*;
import io.anuke.mindustry.game.EventType.*;
import io.anuke.mindustry.gen.Serialization; import io.anuke.mindustry.gen.Serialization;
import io.anuke.mindustry.net.Net; import io.anuke.mindustry.net.Net;
import io.anuke.mindustry.world.blocks.defense.ForceProjector.ShieldEntity; import io.anuke.mindustry.world.blocks.defense.ForceProjector.ShieldEntity;
@@ -222,5 +223,7 @@ public class Vars{
customMapDirectory = dataDirectory.child("maps/"); customMapDirectory = dataDirectory.child("maps/");
saveDirectory = dataDirectory.child("saves/"); saveDirectory = dataDirectory.child("saves/");
tmpDirectory = dataDirectory.child("tmp/"); tmpDirectory = dataDirectory.child("tmp/");
Events.fire(new AppLoadEvent());
} }
} }
@@ -119,7 +119,7 @@ public class BlockIndexer{
ObjectSet<Tile> set = damagedTiles[team.ordinal()]; ObjectSet<Tile> set = damagedTiles[team.ordinal()];
for(Tile tile : set){ 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); returnArray.add(tile);
} }
} }
@@ -267,7 +267,7 @@ public class Bullets implements ContentList{
keepVelocity = false; keepVelocity = false;
splashDamageRadius = 25f; splashDamageRadius = 25f;
splashDamage = 10f; splashDamage = 10f;
lifetime = 50f; lifetime = 60f;
trailColor = Pal.unitBack; trailColor = Pal.unitBack;
backColor = Pal.unitBack; backColor = Pal.unitBack;
frontColor = Pal.unitFront; frontColor = Pal.unitFront;
@@ -227,12 +227,14 @@ public class TechTree implements ContentList{
node(turbineGenerator, () -> { node(turbineGenerator, () -> {
node(thermalGenerator, () -> { node(thermalGenerator, () -> {
node(rtgGenerator, () -> { node(differentialGenerator, () -> {
node(differentialGenerator, () -> { node(thoriumReactor, () -> {
node(thoriumReactor, () -> { node(impactReactor, () -> {
node(impactReactor, () -> {
});
node(rtgGenerator, () -> {
});
}); });
}); });
}); });
@@ -330,9 +330,9 @@ public class UnitTypes implements ContentList{
baseRotateSpeed = 0.04f; baseRotateSpeed = 0.04f;
weapon = new Weapon("lich-missiles"){{ weapon = new Weapon("lich-missiles"){{
length = 4f; length = 4f;
reload = 180f; reload = 160f;
width = 22f; width = 22f;
shots = 22; shots = 16;
shootCone = 100f; shootCone = 100f;
shotDelay = 2; shotDelay = 2;
inaccuracy = 10f; inaccuracy = 10f;
@@ -341,7 +341,7 @@ public class UnitTypes implements ContentList{
velocityRnd = 0.2f; velocityRnd = 0.2f;
spacing = 1f; spacing = 1f;
bullet = Bullets.missileRevenant; bullet = Bullets.missileRevenant;
shootSound = Sounds.missile; shootSound = Sounds.artillery;
}}; }};
}}; }};
@@ -371,7 +371,18 @@ public class UnitTypes implements ContentList{
inaccuracy = 3f; inaccuracy = 3f;
roundrobin = true; roundrobin = true;
ejectEffect = Fx.none; 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; shootSound = Sounds.shootBig;
}}; }};
}}; }};
+28 -26
View File
@@ -84,7 +84,7 @@ public class Control implements ApplicationListener{
}); });
Events.on(PlayEvent.class, event -> { Events.on(PlayEvent.class, event -> {
player.setTeam(defaultTeam); player.setTeam(state.rules.pvp ? netServer.assignTeam(player, playerGroup.all()) : defaultTeam);
player.setDead(true); player.setDead(true);
player.add(); player.add();
@@ -237,7 +237,7 @@ public class Control implements ApplicationListener{
public void playMap(Map map, Rules rules){ public void playMap(Map map, Rules rules){
ui.loadAnd(() -> { ui.loadAnd(() -> {
logic.reset(); logic.reset();
world.loadMap(map); world.loadMap(map, rules);
state.rules = rules; state.rules = rules;
logic.play(); logic.play();
}); });
@@ -350,35 +350,37 @@ public class Control implements ApplicationListener{
//display UI scale changed dialog //display UI scale changed dialog
if(Core.settings.getBool("uiscalechanged", false)){ 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}; float[] countdown = {60 * 11};
Runnable exit = () -> { Runnable exit = () -> {
Core.settings.put("uiscale", 100); Core.settings.put("uiscale", 100);
Core.settings.put("uiscalechanged", false); Core.settings.put("uiscalechanged", false);
settings.save(); settings.save();
dialog.hide(); dialog.hide();
Core.app.exit(); Core.app.exit();
}; };
dialog.setFillParent(false); dialog.cont.label(() -> {
dialog.cont.label(() -> { if(countdown[0] <= 0){
if(countdown[0] <= 0){ exit.run();
exit.run(); }
} return Core.bundle.format("uiscale.reset", (int)((countdown[0] -= Time.delta()) / 60f));
return Core.bundle.format("uiscale.reset", (int)((countdown[0] -= Time.delta()) / 60f)); }).pad(10f).expand().center();
}).pad(10f).expand().left();
dialog.buttons.defaults().size(200f, 60f); dialog.buttons.defaults().size(200f, 60f);
dialog.buttons.addButton("$uiscale.cancel", exit); dialog.buttons.addButton("$uiscale.cancel", exit);
dialog.buttons.addButton("$ok", () -> { dialog.buttons.addButton("$ok", () -> {
Core.settings.put("uiscalechanged", false); Core.settings.put("uiscalechanged", false);
settings.save(); settings.save();
dialog.hide(); 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 class NetServer implements ApplicationListener{
public final static int maxSnapshotSize = 430; 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 Vector2 vector = new Vector2();
private final static Rectangle viewport = new Rectangle(); private final static Rectangle viewport = new Rectangle();
/** If a player goes away of their server-side coordinates by this distance, they get teleported back. */ /** 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 //playing in pvp mode automatically assigns players to teams
if(state.rules.pvp){ 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()); 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. //find team with minimum amount of players and auto-assign player to that.
return Structs.findMin(Team.all, team -> { return Structs.findMin(Team.all, team -> {
if(state.teams.isActive(team) && !state.teams.get(team).cores.isEmpty()){ if(state.teams.isActive(team) && !state.teams.get(team).cores.isEmpty()){
int count = 0; int count = 0;
for(Player other : players){ for(Player other : players){
if(other.getTeam() == team){ if(other.getTeam() == team && other != current){
count++; count++;
} }
} }
@@ -256,7 +256,7 @@ public class Renderer implements ApplicationListener{
draw(playerGroup, p -> true, Player::drawBuildRequests); draw(playerGroup, p -> true, Player::drawBuildRequests);
if(Entities.countInBounds(shieldGroup) > 0){ if(Entities.countInBounds(shieldGroup) > 0){
if(settings.getBool("animatedshields")){ if(settings.getBool("animatedshields") && Shaders.shield != null){
Draw.flush(); Draw.flush();
shieldBuffer.begin(); shieldBuffer.begin();
graphics.clear(Color.CLEAR); graphics.clear(Color.CLEAR);
+12 -7
View File
@@ -220,6 +220,10 @@ public class World implements ApplicationListener{
} }
public void loadMap(Map map){ public void loadMap(Map map){
loadMap(map, new Rules());
}
public void loadMap(Map map, Rules checkRules){
try{ try{
SaveIO.load(map.file, new FilterContext(map)); SaveIO.load(map.file, new FilterContext(map));
}catch(Exception e){ }catch(Exception e){
@@ -238,20 +242,21 @@ public class World implements ApplicationListener{
invalidMap = false; invalidMap = false;
if(!headless){ if(!headless){
if(state.teams.get(defaultTeam).cores.size == 0){ if(state.teams.get(defaultTeam).cores.size == 0 && !checkRules.pvp){
ui.showError("$map.nospawn"); ui.showError("$map.nospawn");
invalidMap = true; invalidMap = true;
}else if(state.rules.pvp){ //pvp maps need two cores to be valid }else if(checkRules.pvp){ //pvp maps need two cores to be valid
invalidMap = true; int teams = 0;
for(Team team : Team.all){ for(Team team : Team.all){
if(state.teams.get(team).cores.size != 0 && team != defaultTeam){ if(state.teams.get(team).cores.size != 0){
invalidMap = false; teams ++;
} }
} }
if(invalidMap){ if(teams < 2){
invalidMap = true;
ui.showError("$map.nospawn.pvp"); 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(); invalidMap = state.teams.get(waveTeam).cores.isEmpty();
if(invalidMap){ if(invalidMap){
ui.showError("$map.nospawn.attack"); ui.showError("$map.nospawn.attack");
@@ -55,7 +55,7 @@ public class Predict{
* See {@link #intercept(float, float, float, float, float, float, float)}. * See {@link #intercept(float, float, float, float, float, float, float)}.
*/ */
public static Vector2 intercept(TargetTrait src, TargetTrait dst, float v){ 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){ 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.arc.util.Time;
import io.anuke.mindustry.content.Fx; import io.anuke.mindustry.content.Fx;
import io.anuke.mindustry.entities.Effects; import io.anuke.mindustry.entities.Effects;
import io.anuke.mindustry.gen.*;
import io.anuke.mindustry.graphics.Pal; import io.anuke.mindustry.graphics.Pal;
public class MissileBulletType extends BasicBulletType{ public class MissileBulletType extends BasicBulletType{
@@ -18,6 +19,7 @@ public class MissileBulletType extends BasicBulletType{
backColor = Pal.missileYellowBack; backColor = Pal.missileYellowBack;
frontColor = Pal.missileYellow; frontColor = Pal.missileYellow;
homingPower = 7f; homingPower = 7f;
hitSound = Sounds.explosion;
} }
@Override @Override
@@ -1,33 +1,28 @@
package io.anuke.mindustry.entities.traits; package io.anuke.mindustry.entities.traits;
import io.anuke.annotations.Annotations.*; import io.anuke.annotations.Annotations.*;
import io.anuke.arc.Core; import io.anuke.arc.*;
import io.anuke.arc.Events;
import io.anuke.arc.collection.Array;
import io.anuke.arc.collection.Queue; import io.anuke.arc.collection.Queue;
import io.anuke.arc.collection.*;
import io.anuke.arc.graphics.g2d.*; import io.anuke.arc.graphics.g2d.*;
import io.anuke.arc.math.Angles; import io.anuke.arc.math.*;
import io.anuke.arc.math.Mathf; import io.anuke.arc.math.geom.*;
import io.anuke.arc.math.geom.Vector2; import io.anuke.arc.util.*;
import io.anuke.arc.util.Time; import io.anuke.mindustry.*;
import io.anuke.mindustry.Vars; import io.anuke.mindustry.content.*;
import io.anuke.mindustry.content.Blocks; import io.anuke.mindustry.entities.type.*;
import io.anuke.mindustry.entities.type.TileEntity; import io.anuke.mindustry.game.EventType.*;
import io.anuke.mindustry.entities.type.Unit; import io.anuke.mindustry.gen.*;
import io.anuke.mindustry.game.EventType.BuildSelectEvent; import io.anuke.mindustry.graphics.*;
import io.anuke.mindustry.gen.Call;
import io.anuke.mindustry.graphics.Pal;
import io.anuke.mindustry.net.Net;
import io.anuke.mindustry.world.*; import io.anuke.mindustry.world.*;
import io.anuke.mindustry.world.blocks.BuildBlock; import io.anuke.mindustry.world.blocks.*;
import io.anuke.mindustry.world.blocks.BuildBlock.BuildEntity; import io.anuke.mindustry.world.blocks.BuildBlock.*;
import java.io.*; import java.io.*;
import java.util.Arrays; import java.util.*;
import static io.anuke.mindustry.Vars.*; 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.*;
import static io.anuke.mindustry.entities.traits.BuilderTrait.BuildDataStatic.tmptr;
/** Interface for units that build things.*/ /** Interface for units that build things.*/
public interface BuilderTrait extends Entity, TeamTrait{ 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); unit.rotation = Mathf.slerpDelta(unit.rotation, unit.angleTo(entity), 0.4f);
} }
//progress is synced, thus not updated clientside //deconstructing is 2x as fast
if(!Net.client()){ if(current.breaking){
//deconstructing is 2x as fast entity.deconstruct(unit, core, 2f / entity.buildCost * Time.delta() * getBuildPower(tile) * state.rules.buildSpeedMultiplier);
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();
}else{ }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. */ /** Returns the queue for storing build requests. */
@@ -135,7 +125,7 @@ public interface BuilderTrait extends Entity, TeamTrait{
default void writeBuilding(DataOutput output) throws IOException{ default void writeBuilding(DataOutput output) throws IOException{
BuildRequest request = buildRequest(); BuildRequest request = buildRequest();
if(request != null){ if(request != null && (request.block != null || request.breaking)){
output.writeByte(request.breaking ? 1 : 0); output.writeByte(request.breaking ? 1 : 0);
output.writeInt(Pos.get(request.x, request.y)); output.writeInt(Pos.get(request.x, request.y));
output.writeFloat(request.progress); output.writeFloat(request.progress);
@@ -174,7 +164,11 @@ public interface BuilderTrait extends Entity, TeamTrait{
if(applyChanges){ if(applyChanges){
buildQueue().addLast(request); buildQueue().addLast(request);
}else if(isBuilding()){ }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; this.breaking = true;
} }
public Tile tile(){
return world.tile(x, y);
}
@Override @Override
public String toString(){ public String toString(){
return "BuildRequest{" + return "BuildRequest{" +
@@ -70,7 +70,6 @@ public class Player extends Unit implements BuilderMinerTrait, ShooterTrait{
private Tile mining; private Tile mining;
private Vector2 movement = new Vector2(); private Vector2 movement = new Vector2();
private boolean moved; private boolean moved;
private SoundLoop buildSound = new SoundLoop(Sounds.build, 0.75f);
//endregion //endregion
@@ -131,11 +130,6 @@ public class Player extends Unit implements BuilderMinerTrait, ShooterTrait{
} }
} }
@Override
public void removed(){
buildSound.stop();
}
@Override @Override
public float drag(){ public float drag(){
return mech.drag; return mech.drag;
@@ -514,11 +508,13 @@ public class Player extends Unit implements BuilderMinerTrait, ShooterTrait{
} }
if(!isDead() && isFlying()){ 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(); 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()){ if(isDead()){
isBoosting = false; isBoosting = false;
@@ -531,7 +527,9 @@ public class Player extends Unit implements BuilderMinerTrait, ShooterTrait{
spawner = null; spawner = null;
} }
avoidOthers(); if(isLocal || Net.server()){
avoidOthers();
}
Tile tile = world.tileWorld(x, y); 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.entities.units.UnitState;
import io.anuke.mindustry.world.Pos; import io.anuke.mindustry.world.Pos;
import io.anuke.mindustry.world.Tile; import io.anuke.mindustry.world.Tile;
import io.anuke.mindustry.world.blocks.*;
import java.io.*; import java.io.*;
@@ -23,6 +24,10 @@ public class RepairDrone extends BaseDrone{
target = Units.findDamagedTile(team, x, y); target = Units.findDamagedTile(team, x, y);
} }
if(target instanceof TileEntity && ((TileEntity)target).block instanceof BuildBlock){
target = null;
}
if(target != null){ if(target != null){
if(target.dst(RepairDrone.this) > type.range){ if(target.dst(RepairDrone.this) > type.range){
circle(type.range * 0.9f); circle(type.range * 0.9f);
@@ -27,8 +27,13 @@ public class EventType{
} }
} }
/** Called when the game is first loaded. */ /** Called when the client game is first loaded. */
public static class GameLoadEvent{ 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.*/ /** Controls playback of multiple music tracks.*/
public class MusicControl{ 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 */ /** normal, ambient music, plays at any time */
public final Array<Music> ambientMusic = Array.with(Musics.game1, Musics.game3, Musics.game4, Musics.game6); 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){ public RankResult calculateRank(Zone zone, boolean launched){
float score = 0; float score = 0;
//each new launch period adds onto the rank 'points' if(launched && zone.getRules().attackMode){
if(wavesLasted >= zone.conditionWave){ 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; score += (float)((wavesLasted - zone.conditionWave) / zone.launchPeriod + 1) * 1.2f;
} }
@@ -1,5 +1,6 @@
package io.anuke.mindustry.graphics; package io.anuke.mindustry.graphics;
import io.anuke.annotations.Annotations.*;
import io.anuke.arc.Core; import io.anuke.arc.Core;
import io.anuke.arc.graphics.Color; import io.anuke.arc.graphics.Color;
import io.anuke.arc.graphics.g2d.TextureRegion; import io.anuke.arc.graphics.g2d.TextureRegion;
@@ -10,7 +11,7 @@ import io.anuke.arc.util.Time;
public class Shaders{ public class Shaders{
public static Shadow shadow; public static Shadow shadow;
public static BlockBuild blockbuild; public static BlockBuild blockbuild;
public static Shield shield; public static @Nullable Shield shield;
public static UnitBuild build; public static UnitBuild build;
public static FogShader fog; public static FogShader fog;
public static MenuShader menu; public static MenuShader menu;
@@ -19,7 +20,13 @@ public class Shaders{
public static void init(){ public static void init(){
shadow = new Shadow(); shadow = new Shadow();
blockbuild = new BlockBuild(); 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(); build = new UnitBuild();
fog = new FogShader(); fog = new FogShader();
menu = new MenuShader(); menu = new MenuShader();
@@ -131,7 +131,7 @@ public class DesktopInput extends InputHandler{
player.isShooting = false; 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()){ if(!ui.minimap.isShown()){
ui.minimap.show(); ui.minimap.show();
}else{ }else{
+6 -1
View File
@@ -214,7 +214,12 @@ public class Maps implements Disposable{
return filters; return filters;
}else{ }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)); options(new SliderOption("angle", () -> angle, f -> angle = (int)f, 0, 360, 45));
buffered = true;
} }
@Override @Override
@@ -1,14 +1,15 @@
package io.anuke.mindustry.net; package io.anuke.mindustry.net;
import io.anuke.arc.math.Mathf; import io.anuke.arc.math.*;
import io.anuke.arc.math.geom.Vector2; import io.anuke.arc.math.geom.*;
import io.anuke.arc.util.Time; import io.anuke.arc.util.*;
public class Interpolator{ public class Interpolator{
//used for movement //used for movement
public Vector2 target = new Vector2(); public Vector2 target = new Vector2();
public Vector2 last = new Vector2(); public Vector2 last = new Vector2();
public float[] targets = {}; public float[] targets = {};
public float[] lasts = {};
public long lastUpdated, updateSpacing; public long lastUpdated, updateSpacing;
//current state //current state
@@ -21,6 +22,12 @@ public class Interpolator{
lastUpdated = Time.millis(); lastUpdated = Time.millis();
targets = target1ds; 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); last.set(cx, cy);
target.set(x, y); target.set(x, y);
} }
@@ -46,8 +53,12 @@ public class Interpolator{
values = new float[targets.length]; values = new float[targets.length];
} }
if(lasts.length != targets.length){
lasts = new float[targets.length];
}
for(int i = 0; i < values.length; i++){ 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{ }else{
pos.set(target); pos.set(target);
+61 -32
View File
@@ -1,19 +1,18 @@
package io.anuke.mindustry.net; package io.anuke.mindustry.net;
import io.anuke.arc.Core; import io.anuke.arc.*;
import io.anuke.arc.collection.*; import io.anuke.arc.collection.*;
import io.anuke.arc.function.BiConsumer; import io.anuke.arc.function.*;
import io.anuke.arc.function.Consumer;
import io.anuke.arc.util.*; import io.anuke.arc.util.*;
import io.anuke.arc.util.pooling.Pools; import io.anuke.arc.util.pooling.*;
import io.anuke.mindustry.core.Platform; import io.anuke.mindustry.core.*;
import io.anuke.mindustry.gen.Call; import io.anuke.mindustry.gen.*;
import io.anuke.mindustry.net.Packets.*; 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.io.*;
import java.nio.BufferOverflowException; import java.nio.*;
import java.nio.BufferUnderflowException;
import static io.anuke.mindustry.Vars.*; import static io.anuke.mindustry.Vars.*;
@@ -28,6 +27,8 @@ public class Net{
private static ClientProvider clientProvider; private static ClientProvider clientProvider;
private static ServerProvider serverProvider; private static ServerProvider serverProvider;
private static IntMap<StreamBuilder> streams = new IntMap<>(); 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. */ /** Display a network error. Call on the graphics thread. */
public static void showError(Throwable e){ public static void showError(Throwable e){
@@ -144,11 +145,11 @@ public class Net{
} }
public static byte[] compressSnapshot(byte[] input){ public static byte[] compressSnapshot(byte[] input){
return serverProvider.compressSnapshot(input); return compressor.compress(input);
} }
public static byte[] decompressSnapshot(byte[] input, int size){ 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. * Returns a list of all connections IDs.
*/ */
public static Array<NetConnection> getConnections(){ public static Iterable<NetConnection> getConnections(){
return (Array<NetConnection>)serverProvider.getConnections(); return (Iterable<NetConnection>)serverProvider.getConnections();
} }
/** /**
@@ -326,7 +327,7 @@ public class Net{
public static void dispose(){ public static void dispose(){
if(clientProvider != null) clientProvider.dispose(); if(clientProvider != null) clientProvider.dispose();
if(serverProvider != null) serverProvider.dispose(); if(serverProvider != null) serverProvider.close();
clientProvider = null; clientProvider = null;
serverProvider = null; serverProvider = null;
server = false; server = false;
@@ -354,9 +355,6 @@ public class Net{
/** Disconnect from the server. */ /** Disconnect from the server. */
void disconnect(); 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. * 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. * Callback should be run on libGDX main thread.
@@ -377,30 +375,61 @@ public class Net{
void host(int port) throws IOException; void host(int port) throws IOException;
/** Sends a large stream of data to a specific client. */ /** 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. */ while(stream.stream.available() > 0){
void send(Object object, SendMode mode); byte[] bytes = new byte[Math.min(512, stream.stream.available())];
stream.stream.read(bytes);
/** Send an object to a specific client ID. */ StreamChunk chunk = new StreamChunk();
void sendTo(int id, Object object, SendMode mode); 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. */ default void send(Object object, SendMode mode){
void sendExcept(int id, 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. */ /** Close the server connection. */
void close(); void close();
/** Compress an input snapshot byte array. */
byte[] compressSnapshot(byte[] input);
/** Return all connected users. */ /** Return all connected users. */
Array<? extends NetConnection> getConnections(); Iterable<? extends NetConnection> getConnections();
/** Returns a connection by ID. */ /** Returns a connection by ID. */
NetConnection getByID(int 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; import io.anuke.mindustry.net.Net.SendMode;
public abstract class NetConnection{ public abstract class NetConnection{
private static int lastID;
public final int id; public final int id;
public final String address; public final String address;
@@ -18,8 +20,9 @@ public abstract class NetConnection{
public boolean hasBegunConnecting = false; public boolean hasBegunConnecting = false;
public float viewWidth, viewHeight, viewX, viewY; public float viewWidth, viewHeight, viewX, viewY;
public NetConnection(int id, String address){ /** Assigns this connection a unique ID. No two connections will ever have the same ID.*/
this.id = id; public NetConnection(String address){
this.id = lastID++;
this.address = address; this.address = address;
} }
@@ -31,7 +31,6 @@ public class FileChooser extends FloatingDialog{
private Predicate<FileHandle> filter; private Predicate<FileHandle> filter;
private Consumer<FileHandle> selectListener; private Consumer<FileHandle> selectListener;
private boolean open; 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> pngFiles = str -> str.equals("png");
public static final Predicate<String> anyMapFiles = str -> str.equals(oldMapExtension) || str.equals(mapExtension); 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.filter = filter;
this.selectListener = result; this.selectListener = result;
update(() -> { onResize(() -> {
if(Core.graphics.getWidth() != lastWidth || Core.graphics.getHeight() != lastHeight){ cont.clear();
updateFiles(false); setupWidgets();
lastHeight = Core.graphics.getHeight(); });
lastWidth = Core.graphics.getWidth();
} shown(() -> {
cont.clear();
setupWidgets();
}); });
} }
@@ -121,8 +122,9 @@ public class FileChooser extends FloatingDialog{
forward.resizeImage(isize); forward.resizeImage(isize);
forward.clicked(() -> stack.forward()); forward.clicked(() -> stack.forward());
back.clicked(() -> stack.back()); back.clicked(() -> stack.back());
forward.setDisabled(() -> !stack.canForward());
back.setDisabled(() -> !stack.canBack());
ImageButton home = new ImageButton("icon-home"); ImageButton home = new ImageButton("icon-home");
home.resizeImage(isize); home.resizeImage(isize);
@@ -206,7 +208,7 @@ public class FileChooser extends FloatingDialog{
//macs are confined to the Downloads/ directory //macs are confined to the Downloads/ directory
if(!OS.isMac){ 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"); TextButton upbutton = new TextButton(".." + directory.toString(), "clear-toggle");
upbutton.clicked(() -> { upbutton.clicked(() -> {
directory = directory.parent(); directory = directory.parent();
@@ -214,7 +216,7 @@ public class FileChooser extends FloatingDialog{
updateFiles(true); 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.getLabel().setAlignment(Align.left);
upbutton.getCells().reverse(); upbutton.getCells().reverse();
@@ -248,9 +250,9 @@ public class FileChooser extends FloatingDialog{
button.setChecked(filename.equals(filefield.getText())); 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(); button.getCells().reverse();
files.top().left().add(button).align(Align.topLeft).fillX().expandX() files.top().left().add(button).align(Align.topLeft).fillX().expandX()
.height(50).pad(2).padTop(0).padBottom(0).colspan(2); .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{ public class FileHistory{
private Array<FileHandle> history = new Array<>(); private Array<FileHandle> history = new Array<>();
private int index; private int index;
@@ -39,18 +39,6 @@ public class FloatingDialog extends Dialog{
state.set(State.paused); 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){ public FloatingDialog(String title){
@@ -59,8 +47,9 @@ public class FloatingDialog extends Dialog{
protected void onResize(Runnable run){ protected void onResize(Runnable run){
Events.on(ResizeEvent.class, event -> { Events.on(ResizeEvent.class, event -> {
if(isShown()){ if(isShown() && Core.scene.getDialog() == this){
run.run(); run.run();
updateScrollFocus();
} }
}); });
} }
@@ -1,11 +1,11 @@
package io.anuke.mindustry.ui.dialogs; package io.anuke.mindustry.ui.dialogs;
import io.anuke.arc.Core; import io.anuke.arc.*;
import io.anuke.mindustry.core.GameState.State; import io.anuke.mindustry.core.GameState.*;
import io.anuke.mindustry.game.Stats.RankResult; import io.anuke.mindustry.game.Stats.*;
import io.anuke.mindustry.game.Team; import io.anuke.mindustry.game.*;
import io.anuke.mindustry.type.Item; import io.anuke.mindustry.type.*;
import io.anuke.mindustry.type.Item.Icon; import io.anuke.mindustry.type.Item.*;
import static io.anuke.mindustry.Vars.*; import static io.anuke.mindustry.Vars.*;
@@ -1,21 +1,20 @@
package io.anuke.mindustry.ui.dialogs; package io.anuke.mindustry.ui.dialogs;
import io.anuke.annotations.Annotations.Serialize; import io.anuke.annotations.Annotations.*;
import io.anuke.arc.Core; import io.anuke.arc.*;
import io.anuke.arc.collection.Array; import io.anuke.arc.collection.*;
import io.anuke.arc.graphics.Color; import io.anuke.arc.graphics.*;
import io.anuke.arc.math.Mathf; import io.anuke.arc.math.*;
import io.anuke.arc.scene.style.Drawable; import io.anuke.arc.scene.style.*;
import io.anuke.arc.scene.ui.*; import io.anuke.arc.scene.ui.*;
import io.anuke.arc.scene.ui.layout.Cell; import io.anuke.arc.scene.ui.layout.*;
import io.anuke.arc.scene.ui.layout.Table; import io.anuke.arc.util.*;
import io.anuke.arc.util.Strings; import io.anuke.mindustry.*;
import io.anuke.arc.util.Time; import io.anuke.mindustry.core.*;
import io.anuke.mindustry.Vars; import io.anuke.mindustry.game.*;
import io.anuke.mindustry.core.Platform;
import io.anuke.mindustry.game.Version;
import io.anuke.mindustry.net.Host;
import io.anuke.mindustry.net.Net; import io.anuke.mindustry.net.Net;
import io.anuke.mindustry.net.*;
import io.anuke.mindustry.net.Packets.*;
import static io.anuke.mindustry.Vars.*; 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", () -> { TextButton button = buttons[0] = remote.addButton("[accent]" + server.displayIP(), "clear", () -> {
if(!buttons[0].childrenPressed()){ 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); button.getLabel().setWrap(true);
@@ -106,7 +106,7 @@ public class PausedDialog extends FloatingDialog{
return; 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); state.set(State.menu);
logic.reset(); logic.reset();
return; return;
@@ -241,7 +241,9 @@ public class SettingsMenuDialog extends SettingsDialog{
graphics.checkPref("fps", false); graphics.checkPref("fps", false);
graphics.checkPref("indicators", true); graphics.checkPref("indicators", true);
graphics.checkPref("animatedwater", false); 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("bloom", false, val -> renderer.toggleBloom(val));
graphics.checkPref("lasers", true); graphics.checkPref("lasers", true);
graphics.checkPref("pixelate", false); graphics.checkPref("pixelate", false);
@@ -113,9 +113,16 @@ public class ZoneInfoDialog extends FloatingDialog{
t.add("$zone.resources").padRight(6); t.add("$zone.resources").padRight(6);
if(zone.resources.length > 0){ if(zone.resources.length > 0){
for(Item item : zone.resources){ t.table(r -> {
t.addImage(item.icon(Item.Icon.medium)).size(8 * 3); 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{ }else{
t.add("$none"); t.add("$none");
} }
@@ -242,9 +242,9 @@ public class HudFragment extends Fragment{
IntFormat fps = new IntFormat("fps"); IntFormat fps = new IntFormat("fps");
IntFormat ping = new IntFormat("ping"); 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.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(); }).top().left();
}); });
+1 -3
View File
@@ -294,9 +294,7 @@ public class Block extends BlockStorage{
/** Called after the block is placed by this client. */ /** Called after the block is placed by this client. */
@CallSuper @CallSuper
public void playerPlaced(Tile tile){ public void playerPlaced(Tile tile){
if(outputsPower && !consumesPower){
PowerNode.lastPlaced = tile.pos();
}
} }
/** Called after the block is placed by anyone. */ /** 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.annotations.Annotations.*;
import io.anuke.arc.*; import io.anuke.arc.*;
import io.anuke.arc.collection.*;
import io.anuke.arc.function.*; import io.anuke.arc.function.*;
import io.anuke.arc.graphics.*; import io.anuke.arc.graphics.*;
import io.anuke.arc.graphics.g2d.*; import io.anuke.arc.graphics.g2d.*;
@@ -20,9 +21,7 @@ import io.anuke.mindustry.world.meta.*;
import static io.anuke.mindustry.Vars.*; import static io.anuke.mindustry.Vars.*;
public class PowerNode extends PowerBlock{ public class PowerNode extends PowerBlock{
//last distribution block placed protected ObjectSet<PowerGraph> graphs = new ObjectSet<>();
public static int lastPlaced = -1;
protected Vector2 t1 = new Vector2(), t2 = new Vector2(); protected Vector2 t1 = new Vector2(), t2 = new Vector2();
protected TextureRegion laser, laserEnd; protected TextureRegion laser, laserEnd;
@@ -99,23 +98,11 @@ public class PowerNode extends PowerBlock{
() -> Mathf.clamp(entity.power.graph.getPowerProduced() / entity.power.graph.getPowerNeeded()))); () -> 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 @Override
public void placed(Tile tile){ public void placed(Tile tile){
if(Net.client()) return; 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; && !other.entity.proximity().contains(tile) && other.entity.power.graph != tile.entity.power.graph;
tempTiles.clear(); tempTiles.clear();
@@ -132,6 +119,28 @@ public class PowerNode extends PowerBlock{
super.placed(tile); 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 @Override
public void setStats(){ public void setStats(){
super.setStats(); super.setStats();
@@ -213,6 +222,11 @@ 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);
});
/*
for(int cx = (int)(x - laserRange - 1); cx <= x + laserRange + 1; cx++){ for(int cx = (int)(x - laserRange - 1); cx <= x + laserRange + 1; cx++){
for(int cy = (int)(y - laserRange - 1); cy <= y + laserRange + 1; cy++){ for(int cy = (int)(y - laserRange - 1); cy <= y + laserRange + 1; cy++){
Tile link = world.ltile(cx, 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); Drawf.square(link.drawx(), link.drawy(), link.block().size * tilesize / 2f + 2f, link.pos() == lastPlaced ? Pal.place : Pal.accent);
} }
} }
} }*/
Draw.reset(); Draw.reset();
} }
@@ -67,7 +67,7 @@ public class Drill extends Block{
hasItems = true; hasItems = true;
idleSound = Sounds.drill; idleSound = Sounds.drill;
idleSoundVolume = 0.002f; idleSoundVolume = 0.003f;
} }
@Override @Override
@@ -12,6 +12,11 @@ public class LiquidConverter extends GenericCrafter{
hasLiquids = true; hasLiquids = true;
} }
@Override
public boolean outputsItems(){
return false;
}
@Override @Override
public void init(){ public void init(){
ConsumeLiquidBase cl = consumes.get(ConsumeType.liquid); 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=");
}
}
+93 -129
View File
@@ -1,43 +1,28 @@
import com.badlogicgames.packr.Packr
import com.badlogicgames.packr.PackrConfig
apply plugin: "java" apply plugin: "java"
sourceCompatibility = 1.8 sourceCompatibility = 1.8
sourceSets.main.java.srcDirs = ["src/"] sourceSets.main.java.srcDirs = [ "src/" ]
project.ext.mainClassName = "io.anuke.mindustry.desktop.DesktopLauncher" project.ext.mainClassName = "io.anuke.mindustry.desktop.DesktopLauncher"
project.ext.assetsDir = new File("../core/assets") 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 JDK_DIR = "$System.env.PACKR_DIR"
def ICON_DIR = new File("core/assets/icons/icon.icns") 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){ task run(dependsOn: classes, type: JavaExec){
main = project.mainClassName main = project.mainClassName
classpath = sourceSets.main.runtimeClasspath classpath = sourceSets.main.runtimeClasspath
standardInput = System.in standardInput = System.in
workingDir = project.assetsDir workingDir = project.assetsDir
if(System.getProperty("os.name").toLowerCase().contains("mac")){
jvmArgs "-XstartOnFirstThread"
}
ignoreExitValue = true ignoreExitValue = true
if(System.getProperty("os.name").toLowerCase().contains("mac")){
jvmArgs("-XstartOnFirstThread", "-Djava.awt.headless=true")
}
if(project.hasProperty("args")){ if(project.hasProperty("args")){
args Eval.me(project.getProperties()["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.classesDirs)
from files(sourceSets.main.output.resourcesDir) from files(sourceSets.main.output.resourcesDir)
from{ configurations.compile.collect{ zipTree(it) } } from {configurations.compile.collect {zipTree(it)}}
from files(project.assetsDir) from files(project.assetsDir)
archiveName = "${appName}.jar"
manifest{ manifest{
attributes 'Main-Class': project.mainClassName attributes 'Main-Class': project.mainClassName
} }
} }
//note: call desktop:dist beforehand
task packrCmd(){
doLast{ PackrConfig.Platform.values().each{ platform ->
def config = new PackrConfig() task "packr${platform.toString()}"{
config.with{ def platformName = platform.toString().replace('64', '').replace('32', '').replace('MacOS', 'Mac')
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"]
vmArgs = ["Djava.net.preferIPv4Stack=true"] dependsOn dist
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")
doLast{ doLast{
copy{ copy{
into "packr-out/jre/bin/" into "build/packr/"
from JDK_DIR + "zip.dll" rename("${appName}.jar", "desktop.jar")
} from "build/libs/${appName}.jar"
}
}
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){ delete{
dependsOn "fixWindows32" 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 rzip(type: Zip){ task "zip${platform.toString()}"(type: Zip){
from "packr-out/" from "build/packr/output"
archiveName "${generateDeployName(getPlatform().toString())}.zip" archiveName "${generateDeployName(platform.toString())}.zip"
destinationDir(file("packr-export")) destinationDir(file("../deploy"))
doLast{
delete{
delete "build/packr/"
}
}
} }
finalizedBy 'rzip' finalizedBy "zip${platform.toString()}"
} }
} }
+13 -1
View File
@@ -27,13 +27,25 @@
"com/sun/jndi", "com/sun/jndi",
"com/sun/xml", "com/sun/xml",
"com/sun/script", "com/sun/script",
"sum/awt", "sun/awt",
"sun/java2d", "sun/java2d",
"sun/font", "sun/font",
"sun/rmi", "sun/rmi",
"sun/swing", "sun/swing",
"java/util/stream", "java/util/stream",
"com/sun/media", "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", "com/sun/naming",
"java/awt", "java/awt",
"com/sun/org/apache/xpath", "com/sun/org/apache/xpath",
@@ -1,27 +1,29 @@
package io.anuke.mindustry.desktop; package io.anuke.mindustry.desktop;
import io.anuke.arc.backends.lwjgl3.Lwjgl3Application; import io.anuke.arc.Files.*;
import io.anuke.arc.backends.lwjgl3.Lwjgl3ApplicationConfiguration; import io.anuke.arc.backends.sdl.*;
import io.anuke.mindustry.Mindustry; import io.anuke.mindustry.*;
import io.anuke.mindustry.core.Platform; import io.anuke.mindustry.core.*;
import io.anuke.mindustry.net.*; import io.anuke.mindustry.net.*;
public class DesktopLauncher{ public class DesktopLauncher{
public static void main(String[] arg){ public static void main(String[] arg){
try{ 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); Platform.instance = new DesktopPlatform(arg);
Net.setClientProvider(new ArcNetClient()); Net.setClientProvider(new MClient());
Net.setServerProvider(new ArcNetServer()); Net.setServerProvider(new MServer());
new Lwjgl3Application(new Mindustry(), config);
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){ }catch(Throwable e){
DesktopPlatform.handleCrash(e); DesktopPlatform.handleCrash(e);
} }
@@ -1,24 +1,23 @@
package io.anuke.mindustry.desktop; package io.anuke.mindustry.desktop;
import club.minnced.discord.rpc.*; import club.minnced.discord.rpc.*;
import io.anuke.arc.collection.Array; import io.anuke.arc.backends.sdl.jni.SDL;
import io.anuke.arc.files.FileHandle; import io.anuke.arc.collection.*;
import io.anuke.arc.function.Consumer; import io.anuke.arc.files.*;
import io.anuke.arc.function.Predicate; import io.anuke.arc.function.*;
import io.anuke.arc.util.*; import io.anuke.arc.util.*;
import io.anuke.arc.util.serialization.Base64Coder; import io.anuke.arc.util.serialization.*;
import io.anuke.mindustry.core.GameState.State; import io.anuke.mindustry.core.GameState.*;
import io.anuke.mindustry.core.Platform; import io.anuke.mindustry.core.*;
import io.anuke.mindustry.net.CrashSender; import io.anuke.mindustry.net.*;
import io.anuke.mindustry.net.Net; import io.anuke.mindustry.ui.dialogs.*;
import io.anuke.mindustry.ui.dialogs.FileChooser;
import org.lwjgl.util.tinyfd.TinyFileDialogs;
import java.net.NetworkInterface; import java.net.*;
import java.util.*; import java.util.*;
import static io.anuke.mindustry.Vars.*; import static io.anuke.mindustry.Vars.*;
public class DesktopPlatform extends Platform{ public class DesktopPlatform extends Platform{
static boolean useDiscord = OS.is64Bit; static boolean useDiscord = OS.is64Bit;
final static String applicationId = "610508934456934412"; final static String applicationId = "610508934456934412";
@@ -32,7 +31,8 @@ public class DesktopPlatform extends Platform{
if(useDiscord){ if(useDiscord){
try{ try{
DiscordEventHandlers handlers = new DiscordEventHandlers(); 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)); Runtime.getRuntime().addShutdownHook(new Thread(DiscordRPC.INSTANCE::Discord_Shutdown));
}catch(Throwable t){ }catch(Throwable t){
@@ -43,16 +43,16 @@ public class DesktopPlatform extends Platform{
} }
static void handleCrash(Throwable e){ static void handleCrash(Throwable e){
Consumer<Runnable> dialog = r -> new Thread(r).start(); Consumer<Runnable> dialog = Runnable::run;
boolean badGPU = false; boolean badGPU = false;
if(e.getMessage() != null && (e.getMessage().contains("Couldn't create window") || e.getMessage().contains("OpenGL 2.0 or higher"))){ 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() : 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" + "Your graphics card does not support OpenGL 2.0!\n" +
"Try to update your graphics drivers.\n\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; badGPU = true;
} }
@@ -60,7 +60,7 @@ public class DesktopPlatform extends Platform{
CrashSender.send(e, file -> { CrashSender.send(e, file -> {
if(!fbgp){ 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 @Override
public void updateRPC(){ public void updateRPC(){
if(!useDiscord) return; if(!useDiscord) return;
DiscordRichPresence presence = new DiscordRichPresence(); DiscordRichPresence presence = new DiscordRichPresence();
@@ -118,7 +117,7 @@ public class DesktopPlatform extends Platform{
String str = new String(Base64Coder.encode(result)); 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; return str;
}catch(Exception e){ }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){ private boolean validAddress(byte[] bytes){
if(bytes == null) return false; if(bytes == null) return false;
byte[] result = new byte[8]; byte[] result = new byte[8];
System.arraycopy(bytes, 0, result, 0, bytes.length); 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
+11 -3
View File
@@ -1,7 +1,15 @@
#!/usr/bin/bash #!/usr/bin/bash
#convert ogg to .caf files for iOS cd $1
for i in $1/*.ogg; do
#convert ogg to .mp3 files for iOS
for i in *.ogg; do
echo $i echo $i
ffmpeg -i "$i" "${i%.*}.caf" ffmpeg -i "$i" "OUT_${i%.*}.mp3"
done 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