From 34c4aa07de846fb8d3d652f4272ccacfe8cd3778 Mon Sep 17 00:00:00 2001 From: buthed010203 Date: Tue, 21 Dec 2021 12:09:51 -0500 Subject: [PATCH 01/16] Fix assertion message (#6448) It previously said `exotic-mod must be loaded. ==> expected: but was: ` when it failed which makes absolutely no sense. --- tests/src/test/java/GenericModTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/src/test/java/GenericModTest.java b/tests/src/test/java/GenericModTest.java index 10b75c1d24..f65aa881e8 100644 --- a/tests/src/test/java/GenericModTest.java +++ b/tests/src/test/java/GenericModTest.java @@ -27,6 +27,6 @@ public class GenericModTest{ static void checkExistence(String modName){ assertNotEquals(Vars.mods, null); assertNotEquals(Vars.mods.list().size, 0, "At least one mod must be loaded."); - assertEquals(Vars.mods.list().first().name, modName, modName + " must be loaded."); + assertEquals(modName, Vars.mods.list().first().name, modName + " must be loaded."); } } From 0036efba0c4f51f29828b3e2b4d141388f0880ff Mon Sep 17 00:00:00 2001 From: buthed010203 Date: Wed, 22 Dec 2021 14:23:24 -0500 Subject: [PATCH 02/16] Properly update map name and gamemode on steam (#6449) * Properly update map name and gamemode on steam This has been bugging me for the longest time but I've been too lazy to fix it, I finally got around to doing so. * fix --- desktop/src/mindustry/desktop/steam/SNet.java | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/desktop/src/mindustry/desktop/steam/SNet.java b/desktop/src/mindustry/desktop/steam/SNet.java index d4b8236afa..0b38dcf23d 100644 --- a/desktop/src/mindustry/desktop/steam/SNet.java +++ b/desktop/src/mindustry/desktop/steam/SNet.java @@ -105,11 +105,8 @@ public class SNet implements SteamNetworkingCallback, SteamMatchmakingCallback, } })); - Events.on(WaveEvent.class, e -> { - if(currentLobby != null && net.server()){ - smat.setLobbyData(currentLobby, "wave", state.wave + ""); - } - }); + Events.on(WaveEvent.class, e -> updateWave()); + Events.run(Trigger.newGame, this::updateWave); } public boolean isSteamClient(){ @@ -201,6 +198,14 @@ public class SNet implements SteamNetworkingCallback, SteamMatchmakingCallback, smat.setLobbyMemberLimit(currentLobby, Core.settings.getInt("playerlimit")); } } + + void updateWave(){ + if(currentLobby != null && net.server()){ + smat.setLobbyData(currentLobby, "mapname", state.map.name()); + smat.setLobbyData(currentLobby, "wave", state.wave + ""); + smat.setLobbyData(currentLobby, "gamemode", state.rules.mode().name() + ""); + } + } @Override public void closeServer(){ From 84d87e7e9f9ac8cb9d799b02bda66a2b163b4f82 Mon Sep 17 00:00:00 2001 From: Phinner <62483793+Phinner@users.noreply.github.com> Date: Fri, 24 Dec 2021 05:30:46 +0100 Subject: [PATCH 03/16] Allow Custom input handling in servers (#6452) * enable input redirection * oops --- .../src/mindustry/server/ServerControl.java | 30 ++++++++++--------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/server/src/mindustry/server/ServerControl.java b/server/src/mindustry/server/ServerControl.java index 2a4026d792..7acb41547c 100644 --- a/server/src/mindustry/server/ServerControl.java +++ b/server/src/mindustry/server/ServerControl.java @@ -45,6 +45,14 @@ public class ServerControl implements ApplicationListener{ public final CommandHandler handler = new CommandHandler(""); public final Fi logFolder = Core.settings.getDataDirectory().child("logs/"); + public Runnable serverInput = () -> { + Scanner scan = new Scanner(System.in); + while(scan.hasNext()){ + String line = scan.nextLine(); + Core.app.post(() -> handleCommandString(line)); + } + }; + private Fi currentLogFile; private boolean inExtraRound; private Task lastTask; @@ -147,10 +155,6 @@ public class ServerControl implements ApplicationListener{ customMapDirectory.mkdirs(); - Thread thread = new Thread(this::readCommands, "Server Controls"); - thread.setDaemon(true); - thread.start(); - if(Version.build == -1){ warn("&lyYour server is running a custom build, which means that client checking is disabled."); warn("&lyIt is highly advised to specify which version you're using by building with gradle args &lb&fb-Pbuildversion=&lr"); @@ -258,7 +262,13 @@ public class ServerControl implements ApplicationListener{ toggleSocket(Config.socketInput.bool()); - info("Server loaded. Type @ for help.", "'help'"); + Events.on(ServerLoadEvent.class, e -> { + Thread thread = new Thread(serverInput, "Server Controls"); + thread.setDaemon(true); + thread.start(); + + info("Server loaded. Type @ for help.", "'help'"); + }); } protected void registerCommands(){ @@ -963,15 +973,7 @@ public class ServerControl implements ApplicationListener{ mods.eachClass(p -> p.registerServerCommands(handler)); } - private void readCommands(){ - Scanner scan = new Scanner(System.in); - while(scan.hasNext()){ - String line = scan.nextLine(); - Core.app.post(() -> handleCommandString(line)); - } - } - - private void handleCommandString(String line){ + public void handleCommandString(String line){ CommandResponse response = handler.handleMessage(line); if(response.type == ResponseType.unknownCommand){ From 692718d4eaeeff91a9dfb8b09af9e5e53f495e93 Mon Sep 17 00:00:00 2001 From: buthed010203 Date: Tue, 28 Dec 2021 23:22:01 -0500 Subject: [PATCH 04/16] Fix strange behavior of MinerAI (#6454) * Fix strange behavior of MinerAI See: https://discord.com/channels/391020510269669376/396416151032299521/925110542216073216 > Anuke, is the current behavior of miner ai where it wont mine anything if the item that the core has the fewest of has all of its ores covered? The only place the hasOre code is used is miner ai so i assume thats a bug? * Update BlockIndexer.java --- core/src/mindustry/ai/BlockIndexer.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/core/src/mindustry/ai/BlockIndexer.java b/core/src/mindustry/ai/BlockIndexer.java index b5a0ef202c..535462e200 100644 --- a/core/src/mindustry/ai/BlockIndexer.java +++ b/core/src/mindustry/ai/BlockIndexer.java @@ -33,7 +33,7 @@ public class BlockIndexer{ /** Stores all damaged tile entities by team. */ private Seq[] damagedTiles = new Seq[Team.all.length]; /** All ores available on this map. */ - private ObjectSet allOres = new ObjectSet<>(); + private ObjectIntMap allOres = new ObjectIntMap<>(); /** Stores teams that are present here as tiles. */ private Seq activeTeams = new Seq<>(Team.class); /** Maps teams to a map of flagged tiles by flag. */ @@ -78,8 +78,6 @@ public class BlockIndexer{ var drop = tile.drop(); if(drop != null){ - allOres.add(drop); - int qx = (tile.x / quadrantSize); int qy = (tile.y / quadrantSize); @@ -92,6 +90,7 @@ public class BlockIndexer{ ores[drop.id][qx][qy] = new IntSeq(false, 16); } ores[drop.id][qx][qy].add(tile.pos()); + allOres.increment(drop); } } } @@ -150,9 +149,11 @@ public class BlockIndexer{ //when the drop can be mined, record the ore position if(tile.block() == Blocks.air && !seq.contains(pos)){ seq.add(pos); + allOres.increment(drop); }else{ //otherwise, it likely became blocked, remove it (even if it wasn't there) seq.removeValue(pos); + allOres.increment(drop, -1); } } @@ -177,7 +178,7 @@ public class BlockIndexer{ /** @return whether this item is present on this map. */ public boolean hasOre(Item item){ - return allOres.contains(item); + return allOres.get(item) > 0; } /** Returns all damaged tiles by team. */ From 2da4408dd13d344d80b80950ffc430cd1a32ffbd Mon Sep 17 00:00:00 2001 From: Nile <80833369+nilederg@users.noreply.github.com> Date: Wed, 29 Dec 2021 06:30:27 -0800 Subject: [PATCH 05/16] Added Infection (#6455) fun gamemode --- servers_v6.json | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/servers_v6.json b/servers_v6.json index 14f1771ee6..64626df553 100644 --- a/servers_v6.json +++ b/servers_v6.json @@ -1,4 +1,8 @@ [ + { + "name": "Infection", + "address": ["plague-continued.ml"] + }, { "name": "RCM", "address": ["185.104.248.61", "easyplay.su"] From ec00f59b824bcccd93ad7ee3f83171ecd9eb5259 Mon Sep 17 00:00:00 2001 From: RebornTrack970 <62565267+RebornTrack970@users.noreply.github.com> Date: Thu, 30 Dec 2021 17:36:55 +0300 Subject: [PATCH 06/16] Infection port change (#6457) --- servers_v6.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/servers_v6.json b/servers_v6.json index 64626df553..f2cbaaecd6 100644 --- a/servers_v6.json +++ b/servers_v6.json @@ -1,7 +1,7 @@ [ { "name": "Infection", - "address": ["plague-continued.ml"] + "address": ["plague-continued.ml:5555"] }, { "name": "RCM", From 3701ac131e38da083cb3105298096abc0026aff2 Mon Sep 17 00:00:00 2001 From: TranquillyUnpleasant <62061444+TranquillyUnpleasant@users.noreply.github.com> Date: Sun, 2 Jan 2022 06:22:19 +0100 Subject: [PATCH 07/16] More info (#6465) * change wave timer to display serverside when waves exist * show total and enemy units, not just enemy units * format --- server/src/mindustry/server/ServerControl.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/server/src/mindustry/server/ServerControl.java b/server/src/mindustry/server/ServerControl.java index 7acb41547c..e54abd1e92 100644 --- a/server/src/mindustry/server/ServerControl.java +++ b/server/src/mindustry/server/ServerControl.java @@ -407,10 +407,9 @@ public class ServerControl implements ApplicationListener{ info(" Playing on map &fi@ / Wave @", Strings.capitalize(Strings.stripColors(state.map.name())), state.wave); if(state.rules.waves){ - info(" @ enemies.", state.enemies); - }else{ info(" @ seconds until next wave.", (int)(state.wavetime / 60)); } + info(" @ units / @ enemies", Groups.unit.size(), state.enemies); info(" @ FPS, @ MB used.", Core.graphics.getFramesPerSecond(), Core.app.getJavaHeap() / 1024 / 1024); @@ -466,7 +465,6 @@ public class ServerControl implements ApplicationListener{ info("&fi&lcServer: &fr@", "&lw" + arg[0]); }); - handler.register("pause", "", "Pause or unpause the game.", arg -> { boolean pause = arg[0].equals("on"); state.serverPaused = pause; From 16d7a368c672633d3897a67abfd371b99ebc61a4 Mon Sep 17 00:00:00 2001 From: Nile <80833369+nilederg@users.noreply.github.com> Date: Thu, 6 Jan 2022 15:59:41 -0800 Subject: [PATCH 08/16] added crawler hell (#6469) --- servers_v6.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/servers_v6.json b/servers_v6.json index f2cbaaecd6..3691d9a47f 100644 --- a/servers_v6.json +++ b/servers_v6.json @@ -1,7 +1,7 @@ [ { "name": "Infection", - "address": ["plague-continued.ml:5555"] + "address": ["plague-continued.ml:5555", "plague-continued.ml:5004"] }, { "name": "RCM", From f8af5931770827cb344062e589895e5c27faaf34 Mon Sep 17 00:00:00 2001 From: Valeriy Date: Sun, 9 Jan 2022 02:47:29 +1000 Subject: [PATCH 09/16] SMoA will come back (#6475) Domen isnt active yet --- servers_v7.json | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/servers_v7.json b/servers_v7.json index befb1d1637..7d7f12a4f4 100644 --- a/servers_v7.json +++ b/servers_v7.json @@ -7,6 +7,10 @@ "name": "C.A.M.S.", "address": ["baseduser.eu.org:6569", "v7.thedimas.pp.ua", "yeeth.mindustry.me:7000", "yeeth.mindustry.me:4000", "yeeth.mindustry.me:2000", "yeeth.mindustry.me:3000"] }, + { + "name": "SMokeOfAnarchy", + "address": "SMokeOfAnarchy.duckdns.org" + }, { "name": "hexpvp.ml", "address": "hexpvp.ml" From 9825d2f7465ba349f27400f0b22ba387fe228b83 Mon Sep 17 00:00:00 2001 From: "Matthew (or Maya) Peng" <54301439+MEEPofFaith@users.noreply.github.com> Date: Sat, 8 Jan 2022 18:34:12 -0800 Subject: [PATCH 10/16] Incorrect reset (#6477) --- core/src/mindustry/world/blocks/defense/turrets/Turret.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/mindustry/world/blocks/defense/turrets/Turret.java b/core/src/mindustry/world/blocks/defense/turrets/Turret.java index 2970fa1d45..c5b7c1b903 100644 --- a/core/src/mindustry/world/blocks/defense/turrets/Turret.java +++ b/core/src/mindustry/world/blocks/defense/turrets/Turret.java @@ -269,7 +269,7 @@ public class Turret extends ReloadTurret{ } if(hasAmmo()){ - if(Float.isNaN(reload)) rotation = 0; + if(Float.isNaN(reload)) reload = 0; if(timer(timerTarget, targetInterval)){ findTarget(); From 030d66fb73b1ec90152e935d31826828b0b6a99a Mon Sep 17 00:00:00 2001 From: KotMilkMeoW <81019712+KotMilkMeoW@users.noreply.github.com> Date: Sun, 9 Jan 2022 18:06:35 +0300 Subject: [PATCH 11/16] MeowLand cumeback (#6478) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 👀 --- servers_v7.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/servers_v7.json b/servers_v7.json index 7d7f12a4f4..129e1bba51 100644 --- a/servers_v7.json +++ b/servers_v7.json @@ -21,7 +21,7 @@ }, { "name": "MeowLand", - "address": ["34.134.111.15", "fifr4.quackhost.uk:21013", "34.134.111.15:4000", "34.134.111.15:7000"] + "address": ["kgstudios.ddns.net:6565"] }, { "name": "DarkDustry", From 12a87970195ee64c7d95383b34afb0672ecffad9 Mon Sep 17 00:00:00 2001 From: Yuri Polyakov <86189625+Kowkodivka@users.noreply.github.com> Date: Sun, 9 Jan 2022 23:37:48 +0700 Subject: [PATCH 12/16] Add server to global (#6479) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add server to global * Ня --- servers_v7.json | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/servers_v7.json b/servers_v7.json index 129e1bba51..fc52112fe9 100644 --- a/servers_v7.json +++ b/servers_v7.json @@ -78,5 +78,9 @@ { "name": "ALEX", "address": ["dogemindustry.ddns.net:25588"] + }, + { + "name": "Beyond Anarchy", + "address": ["45.156.25.49"] } ] From 4eab4ab569f900557ebb7bda4595567bb816509b Mon Sep 17 00:00:00 2001 From: OSP <76648940+osp54@users.noreply.github.com> Date: Mon, 10 Jan 2022 00:00:46 +0200 Subject: [PATCH 13/16] [XCore] update ip (#6481) --- servers_v7.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/servers_v7.json b/servers_v7.json index fc52112fe9..3f100dfe94 100644 --- a/servers_v7.json +++ b/servers_v7.json @@ -33,7 +33,7 @@ }, { "name": "XCore", - "address": ["skaarjproject.duckdns.org:2000"] + "address": ["node.procord.ga:2707"] }, { "name": "Obvilion Network", From 02db63aa917b97de4764b6cbb3a39e55ab522362 Mon Sep 17 00:00:00 2001 From: Volas171 <60143910+Volas171@users.noreply.github.com> Date: Mon, 10 Jan 2022 18:13:07 -0500 Subject: [PATCH 14/16] update omega ips (#6482) --- servers_v7.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/servers_v7.json b/servers_v7.json index 3f100dfe94..fa681a4cf9 100644 --- a/servers_v7.json +++ b/servers_v7.json @@ -17,7 +17,7 @@ }, { "name": "Omega", - "address": ["yeeth.mindustry.me:5002", "yeeth.mindustry.me:5003", "yeeth.mindustry.me:5004","yeeth.mindustry.me:5005", "yeeth.mindustry.me:5006", "yeeth.mindustry.me:5007", "yeeth.mindustry.me", "yeeth.mindustry.me:4006"] + "address": ["n3.mindustry.me:5002", "n3.mindustry.me:5003", "n3.mindustry.me:5004","n3.mindustry.me:5005", "n3.mindustry.me:5006", "n3.mindustry.me:5007", "n3.mindustry.me", "n3.mindustry.me:4006"] }, { "name": "MeowLand", From 1d14fa78bf9ebc1f33d895cebd870795599c1728 Mon Sep 17 00:00:00 2001 From: "Matthew (or Maya) Peng" <54301439+MEEPofFaith@users.noreply.github.com> Date: Mon, 10 Jan 2022 20:38:28 -0800 Subject: [PATCH 15/16] Make ItemEntry's item public (#6474) --- core/src/mindustry/world/blocks/defense/turrets/ItemTurret.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/mindustry/world/blocks/defense/turrets/ItemTurret.java b/core/src/mindustry/world/blocks/defense/turrets/ItemTurret.java index 8e1a2c0ad5..1690b76b80 100644 --- a/core/src/mindustry/world/blocks/defense/turrets/ItemTurret.java +++ b/core/src/mindustry/world/blocks/defense/turrets/ItemTurret.java @@ -196,7 +196,7 @@ public class ItemTurret extends Turret{ } public class ItemEntry extends AmmoEntry{ - protected Item item; + public Item item; ItemEntry(Item item, int amount){ this.item = item; From cd88400154ac20a6b774e6ce36e7bbb78f0c9084 Mon Sep 17 00:00:00 2001 From: Phinner <62483793+Phinner@users.noreply.github.com> Date: Tue, 11 Jan 2022 05:43:11 +0100 Subject: [PATCH 16/16] Better Mod/Plugin dependencies handling (#6328) * Dependencies goes brrrr * mmh, maybe voiding exception in findMeta ? * Let Anuke code handle everything I trust the Cat :^) * My god, I sleep too much... * Forgot that one... --- core/src/mindustry/mod/Mods.java | 101 +++++++++++++++++++++++++++---- 1 file changed, 89 insertions(+), 12 deletions(-) diff --git a/core/src/mindustry/mod/Mods.java b/core/src/mindustry/mod/Mods.java index bd95c20504..538a3450d5 100644 --- a/core/src/mindustry/mod/Mods.java +++ b/core/src/mindustry/mod/Mods.java @@ -355,10 +355,13 @@ public class Mods implements Loadable{ /** Loads all mods from the folder, but does not call any methods on them.*/ public void load(){ - for(Fi file : modDirectory.list()){ - if(!file.extension().equals("jar") && !file.extension().equals("zip") && !(file.isDirectory() && (file.child("mod.json").exists() || file.child("mod.hjson").exists()))) continue; + var files = resolveDependencies(Seq.with(modDirectory.list()).filter(f -> + f.extension().equals("jar") || f.extension().equals("zip") || (f.isDirectory() && (f.child("mod.json").exists() || f.child("mod.hjson").exists())) + )); + for(Fi file : files){ Log.debug("[Mods] Loading mod @", file); + try{ LoadedMod mod = loadMod(file); mods.add(mod); @@ -373,7 +376,7 @@ public class Mods implements Loadable{ } //load workshop mods now - for(Fi file : platform.getWorkshopContent(LoadedMod.class)){ + for(Fi file : resolveDependencies(platform.getWorkshopContent(LoadedMod.class))){ try{ LoadedMod mod = loadMod(file); mods.add(mod); @@ -708,6 +711,86 @@ public class Mods implements Loadable{ } } + /** Tries to find the config file of a mod/plugin. */ + @Nullable + public ModMeta findMeta(Fi file){ + Fi metaFile = + file.child("mod.json").exists() ? file.child("mod.json") : + file.child("mod.hjson").exists() ? file.child("mod.hjson") : + file.child("plugin.json").exists() ? file.child("plugin.json") : + file.child("plugin.hjson"); + + if(!metaFile.exists()){ + return null; + } + + ModMeta meta = json.fromJson(ModMeta.class, Jval.read(metaFile.readString()).toString(Jformat.plain)); + meta.cleanup(); + return meta; + } + + /** Resolves the loading order of a list mods/plugins using their internal names. + * It also skips non-mods files or folders. */ + public Seq resolveDependencies(Seq files){ + ObjectMap fileMapping = new ObjectMap<>(); + ObjectMap> dependencies = new ObjectMap<>(); + + for(Fi file : files){ + Fi zip = file.isDirectory() ? file : new ZipFi(file); + + if(zip.list().length == 1 && zip.list()[0].isDirectory()){ + zip = zip.list()[0]; + } + + ModMeta meta = null; + try{ + meta = findMeta(zip); + }catch(Exception ignored){ + } + + if(meta == null) continue; + dependencies.put(meta.name, meta.dependencies); + fileMapping.put(meta.name, file); + } + + ObjectSet visited = new ObjectSet<>(); + OrderedSet ordered = new OrderedSet<>(); + + for(String modName : dependencies.keys()){ + if(!ordered.contains(modName)){ + // Adds the loaded mods at the beginning of the list + ordered.add(modName, 0); + resolveDependencies(modName, dependencies, ordered, visited); + visited.clear(); + } + } + + // Adds the invalid mods + for(String missingMod : dependencies.keys()){ + if(!ordered.contains(missingMod)) ordered.add(missingMod, 0); + } + + Seq resolved = ordered.orderedItems().map(fileMapping::get); + // Since the resolver explores the dependencies from leaves to the root, reverse the seq + resolved.reverse(); + return resolved; + } + + /** Recursive search of dependencies */ + public void resolveDependencies(String modName, ObjectMap> dependencies, OrderedSet ordered, ObjectSet visited){ + visited.add(modName); + + for(String dependency : dependencies.get(modName)){ + // Checks if the dependency tree isn't circular and that the dependency is not missing + if(!visited.contains(dependency) && dependencies.containsKey(dependency)){ + // Skips if the dependency was already explored in a separate tree + if(ordered.contains(dependency)) continue; + ordered.add(dependency); + resolveDependencies(dependency, dependencies, ordered, visited); + } + } + } + /** Loads a mod file+meta, but does not add it to the list. * Note that directories can be loaded as mods. */ private LoadedMod loadMod(Fi sourceFile) throws Exception{ @@ -727,19 +810,13 @@ public class Mods implements Loadable{ zip = zip.list()[0]; } - Fi metaf = - zip.child("mod.json").exists() ? zip.child("mod.json") : - zip.child("mod.hjson").exists() ? zip.child("mod.hjson") : - zip.child("plugin.json").exists() ? zip.child("plugin.json") : - zip.child("plugin.hjson"); + ModMeta meta = findMeta(zip); - if(!metaf.exists()){ - Log.warn("Mod @ doesn't have a '[mod/plugin].[h]json' file, skipping.", sourceFile); + if(meta == null){ + Log.warn("Mod @ doesn't have a '[mod/plugin].[h]json' file, skipping.", zip); throw new ModLoadException("Invalid file: No mod.json found."); } - ModMeta meta = json.fromJson(ModMeta.class, Jval.read(metaf.readString()).toString(Jformat.plain)); - meta.cleanup(); String camelized = meta.name.replace(" ", ""); String mainClass = meta.main == null ? camelized.toLowerCase(Locale.ROOT) + "." + camelized + "Mod" : meta.main; String baseName = meta.name.toLowerCase(Locale.ROOT).replace(" ", "-");