From ca90af5f5691dd1113a9a2ab7edd4409ec1c41ee Mon Sep 17 00:00:00 2001 From: Anuken Date: Wed, 16 Sep 2026 12:42:44 -0400 Subject: [PATCH 01/25] Updated steamworks --- build.gradle | 2 +- core/src/mindustry/ui/fragments/PlayerListFragment.java | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/build.gradle b/build.gradle index 7ccf160d83..c6c7c3ecfd 100644 --- a/build.gradle +++ b/build.gradle @@ -42,7 +42,7 @@ allprojects{ if(!project.hasProperty("versionModifier")) versionModifier = 'release' if(!project.hasProperty("versionType")) versionType = 'official' appName = 'Mindustry' - steamworksVersion = 'da41c05b7a2a44c8625ca0ba7d6ca1a2e73f621a' + steamworksVersion = '185e76cfe630a6f0e1dd7b9bf57be41f6064a1f2' rhinoVersion = '32395f942976a6d1d21ec9877664554cd5762306' loadVersionProps = { diff --git a/core/src/mindustry/ui/fragments/PlayerListFragment.java b/core/src/mindustry/ui/fragments/PlayerListFragment.java index 65dbc91870..ce97fad416 100644 --- a/core/src/mindustry/ui/fragments/PlayerListFragment.java +++ b/core/src/mindustry/ui/fragments/PlayerListFragment.java @@ -235,8 +235,6 @@ public class PlayerListFragment{ dialog.cont.button("@back", Icon.left, dialog::hide).padTop(-1f).size(220f, 55f); dialog.show(); - - }).size(h); } }else if(!user.isLocal() && !user.admin && net.client() && Groups.player.size() >= 3 && player.team() == user.team()){ //votekick From acf891e41914656514e905f96088d51e61aca14d Mon Sep 17 00:00:00 2001 From: Anuken Date: Wed, 16 Sep 2026 15:40:41 -0400 Subject: [PATCH 02/25] Mod matching release WIP --- .../mindustry/annotations/BaseProcessor.java | 5 +- core/src/mindustry/mod/ModListing.java | 24 +++++++++ core/src/mindustry/ui/dialogs/ModsDialog.java | 51 +++++++++++++++++++ 3 files changed, 76 insertions(+), 4 deletions(-) diff --git a/annotations/src/main/java/mindustry/annotations/BaseProcessor.java b/annotations/src/main/java/mindustry/annotations/BaseProcessor.java index 05f9aae5f6..d9a4ac5998 100644 --- a/annotations/src/main/java/mindustry/annotations/BaseProcessor.java +++ b/annotations/src/main/java/mindustry/annotations/BaseProcessor.java @@ -211,10 +211,7 @@ public abstract class BaseProcessor extends AbstractProcessor{ if(round++ >= rounds) return false; //only process 1 round if(rootDirectory == null){ try{ - String path = Fi.get(filer.getResource(StandardLocation.CLASS_OUTPUT, "no", "no") - .toUri().toURL().toString().substring(OS.isWindows ? 6 : "file:".length())) - .parent().parent().parent().parent().parent().parent().parent().toString().replace("%20", " "); - rootDirectory = Fi.get(path).parent(); + rootDirectory = new Fi(new File(filer.getResource(StandardLocation.CLASS_OUTPUT, "no", "no").toUri())).parent().parent().parent().parent().parent().parent().parent().parent(); }catch(IOException e){ throw new RuntimeException(e); } diff --git a/core/src/mindustry/mod/ModListing.java b/core/src/mindustry/mod/ModListing.java index 68d26ce95f..8c16c84f01 100644 --- a/core/src/mindustry/mod/ModListing.java +++ b/core/src/mindustry/mod/ModListing.java @@ -1,9 +1,15 @@ package mindustry.mod; +import arc.struct.*; +import arc.util.*; +import mindustry.ui.dialogs.*; + /** Mod listing as a data class. */ public class ModListing{ public String repo, name, internalName, author, lastUpdated, description, minGameVersion, version, iconHash = ""; public boolean hasScripts, hasJava, iosCompatible, legacyCompatible, hasIcon; + /** game build -> release ID + mod version */ + public @Nullable ArrayMap releases; public String[] contentTypes = {}; public int stars; @@ -22,4 +28,22 @@ public class ModListing{ ", stars=" + stars + '}'; } + + public @Nullable ModRelease getMatchingRelease(){ + if(releases == null) return null; + for(int i = 0; i < releases.size; i ++){ + String key = releases.keys[i]; + if(ModsDialog.matchesGameVersion(ModsDialog.parseVersion(key))){ + return releases.values[i]; + } + } + return null; + } + + public static class ModRelease{ + /** Github release ID */ + public String id = ""; + /** Actual mod version string in release's mod.json */ + public String version = ""; + } } diff --git a/core/src/mindustry/ui/dialogs/ModsDialog.java b/core/src/mindustry/ui/dialogs/ModsDialog.java index 9446c191de..37af75cadc 100644 --- a/core/src/mindustry/ui/dialogs/ModsDialog.java +++ b/core/src/mindustry/ui/dialogs/ModsDialog.java @@ -17,6 +17,7 @@ import arc.util.Http.*; import arc.util.io.*; import arc.util.serialization.*; import arc.util.serialization.Jval.*; +import mindustry.core.*; import mindustry.ctype.*; import mindustry.game.EventType.*; import mindustry.gen.*; @@ -26,10 +27,13 @@ import mindustry.mod.Mods.*; import mindustry.ui.*; import java.util.*; +import java.util.regex.*; import static mindustry.Vars.*; public class ModsDialog extends BaseDialog{ + private static final Pattern modVersionPattern = Pattern.compile("\\[[vb](\\d+)(?:\\.(\\d+))?\\]"); + public ModBrowserDialog browser; protected float modImportProgress; @@ -686,4 +690,51 @@ public class ModsDialog extends BaseDialog{ }, this::importFail); } } + + /** @return {major, minor} parsed from a leading/trailing "[v{major}]" or "[v{major}.{minor}]" tag, or null if none is found at either end (or the numbers are unparseable). */ + public static @Nullable int[] parseVersionTag(String str){ + if(str == null) return null; + + Matcher m = modVersionPattern.matcher(str); + while(m.find()){ + if(m.start() == 0 || m.end() == str.length()){ + int major = Strings.parseInt(m.group(1)); + if(major == Integer.MIN_VALUE) return null; + int minor = m.group(2) != null ? Strings.parseInt(m.group(2)) : 0; + if(minor == Integer.MIN_VALUE) return null; + return new int[]{major, minor}; + } + } + return null; + } + + public static @Nullable int[] parseVersion(String str){ + if(str == null || str.isEmpty()) return null; + + int dot = str.indexOf('.'); + String majorStr = dot == -1 ? str : str.substring(0, dot); + String minorStr = dot == -1 ? null : str.substring(dot + 1); + + if(majorStr.isEmpty() || (dot != -1 && (minorStr.isEmpty() || str.indexOf('.', dot + 1) != -1))) return null; + + int major = Strings.parseInt(majorStr); + if(major == Integer.MIN_VALUE) return null; + int minor = minorStr != null ? Strings.parseInt(minorStr) : 0; + if(minor == Integer.MIN_VALUE) return null; + + return new int[]{major, minor}; + } + + /** @return whether the specified release name and its tags match the current game build (e.g. "Bingus Mod [v160]" should only match build 160) */ + public static boolean matchesGameVersion(String releaseTitle){ + return matchesGameVersion(parseVersionTag(releaseTitle)); + } + + public static boolean matchesGameVersion(@Nullable int[] tag){ + //version not specified, matches anything. + if(tag == null) return true; + //must match exactly; custom builds (-1) do not match. + //for revisions, either match if the revision is unspecified (v160 -> matches ALL 160.x builds), OR, if it is specified, match the exact version (the mod author must have had a good reason for it) + return Version.build == tag[0] && (tag[1] == 0 || Version.revision == tag[1]); + } } From 088486c1adf65f34067f170145526048b7d7707c Mon Sep 17 00:00:00 2001 From: Anuken Date: Thu, 17 Sep 2026 10:51:38 -0400 Subject: [PATCH 03/25] Fixed #12673 --- core/src/mindustry/entities/comp/TargetDummyComp.java | 1 + core/src/mindustry/mod/DataPatcher.java | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/core/src/mindustry/entities/comp/TargetDummyComp.java b/core/src/mindustry/entities/comp/TargetDummyComp.java index 5167680d41..37748972d2 100644 --- a/core/src/mindustry/entities/comp/TargetDummyComp.java +++ b/core/src/mindustry/entities/comp/TargetDummyComp.java @@ -16,6 +16,7 @@ abstract class TargetDummyComp implements Unitc, Healthc{ } } + @Replace @Override public void rawDamage(float amount){ if(building instanceof TargetDummyBuild td){ diff --git a/core/src/mindustry/mod/DataPatcher.java b/core/src/mindustry/mod/DataPatcher.java index 9b5a5e0041..de6277bf90 100644 --- a/core/src/mindustry/mod/DataPatcher.java +++ b/core/src/mindustry/mod/DataPatcher.java @@ -195,8 +195,8 @@ public class DataPatcher{ //register global variables for(var cont : all){ - if(!cont.hasErrored() && cont instanceof UnlockableContent u && Vars.logicVars.get("@" + u.name) == null){ - addedVars.add(Vars.logicVars.put("@" + u.name, u, false)); + if(!cont.hasErrored() && cont instanceof UnlockableContent u && Vars.logicVars.get("@" + (u instanceof StatusEffect ? "status-" : "") + u.name) == null){ + addedVars.add(Vars.logicVars.put("@" + (u instanceof StatusEffect ? "status-" : "") + u.name, u, false)); } } From bfa31bf184cb86473ec2d88b9b518f811b5ac4aa Mon Sep 17 00:00:00 2001 From: EggleEgg <125359838+EggleEgg@users.noreply.github.com> Date: Thu, 17 Sep 2026 16:51:59 +0200 Subject: [PATCH 04/25] Bugfix: attributecrafter yield string format (#12675) * Bugfix: attributecrafter yield string format * imports --- core/assets/bundles/bundle.properties | 2 +- .../blocks/production/AttributeCrafter.java | 18 ++++++++++-------- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/core/assets/bundles/bundle.properties b/core/assets/bundles/bundle.properties index 30086d23d9..c7adeb08aa 100644 --- a/core/assets/bundles/bundle.properties +++ b/core/assets/bundles/bundle.properties @@ -1304,7 +1304,7 @@ bar.cargounitcap = Cargo Unit Cap Reached bar.drillspeed = Drill Speed: {0}/s bar.pumpspeed = Pump Speed: {0}/s bar.efficiency = Efficiency: {0}% -bar.yield = Yield: +{0}% +bar.yield = Yield: {0}% bar.boost = Boost: +{0}% bar.powerbuffer = Batteries: {0}/{1} bar.powerbalance = Power: {0}/s diff --git a/core/src/mindustry/world/blocks/production/AttributeCrafter.java b/core/src/mindustry/world/blocks/production/AttributeCrafter.java index 1054174ad8..448e00bada 100644 --- a/core/src/mindustry/world/blocks/production/AttributeCrafter.java +++ b/core/src/mindustry/world/blocks/production/AttributeCrafter.java @@ -11,11 +11,15 @@ import mindustry.world.meta.*; /** A crafter that gains efficiency from attribute tiles. */ public class AttributeCrafter extends GenericCrafter{ public Attribute attribute = Attribute.heat; + /** Base efficiency of the crafter. */ public float baseEfficiency = 1f; + /** Maximum efficiency/output boost from attributes. */ public float maxBoost = 1f; + /** Minimum efficiency required to place this block. */ public float minEfficiency = -1f; - public boolean displayEfficiency = true; - public boolean displayScaledOutput = true; + /** Whether to show this bar in the UI. */ + public boolean displayEfficiency = true, displayScaledOutput = true; + /** Whether liquid consumption scales with efficiency. */ public boolean scaleLiquidConsumption = false; /** Scaled output (yield) multiplier, scales with attribute. <=0 to disable. */ public float outputScale = 0f; @@ -34,12 +38,10 @@ public class AttributeCrafter extends GenericCrafter{ drawPlaceText( (displayEfficiency && boostScale > 0f ? - Core.bundle.format("bar.efficiency", - (int)((baseEfficiency + Math.min(maxBoost, boostScale * sumAttribute(attribute, x, y))) * 100f)) + Core.bundle.format("bar.efficiency", (int)((baseEfficiency + Math.min(maxBoost, boostScale * sumAttribute(attribute, x, y))) * 100f)) : "") + - (displayScaledOutput && outputScale > 0f ? "\n" + - Core.bundle.format("bar.yield", - (int)(Math.min(maxBoost, outputScale * sumAttribute(attribute, x, y)) * 100f)) + (displayScaledOutput && outputScale > 0f ? + "\n" + Core.bundle.format("bar.yield", (int)((1f + Math.min(maxBoost, outputScale * sumAttribute(attribute, x, y))) * 100f)) : ""), x, y, valid); } @@ -59,7 +61,7 @@ public class AttributeCrafter extends GenericCrafter{ if(displayScaledOutput && outputScale > 0f){ addBar("yield", (AttributeCrafterBuild entity) -> new Bar( - () -> Core.bundle.format("bar.yield", (int)((entity.outputMultiplier() - baseEfficiency) * 100)), + () -> Core.bundle.format("bar.yield", (int)(entity.outputMultiplier() * 100)), () -> Pal.lightOrange, entity::outputMultiplier)); } From b8f392a1160e29249f8d34f293d0b78f0a983729 Mon Sep 17 00:00:00 2001 From: Anuken Date: Thu, 17 Sep 2026 10:54:49 -0400 Subject: [PATCH 05/25] Fixed #12674 --- core/assets/bundles/bundle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/assets/bundles/bundle.properties b/core/assets/bundles/bundle.properties index 30086d23d9..fb4fad1ce2 100644 --- a/core/assets/bundles/bundle.properties +++ b/core/assets/bundles/bundle.properties @@ -3396,7 +3396,7 @@ logicrule.label.wavetimer = wave timer? logicrule.label.waves = waves logicrule.label.wave = wave logicrule.label.wavespacing = wave spacing -logicrule.label.wavesending = waves ending? +logicrule.label.wavesending = waves sending? logicrule.label.attackmode = attack mode? logicrule.label.enemycorebuildradius = enemy core build radius logicrule.label.dropzoneradius = drop zone radius From ca2c51896d873aa10caa5269d53b990bcb452c74 Mon Sep 17 00:00:00 2001 From: EggleEgg <125359838+EggleEgg@users.noreply.github.com> Date: Thu, 17 Sep 2026 17:10:16 +0200 Subject: [PATCH 06/25] Bugfix: scaled crafters unable to dump fast enough (#12669) --- .../mindustry/world/blocks/production/GenericCrafter.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/core/src/mindustry/world/blocks/production/GenericCrafter.java b/core/src/mindustry/world/blocks/production/GenericCrafter.java index 4c40a18753..1f73d69156 100644 --- a/core/src/mindustry/world/blocks/production/GenericCrafter.java +++ b/core/src/mindustry/world/blocks/production/GenericCrafter.java @@ -335,7 +335,10 @@ public class GenericCrafter extends Block{ public void dumpOutputs(){ if(outputItems != null && timer(timerDump, dumpTime / timeScale)){ for(ItemStack output : outputItems){ - dump(output.item); + int amount = Math.max(1, Mathf.round(scaleOutput(output.amount))); + for(int i = 0; i < amount; i++){ + if(!dump(output.item)) break; + } } } From ec2bc543396c38878ff26b05efb47823b8911c5e Mon Sep 17 00:00:00 2001 From: Anuken Date: Thu, 17 Sep 2026 18:31:36 -0400 Subject: [PATCH 07/25] Fixed #12677 --- core/src/mindustry/content/Blocks.java | 9 ++++----- core/src/mindustry/world/blocks/units/Reconstructor.java | 7 +++++-- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/core/src/mindustry/content/Blocks.java b/core/src/mindustry/content/Blocks.java index 94c11e82fa..7d0101c8dc 100644 --- a/core/src/mindustry/content/Blocks.java +++ b/core/src/mindustry/content/Blocks.java @@ -6484,7 +6484,7 @@ public class Blocks{ regionSuffix = "-dark"; size = 3; - configurable = false; + showAllCommands = false; consumePower(3f); consumeLiquid(Liquids.hydrogen, 3f / 60f); consumeItems(with(Items.silicon, 40, Items.tungsten, 30)); @@ -6502,7 +6502,7 @@ public class Blocks{ regionSuffix = "-dark"; size = 3; - configurable = false; + showAllCommands = false; consumePower(2.5f); consumeLiquid(Liquids.hydrogen, 3f / 60f); consumeItems(with(Items.silicon, 60, Items.tungsten, 40)); @@ -6521,7 +6521,7 @@ public class Blocks{ regionSuffix = "-dark"; size = 3; - configurable = false; + showAllCommands = false; consumePower(2.5f); consumeLiquid(Liquids.hydrogen, 3f / 60f); consumeItems(with(Items.silicon, 50, Items.tungsten, 40)); @@ -6534,7 +6534,6 @@ public class Blocks{ ); }}; - //yes very silly name primeRefabricator = new Reconstructor("prime-refabricator"){{ requirements(Category.units, with(Items.thorium, 250, Items.oxide, 200, Items.tungsten, 200, Items.silicon, 400)); regionSuffix = "-dark"; @@ -6542,7 +6541,7 @@ public class Blocks{ researchCostMultipliers.put(Items.thorium, 0.2f); size = 5; - configurable = false; + showAllCommands = false; consumePower(4.5f); consumeLiquid(Liquids.nitrogen, 10f / 60f); consumeItems(with(Items.thorium, 80, Items.silicon, 100)); diff --git a/core/src/mindustry/world/blocks/units/Reconstructor.java b/core/src/mindustry/world/blocks/units/Reconstructor.java index f02fcf384c..0432cad986 100644 --- a/core/src/mindustry/world/blocks/units/Reconstructor.java +++ b/core/src/mindustry/world/blocks/units/Reconstructor.java @@ -39,6 +39,7 @@ public class Reconstructor extends UnitBlock{ public Sound createSound = Sounds.unitCreate; public float createSoundVolume = 1f; + public boolean showAllCommands = true; public Reconstructor(String name){ super(name); @@ -187,7 +188,7 @@ public class Reconstructor extends UnitBlock{ if(build != null && build.team == this.team){ commandPos.set(build); } - } + } } @Override @@ -197,7 +198,7 @@ public class Reconstructor extends UnitBlock{ public boolean canSetCommand(){ var output = unit(); - return output == null || output.allowChangeCommands; + return showAllCommands ? (output == null || output.allowChangeCommands) : output != null && output.commands.size > 1; } @Override @@ -214,6 +215,8 @@ public class Reconstructor extends UnitBlock{ public void buildConfiguration(Table table){ var unit = unit(); + if(!showAllCommands && unit == null) return; + var group = new ButtonGroup(); group.setMinCheckCount(0); int i = 0, columns = 5; From 543dae701c83858cb130a62209ed85caad724a2e Mon Sep 17 00:00:00 2001 From: Anuken Date: Fri, 18 Sep 2026 10:16:11 -0400 Subject: [PATCH 08/25] Updated PR template --- .github/pull_request_template.md | 3 ++- CONTRIBUTING.md | 4 +--- SERVERLIST.md | 3 --- 3 files changed, 3 insertions(+), 7 deletions(-) delete mode 100644 SERVERLIST.md diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 81d2a8c472..003cb693b1 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -1,5 +1,6 @@ -If your pull request is **not** translation or serverlist-related, read the list of requirements below and check each box: +If your pull request is **not** translation-related, read the list of requirements below and check each box: - [ ] I have read the [contribution guidelines](https://github.com/Anuken/Mindustry/blob/master/CONTRIBUTING.md). - [ ] I have ensured that my code compiles, if applicable. - [ ] I have ensured that any new features in this PR function correctly in-game, if applicable. +- [ ] I affirm that this code was not written using generative AI/LLMs. \ No newline at end of file diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 3f576b35f4..d9600d6bdd 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -22,7 +22,7 @@ I **especially** do not want to see PRs that apply any kind of automated analysi ### Do not make AI "contributions". -If I see a PR with significant amounts of code that's obviously written by AI, I will reject your PR, and you will be blocked. Don't waste my time with slop. +If I see a PR with code that's obviously written by AI, I will reject your PR, and you will be blocked. Don't waste my time with slop. Asking AI questions, and using that information to help you write code? Fine. Using it to actually write code? No. @@ -67,7 +67,6 @@ What you'll usually need to change: ### Avoid boxed types (Integer, Boolean) Never create variables or collections with boxed types `Seq` or `ObjectMap`. Use the collections specialized for this task, e.g. `IntSeq` and `IntMap`. - ### Do not allocate anything if possible. Never allocate `new` objects in the main loop. If you absolutely require new objects, use `Pools` to obtain and free object instances. Otherwise, use the `Tmp` variables for things like vector/shape operations, or create `static` variables for re-use. @@ -77,7 +76,6 @@ If using a list, make it a static variable and clear it every time it is used. R This is situational, but in essence, what it means is to avoid using any sort of getters and setters unless absolutely necessary. Public or protected fields should suffice for most things. If something needs to be encapsulated in the future, IntelliJ can handle it with a few clicks. - ### Do not create methods unless necessary. Unless a block of code is very large or used in more than 1-2 places, don't split it up into a separate method. Making unnecessary methods only creates confusion, and may slightly decrease performance. diff --git a/SERVERLIST.md b/SERVERLIST.md deleted file mode 100644 index 517a48a065..0000000000 --- a/SERVERLIST.md +++ /dev/null @@ -1,3 +0,0 @@ -# Note: The v7 server list is frozen. No new servers will be accepted. All v8 server PRs should be made [here](https://github.com/Anuken/MindustryServerList). - -*PRs to edit addresses of existing servers will still be accepted, although very infrequently.* From 6500b5b6deb352cdf6a2754afe8d6c87ee6650ae Mon Sep 17 00:00:00 2001 From: Cardillan <122014763+cardillan@users.noreply.github.com> Date: Fri, 18 Sep 2026 16:46:33 +0200 Subject: [PATCH 09/25] Improve hex and binary literal parses (#12678) * Improve hex and binary literal parses * Moved the specialized unsigned long parsing routine from Strings directly to LAssembler --- core/src/mindustry/logic/LAssembler.java | 50 +++++++++++++++++------- 1 file changed, 36 insertions(+), 14 deletions(-) diff --git a/core/src/mindustry/logic/LAssembler.java b/core/src/mindustry/logic/LAssembler.java index b5d7443639..c2c40ea97c 100644 --- a/core/src/mindustry/logic/LAssembler.java +++ b/core/src/mindustry/logic/LAssembler.java @@ -11,9 +11,6 @@ import mindustry.logic.LExecutor.*; public class LAssembler{ public static ObjectMap> customParsers = new ObjectMap<>(); - private static final long invalidNumNegative = Long.MIN_VALUE; - private static final long invalidNumPositive = Long.MAX_VALUE; - public boolean privileged; /** Maps names to variable. */ public OrderedMap vars = new OrderedMap<>(); @@ -110,23 +107,48 @@ public class LAssembler{ } double parseDouble(String symbol){ + //fail fast for obvious non-numbers + if(symbol.isEmpty() || !isNumStart(symbol.charAt(0))) return Double.NaN; + //parse hex/binary syntax - if(symbol.startsWith("0b")) return parseLong(false, symbol, 2, 2, symbol.length()); - if(symbol.startsWith("+0b")) return parseLong(false, symbol, 2, 3, symbol.length()); - if(symbol.startsWith("-0b")) return parseLong(true,symbol, 2, 3, symbol.length()); - if(symbol.startsWith("0x")) return parseLong(false,symbol, 16, 2, symbol.length()); - if(symbol.startsWith("+0x")) return parseLong(false,symbol, 16, 3, symbol.length()); - if(symbol.startsWith("-0x")) return parseLong(true,symbol, 16, 3, symbol.length()); + if(symbol.startsWith("0b")) return parseHexOrBin(false, symbol, true, 2); + if(symbol.startsWith("+0b")) return parseHexOrBin(false, symbol, true, 3); + if(symbol.startsWith("-0b")) return parseHexOrBin(true, symbol, true, 3); + if(symbol.startsWith("0x")) return parseHexOrBin(false, symbol, false, 2); + if(symbol.startsWith("+0x")) return parseHexOrBin(false, symbol, false, 3); + if(symbol.startsWith("-0x")) return parseHexOrBin(true, symbol, false, 3); if(symbol.startsWith("%[") && symbol.endsWith("]") && symbol.length() > 3) return parseNamedColor(symbol); if(symbol.startsWith("%") && (symbol.length() == 7 || symbol.length() == 9)) return parseColor(symbol); return Strings.parseDouble(symbol, Double.NaN); } - double parseLong(boolean negative, String s, int radix, int start, int end) { - long usedInvalidNum = negative ? invalidNumPositive : invalidNumNegative; - long l = Strings.parseLong(s, radix, start, end, usedInvalidNum); - return l == usedInvalidNum ? Double.NaN : negative ? -l : l; + boolean isNumStart(char c){ + //note that 'e10' isn't a valid number; '%ffffff' is. Hex numbers start with '0x'. + return c >= '0' && c <= '9' || c == '.' || c == '-' || c == '+' || c == '%'; + } + + //parses *unsigned* hex or bin number, including negative ones (0xffffffffffffffff as -1) + //detects overflow by input length and uses bit manipulation to avoid signed arithmetics + double parseHexOrBin(boolean negative, String s, boolean binary, int offset){ + int end = s.length(); + if(offset >= end) return Double.NaN; + + int pos = offset; + while(pos < end && s.charAt(pos) == '0') pos ++; //skip leading zeros to avoid incorrect overflow detection + + int shift = binary ? 1 : 4; + if(end - pos > 64 / shift) return Double.NaN; + + long acc = 0; + int radix = 1 << shift; + while(pos < end){ + int digit = Character.digit(s.charAt(pos), radix); + if(digit < 0) return Double.NaN; + acc = acc << shift | digit; + pos ++; + } + return negative ? -acc : acc; } double parseColor(String symbol){ @@ -178,4 +200,4 @@ public class LAssembler{ return vars.get(name); } -} \ No newline at end of file +} From 1e8317fbac4c8ce2509eac7a758f4f846c4c00d3 Mon Sep 17 00:00:00 2001 From: Anuken Date: Fri, 18 Sep 2026 10:47:09 -0400 Subject: [PATCH 10/25] Fixed #12683 --- core/src/mindustry/world/Build.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/mindustry/world/Build.java b/core/src/mindustry/world/Build.java index 6d99b4e48a..7036ba204f 100644 --- a/core/src/mindustry/world/Build.java +++ b/core/src/mindustry/world/Build.java @@ -186,7 +186,7 @@ public class Build{ return false; } - if(!state.rules.editor && checkCoreRadius){ + if(!state.rules.editor && checkCoreRadius && !(!checkVisible && team == Team.derelict)){ //find closest core, if it doesn't match the team, placing is not legal if(state.rules.polygonCoreProtection){ float mindst = Float.MAX_VALUE; From ccc5bebc3ba1098417b5c95281c92a243e4e5946 Mon Sep 17 00:00:00 2001 From: summoner Date: Fri, 18 Sep 2026 16:47:37 +0200 Subject: [PATCH 11/25] Translation: Update bundle_hu.properties (#12679) Follow the changes of the english bundle Minor fixes --- core/assets/bundles/bundle_hu.properties | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/core/assets/bundles/bundle_hu.properties b/core/assets/bundles/bundle_hu.properties index 7673840976..160bbee799 100644 --- a/core/assets/bundles/bundle_hu.properties +++ b/core/assets/bundles/bundle_hu.properties @@ -1019,7 +1019,7 @@ sector.crateredBattleground.description = Víz gyűlt össze ebben a kráterben, sector.ruinousShores.description = A pusztaság mögött a partvonal húzódik. Valaha ezen a helyen egy partvédelmi rendszer állt. Nem sok minden maradt belőle. Csak a legalapvetőbb védelmi szerkezetek maradtak érintetlenül, minden más csak törmelék lett.\nFolytasd a terjeszkedést. Fedezd fel újra a technológiát. sector.stainedMountains.description = Mélyebben a szárazföldön fekszenek a hegyek, a spóráktól még érintetlenül.\nTermeld ki a bőséges titán készleteket a körzetben. Tanuld meg felhasználni.\n\nAz ellenség itt nagyobb létszámban van jelen. Ne hagyj nekik időt, hogy a legerősebb egységeiket hadba állíthassák. sector.overgrowth.description = Ez a terület közelebb esik a spórák forrásához, a spórák már kinőtték.\nAz ellenség egy helyőrséget létesített itt. Építs Mace egységeket. Pusztítsd el a bázist. -sector.tarFields.description = Egy olajtermelő övezet peremvidéke a hegyek és a sivatag határán. Egy azon kevés szektorok közül, ahol még hasznosítható kátránykészletek találhatók.\nBár a terület elhagyatott, veszélyes ellenséges erők fészkelnek a közelben. Ne becsüld alá őket.\n\n[lightgray]Fedezd fel az olajfeldolgozási lehetőségeket, ha tudod. +sector.tarFields.description = Egy olajtermelő övezet peremvidéke a hegyek és a sivatag határán. Azon kevés szektorok egyike, ahol még hasznosítható kátránykészletek találhatók.\nBár a terület elhagyatott, veszélyes ellenséges erők fészkelnek a közelben. Ne becsüld alá őket.\n\n[lightgray]Fedezd fel az olajfeldolgozási lehetőségeket, ha tudod. sector.desolateRift.description = Ez egy rendkívül veszélyes zóna. Bár nyersanyagokban gazdag, kevés hely áll rendelkezésre. Magas a kockázat. Építs szárazföldi és légvédelmet, amint csak tudsz. Ne tévesszen meg a hosszú szünet az ellenség támadásai között. sector.nuclearComplex.description = Egy néhai tóriumkitermelő és feldolgozó létesítmény, romokban.\n[lightgray]Fedezd fel a tóriumot és a sokrétű felhasználását.\n\nAz ellenség nagy létszámban van jelen, és folyamatosan megfigyelés alatt tartják a környéket. sector.fungalPass.description = Átmeneti terület a magas hegyek és a mélyebben fekvő, spórák uralta lapály között. Egy kisebb ellenséges megfigyelő állomás található itt.\nSemmisítsd meg.\nHasználj Dagger egységeket. Pusztítsd el a támaszpontot. @@ -1299,7 +1299,7 @@ bar.cargounitcap = Az egység raktere megtelt bar.drillspeed = Termelés: {0}/mp bar.pumpspeed = Termelés: {0}/mp bar.efficiency = Hatásfok: {0}% -bar.yield = Hozam: +{0}% +bar.yield = Hozam: {0}% bar.boost = Erősítés: +{0}% bar.powerbuffer = Akkumulátorok: {0}/{1} bar.powerbalance = Áram: {0}/mp @@ -3391,14 +3391,14 @@ logicrule.label.wavetimer = hullámidőzítő? logicrule.label.waves = hullámok logicrule.label.wave = hullám logicrule.label.wavespacing = hullámok közötti idő -logicrule.label.wavesending = hullámok véget érnek? +logicrule.label.wavesending = hullámok küldése? logicrule.label.attackmode = támadó mód? logicrule.label.enemycorebuildradius = ellenséges támaszpont építési sugara logicrule.label.dropzoneradius = ledobási zóna sugara logicrule.label.unitcap = egységkorlát logicrule.label.maparea = térkép területe logicrule.label.lighting = világítás? -logicrule.label.cangameover = lehetséges játék vége +logicrule.label.cangameover = befejeződhet a játék logicrule.label.ambientlight = környezeti fény logicrule.label.unitlight = egység fénye logicrule.label.solarmultiplier = napelemszorzó From cada4b2543a7ed40adee69881775739ab83f36cd Mon Sep 17 00:00:00 2001 From: Anuken Date: Fri, 18 Sep 2026 11:11:56 -0400 Subject: [PATCH 12/25] Logic parsing tests --- tests/src/test/java/LogicTests.java | 118 ++++++++++++++++++++++++++++ 1 file changed, 118 insertions(+) diff --git a/tests/src/test/java/LogicTests.java b/tests/src/test/java/LogicTests.java index a7abccea83..140145398a 100644 --- a/tests/src/test/java/LogicTests.java +++ b/tests/src/test/java/LogicTests.java @@ -1,3 +1,4 @@ +import arc.graphics.*; import mindustry.logic.*; import mindustry.logic.LExecutor.*; import org.junit.jupiter.api.*; @@ -243,6 +244,123 @@ public class LogicTests{ ); } + /** Values that must resolve to a numeric constant (isobj == false) or an object constant. */ + static Stream parseValCases(){ + return Stream.of( + // name, symbol, expected (Double => numeric, anything else => object) + Arguments.of("parse null", "null", null), + + //decimal + Arguments.of("decimal: zero", "0", 0.0), + Arguments.of("decimal: positive integer", "42", 42.0), + Arguments.of("decimal: negative integer", "-42", -42.0), + Arguments.of("decimal: explicit plus sign", "+42", 42.0), + Arguments.of("decimal: fraction", "3.14", 3.14), + Arguments.of("decimal: negative fraction", "-3.14", -3.14), + Arguments.of("decimal: leading dot", ".5", 0.5), + Arguments.of("decimal: large integer", "123456789012", 123456789012.0), + Arguments.of("decimal: scientific", "1e3", 1000.0), + Arguments.of("decimal: scientific negative exponent", "1.5e-2", 0.015), + + //hex + Arguments.of("hex: zero", "0x0", 0.0), + Arguments.of("hex: uppercase digits", "0xFF", 255.0), + Arguments.of("hex: lowercase digits", "0xff", 255.0), + Arguments.of("hex: mixed case", "0xDeadBeef", 3735928559.0), + Arguments.of("hex: explicit plus", "+0xFF", 255.0), + Arguments.of("hex: negative", "-0xFF", -255.0), + Arguments.of("hex: many leading zeros aren't overflow", "0x0000000000000000000000FF", 255.0), + Arguments.of("hex: only zeros", "0x" + "0".repeat(100), 0.0), + Arguments.of("hex: Long.MAX_VALUE", "0x7FFFFFFFFFFFFFFF", (double)Long.MAX_VALUE), + Arguments.of("hex: Long.MIN_VALUE (0x8000...)", "0x8000000000000000", (double)Long.MIN_VALUE), + Arguments.of("hex: unsigned long max wraps to -1", "0xFFFFFFFFFFFFFFFF", -1.0), + Arguments.of("hex: unsigned long max - 1 wraps to -2", "0xFFFFFFFFFFFFFFFE", -2.0), + Arguments.of("hex: negated -1 wrap gives 1", "-0xFFFFFFFFFFFFFFFF", 1.0), + Arguments.of("hex: negative Long.MAX_VALUE", "-0x7FFFFFFFFFFFFFFF", -(double)Long.MAX_VALUE), + + //binary + Arguments.of("bin: zero", "0b0", 0.0), + Arguments.of("bin: one", "0b1", 1.0), + Arguments.of("bin: ten", "0b1010", 10.0), + Arguments.of("bin: explicit plus", "+0b1010", 10.0), + Arguments.of("bin: negative", "-0b1010", -10.0), + Arguments.of("bin: many leading zeros aren't overflow", "0b" + "0".repeat(70) + "1", 1.0), + Arguments.of("bin: 63 ones is Long.MAX_VALUE", "0b0" + "1".repeat(63), (double)Long.MAX_VALUE), + Arguments.of("bin: 1 followed by 63 zeros is Long.MIN_VALUE", "0b1" + "0".repeat(63), (double)Long.MIN_VALUE), + Arguments.of("bin: 64 ones wraps to -1", "0b" + "1".repeat(64), -1.0) + ); + } + + @ParameterizedTest(name = "{0}") + @MethodSource("parseValCases") + void parseVarValues(String name, String symbol, Object expected){ + LAssembler asm = new LAssembler(); + LVar v = asm.var(symbol); + if(expected instanceof Double d){ + assertFalse(v.isobj, "should be numeric: " + symbol); + assertEquals(d, v.numval, 0.00001f); + }else{ + assertTrue(v.isobj); + assertEquals(expected, v.objval); + } + } + + /** Colors are packed into the bits of a (tiny, denormal) double, so they need an exact comparison. */ + static Stream parseColorCases(){ + return Stream.of( + Arguments.of("color: rgb white", "%ffffff", Color.toDoubleBits(255, 255, 255, 255)), + Arguments.of("color: rgba", "%ff000080", Color.toDoubleBits(255, 0, 0, 128)), + Arguments.of("color: named", "%[red]", Colors.get("red").toDoubleBits()) + ); + } + + @ParameterizedTest(name = "{0}") + @MethodSource("parseColorCases") + void parseColorValues(String name, String symbol, double expected){ + LAssembler asm = new LAssembler(); + LVar v = asm.var(symbol); + assertFalse(v.isobj); + assertEquals(expected, v.numval, 0.0); + } + + /** Anything here must NOT be parsed as a number (i.e. it becomes a plain variable name). */ + static Stream invalidNumberCases(){ + return Stream.of( + //fail-fast: first char can't start a number + "", + "abc", + "e10", + "NaN", + "Infinity", + + //prefix with no digits + "0x", "0b", "+0x", "-0b", + + //invalid digits + "0xG", "0x12G4", "0b2", "0b102", "0x-1", "0x1.5", + + //overflow: more than 64 significant bits + "0x1" + "0".repeat(16), //17 hex digits + "-0x1" + "0".repeat(16), + "0x" + "F".repeat(17), + "0b1" + "0".repeat(64), //65 binary digits + "0b" + "1".repeat(65), + + //malformed colors + "%fff", + "%[nosuchcolor]" + ); + } + + @ParameterizedTest(name = "invalid: [{0}]") + @MethodSource("invalidNumberCases") + void parseInvalidNumbers(String symbol){ + LAssembler asm = new LAssembler(); + LVar v = asm.var(symbol); + assertTrue(v.isobj, "should not parse as a number: " + symbol); + assertNull(v.objval); + } + //unterminated / malformed string literals: these must fail loudly, never silently misparse @ParameterizedTest(name = "{0}") From c58aac5f678065cc54ddd92fd3aca94443313364 Mon Sep 17 00:00:00 2001 From: Anuken Date: Fri, 18 Sep 2026 12:47:14 -0400 Subject: [PATCH 13/25] Version-specific release fetching for mods --- core/src/mindustry/mod/ModListing.java | 20 +++++++++----- .../ui/dialogs/ModBrowserDialog.java | 9 +++++-- core/src/mindustry/ui/dialogs/ModsDialog.java | 27 +++++++++++++++---- gradle.properties | 2 +- 4 files changed, 44 insertions(+), 14 deletions(-) diff --git a/core/src/mindustry/mod/ModListing.java b/core/src/mindustry/mod/ModListing.java index 8c16c84f01..3ddff52b78 100644 --- a/core/src/mindustry/mod/ModListing.java +++ b/core/src/mindustry/mod/ModListing.java @@ -10,7 +10,7 @@ public class ModListing{ public boolean hasScripts, hasJava, iosCompatible, legacyCompatible, hasIcon; /** game build -> release ID + mod version */ public @Nullable ArrayMap releases; - public String[] contentTypes = {}; + public String[] tags = {}; public int stars; @Override @@ -29,21 +29,29 @@ public class ModListing{ '}'; } + /** @return the specific release that matches the current game version, or null if no specific match is found (i.e. /latest should be used) */ public @Nullable ModRelease getMatchingRelease(){ if(releases == null) return null; - for(int i = 0; i < releases.size; i ++){ - String key = releases.keys[i]; - if(ModsDialog.matchesGameVersion(ModsDialog.parseVersion(key))){ - return releases.values[i]; + for(var entry : releases){ + if(ModsDialog.matchesGameVersion(ModsDialog.parseVersion(entry.key))){ + return entry.value; } } return null; } public static class ModRelease{ - /** Github release ID */ + /** Github release ID ($API/releases/$ID) */ public String id = ""; /** Actual mod version string in release's mod.json */ public String version = ""; + + @Override + public String toString(){ + return "ModRelease{" + + "id='" + id + '\'' + + ", version='" + version + '\'' + + '}'; + } } } diff --git a/core/src/mindustry/ui/dialogs/ModBrowserDialog.java b/core/src/mindustry/ui/dialogs/ModBrowserDialog.java index 40caae2fe5..d61372755c 100644 --- a/core/src/mindustry/ui/dialogs/ModBrowserDialog.java +++ b/core/src/mindustry/ui/dialogs/ModBrowserDialog.java @@ -65,6 +65,11 @@ public class ModBrowserDialog extends BaseDialog{ shown(this::rebuildBrowser); } + public @Nullable ModListing getCachedMod(String repo){ + if(modList == null) return null; + return modList.find(m -> m.repo.equalsIgnoreCase(repo)); + } + public void getModList(Cons> listener){ //mods already fetched, use that if(modList != null){ @@ -247,7 +252,7 @@ public class ModBrowserDialog extends BaseDialog{ textureCache.put(repo, last = Core.atlas.find("nomap")); if(mod.hasIcon){ - Fi cacheFolder = Vars.mobile ? Core.files.cache("modIconCache"): dataDirectory.child("modIconCache"); + Fi cacheFolder = mobile ? Core.files.cache("modIconCache"): dataDirectory.child("modIconCache"); cacheFolder.mkdirs(); Fi cacheFile = cacheFolder.child(Strings.sanitizeFilename(mod.repo + "_" + mod.iconHash) + ".png"); @@ -337,7 +342,7 @@ public class ModBrowserDialog extends BaseDialog{ var found = mods.list().find(l -> mod.repo != null && mod.repo.equals(l.getRepo())); sel.buttons.button(found == null ? "@mods.browser.add" : "@mods.browser.reinstall", Icon.download, () -> { sel.hide(); - ui.mods.githubImportMod(mod.repo, mod.hasJava, null, true); + ui.mods.githubImportMod(mod); }); if(Core.graphics.isPortrait()){ diff --git a/core/src/mindustry/ui/dialogs/ModsDialog.java b/core/src/mindustry/ui/dialogs/ModsDialog.java index 37af75cadc..5d2575de75 100644 --- a/core/src/mindustry/ui/dialogs/ModsDialog.java +++ b/core/src/mindustry/ui/dialogs/ModsDialog.java @@ -109,7 +109,11 @@ public class ModsDialog extends BaseDialog{ var mod = repoToMod.get(entry.repo); if(mod != null){ modToListing.put(mod, entry); - if(Strings.checkNewerSemver(entry.version, mod.meta.version)) withUpdates.add(mod); + var release = entry.getMatchingRelease(); + //Only compare to the release that fits the current version the client is using, if one exists; don't look for updates that don't match the version + if(Strings.checkNewerSemver(entry.version, release == null ? mod.meta.version : release.version)){ + withUpdates.add(mod); + } } } @@ -175,8 +179,15 @@ public class ModsDialog extends BaseDialog{ if(text.startsWith("https://github.com/")) text = text.substring("https://github.com/".length()); Core.settings.put("lastmod", text); - //there's no good way to know if it's a java mod here, so assume it's not - githubImportMod(text, false, null, true); + var listing = browser.getCachedMod(text); + if(listing != null){ + //auto-choose release when a listing is found + githubImportMod(listing); + }else{ + //this will auto-detect whether it's java, then grab latest release unconditionally + //TODO: would be nice to grab version-appropriate release but I don't want to copy-paste browser logic for this + githubImportMod(text, false, null, true); + } }); }).margin(12f); }); @@ -530,7 +541,7 @@ public class ModsDialog extends BaseDialog{ } } - public void viewReleases(String repo, boolean isJava, boolean reinstall) { + public void viewReleases(String repo, boolean isJava, boolean reinstall){ BaseDialog load = new BaseDialog(""); load.cont.add("[accent]" + Core.bundle.get("mods.browser.fetching")); load.show(); @@ -600,6 +611,11 @@ public class ModsDialog extends BaseDialog{ })); } + public void githubImportMod(ModListing mod){ + var matchingRelease = mod.getMatchingRelease(); + githubImportMod(mod.repo, mod.hasJava, matchingRelease == null ? null : matchingRelease.id, true); + } + public void githubImportMod(String repo, boolean isJava, boolean forceEnable){ githubImportMod(repo, isJava, null, forceEnable); } @@ -699,7 +715,8 @@ public class ModsDialog extends BaseDialog{ while(m.find()){ if(m.start() == 0 || m.end() == str.length()){ int major = Strings.parseInt(m.group(1)); - if(major == Integer.MIN_VALUE) return null; + //any major version below 15 is likely a major-version tag like [v7] and should be ignored + if(major == Integer.MIN_VALUE || major < 15) return null; int minor = m.group(2) != null ? Strings.parseInt(m.group(2)) : 0; if(minor == Integer.MIN_VALUE) return null; return new int[]{major, minor}; diff --git a/gradle.properties b/gradle.properties index d2f03ad7ec..2cf1dcebad 100644 --- a/gradle.properties +++ b/gradle.properties @@ -26,4 +26,4 @@ org.gradle.caching=true org.gradle.internal.http.socketTimeout=100000 org.gradle.internal.http.connectionTimeout=100000 android.enableR8.fullMode=false -archash=68a04fab6e +archash=4a83c3a235 From be14e4173e1d05ff100bc6f276b7c04c138a57ba Mon Sep 17 00:00:00 2001 From: Anuken Date: Fri, 18 Sep 2026 13:58:24 -0400 Subject: [PATCH 14/25] Null check for displayFlow --- core/src/mindustry/world/modules/ItemModule.java | 2 +- core/src/mindustry/world/modules/LiquidModule.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core/src/mindustry/world/modules/ItemModule.java b/core/src/mindustry/world/modules/ItemModule.java index 59e068a3bf..49240a2f91 100644 --- a/core/src/mindustry/world/modules/ItemModule.java +++ b/core/src/mindustry/world/modules/ItemModule.java @@ -97,7 +97,7 @@ public class ItemModule extends BlockModule{ /** @return a specific item's flow rate in items/s; any value < 0 means not ready.*/ public float getFlowRate(Item item){ - return flow == null ? -1f : displayFlow[item.id] * 60; + return flow == null ? -1f : displayFlow != null ? displayFlow[item.id] * 60 : -1f; } public boolean hasFlowItem(Item item){ diff --git a/core/src/mindustry/world/modules/LiquidModule.java b/core/src/mindustry/world/modules/LiquidModule.java index 23bfc60659..dfbcb8635f 100644 --- a/core/src/mindustry/world/modules/LiquidModule.java +++ b/core/src/mindustry/world/modules/LiquidModule.java @@ -78,7 +78,7 @@ public class LiquidModule extends BlockModule{ /** @return current liquid's flow rate in u/s; any value < 0 means 'not ready'. */ public float getFlowRate(Liquid liquid){ - return flow == null ? -1f : displayFlow[liquid.id] * 60; + return flow == null ? -1f : displayFlow != null ? displayFlow[liquid.id] * 60 : -1f; } public boolean hasFlowLiquid(Liquid liquid){ From 4ef2a6d81e2732de16d73d233d3182ec7f0dc63d Mon Sep 17 00:00:00 2001 From: Anuken Date: Fri, 18 Sep 2026 18:04:25 -0400 Subject: [PATCH 15/25] CADisableMinimumFrameDurationOnPhone on iOS --- gradle.properties | 2 +- ios/Info.plist.xml | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 2cf1dcebad..a0930da613 100644 --- a/gradle.properties +++ b/gradle.properties @@ -26,4 +26,4 @@ org.gradle.caching=true org.gradle.internal.http.socketTimeout=100000 org.gradle.internal.http.connectionTimeout=100000 android.enableR8.fullMode=false -archash=4a83c3a235 +archash=8eb00ffff0 diff --git a/ios/Info.plist.xml b/ios/Info.plist.xml index 3ace8e7c9c..d55a48f855 100644 --- a/ios/Info.plist.xml +++ b/ios/Info.plist.xml @@ -38,6 +38,8 @@ UIRequiresFullScreen + CADisableMinimumFrameDurationOnPhone + LSSupportsOpeningDocumentsInPlace NSPhotoLibraryAddUsageDescription From 1cc5d54fde2204afbd9efc5276d918b6ac199b1b Mon Sep 17 00:00:00 2001 From: Anuken Date: Sat, 19 Sep 2026 10:53:14 -0400 Subject: [PATCH 16/25] Fixed #12690 --- core/src/mindustry/logic/LStatements.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/mindustry/logic/LStatements.java b/core/src/mindustry/logic/LStatements.java index 1491fa884c..575a6c9bc4 100644 --- a/core/src/mindustry/logic/LStatements.java +++ b/core/src/mindustry/logic/LStatements.java @@ -2541,7 +2541,7 @@ public class LStatements{ b.label(() -> bundle(type)); b.clicked(() -> showSelect(b, MapObjectives.allMarkerTypeNames.toArray(String.class), type, t -> { - type = bundle(t); + type = t; build(table); }, 2, cell -> cell.size(160, 50))); }, Styles.logict, () -> {}).size(180, 40).color(table.color).left().padLeft(2); From d2c5e09413f27ad55865dc1698d4eef4d6aa15b9 Mon Sep 17 00:00:00 2001 From: Anuken Date: Sat, 19 Sep 2026 11:43:05 -0400 Subject: [PATCH 17/25] Fixed popups not respecting hidden UI state --- core/src/mindustry/core/UI.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/core/src/mindustry/core/UI.java b/core/src/mindustry/core/UI.java index 344004b14c..cc9ffdc268 100644 --- a/core/src/mindustry/core/UI.java +++ b/core/src/mindustry/core/UI.java @@ -408,8 +408,9 @@ public class UI implements ApplicationListener, Loadable{ table.touchable = Touchable.disabled; table.setFillParent(true); if(cinfo.visible && !state.isMenu()) table.marginTop(cinfo.getPrefHeight() / Scl.scl() / 2); - table.update(() -> { + table.visible(() -> { if(state.isMenu()) table.remove(); + return ui.hudfrag.shown; }); table.actions(Actions.delay(duration * 0.9f), Actions.fadeOut(duration * 0.1f, Interp.fade), Actions.remove()); table.top().table(Styles.black3, t -> t.margin(4).add(info).style(Styles.outlineLabel)).padTop(10); @@ -431,11 +432,12 @@ public class UI implements ApplicationListener, Loadable{ } table.setFillParent(true); table.touchable = Touchable.disabled; - table.update(() -> { + table.visible(() -> { if(state.isMenu()){ table.remove(); if(id != null) popups.remove(id); } + return ui.hudfrag.shown; }); table.actions(Actions.delay(duration), Actions.remove(), Actions.run(() -> { if(id != null) popups.remove(id); })); table.align(align).table(Styles.black3, t -> t.margin(4).add(info).style(Styles.outlineLabel)).pad(top, left, bottom, right); From 9f065cea59a314547c3fcb23ef153485427a4968 Mon Sep 17 00:00:00 2001 From: Anuken Date: Sat, 19 Sep 2026 23:24:54 -0400 Subject: [PATCH 18/25] Do not add liquid bars to blocks with 0 liquid capacity --- core/src/mindustry/world/Block.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/mindustry/world/Block.java b/core/src/mindustry/world/Block.java index 84d636d42d..3de4240ed7 100644 --- a/core/src/mindustry/world/Block.java +++ b/core/src/mindustry/world/Block.java @@ -760,7 +760,7 @@ public class Block extends UnlockableContent implements Senseable{ } //nothing was added, so it's safe to add a dynamic liquid bar (probably?) - if(!added){ + if(!added && liquidCapacity > 0f){ addLiquidBar(build -> build.liquids.current()); } } From 2f3a3979a43485f477a452410d01567512eaeb58 Mon Sep 17 00:00:00 2001 From: EggleEgg <125359838+EggleEgg@users.noreply.github.com> Date: Sun, 20 Sep 2026 15:19:40 +0200 Subject: [PATCH 19/25] Bugfix lightning chain distance (again) (#12695) --- core/src/mindustry/entities/Lightning.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/mindustry/entities/Lightning.java b/core/src/mindustry/entities/Lightning.java index 43c18ca0ba..4554ce7dc9 100644 --- a/core/src/mindustry/entities/Lightning.java +++ b/core/src/mindustry/entities/Lightning.java @@ -84,7 +84,7 @@ public class Lightning{ Unit furthest = Geometry.findFurthest(x, y, entities); - if(furthest != null && furthest.dst(x, y) < length * 1.5f){ + if(furthest != null && furthest.within(x, y, hitRange * 2f)){ hit.add(furthest.id()); x = furthest.x(); y = furthest.y(); From e2ccb6ea964d15f5ca1ef09536f9adcf6027d945 Mon Sep 17 00:00:00 2001 From: Anuken Date: Sun, 20 Sep 2026 09:20:54 -0400 Subject: [PATCH 20/25] Fixed #12691 --- core/src/mindustry/ui/dialogs/EditorMapsDialog.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/mindustry/ui/dialogs/EditorMapsDialog.java b/core/src/mindustry/ui/dialogs/EditorMapsDialog.java index b1ece85c3d..807b7a5d20 100644 --- a/core/src/mindustry/ui/dialogs/EditorMapsDialog.java +++ b/core/src/mindustry/ui/dialogs/EditorMapsDialog.java @@ -130,7 +130,7 @@ public class EditorMapsDialog extends MapListDialog{ if(!map.tags.get("description", "").isEmpty()){ t.add("@editor.description").padRight(10).color(Color.gray).top(); t.row(); - t.add(map.description()).growX().wrap().padTop(2); + t.add(map.description()).growX().wrap(true).padTop(2); } }).height(mapsize).width(mapsize); From 92d53b01fc9bf6ac90f7e50359afec400dccf2cd Mon Sep 17 00:00:00 2001 From: "Sunky.MP3G" <125795960+SunkyMP3G@users.noreply.github.com> Date: Sun, 20 Sep 2026 20:21:11 +0700 Subject: [PATCH 21/25] More RU translations (#12639) * New RU translations and proper processor ones * Finished * Typo --- core/assets/bundles/bundle_ru.properties | 130 +++++++++++------------ 1 file changed, 65 insertions(+), 65 deletions(-) diff --git a/core/assets/bundles/bundle_ru.properties b/core/assets/bundles/bundle_ru.properties index b75072c398..6ad9b7310b 100644 --- a/core/assets/bundles/bundle_ru.properties +++ b/core/assets/bundles/bundle_ru.properties @@ -1299,7 +1299,7 @@ bar.cargounitcap = Достигнут предел грузовой единиц bar.drillspeed = Скорость бурения: {0}/с bar.pumpspeed = Скорость выкачивания: {0}/с bar.efficiency = Эффективность: {0}% -bar.yield = Получение: +{0}% +bar.yield = Получение: {0}% bar.boost = Ускорение: +{0}% bar.powerbuffer = Энергия в аккумуляторах: {0}/{1} bar.powerbalance = Энергия: {0}/с @@ -2945,63 +2945,63 @@ laccess.displayheight = Высота дисплея, в пикселях. laccess.buffersize = Количество необработанных команд в графическом буфере дисплея. laccess.operations = Количество операций, выполненных в блоке.\nДля дисплеев, возвращает количество выполненных операций Вывод рисования/drawflush. laccess.maxunits = Максимальное количество единиц, которое может быть у команды.\nОпределяется с помощью ядер. -laccess.totalitems = Total number of items contained. -laccess.firstitem = First item contained, or null if empty. -laccess.totalliquids = Total amount of liquid contained. -laccess.totalpower = For blocks with a buffered power store, the amount of power stored; for other blocks, buffer fullness from 0 to 1. -laccess.itemcapacity = Maximum number of items this building can hold. -laccess.liquidcapacity = Maximum amount of liquid this building can hold. -laccess.powercapacity = Maximum amount of power this building can store. -laccess.powernetstored = Total power stored in the connected power grid. -laccess.powernetcapacity = Total power storage capacity of the connected power grid. -laccess.powernetin = Power entering the connected power grid, per second. -laccess.powernetout = Power leaving the connected power grid, per second. -laccess.ammo = Current ammo count of a turret. -laccess.ammocapacity = Maximum ammo count of a turret. -laccess.health = Current health.\nFor bullets, their damage. -laccess.maxhealth = Maximum health.\nFor bullets, the base damage. -laccess.heat = Current heat of a turret that consumes heat, 0 to 1. -laccess.shield = Current shield amount of a unit. -laccess.armor = Armor value; flat damage reduction per hit. -laccess.efficiency = Operating efficiency of a building, where 1 is nominal. -laccess.timescale = Time scale multiplier affecting a building, where 1 is normal speed. -laccess.rotation = Facing angle of a unit or turret, in degrees.\nFor most other buildings, the 0 to 3 orientation. -laccess.x = X position, in tiles. -laccess.y = Y position, in tiles. -laccess.velocityx = X velocity of a unit, in tiles/sec. -laccess.velocityy = Y velocity of a unit, in tiles/sec. -laccess.shootx = X coordinate a unit or turret is aiming at. -laccess.shooty = Y coordinate a unit or turret is aiming at. -laccess.camerax = X position of the controlling player's camera. -laccess.cameray = Y position of the controlling player's camera. -laccess.camerawidth = Width of the controlling player's view, in tiles. -laccess.cameraheight = Height of the controlling player's view, in tiles. -laccess.solid = Whether this building blocks movement. -laccess.range = Range of a unit or turret, in tiles. -laccess.shooting = Whether a unit or turret is currently shooting. -laccess.boosting = Whether a unit is currently boosting or flying over terrain. -laccess.minex = X tile coordinate a unit is mining, or -1 if not mining. -laccess.miney = Y tile coordinate a unit is mining, or -1 if not mining. -laccess.mining = Whether a unit is currently mining. -laccess.buildx = X tile coordinate a unit is building at, or -1 if not building. -laccess.buildy = Y tile coordinate a unit is building at, or -1 if not building. -laccess.pingx = X coordinate a player is pinging, or null if not pinging. -laccess.pingy = Y coordinate a player is pinging, or null if not pinging. -laccess.pingtext = Text of a player's current ping, or null if not pinging. -laccess.building = Building a unit is currently constructing, or null. -laccess.breaking = Building a unit is currently deconstructing, or null. -laccess.team = Team ID of a unit or building. -laccess.flag = Numeric flag value stored on a unit. -laccess.flying = Whether a unit is currently airborne. -laccess.name = Name of the player controlling this unit, or null. -laccess.payloadcount = Number of payloads currently held. -laccess.payloadtype = Type of the last payload picked up, or null. -laccess.totalpayload = Combined size of all held payloads. -laccess.payloadcapacity = Maximum combined payload size a unit or building can carry. -laccess.selectedblock = Block currently selected by the controlling player, or null. -laccess.selectedrotation = Build rotation currently selected by the controlling player, 0 to 3. -laccess.bulletlifetime = Total lifetime of a bullet, in ticks. -laccess.bullettime = Time a bullet has existed, in ticks. +laccess.totalitems = Общее количество хранимых предметов. +laccess.firstitem = Первый хранимый предмет. Если пусто - возвращает null. +laccess.totalliquids = Общее количество хранимой жидкости. +laccess.totalpower = Для блоков, хранящих энергию, возвращает её количество; для остальных блоков, их уровень энергии от 0 до 1. +laccess.itemcapacity = Максимальное количество предметов, хранимых этой постройкой. +laccess.liquidcapacity = Максимальное количество жидкости, хранимой этой постройкой. +laccess.powercapacity = Максимальное количество энергии, хранимой этой постройкой. +laccess.powernetstored = Общее количество энергии, хранимой в сети. +laccess.powernetcapacity = Максимальное количество энергии, хранимой в сети. +laccess.powernetin = Энергия, входящая в сеть за секунду. +laccess.powernetout = Энергия, выходящая из сети за секунду. +laccess.ammo = Текущее количество боеприпасов в турели. +laccess.ammocapacity = Максимальное количество боеприпасов в турели. +laccess.health = Текущее здоровье.\nДля пуль возвращает их урон. +laccess.maxhealth = Максимальное здоровье.\nДля пуль возвращает их базовый урон. +laccess.heat = Текущий нагрев турели, от 0 до 1. +laccess.shield = Общее количество щита у юнита. +laccess.armor = Значение брони; на сколько снизится получаемый урон за удар. +laccess.efficiency = Эффективность работы постройки. 1 - обычная эффективность. +laccess.timescale = Множитель скорости, применённый на эту постройку. 1 - обычная скорость. +laccess.rotation = Угол направления юнита или турели в градусах.\nДля большинства других построек возвращает 0-3 в зависимости от их направления. +laccess.x = Позиция X блока/юнита в блоках. +laccess.y = Позиция Y блока/юнита в блоках. +laccess.velocityx = Скорость юнита по X в блоках/сек. +laccess.velocityy = Скорость юнита по Y в блоках/сек. +laccess.shootx = Позиция X, в которую нацелен юнит или турель. +laccess.shooty = Позиция Y, в которую нацелен юнит или турель. +laccess.camerax = Позиция X камеры управляющего игрока. +laccess.cameray = Позиция Y камеры управляющего игрока. +laccess.camerawidth = Ширина камеры управляющего игрока в блоках. +laccess.cameraheight = Высота камеры управляющего игрока в блоках. +laccess.solid = Блокирует ли этот блок движение. +laccess.range = Радиус юнита или турели в блоках. +laccess.shooting = Стреляет ли юнит/турель в данный момент. +laccess.boosting = Летает ли этот наземный юнит. +laccess.minex = Позиция X руды, которую сейчас добывает юнит, или -1, если не добывает. +laccess.miney = Позиция Y руды, которую сейчас добывает юнит, или -1, если не добывает. +laccess.mining = Добывает ли юнит руду. +laccess.buildx = Позиция X, на которой сейчас строит юнит, или -1, если не строит. +laccess.buildy = Позиция Y, на которой сейчас строит юнит, или -1, если не строит. +laccess.pingx = Позиция X отметки, поставленной игроком, или null, если отметки нет. +laccess.pingy = Позиция Y отметки, поставленной игроком, или null, если отметки нет. +laccess.pingtext = Текст отметки, поставленной игроком, или null, если отметки нет. +laccess.building = Блок, который сейчас строится юнитом, или null. +laccess.breaking = Блок, который сейчас разбирается юнитом, или null. +laccess.team = ID команды юнита/блока. +laccess.flag = Числовой флаг, назначенный юниту. +laccess.flying = Летает ли этот юнит. +laccess.name = Имя управляющего игрока, или null. +laccess.payloadcount = Количество перевозимых грузов. +laccess.payloadtype = Тип последнего подобранного груза, или null. +laccess.totalpayload = Суммарный размер всех перевозимых грузов. +laccess.payloadcapacity = Максимальный суммарный размер всех перевозимых грузов юнита. +laccess.selectedblock = Блок, выбранный управляющим игроком, или null. +laccess.selectedrotation = Вращение блока, выбранного управляющим игроком, от 0 до 3. +laccess.bulletlifetime = Максимальное время жизни пули в тиках. +laccess.bullettime = Время существования пули в тиках. lcategory.unknown = Неизвестно lcategory.unknown.description = Нет категории. @@ -3496,9 +3496,9 @@ name.token.global = глобальный name.token.target = цель name.token.and = и name.token.or = или -name.token.b-and = бит-и -name.token.xor = ис-или -name.token.flip = бит-не +name.token.b-and = b-and +name.token.xor = xor +name.token.flip = flip name.token.order = порядок name.token.sort = сортировка name.token.output = выход @@ -3509,8 +3509,8 @@ name.token.find = найти name.token.group = группа name.token.enemy = враг? name.token.ore = руда -name.token.outX = X -name.token.outY = Y +name.token.outX = X цели +name.token.outY = Y цели name.token.owner = владелец name.token.found = найден? name.token.building = постройка @@ -3532,7 +3532,7 @@ name.token.natural = естественная name.token.speed = скорость name.token.level = уровень name.token.duration = длительность -name.token.seconds = seconds +name.token.seconds = секунд name.token.shown = отображается name.token.data = данные name.token.effect = эффект @@ -3599,7 +3599,7 @@ name.token.blockFall = падение блока name.token.placeBlock = размещение блока name.token.placeBlockSpark = размещение блока (искры) name.token.breakBlock = разрушение блока -name.token.-spawn = = spawn +name.token.-spawn = = создать name.token.trail = след name.token.breakProp = разрушение валуна name.token.smokeCloud = облако дыма From 78921a064e7766fb528d654d0dbdcc0dcd2cfab4 Mon Sep 17 00:00:00 2001 From: Vector <106137239+Vect0r0@users.noreply.github.com> Date: Sun, 20 Sep 2026 07:21:19 -0600 Subject: [PATCH 22/25] Update bundle_es.properties (#12672) * Update bundle_es.properties * Update bundle_es.properties * Update bundle_es.properties * sensor descriptions * Update bundle_es.properties * Update bundle_es.properties * Update bundle_es.properties * Update bundle_es.properties --- core/assets/bundles/bundle_es.properties | 360 +++++++++++------------ 1 file changed, 180 insertions(+), 180 deletions(-) diff --git a/core/assets/bundles/bundle_es.properties b/core/assets/bundles/bundle_es.properties index a358da10d5..869badf512 100644 --- a/core/assets/bundles/bundle_es.properties +++ b/core/assets/bundles/bundle_es.properties @@ -838,7 +838,7 @@ objective.destroyblock.name = Destruir bloque objective.destroyblocks.name = Destruir bloques objective.destroycore.name = Destruir núcleo objective.commandmode.name = Modo comando -objective.flag.name = Etiqueta +objective.flag.name = Flag marker.shapetext.name = Forma del texto marker.point.name = Punto @@ -1238,7 +1238,7 @@ stat.reactive = Reacciona con stat.immunities = Inmune a stat.healing = Curación stat.status = Efecto de estado -stat.efficiency = [stat]{0}% Eficiencia +stat.efficiency = {0}% Eficiencia stat.chance = [stat]{0}%[lightgray] probabilidad de [white] stat.hitsize = Tamaño de Unidad stat.resettime = Tiempo de Reinicio @@ -1299,7 +1299,7 @@ bar.cargounitcap = Se alcanzó el límite de carga de unidades bar.drillspeed = Velocidad del taladro: {0}/s bar.pumpspeed = Velocidad de bombeado: {0}/s bar.efficiency = Eficiencia: {0}% -bar.yield = Yield: +{0}% +bar.yield = Producción: {0}% bar.boost = Aceleración: +{0}% bar.powerbuffer = Poder en baterías: {0}/{1} bar.powerbalance = Energía: {0}/s @@ -1319,7 +1319,7 @@ bar.nevermelts = nunca hace fusión bar.heatamount = Calor: {0} bar.heatpercent = Calor: {0} ({1}%) bar.power = Energía -bar.progress = Construyendo... +bar.progress = {0}% Construido bar.loadprogress = Progreso bar.launchcooldown = Recarga de lanzamiento bar.input = Entrada @@ -1990,8 +1990,8 @@ block.metal-tiles-13.name = Casilla de metal 13 block.metal-wall-1.name = Muro de metal 1 block.metal-wall-2.name = Muro de metal 2 block.metal-wall-3.name = Muro de metal 3 -block.colored-floor.name = Piso coloreado -block.colored-wall.name = Muro coloreado +block.colored-floor.name = Suelo de Color +block.colored-wall.name = Muro de Color block.character-overlay.name = Caracter block.character-overlay-white.name = Caracter (Blanco) block.rune-overlay.name = Runa @@ -2757,7 +2757,7 @@ block.ship-refabricator.description = Mejora al segundo nivel la nave selecciona block.mech-refabricator.description = Mejora al segundo nivel el mech seleccionado. block.prime-refabricator.description = Mejora al tercer nivel las unidades entrantes. block.basic-assembler-module.description = Incrementa el nivel del ensamblador si se coloca junto a un área de construcción. Requiere energía. Se puede usar como entrada de un cargador. -block.small-deconstructor.description = Deconstruye las estructuras y unidades entrantes. Devuelve el 100% de su coste de construcción. +block.small-deconstructor.description = Deconstruye las estructuras y unidades entrantes. Devuelve el 100% de su coste de construcción. Guarda los objetos en diferentes capacidades de objetos. block.reinforced-payload-conveyor.description = Mueve los lotes de carga en una dirección. block.reinforced-payload-router.description = Distribuye las cargas a los bloques adyacentes. Funcionará como un clasificador si se le establece un filtro. block.payload-mass-driver.description = Estructura de transporte de carga de largo alcance. Dispara las cargas entrantes a otras catapultas enlazadas. @@ -2945,63 +2945,63 @@ laccess.displayheight = Alto de un bloque de pantalla, en pixeles. laccess.buffersize = Número de comandos sin ejecutar en el buffer gráfico de una pantalla. laccess.operations = Número de operaciones ejecutadas en el bloque.\nPara pantallas, retorna el número de operaciones drawflush. laccess.maxunits = Unidades máximas que un equipo puede tener.\nSolo puede ser obtenido de los núcleos. -laccess.totalitems = Total number of items contained. -laccess.firstitem = First item contained, or null if empty. -laccess.totalliquids = Total amount of liquid contained. -laccess.totalpower = For blocks with a buffered power store, the amount of power stored; for other blocks, buffer fullness from 0 to 1. -laccess.itemcapacity = Maximum number of items this building can hold. -laccess.liquidcapacity = Maximum amount of liquid this building can hold. -laccess.powercapacity = Maximum amount of power this building can store. -laccess.powernetstored = Total power stored in the connected power grid. -laccess.powernetcapacity = Total power storage capacity of the connected power grid. -laccess.powernetin = Power entering the connected power grid, per second. -laccess.powernetout = Power leaving the connected power grid, per second. -laccess.ammo = Current ammo count of a turret. -laccess.ammocapacity = Maximum ammo count of a turret. -laccess.health = Current health.\nFor bullets, their damage. -laccess.maxhealth = Maximum health.\nFor bullets, the base damage. -laccess.heat = Current heat of a turret that consumes heat, 0 to 1. -laccess.shield = Current shield amount of a unit. -laccess.armor = Armor value; flat damage reduction per hit. -laccess.efficiency = Operating efficiency of a building, where 1 is nominal. -laccess.timescale = Time scale multiplier affecting a building, where 1 is normal speed. -laccess.rotation = Facing angle of a unit or turret, in degrees.\nFor most other buildings, the 0 to 3 orientation. -laccess.x = X position, in tiles. -laccess.y = Y position, in tiles. -laccess.velocityx = X velocity of a unit, in tiles/sec. -laccess.velocityy = Y velocity of a unit, in tiles/sec. -laccess.shootx = X coordinate a unit or turret is aiming at. -laccess.shooty = Y coordinate a unit or turret is aiming at. -laccess.camerax = X position of the controlling player's camera. -laccess.cameray = Y position of the controlling player's camera. -laccess.camerawidth = Width of the controlling player's view, in tiles. -laccess.cameraheight = Height of the controlling player's view, in tiles. -laccess.solid = Whether this building blocks movement. -laccess.range = Range of a unit or turret, in tiles. -laccess.shooting = Whether a unit or turret is currently shooting. -laccess.boosting = Whether a unit is currently boosting or flying over terrain. -laccess.minex = X tile coordinate a unit is mining, or -1 if not mining. -laccess.miney = Y tile coordinate a unit is mining, or -1 if not mining. -laccess.mining = Whether a unit is currently mining. -laccess.buildx = X tile coordinate a unit is building at, or -1 if not building. -laccess.buildy = Y tile coordinate a unit is building at, or -1 if not building. -laccess.pingx = X coordinate a player is pinging, or null if not pinging. -laccess.pingy = Y coordinate a player is pinging, or null if not pinging. -laccess.pingtext = Text of a player's current ping, or null if not pinging. -laccess.building = Building a unit is currently constructing, or null. -laccess.breaking = Building a unit is currently deconstructing, or null. -laccess.team = Team ID of a unit or building. -laccess.flag = Numeric flag value stored on a unit. -laccess.flying = Whether a unit is currently airborne. -laccess.name = Name of the player controlling this unit, or null. -laccess.payloadcount = Number of payloads currently held. -laccess.payloadtype = Type of the last payload picked up, or null. -laccess.totalpayload = Combined size of all held payloads. -laccess.payloadcapacity = Maximum combined payload size a unit or building can carry. -laccess.selectedblock = Block currently selected by the controlling player, or null. -laccess.selectedrotation = Build rotation currently selected by the controlling player, 0 to 3. -laccess.bulletlifetime = Total lifetime of a bullet, in ticks. -laccess.bullettime = Time a bullet has existed, in ticks. +laccess.totalitems = Número total de items dentro. +laccess.firstitem = Primer item dentro, Devuelve null si se encuentra vacío. +laccess.totalliquids = Cantidad total de líquido contenido. +laccess.totalpower = Para bloques con la capacidad de almacenar energía, la cantidad de energía almacenada; para otros bloques, de 0 a 1. +laccess.itemcapacity = Número total de items que esta construcción o unidad puede almacenar. +laccess.liquidcapacity = Tamaño máximo de liquido que esta construcción puede almacenar. +laccess.powercapacity = Cantidad máxima de energía que esta construcción puede almacenar. +laccess.powernetstored = Total de energía almacenada en la red de energía conectada. +laccess.powernetcapacity = Capacidad de almacenamiento total en la red de energía conectada. +laccess.powernetin = Energía que entra en la red de energía conectada, por segundo. +laccess.powernetout = Energía que abandona la red de energía conectada, por segundo. +laccess.ammo = Cantidad de munición actual de una torreta. +laccess.ammocapacity = Cantidad de munición máxima de una torreta. +laccess.health = Salud actual.\nPara balas, su daño. +laccess.maxhealth = Salud máxima.\nPara balas, su daño base. +laccess.heat = Calor actual de una torreta que puede usarlo, 0 a 1. +laccess.shield = Cantidad de escudo actual de una unidad. +laccess.armor = Valor de armadura; reducción plana de daño por golpe. +laccess.efficiency = Eficiencia operativa de la construcción, donde 1 es el valor nominal. +laccess.timescale = Multiplicador de escala de tiempo afectando a la construcción, donde 1 es la velocidad normal. +laccess.rotation = El ángulo al que está mirando una unidad o torreta, en grados.\nPara muchas de las otras construcciones, la orientación de 0 a 3. +laccess.x = Posición X, en casillas. +laccess.y = Posición Y, en casillas. +laccess.velocityx = Velocidad horizontal de una unidad, en casillas/segundo. +laccess.velocityy = Velocidad vertical de una unidad, en casillas/segundo. +laccess.shootx = Coordenada X a la cual una unidad o torreta está apuntando. +laccess.shooty = Coordenada Y a la cual una unidad o torreta está apuntando. +laccess.camerax = Posición X de la camara del jugador que está controlando. +laccess.cameray = Posición Y de la camara del jugador que está controlando. +laccess.camerawidth = Ancho de la vista del jugador que está controlando, en casillas. +laccess.cameraheight = Largo de la vista del jugador que está controlando, en casillas. +laccess.solid = Si una construcción bloquea el movimiento sobre de ella. +laccess.range = Rango de una unidad o torreta, en casillas. +laccess.shooting = Si una unidad o torreta se encuentra disparando. +laccess.boosting = Si una unidad está volando sobrevolando o volando sobre el terreno. +laccess.minex = Coordenada X de la casilla en la cual una unidad está minando, o -1 si no está minando. +laccess.miney = Coordenada Y de la casilla en la cual una unidad está minando, o -1 si no está minando. +laccess.mining = Si una unidad se encuentra minando. +laccess.buildx = Coordenada X de la casilla en la cual una unidad está construyendo, o -1 si no está construyendo. +laccess.buildy = Coordenada Y de la casilla en la cual una unidad está construyendo, o -1 si no está construyendo. +laccess.pingx = Coordenada X en la cual un jugador esta pingeando, o null si no está pingeando. +laccess.pingy = Coordenada Y en la cual un jugador está pingeando, o null si no está pingeando. +laccess.pingtext = Texto del ping actual de un jugador, o null si no está pingeando. +laccess.building = Construcción que la unidad está construyendo actualmente, o null. +laccess.breaking = Construcción que la unidad está deconstruyendo actualmente, o null. +laccess.team = Identificador de equipo de una unidad o construcción. +laccess.flag = Valor numérico o flag almacenada en una unidad. +laccess.flying = Si la unidad se encuentra volando. +laccess.name = Nombre del jugador controlando esta unidad, o null. +laccess.payloadcount = Numero de carga que se lleva actualmente. +laccess.payloadtype = Tipo de la última carga recogida, o null. +laccess.totalpayload = Tamaño combinado de toda la carga llevada. +laccess.payloadcapacity = Tamaño máximo combinado que una unidad o construcción pueden cargar. +laccess.selectedblock = Bloque seleccionado actualmente por el jugador que está controlando, o null. +laccess.selectedrotation = Rotación del bloque actualmente seleccionado por el jugador que está controland, de 0 a 3. +laccess.bulletlifetime = Tiempo de vida total de una bala, en ticks. +laccess.bullettime = Tiempo que una bala ha existido, en ticks. lcategory.unknown = Desconocido lcategory.unknown.description = Instrucciones no clasificadas. @@ -3186,8 +3186,8 @@ instruction.print = Agregar texto instruction.printchar = Agregar Carácter instruction.format = Reemplazar Formato instruction.drawflush = Dibujar Gráficos -instruction.printflush = Imprimir -instruction.getlink = Obtener Enlazados +instruction.printflush = Imprimir Texto +instruction.getlink = Obtener Enlazado instruction.control = Controlar instruction.radar = Radar instruction.sensor = Sensor @@ -3195,9 +3195,9 @@ instruction.set = Asignar instruction.operation = Operación instruction.select = Seleccionar instruction.wait = Esperar -instruction.stop = Detener +instruction.stop = Detener Ejecución instruction.lookup = Buscar -instruction.jump = Salto Condicional +instruction.jump = Jump instruction.end = Terminar instruction.unitbind = Vincular Unidad instruction.unitcontrol = Controlar Unidad @@ -3206,31 +3206,31 @@ instruction.unitlocate = Localizar con Unidad instruction.query = Query instruction.getblock = Obtener Bloque instruction.setblock = Crear Bloque -instruction.spawnunit = Aparecer Unidad -instruction.spawnbullet = Aparecer Bala +instruction.spawnunit = Crear Unidad +instruction.spawnbullet = Crear Bala instruction.applystatus = Aplicar Estado -instruction.weathersense = Detectar Clima +instruction.weathersense = Obtener Clima instruction.weatherset = Establecer Clima -instruction.spawnwave = Aparecer Oleada +instruction.spawnwave = Generar Oleada instruction.setrule = Cambiar Regla -instruction.flushmessage = Flush Message +instruction.flushmessage = Mostrar Mensaje instruction.cutscene = Cinematica instruction.effect = Efecto instruction.explosion = Explosion -instruction.setrate = Set Rate +instruction.setrate = Establecer Velocidad instruction.fetch = Buscar instruction.sync = Sincronizar instruction.clientdata = Datos del Cliente -instruction.getflag = Get Flag -instruction.setflag = Set Flag -instruction.setprop = Set Prop +instruction.getflag = Obtener Flag Global +instruction.setflag = Asignar Flag Global +instruction.setprop = Asignar Propiedad instruction.playsound = Reproducir Sonido instruction.playmusic = Reproducir Musica instruction.setmarker = Set Marker instruction.makemarker = Make Marker instruction.localeprint = Locale Print -instruction.packcolor = Desagrupar Color -instruction.unpackcolor = Agrupar Color +instruction.packcolor = Agrupar Color +instruction.unpackcolor = Desagrupar Color instruction.invalid = Instrucción Invalida # Implemented via the enumText() method blockflag.label.core = núcleos @@ -3263,22 +3263,22 @@ fetchtype.label.unitcount = cantidad de unidades fetchtype.label.playercount = cantidad de jugadores fetchtype.label.corecount = cantidad de núcleos fetchtype.label.buildcount = cantidad de construcciones -graphicstype.label.clear = clear +graphicstype.label.clear = llenar graphicstype.label.color = color graphicstype.label.col = col -graphicstype.label.stroke = stroke -graphicstype.label.line = line -graphicstype.label.rect = rect -graphicstype.label.linerect = line rect -graphicstype.label.poly = poly -graphicstype.label.linepoly = line poly -graphicstype.label.triangle = triangle -graphicstype.label.image = image -graphicstype.label.print = print +graphicstype.label.stroke = ancho +graphicstype.label.line = linea +graphicstype.label.rect = rectangulo +graphicstype.label.linerect = lineas rect +graphicstype.label.poly = poligono +graphicstype.label.linepoly = lineas poly +graphicstype.label.triangle = triangulo +graphicstype.label.image = imágen +graphicstype.label.print = texto graphicstype.label.translate = translate -graphicstype.label.scale = scale -graphicstype.label.rotate = rotate -graphicstype.label.reset = reset +graphicstype.label.scale = escalar +graphicstype.label.rotate = rotar +graphicstype.label.reset = reiniciar laccess.label.totalitems = total de objetos laccess.label.firstitem = primer objeto laccess.label.totalliquids = liquido total @@ -3318,27 +3318,27 @@ laccess.label.displayheight = largo de pantalla laccess.label.buffersize = tamaño de buffer laccess.label.operations = operaciones laccess.label.size = tamaño -laccess.label.solid = ¿solido? -laccess.label.dead = ¿muerto? +laccess.label.solid = solido? +laccess.label.dead = muerto? laccess.label.range = rango -laccess.label.shooting = ¿disparando? -laccess.label.boosting = ¿sobrevolando? +laccess.label.shooting = disparando? +laccess.label.boosting = sobrevolando? laccess.label.minex = minando x laccess.label.miney = minando y -laccess.label.mining = ¿minando? +laccess.label.mining = minando? laccess.label.buildx = construyendo x laccess.label.buildy = construyendo y laccess.label.pingx = ping x laccess.label.pingy = ping y laccess.label.pingtext = texto en ping -laccess.label.building = ¿construyendo? -laccess.label.breaking = ¿deconstruyendo? +laccess.label.building = construyendo? +laccess.label.breaking = deconstruyendo? laccess.label.speed = velocidad laccess.label.team = equipo laccess.label.type = tipo laccess.label.flag = flag -laccess.label.flying = ¿puede volar? -laccess.label.controlled = ¿controlada? +laccess.label.flying = puede volar? +laccess.label.controlled = controlada? laccess.label.controller = controlador laccess.label.name = nombre laccess.label.payloadcount = conteo de carga @@ -3351,7 +3351,7 @@ laccess.label.selectedblock = bloque seleccionado laccess.label.selectedrotation = rotación seleccionada laccess.label.bulletlifetime = tiempo de vida de la bala laccess.label.bullettime = tiempo de bala -laccess.label.enabled = ¿activado? +laccess.label.enabled = activado? laccess.label.shoot = disparo laccess.label.shootp = disparo con predicción laccess.label.config = configuración @@ -3387,17 +3387,17 @@ lmarkercontrol.label.posi = posi lmarkercontrol.label.uvi = uvi lmarkercontrol.label.colori = colori logicrule.label.currentwavetime = tiempo restante oleada actual -logicrule.label.wavetimer = ¿temporizador de oleada? -logicrule.label.waves = ¿oleadas activas? +logicrule.label.wavetimer = temporizador de oleada? +logicrule.label.waves = oleadas activas? logicrule.label.wave = oleada logicrule.label.wavespacing = tiempo entre oleadas -logicrule.label.wavesending = ¿adelantar oleada? -logicrule.label.attackmode = ¿modo de juego ataque? +logicrule.label.wavesending = enviar oleadas? +logicrule.label.attackmode = modo de juego ataque? logicrule.label.enemycorebuildradius = radio de construccion de núcleo enemiga logicrule.label.dropzoneradius = radio de zona de aparición logicrule.label.unitcap = capacidad de unidades logicrule.label.maparea = area del mapa -logicrule.label.lighting = ¿iluminación? +logicrule.label.lighting = iluminación? logicrule.label.cangameover = se puede perder logicrule.label.ambientlight = iluminación ambiental logicrule.label.unitlight = iluminación de unidad @@ -3405,7 +3405,7 @@ logicrule.label.solarmultiplier = multiplicador solar logicrule.label.dragmultiplier = multiplicador de arrastre logicrule.label.ban = banear logicrule.label.unban = desbanear -logicrule.label.pausedisabled = ¿desactivar pausa? +logicrule.label.pausedisabled = desactivar pausa? logicrule.label.musicvolume = volumen de la música logicrule.label.buildspeed = velocidad de construcción logicrule.label.unithealth = salud de unidad @@ -3421,29 +3421,29 @@ lunitcontrol.label.idle = inactiva lunitcontrol.label.stop = detenerse lunitcontrol.label.unbind = desvincular lunitcontrol.label.move = mover -lunitcontrol.label.approach = aproximar -lunitcontrol.label.pathfind = encontrarRuta -lunitcontrol.label.autopathfind = encontrarRuta auto -lunitcontrol.label.target = target -lunitcontrol.label.targetp = target predict +lunitcontrol.label.approach = acercar +lunitcontrol.label.pathfind = seguir ruta +lunitcontrol.label.autopathfind = auto-seguir ruta +lunitcontrol.label.target = disparar +lunitcontrol.label.targetp = disparar con predicción lunitcontrol.label.itemdrop = soltar objeto lunitcontrol.label.itemtake = tomar objeto lunitcontrol.label.paydrop = soltar carga lunitcontrol.label.paytake = tomar carga lunitcontrol.label.payenter = entrar como carga -lunitcontrol.label.flag = etiqueta +lunitcontrol.label.flag = flag lunitcontrol.label.mine = minar lunitcontrol.label.build = construir bloque lunitcontrol.label.getblock = obtener bloque lunitcontrol.label.deconstruct = deconstruir -lunitcontrol.label.within = ¿dentro de? -lunitcontrol.label.boost = ¿potenciar? +lunitcontrol.label.within = dentro de? +lunitcontrol.label.boost = sobrevolar? messagetype.label.notify = notify messagetype.label.announce = announce messagetype.label.toast = toast messagetype.label.mission = mission -querytype.label.unit = unit -querytype.label.building = building +querytype.label.unit = unidad +querytype.label.building = construcción radarsort.label.distance = distancia radarsort.label.health = salud radarsort.label.maxhealth = salud máxima @@ -3457,40 +3457,40 @@ radartarget.label.attacker = unidad armada radartarget.label.flying = unidad aérea radartarget.label.ground = unidad terrestre radartarget.label.boss = boss -tilelayer.label.floor = floor -tilelayer.label.ore = ore -tilelayer.label.block = block -tilelayer.label.building = building +tilelayer.label.floor = suelo +tilelayer.label.ore = mineral +tilelayer.label.block = bloque +tilelayer.label.building = construcción name.token.color = color -name.token.width = width -name.token.height = height -name.token.sides = sides -name.token.radius = radius -name.token.rotation = rotation -name.token.image = image -name.token.size = size -name.token.align = align -name.token.set = crear -name.token.of = of +name.token.width = ancho +name.token.height = largo +name.token.sides = lados +name.token.radius = radio +name.token.rotation = rotación +name.token.image = imagen +name.token.size = tamaño +name.token.align = alinear +name.token.set = asigna +name.token.of = de name.token.to = a name.token.at = en name.token.in = en name.token.damage = daño -name.token.velocityScl = velocity scale -name.token.lifeScl = life scale -name.token.aimX = aim X -name.token.aimY = aim Y -name.token.read = read -name.token.write = write -name.token.from = from -name.token.char = char -name.token.linknum = link# -name.token.draw = draw -name.token.clear = clear -name.token.apply = apply -name.token.circle = circle -name.token.rect = rect +name.token.velocityScl = escala de velocidad +name.token.lifeScl = escala de salud +name.token.aimX = apuntar X +name.token.aimY = apuntar Y +name.token.read = lee +name.token.write = escribe +name.token.from = de +name.token.char = carácter +name.token.linknum = link\# +name.token.draw = dibujar +name.token.clear = limpiar +name.token.apply = aplicar +name.token.circle = circulo +name.token.rect = recta name.token.positional = posicional name.token.global = global name.token.target = objetivo @@ -3507,43 +3507,43 @@ name.token.then = then name.token.else = else name.token.find = localizar name.token.group = grupo -name.token.enemy = ¿enemigo? +name.token.enemy = enemigo? name.token.ore = mineral name.token.outX = X obtenida name.token.outY = Y obtenida name.token.owner = owner -name.token.found = ¿encontrado? +name.token.found = encontrado? name.token.building = construcción name.token.always = always name.token.not = not -name.token.pack = pack -name.token.unpack = unpack -name.token.-lookup = = lookup -name.token.type = type +name.token.pack = agrupar +name.token.unpack = desagrupar +name.token.-lookup = = bucar +name.token.type = tipo name.token.get = get -name.token.team = team -name.token.angle = angle -name.token.spawn = spawn -name.token.-bullet = = bullet -name.token.unit = unit -name.token.weather = weather -name.token.state = state +name.token.team = equipo +name.token.angle = ángulo +name.token.spawn = crear +name.token.-bullet = = bala +name.token.unit = unidad +name.token.weather = clima +name.token.state = estado name.token.natural = natural name.token.speed = speed name.token.level = level -name.token.duration = duration -name.token.seconds = seconds +name.token.duration = duración +name.token.seconds = segundos name.token.shown = shown name.token.data = data -name.token.effect = effect -name.token.pierce = pierce -name.token.ground = ground +name.token.effect = efecto +name.token.pierce = atraviesa +name.token.ground = terrestre name.token.air = air name.token.flag = flag -name.token.volume = volume +name.token.volume = volumen name.token.pitch = pitch name.token.pan = pan -name.token.limit = limit +name.token.limit = limite name.token.id = id # name.token.replace = replace? name.token.for = for @@ -3562,13 +3562,13 @@ name.token.name = name name.token.index = index name.token.block-unit = block/unit name.token.enable = enable -name.token.amount = amount +name.token.amount = cantidad name.token.item = item -name.token.takeUnits = take units +name.token.takeUnits = tomar unidades? name.token.value = value name.token.floor = floor name.token.result = resultado -name.token.config = config +name.token.config = configuración name.token.shapeText = shape text name.token.point = point name.token.shape = shape @@ -3577,12 +3577,12 @@ name.token.line = line name.token.texture = texture name.token.quad = quad name.token.light = light -name.token.snowing = snowing -name.token.rain = rain -name.token.sandstorm = sand storm -name.token.sporestorm = spore storm -name.token.fog = fog -name.token.suspend-particles = suspended particles +name.token.snowing = nevando +name.token.rain = lloviendo +name.token.sandstorm = tormenta de arena +name.token.sporestorm = tormenta de esporas +name.token.fog = neblina +name.token.suspend-particles = particulas suspendidas name.token.topLeft = top left name.token.top = top name.token.topRight = top right @@ -3626,15 +3626,15 @@ name.token.sparkExplosion = explosión con chispas name.token.crossExplosion = explosión con cruz name.token.wave = oleada name.token.bubble = burbuja -name.token.music = music -name.token.interrupt = interrupt +name.token.music = musica +name.token.interrupt = interrumpe name.token.all = Todos name.token.beams = Rayos -name.token.block = Bloques +name.token.block = bloque name.token.charge = Carga name.token.environment = Clima name.token.explosions = Explosiones name.token.loops = Bucles name.token.movement = Movimiento -name.token.shoot = Disparos -name.token.ui = Interfaz Usuario +name.token.shoot = disparar +name.token.ui = Interfaz de Usuario From 2541682beede1dc391ca927ddd9d2c8024880a5b Mon Sep 17 00:00:00 2001 From: Kevin Vilyan <146146416+Kev-Vily@users.noreply.github.com> Date: Sun, 20 Sep 2026 20:21:29 +0700 Subject: [PATCH 23/25] Update Bundle ID (#12693) --- core/assets/bundles/bundle_id_ID.properties | 138 ++++++++++---------- 1 file changed, 69 insertions(+), 69 deletions(-) diff --git a/core/assets/bundles/bundle_id_ID.properties b/core/assets/bundles/bundle_id_ID.properties index dc5d8c72d7..170fee8ea9 100644 --- a/core/assets/bundles/bundle_id_ID.properties +++ b/core/assets/bundles/bundle_id_ID.properties @@ -882,7 +882,7 @@ bannedunits.whitelist = Unit yang Dilarang Sebagai Whitelist bannedblocks.whitelist = Blok yang Dilarang Sebagai Whitelist addall = Tambah Semua launch.from = Meluncurkan Dari: [accent]{0} -launch.capacity = Kapasitas item yang Diluncurkan: [accent]{0} +launch.capacity = Kapasitas Item yang Diluncurkan: [accent]{0} launch.destination = Destinasi: {0} landing.sources = Total Sumber Sektor: [accent]{0}[] landing.import = Total Impor Maksimum: {0}[accent]{1}[lightgray]/mnt @@ -1074,7 +1074,7 @@ sector.caldera-erekir.description = Sumber daya yang terdeteksi di sektor ini te sector.stronghold.description = Markas musuh yang besar di sektor ini menjaga simpanan [accent]torium[] dalam jumlah besar.\nGunakan itu untuk mengembangkan unit dan menara ke tingkat yang lebih tinggi. sector.crevice.description = Musuh akan mengirimkan pasukan serangan yang hebat untuk menghancurkan markasmu di sektor ini.\nKembangkan [accent]karbida[] dan [accent]Generator Pirolisis[] mungkin imperatif untuk bertahan hidup. sector.siege.description = Sektor ini memiliki dua ngarai paralel yang akan memaksa serangan dari dua arah.\nRiset [accent]sianogen[] untuk mendapatkan kemampuan untuk memproduksi unit tank yang lebih kuat.\nPeringatan: Rudal jarak jauh milik musuh telah terdeteksi. Rudal tersebut mungkin ditembak jatuh sebelum terjadi benturan. -sector.crossroads.description = Markas musuh di sektor ini telah didirikan di berbagai medan. Riset unit yang berbeda untuk beradaptasi.\nSelain itu, beberapa markas telah dilindungi oleh perisai. Cari tahu bagaimana mereka diberi daya. +sector.crossroads.description = Markas musuh di sektor ini telah didirikan di berbagai medan. Riset unit yang berbeda untuk beradaptasi.\nSelain itu, beberapa markas telah dilindungi oleh perisai. Cari tahu bagaimana mereka diberi tenaga. sector.karst.description = Sektor ini kaya akan sumber daya, namun akan diserang oleh musuh begitu inti baru mendarat.\nManfaatkan sumber daya dan riset [accent]fabrik phase[]. sector.origin.description = Sektor terakhir dengan kehadiran musuh yang signifikan.\nTidak ada peluang riset yang tersisa - fokus menghancurkan semua inti musuh. @@ -1299,7 +1299,7 @@ bar.cargounitcap = Kapasitas Unit Kargo Telah Mencapai Batas bar.drillspeed = Kecepatan Bor: {0}/d bar.pumpspeed = Kecepatan Pompa: {0}/d bar.efficiency = Efisiensi: {0}% -bar.yield = Hasil: +{0}% +bar.yield = Hasil: {0}% bar.boost = Pendorongan: +{0}% bar.powerbuffer = Tenaga Baterai: {0}/{1} bar.powerbalance = Tenaga: {0}/d @@ -1447,7 +1447,7 @@ setting.autotarget.name = Bidik Musuh Secara Otomatis setting.autotarget.description = Ketika diaktifkan, unit Anda akan secara otomatis membidik dan menembaki musuh di sekitar. setting.keyboard.name = Kontrol Tetikus+Papan Ketik setting.fpscap.name = Batas FPS -setting.fpscap.description = Mengatur jumlah maksimum bingkai per detik (FPS) saat permainan berjalan.\nNilai yang lebih tinggi dapat meningkatkan konsumsi daya baterai. +setting.fpscap.description = Mengatur jumlah maksimum bingkai per detik (FPS) saat permainan berjalan.\nNilai yang lebih tinggi dapat meningkatkan konsumsi baterai. setting.fpscap.none = Tidak Ada setting.fpscap.text = {0} FPS setting.uiscale.name = Skala UI @@ -2453,7 +2453,7 @@ onset.defenses = [accent]Siapkan pertahanan:[lightgray] {0} onset.attack = Musuh dalam keadaan rentan diserang. Lancarkan serangan balasan. onset.cores = Inti baru dapat ditempatkan di [accent]ubin inti[].\nInti baru berfungsi sebagai pangkalan depan dan berbagi sumber daya dengan inti lainnya.\nTempatkan sebuah :core-bastion: inti. onset.detect = Musuh akan dapat mendeteksi Anda dalam 2 menit.\nSiapkan pertahanan, penambangan, dan produksi. -onset.commandmode = Tahan [accent]shift[] untuk masuk ke[accent]mode perintah[].\n[accent]Klik kiri dan seret[] untuk memilih unit.\n[accent]Klik kanan[] untuk memerintahkan unit yang dipilih untuk bergerak atau menyerang. +onset.commandmode = Tahan [accent]shift[] untuk masuk ke [accent]mode perintah[].\n[accent]Klik kiri dan seret[] untuk memilih unit.\n[accent]Klik kanan[] untuk memerintahkan unit yang dipilih untuk bergerak atau menyerang. onset.commandmode.mobile = Tekan tombol [accent]perintah[] untuk masuk ke [accent]mode perintah[].\nTekan dan tahan jari Anda, lalu [accent]seret[] untuk memilih unit.\n[accent]Ketuk[] untuk memerintahkan unit yang dipilih untuk bergerak atau menyerang. aegis.tungsten = Tungsten dapat ditambang menggunakan [accent]bor tumbukan[].\nBangunan ini memerlukan [accent]air[] dan [accent]tenaga[]. @@ -2686,7 +2686,7 @@ block.smite.description = Menembakan semburan peluru yang menusuk dan menyambar. block.malign.description = Menembakkan rentetan muatan laser pelacak ke arah musuh. Memerlukan pemanasan ekstensif. block.silicon-arc-furnace.description = Memurnikan silikon dari pasir dan grafit. block.oxidation-chamber.description = Mengubah berilium dan ozon menjadi oksida. Memancarkan panas sebagai produk sampingan. -block.electric-heater.description = Pemanas yang menghadap ke arah blok. Memerlukan daya yang besar. +block.electric-heater.description = Pemanas yang menghadap ke arah blok. Memerlukan tenaga yang besar. block.slag-heater.description = Pemanas yang menghadap ke arah blok. Memerlukan lava. block.phase-heater.description = Pemanas yang menghadap ke arah blok. Memerlukan fabrik phase. block.heat-redirector.description = Mengalihkan akumulasi panas ke blok lain. @@ -2700,7 +2700,7 @@ block.carbide-crucible.description = Memadukan grafit dan tungsten menjadi karbi block.cyanogen-synthesizer.description = Mensintesis sianogen dari arkisit dan grafit. Memerlukan panas. block.slag-incinerator.description = Membakar benda atau cairan yang tidak mudah menguap. Memerlukan lava. block.vent-condenser.description = Mengondensasi gas ventilasi menjadi air. Memerlukan tenaga. -block.plasma-bore.description = Saat ditempatkan menghadap dinding bijih, mengeluarkan bahan tanpa batas. Memerlukan daya dalam jumlah kecil. +block.plasma-bore.description = Saat ditempatkan menghadap dinding bijih, mengeluarkan bahan tanpa batas. Memerlukan tenaga dalam jumlah kecil. block.large-plasma-bore.description = Bor plasma yang lebih besar. Mampu menambang tungsten dan torium. Memerlukan hidrogen dan tenaga. block.cliff-crusher.description = Menghancurkan dinding, mengeluarkan pasir tanpa batas. Memerlukan tenaga. Efisiensi bervariasi berdasarkan jenis dinding. block.large-cliff-crusher.description = Menghancurkan dinding, mengeluarkan pasir tanpa batas. Memerlukan tenaga dan hidrogen. Efisiensi bervariasi berdasarkan jenis dinding. Dapat menggunakan grafit untuk meningkatkan efisiensi. @@ -2741,7 +2741,7 @@ block.turbine-condenser.description = Menghasilkan tenaga ketika ditempatkan pad block.chemical-combustion-chamber.description = Menghasilkan tenaga dari arkisit dan ozon. block.pyrolysis-generator.description = Menghasilkan tenaga dalam jumlah besar dari arkisit dan lava. Memproduksi air sebagai produk sampingan. block.flux-reactor.description = Menghasilkan tenaga dalam jumlah besar ketika dipanaskan. Memerlukan sianogen sebagai penstabil. Tenaga yang dihasilkan dan kebutuhan sianogen sebanding dengan panas yang masuk.\nMeledak jika sianogen yang disediakan tidak mencukupi. -block.neoplasia-reactor.description = Menggunakan arkisit, air, dan fabrik phase untuk menghasilkan daya dalam jumlah besar. Menghasilkan panas dan neoplasma yang berbahaya sebagai produk sampingan.\nMeledak jika neoplasma tidak dikeluarkan dari reaktor melalui saluran. +block.neoplasia-reactor.description = Menggunakan arkisit, air, dan fabrik phase untuk menghasilkan tenaga dalam jumlah besar. Menghasilkan panas dan neoplasma yang berbahaya sebagai produk sampingan.\nMeledak jika neoplasma tidak dikeluarkan dari reaktor melalui saluran. block.build-tower.description = Secara otomatis membangun kembali bangunan dalam jangkauan dan membantu unit lain dalam konstruksi. block.regen-projector.description = Perlahan memperbaiki bangunan sekutu di perimeter persegi. Memerlukan hidrogen. Dapat menggunakan fabrik phase untuk meningkatkan efisiensi. block.reinforced-container.description = Menyimpan sejumlah kecil item. Isi kontainer dapat dibongkar melalui pembongkar muatan. Tidak dapat meningkatkan kapasitas penyimpanan inti. @@ -2945,63 +2945,63 @@ laccess.displayheight = Tinggi blok tampilan logika dalam piksel. laccess.buffersize = Untuk pesan: Panjang dari isi pesan.\nUntuk tampilan: Jumlah dari perintah grafis mentah. laccess.operations = Jumlah operasi yang dilakukan pada blok.\nUntuk tampilan, mengembalikan jumlah dari operasi drawflush. laccess.maxunits = Jumlah unit maksimum yang dapat dimiliki sebuah tim.\nHanya dapat dideteksi dari inti. -laccess.totalitems = Total number of items contained. -laccess.firstitem = First item contained, or null if empty. -laccess.totalliquids = Total amount of liquid contained. -laccess.totalpower = For blocks with a buffered power store, the amount of power stored; for other blocks, buffer fullness from 0 to 1. -laccess.itemcapacity = Maximum number of items this building can hold. -laccess.liquidcapacity = Maximum amount of liquid this building can hold. -laccess.powercapacity = Maximum amount of power this building can store. -laccess.powernetstored = Total power stored in the connected power grid. -laccess.powernetcapacity = Total power storage capacity of the connected power grid. -laccess.powernetin = Power entering the connected power grid, per second. -laccess.powernetout = Power leaving the connected power grid, per second. -laccess.ammo = Current ammo count of a turret. -laccess.ammocapacity = Maximum ammo count of a turret. -laccess.health = Current health.\nFor bullets, their damage. -laccess.maxhealth = Maximum health.\nFor bullets, the base damage. -laccess.heat = Current heat of a turret that consumes heat, 0 to 1. -laccess.shield = Current shield amount of a unit. -laccess.armor = Armor value; flat damage reduction per hit. -laccess.efficiency = Operating efficiency of a building, where 1 is nominal. -laccess.timescale = Time scale multiplier affecting a building, where 1 is normal speed. -laccess.rotation = Facing angle of a unit or turret, in degrees.\nFor most other buildings, the 0 to 3 orientation. -laccess.x = X position, in tiles. -laccess.y = Y position, in tiles. -laccess.velocityx = X velocity of a unit, in tiles/sec. -laccess.velocityy = Y velocity of a unit, in tiles/sec. -laccess.shootx = X coordinate a unit or turret is aiming at. -laccess.shooty = Y coordinate a unit or turret is aiming at. -laccess.camerax = X position of the controlling player's camera. -laccess.cameray = Y position of the controlling player's camera. -laccess.camerawidth = Width of the controlling player's view, in tiles. -laccess.cameraheight = Height of the controlling player's view, in tiles. -laccess.solid = Whether this building blocks movement. -laccess.range = Range of a unit or turret, in tiles. -laccess.shooting = Whether a unit or turret is currently shooting. -laccess.boosting = Whether a unit is currently boosting or flying over terrain. -laccess.minex = X tile coordinate a unit is mining, or -1 if not mining. -laccess.miney = Y tile coordinate a unit is mining, or -1 if not mining. -laccess.mining = Whether a unit is currently mining. -laccess.buildx = X tile coordinate a unit is building at, or -1 if not building. -laccess.buildy = Y tile coordinate a unit is building at, or -1 if not building. -laccess.pingx = X coordinate a player is pinging, or null if not pinging. -laccess.pingy = Y coordinate a player is pinging, or null if not pinging. -laccess.pingtext = Text of a player's current ping, or null if not pinging. -laccess.building = Building a unit is currently constructing, or null. -laccess.breaking = Building a unit is currently deconstructing, or null. -laccess.team = Team ID of a unit or building. -laccess.flag = Numeric flag value stored on a unit. -laccess.flying = Whether a unit is currently airborne. -laccess.name = Name of the player controlling this unit, or null. -laccess.payloadcount = Number of payloads currently held. -laccess.payloadtype = Type of the last payload picked up, or null. -laccess.totalpayload = Combined size of all held payloads. -laccess.payloadcapacity = Maximum combined payload size a unit or building can carry. -laccess.selectedblock = Block currently selected by the controlling player, or null. -laccess.selectedrotation = Build rotation currently selected by the controlling player, 0 to 3. -laccess.bulletlifetime = Total lifetime of a bullet, in ticks. -laccess.bullettime = Time a bullet has existed, in ticks. +laccess.totalitems = Jumlah total item yang tersimpan. +laccess.firstitem = Item pertama yang dimuat, atau null jika kosong. +laccess.totalliquids = Jumlah total cairan yang tersimpan. +laccess.totalpower = Untuk blok dengan penyimpanan tenaga berpenyangga (dioda), jumlah tenaga yang tersimpan; untuk blok lainnya, tingkat keterisian penyangga dari 0 hingga 1. +laccess.itemcapacity = Jumlah maksimum item yang dapat disimpan oleh bangunan ini. +laccess.liquidcapacity = Jumlah maksimum cairan yang dapat disimpan oleh bangunan ini. +laccess.powercapacity = Jumlah tenaga maksimum yang dapat disimpan oleh bangunan ini. +laccess.powernetstored = Total Tenaga yang tersimpan dalam jaringan listrik yang terhubung. +laccess.powernetcapacity = Total kapasitas penyimpanan tenaga dari jaringan listrik yang terhubung. +laccess.powernetin = Tenaga yang masuk ke jaringan listrik yang terhubung, per detik. +laccess.powernetout = Tenaga yang keluar dari jaringan listrik yang terhubung, per detik. +laccess.ammo = Jumlah amunisi menara saat ini. +laccess.ammocapacity = Jumlah amunisi maksimum menara. +laccess.health = Nyawa saat ini.\nUntuk peluru, besaran damage-nya. +laccess.maxhealth = Nyawa maksimum.\nUntuk peluru, damage dasar. +laccess.heat = Unit panas saat ini dari menara yang mengonsumsi unit panas, 0 hingga 1. +laccess.shield = Jumlah perisai yang dimiliki oleh unit saat ini. +laccess.armor = Nilai armor; pengurangan damage tetap per serangan. +laccess.efficiency = Efisiensi operasional bangunan, dengan nilai nominal 1. +laccess.timescale = Pengali skala waktu yang memengaruhi bangunan, dengan nilai 1 berarti kecepatan normal. +laccess.rotation = Sudut hadap unit atau turret, dalam derajat.\nUntuk sebagian besar bangunan lainnya, orientasi berkisar antara 0 hingga 3. +laccess.x = Posisi X, dalam satuan ubin. +laccess.y = Posisi Y, dalam satuan ubin. +laccess.velocityx = Kecepatan X suatu unit, dalam satuan ubin/detik. +laccess.velocityy = Kecepatan Y suatu unit, dalam satuan ubin/detik. +laccess.shootx = Koordinat X yang dituju oleh unit atau turret. +laccess.shooty = Koordinat Y yang dituju oleh unit atau turret. +laccess.camerax = Posisi X kamera pemain yang memegang kendali. +laccess.cameray = Posisi Y kamera pemain yang memegang kendali. +laccess.camerawidth = Lebar pandangan pemain yang memegang kendali, dalam satuan ubin. +laccess.cameraheight = Tinggi pandangan pemain yang memegang kendali, dalam satuan ubin. +laccess.solid = Apakah bangunan ini menghalangi pergerakan. +laccess.range = Jangkauan unit atau turret, dalam satuan ubin. +laccess.shooting = Apakah unit atau turret sedang menembak. +laccess.boosting = Apakah unit saat ini sedang mengaktifkan pendorong atau terbang melintasi medan. +laccess.minex = Koordinat ubin X tempat unit sedang menambang, atau -1 jika tidak sedang menambang. +laccess.miney = Koordinat ubin Y tempat unit sedang menambang, atau -1 jika tidak sedang menambang. +laccess.mining = Apakah suatu unit sedang menambang. +laccess.buildx = Koordinat ubin X tempat unit sedang membangun, atau -1 jika tidak sedang membangun. +laccess.buildy = Koordinat ubin Y tempat unit sedang membangun, atau -1 jika tidak sedang membangun. +laccess.pingx = Koordinat X yang sedang ditandai oleh pemain, atau null jika tidak sedang menandai. +laccess.pingy = Koordinat Y yang sedang ditandai oleh pemain, atau null jika tidak sedang menandai. +laccess.pingtext = Teks yang menunjukkan ping pemain saat ini, atau null jika tidak sedang melakukan ping. +laccess.building = Unit yang sedang membangun saat ini, atau null. +laccess.breaking = Unit yang sedang mendekonstruksi saat ini, atau null. +laccess.team = ID Tim dari unit atau bangunan. +laccess.flag = Nilai flag numerik yang disimpan pada unit. +laccess.flying = Apakah suatu unit saat ini sedang berada di udara. +laccess.name = Nama pemain yang mengendalikan unit ini, atau null. +laccess.payloadcount = Jumlah muatan yang saat ini dimiliki. +laccess.payloadtype = Jenis muatan terakhir yang diambil, atau null. +laccess.totalpayload = Ukuran gabungan dari semua muatan yang disimpan. +laccess.payloadcapacity = Ukuran muatan gabungan maksimum yang dapat dibawa oleh unit atau bangunan. +laccess.selectedblock = Blok yang saat ini dipilih oleh pemain yang memegang kendali, atau null. +laccess.selectedrotation = Rotasi bangunan yang saat ini dipilih oleh pemain yang memegang kendali, 0 hingga 3. +laccess.bulletlifetime = Total masa hidup peluru, dalam satuan tick. +laccess.bullettime = Durasi peluru aktif, dalam satuan tick. lcategory.unknown = Tak Diketahui lcategory.unknown.description = Instruksi tanpa kategori. @@ -3282,7 +3282,7 @@ graphicstype.label.reset = atur ulang laccess.label.totalitems = total item laccess.label.firstitem = item pertama laccess.label.totalliquids = total cairan -laccess.label.totalpower = total daya +laccess.label.totalpower = total tenaga laccess.label.itemcapacity = kapasitas item laccess.label.liquidcapacity = kapasitas cairan laccess.label.powercapacity = kapasitas tenaga @@ -3351,7 +3351,7 @@ laccess.label.selectedblock = blok terpilih laccess.label.selectedrotation = rotasi terpilih laccess.label.bulletlifetime = masa aktif peluru laccess.label.bullettime = waktu peluru -laccess.label.enabled = diaktifkan +laccess.label.enabled = aktifkan laccess.label.shoot = tembak laccess.label.shootp = prediksi tembak laccess.label.config = konfig @@ -3456,7 +3456,7 @@ radartarget.label.player = pemain radartarget.label.attacker = penyerang radartarget.label.flying = terbang radartarget.label.ground = darat -radartarget.label.boss = boss +radartarget.label.boss = penjaga tilelayer.label.floor = lantai tilelayer.label.ore = bijih tilelayer.label.block = blok @@ -3637,4 +3637,4 @@ name.token.explosions = ledakan name.token.loops = putaran name.token.movement = pergerakan name.token.shoot = tembakan -name.token.ui = UI +name.token.ui = UI \ No newline at end of file From 067c720a8817c1c9fb586c03898a7d948caaed56 Mon Sep 17 00:00:00 2001 From: Github Actions Date: Sun, 20 Sep 2026 13:22:06 +0000 Subject: [PATCH 24/25] Automatic bundle update --- core/assets/bundles/bundle_es.properties | 2 +- core/assets/bundles/bundle_id_ID.properties | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core/assets/bundles/bundle_es.properties b/core/assets/bundles/bundle_es.properties index 869badf512..322dbae918 100644 --- a/core/assets/bundles/bundle_es.properties +++ b/core/assets/bundles/bundle_es.properties @@ -3485,7 +3485,7 @@ name.token.read = lee name.token.write = escribe name.token.from = de name.token.char = carácter -name.token.linknum = link\# +name.token.linknum = link# name.token.draw = dibujar name.token.clear = limpiar name.token.apply = aplicar diff --git a/core/assets/bundles/bundle_id_ID.properties b/core/assets/bundles/bundle_id_ID.properties index 170fee8ea9..3f682a05f2 100644 --- a/core/assets/bundles/bundle_id_ID.properties +++ b/core/assets/bundles/bundle_id_ID.properties @@ -3637,4 +3637,4 @@ name.token.explosions = ledakan name.token.loops = putaran name.token.movement = pergerakan name.token.shoot = tembakan -name.token.ui = UI \ No newline at end of file +name.token.ui = UI From 580f8f521724b3fb3e4f38b5aca00301574277ac Mon Sep 17 00:00:00 2001 From: Anuken Date: Sun, 20 Sep 2026 13:55:06 -0400 Subject: [PATCH 25/25] Fixed #12697 --- core/src/mindustry/ai/Pathfinder.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/core/src/mindustry/ai/Pathfinder.java b/core/src/mindustry/ai/Pathfinder.java index f2baaaaddb..37b4a9e811 100644 --- a/core/src/mindustry/ai/Pathfinder.java +++ b/core/src/mindustry/ai/Pathfinder.java @@ -8,7 +8,6 @@ import arc.struct.*; import arc.util.TaskQueue; import arc.util.*; import mindustry.annotations.Annotations.*; -import mindustry.content.*; import mindustry.core.*; import mindustry.game.EventType.*; import mindustry.game.*; @@ -263,7 +262,7 @@ public class Pathfinder implements Runnable{ tile.build == null || !solid || tile.block() instanceof CoreBlock ? 0 : Math.min((int)(tile.build.health / 40), 80), tid == 0 && tile.build != null && state.rules.coreCapture ? 255 : tid, //use teamid = 255 when core capture is enabled to mark out derelict structures solid, - tile.floor().isLiquid && tile.block() == Blocks.air, + tile.floor().isLiquid && !tile.block().solid, tile.legSolid(), nearLiquid, nearGround,