From d43b40fab557a96612e77cce8b4d1183c36a5c34 Mon Sep 17 00:00:00 2001 From: AmateurPotion <47741752+AmateurPotion@users.noreply.github.com> Date: Sun, 29 Dec 2019 01:21:55 +0900 Subject: [PATCH 01/15] Update bundle_ko.properties (#1262) --- core/assets/bundles/bundle_ko.properties | 68 +++++++++++++----------- 1 file changed, 36 insertions(+), 32 deletions(-) diff --git a/core/assets/bundles/bundle_ko.properties b/core/assets/bundles/bundle_ko.properties index 71a44a6bff..3d9c8e0475 100644 --- a/core/assets/bundles/bundle_ko.properties +++ b/core/assets/bundles/bundle_ko.properties @@ -7,14 +7,15 @@ link.reddit.description = Mindustry 레딧 link.github.description = 게임 소스코드 link.changelog.description = 새로 추가된 것들 link.dev-builds.description = 불안정한 개발 빌드들 -link.trello.description = 다음 출시될 기능들을 게시한 공식 Trello 보드 +link.trello.description = 출시 예정중인 기능들을 게시한 공식 Trello 보드 link.itch.io.description = PC 버전 다운로드와 HTML5 버전이 있는 itch.io 사이트 link.google-play.description = Google Play 스토어 정보 link.f-droid.description = F-Droid 카탈로그 link.wiki.description = 공식 Mindustry 위키 +link.feathub.description = 기능 아이디어 건의하기 linkfail = 링크를 여는 데 실패했습니다!\nURL이 기기의 클립보드에 복사되었습니다. -screenshot = 스크린샷이 {0} 경로에 저장되었습니다. -screenshot.invalid = 맵이 너무 커서 스크린샷을 찍을 메모리가 충분하지 않습니다. +screenshot = 스크린 샷이 {0} 경로에 저장되었습니다. +screenshot.invalid = 맵이 너무 커서 스크린 샷을 찍을 메모리가 충분하지 않습니다. gameover = 게임 오버 gameover.pvp = [accent]{0}[] 팀이 승리했습니다! highscore = [accent]최고점수 달성! @@ -35,11 +36,11 @@ schematic.replace = 이 설계도와 같은 이름의 설계도가 이미 존재 schematic.import = 설계도 불러오기 schematic.exportfile = 파일 내보내기 schematic.importfile = 파일 불러오기 -schematic.browseworkshop = 워크샵 탐색 +schematic.browseworkshop = Workshop 탐색 schematic.copy = 클립보드에 복사하기 schematic.copy.import = 클립보드에서 붙여넣기 schematic.shareworkshop = 워크샵에 공유 -schematic.flip = 좌우 뒤집기 :[accent][[{0}][] / 상하 뒤집기 : [accent][[{1}][] +schematic.flip = 좌우 뒤집기 : [accent][[{0}][] / 상하 뒤집기 : [accent][[{1}][] schematic.saved = 설계도 저장됨. schematic.delete.confirm = 삭제된 설계도는 복구할 수 없습니다. 정말로 삭제하시겠습니까? schematic.rename = 설계도명 변경 @@ -94,7 +95,7 @@ mods.alpha = [scarlet](Alpha) mods = 모드 mods.none = [LIGHT_GRAY]추가한 모드가 없습니다! mods.guide = 모드 가이드 -mods.report = 버그 신고 +mods.report = 문제 신고 mods.openfolder = 모드 폴더 열기 mod.enabled = [lightgray]활성화 mod.disabled = [scarlet]비활성화 @@ -102,7 +103,10 @@ mod.disable = 비활성화 mod.delete.error = 모드를 삭제할 수 없습니다. 아마도 해당 모드가 사용중인 것 같습니다. mod.requiresversion = [scarlet]게임의 버전이 낮아 모드를 활성화할 수 없습니다!\n[scarlet]요구되는 게임 버전 : [accent]{0} mod.missingdependencies = [scarlet]의존되는 모드: {0} -mod.nowdisabled = [scarlet]모드 '{0}'는 다음의 모드에 의존합니다 :[accent] {1}\n[lightgray]이 모드를 먼저 다운로드해야합니다.\n이 모드는 자동으로 비활성화됩니다. +mod.erroredcontent = [scarlet]컨텐츠 오류 +mod.errors = 컨텐츠를 불러오는 중 오류가 발생하였습니다. +mod.noerrorplay = [scarlet]모드에 오류가 존재합니다.[] 해당 오류가 발생하는 모드를 비활성화하거나 모드의 오류를 고친 후 플레이가 가능합니다. +mod.nowdisabled = [scarlet]모드 '{0}'는 다음의 모드에 의존합니다 : [accent] {1}\n[lightgray]이 모드를 먼저 다운로드해야합니다.\n이 모드는 자동으로 비활성화됩니다. mod.enable = 활성화 mod.requiresrestart = 모드 변경사항을 적용하기 위해 게임을 종료합니다. mod.reloadrequired = [scarlet]새로고침 예정됨 @@ -111,7 +115,7 @@ mod.import.github = 깃허브 모드 추가 mod.item.remove = 이것은 모드[accent] '{0}'[]의 자원입니다. 이 자원을 삭제하려면, 이 모드를 제거해야합니다. mod.remove.confirm = 이 모드를 삭제하시겠습니까? mod.author = [LIGHT_GRAY]제작자 : [] {0} -mod.missing = 이 세이브파일에는 설치하지 않은 모드 혹은 이 버전에 속해있지 않은 데이터가 포함되어 있습니다. 이 파일을 불러올 경우 세이브파일의 데이터가 손상될 수 있습니다. 정말로 이 파일을 불러오시겠습니까?\n[lightgray]모드 :\n{0} +mod.missing = 이 세이브파일에는 설치하지 않은 모드 혹은 현재 버전에 속해있지 않은 데이터가 포함되어 있습니다. 이 파일을 불러올 경우 세이브파일의 데이터가 손상될 수 있습니다. 정말로 이 파일을 불러오시겠습니까?\n[lightgray]모드 :\n{0} mod.preview.missing = 워크샵에 당신의 모드를 업로드하기 전에 미리보기 이미지를 먼저 추가해야합니다.\n[accent] preview.png[]라는 이름으로 미리보기 이미지를 당신의 모드 폴더안에 준비한 후 다시 시도해주세요. mod.folder.missing = 워크샵에는 폴더 형태의 모드만 게시할 수 있습니다.\n모드를 폴더 형태로 바꾸려면 파일을 폴더에 압축 해제하고 이전 압축파일을 제거한 후, 게임을 재시작하거나 모드를 다시 로드하십시오. mod.scripts.unsupported = 당신의 기기는 모드스크립트를 지원하지 않습니다. 모드의 일부 기능이 작동하지 않을 수 있습니다. @@ -594,8 +598,8 @@ unit.persecond = /초 unit.timesspeed = x 배 unit.percent = % unit.items = 자원 -unit.thousands = 천 -unit.millions = 백만 +unit.thousands = k +unit.millions = mil category.general = 일반 category.power = 전력 category.liquids = 액체 @@ -635,7 +639,7 @@ setting.sensitivity.name = 컨트롤러 감도 setting.saveinterval.name = 저장 간격 setting.seconds = {0} 초 setting.blockselecttimeout.name = 블록 선택 시간 초과 -setting.milliseconds = {0} 밀리초 +setting.milliseconds = {0} ms setting.fullscreen.name = 전체 화면 setting.borderlesswindow.name = 테두리 없는 창모드[LIGHT_GRAY] (재시작이 필요할 수 있습니다) setting.fps.name = FPS 표시 @@ -683,20 +687,20 @@ keybind.schematic_flip_x.name = 설계도 X축 뒤집기 keybind.schematic_flip_y.name = 설계도 Y축 뒤집기 keybind.category_prev.name = 이전 목록 keybind.category_next.name = 다음 목록 -keybind.block_select_left.name = 블럭 왼쪽 선택 -keybind.block_select_right.name = 블럭 오른쪽 선택 -keybind.block_select_up.name = 블럭 위쪽 선택 -keybind.block_select_down.name = 블럭 아래쪽 선택 -keybind.block_select_01.name = 카테고리/블럭 선택 1 -keybind.block_select_02.name = 카테고리/블럭 선택 2 -keybind.block_select_03.name = 카테고리/블럭 선택 3 -keybind.block_select_04.name = 카테고리/블럭 선택 4 -keybind.block_select_05.name = 카테고리/블럭 선택 5 -keybind.block_select_06.name = 카테고리/블럭 선택 6 -keybind.block_select_07.name = 카테고리/블럭 선택 7 -keybind.block_select_08.name = 카테고리/블럭 선택 8 -keybind.block_select_09.name = 카테고리/블럭 선택 9 -keybind.block_select_10.name = 카테고리/블럭 선택 10 +keybind.block_select_left.name = 블록 왼쪽 선택 +keybind.block_select_right.name = 블록 오른쪽 선택 +keybind.block_select_up.name = 블록 위쪽 선택 +keybind.block_select_down.name = 블록 아래쪽 선택 +keybind.block_select_01.name = 카테고리/블록 선택 1 +keybind.block_select_02.name = 카테고리/블록 선택 2 +keybind.block_select_03.name = 카테고리/블록 선택 3 +keybind.block_select_04.name = 카테고리/블록 선택 4 +keybind.block_select_05.name = 카테고리/블록 선택 5 +keybind.block_select_06.name = 카테고리/블록 선택 6 +keybind.block_select_07.name = 카테고리/블록 선택 7 +keybind.block_select_08.name = 카테고리/블록 선택 8 +keybind.block_select_09.name = 카테고리/블록 선택 9 +keybind.block_select_10.name = 카테고리/블록 선택 10 keybind.fullscreen.name = 전체 화면 keybind.select.name = 선택/공격 keybind.diagonal_placement.name = 대각선 설치 @@ -716,8 +720,8 @@ keybind.console.name = 콘솔 keybind.rotate.name = 회전 keybind.rotateplaced.name = 기존 회전 (고정) keybind.toggle_menus.name = 메뉴 보이기/숨기기 -keybind.chat_history_prev.name = 이전 채팅기록 -keybind.chat_history_next.name = 다음 채팅기록 +keybind.chat_history_prev.name = 이전 채팅 기록 +keybind.chat_history_next.name = 다음 채팅 기록 keybind.chat_scroll.name = 채팅 스크롤 keybind.drop_unit.name = 유닛 처치 시 자원획득 keybind.zoom_minimap.name = 미니맵 확대 @@ -730,11 +734,11 @@ mode.editor.name = 편집기 mode.pvp.name = PvP mode.pvp.description = 실제 플레이어와 PvP를 합니다. 맵에 적어도 2개의 다른 색상 코어가 있어야 합니다. mode.attack.name = 공격 -mode.attack.description = 적 기지를 파괴하세요. 맵에 빨간팀 코어가 있어야 플레이 가능합니다. +mode.attack.description = 적 기지를 파괴하세요. 맵에 빨간 팀 코어가 있어야 플레이 가능합니다. mode.custom = 사용자 정의 규칙 rules.infiniteresources = 무한 자원 -rules.reactorexplosions = 원자로 폭발 허가여부 +rules.reactorexplosions = 원자로 폭발 허가 여부 rules.wavetimer = 단계 대기시간 rules.waves = 단계 활성화 rules.attack = 공격 모드 @@ -750,7 +754,7 @@ rules.respawntime = 플레이어 부활 대기 시간 : [LIGHT_GRAY] (초) rules.wavespacing = 단계 간격 : [LIGHT_GRAY] (초) rules.buildcostmultiplier = 건설 소모 배수 rules.buildspeedmultiplier = 건설 속도 배수 -rules.waitForWaveToEnd = 단계가 끝날때까지 기다리는중 +rules.waitForWaveToEnd = 단계가 끝날때까지 기다리는 중 rules.dropzoneradius = 소환 충격파 범위 : [LIGHT_GRAY] (타일) rules.respawns = 단계당 최대 플레이어 부활 횟수 rules.limitedRespawns = 플레이어 부활 제한 @@ -810,7 +814,7 @@ mech.trident-ship.name = 트라이던트 mech.trident-ship.weapon = 폭탄 저장고 mech.glaive-ship.name = 글레이브 mech.glaive-ship.weapon = 중무장 인화성 소총 -item.corestorable = [lightgray]코어 잔여 저장공간: {0} +item.corestorable = [lightgray]코어 저장 가능 여부 : {0} item.explosiveness = [LIGHT_GRAY]폭발성 : {0} item.flammability = [LIGHT_GRAY]인화성 : {0} item.radioactivity = [LIGHT_GRAY]방사능 : {0} @@ -1117,7 +1121,7 @@ block.cryofluidmixer.description = 물과 티타늄을 냉각에 훨씬 더 효 block.blast-mixer.description = 포자를 사용하여 파이라타이트를 폭발성 화합물로 변환시킵니다. block.pyratite-mixer.description = 석탄, 납, 모래를 가연성이 높은 파이라타이트로 만듭니다. block.melter.description = 고철을 녹여 파도의 탄약 혹은 원심 분리기에 사용할 수 있는 액체인 광재로 만듭니다. -block.separator.description = 광재룰 각종 자원으로 재활용 할 수 있게 해 주는 건물입니다. +block.separator.description = 광재를 각종 자원으로 재활용 할 수 있게 해 주는 건물입니다. block.spore-press.description = 포자를 압축해 기름을 추출합니다. block.pulverizer.description = 고철을 갈아 모래로 만듭니다. 맵에 모래가 부족할 때 유용합니다. block.coal-centrifuge.description = 석유로 석탄을 만듭니다. From e1bf8bdab19d8c8bb5290800d9e02194bc10e060 Mon Sep 17 00:00:00 2001 From: Anuken Date: Sat, 28 Dec 2019 16:30:40 -0500 Subject: [PATCH 02/15] Added BE auto-updater / Server config / Fixed #1266 --- core/assets/bundles/bundle.properties | 7 + core/src/mindustry/Vars.java | 6 + core/src/mindustry/ai/Pathfinder.java | 2 +- core/src/mindustry/core/Version.java | 4 +- core/src/mindustry/core/World.java | 2 +- core/src/mindustry/game/EventType.java | 3 +- core/src/mindustry/net/Administration.java | 97 +++++++--- core/src/mindustry/net/BeControl.java | 168 ++++++++++++++++++ core/src/mindustry/net/CrashSender.java | 20 ++- core/src/mindustry/net/NetworkIO.java | 4 +- core/src/mindustry/ui/dialogs/ModsDialog.java | 2 +- .../mindustry/ui/fragments/MenuFragment.java | 12 ++ core/src/mindustry/world/Tile.java | 2 +- .../world/blocks/production/SolidPump.java | 8 +- gradle.properties | 2 +- run-server | 8 + .../src/mindustry/server/ServerControl.java | 146 +++++---------- 17 files changed, 349 insertions(+), 144 deletions(-) create mode 100644 core/src/mindustry/net/BeControl.java diff --git a/core/assets/bundles/bundle.properties b/core/assets/bundles/bundle.properties index 9ee0b4842a..2b2a1aa548 100644 --- a/core/assets/bundles/bundle.properties +++ b/core/assets/bundles/bundle.properties @@ -29,6 +29,13 @@ load.system = System load.mod = Mods load.scripts = Scripts +be.update = A new Bleeding Edge build is available: +be.update.confirm = Download it and restart now? +be.updating = Updating... +be.ignore = Ignore +be.noupdates = No updates found. +be.check = Check for updates + schematic = Schematic schematic.add = Save Schematic... schematics = Schematics diff --git a/core/src/mindustry/Vars.java b/core/src/mindustry/Vars.java index dfefeb2a68..2cfa4bad45 100644 --- a/core/src/mindustry/Vars.java +++ b/core/src/mindustry/Vars.java @@ -21,6 +21,7 @@ import mindustry.gen.*; import mindustry.input.*; import mindustry.maps.*; import mindustry.mod.*; +import mindustry.net.*; import mindustry.net.Net; import mindustry.world.blocks.defense.ForceProjector.*; @@ -136,6 +137,8 @@ public class Vars implements Loadable{ public static Fi modDirectory; /** data subdirectory used for schematics */ public static Fi schematicDirectory; + /** data subdirectory used for bleeding edge build versions */ + public static Fi bebuildDirectory; /** map file extension */ public static final String mapExtension = "msav"; /** save file extension */ @@ -157,6 +160,7 @@ public class Vars implements Loadable{ public static Platform platform = new Platform(){}; public static Mods mods; public static Schematics schematics = new Schematics(); + public static BeControl becontrol; public static World world; public static Maps maps; @@ -220,6 +224,7 @@ public class Vars implements Loadable{ defaultWaves = new DefaultWaves(); collisions = new EntityCollisions(); world = new World(); + becontrol = new BeControl(); maps = new Maps(); spawner = new WaveSpawner(); @@ -260,6 +265,7 @@ public class Vars implements Loadable{ tmpDirectory = dataDirectory.child("tmp/"); modDirectory = dataDirectory.child("mods/"); schematicDirectory = dataDirectory.child("schematics/"); + bebuildDirectory = dataDirectory.child("be_builds/"); modDirectory.mkdirs(); diff --git a/core/src/mindustry/ai/Pathfinder.java b/core/src/mindustry/ai/Pathfinder.java index 6a2515bb7a..a16ac8f410 100644 --- a/core/src/mindustry/ai/Pathfinder.java +++ b/core/src/mindustry/ai/Pathfinder.java @@ -139,7 +139,7 @@ public class Pathfinder implements Runnable{ //stop looping when interrupted externally return; } - }catch(Exception e){ + }catch(Throwable e){ e.printStackTrace(); } } diff --git a/core/src/mindustry/core/Version.java b/core/src/mindustry/core/Version.java index 700b8776e6..08a105d8fb 100644 --- a/core/src/mindustry/core/Version.java +++ b/core/src/mindustry/core/Version.java @@ -9,9 +9,9 @@ import arc.util.io.*; public class Version{ /** Build type. 'official' for official releases; 'custom' or 'bleeding edge' are also used. */ - public static String type; + public static String type = "unknown"; /** Build modifier, e.g. 'alpha' or 'release' */ - public static String modifier; + public static String modifier = "unknown"; /** Number specifying the major version, e.g. '4' */ public static int number; /** Build number, e.g. '43'. set to '-1' for custom builds. */ diff --git a/core/src/mindustry/core/World.java b/core/src/mindustry/core/World.java index ea0e9aa054..bbc3f4074c 100644 --- a/core/src/mindustry/core/World.java +++ b/core/src/mindustry/core/World.java @@ -217,7 +217,7 @@ public class World{ public void loadMap(Map map, Rules checkRules){ try{ SaveIO.load(map.file, new FilterContext(map)); - }catch(Exception e){ + }catch(Throwable e){ Log.err(e); if(!headless){ ui.showErrorMessage("$map.invalid"); diff --git a/core/src/mindustry/game/EventType.java b/core/src/mindustry/game/EventType.java index dfa1469fc1..6cbaba5e4b 100644 --- a/core/src/mindustry/game/EventType.java +++ b/core/src/mindustry/game/EventType.java @@ -28,7 +28,8 @@ public class EventType{ exclusionDeath, suicideBomb, openWiki, - teamCoreDamage + teamCoreDamage, + socketConfigChanged } public static class WinEvent{} diff --git a/core/src/mindustry/net/Administration.java b/core/src/mindustry/net/Administration.java index dabf679d34..157566a5c3 100644 --- a/core/src/mindustry/net/Administration.java +++ b/core/src/mindustry/net/Administration.java @@ -18,11 +18,6 @@ public class Administration{ private Array chatFilters = new Array<>(); public Administration(){ - Core.settings.defaults( - "strict", true, - "servername", "Server" - ); - load(); } @@ -51,21 +46,12 @@ public class Administration{ Core.settings.putSave("playerlimit", limit); } - public void setStrict(boolean on){ - Core.settings.putSave("strict", on); - } - public boolean getStrict(){ - return Core.settings.getBool("strict"); + return Config.strict.bool(); } public boolean allowsCustomClients(){ - return Core.settings.getBool("allow-custom", !headless); - } - - public void setCustomClients(boolean allowed){ - Core.settings.put("allow-custom", allowed); - Core.settings.save(); + return Config.allowCustomClients.bool(); } /** Call when a player joins to update their information here. */ @@ -219,11 +205,7 @@ public class Administration{ } public boolean isWhitelistEnabled(){ - return Core.settings.getBool("whitelist", false); - } - - public void setWhitelist(boolean enabled){ - Core.settings.putSave("whitelist", enabled); + return Config.whitelist.bool(); } public boolean isWhitelisted(String id, String usid){ @@ -333,6 +315,79 @@ public class Administration{ whitelist = Core.settings.getObject("whitelisted", Array.class, Array::new); } + /** Server configuration definition. Each config value can be a string, boolean or number. */ + public enum Config{ + name("The server name as displayed on clients.", "Server", "servername"), + port("The port to host on.", Vars.port), + autoUpdate("Whether to auto-restart when a new update arrives.", false), + crashReport("Whether to send crash reports.", false, "crashreport"), + logging("Whether to log everything to files.", true), + strict("Whether strict mode is on - corrects positions and prevents duplicate UUIDs.", true), + socketInput("Allows a local application to control this server through a local TCP socket.", false, "socket", () -> Events.fire(Trigger.socketConfigChanged)), + socketInputPort("The port for socket input.", 6859, () -> Events.fire(Trigger.socketConfigChanged)), + socketInputAddress("The bind address for socket input.", "localhost", () -> Events.fire(Trigger.socketConfigChanged)), + allowCustomClients("Whether custom clients are allowed to connect.", !headless, "allow-custom"), + whitelist("Whether the whitelist is used.", false); + + public static final Config[] all = values(); + + public final Object defaultValue; + public final String key, description; + final Runnable changed; + + Config(String description, Object def){ + this(description, def, null, null); + } + + Config(String description, Object def, String key){ + this(description, def, key, null); + } + + Config(String description, Object def, Runnable changed){ + this(description, def, null, changed); + } + + Config(String description, Object def, String key, Runnable changed){ + this.description = description; + this.key = key == null ? name() : key; + this.defaultValue = def; + this.changed = changed == null ? () -> {} : changed; + } + + public boolean isNum(){ + return defaultValue instanceof Integer; + } + + public boolean isBool(){ + return defaultValue instanceof Boolean; + } + + public boolean isString(){ + return defaultValue instanceof String; + } + + public Object get(){ + return Core.settings.get(key, defaultValue); + } + + public boolean bool(){ + return Core.settings.getBool(key, (Boolean)defaultValue); + } + + public int num(){ + return Core.settings.getInt(key, (Integer)defaultValue); + } + + public String string(){ + return Core.settings.getString(key, (String)defaultValue); + } + + public void set(Object value){ + Core.settings.putSave(key, value); + changed.run(); + } + } + @Serialize public static class PlayerInfo{ public String id; diff --git a/core/src/mindustry/net/BeControl.java b/core/src/mindustry/net/BeControl.java new file mode 100644 index 0000000000..d81c5e721d --- /dev/null +++ b/core/src/mindustry/net/BeControl.java @@ -0,0 +1,168 @@ +package mindustry.net; + +import arc.*; +import arc.Net.*; +import arc.files.*; +import arc.func.*; +import arc.util.*; +import arc.util.async.*; +import arc.util.serialization.*; +import mindustry.core.*; +import mindustry.gen.*; +import mindustry.graphics.*; +import mindustry.net.Administration.*; +import mindustry.ui.*; +import mindustry.ui.dialogs.*; + +import java.io.*; +import java.net.*; + +import static mindustry.Vars.*; + +/** Handles control of bleeding edge builds. */ +public class BeControl{ + private static final int updateInterval = 60; + + private AsyncExecutor executor = new AsyncExecutor(1); + private boolean checkUpdates = true; + private boolean updateAvailable; + private String updateUrl; + private int updateBuild; + + /** @return whether this is a bleeding edge build. */ + public boolean active(){ + return Version.type.equals("bleeding-edge"); + } + + public BeControl(){ + if(active()){ + Timer.schedule(() -> { + if(checkUpdates && !mobile){ + checkUpdate(t -> {}); + } + }, 1, updateInterval); + } + } + + /** asynchronously checks for updates. */ + public void checkUpdate(Boolc done){ + Core.net.httpGet("https://api.github.com/repos/Anuken/MindustryBuilds/releases/latest", res -> { + if(res.getStatus() == HttpStatus.OK){ + Jval val = Jval.read(res.getResultAsString()); + int newBuild = Strings.parseInt(val.getString("tag_name", "0")); + if(newBuild > Version.build){ + Jval asset = val.get("assets").asArray().find(v -> v.getString("name", "").startsWith(headless ? "Mindustry-BE-Server" : "Mindustry-BE-Desktop")); + String url = asset.getString("browser_download_url", ""); + updateAvailable = true; + updateBuild = newBuild; + updateUrl = url; + showUpdateDialog(); + Core.app.post(() -> done.get(true)); + }else{ + Core.app.post(() -> done.get(false)); + } + }else{ + Core.app.post(() -> done.get(false)); + Log.err("Update check responded with: {0}", res.getStatus()); + } + }, error -> { + if(!headless){ + ui.showException(error); + }else{ + error.printStackTrace(); + } + }); + } + + /** @return whether a new update is available */ + public boolean isUpdateAvailable(){ + return updateAvailable; + } + + /** shows the dialog for updating the game on desktop, or a prompt for doing so on the server */ + public void showUpdateDialog(){ + if(!updateAvailable) return; + + if(!headless){ + ui.showCustomConfirm(Core.bundle.format("be.update", "") + " " + updateBuild, "$be.update.confirm", "$ok", "$be.ignore", () -> { + boolean[] cancel = {false}; + float[] progress = {0}; + int[] length = {0}; + Fi file = bebuildDirectory.child("client-be-" + updateBuild + ".jar"); + + FloatingDialog dialog = new FloatingDialog("$be.updating"); + download(updateUrl, file, i -> length[0] = i, v -> progress[0] = v, () -> cancel[0], () -> { + try{ + Runtime.getRuntime().exec(new String[]{"java", "-DlastBuild=" + Version.build, "-Dberestart", "-jar", file.absolutePath()}); + System.exit(0); + }catch(IOException e){ + ui.showException(e); + } + }, e -> { + dialog.hide(); + ui.showException(e); + }); + + dialog.cont.add(new Bar(() -> length[0] == 0 ? Core.bundle.get("be.updating") : (int)(progress[0] * length[0]) / 1024/ 1024 + "/" + length[0]/1024/1024 + " MB", () -> Pal.accent, () -> progress[0])).width(400f).height(70f); + dialog.buttons.addImageTextButton("$cancel", Icon.cancelSmall, () -> { + cancel[0] = true; + dialog.hide(); + }).size(210f, 64f); + dialog.setFillParent(false); + dialog.show(); + }, () -> checkUpdates = false); + }else{ + Log.info("&lcA new update is available: &lyBleeding Edge build {0}", updateBuild); + if(Config.autoUpdate.bool()){ + Log.info("&lcAuto-downloading next version..."); + + try{ + Fi source = Fi.get(BeControl.class.getProtectionDomain().getCodeSource().getLocation().toURI().getPath()); + Fi dest = source.sibling("server-be-" + updateBuild + ".jar"); + + download(updateUrl, dest, + len -> Core.app.post(() -> Log.info("&ly| Size: {0} MB.", Strings.fixed((float)len / 1024 / 1024, 2))), + progress -> {}, + () -> false, + () -> { + Log.info("&lcVersion downloaded, exiting. Note that if you are not using the run-server script, the server will not restart automatically."); + dest.copyTo(source); + dest.delete(); + System.exit(2); //this will cause a restart if using the script + }, + Throwable::printStackTrace); + }catch(Exception e){ + e.printStackTrace(); + } + } + checkUpdates = false; + //todo server updates + } + } + + private void download(String furl, Fi dest, Intc length, Floatc progressor, Boolp canceled, Runnable done, Cons error){ + executor.submit(() -> { + try{ + HttpURLConnection con = (HttpURLConnection)new URL(furl).openConnection(); + BufferedInputStream in = new BufferedInputStream(con.getInputStream()); + OutputStream out = dest.write(false, 4096); + + byte[] data = new byte[4096]; + long size = con.getContentLength(); + long counter = 0; + length.get((int)size); + int x; + while((x = in.read(data, 0, data.length)) >= 0 && !canceled.get()){ + counter += x; + progressor.get((float)counter / (float)size); + out.write(data, 0, x); + } + out.close(); + in.close(); + if(!canceled.get()) done.run(); + }catch(Throwable e){ + error.get(e); + } + }); + } +} diff --git a/core/src/mindustry/net/CrashSender.java b/core/src/mindustry/net/CrashSender.java index 43692c77d6..1b24b2af3a 100644 --- a/core/src/mindustry/net/CrashSender.java +++ b/core/src/mindustry/net/CrashSender.java @@ -27,7 +27,9 @@ public class CrashSender{ exception.printStackTrace(); //don't create crash logs for custom builds, as it's expected - if(Version.build == -1 || (System.getProperty("user.name").equals("anuke") && "release".equals(Version.modifier))) return; + if(Version.build == -1 || (System.getProperty("user.name").equals("anuke") && "release".equals(Version.modifier))){ + ret(); + } //attempt to load version regardless if(Version.number == 0){ @@ -63,7 +65,7 @@ public class CrashSender{ try{ //check crash report setting if(!Core.settings.getBool("crashreport", true)){ - return; + ret(); } }catch(Throwable ignored){ //if there's no settings init we don't know what the user wants but chances are it's an important crash, so send it anyway @@ -72,14 +74,14 @@ public class CrashSender{ try{ //check any mods - if there are any, don't send reports if(Vars.mods != null && !Vars.mods.list().isEmpty()){ - return; + ret(); } }catch(Throwable ignored){ } //do not send exceptions that occur for versions that can't be parsed if(Version.number == 0){ - return; + ret(); } boolean netActive = false, netServer = false; @@ -130,12 +132,16 @@ public class CrashSender{ while(!sent[0]){ Thread.sleep(30); } - }catch(InterruptedException ignored){ - } + }catch(InterruptedException ignored){} }catch(Throwable death){ death.printStackTrace(); - System.exit(1); } + + ret(); + } + + private static void ret(){ + System.exit(1); } private static void httpPost(String url, String content, Cons success, Cons failure){ diff --git a/core/src/mindustry/net/NetworkIO.java b/core/src/mindustry/net/NetworkIO.java index d877ac6e3a..1c6e1acba2 100644 --- a/core/src/mindustry/net/NetworkIO.java +++ b/core/src/mindustry/net/NetworkIO.java @@ -1,12 +1,12 @@ package mindustry.net; -import arc.*; import arc.util.*; import mindustry.core.*; import mindustry.entities.type.*; import mindustry.game.*; import mindustry.io.*; import mindustry.maps.Map; +import mindustry.net.Administration.*; import java.io.*; import java.nio.*; @@ -62,7 +62,7 @@ public class NetworkIO{ } public static ByteBuffer writeServerData(){ - String name = (headless ? Core.settings.getString("servername") : player.name); + String name = (headless ? Config.name.string() : player.name); String map = world.getMap() == null ? "None" : world.getMap().name(); ByteBuffer buffer = ByteBuffer.allocate(256); diff --git a/core/src/mindustry/ui/dialogs/ModsDialog.java b/core/src/mindustry/ui/dialogs/ModsDialog.java index 96b71b6861..4b42f64d80 100644 --- a/core/src/mindustry/ui/dialogs/ModsDialog.java +++ b/core/src/mindustry/ui/dialogs/ModsDialog.java @@ -32,7 +32,7 @@ public class ModsDialog extends FloatingDialog{ buttons.row(); - buttons.addImageTextButton("$mods.guide", Icon.wiki, + buttons.addImageTextButton("$mods.guide", Icon.link, () -> Core.net.openURI(modGuideURL)) .size(210, 64f); diff --git a/core/src/mindustry/ui/fragments/MenuFragment.java b/core/src/mindustry/ui/fragments/MenuFragment.java index 535f4d6046..8737db0d9a 100644 --- a/core/src/mindustry/ui/fragments/MenuFragment.java +++ b/core/src/mindustry/ui/fragments/MenuFragment.java @@ -59,6 +59,18 @@ public class MenuFragment extends Fragment{ if(mobile){ parent.fill(c -> c.bottom().left().addButton("", Styles.infot, ui.about::show).size(84, 45)); parent.fill(c -> c.bottom().right().addButton("", Styles.discordt, ui.discord::show).size(84, 45)); + }else if(becontrol.active()){ + parent.fill(c -> c.bottom().right().addImageTextButton("$be.check", Icon.refreshSmall, () -> { + ui.loadfrag.show(); + becontrol.checkUpdate(result -> { + ui.loadfrag.hide(); + if(!result){ + ui.showInfo("$be.noupdates"); + } + }); + }).size(200, 60).update(t -> { + t.getLabel().setColor(becontrol.isUpdateAvailable() ? Tmp.c1.set(Color.white).lerp(Pal.accent, Mathf.absin(5f, 1f)) : Color.white); + })); } String versionText = "[#ffffffba]" + ((Version.build == -1) ? "[#fc8140aa]custom build" : (Version.type.equals("official") ? Version.modifier : Version.type) + " build " + Version.build + (Version.revision == 0 ? "" : "." + Version.revision)); diff --git a/core/src/mindustry/world/Tile.java b/core/src/mindustry/world/Tile.java index 0572c74286..119af5b8df 100644 --- a/core/src/mindustry/world/Tile.java +++ b/core/src/mindustry/world/Tile.java @@ -257,7 +257,7 @@ public class Tile implements Position, TargetTrait{ } public boolean solid(){ - return block.solid || block.isSolidFor(this) || (isLinked() && link().solid()); + return block.solid || block.isSolidFor(this) || (isLinked() && link() != this && link().solid()); } public boolean breakable(){ diff --git a/core/src/mindustry/world/blocks/production/SolidPump.java b/core/src/mindustry/world/blocks/production/SolidPump.java index 854d4be010..ac199c7b27 100644 --- a/core/src/mindustry/world/blocks/production/SolidPump.java +++ b/core/src/mindustry/world/blocks/production/SolidPump.java @@ -4,6 +4,7 @@ import arc.Core; import arc.graphics.g2d.Draw; import arc.graphics.g2d.TextureRegion; import arc.math.Mathf; +import arc.util.*; import mindustry.content.Fx; import mindustry.content.Liquids; import mindustry.entities.Effects; @@ -51,8 +52,8 @@ public class SolidPump extends Pump{ public void setBars(){ super.setBars(); bars.add("efficiency", entity -> new Bar(() -> - Core.bundle.formatFloat("bar.efficiency", - ((((SolidPumpEntity)entity).boost + 1f) * ((SolidPumpEntity)entity).warmup) * 100 * percentSolid(entity.tile.x, entity.tile.y), 1), + Core.bundle.formatFloat("bar.pumpspeed", + ((SolidPumpEntity)entity).lastPump / Time.delta() * 60, 1), () -> Pal.ammo, () -> ((SolidPumpEntity)entity).warmup)); } @@ -104,11 +105,13 @@ public class SolidPump extends Pump{ if(tile.entity.cons.valid() && typeLiquid(tile) < liquidCapacity - 0.001f){ float maxPump = Math.min(liquidCapacity - typeLiquid(tile), pumpAmount * entity.delta() * fraction * entity.efficiency()); tile.entity.liquids.add(result, maxPump); + entity.lastPump = maxPump; entity.warmup = Mathf.lerpDelta(entity.warmup, 1f, 0.02f); if(Mathf.chance(entity.delta() * updateEffectChance)) Effects.effect(updateEffect, entity.x + Mathf.range(size * 2f), entity.y + Mathf.range(size * 2f)); }else{ entity.warmup = Mathf.lerpDelta(entity.warmup, 0f, 0.02f); + entity.lastPump = 0f; } entity.pumpTime += entity.warmup * entity.delta(); @@ -153,5 +156,6 @@ public class SolidPump extends Pump{ public float warmup; public float pumpTime; public float boost; + public float lastPump; } } diff --git a/gradle.properties b/gradle.properties index 19101944cf..0b0bc673e4 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,3 +1,3 @@ org.gradle.daemon=true org.gradle.jvmargs=-Xms256m -Xmx1024m -archash=60a9ebe264f92f2c3082596c77b9ab29474c4a7f +archash=0e25944f7f3a065ed6707f0dbe48548980cad8a6 diff --git a/run-server b/run-server index 0358cb521b..25a8254723 100755 --- a/run-server +++ b/run-server @@ -5,4 +5,12 @@ if [[ $# -eq 0 ]] ; then fi ./gradlew server:dist -Pbuildversion=$1 + +while true; do +#auto-restart until ctrl-c or exit 0 java -jar -XX:+HeapDumpOnOutOfMemoryError server/build/libs/server-release.jar +excode=$? +if [ $excode -eq 0 ] || [ $excode -eq 130 ]; then + exit 0 +fi +done diff --git a/server/src/mindustry/server/ServerControl.java b/server/src/mindustry/server/ServerControl.java index 3637ac972e..f1dbb59803 100644 --- a/server/src/mindustry/server/ServerControl.java +++ b/server/src/mindustry/server/ServerControl.java @@ -40,7 +40,6 @@ import static mindustry.Vars.*; public class ServerControl implements ApplicationListener{ private static final int roundExtraTime = 12; private static final int maxLogLength = 1024 * 512; - private static final int commandSocketPort = 6859; protected static String[] tags = {"&lc&fb[D]", "&lg&fb[I]", "&ly&fb[W]", "&lr&fb[E]", ""}; protected static DateTimeFormatter dateTime = DateTimeFormatter.ofPattern("MM-dd-yyyy | HH:mm:ss"); @@ -64,10 +63,6 @@ public class ServerControl implements ApplicationListener{ "bans", "", "admins", "", "shufflemode", "custom", - "crashreport", false, - "port", port, - "logging", true, - "socket", false, "globalrules", "{reactorExplosions: false}" ); @@ -75,7 +70,7 @@ public class ServerControl implements ApplicationListener{ String result = "[" + dateTime.format(LocalDateTime.now()) + "] " + format(tags[level.ordinal()] + " " + text + "&fr", args1); System.out.println(result); - if(Core.settings.getBool("logging")){ + if(Config.logging.bool()){ logToFile("[" + dateTime.format(LocalDateTime.now()) + "] " + format(tags[level.ordinal()] + " " + text + "&fr", false, args1)); } @@ -158,16 +153,19 @@ public class ServerControl implements ApplicationListener{ } }); + Events.on(Trigger.socketConfigChanged, () -> { + toggleSocket(false); + toggleSocket(Config.socketInput.bool()); + }); + if(!mods.list().isEmpty()){ info("&lc{0} mods loaded.", mods.list().size); } + toggleSocket(Config.socketInput.bool()); + info("&lcServer loaded. Type &ly'help'&lc for help."); System.out.print("> "); - - if(Core.settings.getBool("socket")){ - toggleSocket(true); - } } private void registerCommands(){ @@ -247,21 +245,6 @@ public class ServerControl implements ApplicationListener{ } }); - handler.register("port", "[port]", "Sets or displays the port for hosting the server.", arg -> { - if(arg.length == 0){ - info("&lyPort: &lc{0}", Core.settings.getInt("port")); - }else{ - int port = Strings.parseInt(arg[0]); - if(port < 0 || port > 65535){ - err("Port must be a number between 0 and 65535."); - return; - } - info("&lyPort set to {0}.", port); - Core.settings.put("port", port); - Core.settings.save(); - } - }); - handler.register("maps", "Display all available maps.", arg -> { if(!maps.all().isEmpty()){ info("Maps:"); @@ -440,16 +423,6 @@ public class ServerControl implements ApplicationListener{ }); - handler.register("name", "[name...]", "Change the server display name.", arg -> { - if(arg.length == 0){ - info("Server name is currently &lc'{0}'.", Core.settings.getString("servername")); - return; - } - Core.settings.put("servername", arg[0]); - Core.settings.save(); - info("Server name is now &lc'{0}'.", arg[0]); - }); - handler.register("playerlimit", "[off/somenumber]", "Set the server player limit.", arg -> { if(arg.length == 0){ info("Player limit is currently &lc{0}.", netServer.admins.getPlayerLimit() == 0 ? "off" : netServer.admins.getPlayerLimit()); @@ -470,14 +443,40 @@ public class ServerControl implements ApplicationListener{ } }); - handler.register("whitelist", "[on/off...]", "Enable/disable whitelisting.", arg -> { + handler.register("config", "[name] [value]", "Configure server settings.", arg -> { if(arg.length == 0){ - info("Whitelist is currently &lc{0}.", netServer.admins.isWhitelistEnabled() ? "on" : "off"); + info("&lyAll config values:"); + for(Config c : Config.all){ + Log.info("&ly| &lc{0}:&lm {1}", c.name(), c.get()); + Log.info("&ly| | {0}", c.description); + Log.info("&ly|"); + } return; } - boolean on = arg[0].equalsIgnoreCase("on"); - netServer.admins.setWhitelist(on); - info("Whitelist is now &lc{0}.", on ? "on" : "off"); + + try{ + Config c = Config.valueOf(arg[0]); + if(arg.length == 1){ + Log.info("&lc'{0}'&lg is currently &lc{0}.", c.name(), c.get()); + }else{ + if(c.isBool()){ + c.set(arg[1].equals("on") || arg[1].equals("true")); + }else if(c.isNum()){ + try{ + c.set(Integer.parseInt(arg[1])); + }catch(NumberFormatException e){ + Log.err("Not a valid number: {0}", arg[1]); + return; + } + }else if(c.isString()){ + c.set(arg[1]); + } + + Log.info("&lc{0}&lg set to &lc{1}.", c.name(), c.get()); + } + }catch(IllegalArgumentException e){ + err("Unknown config: '{0}'. Run the command with no arguments to get a list of valid configs.", arg[0]); + } }); handler.register("whitelisted", "List the entire whitelist.", arg -> { @@ -512,67 +511,6 @@ public class ServerControl implements ApplicationListener{ info("Player &ly'{0}'&lg has been un-whitelisted.", info.lastName); }); - handler.register("sync", "[on/off...]", "Enable/disable block sync. Experimental.", arg -> { - if(arg.length == 0){ - info("Block sync is currently &lc{0}.", Core.settings.getBool("blocksync") ? "enabled" : "disabled"); - return; - } - boolean on = arg[0].equalsIgnoreCase("on"); - Core.settings.putSave("blocksync", on); - info("Block syncing is now &lc{0}.", on ? "on" : "off"); - }); - - handler.register("crashreport", "", "Disables or enables automatic crash reporting", arg -> { - boolean value = arg[0].equalsIgnoreCase("on"); - Core.settings.put("crashreport", value); - Core.settings.save(); - info("Crash reporting is now {0}.", value ? "on" : "off"); - }); - - handler.register("logging", "", "Disables or enables server logs", arg -> { - boolean value = arg[0].equalsIgnoreCase("on"); - Core.settings.put("logging", value); - Core.settings.save(); - info("Logging is now {0}.", value ? "on" : "off"); - }); - - handler.register("strict", "", "Disables or enables strict mode", arg -> { - boolean value = arg[0].equalsIgnoreCase("on"); - netServer.admins.setStrict(value); - info("Strict mode is now {0}.", netServer.admins.getStrict() ? "on" : "off"); - }); - - handler.register("socketinput", "[on/off]", "Disables or enables a local TCP socket at port "+commandSocketPort+" to recieve commands from other applications", arg -> { - if(arg.length == 0){ - info("Socket input is currently &lc{0}.", Core.settings.getBool("socket") ? "on" : "off"); - return; - } - - boolean value = arg[0].equalsIgnoreCase("on"); - toggleSocket(value); - Core.settings.put("socket", value); - Core.settings.save(); - info("Socket input is now &lc{0}.", value ? "on" : "off"); - }); - - handler.register("allow-custom-clients", "[on/off]", "Allow or disallow custom clients.", arg -> { - if(arg.length == 0){ - info("Custom clients are currently &lc{0}.", netServer.admins.allowsCustomClients() ? "allowed" : "disallowed"); - return; - } - - String s = arg[0]; - if(s.equalsIgnoreCase("on")){ - netServer.admins.setCustomClients(true); - info("Custom clients enabled."); - }else if(s.equalsIgnoreCase("off")){ - netServer.admins.setCustomClients(false); - info("Custom clients disabled."); - }else{ - err("Incorrect command usage."); - } - }); - handler.register("shuffle", "[none/all/custom/builtin]", "Set map shuffling mode.", arg -> { if(arg.length == 0){ info("Shuffle mode current set to &ly'{0}'&lg.", maps.getShuffleMode()); @@ -933,8 +871,8 @@ public class ServerControl implements ApplicationListener{ private void host(){ try{ - net.host(Core.settings.getInt("port")); - info("&lcOpened a server on port {0}.", Core.settings.getInt("port")); + net.host(Config.port.num()); + info("&lcOpened a server on port {0}.", Config.port.num()); }catch(BindException e){ Log.err("Unable to host: Port already in use! Make sure no other servers are running on the same port in your network."); state.set(State.menu); @@ -968,7 +906,7 @@ public class ServerControl implements ApplicationListener{ socketThread = new Thread(() -> { try{ serverSocket = new ServerSocket(); - serverSocket.bind(new InetSocketAddress("localhost", commandSocketPort)); + serverSocket.bind(new InetSocketAddress(Config.socketInputAddress.string(), Config.socketInputPort.num())); while(true){ Socket client = serverSocket.accept(); info("&lmRecieved command socket connection: &lb{0}", serverSocket.getLocalSocketAddress()); From 179bf4d525dbe3f4bf23df9e837a95f7b291fc70 Mon Sep 17 00:00:00 2001 From: Anuken Date: Sat, 28 Dec 2019 16:34:35 -0500 Subject: [PATCH 03/15] Added BE-specific server list --- core/src/mindustry/Vars.java | 4 +++- core/src/mindustry/net/BeControl.java | 3 ++- core/src/mindustry/ui/dialogs/JoinDialog.java | 2 +- servers_be.json | 1 + 4 files changed, 7 insertions(+), 3 deletions(-) create mode 100644 servers_be.json diff --git a/core/src/mindustry/Vars.java b/core/src/mindustry/Vars.java index 2cfa4bad45..80e6241e09 100644 --- a/core/src/mindustry/Vars.java +++ b/core/src/mindustry/Vars.java @@ -54,8 +54,10 @@ public class Vars implements Loadable{ public static final String crashReportURL = "http://192.99.169.18/report"; /** URL the links to the wiki's modding guide.*/ public static final String modGuideURL = "https://mindustrygame.github.io/wiki/modding/"; - /** URL to the JSON file containing all the global, public servers. */ + /** URL to the JSON file containing all the global, public servers. Not queried in BE. */ public static final String serverJsonURL = "https://raw.githubusercontent.com/Anuken/Mindustry/master/servers.json"; + /** URL to the JSON file containing all the BE servers. Only queried in BE. */ + public static final String serverJsonBeURL = "https://raw.githubusercontent.com/Anuken/Mindustry/master/servers_be.json"; /** URL the links to the wiki's modding guide.*/ public static final String reportIssueURL = "https://github.com/Anuken/Mindustry/issues/new?template=bug_report.md"; /** list of built-in servers.*/ diff --git a/core/src/mindustry/net/BeControl.java b/core/src/mindustry/net/BeControl.java index d81c5e721d..4de581108f 100644 --- a/core/src/mindustry/net/BeControl.java +++ b/core/src/mindustry/net/BeControl.java @@ -117,6 +117,7 @@ public class BeControl{ Log.info("&lcAuto-downloading next version..."); try{ + //download new file from github Fi source = Fi.get(BeControl.class.getProtectionDomain().getCodeSource().getLocation().toURI().getPath()); Fi dest = source.sibling("server-be-" + updateBuild + ".jar"); @@ -126,6 +127,7 @@ public class BeControl{ () -> false, () -> { Log.info("&lcVersion downloaded, exiting. Note that if you are not using the run-server script, the server will not restart automatically."); + //replace old file with new dest.copyTo(source); dest.delete(); System.exit(2); //this will cause a restart if using the script @@ -136,7 +138,6 @@ public class BeControl{ } } checkUpdates = false; - //todo server updates } } diff --git a/core/src/mindustry/ui/dialogs/JoinDialog.java b/core/src/mindustry/ui/dialogs/JoinDialog.java index 4c8ae3cc58..8984939bcf 100644 --- a/core/src/mindustry/ui/dialogs/JoinDialog.java +++ b/core/src/mindustry/ui/dialogs/JoinDialog.java @@ -362,7 +362,7 @@ public class JoinDialog extends FloatingDialog{ servers = Core.settings.getObject("server-list", Array.class, Array::new); //get servers - Core.net.httpGet(serverJsonURL, result -> { + Core.net.httpGet(becontrol.active() ? serverJsonBeURL : serverJsonURL, result -> { try{ Jval val = Jval.read(result.getResultAsString()); Core.app.post(() -> { diff --git a/servers_be.json b/servers_be.json new file mode 100644 index 0000000000..0637a088a0 --- /dev/null +++ b/servers_be.json @@ -0,0 +1 @@ +[] \ No newline at end of file From d3c559fa0061a26963e0daeee6261331f77dda19 Mon Sep 17 00:00:00 2001 From: Anuken Date: Sat, 28 Dec 2019 17:33:17 -0500 Subject: [PATCH 04/15] Moved server run scripts --- core/src/mindustry/net/Administration.java | 2 +- core/src/mindustry/net/BeControl.java | 2 +- server/run-jar | 19 +++++++++++++++++++ run-server => server/run-server | 11 ++++++++++- 4 files changed, 31 insertions(+), 3 deletions(-) create mode 100755 server/run-jar rename run-server => server/run-server (81%) diff --git a/core/src/mindustry/net/Administration.java b/core/src/mindustry/net/Administration.java index 157566a5c3..268e8d089f 100644 --- a/core/src/mindustry/net/Administration.java +++ b/core/src/mindustry/net/Administration.java @@ -319,7 +319,7 @@ public class Administration{ public enum Config{ name("The server name as displayed on clients.", "Server", "servername"), port("The port to host on.", Vars.port), - autoUpdate("Whether to auto-restart when a new update arrives.", false), + autoUpdate("Whether to auto-update and exit when a new bleeding-edge update arrives.", false), crashReport("Whether to send crash reports.", false, "crashreport"), logging("Whether to log everything to files.", true), strict("Whether strict mode is on - corrects positions and prevents duplicate UUIDs.", true), diff --git a/core/src/mindustry/net/BeControl.java b/core/src/mindustry/net/BeControl.java index 4de581108f..bce61a1663 100644 --- a/core/src/mindustry/net/BeControl.java +++ b/core/src/mindustry/net/BeControl.java @@ -126,7 +126,7 @@ public class BeControl{ progress -> {}, () -> false, () -> { - Log.info("&lcVersion downloaded, exiting. Note that if you are not using the run-server script, the server will not restart automatically."); + Log.info("&lcVersion downloaded, exiting. Note that if you are not using a auto-restart script, the server will not restart automatically."); //replace old file with new dest.copyTo(source); dest.delete(); diff --git a/server/run-jar b/server/run-jar new file mode 100755 index 0000000000..2ab341566f --- /dev/null +++ b/server/run-jar @@ -0,0 +1,19 @@ +#!/usr/bin/env bash +if [[ $# -eq 0 ]] ; then + echo 'A server jar must be supplied as the first argument.' + exit 1 +fi + +if [[ ! -e $1 ]] ; then + echo "The supplied jar file '$1' must exist." + exit 1 +fi + +while true; do +#auto-restart until ctrl-c or exit 0 +java -jar -XX:+HeapDumpOnOutOfMemoryError $1 +excode=$? +if [ $excode -eq 0 ] || [ $excode -eq 130 ]; then + exit 0 +fi +done diff --git a/run-server b/server/run-server similarity index 81% rename from run-server rename to server/run-server index 25a8254723..4e337686a0 100755 --- a/run-server +++ b/server/run-server @@ -4,13 +4,22 @@ if [[ $# -eq 0 ]] ; then exit 1 fi +cd .. + ./gradlew server:dist -Pbuildversion=$1 +excode=$? + +if [ $excode -ne 0 ]; then + echo $excode + exit 1 +fi + while true; do #auto-restart until ctrl-c or exit 0 java -jar -XX:+HeapDumpOnOutOfMemoryError server/build/libs/server-release.jar excode=$? if [ $excode -eq 0 ] || [ $excode -eq 130 ]; then - exit 0 + exit 0 fi done From e0f59404c1ac46c7e074fa91428b64696a164a4a Mon Sep 17 00:00:00 2001 From: Anuken Date: Sat, 28 Dec 2019 17:49:49 -0500 Subject: [PATCH 05/15] Added BE server --- servers_be.json | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/servers_be.json b/servers_be.json index 0637a088a0..be72d9d6da 100644 --- a/servers_be.json +++ b/servers_be.json @@ -1 +1,5 @@ -[] \ No newline at end of file +[ + { + "address": "mindustry.us.to:6568" + } +] \ No newline at end of file From 60d83751e87122d1e80ebedceda61ef5b3168218 Mon Sep 17 00:00:00 2001 From: Anuken Date: Sat, 28 Dec 2019 17:55:00 -0500 Subject: [PATCH 06/15] Fixed server port not being parsed --- core/src/mindustry/ui/dialogs/JoinDialog.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/core/src/mindustry/ui/dialogs/JoinDialog.java b/core/src/mindustry/ui/dialogs/JoinDialog.java index 8984939bcf..8ab0ff8fd2 100644 --- a/core/src/mindustry/ui/dialogs/JoinDialog.java +++ b/core/src/mindustry/ui/dialogs/JoinDialog.java @@ -288,7 +288,13 @@ public class JoinDialog extends FloatingDialog{ local.table(Tex.button, t -> t.label(() -> "[accent]" + Core.bundle.get("hosts.discovering.any") + Strings.animated(Time.time(), 4, 10f, ".")).pad(10f)).growX(); net.discoverServers(this::addLocalHost, this::finishLocalHosts); for(String host : defaultServers){ - net.pingHost(host, port, this::addLocalHost, e -> {}); + String address = host; + int p = port; + if(host.contains(":")){ + address = host.split(":")[0]; + p = Strings.parseInt(host.split(":")[1]); + } + net.pingHost(address, p, this::addLocalHost, e -> {}); } } From 7543d92473e79d3957740cc07523d05adfe186c1 Mon Sep 17 00:00:00 2001 From: Anuken Date: Sat, 28 Dec 2019 18:05:45 -0500 Subject: [PATCH 07/15] Added startup commands to server --- core/src/mindustry/net/Administration.java | 1 + server/src/mindustry/server/ServerControl.java | 15 ++++++++++----- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/core/src/mindustry/net/Administration.java b/core/src/mindustry/net/Administration.java index 268e8d089f..57a728a020 100644 --- a/core/src/mindustry/net/Administration.java +++ b/core/src/mindustry/net/Administration.java @@ -320,6 +320,7 @@ public class Administration{ name("The server name as displayed on clients.", "Server", "servername"), port("The port to host on.", Vars.port), autoUpdate("Whether to auto-update and exit when a new bleeding-edge update arrives.", false), + startCommands("Commands run at startup. This should be a comma-separated list.", ""), crashReport("Whether to send crash reports.", false, "crashreport"), logging("Whether to log everything to files.", true), strict("Whether strict mode is on - corrects positions and prevents duplicate UUIDs.", true), diff --git a/server/src/mindustry/server/ServerControl.java b/server/src/mindustry/server/ServerControl.java index f1dbb59803..619004f79f 100644 --- a/server/src/mindustry/server/ServerControl.java +++ b/server/src/mindustry/server/ServerControl.java @@ -90,11 +90,17 @@ public class ServerControl implements ApplicationListener{ registerCommands(); Core.app.post(() -> { - String[] commands = {}; + Array commands = new Array<>(); if(args.length > 0){ - commands = Strings.join(" ", args).split(","); - info("&lmFound {0} command-line arguments to parse.", commands.length); + commands.addAll(Strings.join(" ", args).split(",")); + info("&lmFound {0} command-line arguments to parse.", commands.size); + } + + if(!Config.startCommands.string().isEmpty()){ + String[] startup = Strings.join(" ", Config.startCommands.string()).split(","); + info("&lmFound {0} startup commands.", startup.length); + commands.addAll(startup); } for(String s : commands){ @@ -102,7 +108,6 @@ public class ServerControl implements ApplicationListener{ if(response.type != ResponseType.valid){ err("Invalid command argument sent: '{0}': {1}", s, response.type.name()); err("Argument usage: &lc , "); - System.exit(1); } } }); @@ -443,7 +448,7 @@ public class ServerControl implements ApplicationListener{ } }); - handler.register("config", "[name] [value]", "Configure server settings.", arg -> { + handler.register("config", "[name] [value...]", "Configure server settings.", arg -> { if(arg.length == 0){ info("&lyAll config values:"); for(Config c : Config.all){ From 497ae740aae893c8e842eccead533eddac2a7fd9 Mon Sep 17 00:00:00 2001 From: Anuken Date: Sat, 28 Dec 2019 18:12:34 -0500 Subject: [PATCH 08/15] Removed pointless "> " --- core/src/mindustry/net/BeControl.java | 1 + server/src/mindustry/server/ServerControl.java | 3 --- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/core/src/mindustry/net/BeControl.java b/core/src/mindustry/net/BeControl.java index bce61a1663..76fa81f310 100644 --- a/core/src/mindustry/net/BeControl.java +++ b/core/src/mindustry/net/BeControl.java @@ -84,6 +84,7 @@ public class BeControl{ if(!updateAvailable) return; if(!headless){ + checkUpdates = false; ui.showCustomConfirm(Core.bundle.format("be.update", "") + " " + updateBuild, "$be.update.confirm", "$ok", "$be.ignore", () -> { boolean[] cancel = {false}; float[] progress = {0}; diff --git a/server/src/mindustry/server/ServerControl.java b/server/src/mindustry/server/ServerControl.java index 619004f79f..655e7951b5 100644 --- a/server/src/mindustry/server/ServerControl.java +++ b/server/src/mindustry/server/ServerControl.java @@ -170,7 +170,6 @@ public class ServerControl implements ApplicationListener{ toggleSocket(Config.socketInput.bool()); info("&lcServer loaded. Type &ly'help'&lc for help."); - System.out.print("> "); } private void registerCommands(){ @@ -822,8 +821,6 @@ public class ServerControl implements ApplicationListener{ }else if(response.type == ResponseType.manyArguments){ err("Too many command arguments. Usage: " + response.command.text + " " + response.command.paramText); } - - System.out.print("> "); } private void play(boolean wait, Runnable run){ From b01d56aae84bfd3282d23248642058c3ec6448f4 Mon Sep 17 00:00:00 2001 From: Anuken Date: Sat, 28 Dec 2019 18:22:20 -0500 Subject: [PATCH 09/15] Bugfixes --- core/src/mindustry/net/Host.java | 3 ++- core/src/mindustry/ui/dialogs/JoinDialog.java | 15 +++++++-------- server/src/mindustry/server/ServerControl.java | 2 +- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/core/src/mindustry/net/Host.java b/core/src/mindustry/net/Host.java index 387fafc043..5c3b010c45 100644 --- a/core/src/mindustry/net/Host.java +++ b/core/src/mindustry/net/Host.java @@ -1,5 +1,6 @@ package mindustry.net; +import mindustry.*; import mindustry.game.*; public class Host{ @@ -11,7 +12,7 @@ public class Host{ public final int version; public final String versionType; public final Gamemode mode; - public int ping; + public int ping, port = Vars.port; public Host(String name, String address, String mapname, int wave, int players, int version, String versionType, Gamemode mode, int playerLimit){ this.name = name; diff --git a/core/src/mindustry/ui/dialogs/JoinDialog.java b/core/src/mindustry/ui/dialogs/JoinDialog.java index 8ab0ff8fd2..d3e154b3b1 100644 --- a/core/src/mindustry/ui/dialogs/JoinDialog.java +++ b/core/src/mindustry/ui/dialogs/JoinDialog.java @@ -288,13 +288,12 @@ public class JoinDialog extends FloatingDialog{ local.table(Tex.button, t -> t.label(() -> "[accent]" + Core.bundle.get("hosts.discovering.any") + Strings.animated(Time.time(), 4, 10f, ".")).pad(10f)).growX(); net.discoverServers(this::addLocalHost, this::finishLocalHosts); for(String host : defaultServers){ - String address = host; - int p = port; - if(host.contains(":")){ - address = host.split(":")[0]; - p = Strings.parseInt(host.split(":")[1]); - } - net.pingHost(address, p, this::addLocalHost, e -> {}); + String resaddress = host.contains(":") ? host.split(":")[0] : host; + int resport = host.contains(":") ? Strings.parseInt(host.split(":")[1]) : port; + net.pingHost(resaddress, resport, res -> { + res.port = resport; + addLocalHost(res); + }, e -> {}); } } @@ -320,7 +319,7 @@ public class JoinDialog extends FloatingDialog{ local.row(); - TextButton button = local.addButton("", Styles.cleart, () -> safeConnect(host.address, port, host.version)) + TextButton button = local.addButton("", Styles.cleart, () -> safeConnect(host.address, host.port, host.version)) .width(w).pad(5f).get(); button.clearChildren(); buildServer(host, button); diff --git a/server/src/mindustry/server/ServerControl.java b/server/src/mindustry/server/ServerControl.java index 655e7951b5..df70cf3c0a 100644 --- a/server/src/mindustry/server/ServerControl.java +++ b/server/src/mindustry/server/ServerControl.java @@ -461,7 +461,7 @@ public class ServerControl implements ApplicationListener{ try{ Config c = Config.valueOf(arg[0]); if(arg.length == 1){ - Log.info("&lc'{0}'&lg is currently &lc{0}.", c.name(), c.get()); + Log.info("&lc'{0}'&lg is currently &lc{1}.", c.name(), c.get()); }else{ if(c.isBool()){ c.set(arg[1].equals("on") || arg[1].equals("true")); From 8c941c7165d100dc1952e65fbed254dd0757d8d9 Mon Sep 17 00:00:00 2001 From: Anuken Date: Sat, 28 Dec 2019 21:34:20 -0500 Subject: [PATCH 10/15] Added update trigger / Server moddability tweaks --- core/assets/bundles/bundle.properties | 1 + core/src/mindustry/core/Logic.java | 3 ++- core/src/mindustry/core/NetServer.java | 1 - core/src/mindustry/game/EventType.java | 3 ++- core/src/mindustry/game/Rules.java | 2 ++ core/src/mindustry/net/BeControl.java | 8 +++++-- core/src/mindustry/net/Packets.java | 3 ++- .../src/mindustry/server/ServerControl.java | 24 +++++++++---------- 8 files changed, 26 insertions(+), 19 deletions(-) diff --git a/core/assets/bundles/bundle.properties b/core/assets/bundles/bundle.properties index 2b2a1aa548..0ee7e3bd4e 100644 --- a/core/assets/bundles/bundle.properties +++ b/core/assets/bundles/bundle.properties @@ -155,6 +155,7 @@ server.kicked.nameEmpty = Your chosen name is invalid. server.kicked.idInUse = You are already on this server! Connecting with two accounts is not permitted. server.kicked.customClient = This server does not support custom builds. Download an official version. server.kicked.gameover = Game over! +server.kicked.serverRestarting = The server is restarting. server.versions = Your version:[accent] {0}[]\nServer version:[accent] {1}[] host.info = The [accent]host[] button hosts a server on port [scarlet]6567[]. \nAnybody on the same [lightgray]wifi or local network[] should be able to see your server in their server list.\n\nIf you want people to be able to connect from anywhere by IP, [accent]port forwarding[] is required.\n\n[lightgray]Note: If someone is experiencing trouble connecting to your LAN game, make sure you have allowed Mindustry access to your local network in your firewall settings. Note that public networks sometimes do not allow server discovery. join.info = Here, you can enter a [accent]server IP[] to connect to, or discover [accent]local network[] servers to connect to.\nBoth LAN and WAN multiplayer is supported.\n\n[lightgray]Note: There is no automatic global server list; if you want to connect to someone by IP, you would need to ask the host for their IP. diff --git a/core/src/mindustry/core/Logic.java b/core/src/mindustry/core/Logic.java index 17fedab303..12761439b7 100644 --- a/core/src/mindustry/core/Logic.java +++ b/core/src/mindustry/core/Logic.java @@ -209,6 +209,7 @@ public class Logic implements ApplicationListener{ @Override public void update(){ + Events.fire(Trigger.update); if(!state.is(State.menu)){ if(!net.client()){ @@ -260,7 +261,7 @@ public class Logic implements ApplicationListener{ } } - if(!net.client() && !world.isInvalidMap() && !state.isEditor()){ + if(!net.client() && !world.isInvalidMap() && !state.isEditor() && !state.rules.canGameOver){ checkGameOver(); } } diff --git a/core/src/mindustry/core/NetServer.java b/core/src/mindustry/core/NetServer.java index c74f14211c..a355ecbd76 100644 --- a/core/src/mindustry/core/NetServer.java +++ b/core/src/mindustry/core/NetServer.java @@ -217,7 +217,6 @@ public class NetServer implements ApplicationListener{ //playing in pvp mode automatically assigns players to teams player.setTeam(assignTeam(player, playerGroup.all())); - Log.info("Auto-assigned player {0} to team {1}.", player.name, player.getTeam()); sendWorldData(player); diff --git a/core/src/mindustry/game/EventType.java b/core/src/mindustry/game/EventType.java index 6cbaba5e4b..5a9950b489 100644 --- a/core/src/mindustry/game/EventType.java +++ b/core/src/mindustry/game/EventType.java @@ -29,7 +29,8 @@ public class EventType{ suicideBomb, openWiki, teamCoreDamage, - socketConfigChanged + socketConfigChanged, + update } public static class WinEvent{} diff --git a/core/src/mindustry/game/Rules.java b/core/src/mindustry/game/Rules.java index 93ceaf5cfe..06231e5318 100644 --- a/core/src/mindustry/game/Rules.java +++ b/core/src/mindustry/game/Rules.java @@ -70,6 +70,8 @@ public class Rules{ public boolean editor = false; /** Whether the tutorial is enabled. False by default. */ public boolean tutorial = false; + /** Whether a gameover can happen at all. Set this to false to implement custom gameover conditions. */ + public boolean canGameOver = true; /** Starting items put in cores */ public Array loadout = Array.with(ItemStack.with(Items.copper, 100)); /** Blocks that cannot be placed. */ diff --git a/core/src/mindustry/net/BeControl.java b/core/src/mindustry/net/BeControl.java index 76fa81f310..13f645b996 100644 --- a/core/src/mindustry/net/BeControl.java +++ b/core/src/mindustry/net/BeControl.java @@ -11,6 +11,7 @@ import mindustry.core.*; import mindustry.gen.*; import mindustry.graphics.*; import mindustry.net.Administration.*; +import mindustry.net.Packets.*; import mindustry.ui.*; import mindustry.ui.dialogs.*; @@ -126,13 +127,16 @@ public class BeControl{ len -> Core.app.post(() -> Log.info("&ly| Size: {0} MB.", Strings.fixed((float)len / 1024 / 1024, 2))), progress -> {}, () -> false, - () -> { + () -> Core.app.post(() -> { + netServer.kickAll(KickReason.serverRestarting); + Threads.sleep(32); + Log.info("&lcVersion downloaded, exiting. Note that if you are not using a auto-restart script, the server will not restart automatically."); //replace old file with new dest.copyTo(source); dest.delete(); System.exit(2); //this will cause a restart if using the script - }, + }), Throwable::printStackTrace); }catch(Exception e){ e.printStackTrace(); diff --git a/core/src/mindustry/net/Packets.java b/core/src/mindustry/net/Packets.java index 683983d69b..98a3bad857 100644 --- a/core/src/mindustry/net/Packets.java +++ b/core/src/mindustry/net/Packets.java @@ -15,7 +15,8 @@ public class Packets{ public enum KickReason{ kick, clientOutdated, serverOutdated, banned, gameover(true), recentKick, - nameInUse, idInUse, nameEmpty, customClient, serverClose, vote, typeMismatch, whitelist, playerLimit; + nameInUse, idInUse, nameEmpty, customClient, serverClose, vote, typeMismatch, + whitelist, playerLimit, serverRestarting; public final boolean quiet; diff --git a/server/src/mindustry/server/ServerControl.java b/server/src/mindustry/server/ServerControl.java index df70cf3c0a..094d020e78 100644 --- a/server/src/mindustry/server/ServerControl.java +++ b/server/src/mindustry/server/ServerControl.java @@ -163,6 +163,15 @@ public class ServerControl implements ApplicationListener{ toggleSocket(Config.socketInput.bool()); }); + Events.on(PlayEvent.class, e -> { + try{ + JsonValue value = JsonIO.json().fromJson(null, Core.settings.getString("globalrules")); + JsonIO.json().readFields(state.rules, value); + }catch(Throwable t){ + Log.err("Error applying custom rules, proceeding without them.", t); + } + }); + if(!mods.list().isEmpty()){ info("&lc{0} mods loaded.", mods.list().size); } @@ -238,7 +247,6 @@ public class ServerControl implements ApplicationListener{ try{ world.loadMap(result, result.applyRules(lastMode)); state.rules = result.applyRules(preset); - applyRules(); logic.play(); info("Map loaded."); @@ -390,7 +398,7 @@ public class ServerControl implements ApplicationListener{ base.addChild(arg[1], value); Log.info("Changed rule: &ly{0}", value.toString().replace("\n", " ")); }catch(Throwable e){ - Log.err("Error parsing rule JSON", e); + Log.err("Error parsing rule JSON: {0}", e.getMessage()); } } @@ -777,15 +785,6 @@ public class ServerControl implements ApplicationListener{ mods.eachClass(p -> p.registerClientCommands(netServer.clientCommands)); } - private void applyRules(){ - try{ - JsonValue value = JsonIO.json().fromJson(null, Core.settings.getString("globalrules")); - JsonIO.json().readFields(state.rules, value); - }catch(Throwable t){ - Log.err("Error applying custom rules, proceeding without them.", t); - } - } - private void readCommands(){ Scanner scan = new Scanner(System.in); @@ -836,9 +835,8 @@ public class ServerControl implements ApplicationListener{ Call.onWorldDataBegin(); run.run(); - logic.play(); state.rules = world.getMap().applyRules(lastMode); - applyRules(); + logic.play(); for(Player p : players){ if(p.con == null) continue; From df4a0dd5e4b40c2ad4b97ddfa31d3e177b7b11f4 Mon Sep 17 00:00:00 2001 From: Anuken Date: Sat, 28 Dec 2019 22:18:16 -0500 Subject: [PATCH 11/15] Added openServer method --- core/src/mindustry/core/NetServer.java | 21 +++++++++++++++++-- .../src/mindustry/server/ServerControl.java | 17 ++------------- 2 files changed, 21 insertions(+), 17 deletions(-) diff --git a/core/src/mindustry/core/NetServer.java b/core/src/mindustry/core/NetServer.java index a355ecbd76..b37ab7a57a 100644 --- a/core/src/mindustry/core/NetServer.java +++ b/core/src/mindustry/core/NetServer.java @@ -1,14 +1,14 @@ package mindustry.core; import arc.*; -import mindustry.annotations.Annotations.*; -import arc.struct.*; import arc.graphics.*; import arc.math.*; import arc.math.geom.*; +import arc.struct.*; import arc.util.*; import arc.util.CommandHandler.*; import arc.util.io.*; +import mindustry.annotations.Annotations.*; import mindustry.content.*; import mindustry.core.GameState.*; import mindustry.entities.*; @@ -26,9 +26,11 @@ import mindustry.world.*; import mindustry.world.blocks.storage.CoreBlock.*; import java.io.*; +import java.net.*; import java.nio.*; import java.util.zip.*; +import static arc.util.Log.*; import static mindustry.Vars.*; public class NetServer implements ApplicationListener{ @@ -598,6 +600,7 @@ public class NetServer implements ApplicationListener{ return false; } + @Override public void update(){ if(!headless && !closing && net.server() && state.is(State.menu)){ @@ -615,6 +618,20 @@ public class NetServer implements ApplicationListener{ } } + /** Should only be used on the headless backend. */ + public void openServer(){ + try{ + net.host(Config.port.num()); + info("&lcOpened a server on port {0}.", Config.port.num()); + }catch(BindException e){ + Log.err("Unable to host: Port already in use! Make sure no other servers are running on the same port in your network."); + state.set(State.menu); + }catch(IOException e){ + err(e); + state.set(State.menu); + } + } + public void kickAll(KickReason reason){ for(NetConnection con : net.getConnections()){ con.kick(reason); diff --git a/server/src/mindustry/server/ServerControl.java b/server/src/mindustry/server/ServerControl.java index 094d020e78..352331f80c 100644 --- a/server/src/mindustry/server/ServerControl.java +++ b/server/src/mindustry/server/ServerControl.java @@ -251,7 +251,7 @@ public class ServerControl implements ApplicationListener{ info("Map loaded."); - host(); + netServer.openServer(); }catch(MapException e){ Log.err(e.map.name() + ": " + e.getMessage()); } @@ -711,8 +711,8 @@ public class ServerControl implements ApplicationListener{ SaveIO.load(file); state.rules.zone = null; info("Save loaded."); - host(); state.set(State.playing); + netServer.openServer(); }catch(Throwable t){ err("Failed to load save. Outdated or corrupt file."); } @@ -869,19 +869,6 @@ public class ServerControl implements ApplicationListener{ } } - private void host(){ - try{ - net.host(Config.port.num()); - info("&lcOpened a server on port {0}.", Config.port.num()); - }catch(BindException e){ - Log.err("Unable to host: Port already in use! Make sure no other servers are running on the same port in your network."); - state.set(State.menu); - }catch(IOException e){ - err(e); - state.set(State.menu); - } - } - private void logToFile(String text){ if(currentLogFile != null && currentLogFile.length() > maxLogLength){ String date = DateTimeFormatter.ofPattern("MM-dd-yyyy | HH:mm:ss").format(LocalDateTime.now()); From 77b89d45d69f811c92d1124a25f3d23563638a54 Mon Sep 17 00:00:00 2001 From: Anuken Date: Sun, 29 Dec 2019 00:09:46 -0500 Subject: [PATCH 12/15] Cleanup / Desktop dead camera panning --- core/src/mindustry/core/Renderer.java | 2 +- core/src/mindustry/entities/EntityGroup.java | 11 ++++++++-- core/src/mindustry/input/DesktopInput.java | 7 +++++++ .../world/blocks/defense/ForceProjector.java | 21 ++----------------- gradle.properties | 2 +- 5 files changed, 20 insertions(+), 23 deletions(-) diff --git a/core/src/mindustry/core/Renderer.java b/core/src/mindustry/core/Renderer.java index d4983e992a..9c284a5f06 100644 --- a/core/src/mindustry/core/Renderer.java +++ b/core/src/mindustry/core/Renderer.java @@ -125,7 +125,7 @@ public class Renderer implements ApplicationListener{ TileEntity core = player.getClosestCore(); if(core != null && player.spawner == null){ camera.position.lerpDelta(core.x, core.y, 0.08f); - }else{ + }else if(core != null){ camera.position.lerpDelta(position, 0.08f); } }else if(control.input instanceof DesktopInput){ diff --git a/core/src/mindustry/entities/EntityGroup.java b/core/src/mindustry/entities/EntityGroup.java index 8c0ac76442..24c3f0e4f0 100644 --- a/core/src/mindustry/entities/EntityGroup.java +++ b/core/src/mindustry/entities/EntityGroup.java @@ -7,11 +7,13 @@ import arc.graphics.*; import arc.math.geom.*; import mindustry.entities.traits.*; +import java.util.*; + import static mindustry.Vars.collisions; /** Represents a group of a certain type of entity.*/ @SuppressWarnings("unchecked") -public class EntityGroup{ +public class EntityGroup implements Iterable{ private final boolean useTree; private final int id; private final Class type; @@ -253,8 +255,13 @@ public class EntityGroup{ return null; } - /** Returns the logic-only array for iteration. */ + /** Returns the array for iteration. */ public Array all(){ return entityArray; } + + @Override + public Iterator iterator(){ + return entityArray.iterator(); + } } diff --git a/core/src/mindustry/input/DesktopInput.java b/core/src/mindustry/input/DesktopInput.java index c76968a56e..df735999d8 100644 --- a/core/src/mindustry/input/DesktopInput.java +++ b/core/src/mindustry/input/DesktopInput.java @@ -10,6 +10,7 @@ import arc.scene.event.*; import arc.scene.ui.*; import arc.scene.ui.layout.*; import arc.util.ArcAnnotate.*; +import arc.util.*; import mindustry.*; import mindustry.core.GameState.*; import mindustry.entities.traits.BuilderTrait.*; @@ -135,6 +136,12 @@ public class DesktopInput extends InputHandler{ ui.listfrag.toggle(); } + if(player.getClosestCore() == null){ + //move camera around + float camSpeed = 6f; + Core.camera.position.add(Tmp.v1.setZero().add(Core.input.axis(Binding.move_x), Core.input.axis(Binding.move_y)).nor().scl(Time.delta() * camSpeed)); + } + if(Core.input.keyRelease(Binding.select)){ player.isShooting = false; } diff --git a/core/src/mindustry/world/blocks/defense/ForceProjector.java b/core/src/mindustry/world/blocks/defense/ForceProjector.java index a417c2b9e5..36ed812b5d 100644 --- a/core/src/mindustry/world/blocks/defense/ForceProjector.java +++ b/core/src/mindustry/world/blocks/defense/ForceProjector.java @@ -5,6 +5,7 @@ import arc.func.*; import arc.graphics.*; import arc.graphics.g2d.*; import arc.math.*; +import arc.math.geom.*; import arc.util.*; import mindustry.content.*; import mindustry.entities.*; @@ -37,7 +38,7 @@ public class ForceProjector extends Block{ private static ForceProjector paramBlock; private static ForceEntity paramEntity; private static Cons shieldConsumer = trait -> { - if(trait.canBeAbsorbed() && trait.getTeam() != paramTile.getTeam() && paramBlock.isInsideHexagon(trait.getX(), trait.getY(), paramBlock.realRadius(paramEntity) * 2f, paramTile.drawx(), paramTile.drawy())){ + if(trait.canBeAbsorbed() && trait.getTeam() != paramTile.getTeam() && Intersector.isInsideHexagon(trait.getX(), trait.getY(), paramBlock.realRadius(paramEntity) * 2f, paramTile.drawx(), paramTile.drawy())){ trait.absorb(); Effects.effect(Fx.absorb, trait); paramEntity.hit = 1f; @@ -111,17 +112,6 @@ public class ForceProjector extends Block{ entity.warmup = Mathf.lerpDelta(entity.warmup, entity.efficiency(), 0.1f); -/* - if(entity.power.status < relativePowerDraw){ - entity.warmup = Mathf.lerpDelta(entity.warmup, 0f, 0.15f); - entity.power.status = 0f; - if(entity.warmup <= 0.09f){ - entity.broken = true; - } - }else{ - entity.warmup = Mathf.lerpDelta(entity.warmup, 1f, 0.1f); - }*/ - if(entity.buildup > 0){ float scale = !entity.broken ? cooldownNormal : cooldownBrokenBase; ConsumeLiquidFilter cons = consumes.get(ConsumeType.liquid); @@ -159,13 +149,6 @@ public class ForceProjector extends Block{ return (radius + entity.phaseHeat * phaseRadiusBoost) * entity.radscl; } - boolean isInsideHexagon(float x0, float y0, float d, float x, float y){ - float dx = Math.abs(x - x0) / d; - float dy = Math.abs(y - y0) / d; - float a = 0.25f * Mathf.sqrt3; - return (dy <= a) && (a * dx + 0.25 * dy <= 0.5 * a); - } - @Override public void draw(Tile tile){ super.draw(tile); diff --git a/gradle.properties b/gradle.properties index 0b0bc673e4..51de1f3142 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,3 +1,3 @@ org.gradle.daemon=true org.gradle.jvmargs=-Xms256m -Xmx1024m -archash=0e25944f7f3a065ed6707f0dbe48548980cad8a6 +archash=fe82ca9037028044764cc4b02fdbf851e3d09f78 From e04c592f9eae9aa047b1b28a1589544f155b41da Mon Sep 17 00:00:00 2001 From: Anuken Date: Sun, 29 Dec 2019 00:40:25 -0500 Subject: [PATCH 13/15] Bugfixes --- core/src/mindustry/graphics/MinimapRenderer.java | 1 + core/src/mindustry/net/BeControl.java | 3 +-- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core/src/mindustry/graphics/MinimapRenderer.java b/core/src/mindustry/graphics/MinimapRenderer.java index 60f3d2974b..5d8af45304 100644 --- a/core/src/mindustry/graphics/MinimapRenderer.java +++ b/core/src/mindustry/graphics/MinimapRenderer.java @@ -82,6 +82,7 @@ public class MinimapRenderer implements Disposable{ rect.set((dx - sz) * tilesize, (dy - sz) * tilesize, sz * 2 * tilesize, sz * 2 * tilesize); for(Unit unit : units){ + if(unit.isDead()) continue; float rx = (unit.x - rect.x) / rect.width * w; float ry = (unit.y - rect.y) / rect.width * h; diff --git a/core/src/mindustry/net/BeControl.java b/core/src/mindustry/net/BeControl.java index 13f645b996..ee084f743a 100644 --- a/core/src/mindustry/net/BeControl.java +++ b/core/src/mindustry/net/BeControl.java @@ -22,7 +22,7 @@ import static mindustry.Vars.*; /** Handles control of bleeding edge builds. */ public class BeControl{ - private static final int updateInterval = 60; + private static final int updateInterval = 60 * 2; private AsyncExecutor executor = new AsyncExecutor(1); private boolean checkUpdates = true; @@ -64,7 +64,6 @@ public class BeControl{ } }else{ Core.app.post(() -> done.get(false)); - Log.err("Update check responded with: {0}", res.getStatus()); } }, error -> { if(!headless){ From 730d30ef9829fb3e54032e694c4af464ce5860b2 Mon Sep 17 00:00:00 2001 From: Anuken Date: Sun, 29 Dec 2019 11:40:52 -0500 Subject: [PATCH 14/15] Added core schematic selection setting --- core/assets/bundles/bundle.properties | 1 + core/src/mindustry/content/Blocks.java | 6 +++--- core/src/mindustry/content/Loadouts.java | 14 ++++---------- core/src/mindustry/game/Schematics.java | 11 ++++++++--- .../src/mindustry/ui/dialogs/SchematicsDialog.java | 2 +- .../mindustry/ui/dialogs/SettingsMenuDialog.java | 1 + 6 files changed, 18 insertions(+), 17 deletions(-) diff --git a/core/assets/bundles/bundle.properties b/core/assets/bundles/bundle.properties index 0ee7e3bd4e..73fee4471d 100644 --- a/core/assets/bundles/bundle.properties +++ b/core/assets/bundles/bundle.properties @@ -643,6 +643,7 @@ setting.screenshake.name = Screen Shake setting.effects.name = Display Effects setting.destroyedblocks.name = Display Destroyed Blocks setting.conveyorpathfinding.name = Conveyor Placement Pathfinding +setting.coreselect.name = Allow Schematic Cores setting.sensitivity.name = Controller Sensitivity setting.saveinterval.name = Save Interval setting.seconds = {0} seconds diff --git a/core/src/mindustry/content/Blocks.java b/core/src/mindustry/content/Blocks.java index 8fe9cdb52f..58ff4a7c35 100644 --- a/core/src/mindustry/content/Blocks.java +++ b/core/src/mindustry/content/Blocks.java @@ -1234,7 +1234,7 @@ public class Blocks implements ContentList{ //region storage coreShard = new CoreBlock("core-shard"){{ - requirements(Category.effect, BuildVisibility.debugOnly, ItemStack.with(Items.titanium, 4000)); + requirements(Category.effect, BuildVisibility.debugOnly, ItemStack.with()); alwaysUnlocked = true; health = 1100; @@ -1243,7 +1243,7 @@ public class Blocks implements ContentList{ }}; coreFoundation = new CoreBlock("core-foundation"){{ - requirements(Category.effect, BuildVisibility.debugOnly, ItemStack.with(Items.titanium, 400, Items.silicon, 3000)); + requirements(Category.effect, BuildVisibility.debugOnly, ItemStack.with()); health = 2000; itemCapacity = 9000; @@ -1251,7 +1251,7 @@ public class Blocks implements ContentList{ }}; coreNucleus = new CoreBlock("core-nucleus"){{ - requirements(Category.effect, BuildVisibility.debugOnly, ItemStack.with(Items.titanium, 4000, Items.silicon, 2000, Items.surgealloy, 3000)); + requirements(Category.effect, BuildVisibility.debugOnly, ItemStack.with()); health = 4000; itemCapacity = 13000; diff --git a/core/src/mindustry/content/Loadouts.java b/core/src/mindustry/content/Loadouts.java index 16252b686f..145da6120e 100644 --- a/core/src/mindustry/content/Loadouts.java +++ b/core/src/mindustry/content/Loadouts.java @@ -3,8 +3,6 @@ package mindustry.content; import mindustry.ctype.*; import mindustry.game.*; -import java.io.*; - public class Loadouts implements ContentList{ public static Schematic basicShard, @@ -14,13 +12,9 @@ public class Loadouts implements ContentList{ @Override public void load(){ - try{ - basicShard = Schematics.readBase64("bXNjaAB4nD2K2wqAIBiD5ymibnoRn6YnEP1BwUMoBL19FuJ2sbFvUFgYZDaJsLeQrkinN9UJHImsNzlYE7WrIUastuSbnlKx2VJJt+8IQGGKdfO/8J5yrGJSMegLg+YUIA=="); - advancedShard = Schematics.readBase64("bXNjaAB4nD2LjQqAIAyET7OMIOhFfJqeYMxBgSkYCL199gu33fFtB4tOwUTaBCP5QpHFzwtl32DahBeKK1NwPq8hoOcUixwpY+CUxe3XIwBbB/pa6tadVCUP02hgHvp5vZq/0b7pBHPYFOQ="); - basicFoundation = Schematics.readBase64("bXNjaAB4nD1OSQ6DMBBzFhVu8BG+0X8MQyoiJTNSukj8nlCi2Adbtg/GA4OBF8oB00rvyE/9ykafqOIw58A7SWRKy1ZiShhZ5RcOLZhYS1hefQ1gRIeptH9jq/qW2lvc1d2tgWsOfVX/tOwE86AYBA=="); - basicNucleus = Schematics.readBase64("bXNjaAB4nD2MUQqAIBBEJy0s6qOLdJXuYNtCgikYBd2+LNmdj308hkGHtkId7M4YFns4mk/yfB4a48602eDI+mlNznu0FMPFd0wYKCaewl8F0EOueqM+yKSLVfJrNKWnSw/FZGzEGXFG9sy/px4gEBW1"); - }catch(IOException e){ - throw new RuntimeException(e); - } + basicShard = Schematics.readBase64("bXNjaAB4nD2K2wqAIBiD5ymibnoRn6YnEP1BwUMoBL19FuJ2sbFvUFgYZDaJsLeQrkinN9UJHImsNzlYE7WrIUastuSbnlKx2VJJt+8IQGGKdfO/8J5yrGJSMegLg+YUIA=="); + advancedShard = Schematics.readBase64("bXNjaAB4nD2LjQqAIAyET7OMIOhFfJqeYMxBgSkYCL199gu33fFtB4tOwUTaBCP5QpHFzwtl32DahBeKK1NwPq8hoOcUixwpY+CUxe3XIwBbB/pa6tadVCUP02hgHvp5vZq/0b7pBHPYFOQ="); + basicFoundation = Schematics.readBase64("bXNjaAB4nD1OSQ6DMBBzFhVu8BG+0X8MQyoiJTNSukj8nlCi2Adbtg/GA4OBF8oB00rvyE/9ykafqOIw58A7SWRKy1ZiShhZ5RcOLZhYS1hefQ1gRIeptH9jq/qW2lvc1d2tgWsOfVX/tOwE86AYBA=="); + basicNucleus = Schematics.readBase64("bXNjaAB4nD2MUQqAIBBEJy0s6qOLdJXuYNtCgikYBd2+LNmdj308hkGHtkId7M4YFns4mk/yfB4a48602eDI+mlNznu0FMPFd0wYKCaewl8F0EOueqM+yKSLVfJrNKWnSw/FZGzEGXFG9sy/px4gEBW1"); } } diff --git a/core/src/mindustry/game/Schematics.java b/core/src/mindustry/game/Schematics.java index b30658692e..072f063e1f 100644 --- a/core/src/mindustry/game/Schematics.java +++ b/core/src/mindustry/game/Schematics.java @@ -339,7 +339,8 @@ public class Schematics implements Loadable{ for(int cy = oy; cy <= oy2; cy++){ Tile tile = world.ltile(cx, cy); - if(tile != null && tile.entity != null && !counted.contains(tile.pos()) && !(tile.block() instanceof BuildBlock) && tile.entity.block.isVisible()){ + if(tile != null && tile.entity != null && !counted.contains(tile.pos()) && !(tile.block() instanceof BuildBlock) + && (tile.entity.block.isVisible() || (tile.entity.block instanceof CoreBlock && Core.settings.getBool("coreselect")))){ int config = tile.entity.config(); if(tile.block().posConfig){ config = Pos.get(Pos.x(config) + offsetX, Pos.y(config) + offsetY); @@ -368,8 +369,12 @@ public class Schematics implements Loadable{ //region IO methods /** Loads a schematic from base64. May throw an exception. */ - public static Schematic readBase64(String schematic) throws IOException{ - return read(new ByteArrayInputStream(Base64Coder.decode(schematic))); + public static Schematic readBase64(String schematic){ + try{ + return read(new ByteArrayInputStream(Base64Coder.decode(schematic))); + }catch(IOException e){ + throw new RuntimeException(e); + } } public static Schematic read(Fi file) throws IOException{ diff --git a/core/src/mindustry/ui/dialogs/SchematicsDialog.java b/core/src/mindustry/ui/dialogs/SchematicsDialog.java index d12bc4af54..1747cdf2a0 100644 --- a/core/src/mindustry/ui/dialogs/SchematicsDialog.java +++ b/core/src/mindustry/ui/dialogs/SchematicsDialog.java @@ -163,7 +163,7 @@ public class SchematicsDialog extends FloatingDialog{ setup(); ui.showInfoFade("$schematic.saved"); showInfo(s); - }catch(Exception e){ + }catch(Throwable e){ ui.showException(e); } }).marginLeft(12f).disabled(b -> Core.app.getClipboardText() == null || !Core.app.getClipboardText().startsWith(schematicBaseStart)); diff --git a/core/src/mindustry/ui/dialogs/SettingsMenuDialog.java b/core/src/mindustry/ui/dialogs/SettingsMenuDialog.java index 4c01c10abb..3ce8457ec1 100644 --- a/core/src/mindustry/ui/dialogs/SettingsMenuDialog.java +++ b/core/src/mindustry/ui/dialogs/SettingsMenuDialog.java @@ -229,6 +229,7 @@ public class SettingsMenuDialog extends SettingsDialog{ game.checkPref("savecreate", true); game.checkPref("blockreplace", true); game.checkPref("conveyorpathfinding", true); + game.checkPref("coreselect", false); game.checkPref("hints", true); if(!mobile){ game.checkPref("buildautopause", false); From 566052cabfc8d1b9917e47b206455816d5ab5f0f Mon Sep 17 00:00:00 2001 From: Anuken Date: Sun, 29 Dec 2019 12:24:51 -0500 Subject: [PATCH 15/15] Fixed #1272 --- core/assets/scripts/global.js | 1 + core/src/mindustry/game/Schematics.java | 1 + core/src/mindustry/mod/ClassAccess.java | 2 +- tools/src/mindustry/tools/ScriptStubGenerator.java | 3 ++- 4 files changed, 5 insertions(+), 2 deletions(-) diff --git a/core/assets/scripts/global.js b/core/assets/scripts/global.js index 862ded3759..9ba7fc5e4c 100755 --- a/core/assets/scripts/global.js +++ b/core/assets/scripts/global.js @@ -25,6 +25,7 @@ importPackage(Packages.arc.func) importPackage(Packages.arc.graphics) importPackage(Packages.arc.graphics.g2d) importPackage(Packages.arc.math) +importPackage(Packages.arc.math.geom) importPackage(Packages.arc.scene) importPackage(Packages.arc.scene.actions) importPackage(Packages.arc.scene.event) diff --git a/core/src/mindustry/game/Schematics.java b/core/src/mindustry/game/Schematics.java index 072f063e1f..fd6e10022d 100644 --- a/core/src/mindustry/game/Schematics.java +++ b/core/src/mindustry/game/Schematics.java @@ -249,6 +249,7 @@ public class Schematics implements Loadable{ public void placeLoadout(Schematic schem, int x, int y){ Stile coreTile = schem.tiles.find(s -> s.block instanceof CoreBlock); + if(coreTile == null) throw new IllegalArgumentException("Schematic has no core tile. Exiting."); int ox = x - coreTile.x, oy = y - coreTile.y; schem.tiles.each(st -> { Tile tile = world.tile(st.x + ox, st.y + oy); diff --git a/core/src/mindustry/mod/ClassAccess.java b/core/src/mindustry/mod/ClassAccess.java index 06ff74766c..2d1e32cfad 100644 --- a/core/src/mindustry/mod/ClassAccess.java +++ b/core/src/mindustry/mod/ClassAccess.java @@ -3,5 +3,5 @@ package mindustry.mod; import arc.struct.*; //obviously autogenerated, do not touch public class ClassAccess{ - public static final ObjectSet allowedClassNames = ObjectSet.with("arc.Core", "arc.func.Boolc", "arc.func.Boolf", "arc.func.Boolf2", "arc.func.Boolp", "arc.func.Cons", "arc.func.Cons2", "arc.func.Floatc", "arc.func.Floatc2", "arc.func.Floatc4", "arc.func.Floatf", "arc.func.Floatp", "arc.func.Func", "arc.func.Func2", "arc.func.Func3", "arc.func.Intc", "arc.func.Intc2", "arc.func.Intc4", "arc.func.Intf", "arc.func.Intp", "arc.func.Prov", "arc.graphics.Color", "arc.graphics.Pixmap", "arc.graphics.Texture", "arc.graphics.TextureData", "arc.graphics.g2d.Draw", "arc.graphics.g2d.Fill", "arc.graphics.g2d.Lines", "arc.graphics.g2d.TextureAtlas", "arc.graphics.g2d.TextureAtlas$AtlasRegion", "arc.graphics.g2d.TextureRegion", "arc.math.Angles", "arc.math.Mathf", "arc.scene.Action", "arc.scene.Element", "arc.scene.Group", "arc.scene.Scene", "arc.scene.actions.Actions", "arc.scene.actions.AddAction", "arc.scene.actions.AddListenerAction", "arc.scene.actions.AfterAction", "arc.scene.actions.AlphaAction", "arc.scene.actions.ColorAction", "arc.scene.actions.DelayAction", "arc.scene.actions.DelegateAction", "arc.scene.actions.FloatAction", "arc.scene.actions.IntAction", "arc.scene.actions.LayoutAction", "arc.scene.actions.MoveByAction", "arc.scene.actions.MoveToAction", "arc.scene.actions.OriginAction", "arc.scene.actions.ParallelAction", "arc.scene.actions.RelativeTemporalAction", "arc.scene.actions.RemoveAction", "arc.scene.actions.RemoveActorAction", "arc.scene.actions.RemoveListenerAction", "arc.scene.actions.RepeatAction", "arc.scene.actions.RotateByAction", "arc.scene.actions.RotateToAction", "arc.scene.actions.RunnableAction", "arc.scene.actions.ScaleByAction", "arc.scene.actions.ScaleToAction", "arc.scene.actions.SequenceAction", "arc.scene.actions.SizeByAction", "arc.scene.actions.SizeToAction", "arc.scene.actions.TemporalAction", "arc.scene.actions.TimeScaleAction", "arc.scene.actions.TouchableAction", "arc.scene.actions.TranslateByAction", "arc.scene.actions.VisibleAction", "arc.scene.event.ChangeListener", "arc.scene.event.ChangeListener$ChangeEvent", "arc.scene.event.ClickListener", "arc.scene.event.DragListener", "arc.scene.event.DragScrollListener", "arc.scene.event.ElementGestureListener", "arc.scene.event.EventListener", "arc.scene.event.FocusListener", "arc.scene.event.FocusListener$FocusEvent", "arc.scene.event.FocusListener$FocusEvent$Type", "arc.scene.event.HandCursorListener", "arc.scene.event.IbeamCursorListener", "arc.scene.event.InputEvent", "arc.scene.event.InputEvent$Type", "arc.scene.event.InputListener", "arc.scene.event.SceneEvent", "arc.scene.event.Touchable", "arc.scene.event.VisibilityEvent", "arc.scene.event.VisibilityListener", "arc.scene.style.BaseDrawable", "arc.scene.style.Drawable", "arc.scene.style.NinePatchDrawable", "arc.scene.style.ScaledNinePatchDrawable", "arc.scene.style.Style", "arc.scene.style.TextureRegionDrawable", "arc.scene.style.TiledDrawable", "arc.scene.style.TransformDrawable", "arc.scene.ui.Button", "arc.scene.ui.Button$ButtonStyle", "arc.scene.ui.ButtonGroup", "arc.scene.ui.CheckBox", "arc.scene.ui.CheckBox$CheckBoxStyle", "arc.scene.ui.ColorImage", "arc.scene.ui.Dialog", "arc.scene.ui.Dialog$DialogStyle", "arc.scene.ui.Image", "arc.scene.ui.ImageButton", "arc.scene.ui.ImageButton$ImageButtonStyle", "arc.scene.ui.KeybindDialog", "arc.scene.ui.KeybindDialog$KeybindDialogStyle", "arc.scene.ui.Label", "arc.scene.ui.Label$LabelStyle", "arc.scene.ui.ProgressBar", "arc.scene.ui.ProgressBar$ProgressBarStyle", "arc.scene.ui.ScrollPane", "arc.scene.ui.ScrollPane$ScrollPaneStyle", "arc.scene.ui.SettingsDialog", "arc.scene.ui.SettingsDialog$SettingsTable", "arc.scene.ui.SettingsDialog$SettingsTable$CheckSetting", "arc.scene.ui.SettingsDialog$SettingsTable$Setting", "arc.scene.ui.SettingsDialog$SettingsTable$SliderSetting", "arc.scene.ui.SettingsDialog$StringProcessor", "arc.scene.ui.Slider", "arc.scene.ui.Slider$SliderStyle", "arc.scene.ui.TextArea", "arc.scene.ui.TextArea$TextAreaListener", "arc.scene.ui.TextButton", "arc.scene.ui.TextButton$TextButtonStyle", "arc.scene.ui.TextField", "arc.scene.ui.TextField$DefaultOnscreenKeyboard", "arc.scene.ui.TextField$OnscreenKeyboard", "arc.scene.ui.TextField$TextFieldClickListener", "arc.scene.ui.TextField$TextFieldFilter", "arc.scene.ui.TextField$TextFieldListener", "arc.scene.ui.TextField$TextFieldStyle", "arc.scene.ui.TextField$TextFieldValidator", "arc.scene.ui.Tooltip", "arc.scene.ui.Tooltip$Tooltips", "arc.scene.ui.Touchpad", "arc.scene.ui.Touchpad$TouchpadStyle", "arc.scene.ui.TreeElement", "arc.scene.ui.TreeElement$Node", "arc.scene.ui.TreeElement$TreeStyle", "arc.scene.ui.layout.Cell", "arc.scene.ui.layout.Collapser", "arc.scene.ui.layout.HorizontalGroup", "arc.scene.ui.layout.Scl", "arc.scene.ui.layout.Stack", "arc.scene.ui.layout.Table", "arc.scene.ui.layout.Table$DrawRect", "arc.scene.ui.layout.VerticalGroup", "arc.scene.ui.layout.WidgetGroup", "arc.scene.utils.ArraySelection", "arc.scene.utils.Cullable", "arc.scene.utils.Disableable", "arc.scene.utils.DragAndDrop", "arc.scene.utils.DragAndDrop$Payload", "arc.scene.utils.DragAndDrop$Source", "arc.scene.utils.DragAndDrop$Target", "arc.scene.utils.Elements", "arc.scene.utils.Layout", "arc.scene.utils.Selection", "arc.struct.Array", "arc.struct.Array$ArrayIterable", "arc.struct.ArrayMap", "arc.struct.ArrayMap$Entries", "arc.struct.ArrayMap$Keys", "arc.struct.ArrayMap$Values", "arc.struct.AtomicQueue", "arc.struct.BinaryHeap", "arc.struct.BinaryHeap$Node", "arc.struct.Bits", "arc.struct.BooleanArray", "arc.struct.ByteArray", "arc.struct.CharArray", "arc.struct.ComparableTimSort", "arc.struct.DelayedRemovalArray", "arc.struct.EnumSet", "arc.struct.EnumSet$EnumSetIterator", "arc.struct.FloatArray", "arc.struct.GridBits", "arc.struct.GridMap", "arc.struct.IdentityMap", "arc.struct.IdentityMap$Entries", "arc.struct.IdentityMap$Entry", "arc.struct.IdentityMap$Keys", "arc.struct.IdentityMap$Values", "arc.struct.IntArray", "arc.struct.IntFloatMap", "arc.struct.IntFloatMap$Entries", "arc.struct.IntFloatMap$Entry", "arc.struct.IntFloatMap$Keys", "arc.struct.IntFloatMap$Values", "arc.struct.IntIntMap", "arc.struct.IntIntMap$Entries", "arc.struct.IntIntMap$Entry", "arc.struct.IntIntMap$Keys", "arc.struct.IntIntMap$Values", "arc.struct.IntMap", "arc.struct.IntMap$Entries", "arc.struct.IntMap$Entry", "arc.struct.IntMap$Keys", "arc.struct.IntMap$Values", "arc.struct.IntQueue", "arc.struct.IntSet", "arc.struct.IntSet$IntSetIterator", "arc.struct.LongArray", "arc.struct.LongMap", "arc.struct.LongMap$Entries", "arc.struct.LongMap$Entry", "arc.struct.LongMap$Keys", "arc.struct.LongMap$Values", "arc.struct.LongQueue", "arc.struct.ObjectFloatMap", "arc.struct.ObjectFloatMap$Entries", "arc.struct.ObjectFloatMap$Entry", "arc.struct.ObjectFloatMap$Keys", "arc.struct.ObjectFloatMap$Values", "arc.struct.ObjectIntMap", "arc.struct.ObjectIntMap$Entries", "arc.struct.ObjectIntMap$Entry", "arc.struct.ObjectIntMap$Keys", "arc.struct.ObjectIntMap$Values", "arc.struct.ObjectMap", "arc.struct.ObjectMap$Entries", "arc.struct.ObjectMap$Entry", "arc.struct.ObjectMap$Keys", "arc.struct.ObjectMap$Values", "arc.struct.ObjectSet", "arc.struct.ObjectSet$ObjectSetIterator", "arc.struct.OrderedMap", "arc.struct.OrderedMap$OrderedMapEntries", "arc.struct.OrderedMap$OrderedMapKeys", "arc.struct.OrderedMap$OrderedMapValues", "arc.struct.OrderedSet", "arc.struct.OrderedSet$OrderedSetIterator", "arc.struct.PooledLinkedList", "arc.struct.PooledLinkedList$Item", "arc.struct.Queue", "arc.struct.Queue$QueueIterable", "arc.struct.ShortArray", "arc.struct.SnapshotArray", "arc.struct.Sort", "arc.struct.SortedIntList", "arc.struct.SortedIntList$Iterator", "arc.struct.SortedIntList$Node", "arc.struct.StringMap", "arc.struct.TimSort", "arc.util.I18NBundle", "arc.util.Time", "java.io.PrintStream", "java.lang.Object", "java.lang.Runnable", "java.lang.String", "java.lang.System", "mindustry.Vars", "mindustry.ai.BlockIndexer", "mindustry.ai.Pathfinder", "mindustry.ai.Pathfinder$PathData", "mindustry.ai.Pathfinder$PathTarget", "mindustry.ai.Pathfinder$PathTileStruct", "mindustry.ai.WaveSpawner", "mindustry.content.Blocks", "mindustry.content.Bullets", "mindustry.content.Fx", "mindustry.content.Items", "mindustry.content.Liquids", "mindustry.content.Loadouts", "mindustry.content.Mechs", "mindustry.content.StatusEffects", "mindustry.content.TechTree", "mindustry.content.TechTree$TechNode", "mindustry.content.TypeIDs", "mindustry.content.UnitTypes", "mindustry.content.Zones", "mindustry.core.ContentLoader", "mindustry.core.Control", "mindustry.core.FileTree", "mindustry.core.GameState", "mindustry.core.GameState$State", "mindustry.core.Logic", "mindustry.core.NetServer$TeamAssigner", "mindustry.core.Platform", "mindustry.core.Renderer", "mindustry.core.UI", "mindustry.core.Version", "mindustry.core.World", "mindustry.core.World$Raycaster", "mindustry.ctype.Content", "mindustry.ctype.Content$ModContentInfo", "mindustry.ctype.ContentList", "mindustry.ctype.ContentType", "mindustry.ctype.MappableContent", "mindustry.ctype.UnlockableContent", "mindustry.editor.DrawOperation", "mindustry.editor.DrawOperation$OpType", "mindustry.editor.DrawOperation$TileOpStruct", "mindustry.editor.EditorTile", "mindustry.editor.EditorTool", "mindustry.editor.MapEditor", "mindustry.editor.MapEditor$Context", "mindustry.editor.MapEditorDialog", "mindustry.editor.MapGenerateDialog", "mindustry.editor.MapInfoDialog", "mindustry.editor.MapLoadDialog", "mindustry.editor.MapRenderer", "mindustry.editor.MapResizeDialog", "mindustry.editor.MapSaveDialog", "mindustry.editor.MapView", "mindustry.editor.OperationStack", "mindustry.editor.WaveInfoDialog", "mindustry.entities.Damage", "mindustry.entities.Damage$PropCellStruct", "mindustry.entities.Effects", "mindustry.entities.Effects$Effect", "mindustry.entities.Effects$EffectContainer", "mindustry.entities.Effects$EffectProvider", "mindustry.entities.Effects$EffectRenderer", "mindustry.entities.Effects$ScreenshakeProvider", "mindustry.entities.Entities", "mindustry.entities.EntityCollisions", "mindustry.entities.EntityGroup", "mindustry.entities.Predict", "mindustry.entities.TargetPriority", "mindustry.entities.Units", "mindustry.entities.bullet.ArtilleryBulletType", "mindustry.entities.bullet.BasicBulletType", "mindustry.entities.bullet.BombBulletType", "mindustry.entities.bullet.BulletType", "mindustry.entities.bullet.FlakBulletType", "mindustry.entities.bullet.HealBulletType", "mindustry.entities.bullet.LiquidBulletType", "mindustry.entities.bullet.MassDriverBolt", "mindustry.entities.bullet.MissileBulletType", "mindustry.entities.effect.Decal", "mindustry.entities.effect.Fire", "mindustry.entities.effect.GroundEffectEntity", "mindustry.entities.effect.GroundEffectEntity$GroundEffect", "mindustry.entities.effect.ItemTransfer", "mindustry.entities.effect.Lightning", "mindustry.entities.effect.Puddle", "mindustry.entities.effect.RubbleDecal", "mindustry.entities.effect.ScorchDecal", "mindustry.entities.traits.AbsorbTrait", "mindustry.entities.traits.BelowLiquidTrait", "mindustry.entities.traits.BuilderMinerTrait", "mindustry.entities.traits.BuilderTrait", "mindustry.entities.traits.BuilderTrait$BuildDataStatic", "mindustry.entities.traits.BuilderTrait$BuildRequest", "mindustry.entities.traits.DamageTrait", "mindustry.entities.traits.DrawTrait", "mindustry.entities.traits.Entity", "mindustry.entities.traits.HealthTrait", "mindustry.entities.traits.KillerTrait", "mindustry.entities.traits.MinerTrait", "mindustry.entities.traits.MoveTrait", "mindustry.entities.traits.SaveTrait", "mindustry.entities.traits.Saveable", "mindustry.entities.traits.ScaleTrait", "mindustry.entities.traits.ShooterTrait", "mindustry.entities.traits.SolidTrait", "mindustry.entities.traits.SpawnerTrait", "mindustry.entities.traits.SyncTrait", "mindustry.entities.traits.TargetTrait", "mindustry.entities.traits.TeamTrait", "mindustry.entities.traits.TimeTrait", "mindustry.entities.traits.TypeTrait", "mindustry.entities.traits.VelocityTrait", "mindustry.entities.type.BaseEntity", "mindustry.entities.type.BaseUnit", "mindustry.entities.type.Bullet", "mindustry.entities.type.DestructibleEntity", "mindustry.entities.type.EffectEntity", "mindustry.entities.type.Player", "mindustry.entities.type.SolidEntity", "mindustry.entities.type.TileEntity", "mindustry.entities.type.TimedEntity", "mindustry.entities.type.Unit", "mindustry.entities.type.base.BaseDrone", "mindustry.entities.type.base.BuilderDrone", "mindustry.entities.type.base.FlyingUnit", "mindustry.entities.type.base.GroundUnit", "mindustry.entities.type.base.HoverUnit", "mindustry.entities.type.base.MinerDrone", "mindustry.entities.type.base.RepairDrone", "mindustry.entities.units.StateMachine", "mindustry.entities.units.Statuses", "mindustry.entities.units.Statuses$StatusEntry", "mindustry.entities.units.UnitCommand", "mindustry.entities.units.UnitDrops", "mindustry.entities.units.UnitState", "mindustry.game.DefaultWaves", "mindustry.game.Difficulty", "mindustry.game.EventType", "mindustry.game.EventType$BlockBuildBeginEvent", "mindustry.game.EventType$BlockBuildEndEvent", "mindustry.game.EventType$BlockDestroyEvent", "mindustry.game.EventType$BlockInfoEvent", "mindustry.game.EventType$BuildSelectEvent", "mindustry.game.EventType$ClientLoadEvent", "mindustry.game.EventType$CommandIssueEvent", "mindustry.game.EventType$ContentReloadEvent", "mindustry.game.EventType$CoreItemDeliverEvent", "mindustry.game.EventType$DepositEvent", "mindustry.game.EventType$DisposeEvent", "mindustry.game.EventType$GameOverEvent", "mindustry.game.EventType$LaunchEvent", "mindustry.game.EventType$LaunchItemEvent", "mindustry.game.EventType$LineConfirmEvent", "mindustry.game.EventType$LoseEvent", "mindustry.game.EventType$MapMakeEvent", "mindustry.game.EventType$MapPublishEvent", "mindustry.game.EventType$MechChangeEvent", "mindustry.game.EventType$PlayEvent", "mindustry.game.EventType$PlayerBanEvent", "mindustry.game.EventType$PlayerChatEvent", "mindustry.game.EventType$PlayerConnect", "mindustry.game.EventType$PlayerIpBanEvent", "mindustry.game.EventType$PlayerIpUnbanEvent", "mindustry.game.EventType$PlayerJoin", "mindustry.game.EventType$PlayerLeave", "mindustry.game.EventType$PlayerUnbanEvent", "mindustry.game.EventType$ResearchEvent", "mindustry.game.EventType$ResetEvent", "mindustry.game.EventType$ResizeEvent", "mindustry.game.EventType$ServerLoadEvent", "mindustry.game.EventType$StateChangeEvent", "mindustry.game.EventType$TapConfigEvent", "mindustry.game.EventType$TapEvent", "mindustry.game.EventType$TileChangeEvent", "mindustry.game.EventType$Trigger", "mindustry.game.EventType$TurretAmmoDeliverEvent", "mindustry.game.EventType$UnitCreateEvent", "mindustry.game.EventType$UnitDestroyEvent", "mindustry.game.EventType$UnlockEvent", "mindustry.game.EventType$WaveEvent", "mindustry.game.EventType$WinEvent", "mindustry.game.EventType$WithdrawEvent", "mindustry.game.EventType$WorldLoadEvent", "mindustry.game.EventType$ZoneConfigureCompleteEvent", "mindustry.game.EventType$ZoneRequireCompleteEvent", "mindustry.game.Gamemode", "mindustry.game.GlobalData", "mindustry.game.LoopControl", "mindustry.game.MusicControl", "mindustry.game.Objective", "mindustry.game.Objectives", "mindustry.game.Objectives$Launched", "mindustry.game.Objectives$Unlock", "mindustry.game.Objectives$Wave", "mindustry.game.Objectives$ZoneObjective", "mindustry.game.Objectives$ZoneWave", "mindustry.game.Rules", "mindustry.game.Saves", "mindustry.game.Saves$SaveSlot", "mindustry.game.Schematic", "mindustry.game.Schematic$Stile", "mindustry.game.Schematics", "mindustry.game.SoundLoop", "mindustry.game.SpawnGroup", "mindustry.game.Stats", "mindustry.game.Stats$Rank", "mindustry.game.Stats$RankResult", "mindustry.game.Team", "mindustry.game.Teams", "mindustry.game.Teams$BrokenBlock", "mindustry.game.Teams$TeamData", "mindustry.game.Tutorial", "mindustry.game.Tutorial$TutorialStage", "mindustry.gen.BufferItem", "mindustry.gen.Call", "mindustry.gen.Call", "mindustry.gen.Icon", "mindustry.gen.Icon", "mindustry.gen.MethodHash", "mindustry.gen.Musics", "mindustry.gen.Musics", "mindustry.gen.PathTile", "mindustry.gen.PropCell", "mindustry.gen.RemoteReadClient", "mindustry.gen.RemoteReadServer", "mindustry.gen.Serialization", "mindustry.gen.Sounds", "mindustry.gen.Sounds", "mindustry.gen.Tex", "mindustry.gen.Tex", "mindustry.gen.TileOp", "mindustry.graphics.BlockRenderer", "mindustry.graphics.Bloom", "mindustry.graphics.CacheLayer", "mindustry.graphics.Drawf", "mindustry.graphics.FloorRenderer", "mindustry.graphics.IndexedRenderer", "mindustry.graphics.Layer", "mindustry.graphics.LightRenderer", "mindustry.graphics.MenuRenderer", "mindustry.graphics.MinimapRenderer", "mindustry.graphics.MultiPacker", "mindustry.graphics.MultiPacker$PageType", "mindustry.graphics.OverlayRenderer", "mindustry.graphics.Pal", "mindustry.graphics.Pixelator", "mindustry.graphics.Shaders", "mindustry.input.Binding", "mindustry.input.DesktopInput", "mindustry.input.InputHandler", "mindustry.input.InputHandler$PlaceLine", "mindustry.input.MobileInput", "mindustry.input.PlaceMode", "mindustry.input.Placement", "mindustry.input.Placement$DistanceHeuristic", "mindustry.input.Placement$NormalizeDrawResult", "mindustry.input.Placement$NormalizeResult", "mindustry.input.Placement$TileHueristic", "mindustry.maps.Map", "mindustry.maps.Maps", "mindustry.maps.Maps$MapProvider", "mindustry.maps.Maps$ShuffleMode", "mindustry.maps.Maps$ShuffleMode", "mindustry.maps.filters.BlendFilter", "mindustry.maps.filters.ClearFilter", "mindustry.maps.filters.DistortFilter", "mindustry.maps.filters.FilterOption", "mindustry.maps.filters.FilterOption$BlockOption", "mindustry.maps.filters.FilterOption$SliderOption", "mindustry.maps.filters.GenerateFilter", "mindustry.maps.filters.GenerateFilter$GenerateInput", "mindustry.maps.filters.GenerateFilter$GenerateInput$TileProvider", "mindustry.maps.filters.MedianFilter", "mindustry.maps.filters.MirrorFilter", "mindustry.maps.filters.NoiseFilter", "mindustry.maps.filters.OreFilter", "mindustry.maps.filters.OreMedianFilter", "mindustry.maps.filters.RiverNoiseFilter", "mindustry.maps.filters.ScatterFilter", "mindustry.maps.filters.TerrainFilter", "mindustry.maps.generators.BasicGenerator", "mindustry.maps.generators.BasicGenerator$DistanceHeuristic", "mindustry.maps.generators.BasicGenerator$TileHueristic", "mindustry.maps.generators.Generator", "mindustry.maps.generators.MapGenerator", "mindustry.maps.generators.MapGenerator$Decoration", "mindustry.maps.generators.RandomGenerator", "mindustry.maps.zonegen.DesertWastesGenerator", "mindustry.maps.zonegen.OvergrowthGenerator", "mindustry.type.Category", "mindustry.type.ErrorContent", "mindustry.type.Item", "mindustry.type.ItemStack", "mindustry.type.ItemType", "mindustry.type.Liquid", "mindustry.type.LiquidStack", "mindustry.type.Mech", "mindustry.type.Publishable", "mindustry.type.StatusEffect", "mindustry.type.StatusEffect$TransitionHandler", "mindustry.type.TypeID", "mindustry.type.UnitType", "mindustry.type.Weapon", "mindustry.type.WeatherEvent", "mindustry.type.Zone", "mindustry.ui.Bar", "mindustry.ui.BorderImage", "mindustry.ui.Cicon", "mindustry.ui.ContentDisplay", "mindustry.ui.Fonts", "mindustry.ui.GridImage", "mindustry.ui.IconSize", "mindustry.ui.IntFormat", "mindustry.ui.ItemDisplay", "mindustry.ui.ItemImage", "mindustry.ui.ItemsDisplay", "mindustry.ui.Links", "mindustry.ui.Links$LinkEntry", "mindustry.ui.LiquidDisplay", "mindustry.ui.Minimap", "mindustry.ui.MobileButton", "mindustry.ui.MultiReqImage", "mindustry.ui.ReqImage", "mindustry.ui.Styles", "mindustry.ui.dialogs.AboutDialog", "mindustry.ui.dialogs.AdminsDialog", "mindustry.ui.dialogs.BansDialog", "mindustry.ui.dialogs.ColorPicker", "mindustry.ui.dialogs.ContentInfoDialog", "mindustry.ui.dialogs.ControlsDialog", "mindustry.ui.dialogs.CustomGameDialog", "mindustry.ui.dialogs.CustomRulesDialog", "mindustry.ui.dialogs.DatabaseDialog", "mindustry.ui.dialogs.DeployDialog", "mindustry.ui.dialogs.DeployDialog$View", "mindustry.ui.dialogs.DeployDialog$ZoneNode", "mindustry.ui.dialogs.DiscordDialog", "mindustry.ui.dialogs.FileChooser", "mindustry.ui.dialogs.FileChooser$FileHistory", "mindustry.ui.dialogs.FloatingDialog", "mindustry.ui.dialogs.GameOverDialog", "mindustry.ui.dialogs.HostDialog", "mindustry.ui.dialogs.JoinDialog", "mindustry.ui.dialogs.JoinDialog$Server", "mindustry.ui.dialogs.LanguageDialog", "mindustry.ui.dialogs.LoadDialog", "mindustry.ui.dialogs.LoadoutDialog", "mindustry.ui.dialogs.MapPlayDialog", "mindustry.ui.dialogs.MapsDialog", "mindustry.ui.dialogs.MinimapDialog", "mindustry.ui.dialogs.ModsDialog", "mindustry.ui.dialogs.PaletteDialog", "mindustry.ui.dialogs.PausedDialog", "mindustry.ui.dialogs.SaveDialog", "mindustry.ui.dialogs.SchematicsDialog", "mindustry.ui.dialogs.SchematicsDialog$SchematicImage", "mindustry.ui.dialogs.SchematicsDialog$SchematicInfoDialog", "mindustry.ui.dialogs.SettingsMenuDialog", "mindustry.ui.dialogs.TechTreeDialog", "mindustry.ui.dialogs.TechTreeDialog$LayoutNode", "mindustry.ui.dialogs.TechTreeDialog$TechTreeNode", "mindustry.ui.dialogs.TechTreeDialog$View", "mindustry.ui.dialogs.TraceDialog", "mindustry.ui.dialogs.ZoneInfoDialog", "mindustry.ui.fragments.BlockConfigFragment", "mindustry.ui.fragments.BlockInventoryFragment", "mindustry.ui.fragments.ChatFragment", "mindustry.ui.fragments.FadeInFragment", "mindustry.ui.fragments.Fragment", "mindustry.ui.fragments.HudFragment", "mindustry.ui.fragments.LoadingFragment", "mindustry.ui.fragments.MenuFragment", "mindustry.ui.fragments.OverlayFragment", "mindustry.ui.fragments.PlacementFragment", "mindustry.ui.fragments.PlayerListFragment", "mindustry.ui.fragments.ScriptConsoleFragment", "mindustry.ui.layout.BranchTreeLayout", "mindustry.ui.layout.BranchTreeLayout$TreeAlignment", "mindustry.ui.layout.BranchTreeLayout$TreeLocation", "mindustry.ui.layout.RadialTreeLayout", "mindustry.ui.layout.TreeLayout", "mindustry.ui.layout.TreeLayout$TreeNode", "mindustry.world.Block", "mindustry.world.BlockStorage", "mindustry.world.Build", "mindustry.world.CachedTile", "mindustry.world.DirectionalItemBuffer", "mindustry.world.DirectionalItemBuffer$BufferItemStruct", "mindustry.world.Edges", "mindustry.world.ItemBuffer", "mindustry.world.LegacyColorMapper", "mindustry.world.LegacyColorMapper$LegacyBlock", "mindustry.world.Pos", "mindustry.world.StaticTree", "mindustry.world.Tile", "mindustry.world.WorldContext", "mindustry.world.blocks.Attributes", "mindustry.world.blocks.Autotiler", "mindustry.world.blocks.Autotiler$AutotilerHolder", "mindustry.world.blocks.BlockPart", "mindustry.world.blocks.BuildBlock", "mindustry.world.blocks.BuildBlock$BuildEntity", "mindustry.world.blocks.DoubleOverlayFloor", "mindustry.world.blocks.Floor", "mindustry.world.blocks.ItemSelection", "mindustry.world.blocks.LiquidBlock", "mindustry.world.blocks.OreBlock", "mindustry.world.blocks.OverlayFloor", "mindustry.world.blocks.PowerBlock", "mindustry.world.blocks.RespawnBlock", "mindustry.world.blocks.Rock", "mindustry.world.blocks.StaticWall", "mindustry.world.blocks.TreeBlock", "mindustry.world.blocks.defense.DeflectorWall", "mindustry.world.blocks.defense.DeflectorWall$DeflectorEntity", "mindustry.world.blocks.defense.Door", "mindustry.world.blocks.defense.Door$DoorEntity", "mindustry.world.blocks.defense.ForceProjector", "mindustry.world.blocks.defense.ForceProjector$ForceEntity", "mindustry.world.blocks.defense.ForceProjector$ShieldEntity", "mindustry.world.blocks.defense.MendProjector", "mindustry.world.blocks.defense.MendProjector$MendEntity", "mindustry.world.blocks.defense.OverdriveProjector", "mindustry.world.blocks.defense.OverdriveProjector$OverdriveEntity", "mindustry.world.blocks.defense.ShockMine", "mindustry.world.blocks.defense.SurgeWall", "mindustry.world.blocks.defense.Wall", "mindustry.world.blocks.defense.turrets.ArtilleryTurret", "mindustry.world.blocks.defense.turrets.BurstTurret", "mindustry.world.blocks.defense.turrets.ChargeTurret", "mindustry.world.blocks.defense.turrets.ChargeTurret$LaserTurretEntity", "mindustry.world.blocks.defense.turrets.CooledTurret", "mindustry.world.blocks.defense.turrets.DoubleTurret", "mindustry.world.blocks.defense.turrets.ItemTurret", "mindustry.world.blocks.defense.turrets.ItemTurret$ItemEntry", "mindustry.world.blocks.defense.turrets.ItemTurret$ItemTurretEntity", "mindustry.world.blocks.defense.turrets.LaserTurret", "mindustry.world.blocks.defense.turrets.LaserTurret$LaserTurretEntity", "mindustry.world.blocks.defense.turrets.LiquidTurret", "mindustry.world.blocks.defense.turrets.PowerTurret", "mindustry.world.blocks.defense.turrets.Turret", "mindustry.world.blocks.defense.turrets.Turret$AmmoEntry", "mindustry.world.blocks.defense.turrets.Turret$TurretEntity", "mindustry.world.blocks.distribution.ArmoredConveyor", "mindustry.world.blocks.distribution.BufferedItemBridge", "mindustry.world.blocks.distribution.BufferedItemBridge$BufferedItemBridgeEntity", "mindustry.world.blocks.distribution.Conveyor", "mindustry.world.blocks.distribution.Conveyor$ConveyorEntity", "mindustry.world.blocks.distribution.Conveyor$ItemPos", "mindustry.world.blocks.distribution.ExtendingItemBridge", "mindustry.world.blocks.distribution.ItemBridge", "mindustry.world.blocks.distribution.ItemBridge$ItemBridgeEntity", "mindustry.world.blocks.distribution.Junction", "mindustry.world.blocks.distribution.Junction$JunctionEntity", "mindustry.world.blocks.distribution.MassDriver", "mindustry.world.blocks.distribution.MassDriver$DriverBulletData", "mindustry.world.blocks.distribution.MassDriver$DriverState", "mindustry.world.blocks.distribution.MassDriver$MassDriverEntity", "mindustry.world.blocks.distribution.OverflowGate", "mindustry.world.blocks.distribution.OverflowGate$OverflowGateEntity", "mindustry.world.blocks.distribution.Router", "mindustry.world.blocks.distribution.Router$RouterEntity", "mindustry.world.blocks.distribution.Sorter", "mindustry.world.blocks.distribution.Sorter$SorterEntity", "mindustry.world.blocks.liquid.ArmoredConduit", "mindustry.world.blocks.liquid.Conduit", "mindustry.world.blocks.liquid.Conduit$ConduitEntity", "mindustry.world.blocks.liquid.LiquidBridge", "mindustry.world.blocks.liquid.LiquidExtendingBridge", "mindustry.world.blocks.liquid.LiquidJunction", "mindustry.world.blocks.liquid.LiquidOverflowGate", "mindustry.world.blocks.liquid.LiquidRouter", "mindustry.world.blocks.liquid.LiquidTank", "mindustry.world.blocks.logic.LogicBlock", "mindustry.world.blocks.logic.MessageBlock", "mindustry.world.blocks.logic.MessageBlock$MessageBlockEntity", "mindustry.world.blocks.power.Battery", "mindustry.world.blocks.power.BurnerGenerator", "mindustry.world.blocks.power.ConditionalConsumePower", "mindustry.world.blocks.power.DecayGenerator", "mindustry.world.blocks.power.ImpactReactor", "mindustry.world.blocks.power.ImpactReactor$FusionReactorEntity", "mindustry.world.blocks.power.ItemLiquidGenerator", "mindustry.world.blocks.power.ItemLiquidGenerator$ItemLiquidGeneratorEntity", "mindustry.world.blocks.power.LightBlock", "mindustry.world.blocks.power.LightBlock$LightEntity", "mindustry.world.blocks.power.NuclearReactor", "mindustry.world.blocks.power.NuclearReactor$NuclearReactorEntity", "mindustry.world.blocks.power.PowerDiode", "mindustry.world.blocks.power.PowerDistributor", "mindustry.world.blocks.power.PowerGenerator", "mindustry.world.blocks.power.PowerGenerator$GeneratorEntity", "mindustry.world.blocks.power.PowerGraph", "mindustry.world.blocks.power.PowerNode", "mindustry.world.blocks.power.SingleTypeGenerator", "mindustry.world.blocks.power.SolarGenerator", "mindustry.world.blocks.power.ThermalGenerator", "mindustry.world.blocks.production.Cultivator", "mindustry.world.blocks.production.Cultivator$CultivatorEntity", "mindustry.world.blocks.production.Drill", "mindustry.world.blocks.production.Drill$DrillEntity", "mindustry.world.blocks.production.Fracker", "mindustry.world.blocks.production.Fracker$FrackerEntity", "mindustry.world.blocks.production.GenericCrafter", "mindustry.world.blocks.production.GenericCrafter$GenericCrafterEntity", "mindustry.world.blocks.production.GenericSmelter", "mindustry.world.blocks.production.Incinerator", "mindustry.world.blocks.production.Incinerator$IncineratorEntity", "mindustry.world.blocks.production.LiquidConverter", "mindustry.world.blocks.production.Pump", "mindustry.world.blocks.production.Separator", "mindustry.world.blocks.production.SolidPump", "mindustry.world.blocks.production.SolidPump$SolidPumpEntity", "mindustry.world.blocks.sandbox.ItemSource", "mindustry.world.blocks.sandbox.ItemSource$ItemSourceEntity", "mindustry.world.blocks.sandbox.ItemVoid", "mindustry.world.blocks.sandbox.LiquidSource", "mindustry.world.blocks.sandbox.LiquidSource$LiquidSourceEntity", "mindustry.world.blocks.sandbox.PowerSource", "mindustry.world.blocks.sandbox.PowerVoid", "mindustry.world.blocks.storage.CoreBlock", "mindustry.world.blocks.storage.CoreBlock$CoreEntity", "mindustry.world.blocks.storage.LaunchPad", "mindustry.world.blocks.storage.StorageBlock", "mindustry.world.blocks.storage.StorageBlock$StorageBlockEntity", "mindustry.world.blocks.storage.Unloader", "mindustry.world.blocks.storage.Unloader$UnloaderEntity", "mindustry.world.blocks.storage.Vault", "mindustry.world.blocks.units.CommandCenter", "mindustry.world.blocks.units.CommandCenter$CommandCenterEntity", "mindustry.world.blocks.units.MechPad", "mindustry.world.blocks.units.MechPad$MechFactoryEntity", "mindustry.world.blocks.units.RallyPoint", "mindustry.world.blocks.units.RepairPoint", "mindustry.world.blocks.units.RepairPoint$RepairPointEntity", "mindustry.world.blocks.units.UnitFactory", "mindustry.world.blocks.units.UnitFactory$UnitFactoryEntity", "mindustry.world.consumers.Consume", "mindustry.world.consumers.ConsumeItemFilter", "mindustry.world.consumers.ConsumeItems", "mindustry.world.consumers.ConsumeLiquid", "mindustry.world.consumers.ConsumeLiquidBase", "mindustry.world.consumers.ConsumeLiquidFilter", "mindustry.world.consumers.ConsumePower", "mindustry.world.consumers.ConsumeType", "mindustry.world.consumers.Consumers", "mindustry.world.meta.Attribute", "mindustry.world.meta.BlockBars", "mindustry.world.meta.BlockFlag", "mindustry.world.meta.BlockGroup", "mindustry.world.meta.BlockStat", "mindustry.world.meta.BlockStats", "mindustry.world.meta.BuildVisibility", "mindustry.world.meta.PowerType", "mindustry.world.meta.Producers", "mindustry.world.meta.StatCategory", "mindustry.world.meta.StatUnit", "mindustry.world.meta.StatValue", "mindustry.world.meta.values.AmmoListValue", "mindustry.world.meta.values.BooleanValue", "mindustry.world.meta.values.BoosterListValue", "mindustry.world.meta.values.ItemFilterValue", "mindustry.world.meta.values.ItemListValue", "mindustry.world.meta.values.LiquidFilterValue", "mindustry.world.meta.values.LiquidValue", "mindustry.world.meta.values.NumberValue", "mindustry.world.meta.values.StringValue", "mindustry.world.modules.BlockModule", "mindustry.world.modules.ConsumeModule", "mindustry.world.modules.ItemModule", "mindustry.world.modules.ItemModule$ItemCalculator", "mindustry.world.modules.ItemModule$ItemConsumer", "mindustry.world.modules.LiquidModule", "mindustry.world.modules.LiquidModule$LiquidCalculator", "mindustry.world.modules.LiquidModule$LiquidConsumer", "mindustry.world.modules.PowerModule", "mindustry.world.producers.Produce", "mindustry.world.producers.ProduceItem"); + public static final ObjectSet allowedClassNames = ObjectSet.with("arc.Core", "arc.func.Boolc", "arc.func.Boolf", "arc.func.Boolf2", "arc.func.Boolp", "arc.func.Cons", "arc.func.Cons2", "arc.func.Floatc", "arc.func.Floatc2", "arc.func.Floatc4", "arc.func.Floatf", "arc.func.Floatp", "arc.func.Func", "arc.func.Func2", "arc.func.Func3", "arc.func.Intc", "arc.func.Intc2", "arc.func.Intc4", "arc.func.Intf", "arc.func.Intp", "arc.func.Prov", "arc.graphics.Color", "arc.graphics.Pixmap", "arc.graphics.Texture", "arc.graphics.TextureData", "arc.graphics.g2d.Draw", "arc.graphics.g2d.Fill", "arc.graphics.g2d.Lines", "arc.graphics.g2d.TextureAtlas", "arc.graphics.g2d.TextureAtlas$AtlasRegion", "arc.graphics.g2d.TextureRegion", "arc.math.Affine2", "arc.math.Angles", "arc.math.Angles", "arc.math.Angles$ParticleConsumer", "arc.math.CumulativeDistribution", "arc.math.CumulativeDistribution$CumulativeValue", "arc.math.DelaunayTriangulator", "arc.math.EarClippingTriangulator", "arc.math.Extrapolator", "arc.math.FloatCounter", "arc.math.Interpolation", "arc.math.Interpolation$Bounce", "arc.math.Interpolation$BounceIn", "arc.math.Interpolation$BounceOut", "arc.math.Interpolation$Elastic", "arc.math.Interpolation$ElasticIn", "arc.math.Interpolation$ElasticOut", "arc.math.Interpolation$Exp", "arc.math.Interpolation$ExpIn", "arc.math.Interpolation$ExpOut", "arc.math.Interpolation$Pow", "arc.math.Interpolation$PowIn", "arc.math.Interpolation$PowOut", "arc.math.Interpolation$Swing", "arc.math.Interpolation$SwingIn", "arc.math.Interpolation$SwingOut", "arc.math.Mathf", "arc.math.Mathf", "arc.math.Matrix3", "arc.math.WindowedMean", "arc.math.geom.BSpline", "arc.math.geom.Bezier", "arc.math.geom.Bresenham2", "arc.math.geom.CatmullRomSpline", "arc.math.geom.Circle", "arc.math.geom.ConvexHull", "arc.math.geom.Ellipse", "arc.math.geom.FixedPosition", "arc.math.geom.Geometry", "arc.math.geom.Geometry$Raycaster", "arc.math.geom.Geometry$SolidChecker", "arc.math.geom.Intersector", "arc.math.geom.Intersector$MinimumTranslationVector", "arc.math.geom.Path", "arc.math.geom.Point2", "arc.math.geom.Point3", "arc.math.geom.Polygon", "arc.math.geom.Polyline", "arc.math.geom.Position", "arc.math.geom.QuadTree", "arc.math.geom.QuadTree$QuadTreeObject", "arc.math.geom.Rect", "arc.math.geom.Shape2D", "arc.math.geom.Spring1D", "arc.math.geom.Spring2D", "arc.math.geom.Vec2", "arc.math.geom.Vec3", "arc.math.geom.Vector", "arc.scene.Action", "arc.scene.Element", "arc.scene.Group", "arc.scene.Scene", "arc.scene.actions.Actions", "arc.scene.actions.AddAction", "arc.scene.actions.AddListenerAction", "arc.scene.actions.AfterAction", "arc.scene.actions.AlphaAction", "arc.scene.actions.ColorAction", "arc.scene.actions.DelayAction", "arc.scene.actions.DelegateAction", "arc.scene.actions.FloatAction", "arc.scene.actions.IntAction", "arc.scene.actions.LayoutAction", "arc.scene.actions.MoveByAction", "arc.scene.actions.MoveToAction", "arc.scene.actions.OriginAction", "arc.scene.actions.ParallelAction", "arc.scene.actions.RelativeTemporalAction", "arc.scene.actions.RemoveAction", "arc.scene.actions.RemoveActorAction", "arc.scene.actions.RemoveListenerAction", "arc.scene.actions.RepeatAction", "arc.scene.actions.RotateByAction", "arc.scene.actions.RotateToAction", "arc.scene.actions.RunnableAction", "arc.scene.actions.ScaleByAction", "arc.scene.actions.ScaleToAction", "arc.scene.actions.SequenceAction", "arc.scene.actions.SizeByAction", "arc.scene.actions.SizeToAction", "arc.scene.actions.TemporalAction", "arc.scene.actions.TimeScaleAction", "arc.scene.actions.TouchableAction", "arc.scene.actions.TranslateByAction", "arc.scene.actions.VisibleAction", "arc.scene.event.ChangeListener", "arc.scene.event.ChangeListener$ChangeEvent", "arc.scene.event.ClickListener", "arc.scene.event.DragListener", "arc.scene.event.DragScrollListener", "arc.scene.event.ElementGestureListener", "arc.scene.event.EventListener", "arc.scene.event.FocusListener", "arc.scene.event.FocusListener$FocusEvent", "arc.scene.event.FocusListener$FocusEvent$Type", "arc.scene.event.HandCursorListener", "arc.scene.event.IbeamCursorListener", "arc.scene.event.InputEvent", "arc.scene.event.InputEvent$Type", "arc.scene.event.InputListener", "arc.scene.event.SceneEvent", "arc.scene.event.Touchable", "arc.scene.event.VisibilityEvent", "arc.scene.event.VisibilityListener", "arc.scene.style.BaseDrawable", "arc.scene.style.Drawable", "arc.scene.style.NinePatchDrawable", "arc.scene.style.ScaledNinePatchDrawable", "arc.scene.style.Style", "arc.scene.style.TextureRegionDrawable", "arc.scene.style.TiledDrawable", "arc.scene.style.TransformDrawable", "arc.scene.ui.Button", "arc.scene.ui.Button$ButtonStyle", "arc.scene.ui.ButtonGroup", "arc.scene.ui.CheckBox", "arc.scene.ui.CheckBox$CheckBoxStyle", "arc.scene.ui.ColorImage", "arc.scene.ui.Dialog", "arc.scene.ui.Dialog$DialogStyle", "arc.scene.ui.Image", "arc.scene.ui.ImageButton", "arc.scene.ui.ImageButton$ImageButtonStyle", "arc.scene.ui.KeybindDialog", "arc.scene.ui.KeybindDialog$KeybindDialogStyle", "arc.scene.ui.Label", "arc.scene.ui.Label$LabelStyle", "arc.scene.ui.ProgressBar", "arc.scene.ui.ProgressBar$ProgressBarStyle", "arc.scene.ui.ScrollPane", "arc.scene.ui.ScrollPane$ScrollPaneStyle", "arc.scene.ui.SettingsDialog", "arc.scene.ui.SettingsDialog$SettingsTable", "arc.scene.ui.SettingsDialog$SettingsTable$CheckSetting", "arc.scene.ui.SettingsDialog$SettingsTable$Setting", "arc.scene.ui.SettingsDialog$SettingsTable$SliderSetting", "arc.scene.ui.SettingsDialog$StringProcessor", "arc.scene.ui.Slider", "arc.scene.ui.Slider$SliderStyle", "arc.scene.ui.TextArea", "arc.scene.ui.TextArea$TextAreaListener", "arc.scene.ui.TextButton", "arc.scene.ui.TextButton$TextButtonStyle", "arc.scene.ui.TextField", "arc.scene.ui.TextField$DefaultOnscreenKeyboard", "arc.scene.ui.TextField$OnscreenKeyboard", "arc.scene.ui.TextField$TextFieldClickListener", "arc.scene.ui.TextField$TextFieldFilter", "arc.scene.ui.TextField$TextFieldListener", "arc.scene.ui.TextField$TextFieldStyle", "arc.scene.ui.TextField$TextFieldValidator", "arc.scene.ui.Tooltip", "arc.scene.ui.Tooltip$Tooltips", "arc.scene.ui.Touchpad", "arc.scene.ui.Touchpad$TouchpadStyle", "arc.scene.ui.TreeElement", "arc.scene.ui.TreeElement$Node", "arc.scene.ui.TreeElement$TreeStyle", "arc.scene.ui.layout.Cell", "arc.scene.ui.layout.Collapser", "arc.scene.ui.layout.HorizontalGroup", "arc.scene.ui.layout.Scl", "arc.scene.ui.layout.Stack", "arc.scene.ui.layout.Table", "arc.scene.ui.layout.Table$DrawRect", "arc.scene.ui.layout.VerticalGroup", "arc.scene.ui.layout.WidgetGroup", "arc.scene.utils.ArraySelection", "arc.scene.utils.Cullable", "arc.scene.utils.Disableable", "arc.scene.utils.DragAndDrop", "arc.scene.utils.DragAndDrop$Payload", "arc.scene.utils.DragAndDrop$Source", "arc.scene.utils.DragAndDrop$Target", "arc.scene.utils.Elements", "arc.scene.utils.Layout", "arc.scene.utils.Selection", "arc.struct.Array", "arc.struct.Array$ArrayIterable", "arc.struct.ArrayMap", "arc.struct.ArrayMap$Entries", "arc.struct.ArrayMap$Keys", "arc.struct.ArrayMap$Values", "arc.struct.AtomicQueue", "arc.struct.BinaryHeap", "arc.struct.BinaryHeap$Node", "arc.struct.Bits", "arc.struct.BooleanArray", "arc.struct.ByteArray", "arc.struct.CharArray", "arc.struct.ComparableTimSort", "arc.struct.DelayedRemovalArray", "arc.struct.EnumSet", "arc.struct.EnumSet$EnumSetIterator", "arc.struct.FloatArray", "arc.struct.GridBits", "arc.struct.GridMap", "arc.struct.IdentityMap", "arc.struct.IdentityMap$Entries", "arc.struct.IdentityMap$Entry", "arc.struct.IdentityMap$Keys", "arc.struct.IdentityMap$Values", "arc.struct.IntArray", "arc.struct.IntFloatMap", "arc.struct.IntFloatMap$Entries", "arc.struct.IntFloatMap$Entry", "arc.struct.IntFloatMap$Keys", "arc.struct.IntFloatMap$Values", "arc.struct.IntIntMap", "arc.struct.IntIntMap$Entries", "arc.struct.IntIntMap$Entry", "arc.struct.IntIntMap$Keys", "arc.struct.IntIntMap$Values", "arc.struct.IntMap", "arc.struct.IntMap$Entries", "arc.struct.IntMap$Entry", "arc.struct.IntMap$Keys", "arc.struct.IntMap$Values", "arc.struct.IntQueue", "arc.struct.IntSet", "arc.struct.IntSet$IntSetIterator", "arc.struct.LongArray", "arc.struct.LongMap", "arc.struct.LongMap$Entries", "arc.struct.LongMap$Entry", "arc.struct.LongMap$Keys", "arc.struct.LongMap$Values", "arc.struct.LongQueue", "arc.struct.ObjectFloatMap", "arc.struct.ObjectFloatMap$Entries", "arc.struct.ObjectFloatMap$Entry", "arc.struct.ObjectFloatMap$Keys", "arc.struct.ObjectFloatMap$Values", "arc.struct.ObjectIntMap", "arc.struct.ObjectIntMap$Entries", "arc.struct.ObjectIntMap$Entry", "arc.struct.ObjectIntMap$Keys", "arc.struct.ObjectIntMap$Values", "arc.struct.ObjectMap", "arc.struct.ObjectMap$Entries", "arc.struct.ObjectMap$Entry", "arc.struct.ObjectMap$Keys", "arc.struct.ObjectMap$Values", "arc.struct.ObjectSet", "arc.struct.ObjectSet$ObjectSetIterator", "arc.struct.OrderedMap", "arc.struct.OrderedMap$OrderedMapEntries", "arc.struct.OrderedMap$OrderedMapKeys", "arc.struct.OrderedMap$OrderedMapValues", "arc.struct.OrderedSet", "arc.struct.OrderedSet$OrderedSetIterator", "arc.struct.PooledLinkedList", "arc.struct.PooledLinkedList$Item", "arc.struct.Queue", "arc.struct.Queue$QueueIterable", "arc.struct.ShortArray", "arc.struct.SnapshotArray", "arc.struct.Sort", "arc.struct.SortedIntList", "arc.struct.SortedIntList$Iterator", "arc.struct.SortedIntList$Node", "arc.struct.StringMap", "arc.struct.TimSort", "arc.util.I18NBundle", "arc.util.Interval", "arc.util.Time", "java.io.DataInput", "java.io.DataInputStream", "java.io.DataOutput", "java.io.DataOutputStream", "java.io.PrintStream", "java.lang.Object", "java.lang.Runnable", "java.lang.String", "java.lang.System", "mindustry.Vars", "mindustry.ai.BlockIndexer", "mindustry.ai.Pathfinder", "mindustry.ai.Pathfinder$PathData", "mindustry.ai.Pathfinder$PathTarget", "mindustry.ai.Pathfinder$PathTileStruct", "mindustry.ai.WaveSpawner", "mindustry.content.Blocks", "mindustry.content.Bullets", "mindustry.content.Fx", "mindustry.content.Items", "mindustry.content.Liquids", "mindustry.content.Loadouts", "mindustry.content.Mechs", "mindustry.content.StatusEffects", "mindustry.content.TechTree", "mindustry.content.TechTree$TechNode", "mindustry.content.TypeIDs", "mindustry.content.UnitTypes", "mindustry.content.Zones", "mindustry.core.ContentLoader", "mindustry.core.Control", "mindustry.core.FileTree", "mindustry.core.GameState", "mindustry.core.GameState$State", "mindustry.core.Logic", "mindustry.core.NetServer$TeamAssigner", "mindustry.core.Platform", "mindustry.core.Renderer", "mindustry.core.UI", "mindustry.core.Version", "mindustry.core.World", "mindustry.core.World$Raycaster", "mindustry.ctype.Content", "mindustry.ctype.Content$ModContentInfo", "mindustry.ctype.ContentList", "mindustry.ctype.ContentType", "mindustry.ctype.MappableContent", "mindustry.ctype.UnlockableContent", "mindustry.editor.DrawOperation", "mindustry.editor.DrawOperation$OpType", "mindustry.editor.DrawOperation$TileOpStruct", "mindustry.editor.EditorTile", "mindustry.editor.EditorTool", "mindustry.editor.MapEditor", "mindustry.editor.MapEditor$Context", "mindustry.editor.MapEditorDialog", "mindustry.editor.MapGenerateDialog", "mindustry.editor.MapInfoDialog", "mindustry.editor.MapLoadDialog", "mindustry.editor.MapRenderer", "mindustry.editor.MapResizeDialog", "mindustry.editor.MapSaveDialog", "mindustry.editor.MapView", "mindustry.editor.OperationStack", "mindustry.editor.WaveInfoDialog", "mindustry.entities.Damage", "mindustry.entities.Damage$PropCellStruct", "mindustry.entities.Effects", "mindustry.entities.Effects$Effect", "mindustry.entities.Effects$EffectContainer", "mindustry.entities.Effects$EffectProvider", "mindustry.entities.Effects$EffectRenderer", "mindustry.entities.Effects$ScreenshakeProvider", "mindustry.entities.Entities", "mindustry.entities.EntityCollisions", "mindustry.entities.EntityGroup", "mindustry.entities.Predict", "mindustry.entities.TargetPriority", "mindustry.entities.Units", "mindustry.entities.bullet.ArtilleryBulletType", "mindustry.entities.bullet.BasicBulletType", "mindustry.entities.bullet.BombBulletType", "mindustry.entities.bullet.BulletType", "mindustry.entities.bullet.FlakBulletType", "mindustry.entities.bullet.HealBulletType", "mindustry.entities.bullet.LiquidBulletType", "mindustry.entities.bullet.MassDriverBolt", "mindustry.entities.bullet.MissileBulletType", "mindustry.entities.effect.Decal", "mindustry.entities.effect.Fire", "mindustry.entities.effect.GroundEffectEntity", "mindustry.entities.effect.GroundEffectEntity$GroundEffect", "mindustry.entities.effect.ItemTransfer", "mindustry.entities.effect.Lightning", "mindustry.entities.effect.Puddle", "mindustry.entities.effect.RubbleDecal", "mindustry.entities.effect.ScorchDecal", "mindustry.entities.traits.AbsorbTrait", "mindustry.entities.traits.BelowLiquidTrait", "mindustry.entities.traits.BuilderMinerTrait", "mindustry.entities.traits.BuilderTrait", "mindustry.entities.traits.BuilderTrait$BuildDataStatic", "mindustry.entities.traits.BuilderTrait$BuildRequest", "mindustry.entities.traits.DamageTrait", "mindustry.entities.traits.DrawTrait", "mindustry.entities.traits.Entity", "mindustry.entities.traits.HealthTrait", "mindustry.entities.traits.KillerTrait", "mindustry.entities.traits.MinerTrait", "mindustry.entities.traits.MoveTrait", "mindustry.entities.traits.SaveTrait", "mindustry.entities.traits.Saveable", "mindustry.entities.traits.ScaleTrait", "mindustry.entities.traits.ShooterTrait", "mindustry.entities.traits.SolidTrait", "mindustry.entities.traits.SpawnerTrait", "mindustry.entities.traits.SyncTrait", "mindustry.entities.traits.TargetTrait", "mindustry.entities.traits.TeamTrait", "mindustry.entities.traits.TimeTrait", "mindustry.entities.traits.TypeTrait", "mindustry.entities.traits.VelocityTrait", "mindustry.entities.type.BaseEntity", "mindustry.entities.type.BaseUnit", "mindustry.entities.type.Bullet", "mindustry.entities.type.DestructibleEntity", "mindustry.entities.type.EffectEntity", "mindustry.entities.type.Player", "mindustry.entities.type.SolidEntity", "mindustry.entities.type.TileEntity", "mindustry.entities.type.TimedEntity", "mindustry.entities.type.Unit", "mindustry.entities.type.base.BaseDrone", "mindustry.entities.type.base.BuilderDrone", "mindustry.entities.type.base.FlyingUnit", "mindustry.entities.type.base.GroundUnit", "mindustry.entities.type.base.HoverUnit", "mindustry.entities.type.base.MinerDrone", "mindustry.entities.type.base.RepairDrone", "mindustry.entities.units.StateMachine", "mindustry.entities.units.Statuses", "mindustry.entities.units.Statuses$StatusEntry", "mindustry.entities.units.UnitCommand", "mindustry.entities.units.UnitDrops", "mindustry.entities.units.UnitState", "mindustry.game.DefaultWaves", "mindustry.game.Difficulty", "mindustry.game.EventType", "mindustry.game.EventType$BlockBuildBeginEvent", "mindustry.game.EventType$BlockBuildEndEvent", "mindustry.game.EventType$BlockDestroyEvent", "mindustry.game.EventType$BlockInfoEvent", "mindustry.game.EventType$BuildSelectEvent", "mindustry.game.EventType$ClientLoadEvent", "mindustry.game.EventType$CommandIssueEvent", "mindustry.game.EventType$ContentReloadEvent", "mindustry.game.EventType$CoreItemDeliverEvent", "mindustry.game.EventType$DepositEvent", "mindustry.game.EventType$DisposeEvent", "mindustry.game.EventType$GameOverEvent", "mindustry.game.EventType$LaunchEvent", "mindustry.game.EventType$LaunchItemEvent", "mindustry.game.EventType$LineConfirmEvent", "mindustry.game.EventType$LoseEvent", "mindustry.game.EventType$MapMakeEvent", "mindustry.game.EventType$MapPublishEvent", "mindustry.game.EventType$MechChangeEvent", "mindustry.game.EventType$PlayEvent", "mindustry.game.EventType$PlayerBanEvent", "mindustry.game.EventType$PlayerChatEvent", "mindustry.game.EventType$PlayerConnect", "mindustry.game.EventType$PlayerIpBanEvent", "mindustry.game.EventType$PlayerIpUnbanEvent", "mindustry.game.EventType$PlayerJoin", "mindustry.game.EventType$PlayerLeave", "mindustry.game.EventType$PlayerUnbanEvent", "mindustry.game.EventType$ResearchEvent", "mindustry.game.EventType$ResetEvent", "mindustry.game.EventType$ResizeEvent", "mindustry.game.EventType$ServerLoadEvent", "mindustry.game.EventType$StateChangeEvent", "mindustry.game.EventType$TapConfigEvent", "mindustry.game.EventType$TapEvent", "mindustry.game.EventType$TileChangeEvent", "mindustry.game.EventType$Trigger", "mindustry.game.EventType$TurretAmmoDeliverEvent", "mindustry.game.EventType$UnitCreateEvent", "mindustry.game.EventType$UnitDestroyEvent", "mindustry.game.EventType$UnlockEvent", "mindustry.game.EventType$WaveEvent", "mindustry.game.EventType$WinEvent", "mindustry.game.EventType$WithdrawEvent", "mindustry.game.EventType$WorldLoadEvent", "mindustry.game.EventType$ZoneConfigureCompleteEvent", "mindustry.game.EventType$ZoneRequireCompleteEvent", "mindustry.game.Gamemode", "mindustry.game.GlobalData", "mindustry.game.LoopControl", "mindustry.game.MusicControl", "mindustry.game.Objective", "mindustry.game.Objectives", "mindustry.game.Objectives$Launched", "mindustry.game.Objectives$Unlock", "mindustry.game.Objectives$Wave", "mindustry.game.Objectives$ZoneObjective", "mindustry.game.Objectives$ZoneWave", "mindustry.game.Rules", "mindustry.game.Saves", "mindustry.game.Saves$SaveSlot", "mindustry.game.Schematic", "mindustry.game.Schematic$Stile", "mindustry.game.Schematics", "mindustry.game.SoundLoop", "mindustry.game.SpawnGroup", "mindustry.game.Stats", "mindustry.game.Stats$Rank", "mindustry.game.Stats$RankResult", "mindustry.game.Team", "mindustry.game.Teams", "mindustry.game.Teams$BrokenBlock", "mindustry.game.Teams$TeamData", "mindustry.game.Tutorial", "mindustry.game.Tutorial$TutorialStage", "mindustry.gen.BufferItem", "mindustry.gen.Call", "mindustry.gen.Call", "mindustry.gen.Icon", "mindustry.gen.Icon", "mindustry.gen.MethodHash", "mindustry.gen.Musics", "mindustry.gen.Musics", "mindustry.gen.PathTile", "mindustry.gen.PropCell", "mindustry.gen.RemoteReadClient", "mindustry.gen.RemoteReadServer", "mindustry.gen.Serialization", "mindustry.gen.Sounds", "mindustry.gen.Sounds", "mindustry.gen.Tex", "mindustry.gen.Tex", "mindustry.gen.TileOp", "mindustry.graphics.BlockRenderer", "mindustry.graphics.Bloom", "mindustry.graphics.CacheLayer", "mindustry.graphics.Drawf", "mindustry.graphics.FloorRenderer", "mindustry.graphics.IndexedRenderer", "mindustry.graphics.Layer", "mindustry.graphics.LightRenderer", "mindustry.graphics.MenuRenderer", "mindustry.graphics.MinimapRenderer", "mindustry.graphics.MultiPacker", "mindustry.graphics.MultiPacker$PageType", "mindustry.graphics.OverlayRenderer", "mindustry.graphics.Pal", "mindustry.graphics.Pixelator", "mindustry.graphics.Shaders", "mindustry.input.Binding", "mindustry.input.DesktopInput", "mindustry.input.InputHandler", "mindustry.input.InputHandler$PlaceLine", "mindustry.input.MobileInput", "mindustry.input.PlaceMode", "mindustry.input.Placement", "mindustry.input.Placement$DistanceHeuristic", "mindustry.input.Placement$NormalizeDrawResult", "mindustry.input.Placement$NormalizeResult", "mindustry.input.Placement$TileHueristic", "mindustry.maps.Map", "mindustry.maps.Maps", "mindustry.maps.Maps$MapProvider", "mindustry.maps.Maps$ShuffleMode", "mindustry.maps.Maps$ShuffleMode", "mindustry.maps.filters.BlendFilter", "mindustry.maps.filters.ClearFilter", "mindustry.maps.filters.DistortFilter", "mindustry.maps.filters.FilterOption", "mindustry.maps.filters.FilterOption$BlockOption", "mindustry.maps.filters.FilterOption$SliderOption", "mindustry.maps.filters.GenerateFilter", "mindustry.maps.filters.GenerateFilter$GenerateInput", "mindustry.maps.filters.GenerateFilter$GenerateInput$TileProvider", "mindustry.maps.filters.MedianFilter", "mindustry.maps.filters.MirrorFilter", "mindustry.maps.filters.NoiseFilter", "mindustry.maps.filters.OreFilter", "mindustry.maps.filters.OreMedianFilter", "mindustry.maps.filters.RiverNoiseFilter", "mindustry.maps.filters.ScatterFilter", "mindustry.maps.filters.TerrainFilter", "mindustry.maps.generators.BasicGenerator", "mindustry.maps.generators.BasicGenerator$DistanceHeuristic", "mindustry.maps.generators.BasicGenerator$TileHueristic", "mindustry.maps.generators.Generator", "mindustry.maps.generators.MapGenerator", "mindustry.maps.generators.MapGenerator$Decoration", "mindustry.maps.generators.RandomGenerator", "mindustry.maps.zonegen.DesertWastesGenerator", "mindustry.maps.zonegen.OvergrowthGenerator", "mindustry.type.Category", "mindustry.type.ErrorContent", "mindustry.type.Item", "mindustry.type.ItemStack", "mindustry.type.ItemType", "mindustry.type.Liquid", "mindustry.type.LiquidStack", "mindustry.type.Mech", "mindustry.type.Publishable", "mindustry.type.StatusEffect", "mindustry.type.StatusEffect$TransitionHandler", "mindustry.type.TypeID", "mindustry.type.UnitType", "mindustry.type.Weapon", "mindustry.type.WeatherEvent", "mindustry.type.Zone", "mindustry.ui.Bar", "mindustry.ui.BorderImage", "mindustry.ui.Cicon", "mindustry.ui.ContentDisplay", "mindustry.ui.Fonts", "mindustry.ui.GridImage", "mindustry.ui.IconSize", "mindustry.ui.IntFormat", "mindustry.ui.ItemDisplay", "mindustry.ui.ItemImage", "mindustry.ui.ItemsDisplay", "mindustry.ui.Links", "mindustry.ui.Links$LinkEntry", "mindustry.ui.LiquidDisplay", "mindustry.ui.Minimap", "mindustry.ui.MobileButton", "mindustry.ui.MultiReqImage", "mindustry.ui.ReqImage", "mindustry.ui.Styles", "mindustry.ui.dialogs.AboutDialog", "mindustry.ui.dialogs.AdminsDialog", "mindustry.ui.dialogs.BansDialog", "mindustry.ui.dialogs.ColorPicker", "mindustry.ui.dialogs.ContentInfoDialog", "mindustry.ui.dialogs.ControlsDialog", "mindustry.ui.dialogs.CustomGameDialog", "mindustry.ui.dialogs.CustomRulesDialog", "mindustry.ui.dialogs.DatabaseDialog", "mindustry.ui.dialogs.DeployDialog", "mindustry.ui.dialogs.DeployDialog$View", "mindustry.ui.dialogs.DeployDialog$ZoneNode", "mindustry.ui.dialogs.DiscordDialog", "mindustry.ui.dialogs.FileChooser", "mindustry.ui.dialogs.FileChooser$FileHistory", "mindustry.ui.dialogs.FloatingDialog", "mindustry.ui.dialogs.GameOverDialog", "mindustry.ui.dialogs.HostDialog", "mindustry.ui.dialogs.JoinDialog", "mindustry.ui.dialogs.JoinDialog$Server", "mindustry.ui.dialogs.LanguageDialog", "mindustry.ui.dialogs.LoadDialog", "mindustry.ui.dialogs.LoadoutDialog", "mindustry.ui.dialogs.MapPlayDialog", "mindustry.ui.dialogs.MapsDialog", "mindustry.ui.dialogs.MinimapDialog", "mindustry.ui.dialogs.ModsDialog", "mindustry.ui.dialogs.PaletteDialog", "mindustry.ui.dialogs.PausedDialog", "mindustry.ui.dialogs.SaveDialog", "mindustry.ui.dialogs.SchematicsDialog", "mindustry.ui.dialogs.SchematicsDialog$SchematicImage", "mindustry.ui.dialogs.SchematicsDialog$SchematicInfoDialog", "mindustry.ui.dialogs.SettingsMenuDialog", "mindustry.ui.dialogs.TechTreeDialog", "mindustry.ui.dialogs.TechTreeDialog$LayoutNode", "mindustry.ui.dialogs.TechTreeDialog$TechTreeNode", "mindustry.ui.dialogs.TechTreeDialog$View", "mindustry.ui.dialogs.TraceDialog", "mindustry.ui.dialogs.ZoneInfoDialog", "mindustry.ui.fragments.BlockConfigFragment", "mindustry.ui.fragments.BlockInventoryFragment", "mindustry.ui.fragments.ChatFragment", "mindustry.ui.fragments.FadeInFragment", "mindustry.ui.fragments.Fragment", "mindustry.ui.fragments.HudFragment", "mindustry.ui.fragments.LoadingFragment", "mindustry.ui.fragments.MenuFragment", "mindustry.ui.fragments.OverlayFragment", "mindustry.ui.fragments.PlacementFragment", "mindustry.ui.fragments.PlayerListFragment", "mindustry.ui.fragments.ScriptConsoleFragment", "mindustry.ui.layout.BranchTreeLayout", "mindustry.ui.layout.BranchTreeLayout$TreeAlignment", "mindustry.ui.layout.BranchTreeLayout$TreeLocation", "mindustry.ui.layout.RadialTreeLayout", "mindustry.ui.layout.TreeLayout", "mindustry.ui.layout.TreeLayout$TreeNode", "mindustry.world.Block", "mindustry.world.BlockStorage", "mindustry.world.Build", "mindustry.world.CachedTile", "mindustry.world.DirectionalItemBuffer", "mindustry.world.DirectionalItemBuffer$BufferItemStruct", "mindustry.world.Edges", "mindustry.world.ItemBuffer", "mindustry.world.LegacyColorMapper", "mindustry.world.LegacyColorMapper$LegacyBlock", "mindustry.world.Pos", "mindustry.world.StaticTree", "mindustry.world.Tile", "mindustry.world.WorldContext", "mindustry.world.blocks.Attributes", "mindustry.world.blocks.Autotiler", "mindustry.world.blocks.Autotiler$AutotilerHolder", "mindustry.world.blocks.BlockPart", "mindustry.world.blocks.BuildBlock", "mindustry.world.blocks.BuildBlock$BuildEntity", "mindustry.world.blocks.DoubleOverlayFloor", "mindustry.world.blocks.Floor", "mindustry.world.blocks.ItemSelection", "mindustry.world.blocks.LiquidBlock", "mindustry.world.blocks.OreBlock", "mindustry.world.blocks.OverlayFloor", "mindustry.world.blocks.PowerBlock", "mindustry.world.blocks.RespawnBlock", "mindustry.world.blocks.Rock", "mindustry.world.blocks.StaticWall", "mindustry.world.blocks.TreeBlock", "mindustry.world.blocks.defense.DeflectorWall", "mindustry.world.blocks.defense.DeflectorWall$DeflectorEntity", "mindustry.world.blocks.defense.Door", "mindustry.world.blocks.defense.Door$DoorEntity", "mindustry.world.blocks.defense.ForceProjector", "mindustry.world.blocks.defense.ForceProjector$ForceEntity", "mindustry.world.blocks.defense.ForceProjector$ShieldEntity", "mindustry.world.blocks.defense.MendProjector", "mindustry.world.blocks.defense.MendProjector$MendEntity", "mindustry.world.blocks.defense.OverdriveProjector", "mindustry.world.blocks.defense.OverdriveProjector$OverdriveEntity", "mindustry.world.blocks.defense.ShockMine", "mindustry.world.blocks.defense.SurgeWall", "mindustry.world.blocks.defense.Wall", "mindustry.world.blocks.defense.turrets.ArtilleryTurret", "mindustry.world.blocks.defense.turrets.BurstTurret", "mindustry.world.blocks.defense.turrets.ChargeTurret", "mindustry.world.blocks.defense.turrets.ChargeTurret$LaserTurretEntity", "mindustry.world.blocks.defense.turrets.CooledTurret", "mindustry.world.blocks.defense.turrets.DoubleTurret", "mindustry.world.blocks.defense.turrets.ItemTurret", "mindustry.world.blocks.defense.turrets.ItemTurret$ItemEntry", "mindustry.world.blocks.defense.turrets.ItemTurret$ItemTurretEntity", "mindustry.world.blocks.defense.turrets.LaserTurret", "mindustry.world.blocks.defense.turrets.LaserTurret$LaserTurretEntity", "mindustry.world.blocks.defense.turrets.LiquidTurret", "mindustry.world.blocks.defense.turrets.PowerTurret", "mindustry.world.blocks.defense.turrets.Turret", "mindustry.world.blocks.defense.turrets.Turret$AmmoEntry", "mindustry.world.blocks.defense.turrets.Turret$TurretEntity", "mindustry.world.blocks.distribution.ArmoredConveyor", "mindustry.world.blocks.distribution.BufferedItemBridge", "mindustry.world.blocks.distribution.BufferedItemBridge$BufferedItemBridgeEntity", "mindustry.world.blocks.distribution.Conveyor", "mindustry.world.blocks.distribution.Conveyor$ConveyorEntity", "mindustry.world.blocks.distribution.Conveyor$ItemPos", "mindustry.world.blocks.distribution.ExtendingItemBridge", "mindustry.world.blocks.distribution.ItemBridge", "mindustry.world.blocks.distribution.ItemBridge$ItemBridgeEntity", "mindustry.world.blocks.distribution.Junction", "mindustry.world.blocks.distribution.Junction$JunctionEntity", "mindustry.world.blocks.distribution.MassDriver", "mindustry.world.blocks.distribution.MassDriver$DriverBulletData", "mindustry.world.blocks.distribution.MassDriver$DriverState", "mindustry.world.blocks.distribution.MassDriver$MassDriverEntity", "mindustry.world.blocks.distribution.OverflowGate", "mindustry.world.blocks.distribution.OverflowGate$OverflowGateEntity", "mindustry.world.blocks.distribution.Router", "mindustry.world.blocks.distribution.Router$RouterEntity", "mindustry.world.blocks.distribution.Sorter", "mindustry.world.blocks.distribution.Sorter$SorterEntity", "mindustry.world.blocks.liquid.ArmoredConduit", "mindustry.world.blocks.liquid.Conduit", "mindustry.world.blocks.liquid.Conduit$ConduitEntity", "mindustry.world.blocks.liquid.LiquidBridge", "mindustry.world.blocks.liquid.LiquidExtendingBridge", "mindustry.world.blocks.liquid.LiquidJunction", "mindustry.world.blocks.liquid.LiquidOverflowGate", "mindustry.world.blocks.liquid.LiquidRouter", "mindustry.world.blocks.liquid.LiquidTank", "mindustry.world.blocks.logic.LogicBlock", "mindustry.world.blocks.logic.MessageBlock", "mindustry.world.blocks.logic.MessageBlock$MessageBlockEntity", "mindustry.world.blocks.power.Battery", "mindustry.world.blocks.power.BurnerGenerator", "mindustry.world.blocks.power.ConditionalConsumePower", "mindustry.world.blocks.power.DecayGenerator", "mindustry.world.blocks.power.ImpactReactor", "mindustry.world.blocks.power.ImpactReactor$FusionReactorEntity", "mindustry.world.blocks.power.ItemLiquidGenerator", "mindustry.world.blocks.power.ItemLiquidGenerator$ItemLiquidGeneratorEntity", "mindustry.world.blocks.power.LightBlock", "mindustry.world.blocks.power.LightBlock$LightEntity", "mindustry.world.blocks.power.NuclearReactor", "mindustry.world.blocks.power.NuclearReactor$NuclearReactorEntity", "mindustry.world.blocks.power.PowerDiode", "mindustry.world.blocks.power.PowerDistributor", "mindustry.world.blocks.power.PowerGenerator", "mindustry.world.blocks.power.PowerGenerator$GeneratorEntity", "mindustry.world.blocks.power.PowerGraph", "mindustry.world.blocks.power.PowerNode", "mindustry.world.blocks.power.SingleTypeGenerator", "mindustry.world.blocks.power.SolarGenerator", "mindustry.world.blocks.power.ThermalGenerator", "mindustry.world.blocks.production.Cultivator", "mindustry.world.blocks.production.Cultivator$CultivatorEntity", "mindustry.world.blocks.production.Drill", "mindustry.world.blocks.production.Drill$DrillEntity", "mindustry.world.blocks.production.Fracker", "mindustry.world.blocks.production.Fracker$FrackerEntity", "mindustry.world.blocks.production.GenericCrafter", "mindustry.world.blocks.production.GenericCrafter$GenericCrafterEntity", "mindustry.world.blocks.production.GenericSmelter", "mindustry.world.blocks.production.Incinerator", "mindustry.world.blocks.production.Incinerator$IncineratorEntity", "mindustry.world.blocks.production.LiquidConverter", "mindustry.world.blocks.production.Pump", "mindustry.world.blocks.production.Separator", "mindustry.world.blocks.production.SolidPump", "mindustry.world.blocks.production.SolidPump$SolidPumpEntity", "mindustry.world.blocks.sandbox.ItemSource", "mindustry.world.blocks.sandbox.ItemSource$ItemSourceEntity", "mindustry.world.blocks.sandbox.ItemVoid", "mindustry.world.blocks.sandbox.LiquidSource", "mindustry.world.blocks.sandbox.LiquidSource$LiquidSourceEntity", "mindustry.world.blocks.sandbox.PowerSource", "mindustry.world.blocks.sandbox.PowerVoid", "mindustry.world.blocks.storage.CoreBlock", "mindustry.world.blocks.storage.CoreBlock$CoreEntity", "mindustry.world.blocks.storage.LaunchPad", "mindustry.world.blocks.storage.StorageBlock", "mindustry.world.blocks.storage.StorageBlock$StorageBlockEntity", "mindustry.world.blocks.storage.Unloader", "mindustry.world.blocks.storage.Unloader$UnloaderEntity", "mindustry.world.blocks.storage.Vault", "mindustry.world.blocks.units.CommandCenter", "mindustry.world.blocks.units.CommandCenter$CommandCenterEntity", "mindustry.world.blocks.units.MechPad", "mindustry.world.blocks.units.MechPad$MechFactoryEntity", "mindustry.world.blocks.units.RallyPoint", "mindustry.world.blocks.units.RepairPoint", "mindustry.world.blocks.units.RepairPoint$RepairPointEntity", "mindustry.world.blocks.units.UnitFactory", "mindustry.world.blocks.units.UnitFactory$UnitFactoryEntity", "mindustry.world.consumers.Consume", "mindustry.world.consumers.ConsumeItemFilter", "mindustry.world.consumers.ConsumeItems", "mindustry.world.consumers.ConsumeLiquid", "mindustry.world.consumers.ConsumeLiquidBase", "mindustry.world.consumers.ConsumeLiquidFilter", "mindustry.world.consumers.ConsumePower", "mindustry.world.consumers.ConsumeType", "mindustry.world.consumers.Consumers", "mindustry.world.meta.Attribute", "mindustry.world.meta.BlockBars", "mindustry.world.meta.BlockFlag", "mindustry.world.meta.BlockGroup", "mindustry.world.meta.BlockStat", "mindustry.world.meta.BlockStats", "mindustry.world.meta.BuildVisibility", "mindustry.world.meta.PowerType", "mindustry.world.meta.Producers", "mindustry.world.meta.StatCategory", "mindustry.world.meta.StatUnit", "mindustry.world.meta.StatValue", "mindustry.world.meta.values.AmmoListValue", "mindustry.world.meta.values.BooleanValue", "mindustry.world.meta.values.BoosterListValue", "mindustry.world.meta.values.ItemFilterValue", "mindustry.world.meta.values.ItemListValue", "mindustry.world.meta.values.LiquidFilterValue", "mindustry.world.meta.values.LiquidValue", "mindustry.world.meta.values.NumberValue", "mindustry.world.meta.values.StringValue", "mindustry.world.modules.BlockModule", "mindustry.world.modules.ConsumeModule", "mindustry.world.modules.ItemModule", "mindustry.world.modules.ItemModule$ItemCalculator", "mindustry.world.modules.ItemModule$ItemConsumer", "mindustry.world.modules.LiquidModule", "mindustry.world.modules.LiquidModule$LiquidCalculator", "mindustry.world.modules.LiquidModule$LiquidConsumer", "mindustry.world.modules.PowerModule", "mindustry.world.producers.Produce", "mindustry.world.producers.ProduceItem"); } \ No newline at end of file diff --git a/tools/src/mindustry/tools/ScriptStubGenerator.java b/tools/src/mindustry/tools/ScriptStubGenerator.java index d13bbbdd49..c60b6589fa 100644 --- a/tools/src/mindustry/tools/ScriptStubGenerator.java +++ b/tools/src/mindustry/tools/ScriptStubGenerator.java @@ -26,7 +26,7 @@ public class ScriptStubGenerator{ Array nameBlacklist = Array.with("ClientLauncher", "NetClient", "NetServer", "ClassAccess"); Array> whitelist = Array.with(Draw.class, Fill.class, Lines.class, Core.class, TextureAtlas.class, TextureRegion.class, Time.class, System.class, PrintStream.class, AtlasRegion.class, String.class, Mathf.class, Angles.class, Color.class, Runnable.class, Object.class, Icon.class, Tex.class, - Sounds.class, Musics.class, Call.class, Texture.class, TextureData.class, Pixmap.class, I18NBundle.class); + Sounds.class, Musics.class, Call.class, Texture.class, TextureData.class, Pixmap.class, I18NBundle.class, Interval.class, DataInput.class, DataOutput.class, DataInputStream.class, DataOutputStream.class); Array nopackage = Array.with("java.lang", "java"); String fileTemplate = "package mindustry.mod;\n" + @@ -49,6 +49,7 @@ public class ScriptStubGenerator{ .include(FilterBuilder.prefix("arc.func")) .include(FilterBuilder.prefix("arc.struct")) .include(FilterBuilder.prefix("arc.scene")) + .include(FilterBuilder.prefix("arc.math")) )); Array> classes = Array.with(reflections.getSubTypesOf(Object.class));