From 8ac0949ddf3ae076c5549de90c2f10908cef274c Mon Sep 17 00:00:00 2001 From: Anuken Date: Wed, 25 Dec 2019 14:38:43 -0500 Subject: [PATCH 01/78] Added default liquid turret liquid display --- core/src/mindustry/content/Blocks.java | 9 --------- .../blocks/defense/turrets/LiquidTurret.java | 17 +++++++++++++++++ 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/core/src/mindustry/content/Blocks.java b/core/src/mindustry/content/Blocks.java index 600220abc9..8fe9cdb52f 100644 --- a/core/src/mindustry/content/Blocks.java +++ b/core/src/mindustry/content/Blocks.java @@ -1388,15 +1388,6 @@ public class Blocks implements ContentList{ range = 110f; health = 250 * size * size; shootSound = Sounds.splash; - - drawer = (tile, entity) -> { - Draw.rect(region, tile.drawx() + tr2.x, tile.drawy() + tr2.y, entity.rotation - 90); - - Draw.color(entity.liquids.current().color); - Draw.alpha(entity.liquids.total() / liquidCapacity); - Draw.rect(name + "-liquid", tile.drawx() + tr2.x, tile.drawy() + tr2.y, entity.rotation - 90); - Draw.color(); - }; }}; lancer = new ChargeTurret("lancer"){{ diff --git a/core/src/mindustry/world/blocks/defense/turrets/LiquidTurret.java b/core/src/mindustry/world/blocks/defense/turrets/LiquidTurret.java index caafd51d2f..42336ea1d9 100644 --- a/core/src/mindustry/world/blocks/defense/turrets/LiquidTurret.java +++ b/core/src/mindustry/world/blocks/defense/turrets/LiquidTurret.java @@ -1,5 +1,7 @@ package mindustry.world.blocks.defense.turrets; +import arc.*; +import arc.graphics.g2d.*; import arc.struct.*; import mindustry.entities.*; import mindustry.entities.bullet.*; @@ -16,11 +18,13 @@ import static mindustry.Vars.*; public class LiquidTurret extends Turret{ public ObjectMap ammo = new ObjectMap<>(); + public int liquidRegion; public LiquidTurret(String name){ super(name); hasLiquids = true; activeSound = Sounds.spray; + liquidRegion = reg("-liquid"); } /** Initializes accepted ammo map. Format: [liquid1, bullet1, liquid2, bullet2...] */ @@ -28,6 +32,19 @@ public class LiquidTurret extends Turret{ ammo = OrderedMap.of(objects); } + @Override + public void drawLayer(Tile tile){ + super.drawLayer(tile); + TurretEntity entity = tile.ent(); + + if(Core.atlas.isFound(reg(liquidRegion))){ + Draw.color(entity.liquids.current().color); + Draw.alpha(entity.liquids.total() / liquidCapacity); + Draw.rect(reg(liquidRegion), tile.drawx() + tr2.x, tile.drawy() + tr2.y, entity.rotation - 90); + Draw.color(); + } + } + @Override public void setStats(){ super.setStats(); From 9016c12d16f1820d00fe0c4182057feea3bdf534 Mon Sep 17 00:00:00 2001 From: Anuken Date: Wed, 25 Dec 2019 19:07:04 -0500 Subject: [PATCH 02/78] Made team a separate class --- core/src/mindustry/Vars.java | 2 +- core/src/mindustry/ai/BlockIndexer.java | 24 ++++++------- core/src/mindustry/ai/Pathfinder.java | 14 ++++---- core/src/mindustry/core/GameState.java | 4 +-- core/src/mindustry/core/Logic.java | 2 +- core/src/mindustry/core/Renderer.java | 8 ++--- core/src/mindustry/editor/EditorTile.java | 2 +- core/src/mindustry/editor/EditorTool.java | 2 +- .../mindustry/editor/MapGenerateDialog.java | 2 +- core/src/mindustry/entities/Damage.java | 2 +- core/src/mindustry/entities/Units.java | 10 +++--- .../src/mindustry/entities/type/BaseUnit.java | 2 +- core/src/mindustry/entities/type/Unit.java | 4 +-- .../entities/type/base/BuilderDrone.java | 2 +- core/src/mindustry/game/Gamemode.java | 2 +- core/src/mindustry/game/Team.java | 34 ++++++++++++------- core/src/mindustry/game/Teams.java | 25 +++++--------- core/src/mindustry/io/MapIO.java | 2 +- core/src/mindustry/io/SaveVersion.java | 2 +- core/src/mindustry/io/TypeIO.java | 4 +-- .../mindustry/ui/fragments/HudFragment.java | 2 +- core/src/mindustry/world/Tile.java | 4 +-- .../world/blocks/units/CommandCenter.java | 4 +-- .../src/mindustry/desktop/steam/SStats.java | 6 ++-- .../src/mindustry/server/ServerControl.java | 2 +- tests/src/test/java/ApplicationTests.java | 4 +-- 26 files changed, 86 insertions(+), 85 deletions(-) diff --git a/core/src/mindustry/Vars.java b/core/src/mindustry/Vars.java index 3d034b1d6f..502c78887d 100644 --- a/core/src/mindustry/Vars.java +++ b/core/src/mindustry/Vars.java @@ -242,7 +242,7 @@ public class Vars implements Loadable{ unitGroups = new EntityGroup[Team.all.length]; for(Team team : Team.all){ - unitGroups[team.ordinal()] = entities.add(BaseUnit.class).enableMapping(); + unitGroups[(int) team.id] = entities.add(BaseUnit.class).enableMapping(); } for(EntityGroup group : entities.all()){ diff --git a/core/src/mindustry/ai/BlockIndexer.java b/core/src/mindustry/ai/BlockIndexer.java index e64ad48064..311e7887a7 100644 --- a/core/src/mindustry/ai/BlockIndexer.java +++ b/core/src/mindustry/ai/BlockIndexer.java @@ -103,7 +103,7 @@ public class BlockIndexer{ } private ObjectSet[] getFlagged(Team team){ - return flagMap[team.ordinal()]; + return flagMap[(int) team.id]; } /** @return whether this item is present on this map.*/ @@ -115,11 +115,11 @@ public class BlockIndexer{ public ObjectSet getDamaged(Team team){ returnArray.clear(); - if(damagedTiles[team.ordinal()] == null){ - damagedTiles[team.ordinal()] = new ObjectSet<>(); + if(damagedTiles[(int) team.id] == null){ + damagedTiles[(int) team.id] = new ObjectSet<>(); } - ObjectSet set = damagedTiles[team.ordinal()]; + ObjectSet set = damagedTiles[(int) team.id]; for(Tile tile : set){ if((tile.entity == null || tile.entity.getTeam() != team || !tile.entity.damaged()) || tile.block() instanceof BuildBlock){ returnArray.add(tile); @@ -135,7 +135,7 @@ public class BlockIndexer{ /** Get all allied blocks with a flag. */ public ObjectSet getAllied(Team team, BlockFlag type){ - return flagMap[team.ordinal()][type.ordinal()]; + return flagMap[(int) team.id][type.ordinal()]; } /** Get all enemy blocks with a flag. */ @@ -155,11 +155,11 @@ public class BlockIndexer{ } public void notifyTileDamaged(TileEntity entity){ - if(damagedTiles[entity.getTeam().ordinal()] == null){ - damagedTiles[entity.getTeam().ordinal()] = new ObjectSet<>(); + if(damagedTiles[(int) entity.getTeam().id] == null){ + damagedTiles[(int) entity.getTeam().id] = new ObjectSet<>(); } - ObjectSet set = damagedTiles[entity.getTeam().ordinal()]; + ObjectSet set = damagedTiles[(int) entity.getTeam().id]; set.add(entity.tile); } @@ -287,11 +287,11 @@ public class BlockIndexer{ //fast-set this quadrant to 'occupied' if the tile just placed is already of this team if(tile.getTeam() == data.team && tile.entity != null && tile.block().targetable){ - structQuadrants[data.team.ordinal()].set(quadrantX, quadrantY); + structQuadrants[(int) data.team.id].set(quadrantX, quadrantY); continue; //no need to process futher } - structQuadrants[data.team.ordinal()].set(quadrantX, quadrantY, false); + structQuadrants[(int) data.team.id].set(quadrantX, quadrantY, false); outer: for(int x = quadrantX * quadrantSize; x < world.width() && x < (quadrantX + 1) * quadrantSize; x++){ @@ -299,7 +299,7 @@ public class BlockIndexer{ Tile result = world.ltile(x, y); //when a targetable block is found, mark this quadrant as occupied and stop searching if(result.entity != null && result.getTeam() == data.team){ - structQuadrants[data.team.ordinal()].set(quadrantX, quadrantY); + structQuadrants[(int) data.team.id].set(quadrantX, quadrantY); break outer; } } @@ -308,7 +308,7 @@ public class BlockIndexer{ } private boolean getQuad(Team team, int quadrantX, int quadrantY){ - return structQuadrants[team.ordinal()].get(quadrantX, quadrantY); + return structQuadrants[(int) team.id].get(quadrantX, quadrantY); } private int quadWidth(){ diff --git a/core/src/mindustry/ai/Pathfinder.java b/core/src/mindustry/ai/Pathfinder.java index 4e1212ea6a..9464111cab 100644 --- a/core/src/mindustry/ai/Pathfinder.java +++ b/core/src/mindustry/ai/Pathfinder.java @@ -84,8 +84,8 @@ public class Pathfinder implements Runnable{ } public int debugValue(Team team, int x, int y){ - if(pathMap[team.ordinal()][PathTarget.enemyCores.ordinal()] == null) return 0; - return pathMap[team.ordinal()][PathTarget.enemyCores.ordinal()].weights[x][y]; + if(pathMap[(int) team.id][PathTarget.enemyCores.ordinal()] == null) return 0; + return pathMap[(int) team.id][PathTarget.enemyCores.ordinal()].weights[x][y]; } /** Update a tile in the internal pathfinding grid. Causes a complete pathfinding reclaculation. */ @@ -149,12 +149,12 @@ public class Pathfinder implements Runnable{ public Tile getTargetTile(Tile tile, Team team, PathTarget target){ if(tile == null) return null; - PathData data = pathMap[team.ordinal()][target.ordinal()]; + PathData data = pathMap[(int) team.id][target.ordinal()]; if(data == null){ //if this combination is not found, create it on request - if(!created.get(team.ordinal(), target.ordinal())){ - created.set(team.ordinal(), target.ordinal()); + if(!created.get((int) team.id, target.ordinal())){ + created.set((int) team.id, target.ordinal()); //grab targets since this is run on main thread IntArray targets = target.getTargets(team, new IntArray()); queue.post(() -> createPath(team, target, targets)); @@ -188,7 +188,7 @@ public class Pathfinder implements Runnable{ /** @return whether a tile can be passed through by this team. Pathfinding thread only.*/ private boolean passable(int x, int y, Team team){ int tile = tiles[x][y]; - return PathTile.passable(tile) || (PathTile.team(tile) != team.ordinal() && PathTile.team(tile) != Team.derelict.ordinal()); + return PathTile.passable(tile) || (PathTile.team(tile) != (int) team.id && PathTile.team(tile) != (int) Team.derelict.id); } /** @@ -238,7 +238,7 @@ public class Pathfinder implements Runnable{ PathData path = new PathData(team, target, world.width(), world.height()); list.add(path); - pathMap[team.ordinal()][target.ordinal()] = path; + pathMap[(int) team.id][target.ordinal()] = path; //grab targets from passed array synchronized(path.targets){ diff --git a/core/src/mindustry/core/GameState.java b/core/src/mindustry/core/GameState.java index 73e3db8259..c2be18cfe4 100644 --- a/core/src/mindustry/core/GameState.java +++ b/core/src/mindustry/core/GameState.java @@ -27,11 +27,11 @@ public class GameState{ private State state = State.menu; public int enemies(){ - return net.client() ? enemies : unitGroups[waveTeam.ordinal()].count(b -> !(b instanceof BaseDrone)); + return net.client() ? enemies : unitGroups[(int) waveTeam.id].count(b -> !(b instanceof BaseDrone)); } public BaseUnit boss(){ - return unitGroups[waveTeam.ordinal()].find(BaseUnit::isBoss); + return unitGroups[(int) waveTeam.id].find(BaseUnit::isBoss); } public void set(State astate){ diff --git a/core/src/mindustry/core/Logic.java b/core/src/mindustry/core/Logic.java index 434058ee72..752017e7ce 100644 --- a/core/src/mindustry/core/Logic.java +++ b/core/src/mindustry/core/Logic.java @@ -217,7 +217,7 @@ public class Logic implements ApplicationListener{ Time.update(); if(state.rules.waves && state.rules.waveTimer && !state.gameOver){ - if(!state.rules.waitForWaveToEnd || unitGroups[waveTeam.ordinal()].size() == 0){ + if(!state.rules.waitForWaveToEnd || unitGroups[(int) waveTeam.id].size() == 0){ state.wavetime = Math.max(state.wavetime - Time.delta(), 0); } } diff --git a/core/src/mindustry/core/Renderer.java b/core/src/mindustry/core/Renderer.java index 4dbb2ef4a1..2a7cd16922 100644 --- a/core/src/mindustry/core/Renderer.java +++ b/core/src/mindustry/core/Renderer.java @@ -376,17 +376,17 @@ public class Renderer implements ApplicationListener{ private void drawAllTeams(boolean flying){ for(Team team : Team.all){ - EntityGroup group = unitGroups[team.ordinal()]; + EntityGroup group = unitGroups[(int) team.id]; if(group.count(p -> p.isFlying() == flying) + playerGroup.count(p -> p.isFlying() == flying && p.getTeam() == team) == 0 && flying) continue; - unitGroups[team.ordinal()].draw(u -> u.isFlying() == flying && !u.isDead(), Unit::drawUnder); + unitGroups[(int) team.id].draw(u -> u.isFlying() == flying && !u.isDead(), Unit::drawUnder); playerGroup.draw(p -> p.isFlying() == flying && p.getTeam() == team && !p.isDead(), Unit::drawUnder); - unitGroups[team.ordinal()].draw(u -> u.isFlying() == flying && !u.isDead(), Unit::drawAll); + unitGroups[(int) team.id].draw(u -> u.isFlying() == flying && !u.isDead(), Unit::drawAll); playerGroup.draw(p -> p.isFlying() == flying && p.getTeam() == team, Unit::drawAll); - unitGroups[team.ordinal()].draw(u -> u.isFlying() == flying && !u.isDead(), Unit::drawOver); + unitGroups[(int) team.id].draw(u -> u.isFlying() == flying && !u.isDead(), Unit::drawOver); playerGroup.draw(p -> p.isFlying() == flying && p.getTeam() == team, Unit::drawOver); } } diff --git a/core/src/mindustry/editor/EditorTile.java b/core/src/mindustry/editor/EditorTile.java index f03c376630..f9d00b8903 100644 --- a/core/src/mindustry/editor/EditorTile.java +++ b/core/src/mindustry/editor/EditorTile.java @@ -74,7 +74,7 @@ public class EditorTile extends Tile{ return; } - if(getTeamID() == team.ordinal()) return; + if(getTeamID() == (int) team.id) return; op(OpType.team, getTeamID()); super.setTeam(team); } diff --git a/core/src/mindustry/editor/EditorTool.java b/core/src/mindustry/editor/EditorTool.java index 3e9fcd47dc..a2a6927398 100644 --- a/core/src/mindustry/editor/EditorTool.java +++ b/core/src/mindustry/editor/EditorTool.java @@ -141,7 +141,7 @@ public enum EditorTool{ if(tile.link().synthetic()){ Team dest = tile.getTeam(); if(dest == editor.drawTeam) return; - fill(editor, x, y, false, t -> t.getTeamID() == dest.ordinal() && t.link().synthetic(), t -> t.setTeam(editor.drawTeam)); + fill(editor, x, y, false, t -> t.getTeamID() == (int) dest.id && t.link().synthetic(), t -> t.setTeam(editor.drawTeam)); } } } diff --git a/core/src/mindustry/editor/MapGenerateDialog.java b/core/src/mindustry/editor/MapGenerateDialog.java index 6a18ebc089..976d7fc3b2 100644 --- a/core/src/mindustry/editor/MapGenerateDialog.java +++ b/core/src/mindustry/editor/MapGenerateDialog.java @@ -415,7 +415,7 @@ public class MapGenerateDialog extends FloatingDialog{ this.floor = floor.id; this.block = wall.id; this.ore = ore.id; - this.team = (byte)team.ordinal(); + this.team = (byte) (int) team.id; this.rotation = (byte)rotation; } diff --git a/core/src/mindustry/entities/Damage.java b/core/src/mindustry/entities/Damage.java index a5bc63bc52..a9bdd04f3f 100644 --- a/core/src/mindustry/entities/Damage.java +++ b/core/src/mindustry/entities/Damage.java @@ -88,7 +88,7 @@ public class Damage{ tr.trns(angle, length); Intc2 collider = (cx, cy) -> { Tile tile = world.ltile(cx, cy); - if(tile != null && !collidedBlocks.contains(tile.pos()) && tile.entity != null && tile.getTeamID() != team.ordinal() && tile.entity.collide(hitter)){ + if(tile != null && !collidedBlocks.contains(tile.pos()) && tile.entity != null && tile.getTeamID() != (int) team.id && tile.entity.collide(hitter)){ tile.entity.collision(hitter); collidedBlocks.add(tile.pos()); hitter.getBulletType().hit(hitter, tile.worldx(), tile.worldy()); diff --git a/core/src/mindustry/entities/Units.java b/core/src/mindustry/entities/Units.java index 94a0cfbd12..ad228556b8 100644 --- a/core/src/mindustry/entities/Units.java +++ b/core/src/mindustry/entities/Units.java @@ -157,7 +157,7 @@ public class Units{ /** Iterates over all units in a rectangle. */ public static void nearby(Team team, float x, float y, float width, float height, Cons cons){ - unitGroups[team.ordinal()].intersect(x, y, width, height, cons); + unitGroups[(int) team.id].intersect(x, y, width, height, cons); playerGroup.intersect(x, y, width, height, player -> { if(player.getTeam() == team){ cons.get(player); @@ -167,7 +167,7 @@ public class Units{ /** Iterates over all units in a circle around this position. */ public static void nearby(Team team, float x, float y, float radius, Cons cons){ - unitGroups[team.ordinal()].intersect(x - radius, y - radius, radius*2f, radius*2f, unit -> { + unitGroups[(int) team.id].intersect(x - radius, y - radius, radius*2f, radius*2f, unit -> { if(unit.withinDst(x, y, radius)){ cons.get(unit); } @@ -183,7 +183,7 @@ public class Units{ /** Iterates over all units in a rectangle. */ public static void nearby(float x, float y, float width, float height, Cons cons){ for(Team team : Team.all){ - unitGroups[team.ordinal()].intersect(x, y, width, height, cons); + unitGroups[(int) team.id].intersect(x, y, width, height, cons); } playerGroup.intersect(x, y, width, height, cons); @@ -199,7 +199,7 @@ public class Units{ EnumSet targets = state.teams.enemiesOf(team); for(Team other : targets){ - unitGroups[other.ordinal()].intersect(x, y, width, height, cons); + unitGroups[(int) other.id].intersect(x, y, width, height, cons); } playerGroup.intersect(x, y, width, height, player -> { @@ -217,7 +217,7 @@ public class Units{ /** Iterates over all units. */ public static void all(Cons cons){ for(Team team : Team.all){ - unitGroups[team.ordinal()].all().each(cons); + unitGroups[(int) team.id].all().each(cons); } playerGroup.all().each(cons); diff --git a/core/src/mindustry/entities/type/BaseUnit.java b/core/src/mindustry/entities/type/BaseUnit.java index 46e2f8f63b..dcf3b369a0 100644 --- a/core/src/mindustry/entities/type/BaseUnit.java +++ b/core/src/mindustry/entities/type/BaseUnit.java @@ -365,7 +365,7 @@ public abstract class BaseUnit extends Unit implements ShooterTrait{ @Override public EntityGroup targetGroup(){ - return unitGroups[team.ordinal()]; + return unitGroups[(int) team.id]; } @Override diff --git a/core/src/mindustry/entities/type/Unit.java b/core/src/mindustry/entities/type/Unit.java index 1bec11c029..81ec1de7cb 100644 --- a/core/src/mindustry/entities/type/Unit.java +++ b/core/src/mindustry/entities/type/Unit.java @@ -169,7 +169,7 @@ public abstract class Unit extends DestructibleEntity implements SaveTrait, Targ public void writeSave(DataOutput stream, boolean net) throws IOException{ if(item.item == null) item.item = Items.copper; - stream.writeByte(team.ordinal()); + stream.writeByte((int) team.id); stream.writeBoolean(isDead()); stream.writeFloat(net ? interpolator.target.x : x); stream.writeFloat(net ? interpolator.target.y : y); @@ -220,7 +220,7 @@ public abstract class Unit extends DestructibleEntity implements SaveTrait, Targ for(Team team : Team.all){ if(team != getTeam() || !(this instanceof Player)){ - avoid(unitGroups[team.ordinal()].intersect(cx, cy, fsize, fsize)); + avoid(unitGroups[(int) team.id].intersect(cx, cy, fsize, fsize)); } } diff --git a/core/src/mindustry/entities/type/base/BuilderDrone.java b/core/src/mindustry/entities/type/base/BuilderDrone.java index f84bdecbca..aad348b9ce 100644 --- a/core/src/mindustry/entities/type/base/BuilderDrone.java +++ b/core/src/mindustry/entities/type/base/BuilderDrone.java @@ -114,7 +114,7 @@ public class BuilderDrone extends BaseDrone implements BuilderTrait{ public BuilderDrone(){ if(reset.check()){ Events.on(BuildSelectEvent.class, event -> { - EntityGroup group = unitGroups[event.team.ordinal()]; + EntityGroup group = unitGroups[(int) event.team.id]; if(!(event.tile.entity instanceof BuildEntity)) return; diff --git a/core/src/mindustry/game/Gamemode.java b/core/src/mindustry/game/Gamemode.java index 3cb2605c24..aca4d3340e 100644 --- a/core/src/mindustry/game/Gamemode.java +++ b/core/src/mindustry/game/Gamemode.java @@ -22,7 +22,7 @@ public enum Gamemode{ attack(rules -> { rules.unitDrops = true; rules.attackMode = true; - }, map -> map.teams.contains(waveTeam.ordinal())), + }, map -> map.teams.contains((int) waveTeam.id)), pvp(rules -> { rules.pvp = true; rules.enemyCoreBuildRadius = 600f; diff --git a/core/src/mindustry/game/Team.java b/core/src/mindustry/game/Team.java index 8e6d66ae1b..a64e5fd127 100644 --- a/core/src/mindustry/game/Team.java +++ b/core/src/mindustry/game/Team.java @@ -1,27 +1,35 @@ package mindustry.game; -import arc.Core; -import arc.graphics.Color; +import arc.*; +import arc.graphics.*; +import arc.struct.*; import mindustry.graphics.*; -public enum Team{ - derelict(Color.valueOf("4d4e58")), - sharded(Pal.accent), - crux(Color.valueOf("e82d2d")), - green(Color.valueOf("4dd98b")), - purple(Color.valueOf("9a4bdf")), - blue(Color.royal.cpy()); +public class Team{ + /** All registered teams. */ + public final static Array all = new Array<>(); + public final static Team + derelict = new Team("derelict", Color.valueOf("4d4e58")), + sharded = new Team("sharded", Pal.accent.cpy()), + crux = new Team("crux", Color.valueOf("e82d2d")), + green = new Team("green", Color.valueOf("4dd98b")), + purple = new Team("purple", Color.valueOf("9a4bdf")), + blue = new Team("blue", Color.royal.cpy()); - public final static Team[] all = values(); public final Color color; public final int intColor; + public final String name; + public final int id; - Team(Color color){ + public Team(String name, Color color){ + this.name = name; this.color = color; - intColor = Color.rgba8888(color); + this.intColor = Color.rgba8888(color); + this.id = all.size; + all.add(this); } public String localized(){ - return Core.bundle.get("team." + name() + ".name"); + return Core.bundle.get("team." + name + ".name"); } } diff --git a/core/src/mindustry/game/Teams.java b/core/src/mindustry/game/Teams.java index 2b03bbfaee..020bfb4b88 100644 --- a/core/src/mindustry/game/Teams.java +++ b/core/src/mindustry/game/Teams.java @@ -6,23 +6,22 @@ import mindustry.world.*; /** Class for various team-based utilities. */ public class Teams{ - private TeamData[] map = new TeamData[Team.all.length]; + private TeamData[] map = new TeamData[256]; /** * Register a team. * @param team The team type enum. - * @param enemies The array of enemies of this team. Any team not in this array is considered neutral. */ - public void add(Team team, Team... enemies){ - map[team.ordinal()] = new TeamData(team, EnumSet.of(enemies)); + public void add(Team team){ + map[team.id] = new TeamData(team); } /** Returns team data by type. */ public TeamData get(Team team){ - if(map[team.ordinal()] == null){ - add(team, Array.with(Team.all).select(t -> t != team).toArray(Team.class)); + if(map[team.id] == null){ + add(team); } - return map[team.ordinal()]; + return map[team.id]; } /** Returns whether a team is active, e.g. whether it has any cores remaining. */ @@ -31,14 +30,10 @@ public class Teams{ return team == Vars.waveTeam || get(team).cores.size > 0; } - /** Returns a set of all teams that are enemies of this team. */ - public EnumSet enemiesOf(Team team){ - return get(team).enemies; - } - /** Returns whether {@param other} is an enemy of {@param #team}. */ public boolean areEnemies(Team team, Team other){ - return enemiesOf(team).contains(other); + //todo what about derelict? + return team != other; } /** Allocates a new array with the active teams. @@ -49,13 +44,11 @@ public class Teams{ public static class TeamData{ public final ObjectSet cores = new ObjectSet<>(); - public final EnumSet enemies; public final Team team; public Queue brokenBlocks = new Queue<>(); - public TeamData(Team team, EnumSet enemies){ + public TeamData(Team team){ this.team = team; - this.enemies = enemies; } } diff --git a/core/src/mindustry/io/MapIO.java b/core/src/mindustry/io/MapIO.java index 88c011442b..07e9823569 100644 --- a/core/src/mindustry/io/MapIO.java +++ b/core/src/mindustry/io/MapIO.java @@ -91,7 +91,7 @@ public class MapIO{ public void setTeam(Team team){ super.setTeam(team); if(block instanceof CoreBlock){ - map.teams.add(team.ordinal()); + map.teams.add((int) team.id); } } }; diff --git a/core/src/mindustry/io/SaveVersion.java b/core/src/mindustry/io/SaveVersion.java index ba9a991e05..f3fdc0c20e 100644 --- a/core/src/mindustry/io/SaveVersion.java +++ b/core/src/mindustry/io/SaveVersion.java @@ -217,7 +217,7 @@ public abstract class SaveVersion extends SaveFileReader{ Array data = state.teams.getActive(); stream.writeInt(data.size); for(TeamData team : data){ - stream.writeInt(team.team.ordinal()); + stream.writeInt((int) team.team.id); stream.writeInt(team.brokenBlocks.size); for(BrokenBlock block : team.brokenBlocks){ stream.writeShort(block.x); diff --git a/core/src/mindustry/io/TypeIO.java b/core/src/mindustry/io/TypeIO.java index 4e9c4b5024..de0faaa372 100644 --- a/core/src/mindustry/io/TypeIO.java +++ b/core/src/mindustry/io/TypeIO.java @@ -87,7 +87,7 @@ public class TypeIO{ @WriteClass(BaseUnit.class) public static void writeBaseUnit(ByteBuffer buffer, BaseUnit unit){ - buffer.put((byte)unit.getTeam().ordinal()); + buffer.put((byte) (int) unit.getTeam().id); buffer.putInt(unit.getID()); } @@ -194,7 +194,7 @@ public class TypeIO{ @WriteClass(Team.class) public static void writeTeam(ByteBuffer buffer, Team reason){ - buffer.put((byte)reason.ordinal()); + buffer.put((byte) (int) reason.id); } @ReadClass(Team.class) diff --git a/core/src/mindustry/ui/fragments/HudFragment.java b/core/src/mindustry/ui/fragments/HudFragment.java index 80e5dc0185..58e1ff9e52 100644 --- a/core/src/mindustry/ui/fragments/HudFragment.java +++ b/core/src/mindustry/ui/fragments/HudFragment.java @@ -628,7 +628,7 @@ public class HudFragment extends Fragment{ } if(state.rules.waveTimer){ - builder.append((state.rules.waitForWaveToEnd && unitGroups[waveTeam.ordinal()].size() > 0) ? Core.bundle.get("wave.waveInProgress") : ( waitingf.get((int)(state.wavetime/60)))); + builder.append((state.rules.waitForWaveToEnd && unitGroups[(int) waveTeam.id].size() > 0) ? Core.bundle.get("wave.waveInProgress") : ( waitingf.get((int)(state.wavetime/60)))); }else if(state.enemies() == 0){ builder.append(Core.bundle.get("waiting")); } diff --git a/core/src/mindustry/world/Tile.java b/core/src/mindustry/world/Tile.java index 1ac2871bab..a1fb5fa9ff 100644 --- a/core/src/mindustry/world/Tile.java +++ b/core/src/mindustry/world/Tile.java @@ -146,7 +146,7 @@ public class Tile implements Position, TargetTrait{ } public void setTeam(Team team){ - this.team = (byte)team.ordinal(); + this.team = (byte) (int) team.id; } public byte getTeamID(){ @@ -156,7 +156,7 @@ public class Tile implements Position, TargetTrait{ public void setBlock(@NonNull Block type, Team team, int rotation){ preChanged(); this.block = type; - this.team = (byte)team.ordinal(); + this.team = (byte) (int) team.id; this.rotation = (byte)Mathf.mod(rotation, 4); changed(); } diff --git a/core/src/mindustry/world/blocks/units/CommandCenter.java b/core/src/mindustry/world/blocks/units/CommandCenter.java index 9e9312af75..9dae2923d3 100644 --- a/core/src/mindustry/world/blocks/units/CommandCenter.java +++ b/core/src/mindustry/world/blocks/units/CommandCenter.java @@ -58,7 +58,7 @@ public class CommandCenter extends Block{ ObjectSet set = indexer.getAllied(tile.getTeam(), BlockFlag.comandCenter); if(set.size == 1){ - for(BaseUnit unit : unitGroups[tile.getTeam().ordinal()].all()){ + for(BaseUnit unit : unitGroups[(int) tile.getTeam().id].all()){ unit.onCommand(UnitCommand.all[0]); } } @@ -116,7 +116,7 @@ public class CommandCenter extends Block{ Team team = (player == null ? tile.getTeam() : player.getTeam()); - for(BaseUnit unit : unitGroups[team.ordinal()].all()){ + for(BaseUnit unit : unitGroups[(int) team.id].all()){ unit.onCommand(command); } diff --git a/desktop/src/mindustry/desktop/steam/SStats.java b/desktop/src/mindustry/desktop/steam/SStats.java index ee1ab916bc..984fa9e985 100644 --- a/desktop/src/mindustry/desktop/steam/SStats.java +++ b/desktop/src/mindustry/desktop/steam/SStats.java @@ -55,13 +55,13 @@ public class SStats implements SteamUserStatsCallback{ private void checkUpdate(){ if(campaign()){ - SStat.maxUnitActive.max(unitGroups[player.getTeam().ordinal()].size()); + SStat.maxUnitActive.max(unitGroups[(int) player.getTeam().id].size()); - if(unitGroups[player.getTeam().ordinal()].count(u -> u.getType() == UnitTypes.phantom) >= 10){ + if(unitGroups[(int) player.getTeam().id].count(u -> u.getType() == UnitTypes.phantom) >= 10){ active10Phantoms.complete(); } - if(unitGroups[player.getTeam().ordinal()].count(u -> u.getType() == UnitTypes.crawler) >= 50){ + if(unitGroups[(int) player.getTeam().id].count(u -> u.getType() == UnitTypes.crawler) >= 50){ active50Crawlers.complete(); } diff --git a/server/src/mindustry/server/ServerControl.java b/server/src/mindustry/server/ServerControl.java index b821d5dcd5..8ff1874407 100644 --- a/server/src/mindustry/server/ServerControl.java +++ b/server/src/mindustry/server/ServerControl.java @@ -292,7 +292,7 @@ public class ServerControl implements ApplicationListener{ info(" &lyPlaying on map &fi{0}&fb &lb/&ly Wave {1}", Strings.capitalize(world.getMap().name()), state.wave); if(state.rules.waves){ - info("&ly {0} enemies.", unitGroups[Team.crux.ordinal()].size()); + info("&ly {0} enemies.", unitGroups[(int) Team.crux.id].size()); }else{ info("&ly {0} seconds until next wave.", (int)(state.wavetime / 60)); } diff --git a/tests/src/test/java/ApplicationTests.java b/tests/src/test/java/ApplicationTests.java index dfda5822c9..43c819bdfd 100644 --- a/tests/src/test/java/ApplicationTests.java +++ b/tests/src/test/java/ApplicationTests.java @@ -106,8 +106,8 @@ public class ApplicationTests{ Time.update(); Time.update(); Time.setDeltaProvider(() -> 1f); - unitGroups[waveTeam.ordinal()].updateEvents(); - assertFalse(unitGroups[waveTeam.ordinal()].isEmpty(), "No enemies spawned."); + unitGroups[(int) waveTeam.id].updateEvents(); + assertFalse(unitGroups[(int) waveTeam.id].isEmpty(), "No enemies spawned."); } @Test From 2b22b7e7e4d524d3687a6c40aeacd1291463d628 Mon Sep 17 00:00:00 2001 From: Anuken Date: Wed, 25 Dec 2019 22:26:51 -0500 Subject: [PATCH 03/78] Condensed unit group array --- core/src/mindustry/Vars.java | 8 ++---- core/src/mindustry/core/GameState.java | 7 +---- core/src/mindustry/core/Logic.java | 26 +++++++------------ core/src/mindustry/core/NetServer.java | 2 +- .../src/mindustry/entities/type/BaseUnit.java | 5 ++++ .../entities/type/base/BaseDrone.java | 4 +++ core/src/mindustry/game/MusicControl.java | 2 +- core/src/mindustry/game/Tutorial.java | 2 +- .../mindustry/ui/fragments/HudFragment.java | 16 ++++++------ 9 files changed, 33 insertions(+), 39 deletions(-) diff --git a/core/src/mindustry/Vars.java b/core/src/mindustry/Vars.java index 502c78887d..1a55d6e23f 100644 --- a/core/src/mindustry/Vars.java +++ b/core/src/mindustry/Vars.java @@ -184,7 +184,7 @@ public class Vars implements Loadable{ public static EntityGroup shieldGroup; public static EntityGroup puddleGroup; public static EntityGroup fireGroup; - public static EntityGroup[] unitGroups; + public static EntityGroup unitGroup; public static Player player; @@ -239,11 +239,7 @@ public class Vars implements Loadable{ puddleGroup = entities.add(Puddle.class).enableMapping(); shieldGroup = entities.add(ShieldEntity.class, false); fireGroup = entities.add(Fire.class).enableMapping(); - unitGroups = new EntityGroup[Team.all.length]; - - for(Team team : Team.all){ - unitGroups[(int) team.id] = entities.add(BaseUnit.class).enableMapping(); - } + unitGroup = entities.add(BaseUnit.class).enableMapping(); for(EntityGroup group : entities.all()){ group.setRemoveListener(entity -> { diff --git a/core/src/mindustry/core/GameState.java b/core/src/mindustry/core/GameState.java index c2be18cfe4..eb7d419a10 100644 --- a/core/src/mindustry/core/GameState.java +++ b/core/src/mindustry/core/GameState.java @@ -2,7 +2,6 @@ package mindustry.core; import arc.*; import mindustry.entities.type.*; -import mindustry.entities.type.base.*; import mindustry.game.EventType.*; import mindustry.game.*; @@ -26,12 +25,8 @@ public class GameState{ /** Current game state. */ private State state = State.menu; - public int enemies(){ - return net.client() ? enemies : unitGroups[(int) waveTeam.id].count(b -> !(b instanceof BaseDrone)); - } - public BaseUnit boss(){ - return unitGroups[(int) waveTeam.id].find(BaseUnit::isBoss); + return unitGroup.find(u -> u.isBoss() && u.getTeam() == waveTeam); } public void set(State astate){ diff --git a/core/src/mindustry/core/Logic.java b/core/src/mindustry/core/Logic.java index 752017e7ce..86061bc6c6 100644 --- a/core/src/mindustry/core/Logic.java +++ b/core/src/mindustry/core/Logic.java @@ -1,8 +1,8 @@ package mindustry.core; import arc.*; -import mindustry.annotations.Annotations.*; import arc.util.*; +import mindustry.annotations.Annotations.*; import mindustry.content.*; import mindustry.core.GameState.*; import mindustry.ctype.*; @@ -212,12 +212,15 @@ public class Logic implements ApplicationListener{ public void update(){ if(!state.is(State.menu)){ + if(!net.client()){ + state.enemies = unitGroup.count(b -> b.getTeam() == waveTeam && b.countsAsEnemy()); + } if(!state.isPaused()){ Time.update(); if(state.rules.waves && state.rules.waveTimer && !state.gameOver){ - if(!state.rules.waitForWaveToEnd || unitGroups[(int) waveTeam.id].size() == 0){ + if(!state.rules.waitForWaveToEnd || state.enemies == 0){ state.wavetime = Math.max(state.wavetime - Time.delta(), 0); } } @@ -232,20 +235,15 @@ public class Logic implements ApplicationListener{ } if(!state.isEditor()){ - for(EntityGroup group : unitGroups){ - group.update(); - } - + unitGroup.update(); puddleGroup.update(); shieldGroup.update(); bulletGroup.update(); tileGroup.update(); fireGroup.update(); }else{ - for(EntityGroup group : unitGroups){ - group.updateEvents(); - collisions.updatePhysics(group); - } + unitGroup.updateEvents(); + collisions.updatePhysics(unitGroup); } @@ -257,12 +255,8 @@ public class Logic implements ApplicationListener{ } if(!state.isEditor()){ - - for(EntityGroup group : unitGroups){ - if(group.isEmpty()) continue; - collisions.collideGroups(bulletGroup, group); - } - + //bulletGroup + collisions.collideGroups(bulletGroup, unitGroup); collisions.collideGroups(bulletGroup, playerGroup); } } diff --git a/core/src/mindustry/core/NetServer.java b/core/src/mindustry/core/NetServer.java index d00fc5a839..4c86ecb9d0 100644 --- a/core/src/mindustry/core/NetServer.java +++ b/core/src/mindustry/core/NetServer.java @@ -660,7 +660,7 @@ public class NetServer implements ApplicationListener{ byte[] stateBytes = syncStream.toByteArray(); //write basic state data. - Call.onStateSnapshot(player.con, state.wavetime, state.wave, state.enemies(), (short)stateBytes.length, net.compressSnapshot(stateBytes)); + Call.onStateSnapshot(player.con, state.wavetime, state.wave, state.enemies, (short)stateBytes.length, net.compressSnapshot(stateBytes)); viewport.setSize(player.con.viewWidth, player.con.viewHeight).setCenter(player.con.viewX, player.con.viewY); diff --git a/core/src/mindustry/entities/type/BaseUnit.java b/core/src/mindustry/entities/type/BaseUnit.java index dcf3b369a0..28a6eea861 100644 --- a/core/src/mindustry/entities/type/BaseUnit.java +++ b/core/src/mindustry/entities/type/BaseUnit.java @@ -126,6 +126,11 @@ public abstract class BaseUnit extends Unit implements ShooterTrait{ this.team = team; } + /** @return whether this unit counts toward the enemy amount in the wave UI. */ + public boolean countsAsEnemy(){ + return true; + } + public UnitType getType(){ return type; } diff --git a/core/src/mindustry/entities/type/base/BaseDrone.java b/core/src/mindustry/entities/type/base/BaseDrone.java index a1b5b1c321..02a8fd9d32 100644 --- a/core/src/mindustry/entities/type/base/BaseDrone.java +++ b/core/src/mindustry/entities/type/base/BaseDrone.java @@ -32,6 +32,10 @@ public abstract class BaseDrone extends FlyingUnit{ } }; + public boolean countsAsEnemy(){ + return false; + } + @Override public void onCommand(UnitCommand command){ //do nothing, normal commands are not applicable here diff --git a/core/src/mindustry/game/MusicControl.java b/core/src/mindustry/game/MusicControl.java index f258b6a520..f4352f28be 100644 --- a/core/src/mindustry/game/MusicControl.java +++ b/core/src/mindustry/game/MusicControl.java @@ -94,7 +94,7 @@ public class MusicControl{ } //dark based on enemies - return Mathf.chance(state.enemies() / 70f + 0.1f); + return Mathf.chance(state.enemies / 70f + 0.1f); } /** Plays and fades in a music track. This must be called every frame. diff --git a/core/src/mindustry/game/Tutorial.java b/core/src/mindustry/game/Tutorial.java index 924e68f63c..569fbd380c 100644 --- a/core/src/mindustry/game/Tutorial.java +++ b/core/src/mindustry/game/Tutorial.java @@ -165,7 +165,7 @@ public class Tutorial{ } }, deposit(() -> event("deposit")), - waves(() -> state.wave > 2 && state.enemies() <= 0 && !spawner.isSpawning()){ + waves(() -> state.wave > 2 && state.enemies <= 0 && !spawner.isSpawning()){ void begin(){ state.rules.waveTimer = true; logic.runWave(); diff --git a/core/src/mindustry/ui/fragments/HudFragment.java b/core/src/mindustry/ui/fragments/HudFragment.java index 58e1ff9e52..c2ca5b25e5 100644 --- a/core/src/mindustry/ui/fragments/HudFragment.java +++ b/core/src/mindustry/ui/fragments/HudFragment.java @@ -557,7 +557,7 @@ public class HudFragment extends Fragment{ } private boolean canLaunch(){ - return inLaunchWave() && state.enemies() <= 0; + return inLaunchWave() && state.enemies <= 0; } private void toggleMenus(){ @@ -604,7 +604,7 @@ public class HudFragment extends Fragment{ if(inLaunchWave()){ builder.append("[#"); - Tmp.c1.set(Color.white).lerp(state.enemies() > 0 ? Color.white : Color.scarlet, Mathf.absin(Time.time(), 2f, 1f)).toString(builder); + Tmp.c1.set(Color.white).lerp(state.enemies > 0 ? Color.white : Color.scarlet, Mathf.absin(Time.time(), 2f, 1f)).toString(builder); builder.append("]"); if(!canLaunch()){ @@ -618,18 +618,18 @@ public class HudFragment extends Fragment{ builder.append("[]\n"); } - if(state.enemies() > 0){ - if(state.enemies() == 1){ - builder.append(enemyf.get(state.enemies())); + if(state.enemies > 0){ + if(state.enemies == 1){ + builder.append(enemyf.get(state.enemies)); }else{ - builder.append(enemiesf.get(state.enemies())); + builder.append(enemiesf.get(state.enemies)); } builder.append("\n"); } if(state.rules.waveTimer){ builder.append((state.rules.waitForWaveToEnd && unitGroups[(int) waveTeam.id].size() > 0) ? Core.bundle.get("wave.waveInProgress") : ( waitingf.get((int)(state.wavetime/60)))); - }else if(state.enemies() == 0){ + }else if(state.enemies == 0){ builder.append(Core.bundle.get("waiting")); } @@ -646,7 +646,7 @@ public class HudFragment extends Fragment{ } private boolean canSkipWave(){ - return state.rules.waves && ((net.server() || player.isAdmin) || !net.active()) && state.enemies() == 0 && !spawner.isSpawning() && !state.rules.tutorial; + return state.rules.waves && ((net.server() || player.isAdmin) || !net.active()) && state.enemies == 0 && !spawner.isSpawning() && !state.rules.tutorial; } private void addPlayButton(Table table){ From 1d6f769e3d1aca7d8f446ac79f36d643d24fb528 Mon Sep 17 00:00:00 2001 From: Anuken Date: Thu, 26 Dec 2019 08:01:24 -0500 Subject: [PATCH 04/78] Debug fixes --- core/src/mindustry/world/blocks/BuildBlock.java | 1 + desktop/build.gradle | 2 +- gradle.properties | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/core/src/mindustry/world/blocks/BuildBlock.java b/core/src/mindustry/world/blocks/BuildBlock.java index 69d9ba61e8..82add253a9 100644 --- a/core/src/mindustry/world/blocks/BuildBlock.java +++ b/core/src/mindustry/world/blocks/BuildBlock.java @@ -337,6 +337,7 @@ public class BuildBlock extends Block{ } public void setDeconstruct(Block previous){ + if(previous == null) return; this.previous = previous; this.progress = 1f; if(previous.buildCost >= 0.01f){ diff --git a/desktop/build.gradle b/desktop/build.gradle index efedf8c57b..d03320d394 100644 --- a/desktop/build.gradle +++ b/desktop/build.gradle @@ -33,7 +33,7 @@ task run(dependsOn: classes, type: JavaExec){ } if(args.contains("debug")){ - main = "io.anuke.mindustry.DebugLauncher" + main = "mindustry.debug.DebugLauncher" } } diff --git a/gradle.properties b/gradle.properties index 29c1e50fad..5404911090 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,3 +1,3 @@ org.gradle.daemon=true org.gradle.jvmargs=-Xms256m -Xmx1024m -archash=88c1a9afe2f5be4dd06e47ac8afe070247b3da29 +archash=6e94de8eaa000725ad8f959009358cf010d6db01 From a5978b61632e3a3e28dee23b13d154ff38fc4ef2 Mon Sep 17 00:00:00 2001 From: Anuken Date: Thu, 26 Dec 2019 08:08:16 -0500 Subject: [PATCH 05/78] Updated Arc --- core/src/mindustry/world/blocks/StaticWall.java | 8 ++++---- gradle.properties | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/core/src/mindustry/world/blocks/StaticWall.java b/core/src/mindustry/world/blocks/StaticWall.java index d81e0521db..531fb010a2 100644 --- a/core/src/mindustry/world/blocks/StaticWall.java +++ b/core/src/mindustry/world/blocks/StaticWall.java @@ -43,9 +43,9 @@ public class StaticWall extends Rock{ boolean eq(int rx, int ry){ return rx < world.width() - 1 && ry < world.height() - 1 - && world.tile(rx + 1, ry).block() == this - && world.tile(rx, ry + 1).block() == this - && world.tile(rx, ry).block() == this - && world.tile(rx + 1, ry + 1).block() == this; + && world.tile(rx + 1, ry).block() == this + && world.tile(rx, ry + 1).block() == this + && world.tile(rx, ry).block() == this + && world.tile(rx + 1, ry + 1).block() == this; } } diff --git a/gradle.properties b/gradle.properties index 5404911090..de2663914f 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,3 +1,3 @@ org.gradle.daemon=true org.gradle.jvmargs=-Xms256m -Xmx1024m -archash=6e94de8eaa000725ad8f959009358cf010d6db01 +archash=6024918f94e31c8efbdfa1587177ccc225931b5b From 36ec88e2e26ee88794aa9d87e2e24bc5a9d1b51f Mon Sep 17 00:00:00 2001 From: Anuken Date: Thu, 26 Dec 2019 14:20:36 -0500 Subject: [PATCH 06/78] Team cleanup --- core/src/mindustry/Vars.java | 4 ++-- core/src/mindustry/game/Teams.java | 13 ++++++++++++- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/core/src/mindustry/Vars.java b/core/src/mindustry/Vars.java index 1a55d6e23f..fafb869c39 100644 --- a/core/src/mindustry/Vars.java +++ b/core/src/mindustry/Vars.java @@ -128,9 +128,9 @@ public class Vars implements Loadable{ public static Fi dataDirectory; /** data subdirectory used for screenshots */ public static Fi screenshotDirectory; - /** data subdirectory used for custom mmaps */ + /** data subdirectory used for custom maps */ public static Fi customMapDirectory; - /** data subdirectory used for custom mmaps */ + /** data subdirectory used for custom map previews */ public static Fi mapPreviewDirectory; /** tmp subdirectory for map conversion */ public static Fi tmpDirectory; diff --git a/core/src/mindustry/game/Teams.java b/core/src/mindustry/game/Teams.java index 020bfb4b88..d77b7902ae 100644 --- a/core/src/mindustry/game/Teams.java +++ b/core/src/mindustry/game/Teams.java @@ -1,12 +1,23 @@ package mindustry.game; +import arc.func.*; import arc.struct.*; import mindustry.*; +import mindustry.entities.type.*; import mindustry.world.*; /** Class for various team-based utilities. */ public class Teams{ - private TeamData[] map = new TeamData[256]; + /** Maps team IDs to team data. */ + private Array map = new Array<>(); + /** Active teams. */ + private Array active = new Array<>(); + + public T eachEnemyCore(Team team, Func ret){ + T out = null; + //todo each enemy, each enemy core... + return out; + } /** * Register a team. From de5979f4ee1c4a6f85edd72117d629668a00d67b Mon Sep 17 00:00:00 2001 From: Anuken Date: Thu, 26 Dec 2019 17:46:01 -0500 Subject: [PATCH 07/78] Many various internal changes --- core/src/mindustry/Vars.java | 4 - core/src/mindustry/ai/BlockIndexer.java | 24 +- core/src/mindustry/ai/Pathfinder.java | 18 +- core/src/mindustry/ai/WaveSpawner.java | 16 +- core/src/mindustry/content/StatusEffects.java | 5 +- core/src/mindustry/core/Control.java | 22 +- core/src/mindustry/core/GameState.java | 2 +- core/src/mindustry/core/Logic.java | 33 ++- core/src/mindustry/core/NetServer.java | 30 +-- core/src/mindustry/core/Renderer.java | 38 +--- core/src/mindustry/core/World.java | 55 +---- core/src/mindustry/editor/DrawOperation.java | 2 +- core/src/mindustry/editor/EditorTile.java | 2 +- core/src/mindustry/editor/EditorTool.java | 19 +- core/src/mindustry/editor/MapEditor.java | 9 +- .../src/mindustry/editor/MapEditorDialog.java | 2 +- .../mindustry/editor/MapGenerateDialog.java | 8 +- core/src/mindustry/entities/Damage.java | 2 +- core/src/mindustry/entities/Units.java | 13 +- .../src/mindustry/entities/type/BaseUnit.java | 17 +- .../mindustry/entities/type/TileEntity.java | 13 +- core/src/mindustry/entities/type/Unit.java | 27 +-- .../entities/type/base/BuilderDrone.java | 2 +- .../mindustry/entities/units/UnitDrops.java | 3 +- core/src/mindustry/game/Gamemode.java | 4 +- core/src/mindustry/game/MusicControl.java | 2 +- core/src/mindustry/game/Rules.java | 4 + core/src/mindustry/game/Schematics.java | 2 +- core/src/mindustry/game/Team.java | 66 ++++-- core/src/mindustry/game/Teams.java | 127 +++++++++-- core/src/mindustry/game/Tutorial.java | 15 +- .../mindustry/graphics/OverlayRenderer.java | 27 +-- core/src/mindustry/input/DesktopInput.java | 2 +- core/src/mindustry/io/LegacyMapIO.java | 214 ------------------ core/src/mindustry/io/MapIO.java | 25 +- core/src/mindustry/io/SaveVersion.java | 4 +- core/src/mindustry/io/TypeIO.java | 8 +- .../maps/generators/MapGenerator.java | 2 +- core/src/mindustry/ui/ItemsDisplay.java | 4 +- .../mindustry/ui/fragments/HudFragment.java | 6 +- .../ui/fragments/PlayerListFragment.java | 3 +- core/src/mindustry/world/Build.java | 15 +- core/src/mindustry/world/CachedTile.java | 2 +- core/src/mindustry/world/Tile.java | 39 +++- .../mindustry/world/blocks/BuildBlock.java | 2 +- .../world/blocks/storage/CoreBlock.java | 33 +-- .../world/blocks/units/CommandCenter.java | 4 +- .../src/mindustry/desktop/steam/SStats.java | 6 +- gradle.properties | 2 +- .../src/mindustry/server/ServerControl.java | 6 +- tests/src/test/java/ApplicationTests.java | 14 +- tests/src/test/java/ZoneTests.java | 4 +- tools/build.gradle | 2 +- 53 files changed, 435 insertions(+), 575 deletions(-) delete mode 100644 core/src/mindustry/io/LegacyMapIO.java diff --git a/core/src/mindustry/Vars.java b/core/src/mindustry/Vars.java index fafb869c39..dfefeb2a68 100644 --- a/core/src/mindustry/Vars.java +++ b/core/src/mindustry/Vars.java @@ -61,10 +61,6 @@ public class Vars implements Loadable{ public static final Array defaultServers = Array.with(); /** maximum distance between mine and core that supports automatic transferring */ public static final float mineTransferRange = 220f; - /** team of the player by default */ - public static final Team defaultTeam = Team.sharded; - /** team of the enemy in waves/sectors */ - public static final Team waveTeam = Team.crux; /** whether to enable editing of units in the editor */ public static final boolean enableUnitEditing = false; /** max chat message length */ diff --git a/core/src/mindustry/ai/BlockIndexer.java b/core/src/mindustry/ai/BlockIndexer.java index 311e7887a7..bb90b37301 100644 --- a/core/src/mindustry/ai/BlockIndexer.java +++ b/core/src/mindustry/ai/BlockIndexer.java @@ -103,7 +103,7 @@ public class BlockIndexer{ } private ObjectSet[] getFlagged(Team team){ - return flagMap[(int) team.id]; + return flagMap[(int)team.id]; } /** @return whether this item is present on this map.*/ @@ -115,11 +115,11 @@ public class BlockIndexer{ public ObjectSet getDamaged(Team team){ returnArray.clear(); - if(damagedTiles[(int) team.id] == null){ - damagedTiles[(int) team.id] = new ObjectSet<>(); + if(damagedTiles[(int)team.id] == null){ + damagedTiles[(int)team.id] = new ObjectSet<>(); } - ObjectSet set = damagedTiles[(int) team.id]; + ObjectSet set = damagedTiles[(int)team.id]; for(Tile tile : set){ if((tile.entity == null || tile.entity.getTeam() != team || !tile.entity.damaged()) || tile.block() instanceof BuildBlock){ returnArray.add(tile); @@ -135,7 +135,7 @@ public class BlockIndexer{ /** Get all allied blocks with a flag. */ public ObjectSet getAllied(Team team, BlockFlag type){ - return flagMap[(int) team.id][type.ordinal()]; + return flagMap[(int)team.id][type.ordinal()]; } /** Get all enemy blocks with a flag. */ @@ -155,11 +155,11 @@ public class BlockIndexer{ } public void notifyTileDamaged(TileEntity entity){ - if(damagedTiles[(int) entity.getTeam().id] == null){ - damagedTiles[(int) entity.getTeam().id] = new ObjectSet<>(); + if(damagedTiles[(int)entity.getTeam().id] == null){ + damagedTiles[(int)entity.getTeam().id] = new ObjectSet<>(); } - ObjectSet set = damagedTiles[(int) entity.getTeam().id]; + ObjectSet set = damagedTiles[(int)entity.getTeam().id]; set.add(entity.tile); } @@ -287,11 +287,11 @@ public class BlockIndexer{ //fast-set this quadrant to 'occupied' if the tile just placed is already of this team if(tile.getTeam() == data.team && tile.entity != null && tile.block().targetable){ - structQuadrants[(int) data.team.id].set(quadrantX, quadrantY); + structQuadrants[(int)data.team.id].set(quadrantX, quadrantY); continue; //no need to process futher } - structQuadrants[(int) data.team.id].set(quadrantX, quadrantY, false); + structQuadrants[(int)data.team.id].set(quadrantX, quadrantY, false); outer: for(int x = quadrantX * quadrantSize; x < world.width() && x < (quadrantX + 1) * quadrantSize; x++){ @@ -299,7 +299,7 @@ public class BlockIndexer{ Tile result = world.ltile(x, y); //when a targetable block is found, mark this quadrant as occupied and stop searching if(result.entity != null && result.getTeam() == data.team){ - structQuadrants[(int) data.team.id].set(quadrantX, quadrantY); + structQuadrants[(int)data.team.id].set(quadrantX, quadrantY); break outer; } } @@ -308,7 +308,7 @@ public class BlockIndexer{ } private boolean getQuad(Team team, int quadrantX, int quadrantY){ - return structQuadrants[(int) team.id].get(quadrantX, quadrantY); + return structQuadrants[(int)team.id].get(quadrantX, quadrantY); } private int quadWidth(){ diff --git a/core/src/mindustry/ai/Pathfinder.java b/core/src/mindustry/ai/Pathfinder.java index 9464111cab..319c85ef2e 100644 --- a/core/src/mindustry/ai/Pathfinder.java +++ b/core/src/mindustry/ai/Pathfinder.java @@ -53,7 +53,7 @@ public class Pathfinder implements Runnable{ } //special preset which may help speed things up; this is optional - preloadPath(waveTeam, PathTarget.enemyCores); + preloadPath(state.rules.waveTeam, PathTarget.enemyCores); start(); }); @@ -84,8 +84,8 @@ public class Pathfinder implements Runnable{ } public int debugValue(Team team, int x, int y){ - if(pathMap[(int) team.id][PathTarget.enemyCores.ordinal()] == null) return 0; - return pathMap[(int) team.id][PathTarget.enemyCores.ordinal()].weights[x][y]; + if(pathMap[(int)team.id][PathTarget.enemyCores.ordinal()] == null) return 0; + return pathMap[(int)team.id][PathTarget.enemyCores.ordinal()].weights[x][y]; } /** Update a tile in the internal pathfinding grid. Causes a complete pathfinding reclaculation. */ @@ -149,12 +149,12 @@ public class Pathfinder implements Runnable{ public Tile getTargetTile(Tile tile, Team team, PathTarget target){ if(tile == null) return null; - PathData data = pathMap[(int) team.id][target.ordinal()]; + PathData data = pathMap[(int)team.id][target.ordinal()]; if(data == null){ //if this combination is not found, create it on request - if(!created.get((int) team.id, target.ordinal())){ - created.set((int) team.id, target.ordinal()); + if(!created.get((int)team.id, target.ordinal())){ + created.set((int)team.id, target.ordinal()); //grab targets since this is run on main thread IntArray targets = target.getTargets(team, new IntArray()); queue.post(() -> createPath(team, target, targets)); @@ -188,7 +188,7 @@ public class Pathfinder implements Runnable{ /** @return whether a tile can be passed through by this team. Pathfinding thread only.*/ private boolean passable(int x, int y, Team team){ int tile = tiles[x][y]; - return PathTile.passable(tile) || (PathTile.team(tile) != (int) team.id && PathTile.team(tile) != (int) Team.derelict.id); + return PathTile.passable(tile) || (PathTile.team(tile) != (int)team.id && PathTile.team(tile) != (int)Team.derelict.id); } /** @@ -238,7 +238,7 @@ public class Pathfinder implements Runnable{ PathData path = new PathData(team, target, world.width(), world.height()); list.add(path); - pathMap[(int) team.id][target.ordinal()] = path; + pathMap[(int)team.id][target.ordinal()] = path; //grab targets from passed array synchronized(path.targets){ @@ -303,7 +303,7 @@ public class Pathfinder implements Runnable{ } //spawn points are also enemies. - if(state.rules.waves && team == defaultTeam){ + if(state.rules.waves && team == state.rules.defaultTeam){ for(Tile other : spawner.getGroundSpawns()){ out.add(other.pos()); } diff --git a/core/src/mindustry/ai/WaveSpawner.java b/core/src/mindustry/ai/WaveSpawner.java index ac4914a90b..25b9983db0 100644 --- a/core/src/mindustry/ai/WaveSpawner.java +++ b/core/src/mindustry/ai/WaveSpawner.java @@ -53,7 +53,7 @@ public class WaveSpawner{ eachFlyerSpawn((spawnX, spawnY) -> { for(int i = 0; i < spawned; i++){ - BaseUnit unit = group.createUnit(waveTeam); + BaseUnit unit = group.createUnit(state.rules.waveTeam); unit.set(spawnX + Mathf.range(spread), spawnY + Mathf.range(spread)); unit.add(); } @@ -66,7 +66,7 @@ public class WaveSpawner{ for(int i = 0; i < spawned; i++){ Tmp.v1.rnd(spread); - BaseUnit unit = group.createUnit(waveTeam); + BaseUnit unit = group.createUnit(state.rules.waveTeam); unit.set(spawnX + Tmp.v1.x, spawnY + Tmp.v1.y); Time.run(Math.min(i * 5, 60 * 2), () -> spawnEffect(unit)); @@ -78,7 +78,7 @@ public class WaveSpawner{ eachGroundSpawn((spawnX, spawnY, doShockwave) -> { if(doShockwave){ Time.run(20f, () -> Effects.effect(Fx.spawnShockwave, spawnX, spawnY, state.rules.dropZoneRadius)); - Time.run(40f, () -> Damage.damage(waveTeam, spawnX, spawnY, state.rules.dropZoneRadius, 99999999f, true)); + Time.run(40f, () -> Damage.damage(state.rules.waveTeam, spawnX, spawnY, state.rules.dropZoneRadius, 99999999f, true)); } }); @@ -90,9 +90,9 @@ public class WaveSpawner{ cons.accept(spawn.worldx(), spawn.worldy(), true); } - if(state.rules.attackMode && state.teams.isActive(waveTeam) && !state.teams.get(defaultTeam).cores.isEmpty()){ - Tile firstCore = state.teams.get(defaultTeam).cores.first(); - for(Tile core : state.teams.get(waveTeam).cores){ + if(state.rules.attackMode && state.teams.isActive(state.rules.waveTeam) && !state.teams.playerCores().isEmpty()){ + Tile firstCore = state.teams.playerCores().first(); + for(Tile core : state.teams.get(state.rules.waveTeam).cores){ Tmp.v1.set(firstCore).sub(core.worldx(), core.worldy()).limit(coreMargin + core.block().size*tilesize); cons.accept(core.worldx() + Tmp.v1.x, core.worldy() + Tmp.v1.y, false); } @@ -107,8 +107,8 @@ public class WaveSpawner{ cons.get(spawnX, spawnY); } - if(state.rules.attackMode && state.teams.isActive(waveTeam)){ - for(Tile core : state.teams.get(waveTeam).cores){ + if(state.rules.attackMode && state.teams.isActive(state.rules.waveTeam)){ + for(Tile core : state.teams.get(state.rules.waveTeam).cores){ cons.get(core.worldx(), core.worldy()); } } diff --git a/core/src/mindustry/content/StatusEffects.java b/core/src/mindustry/content/StatusEffects.java index 525a14199c..6672727847 100644 --- a/core/src/mindustry/content/StatusEffects.java +++ b/core/src/mindustry/content/StatusEffects.java @@ -6,8 +6,7 @@ import mindustry.entities.Effects; import mindustry.ctype.ContentList; import mindustry.game.EventType.*; import mindustry.type.StatusEffect; - -import static mindustry.Vars.waveTeam; +import static mindustry.Vars.*; public class StatusEffects implements ContentList{ public static StatusEffect none, burning, freezing, wet, melting, tarred, overdrive, shielded, shocked, corroded, boss; @@ -48,7 +47,7 @@ public class StatusEffects implements ContentList{ init(() -> { trans(shocked, ((unit, time, newTime, result) -> { unit.damage(20f); - if(unit.getTeam() == waveTeam){ + if(unit.getTeam() == state.rules.waveTeam){ Events.fire(Trigger.shock); } result.set(this, time); diff --git a/core/src/mindustry/core/Control.java b/core/src/mindustry/core/Control.java index f525494963..ef31948c82 100644 --- a/core/src/mindustry/core/Control.java +++ b/core/src/mindustry/core/Control.java @@ -63,7 +63,7 @@ public class Control implements ApplicationListener, Loadable{ }); Events.on(PlayEvent.class, event -> { - player.setTeam(state.rules.pvp ? netServer.assignTeam(player, playerGroup.all()) : defaultTeam); + player.setTeam(state.rules.pvp ? netServer.assignTeam(player, playerGroup.all()) : state.rules.defaultTeam); player.setDead(true); player.add(); @@ -256,9 +256,9 @@ public class Control implements ApplicationListener, Loadable{ world.loadGenerator(zone.generator); zone.rules.get(state.rules); state.rules.zone = zone; - for(Tile core : state.teams.get(defaultTeam).cores){ + for(TileEntity core : state.teams.playerCores()){ for(ItemStack stack : zone.getStartingItems()){ - core.entity.items.add(stack.item, stack.amount); + core.items.add(stack.item, stack.amount); } } state.set(State.playing); @@ -294,8 +294,8 @@ public class Control implements ApplicationListener, Loadable{ Geometry.circle(coreb.x, coreb.y, 10, (cx, cy) -> { Tile tile = world.ltile(cx, cy); - if(tile != null && tile.getTeam() == defaultTeam && !(tile.block() instanceof CoreBlock)){ - world.removeBlock(tile); + if(tile != null && tile.getTeam() == state.rules.defaultTeam && !(tile.block() instanceof CoreBlock)){ + tile.remove(); } }); @@ -305,13 +305,13 @@ public class Control implements ApplicationListener, Loadable{ zone.rules.get(state.rules); state.rules.zone = zone; - for(Tile core : state.teams.get(defaultTeam).cores){ + for(TileEntity core : state.teams.playerCores()){ for(ItemStack stack : zone.getStartingItems()){ - core.entity.items.add(stack.item, stack.amount); + core.items.add(stack.item, stack.amount); } } - Tile core = state.teams.get(defaultTeam).cores.first(); - core.entity.items.clear(); + TileEntity core = state.teams.playerCores().first(); + core.items.clear(); logic.play(); state.rules.waveTimer = false; @@ -434,9 +434,9 @@ public class Control implements ApplicationListener, Loadable{ input.update(); if(world.isZone()){ - for(Tile tile : state.teams.get(player.getTeam()).cores){ + for(TileEntity tile : state.teams.cores(player.getTeam())){ for(Item item : content.items()){ - if(tile.entity != null && tile.entity.items.has(item)){ + if(tile.items.has(item)){ data.unlockContent(item); } } diff --git a/core/src/mindustry/core/GameState.java b/core/src/mindustry/core/GameState.java index eb7d419a10..2b233789eb 100644 --- a/core/src/mindustry/core/GameState.java +++ b/core/src/mindustry/core/GameState.java @@ -26,7 +26,7 @@ public class GameState{ private State state = State.menu; public BaseUnit boss(){ - return unitGroup.find(u -> u.isBoss() && u.getTeam() == waveTeam); + return unitGroup.find(u -> u.isBoss() && u.getTeam() == rules.waveTeam); } public void set(State astate){ diff --git a/core/src/mindustry/core/Logic.java b/core/src/mindustry/core/Logic.java index 86061bc6c6..17fedab303 100644 --- a/core/src/mindustry/core/Logic.java +++ b/core/src/mindustry/core/Logic.java @@ -107,9 +107,9 @@ public class Logic implements ApplicationListener{ //add starting items if(!world.isZone()){ - for(Team team : Team.all){ - if(!state.teams.get(team).cores.isEmpty()){ - TileEntity entity = state.teams.get(team).cores.first().entity; + for(TeamData team : state.teams.getActive()){ + if(team.hasCore()){ + TileEntity entity = team.core(); entity.items.clear(); for(ItemStack stack : state.rules.loadout){ entity.items.add(stack.item, stack.amount); @@ -143,23 +143,23 @@ public class Logic implements ApplicationListener{ } private void checkGameOver(){ - if(!state.rules.attackMode && state.teams.get(defaultTeam).cores.size == 0 && !state.gameOver){ + if(!state.rules.attackMode && state.teams.playerCores().size == 0 && !state.gameOver){ state.gameOver = true; - Events.fire(new GameOverEvent(waveTeam)); + Events.fire(new GameOverEvent(state.rules.waveTeam)); }else if(state.rules.attackMode){ Team alive = null; - for(Team team : Team.all){ - if(state.teams.get(team).cores.size > 0){ + for(TeamData team : state.teams.getActive()){ + if(team.hasCore()){ if(alive != null){ return; } - alive = team; + alive = team.team; } } if(alive != null && !state.gameOver){ - if(world.isZone() && alive == defaultTeam){ + if(world.isZone() && alive == state.rules.defaultTeam){ //in attack maps, a victorious game over is equivalent to a launch Call.launchZone(); }else{ @@ -176,7 +176,7 @@ public class Logic implements ApplicationListener{ ui.hudfrag.showLaunch(); } - for(Tile tile : state.teams.get(defaultTeam).cores){ + for(TileEntity tile : state.teams.playerCores()){ Effects.effect(Fx.launch, tile); } @@ -185,19 +185,18 @@ public class Logic implements ApplicationListener{ } Time.runTask(30f, () -> { - for(Tile tile : state.teams.get(defaultTeam).cores){ + for(TileEntity entity : state.teams.playerCores()){ for(Item item : content.items()){ - if(tile == null || tile.entity == null || tile.entity.items == null) continue; - data.addItem(item, tile.entity.items.get(item)); - Events.fire(new LaunchItemEvent(item, tile.entity.items.get(item))); + data.addItem(item, entity.items.get(item)); + Events.fire(new LaunchItemEvent(item, entity.items.get(item))); } - world.removeBlock(tile); + entity.tile.remove(); } state.launched = true; state.gameOver = true; Events.fire(new LaunchEvent()); //manually fire game over event now - Events.fire(new GameOverEvent(defaultTeam)); + Events.fire(new GameOverEvent(state.rules.defaultTeam)); }); } @@ -213,7 +212,7 @@ public class Logic implements ApplicationListener{ if(!state.is(State.menu)){ if(!net.client()){ - state.enemies = unitGroup.count(b -> b.getTeam() == waveTeam && b.countsAsEnemy()); + state.enemies = unitGroup.count(b -> b.getTeam() == state.rules.waveTeam && b.countsAsEnemy()); } if(!state.isPaused()){ diff --git a/core/src/mindustry/core/NetServer.java b/core/src/mindustry/core/NetServer.java index 4c86ecb9d0..3e325e5b31 100644 --- a/core/src/mindustry/core/NetServer.java +++ b/core/src/mindustry/core/NetServer.java @@ -17,11 +17,13 @@ import mindustry.entities.traits.*; import mindustry.entities.type.*; import mindustry.game.EventType.*; import mindustry.game.*; +import mindustry.game.Teams.*; import mindustry.gen.*; import mindustry.net.*; import mindustry.net.Administration.*; import mindustry.net.Packets.*; import mindustry.world.*; +import mindustry.world.blocks.storage.CoreBlock.*; import java.io.*; import java.nio.*; @@ -402,18 +404,16 @@ public class NetServer implements ApplicationListener{ public Team assignTeam(Player current, Iterable players){ //find team with minimum amount of players and auto-assign player to that. - return Structs.findMin(Team.all, team -> { - if(state.teams.isActive(team) && !state.teams.get(team).cores.isEmpty()){ - int count = 0; - for(Player other : players){ - if(other.getTeam() == team && other != current){ - count++; - } + TeamData re = state.teams.getActive().min(data -> { + int count = 0; + for(Player other : players){ + if(other.getTeam() == data.team && other != current){ + count++; } - return count; } - return Integer.MAX_VALUE; + return count; }); + return re == null ? null : re.team; } public void sendWorldData(Player player){ @@ -584,8 +584,8 @@ public class NetServer implements ApplicationListener{ public boolean isWaitingForPlayers(){ if(state.rules.pvp){ int used = 0; - for(Team t : Team.all){ - if(playerGroup.count(p -> p.getTeam() == t) > 0){ + for(TeamData t : state.teams.getActive()){ + if(playerGroup.count(p -> p.getTeam() == t.team) > 0){ used++; } } @@ -647,13 +647,13 @@ public class NetServer implements ApplicationListener{ public void writeEntitySnapshot(Player player) throws IOException{ syncStream.reset(); - ObjectSet cores = state.teams.get(player.getTeam()).cores; + Array cores = state.teams.cores(player.getTeam()); dataStream.writeByte(cores.size); - for(Tile tile : cores){ - dataStream.writeInt(tile.pos()); - tile.entity.items.write(dataStream); + for(CoreEntity entity : cores){ + dataStream.writeInt(entity.tile.pos()); + entity.items.write(dataStream); } dataStream.close(); diff --git a/core/src/mindustry/core/Renderer.java b/core/src/mindustry/core/Renderer.java index 2a7cd16922..94528a62d8 100644 --- a/core/src/mindustry/core/Renderer.java +++ b/core/src/mindustry/core/Renderer.java @@ -18,11 +18,10 @@ import mindustry.entities.effect.*; import mindustry.entities.effect.GroundEffectEntity.*; import mindustry.entities.traits.*; import mindustry.entities.type.*; -import mindustry.game.*; import mindustry.game.EventType.*; import mindustry.graphics.*; import mindustry.input.*; -import mindustry.ui.Cicon; +import mindustry.ui.*; import mindustry.world.blocks.defense.ForceProjector.*; import static arc.Core.*; @@ -344,11 +343,7 @@ public class Renderer implements ApplicationListener{ Draw.rect("circle-shadow", u.x, u.y, size * rad, size * rad); }; - for(EntityGroup group : unitGroups){ - if(!group.isEmpty()){ - group.draw(unit -> !unit.isDead(), draw::get); - } - } + unitGroup.draw(unit -> !unit.isDead(), draw::get); if(!playerGroup.isEmpty()){ playerGroup.draw(unit -> !unit.isDead(), draw::get); @@ -361,34 +356,21 @@ public class Renderer implements ApplicationListener{ float trnsX = -12, trnsY = -13; Draw.color(0, 0, 0, 0.22f); - for(EntityGroup group : unitGroups){ - if(!group.isEmpty()){ - group.draw(unit -> unit.isFlying() && !unit.isDead(), baseUnit -> baseUnit.drawShadow(trnsX, trnsY)); - } - } - - if(!playerGroup.isEmpty()){ - playerGroup.draw(unit -> unit.isFlying() && !unit.isDead(), player -> player.drawShadow(trnsX, trnsY)); - } + unitGroup.draw(unit -> unit.isFlying() && !unit.isDead(), baseUnit -> baseUnit.drawShadow(trnsX, trnsY)); + playerGroup.draw(unit -> unit.isFlying() && !unit.isDead(), player -> player.drawShadow(trnsX, trnsY)); Draw.color(); } private void drawAllTeams(boolean flying){ - for(Team team : Team.all){ - EntityGroup group = unitGroups[(int) team.id]; + unitGroup.draw(u -> u.isFlying() == flying && !u.isDead(), Unit::drawUnder); + playerGroup.draw(p -> p.isFlying() == flying && !p.isDead(), Unit::drawUnder); - if(group.count(p -> p.isFlying() == flying) + playerGroup.count(p -> p.isFlying() == flying && p.getTeam() == team) == 0 && flying) continue; + unitGroup.draw(u -> u.isFlying() == flying && !u.isDead(), Unit::drawAll); + playerGroup.draw(p -> p.isFlying() == flying, Unit::drawAll); - unitGroups[(int) team.id].draw(u -> u.isFlying() == flying && !u.isDead(), Unit::drawUnder); - playerGroup.draw(p -> p.isFlying() == flying && p.getTeam() == team && !p.isDead(), Unit::drawUnder); - - unitGroups[(int) team.id].draw(u -> u.isFlying() == flying && !u.isDead(), Unit::drawAll); - playerGroup.draw(p -> p.isFlying() == flying && p.getTeam() == team, Unit::drawAll); - - unitGroups[(int) team.id].draw(u -> u.isFlying() == flying && !u.isDead(), Unit::drawOver); - playerGroup.draw(p -> p.isFlying() == flying && p.getTeam() == team, Unit::drawOver); - } + unitGroup.draw(u -> u.isFlying() == flying && !u.isDead(), Unit::drawOver); + playerGroup.draw(p -> p.isFlying() == flying, Unit::drawOver); } public void scaleCamera(float amount){ diff --git a/core/src/mindustry/core/World.java b/core/src/mindustry/core/World.java index 3cdd2ca4f9..ea0e9aa054 100644 --- a/core/src/mindustry/core/World.java +++ b/core/src/mindustry/core/World.java @@ -1,15 +1,15 @@ package mindustry.core; import arc.*; -import arc.struct.*; import arc.math.*; import arc.math.geom.*; -import arc.util.*; +import arc.struct.*; import arc.util.ArcAnnotate.*; -import mindustry.content.*; +import arc.util.*; import mindustry.core.GameState.*; import mindustry.game.EventType.*; import mindustry.game.*; +import mindustry.game.Teams.*; import mindustry.io.*; import mindustry.maps.*; import mindustry.maps.filters.*; @@ -233,33 +233,22 @@ public class World{ invalidMap = false; if(!headless){ - if(state.teams.get(defaultTeam).cores.size == 0 && !checkRules.pvp){ + if(state.teams.playerCores().size == 0 && !checkRules.pvp){ ui.showErrorMessage("$map.nospawn"); invalidMap = true; }else if(checkRules.pvp){ //pvp maps need two cores to be valid - int teams = 0; - for(Team team : Team.all){ - if(state.teams.get(team).cores.size != 0){ - teams ++; - } - } - if(teams < 2){ + if(state.teams.getActive().count(TeamData::hasCore) < 2){ invalidMap = true; ui.showErrorMessage("$map.nospawn.pvp"); } }else if(checkRules.attackMode){ //attack maps need two cores to be valid - invalidMap = state.teams.get(waveTeam).cores.isEmpty(); + invalidMap = state.teams.get(state.rules.waveTeam).noCores(); if(invalidMap){ ui.showErrorMessage("$map.nospawn.attack"); } } }else{ - invalidMap = true; - for(Team team : Team.all){ - if(state.teams.get(team).cores.size != 0){ - invalidMap = false; - } - } + invalidMap = !state.teams.getActive().contains(TeamData::hasCore); if(invalidMap){ throw new MapException(map, "Map has no cores!"); @@ -275,36 +264,6 @@ public class World{ } } - public void removeBlock(Tile tile){ - if(tile == null) return; - tile.link().getLinkedTiles(other -> other.setBlock(Blocks.air)); - } - - public void setBlock(Tile tile, Block block, Team team){ - setBlock(tile, block, team, 0); - } - - public void setBlock(Tile tile, Block block, Team team, int rotation){ - tile.setBlock(block, team, rotation); - if(block.isMultiblock()){ - int offsetx = -(block.size - 1) / 2; - int offsety = -(block.size - 1) / 2; - - for(int dx = 0; dx < block.size; dx++){ - for(int dy = 0; dy < block.size; dy++){ - int worldx = dx + offsetx + tile.x; - int worldy = dy + offsety + tile.y; - if(!(worldx == tile.x && worldy == tile.y)){ - Tile toplace = world.tile(worldx, worldy); - if(toplace != null){ - toplace.setBlock(BlockPart.get(dx + offsetx, dy + offsety), team); - } - } - } - } - } - } - public void raycastEachWorld(float x0, float y0, float x1, float y1, Raycaster cons){ raycastEach(toTile(x0), toTile(y0), toTile(x1), toTile(y1), cons); } diff --git a/core/src/mindustry/editor/DrawOperation.java b/core/src/mindustry/editor/DrawOperation.java index 22a7ad5730..061a7aee84 100755 --- a/core/src/mindustry/editor/DrawOperation.java +++ b/core/src/mindustry/editor/DrawOperation.java @@ -69,7 +69,7 @@ public class DrawOperation{ }else if(type == OpType.rotation.ordinal()){ tile.rotation(to); }else if(type == OpType.team.ordinal()){ - tile.setTeam(Team.all[to]); + tile.setTeam(Team.get(to)); }else if(type == OpType.overlay.ordinal()){ tile.setOverlayID(to); } diff --git a/core/src/mindustry/editor/EditorTile.java b/core/src/mindustry/editor/EditorTile.java index f9d00b8903..4a9effccfd 100644 --- a/core/src/mindustry/editor/EditorTile.java +++ b/core/src/mindustry/editor/EditorTile.java @@ -74,7 +74,7 @@ public class EditorTile extends Tile{ return; } - if(getTeamID() == (int) team.id) return; + if(getTeamID() == (int)team.id) return; op(OpType.team, getTeamID()); super.setTeam(team); } diff --git a/core/src/mindustry/editor/EditorTool.java b/core/src/mindustry/editor/EditorTool.java index a2a6927398..50442ff0f2 100644 --- a/core/src/mindustry/editor/EditorTool.java +++ b/core/src/mindustry/editor/EditorTool.java @@ -1,15 +1,14 @@ package mindustry.editor; -import arc.struct.IntArray; import arc.func.*; -import arc.math.Mathf; -import arc.math.geom.Bresenham2; -import arc.util.Structs; -import mindustry.Vars; -import mindustry.content.Blocks; -import mindustry.game.Team; +import arc.math.*; +import arc.math.geom.*; +import arc.struct.*; +import arc.util.*; +import mindustry.content.*; +import mindustry.game.*; import mindustry.world.*; -import mindustry.world.blocks.BlockPart; +import mindustry.world.blocks.*; public enum EditorTool{ zoom, @@ -80,7 +79,7 @@ public enum EditorTool{ editor.drawCircle(x, y, tile -> { if(mode == -1){ //erase block - Vars.world.removeBlock(tile); + tile.remove(); }else if(mode == 0){ //erase ore tile.clearOverlay(); @@ -141,7 +140,7 @@ public enum EditorTool{ if(tile.link().synthetic()){ Team dest = tile.getTeam(); if(dest == editor.drawTeam) return; - fill(editor, x, y, false, t -> t.getTeamID() == (int) dest.id && t.link().synthetic(), t -> t.setTeam(editor.drawTeam)); + fill(editor, x, y, false, t -> t.getTeamID() == (int)dest.id && t.link().synthetic(), t -> t.setTeam(editor.drawTeam)); } } } diff --git a/core/src/mindustry/editor/MapEditor.java b/core/src/mindustry/editor/MapEditor.java index c83c754b4e..7cab015b1f 100644 --- a/core/src/mindustry/editor/MapEditor.java +++ b/core/src/mindustry/editor/MapEditor.java @@ -10,7 +10,6 @@ import arc.util.Structs; import mindustry.content.Blocks; import mindustry.game.Team; import mindustry.gen.TileOp; -import mindustry.io.LegacyMapIO; import mindustry.io.MapIO; import mindustry.maps.Map; import mindustry.world.*; @@ -65,7 +64,7 @@ public class MapEditor{ reset(); createTiles(pixmap.getWidth(), pixmap.getHeight()); - load(() -> LegacyMapIO.readPixmap(pixmap, tiles())); + load(() -> MapIO.readPixmap(pixmap, tiles())); renderer.resize(width(), height()); } @@ -86,7 +85,7 @@ public class MapEditor{ for(int x = 0; x < width(); x++){ for(int y = 0; y < height(); y++){ if(tiles[x][y].block().isMultiblock()){ - world.setBlock(tiles[x][y], tiles[x][y].block(), tiles[x][y].getTeam()); + tiles[x][y].set(tiles[x][y].block(), tiles[x][y].getTeam()); } } } @@ -176,7 +175,7 @@ public class MapEditor{ } } - world.setBlock(tile(x, y), drawBlock, drawTeam); + tile(x, y).set(drawBlock, drawTeam); }else{ boolean isFloor = drawBlock.isFloor() && drawBlock != Blocks.air; @@ -185,7 +184,7 @@ public class MapEditor{ //remove linked tiles blocking the way if(!isFloor && (tile.isLinked() || tile.block().isMultiblock())){ - world.removeBlock(tile.link()); + tile.link().remove(); } if(isFloor){ diff --git a/core/src/mindustry/editor/MapEditorDialog.java b/core/src/mindustry/editor/MapEditorDialog.java index 0ee0fca085..b9a28501b9 100644 --- a/core/src/mindustry/editor/MapEditorDialog.java +++ b/core/src/mindustry/editor/MapEditorDialog.java @@ -551,7 +551,7 @@ public class MapEditorDialog extends Dialog implements Disposable{ int i = 0; - for(Team team : Team.all){ + for(Team team : Team.base()){ ImageButton button = new ImageButton(Tex.whiteui, Styles.clearTogglePartiali); button.margin(4f); button.getImageCell().grow(); diff --git a/core/src/mindustry/editor/MapGenerateDialog.java b/core/src/mindustry/editor/MapGenerateDialog.java index 976d7fc3b2..8704b8a209 100644 --- a/core/src/mindustry/editor/MapGenerateDialog.java +++ b/core/src/mindustry/editor/MapGenerateDialog.java @@ -138,7 +138,7 @@ public class MapGenerateDialog extends FloatingDialog{ tile.rotation(write.rotation); tile.setFloor((Floor)content.block(write.floor)); tile.setBlock(content.block(write.block)); - tile.setTeam(Team.all[write.team]); + tile.setTeam(Team.get(write.team)); tile.setOverlay(content.block(write.ore)); } } @@ -367,7 +367,7 @@ public class MapGenerateDialog extends FloatingDialog{ GenTile tile = buffer1[px][py]; input.apply(x, y, content.block(tile.floor), content.block(tile.block), content.block(tile.ore)); filter.apply(input); - buffer2[px][py].set(input.floor, input.block, input.ore, Team.all[tile.team], tile.rotation); + buffer2[px][py].set(input.floor, input.block, input.ore, Team.get(tile.team), tile.rotation); } } for(int px = 0; px < pixmap.getWidth(); px++){ @@ -415,7 +415,7 @@ public class MapGenerateDialog extends FloatingDialog{ this.floor = floor.id; this.block = wall.id; this.ore = ore.id; - this.team = (byte) (int) team.id; + this.team = (byte) (int)team.id; this.rotation = (byte)rotation; } @@ -437,7 +437,7 @@ public class MapGenerateDialog extends FloatingDialog{ ctile.setBlock(content.block(block)); ctile.setOverlay(content.block(ore)); ctile.rotation(rotation); - ctile.setTeam(Team.all[team]); + ctile.setTeam(Team.get(team)); return ctile; } } diff --git a/core/src/mindustry/entities/Damage.java b/core/src/mindustry/entities/Damage.java index a9bdd04f3f..3fe1b00d31 100644 --- a/core/src/mindustry/entities/Damage.java +++ b/core/src/mindustry/entities/Damage.java @@ -88,7 +88,7 @@ public class Damage{ tr.trns(angle, length); Intc2 collider = (cx, cy) -> { Tile tile = world.ltile(cx, cy); - if(tile != null && !collidedBlocks.contains(tile.pos()) && tile.entity != null && tile.getTeamID() != (int) team.id && tile.entity.collide(hitter)){ + if(tile != null && !collidedBlocks.contains(tile.pos()) && tile.entity != null && tile.getTeamID() != (int)team.id && tile.entity.collide(hitter)){ tile.entity.collision(hitter); collidedBlocks.add(tile.pos()); hitter.getBulletType().hit(hitter, tile.worldx(), tile.worldy()); diff --git a/core/src/mindustry/entities/Units.java b/core/src/mindustry/entities/Units.java index ad228556b8..09e0293241 100644 --- a/core/src/mindustry/entities/Units.java +++ b/core/src/mindustry/entities/Units.java @@ -157,7 +157,7 @@ public class Units{ /** Iterates over all units in a rectangle. */ public static void nearby(Team team, float x, float y, float width, float height, Cons cons){ - unitGroups[(int) team.id].intersect(x, y, width, height, cons); + unitGroups[(int)team.id].intersect(x, y, width, height, cons); playerGroup.intersect(x, y, width, height, player -> { if(player.getTeam() == team){ cons.get(player); @@ -167,7 +167,7 @@ public class Units{ /** Iterates over all units in a circle around this position. */ public static void nearby(Team team, float x, float y, float radius, Cons cons){ - unitGroups[(int) team.id].intersect(x - radius, y - radius, radius*2f, radius*2f, unit -> { + unitGroups[(int)team.id].intersect(x - radius, y - radius, radius*2f, radius*2f, unit -> { if(unit.withinDst(x, y, radius)){ cons.get(unit); } @@ -183,7 +183,7 @@ public class Units{ /** Iterates over all units in a rectangle. */ public static void nearby(float x, float y, float width, float height, Cons cons){ for(Team team : Team.all){ - unitGroups[(int) team.id].intersect(x, y, width, height, cons); + unitGroups[(int)team.id].intersect(x, y, width, height, cons); } playerGroup.intersect(x, y, width, height, cons); @@ -199,7 +199,7 @@ public class Units{ EnumSet targets = state.teams.enemiesOf(team); for(Team other : targets){ - unitGroups[(int) other.id].intersect(x, y, width, height, cons); + unitGroups[(int)other.id].intersect(x, y, width, height, cons); } playerGroup.intersect(x, y, width, height, player -> { @@ -216,10 +216,7 @@ public class Units{ /** Iterates over all units. */ public static void all(Cons cons){ - for(Team team : Team.all){ - unitGroups[(int) team.id].all().each(cons); - } - + unitGroup.all().each(cons); playerGroup.all().each(cons); } diff --git a/core/src/mindustry/entities/type/BaseUnit.java b/core/src/mindustry/entities/type/BaseUnit.java index 28a6eea861..03b4f2d0de 100644 --- a/core/src/mindustry/entities/type/BaseUnit.java +++ b/core/src/mindustry/entities/type/BaseUnit.java @@ -185,23 +185,16 @@ public abstract class BaseUnit extends Unit implements ShooterTrait{ } } - public Tile getClosest(BlockFlag flag){ + public @Nullable Tile getClosest(BlockFlag flag){ return Geometry.findClosest(x, y, indexer.getAllied(team, flag)); } - public Tile getClosestSpawner(){ + public @Nullable Tile getClosestSpawner(){ return Geometry.findClosest(x, y, Vars.spawner.getGroundSpawns()); } - public TileEntity getClosestEnemyCore(){ - for(Team enemy : Vars.state.teams.enemiesOf(team)){ - Tile tile = Geometry.findClosest(x, y, Vars.state.teams.get(enemy).cores); - if(tile != null){ - return tile.entity; - } - } - - return null; + public @Nullable TileEntity getClosestEnemyCore(){ + return Vars.state.teams.closestEnemyCore(x, y, team); } public UnitState getStartState(){ @@ -370,7 +363,7 @@ public abstract class BaseUnit extends Unit implements ShooterTrait{ @Override public EntityGroup targetGroup(){ - return unitGroups[(int) team.id]; + return unitGroup; } @Override diff --git a/core/src/mindustry/entities/type/TileEntity.java b/core/src/mindustry/entities/type/TileEntity.java index 85c6c9d2eb..4a2a5aee91 100644 --- a/core/src/mindustry/entities/type/TileEntity.java +++ b/core/src/mindustry/entities/type/TileEntity.java @@ -124,7 +124,8 @@ public class TileEntity extends BaseEntity implements TargetTrait, HealthTrait{ @CallSuper public void write(DataOutput stream) throws IOException{ stream.writeShort((short)health); - stream.writeByte(Pack.byteByte(tile.getTeamID(), tile.rotation())); //team + rotation + stream.writeByte(Pack.byteByte((byte)8, tile.rotation())); //rotation + marker to indicate that team is moved (8 isn't valid) + stream.writeByte(tile.getTeamID()); if(items != null) items.write(stream); if(power != null) power.write(stream); if(liquids != null) liquids.write(stream); @@ -134,11 +135,11 @@ public class TileEntity extends BaseEntity implements TargetTrait, HealthTrait{ @CallSuper public void read(DataInput stream, byte revision) throws IOException{ health = stream.readUnsignedShort(); - byte tr = stream.readByte(); - byte team = Pack.leftByte(tr); - byte rotation = Pack.rightByte(tr); + byte packedrot = stream.readByte(); + byte team = Pack.leftByte(packedrot) == 8 ? stream.readByte() : Pack.leftByte(packedrot); + byte rotation = Pack.rightByte(packedrot); - tile.setTeam(Team.all[team]); + tile.setTeam(Team.get(team)); tile.rotation(rotation); if(items != null) items.read(stream); @@ -277,7 +278,7 @@ public class TileEntity extends BaseEntity implements TargetTrait, HealthTrait{ Events.fire(new BlockDestroyEvent(tile)); block.breakSound.at(tile); block.onDestroyed(tile); - world.removeBlock(tile); + tile.remove(); remove(); } } diff --git a/core/src/mindustry/entities/type/Unit.java b/core/src/mindustry/entities/type/Unit.java index 81ec1de7cb..0b0ccc277a 100644 --- a/core/src/mindustry/entities/type/Unit.java +++ b/core/src/mindustry/entities/type/Unit.java @@ -1,12 +1,12 @@ package mindustry.entities.type; import arc.*; -import arc.struct.*; import arc.graphics.*; import arc.graphics.g2d.*; import arc.math.*; import arc.math.geom.*; import arc.scene.ui.layout.*; +import arc.struct.*; import arc.util.*; import arc.util.ArcAnnotate.*; import mindustry.content.*; @@ -16,13 +16,11 @@ import mindustry.entities.traits.*; import mindustry.entities.units.*; import mindustry.game.EventType.*; import mindustry.game.*; -import mindustry.game.Teams.*; import mindustry.gen.*; import mindustry.graphics.*; import mindustry.net.*; import mindustry.type.*; import mindustry.ui.*; -import mindustry.ui.Cicon; import mindustry.world.*; import mindustry.world.blocks.*; @@ -158,7 +156,7 @@ public abstract class Unit extends DestructibleEntity implements SaveTrait, Targ this.item.amount = itemAmount; this.item.item = content.item(itemID); this.dead = dead; - this.team = Team.all[team]; + this.team = Team.get(team); this.health = health; this.x = x; this.y = y; @@ -169,7 +167,7 @@ public abstract class Unit extends DestructibleEntity implements SaveTrait, Targ public void writeSave(DataOutput stream, boolean net) throws IOException{ if(item.item == null) item.item = Items.copper; - stream.writeByte((int) team.id); + stream.writeByte((int)team.id); stream.writeBoolean(isDead()); stream.writeFloat(net ? interpolator.target.x : x); stream.writeFloat(net ? interpolator.target.y : y); @@ -217,13 +215,7 @@ public abstract class Unit extends DestructibleEntity implements SaveTrait, Targ float fsize = getSize() / radScl; moveVector.setZero(); float cx = x - fsize/2f, cy = y - fsize/2f; - - for(Team team : Team.all){ - if(team != getTeam() || !(this instanceof Player)){ - avoid(unitGroups[(int) team.id].intersect(cx, cy, fsize, fsize)); - } - } - + avoid(unitGroup.intersect(cx, cy, fsize, fsize)); if(!(this instanceof Player)){ avoid(playerGroup.intersect(cx, cy, fsize, fsize)); } @@ -242,14 +234,7 @@ public abstract class Unit extends DestructibleEntity implements SaveTrait, Targ } public @Nullable TileEntity getClosestCore(){ - TeamData data = state.teams.get(team); - - Tile tile = Geometry.findClosest(x, y, data.cores); - if(tile == null){ - return null; - }else{ - return tile.entity; - } + return state.teams.closestCore(x, y, team); } public Floor getFloorOn(){ @@ -275,7 +260,7 @@ public abstract class Unit extends DestructibleEntity implements SaveTrait, Targ } //apply knockback based on spawns - if(getTeam() != waveTeam){ + if(getTeam() != state.rules.waveTeam){ float relativeSize = state.rules.dropZoneRadius + getSize()/2f + 1f; for(Tile spawn : spawner.getGroundSpawns()){ if(withinDst(spawn.worldx(), spawn.worldy(), relativeSize)){ diff --git a/core/src/mindustry/entities/type/base/BuilderDrone.java b/core/src/mindustry/entities/type/base/BuilderDrone.java index aad348b9ce..83d4606122 100644 --- a/core/src/mindustry/entities/type/base/BuilderDrone.java +++ b/core/src/mindustry/entities/type/base/BuilderDrone.java @@ -114,7 +114,7 @@ public class BuilderDrone extends BaseDrone implements BuilderTrait{ public BuilderDrone(){ if(reset.check()){ Events.on(BuildSelectEvent.class, event -> { - EntityGroup group = unitGroups[(int) event.team.id]; + EntityGroup group = unitGroups[(int)event.team.id]; if(!(event.tile.entity instanceof BuildEntity)) return; diff --git a/core/src/mindustry/entities/units/UnitDrops.java b/core/src/mindustry/entities/units/UnitDrops.java index b58171ee2f..f57ff0a75d 100644 --- a/core/src/mindustry/entities/units/UnitDrops.java +++ b/core/src/mindustry/entities/units/UnitDrops.java @@ -7,13 +7,14 @@ import mindustry.entities.type.BaseUnit; import mindustry.entities.type.TileEntity; import mindustry.gen.Call; import mindustry.type.Item; +import static mindustry.Vars.*; public class UnitDrops{ private static Item[] dropTable; public static void dropItems(BaseUnit unit){ //items only dropped in waves for enemy team - if(unit.getTeam() != Vars.waveTeam || !Vars.state.rules.unitDrops){ + if(unit.getTeam() != state.rules.waveTeam || !Vars.state.rules.unitDrops){ return; } diff --git a/core/src/mindustry/game/Gamemode.java b/core/src/mindustry/game/Gamemode.java index aca4d3340e..3679ba0ad2 100644 --- a/core/src/mindustry/game/Gamemode.java +++ b/core/src/mindustry/game/Gamemode.java @@ -4,7 +4,7 @@ import arc.*; import arc.func.*; import mindustry.maps.*; -import static mindustry.Vars.waveTeam; +import static mindustry.Vars.*; /** Defines preset rule sets. */ public enum Gamemode{ @@ -22,7 +22,7 @@ public enum Gamemode{ attack(rules -> { rules.unitDrops = true; rules.attackMode = true; - }, map -> map.teams.contains((int) waveTeam.id)), + }, map -> map.teams.contains((int)state.rules.waveTeam.id)), pvp(rules -> { rules.pvp = true; rules.enemyCoreBuildRadius = 600f; diff --git a/core/src/mindustry/game/MusicControl.java b/core/src/mindustry/game/MusicControl.java index f4352f28be..26a44876ac 100644 --- a/core/src/mindustry/game/MusicControl.java +++ b/core/src/mindustry/game/MusicControl.java @@ -83,7 +83,7 @@ public class MusicControl{ /** Whether to play dark music.*/ private boolean isDark(){ - if(!state.teams.get(player.getTeam()).cores.isEmpty() && state.teams.get(player.getTeam()).cores.first().entity.healthf() < 0.85f){ + if(state.teams.get(player.getTeam()).hasCore() && state.teams.get(player.getTeam()).core().healthf() < 0.85f){ //core damaged -> dark return true; } diff --git a/core/src/mindustry/game/Rules.java b/core/src/mindustry/game/Rules.java index 8b40abd1ae..d910952021 100644 --- a/core/src/mindustry/game/Rules.java +++ b/core/src/mindustry/game/Rules.java @@ -78,6 +78,10 @@ public class Rules{ public boolean lighting = false; /** Ambient light color, used when lighting is enabled. */ public Color ambientLight = new Color(0.01f, 0.01f, 0.04f, 0.99f); + /** team of the player by default */ + public Team defaultTeam = Team.sharded; + /** team of the enemy in waves/sectors */ + public Team waveTeam = Team.crux; /** Copies this ruleset exactly. Not very efficient at all, do not use often. */ public Rules copy(){ diff --git a/core/src/mindustry/game/Schematics.java b/core/src/mindustry/game/Schematics.java index b9c56744a3..b30658692e 100644 --- a/core/src/mindustry/game/Schematics.java +++ b/core/src/mindustry/game/Schematics.java @@ -254,7 +254,7 @@ public class Schematics implements Loadable{ Tile tile = world.tile(st.x + ox, st.y + oy); if(tile == null) return; - world.setBlock(tile, st.block, defaultTeam); + tile.set(st.block, state.rules.defaultTeam); tile.rotation(st.rotation); if(st.block.posConfig){ tile.configureAny(Pos.get(tile.x - st.x + Pos.x(st.config), tile.y - st.y + Pos.y(st.config))); diff --git a/core/src/mindustry/game/Team.java b/core/src/mindustry/game/Team.java index a64e5fd127..a97d84a70b 100644 --- a/core/src/mindustry/game/Team.java +++ b/core/src/mindustry/game/Team.java @@ -2,34 +2,66 @@ package mindustry.game; import arc.*; import arc.graphics.*; -import arc.struct.*; +import arc.util.*; import mindustry.graphics.*; -public class Team{ - /** All registered teams. */ - public final static Array all = new Array<>(); - public final static Team - derelict = new Team("derelict", Color.valueOf("4d4e58")), - sharded = new Team("sharded", Pal.accent.cpy()), - crux = new Team("crux", Color.valueOf("e82d2d")), - green = new Team("green", Color.valueOf("4dd98b")), - purple = new Team("purple", Color.valueOf("9a4bdf")), - blue = new Team("blue", Color.royal.cpy()); - +public class Team implements Comparable{ public final Color color; public final int intColor; public final String name; - public final int id; + public final byte id; - public Team(String name, Color color){ + /** All 256 registered teams. */ + private static final Team[] all = new Team[256]; + /** The 6 base teams used in the editor. */ + private static final Team[] baseTeams = new Team[6]; + + public final static Team + derelict = new Team(0, "derelict", Color.valueOf("4d4e58")), + sharded = new Team(1, "sharded", Pal.accent.cpy()), + crux = new Team(2, "crux", Color.valueOf("e82d2d")), + green = new Team(3, "green", Color.valueOf("4dd98b")), + purple = new Team(4, "purple", Color.valueOf("9a4bdf")), + blue = new Team(5, "blue", Color.royal.cpy()); + + static{ + //create the whole 256 placeholder teams + for(int i = 6; i < all.length; i++){ + new Team(i, "team#" + i, Color.HSVtoRGB(360f * (float)(i) / all.length, 100f, 100f, 1f)); + } + } + + public static Team get(int id){ + return all[Pack.u((byte)id)]; + } + + /** @return the 6 base team colors. */ + public static Team[] base(){ + return baseTeams; + } + + /** @return all the teams - do not use this for lookup! */ + public static Team[] all(){ + return all; + } + + protected Team(int id, String name, Color color){ this.name = name; this.color = color; this.intColor = Color.rgba8888(color); - this.id = all.size; - all.add(this); + this.id = (byte)id; + + int us = Pack.u(this.id); + if(us < 6) baseTeams[us] = this; + all[us] = this; } public String localized(){ - return Core.bundle.get("team." + name + ".name"); + return Core.bundle.get("team." + name + ".name", name); + } + + @Override + public int compareTo(Team team){ + return Integer.compare(id, team.id); } } diff --git a/core/src/mindustry/game/Teams.java b/core/src/mindustry/game/Teams.java index d77b7902ae..d5d033ec46 100644 --- a/core/src/mindustry/game/Teams.java +++ b/core/src/mindustry/game/Teams.java @@ -1,44 +1,82 @@ package mindustry.game; import arc.func.*; +import arc.math.geom.*; import arc.struct.*; -import mindustry.*; +import arc.util.*; +import arc.util.ArcAnnotate.*; import mindustry.entities.type.*; -import mindustry.world.*; +import mindustry.world.blocks.storage.CoreBlock.*; + +import static mindustry.Vars.state; /** Class for various team-based utilities. */ public class Teams{ /** Maps team IDs to team data. */ - private Array map = new Array<>(); + private TeamData[] map = new TeamData[256]; /** Active teams. */ private Array active = new Array<>(); - public T eachEnemyCore(Team team, Func ret){ - T out = null; - //todo each enemy, each enemy core... - return out; + public @Nullable CoreEntity closestEnemyCore(float x, float y, Team team){ + for(TeamData data : active){ + if(areEnemies(team, data.team)){ + CoreEntity tile = Geometry.findClosest(x, y, data.cores); + if(tile != null){ + return tile; + } + } + } + return null; } - /** - * Register a team. - * @param team The team type enum. - */ - public void add(Team team){ - map[team.id] = new TeamData(team); + public @Nullable CoreEntity closestCore(float x, float y, Team team){ + return Geometry.findClosest(x, y, get(team).cores); + } + + public boolean eachEnemyCore(Team team, Boolf ret){ + for(TeamData data : active){ + if(areEnemies(team, data.team)){ + for(CoreEntity tile : data.cores){ + if(ret.get(tile)){ + return true; + } + } + } + } + return false; + } + + public void eachEnemyCore(Team team, Cons ret){ + for(TeamData data : active){ + if(areEnemies(team, data.team)){ + for(TileEntity tile : data.cores){ + ret.get(tile); + } + } + } } /** Returns team data by type. */ public TeamData get(Team team){ - if(map[team.id] == null){ - add(team); + if(map[Pack.u(team.id)] == null){ + map[Pack.u(team.id)] = new TeamData(team); } - return map[team.id]; + return map[Pack.u(team.id)]; + } + + public Array playerCores(){ + return get(state.rules.defaultTeam).cores; + } + + /** Do not modify! */ + public Array cores(Team team){ + return get(team).cores; } /** Returns whether a team is active, e.g. whether it has any cores remaining. */ public boolean isActive(Team team){ //the enemy wave team is always active - return team == Vars.waveTeam || get(team).cores.size > 0; + return team == state.rules.waveTeam || get(team).cores.size > 0; } /** Returns whether {@param other} is an enemy of {@param #team}. */ @@ -47,20 +85,63 @@ public class Teams{ return team != other; } - /** Allocates a new array with the active teams. - * Never call in the main game loop.*/ - public Array getActive(){ - return Array.select(map, t -> t != null); + public boolean canInteract(Team team, Team other){ + return team == other || other == Team.derelict; } - public static class TeamData{ - public final ObjectSet cores = new ObjectSet<>(); + /** Do not modify. */ + public Array getActive(){ + return active; + } + + public void registerCore(CoreEntity core){ + TeamData data = get(core.getTeam()); + //add core if not present + if(!data.cores.contains(core)){ + data.cores.add(core); + } + + //register in active list if needed + if(data.active() && !active.contains(data)){ + active.add(data); + } + } + + public void unregisterCore(CoreEntity entity){ + TeamData data = get(entity.getTeam()); + //remove core + data.cores.remove(entity); + //unregister in active list + if(!data.active()){ + active.remove(data); + } + } + + public class TeamData{ + private final Array cores = new Array<>(); + public final Team team; public Queue brokenBlocks = new Queue<>(); public TeamData(Team team){ this.team = team; } + + public boolean active(){ + return team == state.rules.waveTeam || cores.size > 0; + } + + public boolean hasCore(){ + return cores.size > 0; + } + + public boolean noCores(){ + return cores.isEmpty(); + } + + public TileEntity core(){ + return cores.first(); + } } /** Represents a block made by this team that was destroyed somewhere on the map. diff --git a/core/src/mindustry/game/Tutorial.java b/core/src/mindustry/game/Tutorial.java index 569fbd380c..300ab01283 100644 --- a/core/src/mindustry/game/Tutorial.java +++ b/core/src/mindustry/game/Tutorial.java @@ -10,6 +10,7 @@ import arc.scene.ui.*; import arc.scene.ui.layout.*; import arc.util.*; import mindustry.content.*; +import mindustry.entities.type.*; import mindustry.game.EventType.*; import mindustry.graphics.*; import mindustry.type.*; @@ -161,7 +162,7 @@ public class Tutorial{ }, withdraw(() -> event("withdraw")){ void begin(){ - state.teams.get(defaultTeam).cores.first().entity.items.add(Items.copper, 10); + state.teams.playerCores().first().items.add(Items.copper, 10); } }, deposit(() -> event("deposit")), @@ -239,18 +240,18 @@ public class Tutorial{ //utility static void placeBlocks(){ - Tile core = state.teams.get(defaultTeam).cores.first(); + TileEntity core = state.teams.playerCores().first(); for(int i = 0; i < blocksToBreak; i++){ - world.removeBlock(world.ltile(core.x + blockOffset, core.y + i)); - world.tile(core.x + blockOffset, core.y + i).setBlock(Blocks.scrapWall, defaultTeam); + world.ltile(core.tile.x + blockOffset, core.tile.y + i).remove(); + world.tile(core.tile.x + blockOffset, core.tile.y + i).setBlock(Blocks.scrapWall, state.rules.defaultTeam); } } static boolean blocksBroken(){ - Tile core = state.teams.get(defaultTeam).cores.first(); + TileEntity core = state.teams.playerCores().first(); for(int i = 0; i < blocksToBreak; i++){ - if(world.tile(core.x + blockOffset, core.y + i).block() == Blocks.scrapWall){ + if(world.tile(core.tile.x + blockOffset, core.tile.y + i).block() == Blocks.scrapWall){ return false; } } @@ -270,7 +271,7 @@ public class Tutorial{ } static int item(Item item){ - return state.teams.get(defaultTeam).cores.isEmpty() ? 0 : state.teams.get(defaultTeam).cores.first().entity.items.get(item); + return state.teams.get(state.rules.defaultTeam).noCores() ? 0 : state.teams.playerCores().first().items.get(item); } static boolean toggled(String name){ diff --git a/core/src/mindustry/graphics/OverlayRenderer.java b/core/src/mindustry/graphics/OverlayRenderer.java index 3001159c74..3c65c1b9f4 100644 --- a/core/src/mindustry/graphics/OverlayRenderer.java +++ b/core/src/mindustry/graphics/OverlayRenderer.java @@ -10,13 +10,12 @@ import mindustry.*; import mindustry.content.*; import mindustry.entities.*; import mindustry.entities.type.*; -import mindustry.game.*; import mindustry.input.*; -import mindustry.type.Category; -import mindustry.ui.Cicon; +import mindustry.type.*; +import mindustry.ui.*; import mindustry.world.*; -import mindustry.world.blocks.units.MechPad; -import mindustry.world.meta.BlockFlag; +import mindustry.world.blocks.units.*; +import mindustry.world.meta.*; import static mindustry.Vars.*; @@ -95,17 +94,15 @@ public class OverlayRenderer{ Lines.stroke(buildFadeTime * 2f); if(buildFadeTime > 0.005f){ - for(Team enemy : state.teams.enemiesOf(player.getTeam())){ - for(Tile core : state.teams.get(enemy).cores){ - float dst = Mathf.dst(player.x, player.y, core.drawx(), core.drawy()); - if(dst < state.rules.enemyCoreBuildRadius * 1.5f){ - Draw.color(Color.darkGray); - Lines.circle(core.drawx(), core.drawy() - 2, state.rules.enemyCoreBuildRadius); - Draw.color(Pal.accent, enemy.color, 0.5f + Mathf.absin(Time.time(), 10f, 0.5f)); - Lines.circle(core.drawx(), core.drawy(), state.rules.enemyCoreBuildRadius); - } + state.teams.eachEnemyCore(player.getTeam(), core -> { + float dst = core.dst(player); + if(dst < state.rules.enemyCoreBuildRadius * 1.5f){ + Draw.color(Color.darkGray); + Lines.circle(core.x, core.y - 2, state.rules.enemyCoreBuildRadius); + Draw.color(Pal.accent, core.getTeam().color, 0.5f + Mathf.absin(Time.time(), 10f, 0.5f)); + Lines.circle(core.x, core.y, state.rules.enemyCoreBuildRadius); } - } + }); } Lines.stroke(2f); diff --git a/core/src/mindustry/input/DesktopInput.java b/core/src/mindustry/input/DesktopInput.java index b156c3f7f4..38aa0c2fd4 100644 --- a/core/src/mindustry/input/DesktopInput.java +++ b/core/src/mindustry/input/DesktopInput.java @@ -397,7 +397,7 @@ public class DesktopInput extends InputHandler{ } if(mode == placing && block != null){ - if(!overrideLineRotation && !Core.input.keyDown(Binding.diagonal_placement) && (selectX != cursorX || selectY != cursorY) && ((int) Core.input.axisTap(Binding.rotate) != 0)){ + if(!overrideLineRotation && !Core.input.keyDown(Binding.diagonal_placement) && (selectX != cursorX || selectY != cursorY) && ((int)Core.input.axisTap(Binding.rotate) != 0)){ rotation = ((int)((Angles.angle(selectX, selectY, cursorX, cursorY) + 45) / 90f)) % 4; overrideLineRotation = true; } diff --git a/core/src/mindustry/io/LegacyMapIO.java b/core/src/mindustry/io/LegacyMapIO.java deleted file mode 100644 index d3f975e821..0000000000 --- a/core/src/mindustry/io/LegacyMapIO.java +++ /dev/null @@ -1,214 +0,0 @@ -package mindustry.io; - -import arc.struct.*; -import arc.files.*; -import arc.graphics.*; -import arc.util.*; -import arc.util.serialization.*; -import mindustry.content.*; -import mindustry.ctype.ContentType; -import mindustry.game.*; -import mindustry.io.MapIO.*; -import mindustry.maps.*; -import mindustry.world.*; -import mindustry.world.LegacyColorMapper.*; -import mindustry.world.blocks.*; - -import java.io.*; -import java.util.zip.*; - -import static mindustry.Vars.*; - -/** Map IO for the "old" .mmap format. - * Differentiate between legacy maps and new maps by checking the extension (or the header).*/ -public class LegacyMapIO{ - private static final ObjectMap fallback = ObjectMap.of("alpha-dart-mech-pad", "dart-mech-pad"); - private static final Json json = new Json(); - - /* Convert a map from the old format to the new format. */ - public static void convertMap(Fi in, Fi out) throws IOException{ - Map map = readMap(in, true); - - String waves = map.tags.get("waves", "[]"); - Array groups = new Array<>(json.fromJson(SpawnGroup[].class, waves)); - - Tile[][] tiles = world.createTiles(map.width, map.height); - for(int x = 0; x < map.width; x++){ - for(int y = 0; y < map.height; y++){ - tiles[x][y] = new CachedTile(); - tiles[x][y].x = (short)x; - tiles[x][y].y = (short)y; - } - } - state.rules.spawns = groups; - readTiles(map, tiles); - MapIO.writeMap(out, map); - } - - public static Map readMap(Fi file, boolean custom) throws IOException{ - try(DataInputStream stream = new DataInputStream(file.read(1024))){ - StringMap tags = new StringMap(); - - //meta is uncompressed - int version = stream.readInt(); - if(version != 1){ - throw new IOException("Outdated legacy map format"); - } - int build = stream.readInt(); - short width = stream.readShort(), height = stream.readShort(); - byte tagAmount = stream.readByte(); - - for(int i = 0; i < tagAmount; i++){ - String name = stream.readUTF(); - String value = stream.readUTF(); - tags.put(name, value); - } - - return new Map(file, width, height, tags, custom, version, build); - } - } - - public static void readTiles(Map map, Tile[][] tiles) throws IOException{ - readTiles(map, (x, y) -> tiles[x][y]); - } - - public static void readTiles(Map map, TileProvider tiles) throws IOException{ - readTiles(map.file, map.width, map.height, tiles); - } - - private static void readTiles(Fi file, int width, int height, Tile[][] tiles) throws IOException{ - readTiles(file, width, height, (x, y) -> tiles[x][y]); - } - - private static void readTiles(Fi file, int width, int height, TileProvider tiles) throws IOException{ - try(BufferedInputStream input = file.read(bufferSize)){ - - //read map - { - DataInputStream stream = new DataInputStream(input); - - stream.readInt(); //version - stream.readInt(); //build - stream.readInt(); //width + height - byte tagAmount = stream.readByte(); - - for(int i = 0; i < tagAmount; i++){ - stream.readUTF(); //key - stream.readUTF(); //val - } - } - - try(DataInputStream stream = new DataInputStream(new InflaterInputStream(input))){ - - try{ - byte mapped = stream.readByte(); - IntMap idmap = new IntMap<>(); - IntMap namemap = new IntMap<>(); - - for(int i = 0; i < mapped; i++){ - byte type = stream.readByte(); - short total = stream.readShort(); - - for(int j = 0; j < total; j++){ - String name = stream.readUTF(); - if(type == 1){ - Block res = content.getByName(ContentType.block, fallback.get(name, name)); - idmap.put(j, res == null ? Blocks.air : res); - namemap.put(j, fallback.get(name, name)); - } - } - } - - //read floor and create tiles first - for(int i = 0; i < width * height; i++){ - int x = i % width, y = i / width; - int floorid = stream.readUnsignedByte(); - int oreid = stream.readUnsignedByte(); - int consecutives = stream.readUnsignedByte(); - - Tile tile = tiles.get(x, y); - tile.setFloor((Floor)idmap.get(floorid)); - tile.setOverlay(idmap.get(oreid)); - - for(int j = i + 1; j < i + 1 + consecutives; j++){ - int newx = j % width, newy = j / width; - Tile newTile = tiles.get(newx, newy); - newTile.setFloor((Floor)idmap.get(floorid)); - newTile.setOverlay(idmap.get(oreid)); - } - - i += consecutives; - } - - //read blocks - for(int i = 0; i < width * height; i++){ - int x = i % width, y = i / width; - int id = stream.readUnsignedByte(); - Block block = idmap.get(id); - if(block == null) block = Blocks.air; - - Tile tile = tiles.get(x, y); - //the spawn block is saved in the block tile layer in older maps, shift it to the overlay - if(block != Blocks.spawn){ - tile.setBlock(block); - }else{ - tile.setOverlay(block); - } - - if(namemap.get(id, "").equals("part")){ - stream.readByte(); //link - }else if(tile.entity != null){ - byte tr = stream.readByte(); - stream.readShort(); //read health (which is actually irrelevant) - - byte team = Pack.leftByte(tr); - byte rotation = Pack.rightByte(tr); - - tile.setTeam(Team.all[team]); - tile.entity.health = tile.block().health; - tile.rotation(rotation); - - if(tile.block() == Blocks.liquidSource || tile.block() == Blocks.unloader || tile.block() == Blocks.sorter){ - stream.readByte(); //these blocks have an extra config byte, read it - } - }else{ //no entity/part, read consecutives - int consecutives = stream.readUnsignedByte(); - - for(int j = i + 1; j < i + 1 + consecutives; j++){ - int newx = j % width, newy = j / width; - tiles.get(newx, newy).setBlock(block); - } - - i += consecutives; - } - } - - }finally{ - content.setTemporaryMapper(null); - } - } - } - } - - /** Reads a pixmap in the 3.5 pixmap format. */ - public static void readPixmap(Pixmap pixmap, Tile[][] tiles){ - for(int x = 0; x < pixmap.getWidth(); x++){ - for(int y = 0; y < pixmap.getHeight(); y++){ - int color = pixmap.getPixel(x, pixmap.getHeight() - 1 - y); - LegacyBlock block = LegacyColorMapper.get(color); - Tile tile = tiles[x][y]; - - tile.setFloor(block.floor); - tile.setBlock(block.wall); - if(block.ore != null) tile.setOverlay(block.ore); - - //place core - if(color == Color.rgba8888(Color.green)){ - //actual core parts - tile.setBlock(Blocks.coreShard); - tile.setTeam(Team.sharded); - } - } - } - } -} diff --git a/core/src/mindustry/io/MapIO.java b/core/src/mindustry/io/MapIO.java index 07e9823569..d26adee127 100644 --- a/core/src/mindustry/io/MapIO.java +++ b/core/src/mindustry/io/MapIO.java @@ -10,6 +10,7 @@ import mindustry.core.*; import mindustry.game.*; import mindustry.maps.*; import mindustry.world.*; +import mindustry.world.LegacyColorMapper.*; import mindustry.world.blocks.storage.*; import java.io.*; @@ -91,7 +92,7 @@ public class MapIO{ public void setTeam(Team team){ super.setTeam(team); if(block instanceof CoreBlock){ - map.teams.add((int) team.id); + map.teams.add((int)team.id); } } }; @@ -150,6 +151,28 @@ public class MapIO{ return Color.rgba8888(wall.solid ? wall.color : ore == Blocks.air ? floor.color : ore.color); } + /** Reads a pixmap in the 3.5 pixmap format. */ + public static void readPixmap(Pixmap pixmap, Tile[][] tiles){ + for(int x = 0; x < pixmap.getWidth(); x++){ + for(int y = 0; y < pixmap.getHeight(); y++){ + int color = pixmap.getPixel(x, pixmap.getHeight() - 1 - y); + LegacyBlock block = LegacyColorMapper.get(color); + Tile tile = tiles[x][y]; + + tile.setFloor(block.floor); + tile.setBlock(block.wall); + if(block.ore != null) tile.setOverlay(block.ore); + + //place core + if(color == Color.rgba8888(Color.green)){ + //actual core parts + tile.setBlock(Blocks.coreShard); + tile.setTeam(Team.sharded); + } + } + } + } + interface TileProvider{ Tile get(int x, int y); } diff --git a/core/src/mindustry/io/SaveVersion.java b/core/src/mindustry/io/SaveVersion.java index f3fdc0c20e..1d4ab19859 100644 --- a/core/src/mindustry/io/SaveVersion.java +++ b/core/src/mindustry/io/SaveVersion.java @@ -217,7 +217,7 @@ public abstract class SaveVersion extends SaveFileReader{ Array data = state.teams.getActive(); stream.writeInt(data.size); for(TeamData team : data){ - stream.writeInt((int) team.team.id); + stream.writeInt((int)team.team.id); stream.writeInt(team.brokenBlocks.size); for(BrokenBlock block : team.brokenBlocks){ stream.writeShort(block.x); @@ -258,7 +258,7 @@ public abstract class SaveVersion extends SaveFileReader{ public void readEntities(DataInput stream) throws IOException{ int teamc = stream.readInt(); for(int i = 0; i < teamc; i++){ - Team team = Team.all[stream.readInt()]; + Team team = Team.get(stream.readInt()); TeamData data = state.teams.get(team); int blocks = stream.readInt(); for(int j = 0; j < blocks; j++){ diff --git a/core/src/mindustry/io/TypeIO.java b/core/src/mindustry/io/TypeIO.java index de0faaa372..5095ce396a 100644 --- a/core/src/mindustry/io/TypeIO.java +++ b/core/src/mindustry/io/TypeIO.java @@ -87,7 +87,7 @@ public class TypeIO{ @WriteClass(BaseUnit.class) public static void writeBaseUnit(ByteBuffer buffer, BaseUnit unit){ - buffer.put((byte) (int) unit.getTeam().id); + buffer.put((byte) (int)unit.getTeam().id); buffer.putInt(unit.getID()); } @@ -95,7 +95,7 @@ public class TypeIO{ public static BaseUnit readBaseUnit(ByteBuffer buffer){ byte tid = buffer.get(); int id = buffer.getInt(); - return unitGroups[tid].getByID(id); + return unitGroup.getByID(id); } @WriteClass(Tile.class) @@ -194,12 +194,12 @@ public class TypeIO{ @WriteClass(Team.class) public static void writeTeam(ByteBuffer buffer, Team reason){ - buffer.put((byte) (int) reason.id); + buffer.put((byte) (int)reason.id); } @ReadClass(Team.class) public static Team readTeam(ByteBuffer buffer){ - return Team.all[buffer.get()]; + return Team.get(buffer.get()); } @WriteClass(UnitCommand.class) diff --git a/core/src/mindustry/maps/generators/MapGenerator.java b/core/src/mindustry/maps/generators/MapGenerator.java index c0083c4738..69c11bdc7b 100644 --- a/core/src/mindustry/maps/generators/MapGenerator.java +++ b/core/src/mindustry/maps/generators/MapGenerator.java @@ -74,7 +74,7 @@ public class MapGenerator extends Generator{ for(int x = 0; x < width; x++){ for(int y = 0; y < height; y++){ - if(tiles[x][y].block() instanceof CoreBlock && tiles[x][y].getTeam() == defaultTeam){ + if(tiles[x][y].block() instanceof CoreBlock && tiles[x][y].getTeam() == state.rules.defaultTeam){ players.add(new Point2(x, y)); tiles[x][y].setBlock(Blocks.air); } diff --git a/core/src/mindustry/ui/ItemsDisplay.java b/core/src/mindustry/ui/ItemsDisplay.java index 432417b305..755590f34f 100644 --- a/core/src/mindustry/ui/ItemsDisplay.java +++ b/core/src/mindustry/ui/ItemsDisplay.java @@ -39,9 +39,9 @@ public class ItemsDisplay extends Table{ private String format(Item item){ builder.setLength(0); builder.append(ui.formatAmount(data.items().get(item, 0))); - if(!state.is(State.menu) && !state.teams.get(player.getTeam()).cores.isEmpty() && state.teams.get(player.getTeam()).cores.first().entity != null && state.teams.get(player.getTeam()).cores.first().entity.items.get(item) > 0){ + if(!state.is(State.menu) && state.teams.get(player.getTeam()).hasCore() && state.teams.get(player.getTeam()).core().items.get(item) > 0){ builder.append(" [unlaunched]+ "); - builder.append(ui.formatAmount(state.teams.get(player.getTeam()).cores.first().entity.items.get(item))); + builder.append(ui.formatAmount(state.teams.get(player.getTeam()).core().items.get(item))); } return builder.toString(); } diff --git a/core/src/mindustry/ui/fragments/HudFragment.java b/core/src/mindustry/ui/fragments/HudFragment.java index c2ca5b25e5..688923924c 100644 --- a/core/src/mindustry/ui/fragments/HudFragment.java +++ b/core/src/mindustry/ui/fragments/HudFragment.java @@ -168,7 +168,7 @@ public class HudFragment extends Fragment{ t.table(teams -> { teams.left(); int i = 0; - for(Team team : Team.all){ + for(Team team : Team.base()){ ImageButton button = teams.addImageButton(Tex.whiteui, Styles.clearTogglePartiali, 40f, () -> Call.setPlayerTeamEditor(player, team)) .size(50f).margin(6f).get(); button.getImageCell().grow(); @@ -287,7 +287,7 @@ public class HudFragment extends Fragment{ }); t.top().visible(() -> { - if(state.is(State.menu) || state.teams.get(player.getTeam()).cores.size == 0 || state.teams.get(player.getTeam()).cores.first().entity == null){ + if(state.is(State.menu) || !state.teams.get(player.getTeam()).hasCore()){ coreAttackTime[0] = 0f; return false; } @@ -628,7 +628,7 @@ public class HudFragment extends Fragment{ } if(state.rules.waveTimer){ - builder.append((state.rules.waitForWaveToEnd && unitGroups[(int) waveTeam.id].size() > 0) ? Core.bundle.get("wave.waveInProgress") : ( waitingf.get((int)(state.wavetime/60)))); + builder.append((state.rules.waitForWaveToEnd && state.enemies > 0 ? Core.bundle.get("wave.waveInProgress") : ( waitingf.get((int)(state.wavetime/60))))); }else if(state.enemies == 0){ builder.append(Core.bundle.get("waiting")); } diff --git a/core/src/mindustry/ui/fragments/PlayerListFragment.java b/core/src/mindustry/ui/fragments/PlayerListFragment.java index df0d9f7269..a9cca9fb85 100644 --- a/core/src/mindustry/ui/fragments/PlayerListFragment.java +++ b/core/src/mindustry/ui/fragments/PlayerListFragment.java @@ -8,6 +8,7 @@ import arc.scene.ui.*; import arc.scene.ui.layout.*; import arc.util.*; import mindustry.core.GameState.*; +import mindustry.entities.type.*; import mindustry.gen.*; import mindustry.graphics.*; import mindustry.net.*; @@ -65,7 +66,7 @@ public class PlayerListFragment extends Fragment{ float h = 74f; - playerGroup.all().sort((p1, p2) -> p1.getTeam().compareTo(p2.getTeam())); + playerGroup.all().sort(Structs.comparing(Unit::getTeam)); playerGroup.all().each(user -> { NetConnection connection = user.con; diff --git a/core/src/mindustry/world/Build.java b/core/src/mindustry/world/Build.java index dafd9fe38d..f101068cf0 100644 --- a/core/src/mindustry/world/Build.java +++ b/core/src/mindustry/world/Build.java @@ -38,7 +38,7 @@ public class Build{ Block previous = tile.block(); Block sub = BuildBlock.get(previous.size); - world.setBlock(tile, sub, team, rotation); + tile.set(sub, team, rotation); tile.ent().setDeconstruct(previous); tile.entity.health = tile.entity.maxHealth() * prevPercent; @@ -60,7 +60,7 @@ public class Build{ Block previous = tile.block(); Block sub = BuildBlock.get(result.size); - world.setBlock(tile, sub, team, rotation); + tile.set(sub, team, rotation); tile.ent().setConstruct(previous, result); Core.app.post(() -> Events.fire(new BlockBuildBeginEvent(tile, team, false))); @@ -72,7 +72,7 @@ public class Build{ return false; } - if(state.rules.bannedBlocks.contains(type) && !(state.rules.waves && team == waveTeam)){ + if(state.rules.bannedBlocks.contains(type) && !(state.rules.waves && team == state.rules.waveTeam)){ return false; } @@ -80,13 +80,8 @@ public class Build{ return false; } - //check for enemy cores - for(Team enemy : state.teams.enemiesOf(team)){ - for(Tile core : state.teams.get(enemy).cores){ - if(Mathf.dst(x * tilesize + type.offset(), y * tilesize + type.offset(), core.drawx(), core.drawy()) < state.rules.enemyCoreBuildRadius + type.size * tilesize / 2f){ - return false; - } - } + if(!state.teams.eachEnemyCore(team, core -> Mathf.dst(x * tilesize + type.offset(), y * tilesize + type.offset(), core.x, core.y) < state.rules.enemyCoreBuildRadius + type.size * tilesize / 2f)){ + return false; } Tile tile = world.tile(x, y); diff --git a/core/src/mindustry/world/CachedTile.java b/core/src/mindustry/world/CachedTile.java index e46a57d3ba..281828dcd7 100644 --- a/core/src/mindustry/world/CachedTile.java +++ b/core/src/mindustry/world/CachedTile.java @@ -16,7 +16,7 @@ public class CachedTile extends Tile{ @Override public Team getTeam(){ - return Team.all[getTeamID()]; + return Team.get(getTeamID()); } @Override diff --git a/core/src/mindustry/world/Tile.java b/core/src/mindustry/world/Tile.java index a1fb5fa9ff..4a8b2fa629 100644 --- a/core/src/mindustry/world/Tile.java +++ b/core/src/mindustry/world/Tile.java @@ -142,11 +142,11 @@ public class Tile implements Position, TargetTrait{ @Override public Team getTeam(){ - return Team.all[link().team]; + return Team.get(link().team); } public void setTeam(Team team){ - this.team = (byte) (int) team.id; + this.team = (byte) (int)team.id; } public byte getTeamID(){ @@ -156,7 +156,7 @@ public class Tile implements Position, TargetTrait{ public void setBlock(@NonNull Block type, Team team, int rotation){ preChanged(); this.block = type; - this.team = (byte) (int) team.id; + this.team = (byte) (int)team.id; this.rotation = (byte)Mathf.mod(rotation, 4); changed(); } @@ -186,6 +186,35 @@ public class Tile implements Position, TargetTrait{ setOverlay(overlay); } + public void remove(){ + link().getLinkedTiles(other -> other.setBlock(Blocks.air)); + } + + public void set(Block block, Team team){ + set(block, team, 0); + } + + public void set(Block block, Team team, int rotation){ + setBlock(block, team, rotation); + if(block.isMultiblock()){ + int offsetx = -(block.size - 1) / 2; + int offsety = -(block.size - 1) / 2; + + for(int dx = 0; dx < block.size; dx++){ + for(int dy = 0; dy < block.size; dy++){ + int worldx = dx + offsetx + x; + int worldy = dy + offsety + y; + if(!(worldx == x && worldy == y)){ + Tile toplace = world.tile(worldx, worldy); + if(toplace != null){ + toplace.setBlock(BlockPart.get(dx + offsetx, dy + offsety), team); + } + } + } + } + } + } + public byte rotation(){ return rotation; } @@ -240,7 +269,7 @@ public class Tile implements Position, TargetTrait{ } public boolean isEnemyCheat(){ - return getTeam() == waveTeam && state.rules.enemyCheat; + return getTeam() == state.rules.waveTeam && state.rules.enemyCheat; } public boolean isLinked(){ @@ -344,7 +373,7 @@ public class Tile implements Position, TargetTrait{ } public boolean interactable(Team team){ - return getTeam() == Team.derelict || team == getTeam(); + return state.teams.canInteract(team, getTeam()); } public Item drop(){ diff --git a/core/src/mindustry/world/blocks/BuildBlock.java b/core/src/mindustry/world/blocks/BuildBlock.java index 69d9ba61e8..df90a969b7 100644 --- a/core/src/mindustry/world/blocks/BuildBlock.java +++ b/core/src/mindustry/world/blocks/BuildBlock.java @@ -66,7 +66,7 @@ public class BuildBlock extends Block{ public static void onConstructFinish(Tile tile, Block block, int builderID, byte rotation, Team team, boolean skipConfig){ if(tile == null) return; float healthf = tile.entity == null ? 1f : tile.entity.healthf(); - world.setBlock(tile, block, team, rotation); + tile.set(block, team, rotation); if(tile.entity != null){ tile.entity.health = block.health * healthf; } diff --git a/core/src/mindustry/world/blocks/storage/CoreBlock.java b/core/src/mindustry/world/blocks/storage/CoreBlock.java index 7c766fd1d3..f9a5cf6c9b 100644 --- a/core/src/mindustry/world/blocks/storage/CoreBlock.java +++ b/core/src/mindustry/world/blocks/storage/CoreBlock.java @@ -84,12 +84,12 @@ public class CoreBlock extends StorageBlock{ public void onProximityUpdate(Tile tile){ CoreEntity entity = tile.ent(); - for(Tile other : state.teams.get(tile.getTeam()).cores){ - if(other != tile){ - entity.items = other.entity.items; + for(TileEntity other : state.teams.cores(tile.getTeam())){ + if(other.tile != tile){ + entity.items = other.items; } } - state.teams.get(tile.getTeam()).cores.add(tile); + state.teams.registerCore(entity); entity.storageCapacity = itemCapacity + entity.proximity().sum(e -> isContainer(e) ? e.block().itemCapacity : 0); entity.proximity().each(this::isContainer, t -> { @@ -97,9 +97,9 @@ public class CoreBlock extends StorageBlock{ t.ent().linkedCore = tile; }); - for(Tile other : state.teams.get(tile.getTeam()).cores){ - if(other == tile) continue; - entity.storageCapacity += other.block().itemCapacity + other.entity.proximity().sum(e -> isContainer(e) ? e.block().itemCapacity : 0); + for(TileEntity other : state.teams.cores(tile.getTeam())){ + if(other.tile == tile) continue; + entity.storageCapacity += other.block.itemCapacity + entity.proximity().sum(e -> isContainer(e) ? e.block().itemCapacity : 0); } if(!world.isGenerating()){ @@ -108,9 +108,8 @@ public class CoreBlock extends StorageBlock{ } } - for(Tile other : state.teams.get(tile.getTeam()).cores){ - CoreEntity oe = other.ent(); - oe.storageCapacity = entity.storageCapacity; + for(CoreEntity other : state.teams.cores(tile.getTeam())){ + other.storageCapacity = entity.storageCapacity; } } @@ -151,8 +150,9 @@ public class CoreBlock extends StorageBlock{ @Override public void removed(Tile tile){ + CoreEntity entity = tile.ent(); int total = tile.entity.proximity().count(e -> e.entity.items == tile.entity.items); - float fract = 1f / total / state.teams.get(tile.getTeam()).cores.size; + float fract = 1f / total / state.teams.cores(tile.getTeam()).size; tile.entity.proximity().each(e -> isContainer(e) && e.entity.items == tile.entity.items, t -> { StorageBlockEntity ent = (StorageBlockEntity)t.entity; @@ -163,22 +163,23 @@ public class CoreBlock extends StorageBlock{ } }); - state.teams.get(tile.getTeam()).cores.remove(tile); + state.teams.unregisterCore(entity); - int max = itemCapacity * state.teams.get(tile.getTeam()).cores.size; + int max = itemCapacity * state.teams.cores(tile.getTeam()).size; for(Item item : content.items()){ tile.entity.items.set(item, Math.min(tile.entity.items.get(item), max)); } - for(Tile other : state.teams.get(tile.getTeam()).cores){ - other.block().onProximityUpdate(other); + for(CoreEntity other : state.teams.cores(tile.getTeam())){ + other.block.onProximityUpdate(other.tile); } } @Override public void placed(Tile tile){ super.placed(tile); - state.teams.get(tile.getTeam()).cores.add(tile); + CoreEntity entity = tile.ent(); + state.teams.registerCore(entity); } @Override diff --git a/core/src/mindustry/world/blocks/units/CommandCenter.java b/core/src/mindustry/world/blocks/units/CommandCenter.java index 9dae2923d3..0d2e0428de 100644 --- a/core/src/mindustry/world/blocks/units/CommandCenter.java +++ b/core/src/mindustry/world/blocks/units/CommandCenter.java @@ -58,7 +58,7 @@ public class CommandCenter extends Block{ ObjectSet set = indexer.getAllied(tile.getTeam(), BlockFlag.comandCenter); if(set.size == 1){ - for(BaseUnit unit : unitGroups[(int) tile.getTeam().id].all()){ + for(BaseUnit unit : unitGroups[(int)tile.getTeam().id].all()){ unit.onCommand(UnitCommand.all[0]); } } @@ -116,7 +116,7 @@ public class CommandCenter extends Block{ Team team = (player == null ? tile.getTeam() : player.getTeam()); - for(BaseUnit unit : unitGroups[(int) team.id].all()){ + for(BaseUnit unit : unitGroups[(int)team.id].all()){ unit.onCommand(command); } diff --git a/desktop/src/mindustry/desktop/steam/SStats.java b/desktop/src/mindustry/desktop/steam/SStats.java index 984fa9e985..bdbb86ad5e 100644 --- a/desktop/src/mindustry/desktop/steam/SStats.java +++ b/desktop/src/mindustry/desktop/steam/SStats.java @@ -55,13 +55,13 @@ public class SStats implements SteamUserStatsCallback{ private void checkUpdate(){ if(campaign()){ - SStat.maxUnitActive.max(unitGroups[(int) player.getTeam().id].size()); + SStat.maxUnitActive.max(unitGroups[(int)player.getTeam().id].size()); - if(unitGroups[(int) player.getTeam().id].count(u -> u.getType() == UnitTypes.phantom) >= 10){ + if(unitGroups[(int)player.getTeam().id].count(u -> u.getType() == UnitTypes.phantom) >= 10){ active10Phantoms.complete(); } - if(unitGroups[(int) player.getTeam().id].count(u -> u.getType() == UnitTypes.crawler) >= 50){ + if(unitGroups[(int)player.getTeam().id].count(u -> u.getType() == UnitTypes.crawler) >= 50){ active50Crawlers.complete(); } diff --git a/gradle.properties b/gradle.properties index 29c1e50fad..e28d4db59a 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,3 +1,3 @@ org.gradle.daemon=true org.gradle.jvmargs=-Xms256m -Xmx1024m -archash=88c1a9afe2f5be4dd06e47ac8afe070247b3da29 +archash=447f3bb0e4616f82680f3234ad4e0cce48880884 diff --git a/server/src/mindustry/server/ServerControl.java b/server/src/mindustry/server/ServerControl.java index 8ff1874407..109552adb4 100644 --- a/server/src/mindustry/server/ServerControl.java +++ b/server/src/mindustry/server/ServerControl.java @@ -292,7 +292,7 @@ public class ServerControl implements ApplicationListener{ info(" &lyPlaying on map &fi{0}&fb &lb/&ly Wave {1}", Strings.capitalize(world.getMap().name()), state.wave); if(state.rules.waves){ - info("&ly {0} enemies.", unitGroups[(int) Team.crux.id].size()); + info("&ly {0} enemies.", unitGroups[(int)Team.crux.id].size()); }else{ info("&ly {0} seconds until next wave.", (int)(state.wavetime / 60)); } @@ -421,14 +421,14 @@ public class ServerControl implements ApplicationListener{ try{ Team team = arg.length == 0 ? Team.sharded : Team.valueOf(arg[0]); - if(state.teams.get(team).cores.isEmpty()){ + if(state.teams.cores(team).isEmpty()){ err("That team has no cores."); return; } for(Item item : content.items()){ if(item.type == ItemType.material){ - state.teams.get(team).cores.first().entity.items.set(item, state.teams.get(team).cores.first().block().itemCapacity); + state.teams.cores(team).first().entity.items.set(item, state.teams.cores(team).first().block().itemCapacity); } } diff --git a/tests/src/test/java/ApplicationTests.java b/tests/src/test/java/ApplicationTests.java index 43c819bdfd..722bf246d0 100644 --- a/tests/src/test/java/ApplicationTests.java +++ b/tests/src/test/java/ApplicationTests.java @@ -106,8 +106,8 @@ public class ApplicationTests{ Time.update(); Time.update(); Time.setDeltaProvider(() -> 1f); - unitGroups[(int) waveTeam.id].updateEvents(); - assertFalse(unitGroups[(int) waveTeam.id].isEmpty(), "No enemies spawned."); + unitGroup.update(); + assertFalse(unitGroup.isEmpty(), "No enemies spawned."); } @Test @@ -128,7 +128,7 @@ public class ApplicationTests{ createMap(); int bx = 4; int by = 4; - world.setBlock(world.tile(bx, by), Blocks.coreShard, Team.sharded); + world.tile(bx, by).set(Blocks.coreShard, Team.sharded); assertEquals(world.tile(bx, by).getTeam(), Team.sharded); for(int x = bx - 1; x <= bx + 1; x++){ for(int y = by - 1; y <= by + 1; y++){ @@ -198,7 +198,7 @@ public class ApplicationTests{ @Test void save(){ world.loadMap(testMap); - assertTrue(state.teams.get(defaultTeam).cores.size > 0); + assertTrue(state.teams.playerCores().size > 0); SaveIO.save(saveDirectory.child("0.msav")); } @@ -213,7 +213,7 @@ public class ApplicationTests{ assertEquals(world.width(), map.width); assertEquals(world.height(), map.height); - assertTrue(state.teams.get(defaultTeam).cores.size > 0); + assertTrue(state.teams.playerCores().size > 0); } @Test @@ -379,12 +379,12 @@ public class ApplicationTests{ createMap(); Tile core = world.tile(5, 5); - world.setBlock(core, Blocks.coreShard, Team.sharded); + core.set(Blocks.coreShard, Team.sharded); for(Item item : content.items()){ core.entity.items.set(item, 3000); } - assertEquals(core, state.teams.get(Team.sharded).cores.first()); + assertEquals(core.entity, state.teams.get(Team.sharded).core()); } void depositTest(Block block, Item item){ diff --git a/tests/src/test/java/ZoneTests.java b/tests/src/test/java/ZoneTests.java index 2a044d5b75..a238a815ee 100644 --- a/tests/src/test/java/ZoneTests.java +++ b/tests/src/test/java/ZoneTests.java @@ -52,7 +52,7 @@ public class ZoneTests{ if(tile.drop() != null){ resources.add(tile.drop()); } - if(tile.block() instanceof CoreBlock && tile.getTeam() == defaultTeam){ + if(tile.block() instanceof CoreBlock && tile.getTeam() == state.rules.defaultTeam){ hasSpawnPoint = true; } } @@ -69,7 +69,7 @@ public class ZoneTests{ } assertTrue(hasSpawnPoint, "Zone \"" + zone.name + "\" has no spawn points."); - assertTrue(spawner.countSpawns() > 0 || (state.rules.attackMode && !state.teams.get(waveTeam).cores.isEmpty()), "Zone \"" + zone.name + "\" has no enemy spawn points: " + spawner.countSpawns()); + assertTrue(spawner.countSpawns() > 0 || (state.rules.attackMode && state.teams.get(state.rules.waveTeam).hasCore()), "Zone \"" + zone.name + "\" has no enemy spawn points: " + spawner.countSpawns()); for(Item item : resources){ assertTrue(zone.resources.contains(item), "Zone \"" + zone.name + "\" is missing item in resource list: \"" + item.name + "\""); diff --git a/tools/build.gradle b/tools/build.gradle index ea158a66a1..033040e96d 100644 --- a/tools/build.gradle +++ b/tools/build.gradle @@ -240,7 +240,7 @@ task swapColors(){ Color.argb8888ToColor(tmpc, c) if(tmpc.a < 0.1f) continue if(map.containsKey(c)){ - img.setRGB(x, y, (int) map.get(c)) + img.setRGB(x, y, (int)map.get(c)) } } } From 4858e602ed5429e95e5416b757d226134728f92b Mon Sep 17 00:00:00 2001 From: Anuken Date: Thu, 26 Dec 2019 19:40:54 -0500 Subject: [PATCH 08/78] Fixed compilation --- core/src/mindustry/ai/BlockIndexer.java | 61 ++++++++++++------- core/src/mindustry/ai/Pathfinder.java | 22 +++---- core/src/mindustry/ai/WaveSpawner.java | 14 ++--- core/src/mindustry/editor/EditorTile.java | 2 +- .../mindustry/editor/MapGenerateDialog.java | 2 +- core/src/mindustry/entities/Damage.java | 2 +- core/src/mindustry/entities/Units.java | 46 +++++++------- core/src/mindustry/entities/type/Unit.java | 2 +- .../entities/type/base/BuilderDrone.java | 6 +- core/src/mindustry/game/Team.java | 6 +- core/src/mindustry/game/Teams.java | 26 ++++++-- core/src/mindustry/io/MapIO.java | 4 +- core/src/mindustry/world/Tile.java | 4 +- .../mindustry/world/blocks/BuildBlock.java | 2 +- .../world/blocks/units/CommandCenter.java | 16 ++--- desktop/build.gradle | 2 +- .../src/mindustry/desktop/steam/SStats.java | 13 ++-- gradle.properties | 2 +- 18 files changed, 129 insertions(+), 103 deletions(-) diff --git a/core/src/mindustry/ai/BlockIndexer.java b/core/src/mindustry/ai/BlockIndexer.java index bb90b37301..08e7fcf522 100644 --- a/core/src/mindustry/ai/BlockIndexer.java +++ b/core/src/mindustry/ai/BlockIndexer.java @@ -1,10 +1,10 @@ package mindustry.ai; import arc.*; -import arc.struct.*; import arc.func.*; import arc.math.*; import arc.math.geom.*; +import arc.struct.*; import mindustry.content.*; import mindustry.entities.type.*; import mindustry.game.EventType.*; @@ -28,15 +28,15 @@ public class BlockIndexer{ private final ObjectSet itemSet = new ObjectSet<>(); /** Stores all ore quadtrants on the map. */ private ObjectMap> ores = new ObjectMap<>(); - /** Tags all quadrants. */ + /** Maps each team ID to a quarant. A quadrant is a grid of bits, where each bit is set if and only if there is a block of that team in that quadrant. */ private GridBits[] structQuadrants; /** Stores all damaged tile entities by team. */ - private ObjectSet[] damagedTiles = new ObjectSet[Team.all.length]; + private ObjectSet[] damagedTiles = new ObjectSet[Team.all().length]; /**All ores available on this map.*/ private ObjectSet allOres = new ObjectSet<>(); /** Maps teams to a map of flagged tiles by type. */ - private ObjectSet[][] flagMap = new ObjectSet[Team.all.length][BlockFlag.all.length]; + private ObjectSet[][] flagMap = new ObjectSet[Team.all().length][BlockFlag.all.length]; /** Maps tile positions to their last known tile index data. */ private IntMap typeMap = new IntMap<>(); /** Empty set used for returning. */ @@ -59,8 +59,8 @@ public class BlockIndexer{ Events.on(WorldLoadEvent.class, event -> { scanOres.clear(); scanOres.addAll(Item.getAllOres()); - damagedTiles = new ObjectSet[Team.all.length]; - flagMap = new ObjectSet[Team.all.length][BlockFlag.all.length]; + damagedTiles = new ObjectSet[Team.all().length]; + flagMap = new ObjectSet[Team.all().length][BlockFlag.all.length]; for(int i = 0; i < flagMap.length; i++){ for(int j = 0; j < BlockFlag.all.length; j++){ @@ -73,10 +73,7 @@ public class BlockIndexer{ ores = null; //create bitset for each team type that contains each quadrant - structQuadrants = new GridBits[Team.all.length]; - for(int i = 0; i < Team.all.length; i++){ - structQuadrants[i] = new GridBits(Mathf.ceil(world.width() / (float)quadrantSize), Mathf.ceil(world.height() / (float)quadrantSize)); - } + structQuadrants = new GridBits[Team.all().length]; for(int x = 0; x < world.width(); x++){ for(int y = 0; y < world.height(); y++){ @@ -103,7 +100,29 @@ public class BlockIndexer{ } private ObjectSet[] getFlagged(Team team){ - return flagMap[(int)team.id]; + return flagMap[team.id]; + } + + private GridBits structQuadrant(Team t){ + if(structQuadrants[t.id] == null){ + structQuadrants[t.id] = new GridBits(Mathf.ceil(world.width() / (float)quadrantSize), Mathf.ceil(world.height() / (float)quadrantSize)); + } + return structQuadrants[t.id]; + } + + /** Updates all the structure quadrants for a newly activated team. */ + public void updateTeamIndex(Team team){ + //go through every tile... ouch + for(int x = 0; x < world.width(); x++){ + for(int y = 0; y < world.height(); y++){ + Tile tile = world.tile(x, y); + if(tile.getTeam() == team){ + int quadrantX = tile.x / quadrantSize; + int quadrantY = tile.y / quadrantSize; + structQuadrant(team).set(quadrantX, quadrantY); + } + } + } } /** @return whether this item is present on this map.*/ @@ -115,11 +134,11 @@ public class BlockIndexer{ public ObjectSet getDamaged(Team team){ returnArray.clear(); - if(damagedTiles[(int)team.id] == null){ - damagedTiles[(int)team.id] = new ObjectSet<>(); + if(damagedTiles[team.id] == null){ + damagedTiles[team.id] = new ObjectSet<>(); } - ObjectSet set = damagedTiles[(int)team.id]; + ObjectSet set = damagedTiles[team.id]; for(Tile tile : set){ if((tile.entity == null || tile.entity.getTeam() != team || !tile.entity.damaged()) || tile.block() instanceof BuildBlock){ returnArray.add(tile); @@ -135,7 +154,7 @@ public class BlockIndexer{ /** Get all allied blocks with a flag. */ public ObjectSet getAllied(Team team, BlockFlag type){ - return flagMap[(int)team.id][type.ordinal()]; + return flagMap[team.id][type.ordinal()]; } /** Get all enemy blocks with a flag. */ @@ -282,16 +301,16 @@ public class BlockIndexer{ int quadrantY = tile.y / quadrantSize; int index = quadrantX + quadrantY * quadWidth(); - for(Team team : Team.all){ - TeamData data = state.teams.get(team); + for(TeamData data : state.teams.getActive()){ + GridBits bits = structQuadrant(data.team); //fast-set this quadrant to 'occupied' if the tile just placed is already of this team if(tile.getTeam() == data.team && tile.entity != null && tile.block().targetable){ - structQuadrants[(int)data.team.id].set(quadrantX, quadrantY); + bits.set(quadrantX, quadrantY); continue; //no need to process futher } - structQuadrants[(int)data.team.id].set(quadrantX, quadrantY, false); + bits.set(quadrantX, quadrantY, false); outer: for(int x = quadrantX * quadrantSize; x < world.width() && x < (quadrantX + 1) * quadrantSize; x++){ @@ -299,7 +318,7 @@ public class BlockIndexer{ Tile result = world.ltile(x, y); //when a targetable block is found, mark this quadrant as occupied and stop searching if(result.entity != null && result.getTeam() == data.team){ - structQuadrants[(int)data.team.id].set(quadrantX, quadrantY); + bits.set(quadrantX, quadrantY); break outer; } } @@ -308,7 +327,7 @@ public class BlockIndexer{ } private boolean getQuad(Team team, int quadrantX, int quadrantY){ - return structQuadrants[(int)team.id].get(quadrantX, quadrantY); + return structQuadrant(team).get(quadrantX, quadrantY); } private int quadWidth(){ diff --git a/core/src/mindustry/ai/Pathfinder.java b/core/src/mindustry/ai/Pathfinder.java index 319c85ef2e..6a2515bb7a 100644 --- a/core/src/mindustry/ai/Pathfinder.java +++ b/core/src/mindustry/ai/Pathfinder.java @@ -27,9 +27,9 @@ public class Pathfinder implements Runnable{ /** unordered array of path data for iteration only. DO NOT iterate ot access this in the main thread.*/ private Array list = new Array<>(); /** Maps teams + flags to a valid path to get to that flag for that team. */ - private PathData[][] pathMap = new PathData[Team.all.length][PathTarget.all.length]; + private PathData[][] pathMap = new PathData[Team.all().length][PathTarget.all.length]; /** Grid map of created path data that should not be queued again. */ - private GridBits created = new GridBits(Team.all.length, PathTarget.all.length); + private GridBits created = new GridBits(Team.all().length, PathTarget.all.length); /** handles task scheduling on the update thread. */ private TaskQueue queue = new TaskQueue(); /** current pathfinding thread */ @@ -42,8 +42,8 @@ public class Pathfinder implements Runnable{ //reset and update internal tile array tiles = new int[world.width()][world.height()]; - pathMap = new PathData[Team.all.length][PathTarget.all.length]; - created = new GridBits(Team.all.length, PathTarget.all.length); + pathMap = new PathData[Team.all().length][PathTarget.all.length]; + created = new GridBits(Team.all().length, PathTarget.all.length); list = new Array<>(); for(int x = 0; x < world.width(); x++){ @@ -84,8 +84,8 @@ public class Pathfinder implements Runnable{ } public int debugValue(Team team, int x, int y){ - if(pathMap[(int)team.id][PathTarget.enemyCores.ordinal()] == null) return 0; - return pathMap[(int)team.id][PathTarget.enemyCores.ordinal()].weights[x][y]; + if(pathMap[team.id][PathTarget.enemyCores.ordinal()] == null) return 0; + return pathMap[team.id][PathTarget.enemyCores.ordinal()].weights[x][y]; } /** Update a tile in the internal pathfinding grid. Causes a complete pathfinding reclaculation. */ @@ -149,12 +149,12 @@ public class Pathfinder implements Runnable{ public Tile getTargetTile(Tile tile, Team team, PathTarget target){ if(tile == null) return null; - PathData data = pathMap[(int)team.id][target.ordinal()]; + PathData data = pathMap[team.id][target.ordinal()]; if(data == null){ //if this combination is not found, create it on request - if(!created.get((int)team.id, target.ordinal())){ - created.set((int)team.id, target.ordinal()); + if(!created.get(team.id, target.ordinal())){ + created.set(team.id, target.ordinal()); //grab targets since this is run on main thread IntArray targets = target.getTargets(team, new IntArray()); queue.post(() -> createPath(team, target, targets)); @@ -188,7 +188,7 @@ public class Pathfinder implements Runnable{ /** @return whether a tile can be passed through by this team. Pathfinding thread only.*/ private boolean passable(int x, int y, Team team){ int tile = tiles[x][y]; - return PathTile.passable(tile) || (PathTile.team(tile) != (int)team.id && PathTile.team(tile) != (int)Team.derelict.id); + return PathTile.passable(tile) || (PathTile.team(tile) != team.id && PathTile.team(tile) != (int)Team.derelict.id); } /** @@ -238,7 +238,7 @@ public class Pathfinder implements Runnable{ PathData path = new PathData(team, target, world.width(), world.height()); list.add(path); - pathMap[(int)team.id][target.ordinal()] = path; + pathMap[team.id][target.ordinal()] = path; //grab targets from passed array synchronized(path.targets){ diff --git a/core/src/mindustry/ai/WaveSpawner.java b/core/src/mindustry/ai/WaveSpawner.java index 25b9983db0..129b930d3b 100644 --- a/core/src/mindustry/ai/WaveSpawner.java +++ b/core/src/mindustry/ai/WaveSpawner.java @@ -11,7 +11,7 @@ import mindustry.content.Blocks; import mindustry.content.Fx; import mindustry.entities.Damage; import mindustry.entities.Effects; -import mindustry.entities.type.BaseUnit; +import mindustry.entities.type.*; import mindustry.game.EventType.WorldLoadEvent; import mindustry.game.SpawnGroup; import mindustry.world.Tile; @@ -91,10 +91,10 @@ public class WaveSpawner{ } if(state.rules.attackMode && state.teams.isActive(state.rules.waveTeam) && !state.teams.playerCores().isEmpty()){ - Tile firstCore = state.teams.playerCores().first(); - for(Tile core : state.teams.get(state.rules.waveTeam).cores){ - Tmp.v1.set(firstCore).sub(core.worldx(), core.worldy()).limit(coreMargin + core.block().size*tilesize); - cons.accept(core.worldx() + Tmp.v1.x, core.worldy() + Tmp.v1.y, false); + TileEntity firstCore = state.teams.playerCores().first(); + for(TileEntity core : state.teams.get(state.rules.waveTeam).cores){ + Tmp.v1.set(firstCore).sub(core.x, core.y).limit(coreMargin + core.block.size*tilesize); + cons.accept(core.x + Tmp.v1.x, core.y + Tmp.v1.y, false); } } } @@ -108,8 +108,8 @@ public class WaveSpawner{ } if(state.rules.attackMode && state.teams.isActive(state.rules.waveTeam)){ - for(Tile core : state.teams.get(state.rules.waveTeam).cores){ - cons.get(core.worldx(), core.worldy()); + for(TileEntity core : state.teams.get(state.rules.waveTeam).cores){ + cons.get(core.x, core.y); } } } diff --git a/core/src/mindustry/editor/EditorTile.java b/core/src/mindustry/editor/EditorTile.java index 4a9effccfd..6a2829b098 100644 --- a/core/src/mindustry/editor/EditorTile.java +++ b/core/src/mindustry/editor/EditorTile.java @@ -74,7 +74,7 @@ public class EditorTile extends Tile{ return; } - if(getTeamID() == (int)team.id) return; + if(getTeamID() == team.id) return; op(OpType.team, getTeamID()); super.setTeam(team); } diff --git a/core/src/mindustry/editor/MapGenerateDialog.java b/core/src/mindustry/editor/MapGenerateDialog.java index 8704b8a209..12f989c272 100644 --- a/core/src/mindustry/editor/MapGenerateDialog.java +++ b/core/src/mindustry/editor/MapGenerateDialog.java @@ -415,7 +415,7 @@ public class MapGenerateDialog extends FloatingDialog{ this.floor = floor.id; this.block = wall.id; this.ore = ore.id; - this.team = (byte) (int)team.id; + this.team = (byte) team.id; this.rotation = (byte)rotation; } diff --git a/core/src/mindustry/entities/Damage.java b/core/src/mindustry/entities/Damage.java index 3fe1b00d31..73f0b4996e 100644 --- a/core/src/mindustry/entities/Damage.java +++ b/core/src/mindustry/entities/Damage.java @@ -88,7 +88,7 @@ public class Damage{ tr.trns(angle, length); Intc2 collider = (cx, cy) -> { Tile tile = world.ltile(cx, cy); - if(tile != null && !collidedBlocks.contains(tile.pos()) && tile.entity != null && tile.getTeamID() != (int)team.id && tile.entity.collide(hitter)){ + if(tile != null && !collidedBlocks.contains(tile.pos()) && tile.entity != null && tile.getTeamID() != team.id && tile.entity.collide(hitter)){ tile.entity.collision(hitter); collidedBlocks.add(tile.pos()); hitter.getBulletType().hit(hitter, tile.worldx(), tile.worldy()); diff --git a/core/src/mindustry/entities/Units.java b/core/src/mindustry/entities/Units.java index 09e0293241..7592551ce4 100644 --- a/core/src/mindustry/entities/Units.java +++ b/core/src/mindustry/entities/Units.java @@ -1,15 +1,12 @@ package mindustry.entities; -import arc.struct.EnumSet; -import arc.func.Cons; -import arc.func.Boolf; -import arc.math.Mathf; -import arc.math.geom.Geometry; -import arc.math.geom.Rectangle; -import mindustry.entities.traits.TargetTrait; +import arc.func.*; +import arc.math.*; +import arc.math.geom.*; +import mindustry.entities.traits.*; import mindustry.entities.type.*; -import mindustry.game.Team; -import mindustry.world.Tile; +import mindustry.game.*; +import mindustry.world.*; import static mindustry.Vars.*; @@ -157,7 +154,11 @@ public class Units{ /** Iterates over all units in a rectangle. */ public static void nearby(Team team, float x, float y, float width, float height, Cons cons){ - unitGroups[(int)team.id].intersect(x, y, width, height, cons); + unitGroup.intersect(x, y, width, height, u -> { + if(u.getTeam() == team){ + cons.get(u); + } + }); playerGroup.intersect(x, y, width, height, player -> { if(player.getTeam() == team){ cons.get(player); @@ -167,8 +168,8 @@ public class Units{ /** Iterates over all units in a circle around this position. */ public static void nearby(Team team, float x, float y, float radius, Cons cons){ - unitGroups[(int)team.id].intersect(x - radius, y - radius, radius*2f, radius*2f, unit -> { - if(unit.withinDst(x, y, radius)){ + unitGroup.intersect(x - radius, y - radius, radius*2f, radius*2f, unit -> { + if(unit.getTeam() == team && unit.withinDst(x, y, radius)){ cons.get(unit); } }); @@ -182,10 +183,7 @@ public class Units{ /** Iterates over all units in a rectangle. */ public static void nearby(float x, float y, float width, float height, Cons cons){ - for(Team team : Team.all){ - unitGroups[(int)team.id].intersect(x, y, width, height, cons); - } - + unitGroup.intersect(x, y, width, height, cons); playerGroup.intersect(x, y, width, height, cons); } @@ -196,14 +194,14 @@ public class Units{ /** Iterates over all units that are enemies of this team. */ public static void nearbyEnemies(Team team, float x, float y, float width, float height, Cons cons){ - EnumSet targets = state.teams.enemiesOf(team); - - for(Team other : targets){ - unitGroups[(int)other.id].intersect(x, y, width, height, cons); - } + unitGroup.intersect(x, y, width, height, u -> { + if(state.teams.areEnemies(team, u.getTeam())){ + cons.get(u); + } + }); playerGroup.intersect(x, y, width, height, player -> { - if(targets.contains(player.getTeam())){ + if(state.teams.areEnemies(team, player.getTeam())){ cons.get(player); } }); @@ -220,4 +218,8 @@ public class Units{ playerGroup.all().each(cons); } + public static void each(Team team, Cons cons){ + unitGroup.all().each(t -> t.getTeam() == team, cons); + } + } diff --git a/core/src/mindustry/entities/type/Unit.java b/core/src/mindustry/entities/type/Unit.java index 0b0ccc277a..f9c78a747b 100644 --- a/core/src/mindustry/entities/type/Unit.java +++ b/core/src/mindustry/entities/type/Unit.java @@ -167,7 +167,7 @@ public abstract class Unit extends DestructibleEntity implements SaveTrait, Targ public void writeSave(DataOutput stream, boolean net) throws IOException{ if(item.item == null) item.item = Items.copper; - stream.writeByte((int)team.id); + stream.writeByte(team.id); stream.writeBoolean(isDead()); stream.writeFloat(net ? interpolator.target.x : x); stream.writeFloat(net ? interpolator.target.y : y); diff --git a/core/src/mindustry/entities/type/base/BuilderDrone.java b/core/src/mindustry/entities/type/base/BuilderDrone.java index 83d4606122..6442347de4 100644 --- a/core/src/mindustry/entities/type/base/BuilderDrone.java +++ b/core/src/mindustry/entities/type/base/BuilderDrone.java @@ -114,12 +114,10 @@ public class BuilderDrone extends BaseDrone implements BuilderTrait{ public BuilderDrone(){ if(reset.check()){ Events.on(BuildSelectEvent.class, event -> { - EntityGroup group = unitGroups[(int)event.team.id]; - if(!(event.tile.entity instanceof BuildEntity)) return; - for(BaseUnit unit : group.all()){ - if(unit instanceof BuilderDrone){ + for(BaseUnit unit : unitGroup.all()){ + if(unit instanceof BuilderDrone && unit.getTeam() == getTeam()){ BuilderDrone drone = (BuilderDrone)unit; if(drone.isBuilding()){ //stop building if opposite building begins. diff --git a/core/src/mindustry/game/Team.java b/core/src/mindustry/game/Team.java index a97d84a70b..809d60f714 100644 --- a/core/src/mindustry/game/Team.java +++ b/core/src/mindustry/game/Team.java @@ -6,10 +6,9 @@ import arc.util.*; import mindustry.graphics.*; public class Team implements Comparable{ - public final Color color; - public final int intColor; - public final String name; public final byte id; + public final Color color; + public String name; /** All 256 registered teams. */ private static final Team[] all = new Team[256]; @@ -48,7 +47,6 @@ public class Team implements Comparable{ protected Team(int id, String name, Color color){ this.name = name; this.color = color; - this.intColor = Color.rgba8888(color); this.id = (byte)id; int us = Pack.u(this.id); diff --git a/core/src/mindustry/game/Teams.java b/core/src/mindustry/game/Teams.java index d5d033ec46..a0f489cff7 100644 --- a/core/src/mindustry/game/Teams.java +++ b/core/src/mindustry/game/Teams.java @@ -3,12 +3,12 @@ package mindustry.game; import arc.func.*; import arc.math.geom.*; import arc.struct.*; -import arc.util.*; import arc.util.ArcAnnotate.*; +import arc.util.*; import mindustry.entities.type.*; import mindustry.world.blocks.storage.CoreBlock.*; -import static mindustry.Vars.state; +import static mindustry.Vars.*; /** Class for various team-based utilities. */ public class Teams{ @@ -33,6 +33,10 @@ public class Teams{ return Geometry.findClosest(x, y, get(team).cores); } + public Array enemiesOf(Team team){ + return get(team).enemies; + } + public boolean eachEnemyCore(Team team, Boolf ret){ for(TeamData data : active){ if(areEnemies(team, data.team)){ @@ -104,6 +108,8 @@ public class Teams{ //register in active list if needed if(data.active() && !active.contains(data)){ active.add(data); + updateEnemies(); + indexer.updateTeamIndex(data.team); } } @@ -114,12 +120,24 @@ public class Teams{ //unregister in active list if(!data.active()){ active.remove(data); + updateEnemies(); + } + } + + private void updateEnemies(){ + for(TeamData data : active){ + data.enemies.clear(); + for(TeamData other : active){ + if(areEnemies(data.team, other.team)){ + data.enemies.add(other.team); + } + } } } public class TeamData{ - private final Array cores = new Array<>(); - + public final Array cores = new Array<>(); + public final Array enemies = new Array<>(); public final Team team; public Queue brokenBlocks = new Queue<>(); diff --git a/core/src/mindustry/io/MapIO.java b/core/src/mindustry/io/MapIO.java index d26adee127..85c5cc9cb7 100644 --- a/core/src/mindustry/io/MapIO.java +++ b/core/src/mindustry/io/MapIO.java @@ -92,7 +92,7 @@ public class MapIO{ public void setTeam(Team team){ super.setTeam(team); if(block instanceof CoreBlock){ - map.teams.add((int)team.id); + map.teams.add(team.id); } } }; @@ -146,7 +146,7 @@ public class MapIO{ public static int colorFor(Block floor, Block wall, Block ore, Team team){ if(wall.synthetic()){ - return team.intColor; + return team.color.rgba(); } return Color.rgba8888(wall.solid ? wall.color : ore == Blocks.air ? floor.color : ore.color); } diff --git a/core/src/mindustry/world/Tile.java b/core/src/mindustry/world/Tile.java index 4a8b2fa629..c591307176 100644 --- a/core/src/mindustry/world/Tile.java +++ b/core/src/mindustry/world/Tile.java @@ -146,7 +146,7 @@ public class Tile implements Position, TargetTrait{ } public void setTeam(Team team){ - this.team = (byte) (int)team.id; + this.team = (byte) team.id; } public byte getTeamID(){ @@ -156,7 +156,7 @@ public class Tile implements Position, TargetTrait{ public void setBlock(@NonNull Block type, Team team, int rotation){ preChanged(); this.block = type; - this.team = (byte) (int)team.id; + this.team = (byte) team.id; this.rotation = (byte)Mathf.mod(rotation, 4); changed(); } diff --git a/core/src/mindustry/world/blocks/BuildBlock.java b/core/src/mindustry/world/blocks/BuildBlock.java index df90a969b7..1ba7bff365 100644 --- a/core/src/mindustry/world/blocks/BuildBlock.java +++ b/core/src/mindustry/world/blocks/BuildBlock.java @@ -57,7 +57,7 @@ public class BuildBlock extends Block{ public static void onDeconstructFinish(Tile tile, Block block, int builderID){ Team team = tile.getTeam(); Effects.effect(Fx.breakBlock, tile.drawx(), tile.drawy(), block.size); - world.removeBlock(tile); + tile.remove(); Events.fire(new BlockBuildEndEvent(tile, playerGroup.getByID(builderID), team, true)); if(shouldPlay()) Sounds.breaks.at(tile, calcPitch(false)); } diff --git a/core/src/mindustry/world/blocks/units/CommandCenter.java b/core/src/mindustry/world/blocks/units/CommandCenter.java index 0d2e0428de..be82783269 100644 --- a/core/src/mindustry/world/blocks/units/CommandCenter.java +++ b/core/src/mindustry/world/blocks/units/CommandCenter.java @@ -1,11 +1,11 @@ package mindustry.world.blocks.units; import arc.*; -import arc.struct.*; import arc.graphics.*; import arc.graphics.g2d.*; import arc.scene.ui.*; import arc.scene.ui.layout.*; +import arc.struct.*; import arc.util.*; import mindustry.content.*; import mindustry.entities.*; @@ -13,7 +13,6 @@ import mindustry.entities.Effects.*; import mindustry.entities.type.*; import mindustry.entities.units.*; import mindustry.game.EventType.*; -import mindustry.game.*; import mindustry.graphics.*; import mindustry.ui.*; import mindustry.world.*; @@ -21,7 +20,7 @@ import mindustry.world.meta.*; import java.io.*; -import static mindustry.Vars.*; +import static mindustry.Vars.indexer; public class CommandCenter extends Block{ protected TextureRegion[] commandRegions = new TextureRegion[UnitCommand.all.length]; @@ -58,9 +57,7 @@ public class CommandCenter extends Block{ ObjectSet set = indexer.getAllied(tile.getTeam(), BlockFlag.comandCenter); if(set.size == 1){ - for(BaseUnit unit : unitGroups[(int)tile.getTeam().id].all()){ - unit.onCommand(UnitCommand.all[0]); - } + Units.each(tile.getTeam(), u -> u.onCommand(UnitCommand.all[0])); } } @@ -114,12 +111,7 @@ public class CommandCenter extends Block{ } } - Team team = (player == null ? tile.getTeam() : player.getTeam()); - - for(BaseUnit unit : unitGroups[(int)team.id].all()){ - unit.onCommand(command); - } - + Units.each(tile.getTeam(), u -> u.onCommand(command)); Events.fire(new CommandIssueEvent(tile, command)); } diff --git a/desktop/build.gradle b/desktop/build.gradle index efedf8c57b..d03320d394 100644 --- a/desktop/build.gradle +++ b/desktop/build.gradle @@ -33,7 +33,7 @@ task run(dependsOn: classes, type: JavaExec){ } if(args.contains("debug")){ - main = "io.anuke.mindustry.DebugLauncher" + main = "mindustry.debug.DebugLauncher" } } diff --git a/desktop/src/mindustry/desktop/steam/SStats.java b/desktop/src/mindustry/desktop/steam/SStats.java index bdbb86ad5e..bc355c26b0 100644 --- a/desktop/src/mindustry/desktop/steam/SStats.java +++ b/desktop/src/mindustry/desktop/steam/SStats.java @@ -1,9 +1,9 @@ package mindustry.desktop.steam; import arc.*; -import com.codedisaster.steamworks.*; import arc.struct.*; import arc.util.*; +import com.codedisaster.steamworks.*; import mindustry.*; import mindustry.content.*; import mindustry.entities.type.*; @@ -11,7 +11,6 @@ import mindustry.entities.units.*; import mindustry.game.EventType.*; import mindustry.game.Stats.*; import mindustry.type.*; -import mindustry.world.*; import static mindustry.Vars.*; import static mindustry.desktop.steam.SAchievement.*; @@ -55,18 +54,18 @@ public class SStats implements SteamUserStatsCallback{ private void checkUpdate(){ if(campaign()){ - SStat.maxUnitActive.max(unitGroups[(int)player.getTeam().id].size()); + SStat.maxUnitActive.max(unitGroup.count(t -> t.getTeam() == player.getTeam())); - if(unitGroups[(int)player.getTeam().id].count(u -> u.getType() == UnitTypes.phantom) >= 10){ + if(unitGroup.count(u -> u.getType() == UnitTypes.phantom && u.getTeam() == player.getTeam()) >= 10){ active10Phantoms.complete(); } - if(unitGroups[(int)player.getTeam().id].count(u -> u.getType() == UnitTypes.crawler) >= 50){ + if(unitGroup.count(u -> u.getType() == UnitTypes.crawler && u.getTeam() == player.getTeam()) >= 50){ active50Crawlers.complete(); } - for(Tile tile : state.teams.get(player.getTeam()).cores){ - if(!content.items().contains(i -> i.type == ItemType.material && tile.entity.items.get(i) < tile.block().itemCapacity)){ + for(TileEntity entity : state.teams.get(player.getTeam()).cores){ + if(!content.items().contains(i -> i.type == ItemType.material && entity.items.get(i) < entity.block.itemCapacity)){ fillCoreAllCampaign.complete(); break; } diff --git a/gradle.properties b/gradle.properties index e28d4db59a..eb016eca65 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,3 +1,3 @@ org.gradle.daemon=true org.gradle.jvmargs=-Xms256m -Xmx1024m -archash=447f3bb0e4616f82680f3234ad4e0cce48880884 +archash=44e060c9f2bf11eb7e41f79d967fdfeca9f8b62a From c449302d282102dff5e7a404b572582402b5d7f8 Mon Sep 17 00:00:00 2001 From: Anuken Date: Thu, 26 Dec 2019 19:57:24 -0500 Subject: [PATCH 09/78] Fixed tests --- core/src/mindustry/world/Build.java | 2 +- .../src/mindustry/server/ServerControl.java | 40 ++++++++++--------- tests/src/test/java/power/PowerTests.java | 3 ++ 3 files changed, 25 insertions(+), 20 deletions(-) diff --git a/core/src/mindustry/world/Build.java b/core/src/mindustry/world/Build.java index f101068cf0..b8d41df4f0 100644 --- a/core/src/mindustry/world/Build.java +++ b/core/src/mindustry/world/Build.java @@ -80,7 +80,7 @@ public class Build{ return false; } - if(!state.teams.eachEnemyCore(team, core -> Mathf.dst(x * tilesize + type.offset(), y * tilesize + type.offset(), core.x, core.y) < state.rules.enemyCoreBuildRadius + type.size * tilesize / 2f)){ + if(state.teams.eachEnemyCore(team, core -> Mathf.dst(x * tilesize + type.offset(), y * tilesize + type.offset(), core.x, core.y) < state.rules.enemyCoreBuildRadius + type.size * tilesize / 2f)){ return false; } diff --git a/server/src/mindustry/server/ServerControl.java b/server/src/mindustry/server/ServerControl.java index 109552adb4..3637ac972e 100644 --- a/server/src/mindustry/server/ServerControl.java +++ b/server/src/mindustry/server/ServerControl.java @@ -135,7 +135,7 @@ public class ServerControl implements ApplicationListener{ if(state.rules.waves){ info("&lcGame over! Reached wave &ly{0}&lc with &ly{1}&lc players online on map &ly{2}&lc.", state.wave, playerGroup.size(), Strings.capitalize(world.getMap().name())); }else{ - info("&lcGame over! Team &ly{0}&lc is victorious with &ly{1}&lc players online on map &ly{2}&lc.", event.winner.name(), playerGroup.size(), Strings.capitalize(world.getMap().name())); + info("&lcGame over! Team &ly{0}&lc is victorious with &ly{1}&lc players online on map &ly{2}&lc.", event.winner.name, playerGroup.size(), Strings.capitalize(world.getMap().name())); } //set next map to be played @@ -143,7 +143,7 @@ public class ServerControl implements ApplicationListener{ nextMapOverride = null; if(map != null){ Call.onInfoMessage((state.rules.pvp - ? "[YELLOW]The " + event.winner.name() + " team is victorious![]" : "[SCARLET]Game over![]") + ? "[YELLOW]The " + event.winner.name + " team is victorious![]" : "[SCARLET]Game over![]") + "\nNext selected map:[accent] " + map.name() + "[]" + (map.tags.containsKey("author") && !map.tags.get("author").trim().isEmpty() ? " by[accent] " + map.author() + "[]" : "") + "." + "\nNew game begins in " + roundExtraTime + "[] seconds."); @@ -292,7 +292,7 @@ public class ServerControl implements ApplicationListener{ info(" &lyPlaying on map &fi{0}&fb &lb/&ly Wave {1}", Strings.capitalize(world.getMap().name()), state.wave); if(state.rules.waves){ - info("&ly {0} enemies.", unitGroups[(int)Team.crux.id].size()); + info("&ly {0} enemies.", state.enemies); }else{ info("&ly {0} seconds until next wave.", (int)(state.wavetime / 60)); } @@ -418,24 +418,26 @@ public class ServerControl implements ApplicationListener{ return; } - try{ - Team team = arg.length == 0 ? Team.sharded : Team.valueOf(arg[0]); + Team team = arg.length == 0 ? Team.sharded : Structs.find(Team.all(), t -> t.name.equals(arg[0])); - if(state.teams.cores(team).isEmpty()){ - err("That team has no cores."); - return; - } - - for(Item item : content.items()){ - if(item.type == ItemType.material){ - state.teams.cores(team).first().entity.items.set(item, state.teams.cores(team).first().block().itemCapacity); - } - } - - info("Core filled."); - }catch(IllegalArgumentException ignored){ - err("No such team exists."); + if(team == null){ + err("No team with that name found."); + return; } + + if(state.teams.cores(team).isEmpty()){ + err("That team has no cores."); + return; + } + + for(Item item : content.items()){ + if(item.type == ItemType.material){ + state.teams.cores(team).first().items.set(item, state.teams.cores(team).first().block.itemCapacity); + } + } + + info("Core filled."); + }); handler.register("name", "[name...]", "Change the server display name.", arg -> { diff --git a/tests/src/test/java/power/PowerTests.java b/tests/src/test/java/power/PowerTests.java index f017bf6e82..6815f2e880 100644 --- a/tests/src/test/java/power/PowerTests.java +++ b/tests/src/test/java/power/PowerTests.java @@ -3,6 +3,8 @@ package power; import arc.*; import arc.math.*; import arc.util.*; +import mindustry.*; +import mindustry.core.*; import mindustry.world.*; import mindustry.world.blocks.power.*; import mindustry.world.consumers.*; @@ -23,6 +25,7 @@ public class PowerTests extends PowerTestFixture{ @BeforeAll static void init(){ Core.graphics = new FakeGraphics(); + Vars.state = new GameState(); } @Nested From 954e26fc145b7874af2c52f6b148c81d3fe2e10d Mon Sep 17 00:00:00 2001 From: Anuken Date: Thu, 26 Dec 2019 20:08:53 -0500 Subject: [PATCH 10/78] Method cleanup --- core/src/mindustry/ai/BlockIndexer.java | 2 +- core/src/mindustry/ai/WaveSpawner.java | 2 +- core/src/mindustry/entities/Damage.java | 2 +- core/src/mindustry/entities/Units.java | 6 ++-- core/src/mindustry/entities/type/Unit.java | 2 +- .../entities/type/base/BuilderDrone.java | 5 ++-- .../entities/type/base/GroundUnit.java | 6 ++-- core/src/mindustry/game/Team.java | 29 +++++++++++++++++++ core/src/mindustry/game/Teams.java | 2 +- core/src/mindustry/game/Tutorial.java | 2 +- core/src/mindustry/input/InputHandler.java | 2 +- core/src/mindustry/input/MobileInput.java | 2 +- core/src/mindustry/io/SaveVersion.java | 2 +- core/src/mindustry/ui/ItemsDisplay.java | 2 +- .../src/mindustry/desktop/steam/SStats.java | 2 +- gradle.properties | 2 +- 16 files changed, 49 insertions(+), 21 deletions(-) diff --git a/core/src/mindustry/ai/BlockIndexer.java b/core/src/mindustry/ai/BlockIndexer.java index d5d2f747e2..b010562595 100644 --- a/core/src/mindustry/ai/BlockIndexer.java +++ b/core/src/mindustry/ai/BlockIndexer.java @@ -162,7 +162,7 @@ public class BlockIndexer{ /** Get all enemy blocks with a flag. */ public Array getEnemy(Team team, BlockFlag type){ returnArray.clear(); - for(Team enemy : state.teams.enemiesOf(team)){ + for(Team enemy : team.enemies()){ if(state.teams.isActive(enemy)){ ObjectSet set = getFlagged(enemy)[type.ordinal()]; if(set != null){ diff --git a/core/src/mindustry/ai/WaveSpawner.java b/core/src/mindustry/ai/WaveSpawner.java index 129b930d3b..3bd5bc5400 100644 --- a/core/src/mindustry/ai/WaveSpawner.java +++ b/core/src/mindustry/ai/WaveSpawner.java @@ -92,7 +92,7 @@ public class WaveSpawner{ if(state.rules.attackMode && state.teams.isActive(state.rules.waveTeam) && !state.teams.playerCores().isEmpty()){ TileEntity firstCore = state.teams.playerCores().first(); - for(TileEntity core : state.teams.get(state.rules.waveTeam).cores){ + for(TileEntity core : state.rules.waveTeam.cores()){ Tmp.v1.set(firstCore).sub(core.x, core.y).limit(coreMargin + core.block.size*tilesize); cons.accept(core.x + Tmp.v1.x, core.y + Tmp.v1.y, false); } diff --git a/core/src/mindustry/entities/Damage.java b/core/src/mindustry/entities/Damage.java index 73f0b4996e..3c4b130e0d 100644 --- a/core/src/mindustry/entities/Damage.java +++ b/core/src/mindustry/entities/Damage.java @@ -259,7 +259,7 @@ public class Damage{ for(int dx = -trad; dx <= trad; dx++){ for(int dy = -trad; dy <= trad; dy++){ Tile tile = world.tile(Math.round(x / tilesize) + dx, Math.round(y / tilesize) + dy); - if(tile != null && tile.entity != null && (team == null || state.teams.areEnemies(team, tile.getTeam())) && Mathf.dst(dx, dy) <= trad){ + if(tile != null && tile.entity != null && (team == null ||team.isEnemy(tile.getTeam())) && Mathf.dst(dx, dy) <= trad){ tile.entity.damage(damage); } } diff --git a/core/src/mindustry/entities/Units.java b/core/src/mindustry/entities/Units.java index 7592551ce4..6bcd15e1c5 100644 --- a/core/src/mindustry/entities/Units.java +++ b/core/src/mindustry/entities/Units.java @@ -83,7 +83,7 @@ public class Units{ public static TileEntity findEnemyTile(Team team, float x, float y, float range, Boolf pred){ if(team == Team.derelict) return null; - for(Team enemy : state.teams.enemiesOf(team)){ + for(Team enemy : team.enemies()){ TileEntity entity = indexer.findTile(enemy, x, y, range, pred, true); if(entity != null){ return entity; @@ -195,13 +195,13 @@ public class Units{ /** Iterates over all units that are enemies of this team. */ public static void nearbyEnemies(Team team, float x, float y, float width, float height, Cons cons){ unitGroup.intersect(x, y, width, height, u -> { - if(state.teams.areEnemies(team, u.getTeam())){ + if(team.isEnemy(u.getTeam())){ cons.get(u); } }); playerGroup.intersect(x, y, width, height, player -> { - if(state.teams.areEnemies(team, player.getTeam())){ + if(team.isEnemy(player.getTeam())){ cons.get(player); } }); diff --git a/core/src/mindustry/entities/type/Unit.java b/core/src/mindustry/entities/type/Unit.java index f9c78a747b..ab02f24c83 100644 --- a/core/src/mindustry/entities/type/Unit.java +++ b/core/src/mindustry/entities/type/Unit.java @@ -88,7 +88,7 @@ public abstract class Unit extends DestructibleEntity implements SaveTrait, Targ if(isDead()) return false; if(other instanceof DamageTrait){ - return other instanceof TeamTrait && state.teams.areEnemies((((TeamTrait)other).getTeam()), team); + return other instanceof TeamTrait && (((TeamTrait)other).getTeam()).isEnemy(team); }else{ return other instanceof Unit && ((Unit)other).isFlying() == isFlying(); } diff --git a/core/src/mindustry/entities/type/base/BuilderDrone.java b/core/src/mindustry/entities/type/base/BuilderDrone.java index 6442347de4..336be7be6e 100644 --- a/core/src/mindustry/entities/type/base/BuilderDrone.java +++ b/core/src/mindustry/entities/type/base/BuilderDrone.java @@ -1,10 +1,9 @@ package mindustry.entities.type.base; import arc.*; -import arc.struct.*; import arc.math.*; +import arc.struct.*; import arc.util.*; -import mindustry.*; import mindustry.entities.*; import mindustry.entities.traits.*; import mindustry.entities.type.*; @@ -187,7 +186,7 @@ public class BuilderDrone extends BaseDrone implements BuilderTrait{ } if(timer.get(timerTarget, 80) && Units.closestEnemy(getTeam(), x, y, 100f, u -> !(u instanceof BaseDrone)) == null && !isBuilding()){ - TeamData data = Vars.state.teams.get(team); + TeamData data = team.data(); if(!data.brokenBlocks.isEmpty()){ BrokenBlock block = data.brokenBlocks.removeLast(); if(Build.validPlace(getTeam(), block.x, block.y, content.block(block.block), block.rotation)){ diff --git a/core/src/mindustry/entities/type/base/GroundUnit.java b/core/src/mindustry/entities/type/base/GroundUnit.java index 5f7c6d2768..d680fa230a 100644 --- a/core/src/mindustry/entities/type/base/GroundUnit.java +++ b/core/src/mindustry/entities/type/base/GroundUnit.java @@ -237,15 +237,15 @@ public class GroundUnit extends BaseUnit{ protected void moveAwayFromCore(){ Team enemy = null; - for(Team team : Vars.state.teams.enemiesOf(team)){ - if(Vars.state.teams.isActive(team)){ + for(Team team : Vars.team.enemies()){ + if(team.active()){ enemy = team; break; } } if(enemy == null){ - for(Team team : Vars.state.teams.enemiesOf(team)){ + for(Team team : Vars.team.enemies()){ enemy = team; break; } diff --git a/core/src/mindustry/game/Team.java b/core/src/mindustry/game/Team.java index 809d60f714..b6b608d5d0 100644 --- a/core/src/mindustry/game/Team.java +++ b/core/src/mindustry/game/Team.java @@ -2,8 +2,13 @@ package mindustry.game; import arc.*; import arc.graphics.*; +import arc.struct.*; import arc.util.*; +import mindustry.game.Teams.*; import mindustry.graphics.*; +import mindustry.world.blocks.storage.CoreBlock.*; + +import static mindustry.Vars.*; public class Team implements Comparable{ public final byte id; @@ -54,6 +59,30 @@ public class Team implements Comparable{ all[us] = this; } + public Array enemies(){ + return state.teams.enemiesOf(this); + } + + public TeamData data(){ + return state.teams.get(this); + } + + public CoreEntity core(){ + return data().core(); + } + + public boolean active(){ + return state.teams.isActive(this); + } + + public boolean isEnemy(Team other){ + return state.teams.areEnemies(this, other); + } + + public Array cores(){ + return state.teams.cores(this); + } + public String localized(){ return Core.bundle.get("team." + name + ".name", name); } diff --git a/core/src/mindustry/game/Teams.java b/core/src/mindustry/game/Teams.java index 5d2b570cd2..dc44d47240 100644 --- a/core/src/mindustry/game/Teams.java +++ b/core/src/mindustry/game/Teams.java @@ -161,7 +161,7 @@ public class Teams{ return cores.isEmpty(); } - public TileEntity core(){ + public CoreEntity core(){ return cores.first(); } } diff --git a/core/src/mindustry/game/Tutorial.java b/core/src/mindustry/game/Tutorial.java index 300ab01283..4b344bc945 100644 --- a/core/src/mindustry/game/Tutorial.java +++ b/core/src/mindustry/game/Tutorial.java @@ -271,7 +271,7 @@ public class Tutorial{ } static int item(Item item){ - return state.teams.get(state.rules.defaultTeam).noCores() ? 0 : state.teams.playerCores().first().items.get(item); + return state.rules.defaultTeam.data().noCores() ? 0 : state.rules.defaultTeam.core().items.get(item); } static boolean toggled(String name){ diff --git a/core/src/mindustry/input/InputHandler.java b/core/src/mindustry/input/InputHandler.java index 2a4ce0343f..b35683c7e2 100644 --- a/core/src/mindustry/input/InputHandler.java +++ b/core/src/mindustry/input/InputHandler.java @@ -402,7 +402,7 @@ public abstract class InputHandler implements InputProcessor, GestureListener{ } } - for(BrokenBlock req : state.teams.get(player.getTeam()).brokenBlocks){ + for(BrokenBlock req : player.getTeam().data().brokenBlocks){ Block block = content.block(req.block); if(block.bounds(req.x, req.y, Tmp.r2).overlaps(Tmp.r1)){ drawSelected(req.x, req.y, content.block(req.block), Pal.remove); diff --git a/core/src/mindustry/input/MobileInput.java b/core/src/mindustry/input/MobileInput.java index 5379caf113..81f657c876 100644 --- a/core/src/mindustry/input/MobileInput.java +++ b/core/src/mindustry/input/MobileInput.java @@ -77,7 +77,7 @@ public class MobileInput extends InputHandler implements GestureListener{ }else{ Tile tile = world.ltileWorld(x, y); - if(tile != null && tile.synthetic() && state.teams.areEnemies(player.getTeam(), tile.getTeam())){ + if(tile != null && tile.synthetic() && player.getTeam().isEnemy(tile.getTeam())){ TileEntity entity = tile.entity; player.setMineTile(null); player.target = entity; diff --git a/core/src/mindustry/io/SaveVersion.java b/core/src/mindustry/io/SaveVersion.java index 1d4ab19859..06c75bc878 100644 --- a/core/src/mindustry/io/SaveVersion.java +++ b/core/src/mindustry/io/SaveVersion.java @@ -259,7 +259,7 @@ public abstract class SaveVersion extends SaveFileReader{ int teamc = stream.readInt(); for(int i = 0; i < teamc; i++){ Team team = Team.get(stream.readInt()); - TeamData data = state.teams.get(team); + TeamData data = team.data(); int blocks = stream.readInt(); for(int j = 0; j < blocks; j++){ data.brokenBlocks.addLast(new BrokenBlock(stream.readShort(), stream.readShort(), stream.readShort(), content.block(stream.readShort()).id, stream.readInt())); diff --git a/core/src/mindustry/ui/ItemsDisplay.java b/core/src/mindustry/ui/ItemsDisplay.java index 755590f34f..d59a579c16 100644 --- a/core/src/mindustry/ui/ItemsDisplay.java +++ b/core/src/mindustry/ui/ItemsDisplay.java @@ -39,7 +39,7 @@ public class ItemsDisplay extends Table{ private String format(Item item){ builder.setLength(0); builder.append(ui.formatAmount(data.items().get(item, 0))); - if(!state.is(State.menu) && state.teams.get(player.getTeam()).hasCore() && state.teams.get(player.getTeam()).core().items.get(item) > 0){ + if(!state.is(State.menu) && player.getTeam().data().hasCore() && player.getTeam().core().items.get(item) > 0){ builder.append(" [unlaunched]+ "); builder.append(ui.formatAmount(state.teams.get(player.getTeam()).core().items.get(item))); } diff --git a/desktop/src/mindustry/desktop/steam/SStats.java b/desktop/src/mindustry/desktop/steam/SStats.java index bc355c26b0..950bffc249 100644 --- a/desktop/src/mindustry/desktop/steam/SStats.java +++ b/desktop/src/mindustry/desktop/steam/SStats.java @@ -64,7 +64,7 @@ public class SStats implements SteamUserStatsCallback{ active50Crawlers.complete(); } - for(TileEntity entity : state.teams.get(player.getTeam()).cores){ + for(TileEntity entity : player.getTeam().cores()){ if(!content.items().contains(i -> i.type == ItemType.material && entity.items.get(i) < entity.block.itemCapacity)){ fillCoreAllCampaign.complete(); break; diff --git a/gradle.properties b/gradle.properties index eb016eca65..f8748c523a 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,3 +1,3 @@ org.gradle.daemon=true org.gradle.jvmargs=-Xms256m -Xmx1024m -archash=44e060c9f2bf11eb7e41f79d967fdfeca9f8b62a +archash=29782072a3c824715118f51ebe23c189ba0d9597 From 684f3075cbab4509c3a3300b504c8378557fefcb Mon Sep 17 00:00:00 2001 From: Anuken Date: Thu, 26 Dec 2019 20:20:12 -0500 Subject: [PATCH 11/78] Team#toString() --- core/src/mindustry/entities/type/base/GroundUnit.java | 4 ++-- core/src/mindustry/game/Team.java | 7 ++++++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/core/src/mindustry/entities/type/base/GroundUnit.java b/core/src/mindustry/entities/type/base/GroundUnit.java index d680fa230a..56ba404a30 100644 --- a/core/src/mindustry/entities/type/base/GroundUnit.java +++ b/core/src/mindustry/entities/type/base/GroundUnit.java @@ -237,7 +237,7 @@ public class GroundUnit extends BaseUnit{ protected void moveAwayFromCore(){ Team enemy = null; - for(Team team : Vars.team.enemies()){ + for(Team team : team.enemies()){ if(team.active()){ enemy = team; break; @@ -245,7 +245,7 @@ public class GroundUnit extends BaseUnit{ } if(enemy == null){ - for(Team team : Vars.team.enemies()){ + for(Team team : team.enemies()){ enemy = team; break; } diff --git a/core/src/mindustry/game/Team.java b/core/src/mindustry/game/Team.java index b6b608d5d0..f5b02e4d9a 100644 --- a/core/src/mindustry/game/Team.java +++ b/core/src/mindustry/game/Team.java @@ -31,7 +31,7 @@ public class Team implements Comparable{ static{ //create the whole 256 placeholder teams for(int i = 6; i < all.length; i++){ - new Team(i, "team#" + i, Color.HSVtoRGB(360f * (float)(i) / all.length, 100f, 100f, 1f)); + new Team(i, "team#" + i, Color.HSVtoRGB(360f * (float)(i) / all.length * 10, 100f * 0.8f, 100f * 0.8f, 1f)); } } @@ -91,4 +91,9 @@ public class Team implements Comparable{ public int compareTo(Team team){ return Integer.compare(id, team.id); } + + @Override + public String toString(){ + return name; + } } From c339a0ecdf078391e405e58dd4c5ba2b9845bc39 Mon Sep 17 00:00:00 2001 From: Anuken Date: Thu, 26 Dec 2019 20:44:05 -0500 Subject: [PATCH 12/78] Merge --- core/src/mindustry/entities/bullet/ArtilleryBulletType.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/mindustry/entities/bullet/ArtilleryBulletType.java b/core/src/mindustry/entities/bullet/ArtilleryBulletType.java index 3a098e8765..c59dedf99a 100644 --- a/core/src/mindustry/entities/bullet/ArtilleryBulletType.java +++ b/core/src/mindustry/entities/bullet/ArtilleryBulletType.java @@ -25,7 +25,7 @@ public class ArtilleryBulletType extends BasicBulletType{ } @Override - public void update(mindustry.entities.type.Bullet b){ + public void update(Bullet b){ super.update(b); if(b.timer.get(0, 3 + b.fslope() * 2f)){ From 6080a7e4bcb9972c208630a8295c92f328a9054a Mon Sep 17 00:00:00 2001 From: Anuken Date: Thu, 26 Dec 2019 20:53:53 -0500 Subject: [PATCH 13/78] Possibly fixed tests / Added support for mod icons --- core/src/mindustry/mod/Mods.java | 25 +++++++++++++++++-- .../src/test/java/power/PowerTestFixture.java | 1 + 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/core/src/mindustry/mod/Mods.java b/core/src/mindustry/mod/Mods.java index e4da45357b..b92b2fefc5 100644 --- a/core/src/mindustry/mod/Mods.java +++ b/core/src/mindustry/mod/Mods.java @@ -2,7 +2,6 @@ package mindustry.mod; import arc.*; import arc.assets.*; -import arc.struct.*; import arc.files.*; import arc.func.*; import arc.graphics.*; @@ -10,6 +9,7 @@ import arc.graphics.Texture.*; import arc.graphics.g2d.*; import arc.graphics.g2d.TextureAtlas.*; import arc.scene.ui.*; +import arc.struct.*; import arc.util.*; import arc.util.ArcAnnotate.*; import arc.util.io.*; @@ -142,6 +142,17 @@ public class Mods implements Loadable{ @Override public void loadSync(){ + for(LoadedMod mod : mods){ + //try to load icon for each mod that can have one + if(mod.root.child("icon.png").exists()){ + try{ + mod.iconTexture = new Texture(mod.root.child("icon.png")); + }catch(Throwable t){ + Log.err("Failed to load icon for mod '" + mod.name + "'.", t); + } + } + } + if(packer == null) return; Time.mark(); @@ -408,6 +419,7 @@ public class Mods implements Loadable{ //TODO make it less epic Core.atlas = new TextureAtlas(Core.files.internal("sprites/sprites.atlas")); + mods.each(LoadedMod::dispose); mods.clear(); Core.bundle = I18NBundle.createBundle(Core.files.internal("bundles/bundle"), Core.bundle.getLocale()); load(); @@ -643,7 +655,7 @@ public class Mods implements Loadable{ } /** Represents a plugin that has been loaded from a jar file.*/ - public static class LoadedMod implements Publishable{ + public static class LoadedMod implements Publishable, Disposable{ /** The location of this mod's zip file/folder on the disk. */ public final Fi file; /** The root zip file; points to the contents of this mod. In the case of folders, this is the same as the mod's file. */ @@ -664,6 +676,8 @@ public class Mods implements Loadable{ public ObjectSet erroredContent = new ObjectSet<>(); /** Current state of this mod. */ public ModState state = ModState.enabled; + /** Icon texture. Should be disposed. */ + public @Nullable Texture iconTexture; public LoadedMod(Fi file, Fi root, Mod main, ModMeta meta){ this.root = root; @@ -701,6 +715,13 @@ public class Mods implements Loadable{ return Version.build >= Strings.parseInt(meta.minGameVersion, 0); } + @Override + public void dispose(){ + if(iconTexture != null){ + iconTexture.dispose(); + } + } + @Override public String getSteamID(){ return Core.settings.getString(name + "-steamid", null); diff --git a/tests/src/test/java/power/PowerTestFixture.java b/tests/src/test/java/power/PowerTestFixture.java index fd445a2c25..e5735052f5 100644 --- a/tests/src/test/java/power/PowerTestFixture.java +++ b/tests/src/test/java/power/PowerTestFixture.java @@ -27,6 +27,7 @@ public class PowerTestFixture{ @BeforeAll static void initializeDependencies(){ Core.graphics = new FakeGraphics(); + Vars.state = new GameState(); Vars.content = new ContentLoader(){ @Override public void handleMappableContent(MappableContent content){ From d6d6dc29dc5cca2d702a67e09c78b36b3b84996d Mon Sep 17 00:00:00 2001 From: Anuken Date: Thu, 26 Dec 2019 22:44:15 -0500 Subject: [PATCH 14/78] More plugin customization / Renamed Rectangle --- core/src/mindustry/core/Control.java | 2 +- core/src/mindustry/core/NetClient.java | 10 ++++- core/src/mindustry/core/NetServer.java | 43 +++++++++++-------- core/src/mindustry/core/Renderer.java | 6 +-- core/src/mindustry/editor/MapView.java | 2 +- core/src/mindustry/entities/Damage.java | 6 +-- .../mindustry/entities/EntityCollisions.java | 10 ++--- core/src/mindustry/entities/EntityGroup.java | 8 ++-- core/src/mindustry/entities/Units.java | 6 +-- .../entities/bullet/FlakBulletType.java | 4 +- .../mindustry/entities/effect/Lightning.java | 2 +- .../src/mindustry/entities/effect/Puddle.java | 12 +++--- .../entities/traits/BuilderTrait.java | 2 +- .../mindustry/entities/traits/SolidTrait.java | 4 +- .../src/mindustry/entities/type/BaseUnit.java | 8 ++-- core/src/mindustry/entities/type/Bullet.java | 8 ++-- core/src/mindustry/entities/type/Player.java | 10 ++--- core/src/mindustry/game/EventType.java | 5 ++- core/src/mindustry/game/Rules.java | 2 + .../mindustry/graphics/MinimapRenderer.java | 2 +- .../mindustry/graphics/OverlayRenderer.java | 2 +- core/src/mindustry/input/InputHandler.java | 2 +- core/src/mindustry/io/JsonIO.java | 14 +++++- core/src/mindustry/net/Administration.java | 30 +++++++++++-- core/src/mindustry/ui/Bar.java | 2 +- .../mindustry/ui/dialogs/DeployDialog.java | 2 +- .../mindustry/ui/dialogs/TechTreeDialog.java | 4 +- .../mindustry/ui/layout/BranchTreeLayout.java | 4 +- core/src/mindustry/world/Block.java | 2 +- core/src/mindustry/world/Tile.java | 2 +- .../world/blocks/defense/DeflectorWall.java | 4 +- .../mindustry/world/blocks/defense/Door.java | 2 +- .../world/blocks/units/RepairPoint.java | 4 +- gradle.properties | 2 +- tests/src/test/java/IOTests.java | 28 +++++++++--- 35 files changed, 166 insertions(+), 90 deletions(-) diff --git a/core/src/mindustry/core/Control.java b/core/src/mindustry/core/Control.java index ef31948c82..458cb313ae 100644 --- a/core/src/mindustry/core/Control.java +++ b/core/src/mindustry/core/Control.java @@ -63,7 +63,7 @@ public class Control implements ApplicationListener, Loadable{ }); Events.on(PlayEvent.class, event -> { - player.setTeam(state.rules.pvp ? netServer.assignTeam(player, playerGroup.all()) : state.rules.defaultTeam); + player.setTeam(netServer.assignTeam(player, playerGroup.all())); player.setDead(true); player.add(); diff --git a/core/src/mindustry/core/NetClient.java b/core/src/mindustry/core/NetClient.java index 65c6122d72..96daa07041 100644 --- a/core/src/mindustry/core/NetClient.java +++ b/core/src/mindustry/core/NetClient.java @@ -160,9 +160,17 @@ public class NetClient implements ApplicationListener{ throw new ValidateException(player, "Player has sent a message above the text limit."); } + String original = message; + //check if it's a command CommandResponse response = netServer.clientCommands.handleMessage(message, player); if(response.type == ResponseType.noCommand){ //no command to handle + message = netServer.admins.filterMessage(player, message); + //supress chat message if it's filtered out + if(message == null){ + return; + } + //server console logging Log.info("&y{0}: &lb{1}", player.name, message); @@ -190,7 +198,7 @@ public class NetClient implements ApplicationListener{ } } - Events.fire(new PlayerChatEvent(player, message)); + Events.fire(new PlayerChatEvent(player, message, original)); } public static String colorizeName(int id, String name){ diff --git a/core/src/mindustry/core/NetServer.java b/core/src/mindustry/core/NetServer.java index 3e325e5b31..c74f14211c 100644 --- a/core/src/mindustry/core/NetServer.java +++ b/core/src/mindustry/core/NetServer.java @@ -33,14 +33,31 @@ import static mindustry.Vars.*; public class NetServer implements ApplicationListener{ private final static int maxSnapshotSize = 430, timerBlockSync = 0; - private final static float serverSyncTime = 12, kickDuration = 30 * 1000, blockSyncTime = 60 * 10; + private final static float serverSyncTime = 12, kickDuration = 30 * 1000, blockSyncTime = 60 * 8; private final static Vec2 vector = new Vec2(); - private final static Rectangle viewport = new Rectangle(); + private final static Rect viewport = new Rect(); /** If a player goes away of their server-side coordinates by this distance, they get teleported back. */ private final static float correctDist = 16f; public final Administration admins = new Administration(); public final CommandHandler clientCommands = new CommandHandler("/"); + public TeamAssigner assigner = (player, players) -> { + if(state.rules.pvp){ + //find team with minimum amount of players and auto-assign player to that. + TeamData re = state.teams.getActive().min(data -> { + int count = 0; + for(Player other : players){ + if(other.getTeam() == data.team && other != player){ + count++; + } + } + return count; + }); + return re == null ? null : re.team; + } + + return state.rules.defaultTeam; + }; private boolean closing = false; private Interval timer = new Interval(); @@ -199,10 +216,8 @@ public class NetServer implements ApplicationListener{ con.player = player; //playing in pvp mode automatically assigns players to teams - if(state.rules.pvp){ - player.setTeam(assignTeam(player, playerGroup.all())); - Log.info("Auto-assigned player {0} to team {1}.", player.name, player.getTeam()); - } + player.setTeam(assignTeam(player, playerGroup.all())); + Log.info("Auto-assigned player {0} to team {1}.", player.name, player.getTeam()); sendWorldData(player); @@ -403,17 +418,7 @@ public class NetServer implements ApplicationListener{ } public Team assignTeam(Player current, Iterable players){ - //find team with minimum amount of players and auto-assign player to that. - TeamData re = state.teams.getActive().min(data -> { - int count = 0; - for(Player other : players){ - if(other.getTeam() == data.team && other != current){ - count++; - } - } - return count; - }); - return re == null ? null : re.team; + return assigner.assign(current, players); } public void sendWorldData(Player player){ @@ -784,4 +789,8 @@ public class NetServer implements ApplicationListener{ e.printStackTrace(); } } + + public interface TeamAssigner{ + Team assign(Player player, Iterable players); + } } diff --git a/core/src/mindustry/core/Renderer.java b/core/src/mindustry/core/Renderer.java index 94528a62d8..d4983e992a 100644 --- a/core/src/mindustry/core/Renderer.java +++ b/core/src/mindustry/core/Renderer.java @@ -41,7 +41,7 @@ public class Renderer implements ApplicationListener{ private float camerascale = targetscale; private float landscale = 0f, landTime; private float minZoomScl = Scl.scl(0.01f); - private Rectangle rect = new Rectangle(), rect2 = new Rectangle(); + private Rect rect = new Rect(), rect2 = new Rect(); private float shakeIntensity, shaketime; public Renderer(){ @@ -56,8 +56,8 @@ public class Renderer implements ApplicationListener{ Effects.setEffectProvider((effect, color, x, y, rotation, data) -> { if(effect == Fx.none) return; if(Core.settings.getBool("effects")){ - Rectangle view = camera.bounds(rect); - Rectangle pos = rect2.setSize(effect.size).setCenter(x, y); + Rect view = camera.bounds(rect); + Rect pos = rect2.setSize(effect.size).setCenter(x, y); if(view.overlaps(pos)){ diff --git a/core/src/mindustry/editor/MapView.java b/core/src/mindustry/editor/MapView.java index 4c99ffba61..6787f418ab 100644 --- a/core/src/mindustry/editor/MapView.java +++ b/core/src/mindustry/editor/MapView.java @@ -28,7 +28,7 @@ public class MapView extends Element implements GestureListener{ private boolean grid = false; private GridImage image = new GridImage(0, 0); private Vec2 vec = new Vec2(); - private Rectangle rect = new Rectangle(); + private Rect rect = new Rect(); private Vec2[][] brushPolygons = new Vec2[MapEditor.brushSizes.length][0]; private boolean drawing; diff --git a/core/src/mindustry/entities/Damage.java b/core/src/mindustry/entities/Damage.java index 3c4b130e0d..335ac96385 100644 --- a/core/src/mindustry/entities/Damage.java +++ b/core/src/mindustry/entities/Damage.java @@ -22,8 +22,8 @@ import static mindustry.Vars.*; /** Utility class for damaging in an area. */ public class Damage{ - private static Rectangle rect = new Rectangle(); - private static Rectangle hitrect = new Rectangle(); + private static Rect rect = new Rect(); + private static Rect hitrect = new Rect(); private static Vec2 tr = new Vec2(); private static GridBits bits = new GridBits(30, 30); private static IntQueue propagation = new IntQueue(); @@ -127,7 +127,7 @@ public class Damage{ Cons cons = e -> { e.hitbox(hitrect); - Rectangle other = hitrect; + Rect other = hitrect; other.y -= expand; other.x -= expand; other.width += expand * 2; diff --git a/core/src/mindustry/entities/EntityCollisions.java b/core/src/mindustry/entities/EntityCollisions.java index 6a7fefffd1..72e177d71e 100644 --- a/core/src/mindustry/entities/EntityCollisions.java +++ b/core/src/mindustry/entities/EntityCollisions.java @@ -17,11 +17,11 @@ public class EntityCollisions{ private static final float seg = 1f; //tile collisions - private Rectangle tmp = new Rectangle(); + private Rect tmp = new Rect(); private Vec2 vector = new Vec2(); private Vec2 l1 = new Vec2(); - private Rectangle r1 = new Rectangle(); - private Rectangle r2 = new Rectangle(); + private Rect r1 = new Rect(); + private Rect r2 = new Rect(); //entity collisions private Array arrOut = new Array<>(); @@ -57,7 +57,7 @@ public class EntityCollisions{ public void moveDelta(SolidTrait entity, float deltax, float deltay, boolean x){ - Rectangle rect = r1; + Rect rect = r1; entity.hitboxTile(rect); entity.hitboxTile(r2); rect.x += deltax; @@ -84,7 +84,7 @@ public class EntityCollisions{ entity.setY(entity.getY() + rect.y - r2.y); } - public boolean overlapsTile(Rectangle rect){ + public boolean overlapsTile(Rect rect){ rect.getCenter(vector); int r = 1; diff --git a/core/src/mindustry/entities/EntityGroup.java b/core/src/mindustry/entities/EntityGroup.java index d691949272..8c0ac76442 100644 --- a/core/src/mindustry/entities/EntityGroup.java +++ b/core/src/mindustry/entities/EntityGroup.java @@ -19,13 +19,13 @@ public class EntityGroup{ private final Array entitiesToRemove = new Array<>(false, 32); private final Array entitiesToAdd = new Array<>(false, 32); private final Array intersectArray = new Array<>(); - private final Rectangle intersectRect = new Rectangle(); + private final Rect intersectRect = new Rect(); private IntMap map; private QuadTree tree; private Cons removeListener; private Cons addListener; - private final Rectangle viewport = new Rectangle(); + private final Rect viewport = new Rect(); private int count = 0; public EntityGroup(int id, Class type, boolean useTree){ @@ -34,7 +34,7 @@ public class EntityGroup{ this.type = type; if(useTree){ - tree = new QuadTree<>(new Rectangle(0, 0, 0, 0)); + tree = new QuadTree<>(new Rect(0, 0, 0, 0)); } } @@ -180,7 +180,7 @@ public class EntityGroup{ /** Resizes the internal quadtree, if it is enabled.*/ public void resize(float x, float y, float w, float h){ if(useTree){ - tree = new QuadTree<>(new Rectangle(x, y, w, h)); + tree = new QuadTree<>(new Rect(x, y, w, h)); } } diff --git a/core/src/mindustry/entities/Units.java b/core/src/mindustry/entities/Units.java index 6bcd15e1c5..fac56dcc0e 100644 --- a/core/src/mindustry/entities/Units.java +++ b/core/src/mindustry/entities/Units.java @@ -12,7 +12,7 @@ import static mindustry.Vars.*; /** Utility class for unit and team interactions.*/ public class Units{ - private static Rectangle hitrect = new Rectangle(); + private static Rect hitrect = new Rect(); private static Unit result; private static float cdist; private static boolean boolResult; @@ -188,7 +188,7 @@ public class Units{ } /** Iterates over all units in a rectangle. */ - public static void nearby(Rectangle rect, Cons cons){ + public static void nearby(Rect rect, Cons cons){ nearby(rect.x, rect.y, rect.width, rect.height, cons); } @@ -208,7 +208,7 @@ public class Units{ } /** Iterates over all units that are enemies of this team. */ - public static void nearbyEnemies(Team team, Rectangle rect, Cons cons){ + public static void nearbyEnemies(Team team, Rect rect, Cons cons){ nearbyEnemies(team, rect.x, rect.y, rect.width, rect.height, cons); } diff --git a/core/src/mindustry/entities/bullet/FlakBulletType.java b/core/src/mindustry/entities/bullet/FlakBulletType.java index b68e3af59a..ead19859cc 100644 --- a/core/src/mindustry/entities/bullet/FlakBulletType.java +++ b/core/src/mindustry/entities/bullet/FlakBulletType.java @@ -1,13 +1,13 @@ package mindustry.entities.bullet; -import arc.math.geom.Rectangle; +import arc.math.geom.Rect; import arc.util.Time; import mindustry.content.Fx; import mindustry.entities.Units; import mindustry.entities.type.Bullet; public class FlakBulletType extends BasicBulletType{ - protected static Rectangle rect = new Rectangle(); + protected static Rect rect = new Rect(); protected float explodeRange = 30f; public FlakBulletType(float speed, float damage){ diff --git a/core/src/mindustry/entities/effect/Lightning.java b/core/src/mindustry/entities/effect/Lightning.java index 1e88c29df2..59b7f833fa 100644 --- a/core/src/mindustry/entities/effect/Lightning.java +++ b/core/src/mindustry/entities/effect/Lightning.java @@ -28,7 +28,7 @@ public class Lightning extends TimedEntity implements DrawTrait, TimeTrait{ public static final float lifetime = 10f; private static final RandomXS128 random = new RandomXS128(); - private static final Rectangle rect = new Rectangle(); + private static final Rect rect = new Rect(); private static final Array entities = new Array<>(); private static final IntSet hit = new IntSet(); private static final int maxChain = 8; diff --git a/core/src/mindustry/entities/effect/Puddle.java b/core/src/mindustry/entities/effect/Puddle.java index e2d5d2e10c..132c2d1379 100644 --- a/core/src/mindustry/entities/effect/Puddle.java +++ b/core/src/mindustry/entities/effect/Puddle.java @@ -27,8 +27,8 @@ public class Puddle extends SolidEntity implements SaveTrait, Poolable, DrawTrai private static final float maxLiquid = 70f; private static final int maxGeneration = 2; private static final Color tmp = new Color(); - private static final Rectangle rect = new Rectangle(); - private static final Rectangle rect2 = new Rectangle(); + private static final Rect rect = new Rect(); + private static final Rect rect2 = new Rect(); private static int seeds; private int loadedPosition = -1; @@ -151,13 +151,13 @@ public class Puddle extends SolidEntity implements SaveTrait, Poolable, DrawTrai } @Override - public void hitbox(Rectangle rectangle){ - rectangle.setCenter(x, y).setSize(tilesize); + public void hitbox(Rect rect){ + rect.setCenter(x, y).setSize(tilesize); } @Override - public void hitboxTile(Rectangle rectangle){ - rectangle.setCenter(x, y).setSize(0f); + public void hitboxTile(Rect rect){ + rect.setCenter(x, y).setSize(0f); } @Override diff --git a/core/src/mindustry/entities/traits/BuilderTrait.java b/core/src/mindustry/entities/traits/BuilderTrait.java index 2f302be8e6..02ae0bca5b 100644 --- a/core/src/mindustry/entities/traits/BuilderTrait.java +++ b/core/src/mindustry/entities/traits/BuilderTrait.java @@ -343,7 +343,7 @@ public interface BuilderTrait extends Entity, TeamTrait{ return this; } - public Rectangle bounds(Rectangle rect){ + public Rect bounds(Rect rect){ if(breaking){ return rect.set(-100f, -100f, 0f, 0f); }else{ diff --git a/core/src/mindustry/entities/traits/SolidTrait.java b/core/src/mindustry/entities/traits/SolidTrait.java index f799f13cba..afa2efd6b0 100644 --- a/core/src/mindustry/entities/traits/SolidTrait.java +++ b/core/src/mindustry/entities/traits/SolidTrait.java @@ -7,9 +7,9 @@ import mindustry.Vars; public interface SolidTrait extends QuadTreeObject, MoveTrait, VelocityTrait, Entity, Position{ - void hitbox(Rectangle rectangle); + void hitbox(Rect rect); - void hitboxTile(Rectangle rectangle); + void hitboxTile(Rect rect); Vec2 lastPosition(); diff --git a/core/src/mindustry/entities/type/BaseUnit.java b/core/src/mindustry/entities/type/BaseUnit.java index 03b4f2d0de..6062662e9b 100644 --- a/core/src/mindustry/entities/type/BaseUnit.java +++ b/core/src/mindustry/entities/type/BaseUnit.java @@ -352,13 +352,13 @@ public abstract class BaseUnit extends Unit implements ShooterTrait{ } @Override - public void hitbox(Rectangle rectangle){ - rectangle.setSize(type.hitsize).setCenter(x, y); + public void hitbox(Rect rect){ + rect.setSize(type.hitsize).setCenter(x, y); } @Override - public void hitboxTile(Rectangle rectangle){ - rectangle.setSize(type.hitsizeTile).setCenter(x, y); + public void hitboxTile(Rect rect){ + rect.setSize(type.hitsizeTile).setCenter(x, y); } @Override diff --git a/core/src/mindustry/entities/type/Bullet.java b/core/src/mindustry/entities/type/Bullet.java index 6afafb5f29..f7e676ecc9 100644 --- a/core/src/mindustry/entities/type/Bullet.java +++ b/core/src/mindustry/entities/type/Bullet.java @@ -246,13 +246,13 @@ public class Bullet extends SolidEntity implements DamageTrait, ScaleTrait, Pool } @Override - public void hitbox(Rectangle rectangle){ - rectangle.setSize(type.hitSize).setCenter(x, y); + public void hitbox(Rect rect){ + rect.setSize(type.hitSize).setCenter(x, y); } @Override - public void hitboxTile(Rectangle rectangle){ - rectangle.setSize(type.hitSize).setCenter(x, y); + public void hitboxTile(Rect rect){ + rect.setSize(type.hitSize).setCenter(x, y); } @Override diff --git a/core/src/mindustry/entities/type/Player.java b/core/src/mindustry/entities/type/Player.java index a6a74683bb..af5165fc60 100644 --- a/core/src/mindustry/entities/type/Player.java +++ b/core/src/mindustry/entities/type/Player.java @@ -41,7 +41,7 @@ public class Player extends Unit implements BuilderMinerTrait, ShooterTrait{ private static final int timerShootRight = 1; private static final float liftoffBoost = 0.2f; - private static final Rectangle rect = new Rectangle(); + private static final Rect rect = new Rect(); //region instance variables @@ -93,13 +93,13 @@ public class Player extends Unit implements BuilderMinerTrait, ShooterTrait{ } @Override - public void hitbox(Rectangle rectangle){ - rectangle.setSize(mech.hitsize).setCenter(x, y); + public void hitbox(Rect rect){ + rect.setSize(mech.hitsize).setCenter(x, y); } @Override - public void hitboxTile(Rectangle rectangle){ - rectangle.setSize(mech.hitsize * 2f / 3f).setCenter(x, y); + public void hitboxTile(Rect rect){ + rect.setSize(mech.hitsize * 2f / 3f).setCenter(x, y); } @Override diff --git a/core/src/mindustry/game/EventType.java b/core/src/mindustry/game/EventType.java index cf26f06fec..dfa1469fc1 100644 --- a/core/src/mindustry/game/EventType.java +++ b/core/src/mindustry/game/EventType.java @@ -62,10 +62,13 @@ public class EventType{ public static class PlayerChatEvent{ public final Player player; public final String message; + /** The original, unfiltered message. */ + public final String originalMessage; - public PlayerChatEvent(Player player, String message){ + public PlayerChatEvent(Player player, String message, String originalMessage){ this.player = player; this.message = message; + this.originalMessage = originalMessage; } } diff --git a/core/src/mindustry/game/Rules.java b/core/src/mindustry/game/Rules.java index d910952021..93ceaf5cfe 100644 --- a/core/src/mindustry/game/Rules.java +++ b/core/src/mindustry/game/Rules.java @@ -82,6 +82,8 @@ public class Rules{ public Team defaultTeam = Team.sharded; /** team of the enemy in waves/sectors */ public Team waveTeam = Team.crux; + /** special tags for additional info */ + public StringMap tags = new StringMap(); /** Copies this ruleset exactly. Not very efficient at all, do not use often. */ public Rules copy(){ diff --git a/core/src/mindustry/graphics/MinimapRenderer.java b/core/src/mindustry/graphics/MinimapRenderer.java index ffeadc98da..60f3d2974b 100644 --- a/core/src/mindustry/graphics/MinimapRenderer.java +++ b/core/src/mindustry/graphics/MinimapRenderer.java @@ -25,7 +25,7 @@ public class MinimapRenderer implements Disposable{ private Pixmap pixmap; private Texture texture; private TextureRegion region; - private Rectangle rect = new Rectangle(); + private Rect rect = new Rect(); private float zoom = 4; public MinimapRenderer(){ diff --git a/core/src/mindustry/graphics/OverlayRenderer.java b/core/src/mindustry/graphics/OverlayRenderer.java index 3c65c1b9f4..c0cd917952 100644 --- a/core/src/mindustry/graphics/OverlayRenderer.java +++ b/core/src/mindustry/graphics/OverlayRenderer.java @@ -22,7 +22,7 @@ import static mindustry.Vars.*; public class OverlayRenderer{ private static final float indicatorLength = 14f; private static final float spawnerMargin = tilesize*11f; - private static final Rectangle rect = new Rectangle(); + private static final Rect rect = new Rect(); private float buildFadeTime; public void drawBottom(){ diff --git a/core/src/mindustry/input/InputHandler.java b/core/src/mindustry/input/InputHandler.java index b35683c7e2..4a6ffb575b 100644 --- a/core/src/mindustry/input/InputHandler.java +++ b/core/src/mindustry/input/InputHandler.java @@ -44,7 +44,7 @@ public abstract class InputHandler implements InputProcessor, GestureListener{ /** Maximum line length. */ final static int maxLength = 100; final static Vec2 stackTrns = new Vec2(); - final static Rectangle r1 = new Rectangle(), r2 = new Rectangle(); + final static Rect r1 = new Rect(), r2 = new Rect(); /** Distance on the back from where items originate. */ final static float backTrns = 3f; diff --git a/core/src/mindustry/io/JsonIO.java b/core/src/mindustry/io/JsonIO.java index 7c570bace8..ef37dd9d65 100644 --- a/core/src/mindustry/io/JsonIO.java +++ b/core/src/mindustry/io/JsonIO.java @@ -20,7 +20,7 @@ public class JsonIO{ @Override public void writeValue(Object value, Class knownType, Class elementType){ - if(value instanceof mindustry.ctype.MappableContent){ + if(value instanceof MappableContent){ try{ getWriter().value(((MappableContent)value).name); }catch(IOException e){ @@ -95,6 +95,18 @@ public class JsonIO{ } }); + json.setSerializer(Team.class, new Serializer(){ + @Override + public void write(Json json, Team object, Class knownType){ + json.writeValue(object.id); + } + + @Override + public Team read(Json json, JsonValue jsonData, Class type){ + return Team.get(jsonData.asInt()); + } + }); + json.setSerializer(Block.class, new Serializer(){ @Override public void write(Json json, Block object, Class knownType){ diff --git a/core/src/mindustry/net/Administration.java b/core/src/mindustry/net/Administration.java index cd490eed04..dabf679d34 100644 --- a/core/src/mindustry/net/Administration.java +++ b/core/src/mindustry/net/Administration.java @@ -1,10 +1,11 @@ package mindustry.net; import arc.*; -import mindustry.annotations.Annotations.*; import arc.struct.*; -import mindustry.Vars; - +import arc.util.ArcAnnotate.*; +import mindustry.*; +import mindustry.annotations.Annotations.*; +import mindustry.entities.type.*; import static mindustry.Vars.headless; import static mindustry.game.EventType.*; @@ -14,6 +15,7 @@ public class Administration{ private ObjectMap playerInfo = new ObjectMap<>(); private Array bannedIPs = new Array<>(); private Array whitelist = new Array<>(); + private Array chatFilters = new Array<>(); public Administration(){ Core.settings.defaults( @@ -24,6 +26,23 @@ public class Administration{ load(); } + /** Adds a chat filter. This will transform the chat messages of every player. + * This functionality can be used to implement things like swear filters and special commands. + * Note that commands (starting with /) are not filtered.*/ + public void addChatFilter(ChatFilter filter){ + chatFilters.add(filter); + } + + /** Filters out a chat message. */ + public @Nullable String filterMessage(Player player, String message){ + String current = message; + for(ChatFilter f : chatFilters){ + current = f.filter(player, message); + if(current == null) return null; + } + return current; + } + public int getPlayerLimit(){ return Core.settings.getInt("playerlimit", 0); } @@ -334,6 +353,11 @@ public class Administration{ } } + public interface ChatFilter{ + /** @return the filtered message; a null string signals that the message should not be sent. */ + @Nullable String filter(Player player, String message); + } + public static class TraceInfo{ public String ip, uuid; public boolean modded, mobile; diff --git a/core/src/mindustry/ui/Bar.java b/core/src/mindustry/ui/Bar.java index c04a25167f..8c23ec0ad3 100644 --- a/core/src/mindustry/ui/Bar.java +++ b/core/src/mindustry/ui/Bar.java @@ -12,7 +12,7 @@ import arc.util.pooling.*; import mindustry.gen.*; public class Bar extends Element{ - private static Rectangle scissor = new Rectangle(); + private static Rect scissor = new Rect(); private Floatp fraction; private String name = ""; diff --git a/core/src/mindustry/ui/dialogs/DeployDialog.java b/core/src/mindustry/ui/dialogs/DeployDialog.java index dda43d0e13..811caca161 100644 --- a/core/src/mindustry/ui/dialogs/DeployDialog.java +++ b/core/src/mindustry/ui/dialogs/DeployDialog.java @@ -33,7 +33,7 @@ public class DeployDialog extends FloatingDialog{ private final float nodeSize = Scl.scl(230f); private ObjectSet nodes = new ObjectSet<>(); private ZoneInfoDialog info = new ZoneInfoDialog(); - private Rectangle bounds = new Rectangle(); + private Rect bounds = new Rect(); private View view = new View(); public DeployDialog(){ diff --git a/core/src/mindustry/ui/dialogs/TechTreeDialog.java b/core/src/mindustry/ui/dialogs/TechTreeDialog.java index 6bbb249a66..0d28af70c5 100644 --- a/core/src/mindustry/ui/dialogs/TechTreeDialog.java +++ b/core/src/mindustry/ui/dialogs/TechTreeDialog.java @@ -31,7 +31,7 @@ public class TechTreeDialog extends FloatingDialog{ private final float nodeSize = Scl.scl(60f); private ObjectSet nodes = new ObjectSet<>(); private TechTreeNode root = new TechTreeNode(TechTree.root, null); - private Rectangle bounds = new Rectangle(); + private Rect bounds = new Rect(); private ItemsDisplay items; private View view; @@ -123,7 +123,7 @@ public class TechTreeDialog extends FloatingDialog{ miny = Math.min(n.y - n.height/2f, miny); maxy = Math.max(n.y + n.height/2f, maxy); } - bounds = new Rectangle(minx, miny, maxx - minx, maxy - miny); + bounds = new Rect(minx, miny, maxx - minx, maxy - miny); bounds.y += nodeSize*1.5f; } diff --git a/core/src/mindustry/ui/layout/BranchTreeLayout.java b/core/src/mindustry/ui/layout/BranchTreeLayout.java index b012d68e71..07c3fb5497 100644 --- a/core/src/mindustry/ui/layout/BranchTreeLayout.java +++ b/core/src/mindustry/ui/layout/BranchTreeLayout.java @@ -66,8 +66,8 @@ public class BranchTreeLayout implements TreeLayout{ } } - public Rectangle getBounds(){ - return new Rectangle(boundsLeft, boundsBottom, boundsRight - boundsLeft, boundsTop - boundsBottom); + public Rect getBounds(){ + return new Rect(boundsLeft, boundsBottom, boundsRight - boundsLeft, boundsTop - boundsBottom); } private void calcSizeOfLevels(TreeNode node, int level){ diff --git a/core/src/mindustry/world/Block.java b/core/src/mindustry/world/Block.java index 9bd64f023a..9bec4cd0f6 100644 --- a/core/src/mindustry/world/Block.java +++ b/core/src/mindustry/world/Block.java @@ -864,7 +864,7 @@ public class Block extends BlockStorage{ return ((size + 1) % 2) * tilesize / 2f; } - public Rectangle bounds(int x, int y, Rectangle rect){ + public Rect bounds(int x, int y, Rect rect){ return rect.setSize(size * tilesize).setCenter(x * tilesize + offset(), y * tilesize + offset()); } diff --git a/core/src/mindustry/world/Tile.java b/core/src/mindustry/world/Tile.java index c591307176..0572c74286 100644 --- a/core/src/mindustry/world/Tile.java +++ b/core/src/mindustry/world/Tile.java @@ -327,7 +327,7 @@ public class Tile implements Position, TargetTrait{ return tmpArray; } - public Rectangle getHitbox(Rectangle rect){ + public Rect getHitbox(Rect rect){ return rect.setSize(block().size * tilesize).setCenter(drawx(), drawy()); } diff --git a/core/src/mindustry/world/blocks/defense/DeflectorWall.java b/core/src/mindustry/world/blocks/defense/DeflectorWall.java index cf8f54a8ce..ae535ca8a6 100644 --- a/core/src/mindustry/world/blocks/defense/DeflectorWall.java +++ b/core/src/mindustry/world/blocks/defense/DeflectorWall.java @@ -15,8 +15,8 @@ public class DeflectorWall extends Wall{ public static final float hitTime = 10f; protected float maxDamageDeflect = 10f; - protected Rectangle rect = new Rectangle(); - protected Rectangle rect2 = new Rectangle(); + protected Rect rect = new Rect(); + protected Rect rect2 = new Rect(); public DeflectorWall(String name){ super(name); diff --git a/core/src/mindustry/world/blocks/defense/Door.java b/core/src/mindustry/world/blocks/defense/Door.java index 27a0d26bff..df75416207 100644 --- a/core/src/mindustry/world/blocks/defense/Door.java +++ b/core/src/mindustry/world/blocks/defense/Door.java @@ -18,7 +18,7 @@ import java.io.*; import static mindustry.Vars.*; public class Door extends Wall{ - protected final static Rectangle rect = new Rectangle(); + protected final static Rect rect = new Rect(); public final int timerToggle = timers++; public Effect openfx = Fx.dooropen; diff --git a/core/src/mindustry/world/blocks/units/RepairPoint.java b/core/src/mindustry/world/blocks/units/RepairPoint.java index 183404148d..a17fffe1b1 100644 --- a/core/src/mindustry/world/blocks/units/RepairPoint.java +++ b/core/src/mindustry/world/blocks/units/RepairPoint.java @@ -6,7 +6,7 @@ import arc.graphics.Color; import arc.graphics.g2d.*; import arc.math.Angles; import arc.math.Mathf; -import arc.math.geom.Rectangle; +import arc.math.geom.Rect; import arc.util.Time; import mindustry.entities.Units; import mindustry.entities.type.TileEntity; @@ -19,7 +19,7 @@ import mindustry.world.meta.*; import static mindustry.Vars.tilesize; public class RepairPoint extends Block{ - private static Rectangle rect = new Rectangle(); + private static Rect rect = new Rect(); public int timerTarget = timers++; diff --git a/gradle.properties b/gradle.properties index f8748c523a..19101944cf 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,3 +1,3 @@ org.gradle.daemon=true org.gradle.jvmargs=-Xms256m -Xmx1024m -archash=29782072a3c824715118f51ebe23c189ba0d9597 +archash=60a9ebe264f92f2c3082596c77b9ab29474c4a7f diff --git a/tests/src/test/java/IOTests.java b/tests/src/test/java/IOTests.java index 240334f6dd..79f7a213cf 100644 --- a/tests/src/test/java/IOTests.java +++ b/tests/src/test/java/IOTests.java @@ -1,11 +1,11 @@ +import arc.util.*; import mindustry.game.*; -import mindustry.io.TypeIO; -import org.junit.jupiter.api.Test; +import mindustry.io.*; +import org.junit.jupiter.api.*; -import java.nio.ByteBuffer; +import java.nio.*; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.*; public class IOTests{ @@ -49,5 +49,23 @@ public class IOTests{ assertEquals(rules.attackMode, res.attackMode); } + @Test + void writeRules2(){ + Rules rules = new Rules(); + rules.attackMode = true; + rules.tags.put("blah", "bleh"); + rules.buildSpeedMultiplier = 99.1f; + String str = JsonIO.write(rules); + Rules res = JsonIO.read(Rules.class, str); + + assertEquals(rules.buildSpeedMultiplier, res.buildSpeedMultiplier); + assertEquals(rules.attackMode, res.attackMode); + assertEquals(rules.tags.get("blah"), res.tags.get("blah")); + + String str2 = JsonIO.write(new Rules(){{ + attackMode = true; + }}); + Log.info(str2); + } } From 98f8a1732e1185e24ad6b0999186aff3b5d378e0 Mon Sep 17 00:00:00 2001 From: Anuken Date: Thu, 26 Dec 2019 23:00:26 -0500 Subject: [PATCH 15/78] Renamed Calls -> Call --- core/assets/scripts/base.js | 3 ++- core/assets/scripts/global.js | 3 ++- core/src/mindustry/game/Team.java | 5 ++++- core/src/mindustry/mod/ClassAccess.java | 2 +- 4 files changed, 9 insertions(+), 4 deletions(-) diff --git a/core/assets/scripts/base.js b/core/assets/scripts/base.js index 9b3fb5dcb4..a83a66c728 100755 --- a/core/assets/scripts/base.js +++ b/core/assets/scripts/base.js @@ -16,4 +16,5 @@ const boolp = method => new Boolp(){get: method} const cons = method => new Cons(){get: method} const prov = method => new Prov(){get: method} const newEffect = (lifetime, renderer) => new Effects.Effect(lifetime, new Effects.EffectRenderer({render: renderer})) -const Calls = Packages.io.anuke.mindustry.gen.Call \ No newline at end of file +Call = Packages.io.anuke.mindustry.gen.Call +const Calls = Call //backwards compat \ No newline at end of file diff --git a/core/assets/scripts/global.js b/core/assets/scripts/global.js index badba9d273..862ded3759 100755 --- a/core/assets/scripts/global.js +++ b/core/assets/scripts/global.js @@ -18,7 +18,8 @@ const boolp = method => new Boolp(){get: method} const cons = method => new Cons(){get: method} const prov = method => new Prov(){get: method} const newEffect = (lifetime, renderer) => new Effects.Effect(lifetime, new Effects.EffectRenderer({render: renderer})) -const Calls = Packages.io.anuke.mindustry.gen.Call +Call = Packages.io.anuke.mindustry.gen.Call +const Calls = Call //backwards compat importPackage(Packages.arc) importPackage(Packages.arc.func) importPackage(Packages.arc.graphics) diff --git a/core/src/mindustry/game/Team.java b/core/src/mindustry/game/Team.java index f5b02e4d9a..a6e9d1e20a 100644 --- a/core/src/mindustry/game/Team.java +++ b/core/src/mindustry/game/Team.java @@ -2,6 +2,7 @@ package mindustry.game; import arc.*; import arc.graphics.*; +import arc.math.*; import arc.struct.*; import arc.util.*; import mindustry.game.Teams.*; @@ -29,10 +30,12 @@ public class Team implements Comparable{ blue = new Team(5, "blue", Color.royal.cpy()); static{ + Mathf.random.setSeed(7); //create the whole 256 placeholder teams for(int i = 6; i < all.length; i++){ - new Team(i, "team#" + i, Color.HSVtoRGB(360f * (float)(i) / all.length * 10, 100f * 0.8f, 100f * 0.8f, 1f)); + new Team(i, "team#" + i, Color.HSVtoRGB(360f * Mathf.random(), 100f * Mathf.random(0.6f, 1f), 100f * Mathf.random(0.8f, 1f), 1f)); } + Mathf.random.setSeed(new RandomXS128().nextLong()); } public static Team get(int id){ diff --git a/core/src/mindustry/mod/ClassAccess.java b/core/src/mindustry/mod/ClassAccess.java index 62f089a107..06ff74766c 100644 --- a/core/src/mindustry/mod/ClassAccess.java +++ b/core/src/mindustry/mod/ClassAccess.java @@ -3,5 +3,5 @@ package mindustry.mod; import arc.struct.*; //obviously autogenerated, do not touch public class ClassAccess{ - public static final ObjectSet allowedClassNames = ObjectSet.with("arc.Core", "arc.func.Boolc", "arc.func.Boolf", "arc.func.Boolf2", "arc.func.Boolp", "arc.func.Cons", "arc.func.Cons2", "arc.func.Floatc", "arc.func.Floatc2", "arc.func.Floatc4", "arc.func.Floatf", "arc.func.Floatp", "arc.func.Func", "arc.func.Func2", "arc.func.Func3", "arc.func.Intc", "arc.func.Intc2", "arc.func.Intc4", "arc.func.Intf", "arc.func.Intp", "arc.func.Prov", "arc.graphics.Color", "arc.graphics.Pixmap", "arc.graphics.Texture", "arc.graphics.TextureData", "arc.graphics.g2d.Draw", "arc.graphics.g2d.Fill", "arc.graphics.g2d.Lines", "arc.graphics.g2d.TextureAtlas", "arc.graphics.g2d.TextureAtlas$AtlasRegion", "arc.graphics.g2d.TextureRegion", "arc.math.Angles", "arc.math.Mathf", "arc.scene.Action", "arc.scene.Element", "arc.scene.Group", "arc.scene.Scene", "arc.scene.actions.Actions", "arc.scene.actions.AddAction", "arc.scene.actions.AddListenerAction", "arc.scene.actions.AfterAction", "arc.scene.actions.AlphaAction", "arc.scene.actions.ColorAction", "arc.scene.actions.DelayAction", "arc.scene.actions.DelegateAction", "arc.scene.actions.FloatAction", "arc.scene.actions.IntAction", "arc.scene.actions.LayoutAction", "arc.scene.actions.MoveByAction", "arc.scene.actions.MoveToAction", "arc.scene.actions.OriginAction", "arc.scene.actions.ParallelAction", "arc.scene.actions.RelativeTemporalAction", "arc.scene.actions.RemoveAction", "arc.scene.actions.RemoveActorAction", "arc.scene.actions.RemoveListenerAction", "arc.scene.actions.RepeatAction", "arc.scene.actions.RotateByAction", "arc.scene.actions.RotateToAction", "arc.scene.actions.RunnableAction", "arc.scene.actions.ScaleByAction", "arc.scene.actions.ScaleToAction", "arc.scene.actions.SequenceAction", "arc.scene.actions.SizeByAction", "arc.scene.actions.SizeToAction", "arc.scene.actions.TemporalAction", "arc.scene.actions.TimeScaleAction", "arc.scene.actions.TouchableAction", "arc.scene.actions.TranslateByAction", "arc.scene.actions.VisibleAction", "arc.scene.event.ChangeListener", "arc.scene.event.ChangeListener$ChangeEvent", "arc.scene.event.ClickListener", "arc.scene.event.DragListener", "arc.scene.event.DragScrollListener", "arc.scene.event.ElementGestureListener", "arc.scene.event.EventListener", "arc.scene.event.FocusListener", "arc.scene.event.FocusListener$FocusEvent", "arc.scene.event.FocusListener$FocusEvent$Type", "arc.scene.event.HandCursorListener", "arc.scene.event.IbeamCursorListener", "arc.scene.event.InputEvent", "arc.scene.event.InputEvent$Type", "arc.scene.event.InputListener", "arc.scene.event.SceneEvent", "arc.scene.event.Touchable", "arc.scene.event.VisibilityEvent", "arc.scene.event.VisibilityListener", "arc.scene.style.BaseDrawable", "arc.scene.style.Drawable", "arc.scene.style.NinePatchDrawable", "arc.scene.style.ScaledNinePatchDrawable", "arc.scene.style.Style", "arc.scene.style.TextureRegionDrawable", "arc.scene.style.TiledDrawable", "arc.scene.style.TransformDrawable", "arc.scene.ui.Button", "arc.scene.ui.Button$ButtonStyle", "arc.scene.ui.ButtonGroup", "arc.scene.ui.CheckBox", "arc.scene.ui.CheckBox$CheckBoxStyle", "arc.scene.ui.ColorImage", "arc.scene.ui.Dialog", "arc.scene.ui.Dialog$DialogStyle", "arc.scene.ui.Image", "arc.scene.ui.ImageButton", "arc.scene.ui.ImageButton$ImageButtonStyle", "arc.scene.ui.KeybindDialog", "arc.scene.ui.KeybindDialog$KeybindDialogStyle", "arc.scene.ui.Label", "arc.scene.ui.Label$LabelStyle", "arc.scene.ui.ProgressBar", "arc.scene.ui.ProgressBar$ProgressBarStyle", "arc.scene.ui.ScrollPane", "arc.scene.ui.ScrollPane$ScrollPaneStyle", "arc.scene.ui.SettingsDialog", "arc.scene.ui.SettingsDialog$SettingsTable", "arc.scene.ui.SettingsDialog$SettingsTable$CheckSetting", "arc.scene.ui.SettingsDialog$SettingsTable$Setting", "arc.scene.ui.SettingsDialog$SettingsTable$SliderSetting", "arc.scene.ui.SettingsDialog$StringProcessor", "arc.scene.ui.Slider", "arc.scene.ui.Slider$SliderStyle", "arc.scene.ui.TextArea", "arc.scene.ui.TextArea$TextAreaListener", "arc.scene.ui.TextButton", "arc.scene.ui.TextButton$TextButtonStyle", "arc.scene.ui.TextField", "arc.scene.ui.TextField$DefaultOnscreenKeyboard", "arc.scene.ui.TextField$OnscreenKeyboard", "arc.scene.ui.TextField$TextFieldClickListener", "arc.scene.ui.TextField$TextFieldFilter", "arc.scene.ui.TextField$TextFieldListener", "arc.scene.ui.TextField$TextFieldStyle", "arc.scene.ui.TextField$TextFieldValidator", "arc.scene.ui.Tooltip", "arc.scene.ui.Tooltip$Tooltips", "arc.scene.ui.Touchpad", "arc.scene.ui.Touchpad$TouchpadStyle", "arc.scene.ui.TreeElement", "arc.scene.ui.TreeElement$Node", "arc.scene.ui.TreeElement$TreeStyle", "arc.scene.ui.layout.Cell", "arc.scene.ui.layout.Collapser", "arc.scene.ui.layout.HorizontalGroup", "arc.scene.ui.layout.Scl", "arc.scene.ui.layout.Stack", "arc.scene.ui.layout.Table", "arc.scene.ui.layout.Table$DrawRect", "arc.scene.ui.layout.VerticalGroup", "arc.scene.ui.layout.WidgetGroup", "arc.scene.utils.ArraySelection", "arc.scene.utils.Cullable", "arc.scene.utils.Disableable", "arc.scene.utils.DragAndDrop", "arc.scene.utils.DragAndDrop$Payload", "arc.scene.utils.DragAndDrop$Source", "arc.scene.utils.DragAndDrop$Target", "arc.scene.utils.Elements", "arc.scene.utils.Layout", "arc.scene.utils.Selection", "arc.struct.Array", "arc.struct.Array$ArrayIterable", "arc.struct.ArrayMap", "arc.struct.ArrayMap$Entries", "arc.struct.ArrayMap$Keys", "arc.struct.ArrayMap$Values", "arc.struct.AtomicQueue", "arc.struct.BinaryHeap", "arc.struct.BinaryHeap$Node", "arc.struct.Bits", "arc.struct.BooleanArray", "arc.struct.ByteArray", "arc.struct.CharArray", "arc.struct.ComparableTimSort", "arc.struct.DelayedRemovalArray", "arc.struct.EnumSet", "arc.struct.EnumSet$EnumSetIterator", "arc.struct.FloatArray", "arc.struct.GridBits", "arc.struct.GridMap", "arc.struct.IdentityMap", "arc.struct.IdentityMap$Entries", "arc.struct.IdentityMap$Entry", "arc.struct.IdentityMap$Keys", "arc.struct.IdentityMap$Values", "arc.struct.IntArray", "arc.struct.IntFloatMap", "arc.struct.IntFloatMap$Entries", "arc.struct.IntFloatMap$Entry", "arc.struct.IntFloatMap$Keys", "arc.struct.IntFloatMap$Values", "arc.struct.IntIntMap", "arc.struct.IntIntMap$Entries", "arc.struct.IntIntMap$Entry", "arc.struct.IntIntMap$Keys", "arc.struct.IntIntMap$Values", "arc.struct.IntMap", "arc.struct.IntMap$Entries", "arc.struct.IntMap$Entry", "arc.struct.IntMap$Keys", "arc.struct.IntMap$Values", "arc.struct.IntQueue", "arc.struct.IntSet", "arc.struct.IntSet$IntSetIterator", "arc.struct.LongArray", "arc.struct.LongMap", "arc.struct.LongMap$Entries", "arc.struct.LongMap$Entry", "arc.struct.LongMap$Keys", "arc.struct.LongMap$Values", "arc.struct.LongQueue", "arc.struct.ObjectFloatMap", "arc.struct.ObjectFloatMap$Entries", "arc.struct.ObjectFloatMap$Entry", "arc.struct.ObjectFloatMap$Keys", "arc.struct.ObjectFloatMap$Values", "arc.struct.ObjectIntMap", "arc.struct.ObjectIntMap$Entries", "arc.struct.ObjectIntMap$Entry", "arc.struct.ObjectIntMap$Keys", "arc.struct.ObjectIntMap$Values", "arc.struct.ObjectMap", "arc.struct.ObjectMap$Entries", "arc.struct.ObjectMap$Entry", "arc.struct.ObjectMap$Keys", "arc.struct.ObjectMap$Values", "arc.struct.ObjectSet", "arc.struct.ObjectSet$ObjectSetIterator", "arc.struct.OrderedMap", "arc.struct.OrderedMap$OrderedMapEntries", "arc.struct.OrderedMap$OrderedMapKeys", "arc.struct.OrderedMap$OrderedMapValues", "arc.struct.OrderedSet", "arc.struct.OrderedSet$OrderedSetIterator", "arc.struct.PooledLinkedList", "arc.struct.PooledLinkedList$Item", "arc.struct.Queue", "arc.struct.Queue$QueueIterable", "arc.struct.ShortArray", "arc.struct.SnapshotArray", "arc.struct.Sort", "arc.struct.SortedIntList", "arc.struct.SortedIntList$Iterator", "arc.struct.SortedIntList$Node", "arc.struct.StringMap", "arc.struct.TimSort", "arc.util.I18NBundle", "arc.util.Time", "java.io.PrintStream", "java.lang.Object", "java.lang.Runnable", "java.lang.String", "java.lang.System", "mindustry.Vars", "mindustry.ai.BlockIndexer", "mindustry.ai.Pathfinder", "mindustry.ai.Pathfinder$PathData", "mindustry.ai.Pathfinder$PathTarget", "mindustry.ai.Pathfinder$PathTileStruct", "mindustry.ai.WaveSpawner", "mindustry.content.Blocks", "mindustry.content.Bullets", "mindustry.content.Fx", "mindustry.content.Items", "mindustry.content.Liquids", "mindustry.content.Loadouts", "mindustry.content.Mechs", "mindustry.content.StatusEffects", "mindustry.content.TechTree", "mindustry.content.TechTree$TechNode", "mindustry.content.TypeIDs", "mindustry.content.UnitTypes", "mindustry.content.Zones", "mindustry.core.ContentLoader", "mindustry.core.Control", "mindustry.core.FileTree", "mindustry.core.GameState", "mindustry.core.GameState$State", "mindustry.core.Logic", "mindustry.core.Platform", "mindustry.core.Renderer", "mindustry.core.UI", "mindustry.core.Version", "mindustry.core.World", "mindustry.core.World$Raycaster", "mindustry.ctype.Content", "mindustry.ctype.Content$ModContentInfo", "mindustry.ctype.ContentList", "mindustry.ctype.ContentType", "mindustry.ctype.MappableContent", "mindustry.ctype.UnlockableContent", "mindustry.editor.DrawOperation", "mindustry.editor.DrawOperation$OpType", "mindustry.editor.DrawOperation$TileOpStruct", "mindustry.editor.EditorTile", "mindustry.editor.EditorTool", "mindustry.editor.MapEditor", "mindustry.editor.MapEditor$Context", "mindustry.editor.MapEditorDialog", "mindustry.editor.MapGenerateDialog", "mindustry.editor.MapInfoDialog", "mindustry.editor.MapLoadDialog", "mindustry.editor.MapRenderer", "mindustry.editor.MapResizeDialog", "mindustry.editor.MapSaveDialog", "mindustry.editor.MapView", "mindustry.editor.OperationStack", "mindustry.editor.WaveInfoDialog", "mindustry.entities.Damage", "mindustry.entities.Damage$PropCellStruct", "mindustry.entities.Effects", "mindustry.entities.Effects$Effect", "mindustry.entities.Effects$EffectContainer", "mindustry.entities.Effects$EffectProvider", "mindustry.entities.Effects$EffectRenderer", "mindustry.entities.Effects$ScreenshakeProvider", "mindustry.entities.Entities", "mindustry.entities.EntityCollisions", "mindustry.entities.EntityGroup", "mindustry.entities.Predict", "mindustry.entities.TargetPriority", "mindustry.entities.Units", "mindustry.entities.bullet.ArtilleryBulletType", "mindustry.entities.bullet.BasicBulletType", "mindustry.entities.bullet.BombBulletType", "mindustry.entities.bullet.BulletType", "mindustry.entities.bullet.FlakBulletType", "mindustry.entities.bullet.HealBulletType", "mindustry.entities.bullet.LiquidBulletType", "mindustry.entities.bullet.MassDriverBolt", "mindustry.entities.bullet.MissileBulletType", "mindustry.entities.effect.Decal", "mindustry.entities.effect.Fire", "mindustry.entities.effect.GroundEffectEntity", "mindustry.entities.effect.GroundEffectEntity$GroundEffect", "mindustry.entities.effect.ItemTransfer", "mindustry.entities.effect.Lightning", "mindustry.entities.effect.Puddle", "mindustry.entities.effect.RubbleDecal", "mindustry.entities.effect.ScorchDecal", "mindustry.entities.traits.AbsorbTrait", "mindustry.entities.traits.BelowLiquidTrait", "mindustry.entities.traits.BuilderMinerTrait", "mindustry.entities.traits.BuilderTrait", "mindustry.entities.traits.BuilderTrait$BuildDataStatic", "mindustry.entities.traits.BuilderTrait$BuildRequest", "mindustry.entities.traits.DamageTrait", "mindustry.entities.traits.DrawTrait", "mindustry.entities.traits.Entity", "mindustry.entities.traits.HealthTrait", "mindustry.entities.traits.KillerTrait", "mindustry.entities.traits.MinerTrait", "mindustry.entities.traits.MoveTrait", "mindustry.entities.traits.SaveTrait", "mindustry.entities.traits.Saveable", "mindustry.entities.traits.ScaleTrait", "mindustry.entities.traits.ShooterTrait", "mindustry.entities.traits.SolidTrait", "mindustry.entities.traits.SpawnerTrait", "mindustry.entities.traits.SyncTrait", "mindustry.entities.traits.TargetTrait", "mindustry.entities.traits.TeamTrait", "mindustry.entities.traits.TimeTrait", "mindustry.entities.traits.TypeTrait", "mindustry.entities.traits.VelocityTrait", "mindustry.entities.type.BaseEntity", "mindustry.entities.type.BaseUnit", "mindustry.entities.type.Bullet", "mindustry.entities.type.DestructibleEntity", "mindustry.entities.type.EffectEntity", "mindustry.entities.type.Player", "mindustry.entities.type.SolidEntity", "mindustry.entities.type.TileEntity", "mindustry.entities.type.TimedEntity", "mindustry.entities.type.Unit", "mindustry.entities.type.base.BaseDrone", "mindustry.entities.type.base.BuilderDrone", "mindustry.entities.type.base.FlyingUnit", "mindustry.entities.type.base.GroundUnit", "mindustry.entities.type.base.HoverUnit", "mindustry.entities.type.base.MinerDrone", "mindustry.entities.type.base.RepairDrone", "mindustry.entities.units.StateMachine", "mindustry.entities.units.Statuses", "mindustry.entities.units.Statuses$StatusEntry", "mindustry.entities.units.UnitCommand", "mindustry.entities.units.UnitDrops", "mindustry.entities.units.UnitState", "mindustry.game.DefaultWaves", "mindustry.game.Difficulty", "mindustry.game.EventType", "mindustry.game.EventType$BlockBuildBeginEvent", "mindustry.game.EventType$BlockBuildEndEvent", "mindustry.game.EventType$BlockDestroyEvent", "mindustry.game.EventType$BlockInfoEvent", "mindustry.game.EventType$BuildSelectEvent", "mindustry.game.EventType$ClientLoadEvent", "mindustry.game.EventType$CommandIssueEvent", "mindustry.game.EventType$ContentReloadEvent", "mindustry.game.EventType$CoreItemDeliverEvent", "mindustry.game.EventType$DepositEvent", "mindustry.game.EventType$DisposeEvent", "mindustry.game.EventType$GameOverEvent", "mindustry.game.EventType$LaunchEvent", "mindustry.game.EventType$LaunchItemEvent", "mindustry.game.EventType$LineConfirmEvent", "mindustry.game.EventType$LoseEvent", "mindustry.game.EventType$MapMakeEvent", "mindustry.game.EventType$MapPublishEvent", "mindustry.game.EventType$MechChangeEvent", "mindustry.game.EventType$PlayEvent", "mindustry.game.EventType$PlayerBanEvent", "mindustry.game.EventType$PlayerChatEvent", "mindustry.game.EventType$PlayerConnect", "mindustry.game.EventType$PlayerIpBanEvent", "mindustry.game.EventType$PlayerIpUnbanEvent", "mindustry.game.EventType$PlayerJoin", "mindustry.game.EventType$PlayerLeave", "mindustry.game.EventType$PlayerUnbanEvent", "mindustry.game.EventType$ResearchEvent", "mindustry.game.EventType$ResetEvent", "mindustry.game.EventType$ResizeEvent", "mindustry.game.EventType$ServerLoadEvent", "mindustry.game.EventType$StateChangeEvent", "mindustry.game.EventType$TapConfigEvent", "mindustry.game.EventType$TapEvent", "mindustry.game.EventType$TileChangeEvent", "mindustry.game.EventType$Trigger", "mindustry.game.EventType$TurretAmmoDeliverEvent", "mindustry.game.EventType$UnitCreateEvent", "mindustry.game.EventType$UnitDestroyEvent", "mindustry.game.EventType$UnlockEvent", "mindustry.game.EventType$WaveEvent", "mindustry.game.EventType$WinEvent", "mindustry.game.EventType$WithdrawEvent", "mindustry.game.EventType$WorldLoadEvent", "mindustry.game.EventType$ZoneConfigureCompleteEvent", "mindustry.game.EventType$ZoneRequireCompleteEvent", "mindustry.game.Gamemode", "mindustry.game.GlobalData", "mindustry.game.LoopControl", "mindustry.game.MusicControl", "mindustry.game.Objective", "mindustry.game.Objectives", "mindustry.game.Objectives$Launched", "mindustry.game.Objectives$Unlock", "mindustry.game.Objectives$Wave", "mindustry.game.Objectives$ZoneObjective", "mindustry.game.Objectives$ZoneWave", "mindustry.game.Rules", "mindustry.game.Saves", "mindustry.game.Saves$SaveSlot", "mindustry.game.Schematic", "mindustry.game.Schematic$Stile", "mindustry.game.Schematics", "mindustry.game.SoundLoop", "mindustry.game.SpawnGroup", "mindustry.game.Stats", "mindustry.game.Stats$Rank", "mindustry.game.Stats$RankResult", "mindustry.game.Team", "mindustry.game.Teams", "mindustry.game.Teams$BrokenBlock", "mindustry.game.Teams$TeamData", "mindustry.game.Tutorial", "mindustry.game.Tutorial$TutorialStage", "mindustry.gen.BufferItem", "mindustry.gen.Call", "mindustry.gen.Call", "mindustry.gen.Icon", "mindustry.gen.Icon", "mindustry.gen.MethodHash", "mindustry.gen.Musics", "mindustry.gen.Musics", "mindustry.gen.PathTile", "mindustry.gen.PropCell", "mindustry.gen.RemoteReadClient", "mindustry.gen.RemoteReadServer", "mindustry.gen.Serialization", "mindustry.gen.Sounds", "mindustry.gen.Sounds", "mindustry.gen.Tex", "mindustry.gen.Tex", "mindustry.gen.TileOp", "mindustry.graphics.BlockRenderer", "mindustry.graphics.Bloom", "mindustry.graphics.CacheLayer", "mindustry.graphics.Drawf", "mindustry.graphics.FloorRenderer", "mindustry.graphics.IndexedRenderer", "mindustry.graphics.Layer", "mindustry.graphics.LightRenderer", "mindustry.graphics.MenuRenderer", "mindustry.graphics.MinimapRenderer", "mindustry.graphics.MultiPacker", "mindustry.graphics.MultiPacker$PageType", "mindustry.graphics.OverlayRenderer", "mindustry.graphics.Pal", "mindustry.graphics.Pixelator", "mindustry.graphics.Shaders", "mindustry.input.Binding", "mindustry.input.DesktopInput", "mindustry.input.InputHandler", "mindustry.input.InputHandler$PlaceLine", "mindustry.input.MobileInput", "mindustry.input.PlaceMode", "mindustry.input.Placement", "mindustry.input.Placement$DistanceHeuristic", "mindustry.input.Placement$NormalizeDrawResult", "mindustry.input.Placement$NormalizeResult", "mindustry.input.Placement$TileHueristic", "mindustry.maps.Map", "mindustry.maps.Maps", "mindustry.maps.Maps$MapProvider", "mindustry.maps.Maps$ShuffleMode", "mindustry.maps.Maps$ShuffleMode", "mindustry.maps.filters.BlendFilter", "mindustry.maps.filters.ClearFilter", "mindustry.maps.filters.DistortFilter", "mindustry.maps.filters.FilterOption", "mindustry.maps.filters.FilterOption$BlockOption", "mindustry.maps.filters.FilterOption$SliderOption", "mindustry.maps.filters.GenerateFilter", "mindustry.maps.filters.GenerateFilter$GenerateInput", "mindustry.maps.filters.GenerateFilter$GenerateInput$TileProvider", "mindustry.maps.filters.MedianFilter", "mindustry.maps.filters.MirrorFilter", "mindustry.maps.filters.NoiseFilter", "mindustry.maps.filters.OreFilter", "mindustry.maps.filters.OreMedianFilter", "mindustry.maps.filters.RiverNoiseFilter", "mindustry.maps.filters.ScatterFilter", "mindustry.maps.filters.TerrainFilter", "mindustry.maps.generators.BasicGenerator", "mindustry.maps.generators.BasicGenerator$DistanceHeuristic", "mindustry.maps.generators.BasicGenerator$TileHueristic", "mindustry.maps.generators.Generator", "mindustry.maps.generators.MapGenerator", "mindustry.maps.generators.MapGenerator$Decoration", "mindustry.maps.generators.RandomGenerator", "mindustry.maps.zonegen.DesertWastesGenerator", "mindustry.maps.zonegen.OvergrowthGenerator", "mindustry.type.Category", "mindustry.type.ErrorContent", "mindustry.type.Item", "mindustry.type.ItemStack", "mindustry.type.ItemType", "mindustry.type.Liquid", "mindustry.type.LiquidStack", "mindustry.type.Mech", "mindustry.type.Publishable", "mindustry.type.StatusEffect", "mindustry.type.StatusEffect$TransitionHandler", "mindustry.type.TypeID", "mindustry.type.UnitType", "mindustry.type.Weapon", "mindustry.type.WeatherEvent", "mindustry.type.Zone", "mindustry.ui.Bar", "mindustry.ui.BorderImage", "mindustry.ui.Cicon", "mindustry.ui.ContentDisplay", "mindustry.ui.Fonts", "mindustry.ui.GridImage", "mindustry.ui.IconSize", "mindustry.ui.IntFormat", "mindustry.ui.ItemDisplay", "mindustry.ui.ItemImage", "mindustry.ui.ItemsDisplay", "mindustry.ui.Links", "mindustry.ui.Links$LinkEntry", "mindustry.ui.LiquidDisplay", "mindustry.ui.Minimap", "mindustry.ui.MobileButton", "mindustry.ui.MultiReqImage", "mindustry.ui.ReqImage", "mindustry.ui.Styles", "mindustry.ui.dialogs.AboutDialog", "mindustry.ui.dialogs.AdminsDialog", "mindustry.ui.dialogs.BansDialog", "mindustry.ui.dialogs.ColorPicker", "mindustry.ui.dialogs.ContentInfoDialog", "mindustry.ui.dialogs.ControlsDialog", "mindustry.ui.dialogs.CustomGameDialog", "mindustry.ui.dialogs.CustomRulesDialog", "mindustry.ui.dialogs.DatabaseDialog", "mindustry.ui.dialogs.DeployDialog", "mindustry.ui.dialogs.DeployDialog$View", "mindustry.ui.dialogs.DeployDialog$ZoneNode", "mindustry.ui.dialogs.DiscordDialog", "mindustry.ui.dialogs.FileChooser", "mindustry.ui.dialogs.FileChooser$FileHistory", "mindustry.ui.dialogs.FloatingDialog", "mindustry.ui.dialogs.GameOverDialog", "mindustry.ui.dialogs.HostDialog", "mindustry.ui.dialogs.JoinDialog", "mindustry.ui.dialogs.JoinDialog$Server", "mindustry.ui.dialogs.LanguageDialog", "mindustry.ui.dialogs.LoadDialog", "mindustry.ui.dialogs.LoadoutDialog", "mindustry.ui.dialogs.MapPlayDialog", "mindustry.ui.dialogs.MapsDialog", "mindustry.ui.dialogs.MinimapDialog", "mindustry.ui.dialogs.ModsDialog", "mindustry.ui.dialogs.PaletteDialog", "mindustry.ui.dialogs.PausedDialog", "mindustry.ui.dialogs.SaveDialog", "mindustry.ui.dialogs.SchematicsDialog", "mindustry.ui.dialogs.SchematicsDialog$SchematicImage", "mindustry.ui.dialogs.SchematicsDialog$SchematicInfoDialog", "mindustry.ui.dialogs.SettingsMenuDialog", "mindustry.ui.dialogs.TechTreeDialog", "mindustry.ui.dialogs.TechTreeDialog$LayoutNode", "mindustry.ui.dialogs.TechTreeDialog$TechTreeNode", "mindustry.ui.dialogs.TechTreeDialog$View", "mindustry.ui.dialogs.TraceDialog", "mindustry.ui.dialogs.ZoneInfoDialog", "mindustry.ui.fragments.BlockConfigFragment", "mindustry.ui.fragments.BlockInventoryFragment", "mindustry.ui.fragments.ChatFragment", "mindustry.ui.fragments.FadeInFragment", "mindustry.ui.fragments.Fragment", "mindustry.ui.fragments.HudFragment", "mindustry.ui.fragments.LoadingFragment", "mindustry.ui.fragments.MenuFragment", "mindustry.ui.fragments.OverlayFragment", "mindustry.ui.fragments.PlacementFragment", "mindustry.ui.fragments.PlayerListFragment", "mindustry.ui.fragments.ScriptConsoleFragment", "mindustry.ui.layout.BranchTreeLayout", "mindustry.ui.layout.BranchTreeLayout$TreeAlignment", "mindustry.ui.layout.BranchTreeLayout$TreeLocation", "mindustry.ui.layout.RadialTreeLayout", "mindustry.ui.layout.TreeLayout", "mindustry.ui.layout.TreeLayout$TreeNode", "mindustry.world.Block", "mindustry.world.BlockStorage", "mindustry.world.Build", "mindustry.world.CachedTile", "mindustry.world.DirectionalItemBuffer", "mindustry.world.DirectionalItemBuffer$BufferItemStruct", "mindustry.world.Edges", "mindustry.world.ItemBuffer", "mindustry.world.LegacyColorMapper", "mindustry.world.LegacyColorMapper$LegacyBlock", "mindustry.world.Pos", "mindustry.world.StaticTree", "mindustry.world.Tile", "mindustry.world.WorldContext", "mindustry.world.blocks.Attributes", "mindustry.world.blocks.Autotiler", "mindustry.world.blocks.Autotiler$AutotilerHolder", "mindustry.world.blocks.BlockPart", "mindustry.world.blocks.BuildBlock", "mindustry.world.blocks.BuildBlock$BuildEntity", "mindustry.world.blocks.DoubleOverlayFloor", "mindustry.world.blocks.Floor", "mindustry.world.blocks.ItemSelection", "mindustry.world.blocks.LiquidBlock", "mindustry.world.blocks.OreBlock", "mindustry.world.blocks.OverlayFloor", "mindustry.world.blocks.PowerBlock", "mindustry.world.blocks.RespawnBlock", "mindustry.world.blocks.Rock", "mindustry.world.blocks.StaticWall", "mindustry.world.blocks.TreeBlock", "mindustry.world.blocks.defense.DeflectorWall", "mindustry.world.blocks.defense.DeflectorWall$DeflectorEntity", "mindustry.world.blocks.defense.Door", "mindustry.world.blocks.defense.Door$DoorEntity", "mindustry.world.blocks.defense.ForceProjector", "mindustry.world.blocks.defense.ForceProjector$ForceEntity", "mindustry.world.blocks.defense.ForceProjector$ShieldEntity", "mindustry.world.blocks.defense.MendProjector", "mindustry.world.blocks.defense.MendProjector$MendEntity", "mindustry.world.blocks.defense.OverdriveProjector", "mindustry.world.blocks.defense.OverdriveProjector$OverdriveEntity", "mindustry.world.blocks.defense.ShockMine", "mindustry.world.blocks.defense.SurgeWall", "mindustry.world.blocks.defense.Wall", "mindustry.world.blocks.defense.turrets.ArtilleryTurret", "mindustry.world.blocks.defense.turrets.BurstTurret", "mindustry.world.blocks.defense.turrets.ChargeTurret", "mindustry.world.blocks.defense.turrets.ChargeTurret$LaserTurretEntity", "mindustry.world.blocks.defense.turrets.CooledTurret", "mindustry.world.blocks.defense.turrets.DoubleTurret", "mindustry.world.blocks.defense.turrets.ItemTurret", "mindustry.world.blocks.defense.turrets.ItemTurret$ItemEntry", "mindustry.world.blocks.defense.turrets.ItemTurret$ItemTurretEntity", "mindustry.world.blocks.defense.turrets.LaserTurret", "mindustry.world.blocks.defense.turrets.LaserTurret$LaserTurretEntity", "mindustry.world.blocks.defense.turrets.LiquidTurret", "mindustry.world.blocks.defense.turrets.PowerTurret", "mindustry.world.blocks.defense.turrets.Turret", "mindustry.world.blocks.defense.turrets.Turret$AmmoEntry", "mindustry.world.blocks.defense.turrets.Turret$TurretEntity", "mindustry.world.blocks.distribution.ArmoredConveyor", "mindustry.world.blocks.distribution.BufferedItemBridge", "mindustry.world.blocks.distribution.BufferedItemBridge$BufferedItemBridgeEntity", "mindustry.world.blocks.distribution.Conveyor", "mindustry.world.blocks.distribution.Conveyor$ConveyorEntity", "mindustry.world.blocks.distribution.Conveyor$ItemPos", "mindustry.world.blocks.distribution.ExtendingItemBridge", "mindustry.world.blocks.distribution.ItemBridge", "mindustry.world.blocks.distribution.ItemBridge$ItemBridgeEntity", "mindustry.world.blocks.distribution.Junction", "mindustry.world.blocks.distribution.Junction$JunctionEntity", "mindustry.world.blocks.distribution.MassDriver", "mindustry.world.blocks.distribution.MassDriver$DriverBulletData", "mindustry.world.blocks.distribution.MassDriver$DriverState", "mindustry.world.blocks.distribution.MassDriver$MassDriverEntity", "mindustry.world.blocks.distribution.OverflowGate", "mindustry.world.blocks.distribution.OverflowGate$OverflowGateEntity", "mindustry.world.blocks.distribution.Router", "mindustry.world.blocks.distribution.Router$RouterEntity", "mindustry.world.blocks.distribution.Sorter", "mindustry.world.blocks.distribution.Sorter$SorterEntity", "mindustry.world.blocks.liquid.ArmoredConduit", "mindustry.world.blocks.liquid.Conduit", "mindustry.world.blocks.liquid.Conduit$ConduitEntity", "mindustry.world.blocks.liquid.LiquidBridge", "mindustry.world.blocks.liquid.LiquidExtendingBridge", "mindustry.world.blocks.liquid.LiquidJunction", "mindustry.world.blocks.liquid.LiquidOverflowGate", "mindustry.world.blocks.liquid.LiquidRouter", "mindustry.world.blocks.liquid.LiquidTank", "mindustry.world.blocks.logic.LogicBlock", "mindustry.world.blocks.logic.MessageBlock", "mindustry.world.blocks.logic.MessageBlock$MessageBlockEntity", "mindustry.world.blocks.power.Battery", "mindustry.world.blocks.power.BurnerGenerator", "mindustry.world.blocks.power.ConditionalConsumePower", "mindustry.world.blocks.power.DecayGenerator", "mindustry.world.blocks.power.ImpactReactor", "mindustry.world.blocks.power.ImpactReactor$FusionReactorEntity", "mindustry.world.blocks.power.ItemLiquidGenerator", "mindustry.world.blocks.power.ItemLiquidGenerator$ItemLiquidGeneratorEntity", "mindustry.world.blocks.power.LightBlock", "mindustry.world.blocks.power.LightBlock$LightEntity", "mindustry.world.blocks.power.NuclearReactor", "mindustry.world.blocks.power.NuclearReactor$NuclearReactorEntity", "mindustry.world.blocks.power.PowerDiode", "mindustry.world.blocks.power.PowerDistributor", "mindustry.world.blocks.power.PowerGenerator", "mindustry.world.blocks.power.PowerGenerator$GeneratorEntity", "mindustry.world.blocks.power.PowerGraph", "mindustry.world.blocks.power.PowerNode", "mindustry.world.blocks.power.SingleTypeGenerator", "mindustry.world.blocks.power.SolarGenerator", "mindustry.world.blocks.power.ThermalGenerator", "mindustry.world.blocks.production.Cultivator", "mindustry.world.blocks.production.Cultivator$CultivatorEntity", "mindustry.world.blocks.production.Drill", "mindustry.world.blocks.production.Drill$DrillEntity", "mindustry.world.blocks.production.Fracker", "mindustry.world.blocks.production.Fracker$FrackerEntity", "mindustry.world.blocks.production.GenericCrafter", "mindustry.world.blocks.production.GenericCrafter$GenericCrafterEntity", "mindustry.world.blocks.production.GenericSmelter", "mindustry.world.blocks.production.Incinerator", "mindustry.world.blocks.production.Incinerator$IncineratorEntity", "mindustry.world.blocks.production.LiquidConverter", "mindustry.world.blocks.production.Pump", "mindustry.world.blocks.production.Separator", "mindustry.world.blocks.production.SolidPump", "mindustry.world.blocks.production.SolidPump$SolidPumpEntity", "mindustry.world.blocks.sandbox.ItemSource", "mindustry.world.blocks.sandbox.ItemSource$ItemSourceEntity", "mindustry.world.blocks.sandbox.ItemVoid", "mindustry.world.blocks.sandbox.LiquidSource", "mindustry.world.blocks.sandbox.LiquidSource$LiquidSourceEntity", "mindustry.world.blocks.sandbox.PowerSource", "mindustry.world.blocks.sandbox.PowerVoid", "mindustry.world.blocks.storage.CoreBlock", "mindustry.world.blocks.storage.CoreBlock$CoreEntity", "mindustry.world.blocks.storage.LaunchPad", "mindustry.world.blocks.storage.StorageBlock", "mindustry.world.blocks.storage.StorageBlock$StorageBlockEntity", "mindustry.world.blocks.storage.Unloader", "mindustry.world.blocks.storage.Unloader$UnloaderEntity", "mindustry.world.blocks.storage.Vault", "mindustry.world.blocks.units.CommandCenter", "mindustry.world.blocks.units.CommandCenter$CommandCenterEntity", "mindustry.world.blocks.units.MechPad", "mindustry.world.blocks.units.MechPad$MechFactoryEntity", "mindustry.world.blocks.units.RallyPoint", "mindustry.world.blocks.units.RepairPoint", "mindustry.world.blocks.units.RepairPoint$RepairPointEntity", "mindustry.world.blocks.units.UnitFactory", "mindustry.world.blocks.units.UnitFactory$UnitFactoryEntity", "mindustry.world.consumers.Consume", "mindustry.world.consumers.ConsumeItemFilter", "mindustry.world.consumers.ConsumeItems", "mindustry.world.consumers.ConsumeLiquid", "mindustry.world.consumers.ConsumeLiquidBase", "mindustry.world.consumers.ConsumeLiquidFilter", "mindustry.world.consumers.ConsumePower", "mindustry.world.consumers.ConsumeType", "mindustry.world.consumers.Consumers", "mindustry.world.meta.Attribute", "mindustry.world.meta.BlockBars", "mindustry.world.meta.BlockFlag", "mindustry.world.meta.BlockGroup", "mindustry.world.meta.BlockStat", "mindustry.world.meta.BlockStats", "mindustry.world.meta.BuildVisibility", "mindustry.world.meta.PowerType", "mindustry.world.meta.Producers", "mindustry.world.meta.StatCategory", "mindustry.world.meta.StatUnit", "mindustry.world.meta.StatValue", "mindustry.world.meta.values.AmmoListValue", "mindustry.world.meta.values.BooleanValue", "mindustry.world.meta.values.BoosterListValue", "mindustry.world.meta.values.ItemFilterValue", "mindustry.world.meta.values.ItemListValue", "mindustry.world.meta.values.LiquidFilterValue", "mindustry.world.meta.values.LiquidValue", "mindustry.world.meta.values.NumberValue", "mindustry.world.meta.values.StringValue", "mindustry.world.modules.BlockModule", "mindustry.world.modules.ConsumeModule", "mindustry.world.modules.ItemModule", "mindustry.world.modules.ItemModule$ItemCalculator", "mindustry.world.modules.ItemModule$ItemConsumer", "mindustry.world.modules.LiquidModule", "mindustry.world.modules.LiquidModule$LiquidCalculator", "mindustry.world.modules.LiquidModule$LiquidConsumer", "mindustry.world.modules.PowerModule", "mindustry.world.producers.Produce", "mindustry.world.producers.ProduceItem"); + public static final ObjectSet allowedClassNames = ObjectSet.with("arc.Core", "arc.func.Boolc", "arc.func.Boolf", "arc.func.Boolf2", "arc.func.Boolp", "arc.func.Cons", "arc.func.Cons2", "arc.func.Floatc", "arc.func.Floatc2", "arc.func.Floatc4", "arc.func.Floatf", "arc.func.Floatp", "arc.func.Func", "arc.func.Func2", "arc.func.Func3", "arc.func.Intc", "arc.func.Intc2", "arc.func.Intc4", "arc.func.Intf", "arc.func.Intp", "arc.func.Prov", "arc.graphics.Color", "arc.graphics.Pixmap", "arc.graphics.Texture", "arc.graphics.TextureData", "arc.graphics.g2d.Draw", "arc.graphics.g2d.Fill", "arc.graphics.g2d.Lines", "arc.graphics.g2d.TextureAtlas", "arc.graphics.g2d.TextureAtlas$AtlasRegion", "arc.graphics.g2d.TextureRegion", "arc.math.Angles", "arc.math.Mathf", "arc.scene.Action", "arc.scene.Element", "arc.scene.Group", "arc.scene.Scene", "arc.scene.actions.Actions", "arc.scene.actions.AddAction", "arc.scene.actions.AddListenerAction", "arc.scene.actions.AfterAction", "arc.scene.actions.AlphaAction", "arc.scene.actions.ColorAction", "arc.scene.actions.DelayAction", "arc.scene.actions.DelegateAction", "arc.scene.actions.FloatAction", "arc.scene.actions.IntAction", "arc.scene.actions.LayoutAction", "arc.scene.actions.MoveByAction", "arc.scene.actions.MoveToAction", "arc.scene.actions.OriginAction", "arc.scene.actions.ParallelAction", "arc.scene.actions.RelativeTemporalAction", "arc.scene.actions.RemoveAction", "arc.scene.actions.RemoveActorAction", "arc.scene.actions.RemoveListenerAction", "arc.scene.actions.RepeatAction", "arc.scene.actions.RotateByAction", "arc.scene.actions.RotateToAction", "arc.scene.actions.RunnableAction", "arc.scene.actions.ScaleByAction", "arc.scene.actions.ScaleToAction", "arc.scene.actions.SequenceAction", "arc.scene.actions.SizeByAction", "arc.scene.actions.SizeToAction", "arc.scene.actions.TemporalAction", "arc.scene.actions.TimeScaleAction", "arc.scene.actions.TouchableAction", "arc.scene.actions.TranslateByAction", "arc.scene.actions.VisibleAction", "arc.scene.event.ChangeListener", "arc.scene.event.ChangeListener$ChangeEvent", "arc.scene.event.ClickListener", "arc.scene.event.DragListener", "arc.scene.event.DragScrollListener", "arc.scene.event.ElementGestureListener", "arc.scene.event.EventListener", "arc.scene.event.FocusListener", "arc.scene.event.FocusListener$FocusEvent", "arc.scene.event.FocusListener$FocusEvent$Type", "arc.scene.event.HandCursorListener", "arc.scene.event.IbeamCursorListener", "arc.scene.event.InputEvent", "arc.scene.event.InputEvent$Type", "arc.scene.event.InputListener", "arc.scene.event.SceneEvent", "arc.scene.event.Touchable", "arc.scene.event.VisibilityEvent", "arc.scene.event.VisibilityListener", "arc.scene.style.BaseDrawable", "arc.scene.style.Drawable", "arc.scene.style.NinePatchDrawable", "arc.scene.style.ScaledNinePatchDrawable", "arc.scene.style.Style", "arc.scene.style.TextureRegionDrawable", "arc.scene.style.TiledDrawable", "arc.scene.style.TransformDrawable", "arc.scene.ui.Button", "arc.scene.ui.Button$ButtonStyle", "arc.scene.ui.ButtonGroup", "arc.scene.ui.CheckBox", "arc.scene.ui.CheckBox$CheckBoxStyle", "arc.scene.ui.ColorImage", "arc.scene.ui.Dialog", "arc.scene.ui.Dialog$DialogStyle", "arc.scene.ui.Image", "arc.scene.ui.ImageButton", "arc.scene.ui.ImageButton$ImageButtonStyle", "arc.scene.ui.KeybindDialog", "arc.scene.ui.KeybindDialog$KeybindDialogStyle", "arc.scene.ui.Label", "arc.scene.ui.Label$LabelStyle", "arc.scene.ui.ProgressBar", "arc.scene.ui.ProgressBar$ProgressBarStyle", "arc.scene.ui.ScrollPane", "arc.scene.ui.ScrollPane$ScrollPaneStyle", "arc.scene.ui.SettingsDialog", "arc.scene.ui.SettingsDialog$SettingsTable", "arc.scene.ui.SettingsDialog$SettingsTable$CheckSetting", "arc.scene.ui.SettingsDialog$SettingsTable$Setting", "arc.scene.ui.SettingsDialog$SettingsTable$SliderSetting", "arc.scene.ui.SettingsDialog$StringProcessor", "arc.scene.ui.Slider", "arc.scene.ui.Slider$SliderStyle", "arc.scene.ui.TextArea", "arc.scene.ui.TextArea$TextAreaListener", "arc.scene.ui.TextButton", "arc.scene.ui.TextButton$TextButtonStyle", "arc.scene.ui.TextField", "arc.scene.ui.TextField$DefaultOnscreenKeyboard", "arc.scene.ui.TextField$OnscreenKeyboard", "arc.scene.ui.TextField$TextFieldClickListener", "arc.scene.ui.TextField$TextFieldFilter", "arc.scene.ui.TextField$TextFieldListener", "arc.scene.ui.TextField$TextFieldStyle", "arc.scene.ui.TextField$TextFieldValidator", "arc.scene.ui.Tooltip", "arc.scene.ui.Tooltip$Tooltips", "arc.scene.ui.Touchpad", "arc.scene.ui.Touchpad$TouchpadStyle", "arc.scene.ui.TreeElement", "arc.scene.ui.TreeElement$Node", "arc.scene.ui.TreeElement$TreeStyle", "arc.scene.ui.layout.Cell", "arc.scene.ui.layout.Collapser", "arc.scene.ui.layout.HorizontalGroup", "arc.scene.ui.layout.Scl", "arc.scene.ui.layout.Stack", "arc.scene.ui.layout.Table", "arc.scene.ui.layout.Table$DrawRect", "arc.scene.ui.layout.VerticalGroup", "arc.scene.ui.layout.WidgetGroup", "arc.scene.utils.ArraySelection", "arc.scene.utils.Cullable", "arc.scene.utils.Disableable", "arc.scene.utils.DragAndDrop", "arc.scene.utils.DragAndDrop$Payload", "arc.scene.utils.DragAndDrop$Source", "arc.scene.utils.DragAndDrop$Target", "arc.scene.utils.Elements", "arc.scene.utils.Layout", "arc.scene.utils.Selection", "arc.struct.Array", "arc.struct.Array$ArrayIterable", "arc.struct.ArrayMap", "arc.struct.ArrayMap$Entries", "arc.struct.ArrayMap$Keys", "arc.struct.ArrayMap$Values", "arc.struct.AtomicQueue", "arc.struct.BinaryHeap", "arc.struct.BinaryHeap$Node", "arc.struct.Bits", "arc.struct.BooleanArray", "arc.struct.ByteArray", "arc.struct.CharArray", "arc.struct.ComparableTimSort", "arc.struct.DelayedRemovalArray", "arc.struct.EnumSet", "arc.struct.EnumSet$EnumSetIterator", "arc.struct.FloatArray", "arc.struct.GridBits", "arc.struct.GridMap", "arc.struct.IdentityMap", "arc.struct.IdentityMap$Entries", "arc.struct.IdentityMap$Entry", "arc.struct.IdentityMap$Keys", "arc.struct.IdentityMap$Values", "arc.struct.IntArray", "arc.struct.IntFloatMap", "arc.struct.IntFloatMap$Entries", "arc.struct.IntFloatMap$Entry", "arc.struct.IntFloatMap$Keys", "arc.struct.IntFloatMap$Values", "arc.struct.IntIntMap", "arc.struct.IntIntMap$Entries", "arc.struct.IntIntMap$Entry", "arc.struct.IntIntMap$Keys", "arc.struct.IntIntMap$Values", "arc.struct.IntMap", "arc.struct.IntMap$Entries", "arc.struct.IntMap$Entry", "arc.struct.IntMap$Keys", "arc.struct.IntMap$Values", "arc.struct.IntQueue", "arc.struct.IntSet", "arc.struct.IntSet$IntSetIterator", "arc.struct.LongArray", "arc.struct.LongMap", "arc.struct.LongMap$Entries", "arc.struct.LongMap$Entry", "arc.struct.LongMap$Keys", "arc.struct.LongMap$Values", "arc.struct.LongQueue", "arc.struct.ObjectFloatMap", "arc.struct.ObjectFloatMap$Entries", "arc.struct.ObjectFloatMap$Entry", "arc.struct.ObjectFloatMap$Keys", "arc.struct.ObjectFloatMap$Values", "arc.struct.ObjectIntMap", "arc.struct.ObjectIntMap$Entries", "arc.struct.ObjectIntMap$Entry", "arc.struct.ObjectIntMap$Keys", "arc.struct.ObjectIntMap$Values", "arc.struct.ObjectMap", "arc.struct.ObjectMap$Entries", "arc.struct.ObjectMap$Entry", "arc.struct.ObjectMap$Keys", "arc.struct.ObjectMap$Values", "arc.struct.ObjectSet", "arc.struct.ObjectSet$ObjectSetIterator", "arc.struct.OrderedMap", "arc.struct.OrderedMap$OrderedMapEntries", "arc.struct.OrderedMap$OrderedMapKeys", "arc.struct.OrderedMap$OrderedMapValues", "arc.struct.OrderedSet", "arc.struct.OrderedSet$OrderedSetIterator", "arc.struct.PooledLinkedList", "arc.struct.PooledLinkedList$Item", "arc.struct.Queue", "arc.struct.Queue$QueueIterable", "arc.struct.ShortArray", "arc.struct.SnapshotArray", "arc.struct.Sort", "arc.struct.SortedIntList", "arc.struct.SortedIntList$Iterator", "arc.struct.SortedIntList$Node", "arc.struct.StringMap", "arc.struct.TimSort", "arc.util.I18NBundle", "arc.util.Time", "java.io.PrintStream", "java.lang.Object", "java.lang.Runnable", "java.lang.String", "java.lang.System", "mindustry.Vars", "mindustry.ai.BlockIndexer", "mindustry.ai.Pathfinder", "mindustry.ai.Pathfinder$PathData", "mindustry.ai.Pathfinder$PathTarget", "mindustry.ai.Pathfinder$PathTileStruct", "mindustry.ai.WaveSpawner", "mindustry.content.Blocks", "mindustry.content.Bullets", "mindustry.content.Fx", "mindustry.content.Items", "mindustry.content.Liquids", "mindustry.content.Loadouts", "mindustry.content.Mechs", "mindustry.content.StatusEffects", "mindustry.content.TechTree", "mindustry.content.TechTree$TechNode", "mindustry.content.TypeIDs", "mindustry.content.UnitTypes", "mindustry.content.Zones", "mindustry.core.ContentLoader", "mindustry.core.Control", "mindustry.core.FileTree", "mindustry.core.GameState", "mindustry.core.GameState$State", "mindustry.core.Logic", "mindustry.core.NetServer$TeamAssigner", "mindustry.core.Platform", "mindustry.core.Renderer", "mindustry.core.UI", "mindustry.core.Version", "mindustry.core.World", "mindustry.core.World$Raycaster", "mindustry.ctype.Content", "mindustry.ctype.Content$ModContentInfo", "mindustry.ctype.ContentList", "mindustry.ctype.ContentType", "mindustry.ctype.MappableContent", "mindustry.ctype.UnlockableContent", "mindustry.editor.DrawOperation", "mindustry.editor.DrawOperation$OpType", "mindustry.editor.DrawOperation$TileOpStruct", "mindustry.editor.EditorTile", "mindustry.editor.EditorTool", "mindustry.editor.MapEditor", "mindustry.editor.MapEditor$Context", "mindustry.editor.MapEditorDialog", "mindustry.editor.MapGenerateDialog", "mindustry.editor.MapInfoDialog", "mindustry.editor.MapLoadDialog", "mindustry.editor.MapRenderer", "mindustry.editor.MapResizeDialog", "mindustry.editor.MapSaveDialog", "mindustry.editor.MapView", "mindustry.editor.OperationStack", "mindustry.editor.WaveInfoDialog", "mindustry.entities.Damage", "mindustry.entities.Damage$PropCellStruct", "mindustry.entities.Effects", "mindustry.entities.Effects$Effect", "mindustry.entities.Effects$EffectContainer", "mindustry.entities.Effects$EffectProvider", "mindustry.entities.Effects$EffectRenderer", "mindustry.entities.Effects$ScreenshakeProvider", "mindustry.entities.Entities", "mindustry.entities.EntityCollisions", "mindustry.entities.EntityGroup", "mindustry.entities.Predict", "mindustry.entities.TargetPriority", "mindustry.entities.Units", "mindustry.entities.bullet.ArtilleryBulletType", "mindustry.entities.bullet.BasicBulletType", "mindustry.entities.bullet.BombBulletType", "mindustry.entities.bullet.BulletType", "mindustry.entities.bullet.FlakBulletType", "mindustry.entities.bullet.HealBulletType", "mindustry.entities.bullet.LiquidBulletType", "mindustry.entities.bullet.MassDriverBolt", "mindustry.entities.bullet.MissileBulletType", "mindustry.entities.effect.Decal", "mindustry.entities.effect.Fire", "mindustry.entities.effect.GroundEffectEntity", "mindustry.entities.effect.GroundEffectEntity$GroundEffect", "mindustry.entities.effect.ItemTransfer", "mindustry.entities.effect.Lightning", "mindustry.entities.effect.Puddle", "mindustry.entities.effect.RubbleDecal", "mindustry.entities.effect.ScorchDecal", "mindustry.entities.traits.AbsorbTrait", "mindustry.entities.traits.BelowLiquidTrait", "mindustry.entities.traits.BuilderMinerTrait", "mindustry.entities.traits.BuilderTrait", "mindustry.entities.traits.BuilderTrait$BuildDataStatic", "mindustry.entities.traits.BuilderTrait$BuildRequest", "mindustry.entities.traits.DamageTrait", "mindustry.entities.traits.DrawTrait", "mindustry.entities.traits.Entity", "mindustry.entities.traits.HealthTrait", "mindustry.entities.traits.KillerTrait", "mindustry.entities.traits.MinerTrait", "mindustry.entities.traits.MoveTrait", "mindustry.entities.traits.SaveTrait", "mindustry.entities.traits.Saveable", "mindustry.entities.traits.ScaleTrait", "mindustry.entities.traits.ShooterTrait", "mindustry.entities.traits.SolidTrait", "mindustry.entities.traits.SpawnerTrait", "mindustry.entities.traits.SyncTrait", "mindustry.entities.traits.TargetTrait", "mindustry.entities.traits.TeamTrait", "mindustry.entities.traits.TimeTrait", "mindustry.entities.traits.TypeTrait", "mindustry.entities.traits.VelocityTrait", "mindustry.entities.type.BaseEntity", "mindustry.entities.type.BaseUnit", "mindustry.entities.type.Bullet", "mindustry.entities.type.DestructibleEntity", "mindustry.entities.type.EffectEntity", "mindustry.entities.type.Player", "mindustry.entities.type.SolidEntity", "mindustry.entities.type.TileEntity", "mindustry.entities.type.TimedEntity", "mindustry.entities.type.Unit", "mindustry.entities.type.base.BaseDrone", "mindustry.entities.type.base.BuilderDrone", "mindustry.entities.type.base.FlyingUnit", "mindustry.entities.type.base.GroundUnit", "mindustry.entities.type.base.HoverUnit", "mindustry.entities.type.base.MinerDrone", "mindustry.entities.type.base.RepairDrone", "mindustry.entities.units.StateMachine", "mindustry.entities.units.Statuses", "mindustry.entities.units.Statuses$StatusEntry", "mindustry.entities.units.UnitCommand", "mindustry.entities.units.UnitDrops", "mindustry.entities.units.UnitState", "mindustry.game.DefaultWaves", "mindustry.game.Difficulty", "mindustry.game.EventType", "mindustry.game.EventType$BlockBuildBeginEvent", "mindustry.game.EventType$BlockBuildEndEvent", "mindustry.game.EventType$BlockDestroyEvent", "mindustry.game.EventType$BlockInfoEvent", "mindustry.game.EventType$BuildSelectEvent", "mindustry.game.EventType$ClientLoadEvent", "mindustry.game.EventType$CommandIssueEvent", "mindustry.game.EventType$ContentReloadEvent", "mindustry.game.EventType$CoreItemDeliverEvent", "mindustry.game.EventType$DepositEvent", "mindustry.game.EventType$DisposeEvent", "mindustry.game.EventType$GameOverEvent", "mindustry.game.EventType$LaunchEvent", "mindustry.game.EventType$LaunchItemEvent", "mindustry.game.EventType$LineConfirmEvent", "mindustry.game.EventType$LoseEvent", "mindustry.game.EventType$MapMakeEvent", "mindustry.game.EventType$MapPublishEvent", "mindustry.game.EventType$MechChangeEvent", "mindustry.game.EventType$PlayEvent", "mindustry.game.EventType$PlayerBanEvent", "mindustry.game.EventType$PlayerChatEvent", "mindustry.game.EventType$PlayerConnect", "mindustry.game.EventType$PlayerIpBanEvent", "mindustry.game.EventType$PlayerIpUnbanEvent", "mindustry.game.EventType$PlayerJoin", "mindustry.game.EventType$PlayerLeave", "mindustry.game.EventType$PlayerUnbanEvent", "mindustry.game.EventType$ResearchEvent", "mindustry.game.EventType$ResetEvent", "mindustry.game.EventType$ResizeEvent", "mindustry.game.EventType$ServerLoadEvent", "mindustry.game.EventType$StateChangeEvent", "mindustry.game.EventType$TapConfigEvent", "mindustry.game.EventType$TapEvent", "mindustry.game.EventType$TileChangeEvent", "mindustry.game.EventType$Trigger", "mindustry.game.EventType$TurretAmmoDeliverEvent", "mindustry.game.EventType$UnitCreateEvent", "mindustry.game.EventType$UnitDestroyEvent", "mindustry.game.EventType$UnlockEvent", "mindustry.game.EventType$WaveEvent", "mindustry.game.EventType$WinEvent", "mindustry.game.EventType$WithdrawEvent", "mindustry.game.EventType$WorldLoadEvent", "mindustry.game.EventType$ZoneConfigureCompleteEvent", "mindustry.game.EventType$ZoneRequireCompleteEvent", "mindustry.game.Gamemode", "mindustry.game.GlobalData", "mindustry.game.LoopControl", "mindustry.game.MusicControl", "mindustry.game.Objective", "mindustry.game.Objectives", "mindustry.game.Objectives$Launched", "mindustry.game.Objectives$Unlock", "mindustry.game.Objectives$Wave", "mindustry.game.Objectives$ZoneObjective", "mindustry.game.Objectives$ZoneWave", "mindustry.game.Rules", "mindustry.game.Saves", "mindustry.game.Saves$SaveSlot", "mindustry.game.Schematic", "mindustry.game.Schematic$Stile", "mindustry.game.Schematics", "mindustry.game.SoundLoop", "mindustry.game.SpawnGroup", "mindustry.game.Stats", "mindustry.game.Stats$Rank", "mindustry.game.Stats$RankResult", "mindustry.game.Team", "mindustry.game.Teams", "mindustry.game.Teams$BrokenBlock", "mindustry.game.Teams$TeamData", "mindustry.game.Tutorial", "mindustry.game.Tutorial$TutorialStage", "mindustry.gen.BufferItem", "mindustry.gen.Call", "mindustry.gen.Call", "mindustry.gen.Icon", "mindustry.gen.Icon", "mindustry.gen.MethodHash", "mindustry.gen.Musics", "mindustry.gen.Musics", "mindustry.gen.PathTile", "mindustry.gen.PropCell", "mindustry.gen.RemoteReadClient", "mindustry.gen.RemoteReadServer", "mindustry.gen.Serialization", "mindustry.gen.Sounds", "mindustry.gen.Sounds", "mindustry.gen.Tex", "mindustry.gen.Tex", "mindustry.gen.TileOp", "mindustry.graphics.BlockRenderer", "mindustry.graphics.Bloom", "mindustry.graphics.CacheLayer", "mindustry.graphics.Drawf", "mindustry.graphics.FloorRenderer", "mindustry.graphics.IndexedRenderer", "mindustry.graphics.Layer", "mindustry.graphics.LightRenderer", "mindustry.graphics.MenuRenderer", "mindustry.graphics.MinimapRenderer", "mindustry.graphics.MultiPacker", "mindustry.graphics.MultiPacker$PageType", "mindustry.graphics.OverlayRenderer", "mindustry.graphics.Pal", "mindustry.graphics.Pixelator", "mindustry.graphics.Shaders", "mindustry.input.Binding", "mindustry.input.DesktopInput", "mindustry.input.InputHandler", "mindustry.input.InputHandler$PlaceLine", "mindustry.input.MobileInput", "mindustry.input.PlaceMode", "mindustry.input.Placement", "mindustry.input.Placement$DistanceHeuristic", "mindustry.input.Placement$NormalizeDrawResult", "mindustry.input.Placement$NormalizeResult", "mindustry.input.Placement$TileHueristic", "mindustry.maps.Map", "mindustry.maps.Maps", "mindustry.maps.Maps$MapProvider", "mindustry.maps.Maps$ShuffleMode", "mindustry.maps.Maps$ShuffleMode", "mindustry.maps.filters.BlendFilter", "mindustry.maps.filters.ClearFilter", "mindustry.maps.filters.DistortFilter", "mindustry.maps.filters.FilterOption", "mindustry.maps.filters.FilterOption$BlockOption", "mindustry.maps.filters.FilterOption$SliderOption", "mindustry.maps.filters.GenerateFilter", "mindustry.maps.filters.GenerateFilter$GenerateInput", "mindustry.maps.filters.GenerateFilter$GenerateInput$TileProvider", "mindustry.maps.filters.MedianFilter", "mindustry.maps.filters.MirrorFilter", "mindustry.maps.filters.NoiseFilter", "mindustry.maps.filters.OreFilter", "mindustry.maps.filters.OreMedianFilter", "mindustry.maps.filters.RiverNoiseFilter", "mindustry.maps.filters.ScatterFilter", "mindustry.maps.filters.TerrainFilter", "mindustry.maps.generators.BasicGenerator", "mindustry.maps.generators.BasicGenerator$DistanceHeuristic", "mindustry.maps.generators.BasicGenerator$TileHueristic", "mindustry.maps.generators.Generator", "mindustry.maps.generators.MapGenerator", "mindustry.maps.generators.MapGenerator$Decoration", "mindustry.maps.generators.RandomGenerator", "mindustry.maps.zonegen.DesertWastesGenerator", "mindustry.maps.zonegen.OvergrowthGenerator", "mindustry.type.Category", "mindustry.type.ErrorContent", "mindustry.type.Item", "mindustry.type.ItemStack", "mindustry.type.ItemType", "mindustry.type.Liquid", "mindustry.type.LiquidStack", "mindustry.type.Mech", "mindustry.type.Publishable", "mindustry.type.StatusEffect", "mindustry.type.StatusEffect$TransitionHandler", "mindustry.type.TypeID", "mindustry.type.UnitType", "mindustry.type.Weapon", "mindustry.type.WeatherEvent", "mindustry.type.Zone", "mindustry.ui.Bar", "mindustry.ui.BorderImage", "mindustry.ui.Cicon", "mindustry.ui.ContentDisplay", "mindustry.ui.Fonts", "mindustry.ui.GridImage", "mindustry.ui.IconSize", "mindustry.ui.IntFormat", "mindustry.ui.ItemDisplay", "mindustry.ui.ItemImage", "mindustry.ui.ItemsDisplay", "mindustry.ui.Links", "mindustry.ui.Links$LinkEntry", "mindustry.ui.LiquidDisplay", "mindustry.ui.Minimap", "mindustry.ui.MobileButton", "mindustry.ui.MultiReqImage", "mindustry.ui.ReqImage", "mindustry.ui.Styles", "mindustry.ui.dialogs.AboutDialog", "mindustry.ui.dialogs.AdminsDialog", "mindustry.ui.dialogs.BansDialog", "mindustry.ui.dialogs.ColorPicker", "mindustry.ui.dialogs.ContentInfoDialog", "mindustry.ui.dialogs.ControlsDialog", "mindustry.ui.dialogs.CustomGameDialog", "mindustry.ui.dialogs.CustomRulesDialog", "mindustry.ui.dialogs.DatabaseDialog", "mindustry.ui.dialogs.DeployDialog", "mindustry.ui.dialogs.DeployDialog$View", "mindustry.ui.dialogs.DeployDialog$ZoneNode", "mindustry.ui.dialogs.DiscordDialog", "mindustry.ui.dialogs.FileChooser", "mindustry.ui.dialogs.FileChooser$FileHistory", "mindustry.ui.dialogs.FloatingDialog", "mindustry.ui.dialogs.GameOverDialog", "mindustry.ui.dialogs.HostDialog", "mindustry.ui.dialogs.JoinDialog", "mindustry.ui.dialogs.JoinDialog$Server", "mindustry.ui.dialogs.LanguageDialog", "mindustry.ui.dialogs.LoadDialog", "mindustry.ui.dialogs.LoadoutDialog", "mindustry.ui.dialogs.MapPlayDialog", "mindustry.ui.dialogs.MapsDialog", "mindustry.ui.dialogs.MinimapDialog", "mindustry.ui.dialogs.ModsDialog", "mindustry.ui.dialogs.PaletteDialog", "mindustry.ui.dialogs.PausedDialog", "mindustry.ui.dialogs.SaveDialog", "mindustry.ui.dialogs.SchematicsDialog", "mindustry.ui.dialogs.SchematicsDialog$SchematicImage", "mindustry.ui.dialogs.SchematicsDialog$SchematicInfoDialog", "mindustry.ui.dialogs.SettingsMenuDialog", "mindustry.ui.dialogs.TechTreeDialog", "mindustry.ui.dialogs.TechTreeDialog$LayoutNode", "mindustry.ui.dialogs.TechTreeDialog$TechTreeNode", "mindustry.ui.dialogs.TechTreeDialog$View", "mindustry.ui.dialogs.TraceDialog", "mindustry.ui.dialogs.ZoneInfoDialog", "mindustry.ui.fragments.BlockConfigFragment", "mindustry.ui.fragments.BlockInventoryFragment", "mindustry.ui.fragments.ChatFragment", "mindustry.ui.fragments.FadeInFragment", "mindustry.ui.fragments.Fragment", "mindustry.ui.fragments.HudFragment", "mindustry.ui.fragments.LoadingFragment", "mindustry.ui.fragments.MenuFragment", "mindustry.ui.fragments.OverlayFragment", "mindustry.ui.fragments.PlacementFragment", "mindustry.ui.fragments.PlayerListFragment", "mindustry.ui.fragments.ScriptConsoleFragment", "mindustry.ui.layout.BranchTreeLayout", "mindustry.ui.layout.BranchTreeLayout$TreeAlignment", "mindustry.ui.layout.BranchTreeLayout$TreeLocation", "mindustry.ui.layout.RadialTreeLayout", "mindustry.ui.layout.TreeLayout", "mindustry.ui.layout.TreeLayout$TreeNode", "mindustry.world.Block", "mindustry.world.BlockStorage", "mindustry.world.Build", "mindustry.world.CachedTile", "mindustry.world.DirectionalItemBuffer", "mindustry.world.DirectionalItemBuffer$BufferItemStruct", "mindustry.world.Edges", "mindustry.world.ItemBuffer", "mindustry.world.LegacyColorMapper", "mindustry.world.LegacyColorMapper$LegacyBlock", "mindustry.world.Pos", "mindustry.world.StaticTree", "mindustry.world.Tile", "mindustry.world.WorldContext", "mindustry.world.blocks.Attributes", "mindustry.world.blocks.Autotiler", "mindustry.world.blocks.Autotiler$AutotilerHolder", "mindustry.world.blocks.BlockPart", "mindustry.world.blocks.BuildBlock", "mindustry.world.blocks.BuildBlock$BuildEntity", "mindustry.world.blocks.DoubleOverlayFloor", "mindustry.world.blocks.Floor", "mindustry.world.blocks.ItemSelection", "mindustry.world.blocks.LiquidBlock", "mindustry.world.blocks.OreBlock", "mindustry.world.blocks.OverlayFloor", "mindustry.world.blocks.PowerBlock", "mindustry.world.blocks.RespawnBlock", "mindustry.world.blocks.Rock", "mindustry.world.blocks.StaticWall", "mindustry.world.blocks.TreeBlock", "mindustry.world.blocks.defense.DeflectorWall", "mindustry.world.blocks.defense.DeflectorWall$DeflectorEntity", "mindustry.world.blocks.defense.Door", "mindustry.world.blocks.defense.Door$DoorEntity", "mindustry.world.blocks.defense.ForceProjector", "mindustry.world.blocks.defense.ForceProjector$ForceEntity", "mindustry.world.blocks.defense.ForceProjector$ShieldEntity", "mindustry.world.blocks.defense.MendProjector", "mindustry.world.blocks.defense.MendProjector$MendEntity", "mindustry.world.blocks.defense.OverdriveProjector", "mindustry.world.blocks.defense.OverdriveProjector$OverdriveEntity", "mindustry.world.blocks.defense.ShockMine", "mindustry.world.blocks.defense.SurgeWall", "mindustry.world.blocks.defense.Wall", "mindustry.world.blocks.defense.turrets.ArtilleryTurret", "mindustry.world.blocks.defense.turrets.BurstTurret", "mindustry.world.blocks.defense.turrets.ChargeTurret", "mindustry.world.blocks.defense.turrets.ChargeTurret$LaserTurretEntity", "mindustry.world.blocks.defense.turrets.CooledTurret", "mindustry.world.blocks.defense.turrets.DoubleTurret", "mindustry.world.blocks.defense.turrets.ItemTurret", "mindustry.world.blocks.defense.turrets.ItemTurret$ItemEntry", "mindustry.world.blocks.defense.turrets.ItemTurret$ItemTurretEntity", "mindustry.world.blocks.defense.turrets.LaserTurret", "mindustry.world.blocks.defense.turrets.LaserTurret$LaserTurretEntity", "mindustry.world.blocks.defense.turrets.LiquidTurret", "mindustry.world.blocks.defense.turrets.PowerTurret", "mindustry.world.blocks.defense.turrets.Turret", "mindustry.world.blocks.defense.turrets.Turret$AmmoEntry", "mindustry.world.blocks.defense.turrets.Turret$TurretEntity", "mindustry.world.blocks.distribution.ArmoredConveyor", "mindustry.world.blocks.distribution.BufferedItemBridge", "mindustry.world.blocks.distribution.BufferedItemBridge$BufferedItemBridgeEntity", "mindustry.world.blocks.distribution.Conveyor", "mindustry.world.blocks.distribution.Conveyor$ConveyorEntity", "mindustry.world.blocks.distribution.Conveyor$ItemPos", "mindustry.world.blocks.distribution.ExtendingItemBridge", "mindustry.world.blocks.distribution.ItemBridge", "mindustry.world.blocks.distribution.ItemBridge$ItemBridgeEntity", "mindustry.world.blocks.distribution.Junction", "mindustry.world.blocks.distribution.Junction$JunctionEntity", "mindustry.world.blocks.distribution.MassDriver", "mindustry.world.blocks.distribution.MassDriver$DriverBulletData", "mindustry.world.blocks.distribution.MassDriver$DriverState", "mindustry.world.blocks.distribution.MassDriver$MassDriverEntity", "mindustry.world.blocks.distribution.OverflowGate", "mindustry.world.blocks.distribution.OverflowGate$OverflowGateEntity", "mindustry.world.blocks.distribution.Router", "mindustry.world.blocks.distribution.Router$RouterEntity", "mindustry.world.blocks.distribution.Sorter", "mindustry.world.blocks.distribution.Sorter$SorterEntity", "mindustry.world.blocks.liquid.ArmoredConduit", "mindustry.world.blocks.liquid.Conduit", "mindustry.world.blocks.liquid.Conduit$ConduitEntity", "mindustry.world.blocks.liquid.LiquidBridge", "mindustry.world.blocks.liquid.LiquidExtendingBridge", "mindustry.world.blocks.liquid.LiquidJunction", "mindustry.world.blocks.liquid.LiquidOverflowGate", "mindustry.world.blocks.liquid.LiquidRouter", "mindustry.world.blocks.liquid.LiquidTank", "mindustry.world.blocks.logic.LogicBlock", "mindustry.world.blocks.logic.MessageBlock", "mindustry.world.blocks.logic.MessageBlock$MessageBlockEntity", "mindustry.world.blocks.power.Battery", "mindustry.world.blocks.power.BurnerGenerator", "mindustry.world.blocks.power.ConditionalConsumePower", "mindustry.world.blocks.power.DecayGenerator", "mindustry.world.blocks.power.ImpactReactor", "mindustry.world.blocks.power.ImpactReactor$FusionReactorEntity", "mindustry.world.blocks.power.ItemLiquidGenerator", "mindustry.world.blocks.power.ItemLiquidGenerator$ItemLiquidGeneratorEntity", "mindustry.world.blocks.power.LightBlock", "mindustry.world.blocks.power.LightBlock$LightEntity", "mindustry.world.blocks.power.NuclearReactor", "mindustry.world.blocks.power.NuclearReactor$NuclearReactorEntity", "mindustry.world.blocks.power.PowerDiode", "mindustry.world.blocks.power.PowerDistributor", "mindustry.world.blocks.power.PowerGenerator", "mindustry.world.blocks.power.PowerGenerator$GeneratorEntity", "mindustry.world.blocks.power.PowerGraph", "mindustry.world.blocks.power.PowerNode", "mindustry.world.blocks.power.SingleTypeGenerator", "mindustry.world.blocks.power.SolarGenerator", "mindustry.world.blocks.power.ThermalGenerator", "mindustry.world.blocks.production.Cultivator", "mindustry.world.blocks.production.Cultivator$CultivatorEntity", "mindustry.world.blocks.production.Drill", "mindustry.world.blocks.production.Drill$DrillEntity", "mindustry.world.blocks.production.Fracker", "mindustry.world.blocks.production.Fracker$FrackerEntity", "mindustry.world.blocks.production.GenericCrafter", "mindustry.world.blocks.production.GenericCrafter$GenericCrafterEntity", "mindustry.world.blocks.production.GenericSmelter", "mindustry.world.blocks.production.Incinerator", "mindustry.world.blocks.production.Incinerator$IncineratorEntity", "mindustry.world.blocks.production.LiquidConverter", "mindustry.world.blocks.production.Pump", "mindustry.world.blocks.production.Separator", "mindustry.world.blocks.production.SolidPump", "mindustry.world.blocks.production.SolidPump$SolidPumpEntity", "mindustry.world.blocks.sandbox.ItemSource", "mindustry.world.blocks.sandbox.ItemSource$ItemSourceEntity", "mindustry.world.blocks.sandbox.ItemVoid", "mindustry.world.blocks.sandbox.LiquidSource", "mindustry.world.blocks.sandbox.LiquidSource$LiquidSourceEntity", "mindustry.world.blocks.sandbox.PowerSource", "mindustry.world.blocks.sandbox.PowerVoid", "mindustry.world.blocks.storage.CoreBlock", "mindustry.world.blocks.storage.CoreBlock$CoreEntity", "mindustry.world.blocks.storage.LaunchPad", "mindustry.world.blocks.storage.StorageBlock", "mindustry.world.blocks.storage.StorageBlock$StorageBlockEntity", "mindustry.world.blocks.storage.Unloader", "mindustry.world.blocks.storage.Unloader$UnloaderEntity", "mindustry.world.blocks.storage.Vault", "mindustry.world.blocks.units.CommandCenter", "mindustry.world.blocks.units.CommandCenter$CommandCenterEntity", "mindustry.world.blocks.units.MechPad", "mindustry.world.blocks.units.MechPad$MechFactoryEntity", "mindustry.world.blocks.units.RallyPoint", "mindustry.world.blocks.units.RepairPoint", "mindustry.world.blocks.units.RepairPoint$RepairPointEntity", "mindustry.world.blocks.units.UnitFactory", "mindustry.world.blocks.units.UnitFactory$UnitFactoryEntity", "mindustry.world.consumers.Consume", "mindustry.world.consumers.ConsumeItemFilter", "mindustry.world.consumers.ConsumeItems", "mindustry.world.consumers.ConsumeLiquid", "mindustry.world.consumers.ConsumeLiquidBase", "mindustry.world.consumers.ConsumeLiquidFilter", "mindustry.world.consumers.ConsumePower", "mindustry.world.consumers.ConsumeType", "mindustry.world.consumers.Consumers", "mindustry.world.meta.Attribute", "mindustry.world.meta.BlockBars", "mindustry.world.meta.BlockFlag", "mindustry.world.meta.BlockGroup", "mindustry.world.meta.BlockStat", "mindustry.world.meta.BlockStats", "mindustry.world.meta.BuildVisibility", "mindustry.world.meta.PowerType", "mindustry.world.meta.Producers", "mindustry.world.meta.StatCategory", "mindustry.world.meta.StatUnit", "mindustry.world.meta.StatValue", "mindustry.world.meta.values.AmmoListValue", "mindustry.world.meta.values.BooleanValue", "mindustry.world.meta.values.BoosterListValue", "mindustry.world.meta.values.ItemFilterValue", "mindustry.world.meta.values.ItemListValue", "mindustry.world.meta.values.LiquidFilterValue", "mindustry.world.meta.values.LiquidValue", "mindustry.world.meta.values.NumberValue", "mindustry.world.meta.values.StringValue", "mindustry.world.modules.BlockModule", "mindustry.world.modules.ConsumeModule", "mindustry.world.modules.ItemModule", "mindustry.world.modules.ItemModule$ItemCalculator", "mindustry.world.modules.ItemModule$ItemConsumer", "mindustry.world.modules.LiquidModule", "mindustry.world.modules.LiquidModule$LiquidCalculator", "mindustry.world.modules.LiquidModule$LiquidConsumer", "mindustry.world.modules.PowerModule", "mindustry.world.producers.Produce", "mindustry.world.producers.ProduceItem"); } \ No newline at end of file From c0c0ffa6829c385bbafff92887fe9c10cd3d7fff Mon Sep 17 00:00:00 2001 From: Anuken Date: Fri, 27 Dec 2019 01:22:50 -0500 Subject: [PATCH 16/78] Bugfixes --- core/src/mindustry/content/Fx.java | 1 + core/src/mindustry/input/DesktopInput.java | 2 +- core/src/mindustry/mod/Mods.java | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/core/src/mindustry/content/Fx.java b/core/src/mindustry/content/Fx.java index 379e01f9a6..a116034e1a 100644 --- a/core/src/mindustry/content/Fx.java +++ b/core/src/mindustry/content/Fx.java @@ -1079,6 +1079,7 @@ public class Fx implements ContentList{ healBlockFull = new Effect(20, e -> { Draw.color(e.color); Draw.alpha(e.fout()); + Fill.square(e.x, e.y, e.rotation * tilesize / 2f); }); overdriveBlockFull = new Effect(60, e -> { diff --git a/core/src/mindustry/input/DesktopInput.java b/core/src/mindustry/input/DesktopInput.java index 38aa0c2fd4..c76968a56e 100644 --- a/core/src/mindustry/input/DesktopInput.java +++ b/core/src/mindustry/input/DesktopInput.java @@ -300,7 +300,7 @@ public class DesktopInput extends InputHandler{ } } - if(Core.input.keyTap(Binding.clear_building)){ + if(Core.input.keyTap(Binding.clear_building) || isPlacing()){ lastSchematic = null; selectRequests.clear(); } diff --git a/core/src/mindustry/mod/Mods.java b/core/src/mindustry/mod/Mods.java index b92b2fefc5..e4907ed26c 100644 --- a/core/src/mindustry/mod/Mods.java +++ b/core/src/mindustry/mod/Mods.java @@ -85,6 +85,7 @@ public class Mods implements Loadable{ try{ mods.add(loadMod(dest)); requiresReload = true; + sortMods(); }catch(IOException e){ dest.delete(); throw e; From d43b40fab557a96612e77cce8b4d1183c36a5c34 Mon Sep 17 00:00:00 2001 From: AmateurPotion <47741752+AmateurPotion@users.noreply.github.com> Date: Sun, 29 Dec 2019 01:21:55 +0900 Subject: [PATCH 17/78] Update bundle_ko.properties (#1262) --- core/assets/bundles/bundle_ko.properties | 68 +++++++++++++----------- 1 file changed, 36 insertions(+), 32 deletions(-) diff --git a/core/assets/bundles/bundle_ko.properties b/core/assets/bundles/bundle_ko.properties index 71a44a6bff..3d9c8e0475 100644 --- a/core/assets/bundles/bundle_ko.properties +++ b/core/assets/bundles/bundle_ko.properties @@ -7,14 +7,15 @@ link.reddit.description = Mindustry 레딧 link.github.description = 게임 소스코드 link.changelog.description = 새로 추가된 것들 link.dev-builds.description = 불안정한 개발 빌드들 -link.trello.description = 다음 출시될 기능들을 게시한 공식 Trello 보드 +link.trello.description = 출시 예정중인 기능들을 게시한 공식 Trello 보드 link.itch.io.description = PC 버전 다운로드와 HTML5 버전이 있는 itch.io 사이트 link.google-play.description = Google Play 스토어 정보 link.f-droid.description = F-Droid 카탈로그 link.wiki.description = 공식 Mindustry 위키 +link.feathub.description = 기능 아이디어 건의하기 linkfail = 링크를 여는 데 실패했습니다!\nURL이 기기의 클립보드에 복사되었습니다. -screenshot = 스크린샷이 {0} 경로에 저장되었습니다. -screenshot.invalid = 맵이 너무 커서 스크린샷을 찍을 메모리가 충분하지 않습니다. +screenshot = 스크린 샷이 {0} 경로에 저장되었습니다. +screenshot.invalid = 맵이 너무 커서 스크린 샷을 찍을 메모리가 충분하지 않습니다. gameover = 게임 오버 gameover.pvp = [accent]{0}[] 팀이 승리했습니다! highscore = [accent]최고점수 달성! @@ -35,11 +36,11 @@ schematic.replace = 이 설계도와 같은 이름의 설계도가 이미 존재 schematic.import = 설계도 불러오기 schematic.exportfile = 파일 내보내기 schematic.importfile = 파일 불러오기 -schematic.browseworkshop = 워크샵 탐색 +schematic.browseworkshop = Workshop 탐색 schematic.copy = 클립보드에 복사하기 schematic.copy.import = 클립보드에서 붙여넣기 schematic.shareworkshop = 워크샵에 공유 -schematic.flip = 좌우 뒤집기 :[accent][[{0}][] / 상하 뒤집기 : [accent][[{1}][] +schematic.flip = 좌우 뒤집기 : [accent][[{0}][] / 상하 뒤집기 : [accent][[{1}][] schematic.saved = 설계도 저장됨. schematic.delete.confirm = 삭제된 설계도는 복구할 수 없습니다. 정말로 삭제하시겠습니까? schematic.rename = 설계도명 변경 @@ -94,7 +95,7 @@ mods.alpha = [scarlet](Alpha) mods = 모드 mods.none = [LIGHT_GRAY]추가한 모드가 없습니다! mods.guide = 모드 가이드 -mods.report = 버그 신고 +mods.report = 문제 신고 mods.openfolder = 모드 폴더 열기 mod.enabled = [lightgray]활성화 mod.disabled = [scarlet]비활성화 @@ -102,7 +103,10 @@ mod.disable = 비활성화 mod.delete.error = 모드를 삭제할 수 없습니다. 아마도 해당 모드가 사용중인 것 같습니다. mod.requiresversion = [scarlet]게임의 버전이 낮아 모드를 활성화할 수 없습니다!\n[scarlet]요구되는 게임 버전 : [accent]{0} mod.missingdependencies = [scarlet]의존되는 모드: {0} -mod.nowdisabled = [scarlet]모드 '{0}'는 다음의 모드에 의존합니다 :[accent] {1}\n[lightgray]이 모드를 먼저 다운로드해야합니다.\n이 모드는 자동으로 비활성화됩니다. +mod.erroredcontent = [scarlet]컨텐츠 오류 +mod.errors = 컨텐츠를 불러오는 중 오류가 발생하였습니다. +mod.noerrorplay = [scarlet]모드에 오류가 존재합니다.[] 해당 오류가 발생하는 모드를 비활성화하거나 모드의 오류를 고친 후 플레이가 가능합니다. +mod.nowdisabled = [scarlet]모드 '{0}'는 다음의 모드에 의존합니다 : [accent] {1}\n[lightgray]이 모드를 먼저 다운로드해야합니다.\n이 모드는 자동으로 비활성화됩니다. mod.enable = 활성화 mod.requiresrestart = 모드 변경사항을 적용하기 위해 게임을 종료합니다. mod.reloadrequired = [scarlet]새로고침 예정됨 @@ -111,7 +115,7 @@ mod.import.github = 깃허브 모드 추가 mod.item.remove = 이것은 모드[accent] '{0}'[]의 자원입니다. 이 자원을 삭제하려면, 이 모드를 제거해야합니다. mod.remove.confirm = 이 모드를 삭제하시겠습니까? mod.author = [LIGHT_GRAY]제작자 : [] {0} -mod.missing = 이 세이브파일에는 설치하지 않은 모드 혹은 이 버전에 속해있지 않은 데이터가 포함되어 있습니다. 이 파일을 불러올 경우 세이브파일의 데이터가 손상될 수 있습니다. 정말로 이 파일을 불러오시겠습니까?\n[lightgray]모드 :\n{0} +mod.missing = 이 세이브파일에는 설치하지 않은 모드 혹은 현재 버전에 속해있지 않은 데이터가 포함되어 있습니다. 이 파일을 불러올 경우 세이브파일의 데이터가 손상될 수 있습니다. 정말로 이 파일을 불러오시겠습니까?\n[lightgray]모드 :\n{0} mod.preview.missing = 워크샵에 당신의 모드를 업로드하기 전에 미리보기 이미지를 먼저 추가해야합니다.\n[accent] preview.png[]라는 이름으로 미리보기 이미지를 당신의 모드 폴더안에 준비한 후 다시 시도해주세요. mod.folder.missing = 워크샵에는 폴더 형태의 모드만 게시할 수 있습니다.\n모드를 폴더 형태로 바꾸려면 파일을 폴더에 압축 해제하고 이전 압축파일을 제거한 후, 게임을 재시작하거나 모드를 다시 로드하십시오. mod.scripts.unsupported = 당신의 기기는 모드스크립트를 지원하지 않습니다. 모드의 일부 기능이 작동하지 않을 수 있습니다. @@ -594,8 +598,8 @@ unit.persecond = /초 unit.timesspeed = x 배 unit.percent = % unit.items = 자원 -unit.thousands = 천 -unit.millions = 백만 +unit.thousands = k +unit.millions = mil category.general = 일반 category.power = 전력 category.liquids = 액체 @@ -635,7 +639,7 @@ setting.sensitivity.name = 컨트롤러 감도 setting.saveinterval.name = 저장 간격 setting.seconds = {0} 초 setting.blockselecttimeout.name = 블록 선택 시간 초과 -setting.milliseconds = {0} 밀리초 +setting.milliseconds = {0} ms setting.fullscreen.name = 전체 화면 setting.borderlesswindow.name = 테두리 없는 창모드[LIGHT_GRAY] (재시작이 필요할 수 있습니다) setting.fps.name = FPS 표시 @@ -683,20 +687,20 @@ keybind.schematic_flip_x.name = 설계도 X축 뒤집기 keybind.schematic_flip_y.name = 설계도 Y축 뒤집기 keybind.category_prev.name = 이전 목록 keybind.category_next.name = 다음 목록 -keybind.block_select_left.name = 블럭 왼쪽 선택 -keybind.block_select_right.name = 블럭 오른쪽 선택 -keybind.block_select_up.name = 블럭 위쪽 선택 -keybind.block_select_down.name = 블럭 아래쪽 선택 -keybind.block_select_01.name = 카테고리/블럭 선택 1 -keybind.block_select_02.name = 카테고리/블럭 선택 2 -keybind.block_select_03.name = 카테고리/블럭 선택 3 -keybind.block_select_04.name = 카테고리/블럭 선택 4 -keybind.block_select_05.name = 카테고리/블럭 선택 5 -keybind.block_select_06.name = 카테고리/블럭 선택 6 -keybind.block_select_07.name = 카테고리/블럭 선택 7 -keybind.block_select_08.name = 카테고리/블럭 선택 8 -keybind.block_select_09.name = 카테고리/블럭 선택 9 -keybind.block_select_10.name = 카테고리/블럭 선택 10 +keybind.block_select_left.name = 블록 왼쪽 선택 +keybind.block_select_right.name = 블록 오른쪽 선택 +keybind.block_select_up.name = 블록 위쪽 선택 +keybind.block_select_down.name = 블록 아래쪽 선택 +keybind.block_select_01.name = 카테고리/블록 선택 1 +keybind.block_select_02.name = 카테고리/블록 선택 2 +keybind.block_select_03.name = 카테고리/블록 선택 3 +keybind.block_select_04.name = 카테고리/블록 선택 4 +keybind.block_select_05.name = 카테고리/블록 선택 5 +keybind.block_select_06.name = 카테고리/블록 선택 6 +keybind.block_select_07.name = 카테고리/블록 선택 7 +keybind.block_select_08.name = 카테고리/블록 선택 8 +keybind.block_select_09.name = 카테고리/블록 선택 9 +keybind.block_select_10.name = 카테고리/블록 선택 10 keybind.fullscreen.name = 전체 화면 keybind.select.name = 선택/공격 keybind.diagonal_placement.name = 대각선 설치 @@ -716,8 +720,8 @@ keybind.console.name = 콘솔 keybind.rotate.name = 회전 keybind.rotateplaced.name = 기존 회전 (고정) keybind.toggle_menus.name = 메뉴 보이기/숨기기 -keybind.chat_history_prev.name = 이전 채팅기록 -keybind.chat_history_next.name = 다음 채팅기록 +keybind.chat_history_prev.name = 이전 채팅 기록 +keybind.chat_history_next.name = 다음 채팅 기록 keybind.chat_scroll.name = 채팅 스크롤 keybind.drop_unit.name = 유닛 처치 시 자원획득 keybind.zoom_minimap.name = 미니맵 확대 @@ -730,11 +734,11 @@ mode.editor.name = 편집기 mode.pvp.name = PvP mode.pvp.description = 실제 플레이어와 PvP를 합니다. 맵에 적어도 2개의 다른 색상 코어가 있어야 합니다. mode.attack.name = 공격 -mode.attack.description = 적 기지를 파괴하세요. 맵에 빨간팀 코어가 있어야 플레이 가능합니다. +mode.attack.description = 적 기지를 파괴하세요. 맵에 빨간 팀 코어가 있어야 플레이 가능합니다. mode.custom = 사용자 정의 규칙 rules.infiniteresources = 무한 자원 -rules.reactorexplosions = 원자로 폭발 허가여부 +rules.reactorexplosions = 원자로 폭발 허가 여부 rules.wavetimer = 단계 대기시간 rules.waves = 단계 활성화 rules.attack = 공격 모드 @@ -750,7 +754,7 @@ rules.respawntime = 플레이어 부활 대기 시간 : [LIGHT_GRAY] (초) rules.wavespacing = 단계 간격 : [LIGHT_GRAY] (초) rules.buildcostmultiplier = 건설 소모 배수 rules.buildspeedmultiplier = 건설 속도 배수 -rules.waitForWaveToEnd = 단계가 끝날때까지 기다리는중 +rules.waitForWaveToEnd = 단계가 끝날때까지 기다리는 중 rules.dropzoneradius = 소환 충격파 범위 : [LIGHT_GRAY] (타일) rules.respawns = 단계당 최대 플레이어 부활 횟수 rules.limitedRespawns = 플레이어 부활 제한 @@ -810,7 +814,7 @@ mech.trident-ship.name = 트라이던트 mech.trident-ship.weapon = 폭탄 저장고 mech.glaive-ship.name = 글레이브 mech.glaive-ship.weapon = 중무장 인화성 소총 -item.corestorable = [lightgray]코어 잔여 저장공간: {0} +item.corestorable = [lightgray]코어 저장 가능 여부 : {0} item.explosiveness = [LIGHT_GRAY]폭발성 : {0} item.flammability = [LIGHT_GRAY]인화성 : {0} item.radioactivity = [LIGHT_GRAY]방사능 : {0} @@ -1117,7 +1121,7 @@ block.cryofluidmixer.description = 물과 티타늄을 냉각에 훨씬 더 효 block.blast-mixer.description = 포자를 사용하여 파이라타이트를 폭발성 화합물로 변환시킵니다. block.pyratite-mixer.description = 석탄, 납, 모래를 가연성이 높은 파이라타이트로 만듭니다. block.melter.description = 고철을 녹여 파도의 탄약 혹은 원심 분리기에 사용할 수 있는 액체인 광재로 만듭니다. -block.separator.description = 광재룰 각종 자원으로 재활용 할 수 있게 해 주는 건물입니다. +block.separator.description = 광재를 각종 자원으로 재활용 할 수 있게 해 주는 건물입니다. block.spore-press.description = 포자를 압축해 기름을 추출합니다. block.pulverizer.description = 고철을 갈아 모래로 만듭니다. 맵에 모래가 부족할 때 유용합니다. block.coal-centrifuge.description = 석유로 석탄을 만듭니다. From e1bf8bdab19d8c8bb5290800d9e02194bc10e060 Mon Sep 17 00:00:00 2001 From: Anuken Date: Sat, 28 Dec 2019 16:30:40 -0500 Subject: [PATCH 18/78] Added BE auto-updater / Server config / Fixed #1266 --- core/assets/bundles/bundle.properties | 7 + core/src/mindustry/Vars.java | 6 + core/src/mindustry/ai/Pathfinder.java | 2 +- core/src/mindustry/core/Version.java | 4 +- core/src/mindustry/core/World.java | 2 +- core/src/mindustry/game/EventType.java | 3 +- core/src/mindustry/net/Administration.java | 97 +++++++--- core/src/mindustry/net/BeControl.java | 168 ++++++++++++++++++ core/src/mindustry/net/CrashSender.java | 20 ++- core/src/mindustry/net/NetworkIO.java | 4 +- core/src/mindustry/ui/dialogs/ModsDialog.java | 2 +- .../mindustry/ui/fragments/MenuFragment.java | 12 ++ core/src/mindustry/world/Tile.java | 2 +- .../world/blocks/production/SolidPump.java | 8 +- gradle.properties | 2 +- run-server | 8 + .../src/mindustry/server/ServerControl.java | 146 +++++---------- 17 files changed, 349 insertions(+), 144 deletions(-) create mode 100644 core/src/mindustry/net/BeControl.java diff --git a/core/assets/bundles/bundle.properties b/core/assets/bundles/bundle.properties index 9ee0b4842a..2b2a1aa548 100644 --- a/core/assets/bundles/bundle.properties +++ b/core/assets/bundles/bundle.properties @@ -29,6 +29,13 @@ load.system = System load.mod = Mods load.scripts = Scripts +be.update = A new Bleeding Edge build is available: +be.update.confirm = Download it and restart now? +be.updating = Updating... +be.ignore = Ignore +be.noupdates = No updates found. +be.check = Check for updates + schematic = Schematic schematic.add = Save Schematic... schematics = Schematics diff --git a/core/src/mindustry/Vars.java b/core/src/mindustry/Vars.java index dfefeb2a68..2cfa4bad45 100644 --- a/core/src/mindustry/Vars.java +++ b/core/src/mindustry/Vars.java @@ -21,6 +21,7 @@ import mindustry.gen.*; import mindustry.input.*; import mindustry.maps.*; import mindustry.mod.*; +import mindustry.net.*; import mindustry.net.Net; import mindustry.world.blocks.defense.ForceProjector.*; @@ -136,6 +137,8 @@ public class Vars implements Loadable{ public static Fi modDirectory; /** data subdirectory used for schematics */ public static Fi schematicDirectory; + /** data subdirectory used for bleeding edge build versions */ + public static Fi bebuildDirectory; /** map file extension */ public static final String mapExtension = "msav"; /** save file extension */ @@ -157,6 +160,7 @@ public class Vars implements Loadable{ public static Platform platform = new Platform(){}; public static Mods mods; public static Schematics schematics = new Schematics(); + public static BeControl becontrol; public static World world; public static Maps maps; @@ -220,6 +224,7 @@ public class Vars implements Loadable{ defaultWaves = new DefaultWaves(); collisions = new EntityCollisions(); world = new World(); + becontrol = new BeControl(); maps = new Maps(); spawner = new WaveSpawner(); @@ -260,6 +265,7 @@ public class Vars implements Loadable{ tmpDirectory = dataDirectory.child("tmp/"); modDirectory = dataDirectory.child("mods/"); schematicDirectory = dataDirectory.child("schematics/"); + bebuildDirectory = dataDirectory.child("be_builds/"); modDirectory.mkdirs(); diff --git a/core/src/mindustry/ai/Pathfinder.java b/core/src/mindustry/ai/Pathfinder.java index 6a2515bb7a..a16ac8f410 100644 --- a/core/src/mindustry/ai/Pathfinder.java +++ b/core/src/mindustry/ai/Pathfinder.java @@ -139,7 +139,7 @@ public class Pathfinder implements Runnable{ //stop looping when interrupted externally return; } - }catch(Exception e){ + }catch(Throwable e){ e.printStackTrace(); } } diff --git a/core/src/mindustry/core/Version.java b/core/src/mindustry/core/Version.java index 700b8776e6..08a105d8fb 100644 --- a/core/src/mindustry/core/Version.java +++ b/core/src/mindustry/core/Version.java @@ -9,9 +9,9 @@ import arc.util.io.*; public class Version{ /** Build type. 'official' for official releases; 'custom' or 'bleeding edge' are also used. */ - public static String type; + public static String type = "unknown"; /** Build modifier, e.g. 'alpha' or 'release' */ - public static String modifier; + public static String modifier = "unknown"; /** Number specifying the major version, e.g. '4' */ public static int number; /** Build number, e.g. '43'. set to '-1' for custom builds. */ diff --git a/core/src/mindustry/core/World.java b/core/src/mindustry/core/World.java index ea0e9aa054..bbc3f4074c 100644 --- a/core/src/mindustry/core/World.java +++ b/core/src/mindustry/core/World.java @@ -217,7 +217,7 @@ public class World{ public void loadMap(Map map, Rules checkRules){ try{ SaveIO.load(map.file, new FilterContext(map)); - }catch(Exception e){ + }catch(Throwable e){ Log.err(e); if(!headless){ ui.showErrorMessage("$map.invalid"); diff --git a/core/src/mindustry/game/EventType.java b/core/src/mindustry/game/EventType.java index dfa1469fc1..6cbaba5e4b 100644 --- a/core/src/mindustry/game/EventType.java +++ b/core/src/mindustry/game/EventType.java @@ -28,7 +28,8 @@ public class EventType{ exclusionDeath, suicideBomb, openWiki, - teamCoreDamage + teamCoreDamage, + socketConfigChanged } public static class WinEvent{} diff --git a/core/src/mindustry/net/Administration.java b/core/src/mindustry/net/Administration.java index dabf679d34..157566a5c3 100644 --- a/core/src/mindustry/net/Administration.java +++ b/core/src/mindustry/net/Administration.java @@ -18,11 +18,6 @@ public class Administration{ private Array chatFilters = new Array<>(); public Administration(){ - Core.settings.defaults( - "strict", true, - "servername", "Server" - ); - load(); } @@ -51,21 +46,12 @@ public class Administration{ Core.settings.putSave("playerlimit", limit); } - public void setStrict(boolean on){ - Core.settings.putSave("strict", on); - } - public boolean getStrict(){ - return Core.settings.getBool("strict"); + return Config.strict.bool(); } public boolean allowsCustomClients(){ - return Core.settings.getBool("allow-custom", !headless); - } - - public void setCustomClients(boolean allowed){ - Core.settings.put("allow-custom", allowed); - Core.settings.save(); + return Config.allowCustomClients.bool(); } /** Call when a player joins to update their information here. */ @@ -219,11 +205,7 @@ public class Administration{ } public boolean isWhitelistEnabled(){ - return Core.settings.getBool("whitelist", false); - } - - public void setWhitelist(boolean enabled){ - Core.settings.putSave("whitelist", enabled); + return Config.whitelist.bool(); } public boolean isWhitelisted(String id, String usid){ @@ -333,6 +315,79 @@ public class Administration{ whitelist = Core.settings.getObject("whitelisted", Array.class, Array::new); } + /** Server configuration definition. Each config value can be a string, boolean or number. */ + public enum Config{ + name("The server name as displayed on clients.", "Server", "servername"), + port("The port to host on.", Vars.port), + autoUpdate("Whether to auto-restart when a new update arrives.", false), + crashReport("Whether to send crash reports.", false, "crashreport"), + logging("Whether to log everything to files.", true), + strict("Whether strict mode is on - corrects positions and prevents duplicate UUIDs.", true), + socketInput("Allows a local application to control this server through a local TCP socket.", false, "socket", () -> Events.fire(Trigger.socketConfigChanged)), + socketInputPort("The port for socket input.", 6859, () -> Events.fire(Trigger.socketConfigChanged)), + socketInputAddress("The bind address for socket input.", "localhost", () -> Events.fire(Trigger.socketConfigChanged)), + allowCustomClients("Whether custom clients are allowed to connect.", !headless, "allow-custom"), + whitelist("Whether the whitelist is used.", false); + + public static final Config[] all = values(); + + public final Object defaultValue; + public final String key, description; + final Runnable changed; + + Config(String description, Object def){ + this(description, def, null, null); + } + + Config(String description, Object def, String key){ + this(description, def, key, null); + } + + Config(String description, Object def, Runnable changed){ + this(description, def, null, changed); + } + + Config(String description, Object def, String key, Runnable changed){ + this.description = description; + this.key = key == null ? name() : key; + this.defaultValue = def; + this.changed = changed == null ? () -> {} : changed; + } + + public boolean isNum(){ + return defaultValue instanceof Integer; + } + + public boolean isBool(){ + return defaultValue instanceof Boolean; + } + + public boolean isString(){ + return defaultValue instanceof String; + } + + public Object get(){ + return Core.settings.get(key, defaultValue); + } + + public boolean bool(){ + return Core.settings.getBool(key, (Boolean)defaultValue); + } + + public int num(){ + return Core.settings.getInt(key, (Integer)defaultValue); + } + + public String string(){ + return Core.settings.getString(key, (String)defaultValue); + } + + public void set(Object value){ + Core.settings.putSave(key, value); + changed.run(); + } + } + @Serialize public static class PlayerInfo{ public String id; diff --git a/core/src/mindustry/net/BeControl.java b/core/src/mindustry/net/BeControl.java new file mode 100644 index 0000000000..d81c5e721d --- /dev/null +++ b/core/src/mindustry/net/BeControl.java @@ -0,0 +1,168 @@ +package mindustry.net; + +import arc.*; +import arc.Net.*; +import arc.files.*; +import arc.func.*; +import arc.util.*; +import arc.util.async.*; +import arc.util.serialization.*; +import mindustry.core.*; +import mindustry.gen.*; +import mindustry.graphics.*; +import mindustry.net.Administration.*; +import mindustry.ui.*; +import mindustry.ui.dialogs.*; + +import java.io.*; +import java.net.*; + +import static mindustry.Vars.*; + +/** Handles control of bleeding edge builds. */ +public class BeControl{ + private static final int updateInterval = 60; + + private AsyncExecutor executor = new AsyncExecutor(1); + private boolean checkUpdates = true; + private boolean updateAvailable; + private String updateUrl; + private int updateBuild; + + /** @return whether this is a bleeding edge build. */ + public boolean active(){ + return Version.type.equals("bleeding-edge"); + } + + public BeControl(){ + if(active()){ + Timer.schedule(() -> { + if(checkUpdates && !mobile){ + checkUpdate(t -> {}); + } + }, 1, updateInterval); + } + } + + /** asynchronously checks for updates. */ + public void checkUpdate(Boolc done){ + Core.net.httpGet("https://api.github.com/repos/Anuken/MindustryBuilds/releases/latest", res -> { + if(res.getStatus() == HttpStatus.OK){ + Jval val = Jval.read(res.getResultAsString()); + int newBuild = Strings.parseInt(val.getString("tag_name", "0")); + if(newBuild > Version.build){ + Jval asset = val.get("assets").asArray().find(v -> v.getString("name", "").startsWith(headless ? "Mindustry-BE-Server" : "Mindustry-BE-Desktop")); + String url = asset.getString("browser_download_url", ""); + updateAvailable = true; + updateBuild = newBuild; + updateUrl = url; + showUpdateDialog(); + Core.app.post(() -> done.get(true)); + }else{ + Core.app.post(() -> done.get(false)); + } + }else{ + Core.app.post(() -> done.get(false)); + Log.err("Update check responded with: {0}", res.getStatus()); + } + }, error -> { + if(!headless){ + ui.showException(error); + }else{ + error.printStackTrace(); + } + }); + } + + /** @return whether a new update is available */ + public boolean isUpdateAvailable(){ + return updateAvailable; + } + + /** shows the dialog for updating the game on desktop, or a prompt for doing so on the server */ + public void showUpdateDialog(){ + if(!updateAvailable) return; + + if(!headless){ + ui.showCustomConfirm(Core.bundle.format("be.update", "") + " " + updateBuild, "$be.update.confirm", "$ok", "$be.ignore", () -> { + boolean[] cancel = {false}; + float[] progress = {0}; + int[] length = {0}; + Fi file = bebuildDirectory.child("client-be-" + updateBuild + ".jar"); + + FloatingDialog dialog = new FloatingDialog("$be.updating"); + download(updateUrl, file, i -> length[0] = i, v -> progress[0] = v, () -> cancel[0], () -> { + try{ + Runtime.getRuntime().exec(new String[]{"java", "-DlastBuild=" + Version.build, "-Dberestart", "-jar", file.absolutePath()}); + System.exit(0); + }catch(IOException e){ + ui.showException(e); + } + }, e -> { + dialog.hide(); + ui.showException(e); + }); + + dialog.cont.add(new Bar(() -> length[0] == 0 ? Core.bundle.get("be.updating") : (int)(progress[0] * length[0]) / 1024/ 1024 + "/" + length[0]/1024/1024 + " MB", () -> Pal.accent, () -> progress[0])).width(400f).height(70f); + dialog.buttons.addImageTextButton("$cancel", Icon.cancelSmall, () -> { + cancel[0] = true; + dialog.hide(); + }).size(210f, 64f); + dialog.setFillParent(false); + dialog.show(); + }, () -> checkUpdates = false); + }else{ + Log.info("&lcA new update is available: &lyBleeding Edge build {0}", updateBuild); + if(Config.autoUpdate.bool()){ + Log.info("&lcAuto-downloading next version..."); + + try{ + Fi source = Fi.get(BeControl.class.getProtectionDomain().getCodeSource().getLocation().toURI().getPath()); + Fi dest = source.sibling("server-be-" + updateBuild + ".jar"); + + download(updateUrl, dest, + len -> Core.app.post(() -> Log.info("&ly| Size: {0} MB.", Strings.fixed((float)len / 1024 / 1024, 2))), + progress -> {}, + () -> false, + () -> { + Log.info("&lcVersion downloaded, exiting. Note that if you are not using the run-server script, the server will not restart automatically."); + dest.copyTo(source); + dest.delete(); + System.exit(2); //this will cause a restart if using the script + }, + Throwable::printStackTrace); + }catch(Exception e){ + e.printStackTrace(); + } + } + checkUpdates = false; + //todo server updates + } + } + + private void download(String furl, Fi dest, Intc length, Floatc progressor, Boolp canceled, Runnable done, Cons error){ + executor.submit(() -> { + try{ + HttpURLConnection con = (HttpURLConnection)new URL(furl).openConnection(); + BufferedInputStream in = new BufferedInputStream(con.getInputStream()); + OutputStream out = dest.write(false, 4096); + + byte[] data = new byte[4096]; + long size = con.getContentLength(); + long counter = 0; + length.get((int)size); + int x; + while((x = in.read(data, 0, data.length)) >= 0 && !canceled.get()){ + counter += x; + progressor.get((float)counter / (float)size); + out.write(data, 0, x); + } + out.close(); + in.close(); + if(!canceled.get()) done.run(); + }catch(Throwable e){ + error.get(e); + } + }); + } +} diff --git a/core/src/mindustry/net/CrashSender.java b/core/src/mindustry/net/CrashSender.java index 43692c77d6..1b24b2af3a 100644 --- a/core/src/mindustry/net/CrashSender.java +++ b/core/src/mindustry/net/CrashSender.java @@ -27,7 +27,9 @@ public class CrashSender{ exception.printStackTrace(); //don't create crash logs for custom builds, as it's expected - if(Version.build == -1 || (System.getProperty("user.name").equals("anuke") && "release".equals(Version.modifier))) return; + if(Version.build == -1 || (System.getProperty("user.name").equals("anuke") && "release".equals(Version.modifier))){ + ret(); + } //attempt to load version regardless if(Version.number == 0){ @@ -63,7 +65,7 @@ public class CrashSender{ try{ //check crash report setting if(!Core.settings.getBool("crashreport", true)){ - return; + ret(); } }catch(Throwable ignored){ //if there's no settings init we don't know what the user wants but chances are it's an important crash, so send it anyway @@ -72,14 +74,14 @@ public class CrashSender{ try{ //check any mods - if there are any, don't send reports if(Vars.mods != null && !Vars.mods.list().isEmpty()){ - return; + ret(); } }catch(Throwable ignored){ } //do not send exceptions that occur for versions that can't be parsed if(Version.number == 0){ - return; + ret(); } boolean netActive = false, netServer = false; @@ -130,12 +132,16 @@ public class CrashSender{ while(!sent[0]){ Thread.sleep(30); } - }catch(InterruptedException ignored){ - } + }catch(InterruptedException ignored){} }catch(Throwable death){ death.printStackTrace(); - System.exit(1); } + + ret(); + } + + private static void ret(){ + System.exit(1); } private static void httpPost(String url, String content, Cons success, Cons failure){ diff --git a/core/src/mindustry/net/NetworkIO.java b/core/src/mindustry/net/NetworkIO.java index d877ac6e3a..1c6e1acba2 100644 --- a/core/src/mindustry/net/NetworkIO.java +++ b/core/src/mindustry/net/NetworkIO.java @@ -1,12 +1,12 @@ package mindustry.net; -import arc.*; import arc.util.*; import mindustry.core.*; import mindustry.entities.type.*; import mindustry.game.*; import mindustry.io.*; import mindustry.maps.Map; +import mindustry.net.Administration.*; import java.io.*; import java.nio.*; @@ -62,7 +62,7 @@ public class NetworkIO{ } public static ByteBuffer writeServerData(){ - String name = (headless ? Core.settings.getString("servername") : player.name); + String name = (headless ? Config.name.string() : player.name); String map = world.getMap() == null ? "None" : world.getMap().name(); ByteBuffer buffer = ByteBuffer.allocate(256); diff --git a/core/src/mindustry/ui/dialogs/ModsDialog.java b/core/src/mindustry/ui/dialogs/ModsDialog.java index 96b71b6861..4b42f64d80 100644 --- a/core/src/mindustry/ui/dialogs/ModsDialog.java +++ b/core/src/mindustry/ui/dialogs/ModsDialog.java @@ -32,7 +32,7 @@ public class ModsDialog extends FloatingDialog{ buttons.row(); - buttons.addImageTextButton("$mods.guide", Icon.wiki, + buttons.addImageTextButton("$mods.guide", Icon.link, () -> Core.net.openURI(modGuideURL)) .size(210, 64f); diff --git a/core/src/mindustry/ui/fragments/MenuFragment.java b/core/src/mindustry/ui/fragments/MenuFragment.java index 535f4d6046..8737db0d9a 100644 --- a/core/src/mindustry/ui/fragments/MenuFragment.java +++ b/core/src/mindustry/ui/fragments/MenuFragment.java @@ -59,6 +59,18 @@ public class MenuFragment extends Fragment{ if(mobile){ parent.fill(c -> c.bottom().left().addButton("", Styles.infot, ui.about::show).size(84, 45)); parent.fill(c -> c.bottom().right().addButton("", Styles.discordt, ui.discord::show).size(84, 45)); + }else if(becontrol.active()){ + parent.fill(c -> c.bottom().right().addImageTextButton("$be.check", Icon.refreshSmall, () -> { + ui.loadfrag.show(); + becontrol.checkUpdate(result -> { + ui.loadfrag.hide(); + if(!result){ + ui.showInfo("$be.noupdates"); + } + }); + }).size(200, 60).update(t -> { + t.getLabel().setColor(becontrol.isUpdateAvailable() ? Tmp.c1.set(Color.white).lerp(Pal.accent, Mathf.absin(5f, 1f)) : Color.white); + })); } String versionText = "[#ffffffba]" + ((Version.build == -1) ? "[#fc8140aa]custom build" : (Version.type.equals("official") ? Version.modifier : Version.type) + " build " + Version.build + (Version.revision == 0 ? "" : "." + Version.revision)); diff --git a/core/src/mindustry/world/Tile.java b/core/src/mindustry/world/Tile.java index 0572c74286..119af5b8df 100644 --- a/core/src/mindustry/world/Tile.java +++ b/core/src/mindustry/world/Tile.java @@ -257,7 +257,7 @@ public class Tile implements Position, TargetTrait{ } public boolean solid(){ - return block.solid || block.isSolidFor(this) || (isLinked() && link().solid()); + return block.solid || block.isSolidFor(this) || (isLinked() && link() != this && link().solid()); } public boolean breakable(){ diff --git a/core/src/mindustry/world/blocks/production/SolidPump.java b/core/src/mindustry/world/blocks/production/SolidPump.java index 854d4be010..ac199c7b27 100644 --- a/core/src/mindustry/world/blocks/production/SolidPump.java +++ b/core/src/mindustry/world/blocks/production/SolidPump.java @@ -4,6 +4,7 @@ import arc.Core; import arc.graphics.g2d.Draw; import arc.graphics.g2d.TextureRegion; import arc.math.Mathf; +import arc.util.*; import mindustry.content.Fx; import mindustry.content.Liquids; import mindustry.entities.Effects; @@ -51,8 +52,8 @@ public class SolidPump extends Pump{ public void setBars(){ super.setBars(); bars.add("efficiency", entity -> new Bar(() -> - Core.bundle.formatFloat("bar.efficiency", - ((((SolidPumpEntity)entity).boost + 1f) * ((SolidPumpEntity)entity).warmup) * 100 * percentSolid(entity.tile.x, entity.tile.y), 1), + Core.bundle.formatFloat("bar.pumpspeed", + ((SolidPumpEntity)entity).lastPump / Time.delta() * 60, 1), () -> Pal.ammo, () -> ((SolidPumpEntity)entity).warmup)); } @@ -104,11 +105,13 @@ public class SolidPump extends Pump{ if(tile.entity.cons.valid() && typeLiquid(tile) < liquidCapacity - 0.001f){ float maxPump = Math.min(liquidCapacity - typeLiquid(tile), pumpAmount * entity.delta() * fraction * entity.efficiency()); tile.entity.liquids.add(result, maxPump); + entity.lastPump = maxPump; entity.warmup = Mathf.lerpDelta(entity.warmup, 1f, 0.02f); if(Mathf.chance(entity.delta() * updateEffectChance)) Effects.effect(updateEffect, entity.x + Mathf.range(size * 2f), entity.y + Mathf.range(size * 2f)); }else{ entity.warmup = Mathf.lerpDelta(entity.warmup, 0f, 0.02f); + entity.lastPump = 0f; } entity.pumpTime += entity.warmup * entity.delta(); @@ -153,5 +156,6 @@ public class SolidPump extends Pump{ public float warmup; public float pumpTime; public float boost; + public float lastPump; } } diff --git a/gradle.properties b/gradle.properties index 19101944cf..0b0bc673e4 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,3 +1,3 @@ org.gradle.daemon=true org.gradle.jvmargs=-Xms256m -Xmx1024m -archash=60a9ebe264f92f2c3082596c77b9ab29474c4a7f +archash=0e25944f7f3a065ed6707f0dbe48548980cad8a6 diff --git a/run-server b/run-server index 0358cb521b..25a8254723 100755 --- a/run-server +++ b/run-server @@ -5,4 +5,12 @@ if [[ $# -eq 0 ]] ; then fi ./gradlew server:dist -Pbuildversion=$1 + +while true; do +#auto-restart until ctrl-c or exit 0 java -jar -XX:+HeapDumpOnOutOfMemoryError server/build/libs/server-release.jar +excode=$? +if [ $excode -eq 0 ] || [ $excode -eq 130 ]; then + exit 0 +fi +done diff --git a/server/src/mindustry/server/ServerControl.java b/server/src/mindustry/server/ServerControl.java index 3637ac972e..f1dbb59803 100644 --- a/server/src/mindustry/server/ServerControl.java +++ b/server/src/mindustry/server/ServerControl.java @@ -40,7 +40,6 @@ import static mindustry.Vars.*; public class ServerControl implements ApplicationListener{ private static final int roundExtraTime = 12; private static final int maxLogLength = 1024 * 512; - private static final int commandSocketPort = 6859; protected static String[] tags = {"&lc&fb[D]", "&lg&fb[I]", "&ly&fb[W]", "&lr&fb[E]", ""}; protected static DateTimeFormatter dateTime = DateTimeFormatter.ofPattern("MM-dd-yyyy | HH:mm:ss"); @@ -64,10 +63,6 @@ public class ServerControl implements ApplicationListener{ "bans", "", "admins", "", "shufflemode", "custom", - "crashreport", false, - "port", port, - "logging", true, - "socket", false, "globalrules", "{reactorExplosions: false}" ); @@ -75,7 +70,7 @@ public class ServerControl implements ApplicationListener{ String result = "[" + dateTime.format(LocalDateTime.now()) + "] " + format(tags[level.ordinal()] + " " + text + "&fr", args1); System.out.println(result); - if(Core.settings.getBool("logging")){ + if(Config.logging.bool()){ logToFile("[" + dateTime.format(LocalDateTime.now()) + "] " + format(tags[level.ordinal()] + " " + text + "&fr", false, args1)); } @@ -158,16 +153,19 @@ public class ServerControl implements ApplicationListener{ } }); + Events.on(Trigger.socketConfigChanged, () -> { + toggleSocket(false); + toggleSocket(Config.socketInput.bool()); + }); + if(!mods.list().isEmpty()){ info("&lc{0} mods loaded.", mods.list().size); } + toggleSocket(Config.socketInput.bool()); + info("&lcServer loaded. Type &ly'help'&lc for help."); System.out.print("> "); - - if(Core.settings.getBool("socket")){ - toggleSocket(true); - } } private void registerCommands(){ @@ -247,21 +245,6 @@ public class ServerControl implements ApplicationListener{ } }); - handler.register("port", "[port]", "Sets or displays the port for hosting the server.", arg -> { - if(arg.length == 0){ - info("&lyPort: &lc{0}", Core.settings.getInt("port")); - }else{ - int port = Strings.parseInt(arg[0]); - if(port < 0 || port > 65535){ - err("Port must be a number between 0 and 65535."); - return; - } - info("&lyPort set to {0}.", port); - Core.settings.put("port", port); - Core.settings.save(); - } - }); - handler.register("maps", "Display all available maps.", arg -> { if(!maps.all().isEmpty()){ info("Maps:"); @@ -440,16 +423,6 @@ public class ServerControl implements ApplicationListener{ }); - handler.register("name", "[name...]", "Change the server display name.", arg -> { - if(arg.length == 0){ - info("Server name is currently &lc'{0}'.", Core.settings.getString("servername")); - return; - } - Core.settings.put("servername", arg[0]); - Core.settings.save(); - info("Server name is now &lc'{0}'.", arg[0]); - }); - handler.register("playerlimit", "[off/somenumber]", "Set the server player limit.", arg -> { if(arg.length == 0){ info("Player limit is currently &lc{0}.", netServer.admins.getPlayerLimit() == 0 ? "off" : netServer.admins.getPlayerLimit()); @@ -470,14 +443,40 @@ public class ServerControl implements ApplicationListener{ } }); - handler.register("whitelist", "[on/off...]", "Enable/disable whitelisting.", arg -> { + handler.register("config", "[name] [value]", "Configure server settings.", arg -> { if(arg.length == 0){ - info("Whitelist is currently &lc{0}.", netServer.admins.isWhitelistEnabled() ? "on" : "off"); + info("&lyAll config values:"); + for(Config c : Config.all){ + Log.info("&ly| &lc{0}:&lm {1}", c.name(), c.get()); + Log.info("&ly| | {0}", c.description); + Log.info("&ly|"); + } return; } - boolean on = arg[0].equalsIgnoreCase("on"); - netServer.admins.setWhitelist(on); - info("Whitelist is now &lc{0}.", on ? "on" : "off"); + + try{ + Config c = Config.valueOf(arg[0]); + if(arg.length == 1){ + Log.info("&lc'{0}'&lg is currently &lc{0}.", c.name(), c.get()); + }else{ + if(c.isBool()){ + c.set(arg[1].equals("on") || arg[1].equals("true")); + }else if(c.isNum()){ + try{ + c.set(Integer.parseInt(arg[1])); + }catch(NumberFormatException e){ + Log.err("Not a valid number: {0}", arg[1]); + return; + } + }else if(c.isString()){ + c.set(arg[1]); + } + + Log.info("&lc{0}&lg set to &lc{1}.", c.name(), c.get()); + } + }catch(IllegalArgumentException e){ + err("Unknown config: '{0}'. Run the command with no arguments to get a list of valid configs.", arg[0]); + } }); handler.register("whitelisted", "List the entire whitelist.", arg -> { @@ -512,67 +511,6 @@ public class ServerControl implements ApplicationListener{ info("Player &ly'{0}'&lg has been un-whitelisted.", info.lastName); }); - handler.register("sync", "[on/off...]", "Enable/disable block sync. Experimental.", arg -> { - if(arg.length == 0){ - info("Block sync is currently &lc{0}.", Core.settings.getBool("blocksync") ? "enabled" : "disabled"); - return; - } - boolean on = arg[0].equalsIgnoreCase("on"); - Core.settings.putSave("blocksync", on); - info("Block syncing is now &lc{0}.", on ? "on" : "off"); - }); - - handler.register("crashreport", "", "Disables or enables automatic crash reporting", arg -> { - boolean value = arg[0].equalsIgnoreCase("on"); - Core.settings.put("crashreport", value); - Core.settings.save(); - info("Crash reporting is now {0}.", value ? "on" : "off"); - }); - - handler.register("logging", "", "Disables or enables server logs", arg -> { - boolean value = arg[0].equalsIgnoreCase("on"); - Core.settings.put("logging", value); - Core.settings.save(); - info("Logging is now {0}.", value ? "on" : "off"); - }); - - handler.register("strict", "", "Disables or enables strict mode", arg -> { - boolean value = arg[0].equalsIgnoreCase("on"); - netServer.admins.setStrict(value); - info("Strict mode is now {0}.", netServer.admins.getStrict() ? "on" : "off"); - }); - - handler.register("socketinput", "[on/off]", "Disables or enables a local TCP socket at port "+commandSocketPort+" to recieve commands from other applications", arg -> { - if(arg.length == 0){ - info("Socket input is currently &lc{0}.", Core.settings.getBool("socket") ? "on" : "off"); - return; - } - - boolean value = arg[0].equalsIgnoreCase("on"); - toggleSocket(value); - Core.settings.put("socket", value); - Core.settings.save(); - info("Socket input is now &lc{0}.", value ? "on" : "off"); - }); - - handler.register("allow-custom-clients", "[on/off]", "Allow or disallow custom clients.", arg -> { - if(arg.length == 0){ - info("Custom clients are currently &lc{0}.", netServer.admins.allowsCustomClients() ? "allowed" : "disallowed"); - return; - } - - String s = arg[0]; - if(s.equalsIgnoreCase("on")){ - netServer.admins.setCustomClients(true); - info("Custom clients enabled."); - }else if(s.equalsIgnoreCase("off")){ - netServer.admins.setCustomClients(false); - info("Custom clients disabled."); - }else{ - err("Incorrect command usage."); - } - }); - handler.register("shuffle", "[none/all/custom/builtin]", "Set map shuffling mode.", arg -> { if(arg.length == 0){ info("Shuffle mode current set to &ly'{0}'&lg.", maps.getShuffleMode()); @@ -933,8 +871,8 @@ public class ServerControl implements ApplicationListener{ private void host(){ try{ - net.host(Core.settings.getInt("port")); - info("&lcOpened a server on port {0}.", Core.settings.getInt("port")); + net.host(Config.port.num()); + info("&lcOpened a server on port {0}.", Config.port.num()); }catch(BindException e){ Log.err("Unable to host: Port already in use! Make sure no other servers are running on the same port in your network."); state.set(State.menu); @@ -968,7 +906,7 @@ public class ServerControl implements ApplicationListener{ socketThread = new Thread(() -> { try{ serverSocket = new ServerSocket(); - serverSocket.bind(new InetSocketAddress("localhost", commandSocketPort)); + serverSocket.bind(new InetSocketAddress(Config.socketInputAddress.string(), Config.socketInputPort.num())); while(true){ Socket client = serverSocket.accept(); info("&lmRecieved command socket connection: &lb{0}", serverSocket.getLocalSocketAddress()); From 179bf4d525dbe3f4bf23df9e837a95f7b291fc70 Mon Sep 17 00:00:00 2001 From: Anuken Date: Sat, 28 Dec 2019 16:34:35 -0500 Subject: [PATCH 19/78] Added BE-specific server list --- core/src/mindustry/Vars.java | 4 +++- core/src/mindustry/net/BeControl.java | 3 ++- core/src/mindustry/ui/dialogs/JoinDialog.java | 2 +- servers_be.json | 1 + 4 files changed, 7 insertions(+), 3 deletions(-) create mode 100644 servers_be.json diff --git a/core/src/mindustry/Vars.java b/core/src/mindustry/Vars.java index 2cfa4bad45..80e6241e09 100644 --- a/core/src/mindustry/Vars.java +++ b/core/src/mindustry/Vars.java @@ -54,8 +54,10 @@ public class Vars implements Loadable{ public static final String crashReportURL = "http://192.99.169.18/report"; /** URL the links to the wiki's modding guide.*/ public static final String modGuideURL = "https://mindustrygame.github.io/wiki/modding/"; - /** URL to the JSON file containing all the global, public servers. */ + /** URL to the JSON file containing all the global, public servers. Not queried in BE. */ public static final String serverJsonURL = "https://raw.githubusercontent.com/Anuken/Mindustry/master/servers.json"; + /** URL to the JSON file containing all the BE servers. Only queried in BE. */ + public static final String serverJsonBeURL = "https://raw.githubusercontent.com/Anuken/Mindustry/master/servers_be.json"; /** URL the links to the wiki's modding guide.*/ public static final String reportIssueURL = "https://github.com/Anuken/Mindustry/issues/new?template=bug_report.md"; /** list of built-in servers.*/ diff --git a/core/src/mindustry/net/BeControl.java b/core/src/mindustry/net/BeControl.java index d81c5e721d..4de581108f 100644 --- a/core/src/mindustry/net/BeControl.java +++ b/core/src/mindustry/net/BeControl.java @@ -117,6 +117,7 @@ public class BeControl{ Log.info("&lcAuto-downloading next version..."); try{ + //download new file from github Fi source = Fi.get(BeControl.class.getProtectionDomain().getCodeSource().getLocation().toURI().getPath()); Fi dest = source.sibling("server-be-" + updateBuild + ".jar"); @@ -126,6 +127,7 @@ public class BeControl{ () -> false, () -> { Log.info("&lcVersion downloaded, exiting. Note that if you are not using the run-server script, the server will not restart automatically."); + //replace old file with new dest.copyTo(source); dest.delete(); System.exit(2); //this will cause a restart if using the script @@ -136,7 +138,6 @@ public class BeControl{ } } checkUpdates = false; - //todo server updates } } diff --git a/core/src/mindustry/ui/dialogs/JoinDialog.java b/core/src/mindustry/ui/dialogs/JoinDialog.java index 4c8ae3cc58..8984939bcf 100644 --- a/core/src/mindustry/ui/dialogs/JoinDialog.java +++ b/core/src/mindustry/ui/dialogs/JoinDialog.java @@ -362,7 +362,7 @@ public class JoinDialog extends FloatingDialog{ servers = Core.settings.getObject("server-list", Array.class, Array::new); //get servers - Core.net.httpGet(serverJsonURL, result -> { + Core.net.httpGet(becontrol.active() ? serverJsonBeURL : serverJsonURL, result -> { try{ Jval val = Jval.read(result.getResultAsString()); Core.app.post(() -> { diff --git a/servers_be.json b/servers_be.json new file mode 100644 index 0000000000..0637a088a0 --- /dev/null +++ b/servers_be.json @@ -0,0 +1 @@ +[] \ No newline at end of file From d3c559fa0061a26963e0daeee6261331f77dda19 Mon Sep 17 00:00:00 2001 From: Anuken Date: Sat, 28 Dec 2019 17:33:17 -0500 Subject: [PATCH 20/78] Moved server run scripts --- core/src/mindustry/net/Administration.java | 2 +- core/src/mindustry/net/BeControl.java | 2 +- server/run-jar | 19 +++++++++++++++++++ run-server => server/run-server | 11 ++++++++++- 4 files changed, 31 insertions(+), 3 deletions(-) create mode 100755 server/run-jar rename run-server => server/run-server (81%) diff --git a/core/src/mindustry/net/Administration.java b/core/src/mindustry/net/Administration.java index 157566a5c3..268e8d089f 100644 --- a/core/src/mindustry/net/Administration.java +++ b/core/src/mindustry/net/Administration.java @@ -319,7 +319,7 @@ public class Administration{ public enum Config{ name("The server name as displayed on clients.", "Server", "servername"), port("The port to host on.", Vars.port), - autoUpdate("Whether to auto-restart when a new update arrives.", false), + autoUpdate("Whether to auto-update and exit when a new bleeding-edge update arrives.", false), crashReport("Whether to send crash reports.", false, "crashreport"), logging("Whether to log everything to files.", true), strict("Whether strict mode is on - corrects positions and prevents duplicate UUIDs.", true), diff --git a/core/src/mindustry/net/BeControl.java b/core/src/mindustry/net/BeControl.java index 4de581108f..bce61a1663 100644 --- a/core/src/mindustry/net/BeControl.java +++ b/core/src/mindustry/net/BeControl.java @@ -126,7 +126,7 @@ public class BeControl{ progress -> {}, () -> false, () -> { - Log.info("&lcVersion downloaded, exiting. Note that if you are not using the run-server script, the server will not restart automatically."); + Log.info("&lcVersion downloaded, exiting. Note that if you are not using a auto-restart script, the server will not restart automatically."); //replace old file with new dest.copyTo(source); dest.delete(); diff --git a/server/run-jar b/server/run-jar new file mode 100755 index 0000000000..2ab341566f --- /dev/null +++ b/server/run-jar @@ -0,0 +1,19 @@ +#!/usr/bin/env bash +if [[ $# -eq 0 ]] ; then + echo 'A server jar must be supplied as the first argument.' + exit 1 +fi + +if [[ ! -e $1 ]] ; then + echo "The supplied jar file '$1' must exist." + exit 1 +fi + +while true; do +#auto-restart until ctrl-c or exit 0 +java -jar -XX:+HeapDumpOnOutOfMemoryError $1 +excode=$? +if [ $excode -eq 0 ] || [ $excode -eq 130 ]; then + exit 0 +fi +done diff --git a/run-server b/server/run-server similarity index 81% rename from run-server rename to server/run-server index 25a8254723..4e337686a0 100755 --- a/run-server +++ b/server/run-server @@ -4,13 +4,22 @@ if [[ $# -eq 0 ]] ; then exit 1 fi +cd .. + ./gradlew server:dist -Pbuildversion=$1 +excode=$? + +if [ $excode -ne 0 ]; then + echo $excode + exit 1 +fi + while true; do #auto-restart until ctrl-c or exit 0 java -jar -XX:+HeapDumpOnOutOfMemoryError server/build/libs/server-release.jar excode=$? if [ $excode -eq 0 ] || [ $excode -eq 130 ]; then - exit 0 + exit 0 fi done From e0f59404c1ac46c7e074fa91428b64696a164a4a Mon Sep 17 00:00:00 2001 From: Anuken Date: Sat, 28 Dec 2019 17:49:49 -0500 Subject: [PATCH 21/78] Added BE server --- servers_be.json | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/servers_be.json b/servers_be.json index 0637a088a0..be72d9d6da 100644 --- a/servers_be.json +++ b/servers_be.json @@ -1 +1,5 @@ -[] \ No newline at end of file +[ + { + "address": "mindustry.us.to:6568" + } +] \ No newline at end of file From 60d83751e87122d1e80ebedceda61ef5b3168218 Mon Sep 17 00:00:00 2001 From: Anuken Date: Sat, 28 Dec 2019 17:55:00 -0500 Subject: [PATCH 22/78] Fixed server port not being parsed --- core/src/mindustry/ui/dialogs/JoinDialog.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/core/src/mindustry/ui/dialogs/JoinDialog.java b/core/src/mindustry/ui/dialogs/JoinDialog.java index 8984939bcf..8ab0ff8fd2 100644 --- a/core/src/mindustry/ui/dialogs/JoinDialog.java +++ b/core/src/mindustry/ui/dialogs/JoinDialog.java @@ -288,7 +288,13 @@ public class JoinDialog extends FloatingDialog{ local.table(Tex.button, t -> t.label(() -> "[accent]" + Core.bundle.get("hosts.discovering.any") + Strings.animated(Time.time(), 4, 10f, ".")).pad(10f)).growX(); net.discoverServers(this::addLocalHost, this::finishLocalHosts); for(String host : defaultServers){ - net.pingHost(host, port, this::addLocalHost, e -> {}); + String address = host; + int p = port; + if(host.contains(":")){ + address = host.split(":")[0]; + p = Strings.parseInt(host.split(":")[1]); + } + net.pingHost(address, p, this::addLocalHost, e -> {}); } } From 7543d92473e79d3957740cc07523d05adfe186c1 Mon Sep 17 00:00:00 2001 From: Anuken Date: Sat, 28 Dec 2019 18:05:45 -0500 Subject: [PATCH 23/78] Added startup commands to server --- core/src/mindustry/net/Administration.java | 1 + server/src/mindustry/server/ServerControl.java | 15 ++++++++++----- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/core/src/mindustry/net/Administration.java b/core/src/mindustry/net/Administration.java index 268e8d089f..57a728a020 100644 --- a/core/src/mindustry/net/Administration.java +++ b/core/src/mindustry/net/Administration.java @@ -320,6 +320,7 @@ public class Administration{ name("The server name as displayed on clients.", "Server", "servername"), port("The port to host on.", Vars.port), autoUpdate("Whether to auto-update and exit when a new bleeding-edge update arrives.", false), + startCommands("Commands run at startup. This should be a comma-separated list.", ""), crashReport("Whether to send crash reports.", false, "crashreport"), logging("Whether to log everything to files.", true), strict("Whether strict mode is on - corrects positions and prevents duplicate UUIDs.", true), diff --git a/server/src/mindustry/server/ServerControl.java b/server/src/mindustry/server/ServerControl.java index f1dbb59803..619004f79f 100644 --- a/server/src/mindustry/server/ServerControl.java +++ b/server/src/mindustry/server/ServerControl.java @@ -90,11 +90,17 @@ public class ServerControl implements ApplicationListener{ registerCommands(); Core.app.post(() -> { - String[] commands = {}; + Array commands = new Array<>(); if(args.length > 0){ - commands = Strings.join(" ", args).split(","); - info("&lmFound {0} command-line arguments to parse.", commands.length); + commands.addAll(Strings.join(" ", args).split(",")); + info("&lmFound {0} command-line arguments to parse.", commands.size); + } + + if(!Config.startCommands.string().isEmpty()){ + String[] startup = Strings.join(" ", Config.startCommands.string()).split(","); + info("&lmFound {0} startup commands.", startup.length); + commands.addAll(startup); } for(String s : commands){ @@ -102,7 +108,6 @@ public class ServerControl implements ApplicationListener{ if(response.type != ResponseType.valid){ err("Invalid command argument sent: '{0}': {1}", s, response.type.name()); err("Argument usage: &lc , "); - System.exit(1); } } }); @@ -443,7 +448,7 @@ public class ServerControl implements ApplicationListener{ } }); - handler.register("config", "[name] [value]", "Configure server settings.", arg -> { + handler.register("config", "[name] [value...]", "Configure server settings.", arg -> { if(arg.length == 0){ info("&lyAll config values:"); for(Config c : Config.all){ From 497ae740aae893c8e842eccead533eddac2a7fd9 Mon Sep 17 00:00:00 2001 From: Anuken Date: Sat, 28 Dec 2019 18:12:34 -0500 Subject: [PATCH 24/78] Removed pointless "> " --- core/src/mindustry/net/BeControl.java | 1 + server/src/mindustry/server/ServerControl.java | 3 --- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/core/src/mindustry/net/BeControl.java b/core/src/mindustry/net/BeControl.java index bce61a1663..76fa81f310 100644 --- a/core/src/mindustry/net/BeControl.java +++ b/core/src/mindustry/net/BeControl.java @@ -84,6 +84,7 @@ public class BeControl{ if(!updateAvailable) return; if(!headless){ + checkUpdates = false; ui.showCustomConfirm(Core.bundle.format("be.update", "") + " " + updateBuild, "$be.update.confirm", "$ok", "$be.ignore", () -> { boolean[] cancel = {false}; float[] progress = {0}; diff --git a/server/src/mindustry/server/ServerControl.java b/server/src/mindustry/server/ServerControl.java index 619004f79f..655e7951b5 100644 --- a/server/src/mindustry/server/ServerControl.java +++ b/server/src/mindustry/server/ServerControl.java @@ -170,7 +170,6 @@ public class ServerControl implements ApplicationListener{ toggleSocket(Config.socketInput.bool()); info("&lcServer loaded. Type &ly'help'&lc for help."); - System.out.print("> "); } private void registerCommands(){ @@ -822,8 +821,6 @@ public class ServerControl implements ApplicationListener{ }else if(response.type == ResponseType.manyArguments){ err("Too many command arguments. Usage: " + response.command.text + " " + response.command.paramText); } - - System.out.print("> "); } private void play(boolean wait, Runnable run){ From b01d56aae84bfd3282d23248642058c3ec6448f4 Mon Sep 17 00:00:00 2001 From: Anuken Date: Sat, 28 Dec 2019 18:22:20 -0500 Subject: [PATCH 25/78] Bugfixes --- core/src/mindustry/net/Host.java | 3 ++- core/src/mindustry/ui/dialogs/JoinDialog.java | 15 +++++++-------- server/src/mindustry/server/ServerControl.java | 2 +- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/core/src/mindustry/net/Host.java b/core/src/mindustry/net/Host.java index 387fafc043..5c3b010c45 100644 --- a/core/src/mindustry/net/Host.java +++ b/core/src/mindustry/net/Host.java @@ -1,5 +1,6 @@ package mindustry.net; +import mindustry.*; import mindustry.game.*; public class Host{ @@ -11,7 +12,7 @@ public class Host{ public final int version; public final String versionType; public final Gamemode mode; - public int ping; + public int ping, port = Vars.port; public Host(String name, String address, String mapname, int wave, int players, int version, String versionType, Gamemode mode, int playerLimit){ this.name = name; diff --git a/core/src/mindustry/ui/dialogs/JoinDialog.java b/core/src/mindustry/ui/dialogs/JoinDialog.java index 8ab0ff8fd2..d3e154b3b1 100644 --- a/core/src/mindustry/ui/dialogs/JoinDialog.java +++ b/core/src/mindustry/ui/dialogs/JoinDialog.java @@ -288,13 +288,12 @@ public class JoinDialog extends FloatingDialog{ local.table(Tex.button, t -> t.label(() -> "[accent]" + Core.bundle.get("hosts.discovering.any") + Strings.animated(Time.time(), 4, 10f, ".")).pad(10f)).growX(); net.discoverServers(this::addLocalHost, this::finishLocalHosts); for(String host : defaultServers){ - String address = host; - int p = port; - if(host.contains(":")){ - address = host.split(":")[0]; - p = Strings.parseInt(host.split(":")[1]); - } - net.pingHost(address, p, this::addLocalHost, e -> {}); + String resaddress = host.contains(":") ? host.split(":")[0] : host; + int resport = host.contains(":") ? Strings.parseInt(host.split(":")[1]) : port; + net.pingHost(resaddress, resport, res -> { + res.port = resport; + addLocalHost(res); + }, e -> {}); } } @@ -320,7 +319,7 @@ public class JoinDialog extends FloatingDialog{ local.row(); - TextButton button = local.addButton("", Styles.cleart, () -> safeConnect(host.address, port, host.version)) + TextButton button = local.addButton("", Styles.cleart, () -> safeConnect(host.address, host.port, host.version)) .width(w).pad(5f).get(); button.clearChildren(); buildServer(host, button); diff --git a/server/src/mindustry/server/ServerControl.java b/server/src/mindustry/server/ServerControl.java index 655e7951b5..df70cf3c0a 100644 --- a/server/src/mindustry/server/ServerControl.java +++ b/server/src/mindustry/server/ServerControl.java @@ -461,7 +461,7 @@ public class ServerControl implements ApplicationListener{ try{ Config c = Config.valueOf(arg[0]); if(arg.length == 1){ - Log.info("&lc'{0}'&lg is currently &lc{0}.", c.name(), c.get()); + Log.info("&lc'{0}'&lg is currently &lc{1}.", c.name(), c.get()); }else{ if(c.isBool()){ c.set(arg[1].equals("on") || arg[1].equals("true")); From 8c941c7165d100dc1952e65fbed254dd0757d8d9 Mon Sep 17 00:00:00 2001 From: Anuken Date: Sat, 28 Dec 2019 21:34:20 -0500 Subject: [PATCH 26/78] Added update trigger / Server moddability tweaks --- core/assets/bundles/bundle.properties | 1 + core/src/mindustry/core/Logic.java | 3 ++- core/src/mindustry/core/NetServer.java | 1 - core/src/mindustry/game/EventType.java | 3 ++- core/src/mindustry/game/Rules.java | 2 ++ core/src/mindustry/net/BeControl.java | 8 +++++-- core/src/mindustry/net/Packets.java | 3 ++- .../src/mindustry/server/ServerControl.java | 24 +++++++++---------- 8 files changed, 26 insertions(+), 19 deletions(-) diff --git a/core/assets/bundles/bundle.properties b/core/assets/bundles/bundle.properties index 2b2a1aa548..0ee7e3bd4e 100644 --- a/core/assets/bundles/bundle.properties +++ b/core/assets/bundles/bundle.properties @@ -155,6 +155,7 @@ server.kicked.nameEmpty = Your chosen name is invalid. server.kicked.idInUse = You are already on this server! Connecting with two accounts is not permitted. server.kicked.customClient = This server does not support custom builds. Download an official version. server.kicked.gameover = Game over! +server.kicked.serverRestarting = The server is restarting. server.versions = Your version:[accent] {0}[]\nServer version:[accent] {1}[] host.info = The [accent]host[] button hosts a server on port [scarlet]6567[]. \nAnybody on the same [lightgray]wifi or local network[] should be able to see your server in their server list.\n\nIf you want people to be able to connect from anywhere by IP, [accent]port forwarding[] is required.\n\n[lightgray]Note: If someone is experiencing trouble connecting to your LAN game, make sure you have allowed Mindustry access to your local network in your firewall settings. Note that public networks sometimes do not allow server discovery. join.info = Here, you can enter a [accent]server IP[] to connect to, or discover [accent]local network[] servers to connect to.\nBoth LAN and WAN multiplayer is supported.\n\n[lightgray]Note: There is no automatic global server list; if you want to connect to someone by IP, you would need to ask the host for their IP. diff --git a/core/src/mindustry/core/Logic.java b/core/src/mindustry/core/Logic.java index 17fedab303..12761439b7 100644 --- a/core/src/mindustry/core/Logic.java +++ b/core/src/mindustry/core/Logic.java @@ -209,6 +209,7 @@ public class Logic implements ApplicationListener{ @Override public void update(){ + Events.fire(Trigger.update); if(!state.is(State.menu)){ if(!net.client()){ @@ -260,7 +261,7 @@ public class Logic implements ApplicationListener{ } } - if(!net.client() && !world.isInvalidMap() && !state.isEditor()){ + if(!net.client() && !world.isInvalidMap() && !state.isEditor() && !state.rules.canGameOver){ checkGameOver(); } } diff --git a/core/src/mindustry/core/NetServer.java b/core/src/mindustry/core/NetServer.java index c74f14211c..a355ecbd76 100644 --- a/core/src/mindustry/core/NetServer.java +++ b/core/src/mindustry/core/NetServer.java @@ -217,7 +217,6 @@ public class NetServer implements ApplicationListener{ //playing in pvp mode automatically assigns players to teams player.setTeam(assignTeam(player, playerGroup.all())); - Log.info("Auto-assigned player {0} to team {1}.", player.name, player.getTeam()); sendWorldData(player); diff --git a/core/src/mindustry/game/EventType.java b/core/src/mindustry/game/EventType.java index 6cbaba5e4b..5a9950b489 100644 --- a/core/src/mindustry/game/EventType.java +++ b/core/src/mindustry/game/EventType.java @@ -29,7 +29,8 @@ public class EventType{ suicideBomb, openWiki, teamCoreDamage, - socketConfigChanged + socketConfigChanged, + update } public static class WinEvent{} diff --git a/core/src/mindustry/game/Rules.java b/core/src/mindustry/game/Rules.java index 93ceaf5cfe..06231e5318 100644 --- a/core/src/mindustry/game/Rules.java +++ b/core/src/mindustry/game/Rules.java @@ -70,6 +70,8 @@ public class Rules{ public boolean editor = false; /** Whether the tutorial is enabled. False by default. */ public boolean tutorial = false; + /** Whether a gameover can happen at all. Set this to false to implement custom gameover conditions. */ + public boolean canGameOver = true; /** Starting items put in cores */ public Array loadout = Array.with(ItemStack.with(Items.copper, 100)); /** Blocks that cannot be placed. */ diff --git a/core/src/mindustry/net/BeControl.java b/core/src/mindustry/net/BeControl.java index 76fa81f310..13f645b996 100644 --- a/core/src/mindustry/net/BeControl.java +++ b/core/src/mindustry/net/BeControl.java @@ -11,6 +11,7 @@ import mindustry.core.*; import mindustry.gen.*; import mindustry.graphics.*; import mindustry.net.Administration.*; +import mindustry.net.Packets.*; import mindustry.ui.*; import mindustry.ui.dialogs.*; @@ -126,13 +127,16 @@ public class BeControl{ len -> Core.app.post(() -> Log.info("&ly| Size: {0} MB.", Strings.fixed((float)len / 1024 / 1024, 2))), progress -> {}, () -> false, - () -> { + () -> Core.app.post(() -> { + netServer.kickAll(KickReason.serverRestarting); + Threads.sleep(32); + Log.info("&lcVersion downloaded, exiting. Note that if you are not using a auto-restart script, the server will not restart automatically."); //replace old file with new dest.copyTo(source); dest.delete(); System.exit(2); //this will cause a restart if using the script - }, + }), Throwable::printStackTrace); }catch(Exception e){ e.printStackTrace(); diff --git a/core/src/mindustry/net/Packets.java b/core/src/mindustry/net/Packets.java index 683983d69b..98a3bad857 100644 --- a/core/src/mindustry/net/Packets.java +++ b/core/src/mindustry/net/Packets.java @@ -15,7 +15,8 @@ public class Packets{ public enum KickReason{ kick, clientOutdated, serverOutdated, banned, gameover(true), recentKick, - nameInUse, idInUse, nameEmpty, customClient, serverClose, vote, typeMismatch, whitelist, playerLimit; + nameInUse, idInUse, nameEmpty, customClient, serverClose, vote, typeMismatch, + whitelist, playerLimit, serverRestarting; public final boolean quiet; diff --git a/server/src/mindustry/server/ServerControl.java b/server/src/mindustry/server/ServerControl.java index df70cf3c0a..094d020e78 100644 --- a/server/src/mindustry/server/ServerControl.java +++ b/server/src/mindustry/server/ServerControl.java @@ -163,6 +163,15 @@ public class ServerControl implements ApplicationListener{ toggleSocket(Config.socketInput.bool()); }); + Events.on(PlayEvent.class, e -> { + try{ + JsonValue value = JsonIO.json().fromJson(null, Core.settings.getString("globalrules")); + JsonIO.json().readFields(state.rules, value); + }catch(Throwable t){ + Log.err("Error applying custom rules, proceeding without them.", t); + } + }); + if(!mods.list().isEmpty()){ info("&lc{0} mods loaded.", mods.list().size); } @@ -238,7 +247,6 @@ public class ServerControl implements ApplicationListener{ try{ world.loadMap(result, result.applyRules(lastMode)); state.rules = result.applyRules(preset); - applyRules(); logic.play(); info("Map loaded."); @@ -390,7 +398,7 @@ public class ServerControl implements ApplicationListener{ base.addChild(arg[1], value); Log.info("Changed rule: &ly{0}", value.toString().replace("\n", " ")); }catch(Throwable e){ - Log.err("Error parsing rule JSON", e); + Log.err("Error parsing rule JSON: {0}", e.getMessage()); } } @@ -777,15 +785,6 @@ public class ServerControl implements ApplicationListener{ mods.eachClass(p -> p.registerClientCommands(netServer.clientCommands)); } - private void applyRules(){ - try{ - JsonValue value = JsonIO.json().fromJson(null, Core.settings.getString("globalrules")); - JsonIO.json().readFields(state.rules, value); - }catch(Throwable t){ - Log.err("Error applying custom rules, proceeding without them.", t); - } - } - private void readCommands(){ Scanner scan = new Scanner(System.in); @@ -836,9 +835,8 @@ public class ServerControl implements ApplicationListener{ Call.onWorldDataBegin(); run.run(); - logic.play(); state.rules = world.getMap().applyRules(lastMode); - applyRules(); + logic.play(); for(Player p : players){ if(p.con == null) continue; From df4a0dd5e4b40c2ad4b97ddfa31d3e177b7b11f4 Mon Sep 17 00:00:00 2001 From: Anuken Date: Sat, 28 Dec 2019 22:18:16 -0500 Subject: [PATCH 27/78] Added openServer method --- core/src/mindustry/core/NetServer.java | 21 +++++++++++++++++-- .../src/mindustry/server/ServerControl.java | 17 ++------------- 2 files changed, 21 insertions(+), 17 deletions(-) diff --git a/core/src/mindustry/core/NetServer.java b/core/src/mindustry/core/NetServer.java index a355ecbd76..b37ab7a57a 100644 --- a/core/src/mindustry/core/NetServer.java +++ b/core/src/mindustry/core/NetServer.java @@ -1,14 +1,14 @@ package mindustry.core; import arc.*; -import mindustry.annotations.Annotations.*; -import arc.struct.*; import arc.graphics.*; import arc.math.*; import arc.math.geom.*; +import arc.struct.*; import arc.util.*; import arc.util.CommandHandler.*; import arc.util.io.*; +import mindustry.annotations.Annotations.*; import mindustry.content.*; import mindustry.core.GameState.*; import mindustry.entities.*; @@ -26,9 +26,11 @@ import mindustry.world.*; import mindustry.world.blocks.storage.CoreBlock.*; import java.io.*; +import java.net.*; import java.nio.*; import java.util.zip.*; +import static arc.util.Log.*; import static mindustry.Vars.*; public class NetServer implements ApplicationListener{ @@ -598,6 +600,7 @@ public class NetServer implements ApplicationListener{ return false; } + @Override public void update(){ if(!headless && !closing && net.server() && state.is(State.menu)){ @@ -615,6 +618,20 @@ public class NetServer implements ApplicationListener{ } } + /** Should only be used on the headless backend. */ + public void openServer(){ + try{ + net.host(Config.port.num()); + info("&lcOpened a server on port {0}.", Config.port.num()); + }catch(BindException e){ + Log.err("Unable to host: Port already in use! Make sure no other servers are running on the same port in your network."); + state.set(State.menu); + }catch(IOException e){ + err(e); + state.set(State.menu); + } + } + public void kickAll(KickReason reason){ for(NetConnection con : net.getConnections()){ con.kick(reason); diff --git a/server/src/mindustry/server/ServerControl.java b/server/src/mindustry/server/ServerControl.java index 094d020e78..352331f80c 100644 --- a/server/src/mindustry/server/ServerControl.java +++ b/server/src/mindustry/server/ServerControl.java @@ -251,7 +251,7 @@ public class ServerControl implements ApplicationListener{ info("Map loaded."); - host(); + netServer.openServer(); }catch(MapException e){ Log.err(e.map.name() + ": " + e.getMessage()); } @@ -711,8 +711,8 @@ public class ServerControl implements ApplicationListener{ SaveIO.load(file); state.rules.zone = null; info("Save loaded."); - host(); state.set(State.playing); + netServer.openServer(); }catch(Throwable t){ err("Failed to load save. Outdated or corrupt file."); } @@ -869,19 +869,6 @@ public class ServerControl implements ApplicationListener{ } } - private void host(){ - try{ - net.host(Config.port.num()); - info("&lcOpened a server on port {0}.", Config.port.num()); - }catch(BindException e){ - Log.err("Unable to host: Port already in use! Make sure no other servers are running on the same port in your network."); - state.set(State.menu); - }catch(IOException e){ - err(e); - state.set(State.menu); - } - } - private void logToFile(String text){ if(currentLogFile != null && currentLogFile.length() > maxLogLength){ String date = DateTimeFormatter.ofPattern("MM-dd-yyyy | HH:mm:ss").format(LocalDateTime.now()); From 77b89d45d69f811c92d1124a25f3d23563638a54 Mon Sep 17 00:00:00 2001 From: Anuken Date: Sun, 29 Dec 2019 00:09:46 -0500 Subject: [PATCH 28/78] Cleanup / Desktop dead camera panning --- core/src/mindustry/core/Renderer.java | 2 +- core/src/mindustry/entities/EntityGroup.java | 11 ++++++++-- core/src/mindustry/input/DesktopInput.java | 7 +++++++ .../world/blocks/defense/ForceProjector.java | 21 ++----------------- gradle.properties | 2 +- 5 files changed, 20 insertions(+), 23 deletions(-) diff --git a/core/src/mindustry/core/Renderer.java b/core/src/mindustry/core/Renderer.java index d4983e992a..9c284a5f06 100644 --- a/core/src/mindustry/core/Renderer.java +++ b/core/src/mindustry/core/Renderer.java @@ -125,7 +125,7 @@ public class Renderer implements ApplicationListener{ TileEntity core = player.getClosestCore(); if(core != null && player.spawner == null){ camera.position.lerpDelta(core.x, core.y, 0.08f); - }else{ + }else if(core != null){ camera.position.lerpDelta(position, 0.08f); } }else if(control.input instanceof DesktopInput){ diff --git a/core/src/mindustry/entities/EntityGroup.java b/core/src/mindustry/entities/EntityGroup.java index 8c0ac76442..24c3f0e4f0 100644 --- a/core/src/mindustry/entities/EntityGroup.java +++ b/core/src/mindustry/entities/EntityGroup.java @@ -7,11 +7,13 @@ import arc.graphics.*; import arc.math.geom.*; import mindustry.entities.traits.*; +import java.util.*; + import static mindustry.Vars.collisions; /** Represents a group of a certain type of entity.*/ @SuppressWarnings("unchecked") -public class EntityGroup{ +public class EntityGroup implements Iterable{ private final boolean useTree; private final int id; private final Class type; @@ -253,8 +255,13 @@ public class EntityGroup{ return null; } - /** Returns the logic-only array for iteration. */ + /** Returns the array for iteration. */ public Array all(){ return entityArray; } + + @Override + public Iterator iterator(){ + return entityArray.iterator(); + } } diff --git a/core/src/mindustry/input/DesktopInput.java b/core/src/mindustry/input/DesktopInput.java index c76968a56e..df735999d8 100644 --- a/core/src/mindustry/input/DesktopInput.java +++ b/core/src/mindustry/input/DesktopInput.java @@ -10,6 +10,7 @@ import arc.scene.event.*; import arc.scene.ui.*; import arc.scene.ui.layout.*; import arc.util.ArcAnnotate.*; +import arc.util.*; import mindustry.*; import mindustry.core.GameState.*; import mindustry.entities.traits.BuilderTrait.*; @@ -135,6 +136,12 @@ public class DesktopInput extends InputHandler{ ui.listfrag.toggle(); } + if(player.getClosestCore() == null){ + //move camera around + float camSpeed = 6f; + Core.camera.position.add(Tmp.v1.setZero().add(Core.input.axis(Binding.move_x), Core.input.axis(Binding.move_y)).nor().scl(Time.delta() * camSpeed)); + } + if(Core.input.keyRelease(Binding.select)){ player.isShooting = false; } diff --git a/core/src/mindustry/world/blocks/defense/ForceProjector.java b/core/src/mindustry/world/blocks/defense/ForceProjector.java index a417c2b9e5..36ed812b5d 100644 --- a/core/src/mindustry/world/blocks/defense/ForceProjector.java +++ b/core/src/mindustry/world/blocks/defense/ForceProjector.java @@ -5,6 +5,7 @@ import arc.func.*; import arc.graphics.*; import arc.graphics.g2d.*; import arc.math.*; +import arc.math.geom.*; import arc.util.*; import mindustry.content.*; import mindustry.entities.*; @@ -37,7 +38,7 @@ public class ForceProjector extends Block{ private static ForceProjector paramBlock; private static ForceEntity paramEntity; private static Cons shieldConsumer = trait -> { - if(trait.canBeAbsorbed() && trait.getTeam() != paramTile.getTeam() && paramBlock.isInsideHexagon(trait.getX(), trait.getY(), paramBlock.realRadius(paramEntity) * 2f, paramTile.drawx(), paramTile.drawy())){ + if(trait.canBeAbsorbed() && trait.getTeam() != paramTile.getTeam() && Intersector.isInsideHexagon(trait.getX(), trait.getY(), paramBlock.realRadius(paramEntity) * 2f, paramTile.drawx(), paramTile.drawy())){ trait.absorb(); Effects.effect(Fx.absorb, trait); paramEntity.hit = 1f; @@ -111,17 +112,6 @@ public class ForceProjector extends Block{ entity.warmup = Mathf.lerpDelta(entity.warmup, entity.efficiency(), 0.1f); -/* - if(entity.power.status < relativePowerDraw){ - entity.warmup = Mathf.lerpDelta(entity.warmup, 0f, 0.15f); - entity.power.status = 0f; - if(entity.warmup <= 0.09f){ - entity.broken = true; - } - }else{ - entity.warmup = Mathf.lerpDelta(entity.warmup, 1f, 0.1f); - }*/ - if(entity.buildup > 0){ float scale = !entity.broken ? cooldownNormal : cooldownBrokenBase; ConsumeLiquidFilter cons = consumes.get(ConsumeType.liquid); @@ -159,13 +149,6 @@ public class ForceProjector extends Block{ return (radius + entity.phaseHeat * phaseRadiusBoost) * entity.radscl; } - boolean isInsideHexagon(float x0, float y0, float d, float x, float y){ - float dx = Math.abs(x - x0) / d; - float dy = Math.abs(y - y0) / d; - float a = 0.25f * Mathf.sqrt3; - return (dy <= a) && (a * dx + 0.25 * dy <= 0.5 * a); - } - @Override public void draw(Tile tile){ super.draw(tile); diff --git a/gradle.properties b/gradle.properties index 0b0bc673e4..51de1f3142 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,3 +1,3 @@ org.gradle.daemon=true org.gradle.jvmargs=-Xms256m -Xmx1024m -archash=0e25944f7f3a065ed6707f0dbe48548980cad8a6 +archash=fe82ca9037028044764cc4b02fdbf851e3d09f78 From e04c592f9eae9aa047b1b28a1589544f155b41da Mon Sep 17 00:00:00 2001 From: Anuken Date: Sun, 29 Dec 2019 00:40:25 -0500 Subject: [PATCH 29/78] Bugfixes --- core/src/mindustry/graphics/MinimapRenderer.java | 1 + core/src/mindustry/net/BeControl.java | 3 +-- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core/src/mindustry/graphics/MinimapRenderer.java b/core/src/mindustry/graphics/MinimapRenderer.java index 60f3d2974b..5d8af45304 100644 --- a/core/src/mindustry/graphics/MinimapRenderer.java +++ b/core/src/mindustry/graphics/MinimapRenderer.java @@ -82,6 +82,7 @@ public class MinimapRenderer implements Disposable{ rect.set((dx - sz) * tilesize, (dy - sz) * tilesize, sz * 2 * tilesize, sz * 2 * tilesize); for(Unit unit : units){ + if(unit.isDead()) continue; float rx = (unit.x - rect.x) / rect.width * w; float ry = (unit.y - rect.y) / rect.width * h; diff --git a/core/src/mindustry/net/BeControl.java b/core/src/mindustry/net/BeControl.java index 13f645b996..ee084f743a 100644 --- a/core/src/mindustry/net/BeControl.java +++ b/core/src/mindustry/net/BeControl.java @@ -22,7 +22,7 @@ import static mindustry.Vars.*; /** Handles control of bleeding edge builds. */ public class BeControl{ - private static final int updateInterval = 60; + private static final int updateInterval = 60 * 2; private AsyncExecutor executor = new AsyncExecutor(1); private boolean checkUpdates = true; @@ -64,7 +64,6 @@ public class BeControl{ } }else{ Core.app.post(() -> done.get(false)); - Log.err("Update check responded with: {0}", res.getStatus()); } }, error -> { if(!headless){ From 730d30ef9829fb3e54032e694c4af464ce5860b2 Mon Sep 17 00:00:00 2001 From: Anuken Date: Sun, 29 Dec 2019 11:40:52 -0500 Subject: [PATCH 30/78] Added core schematic selection setting --- core/assets/bundles/bundle.properties | 1 + core/src/mindustry/content/Blocks.java | 6 +++--- core/src/mindustry/content/Loadouts.java | 14 ++++---------- core/src/mindustry/game/Schematics.java | 11 ++++++++--- .../src/mindustry/ui/dialogs/SchematicsDialog.java | 2 +- .../mindustry/ui/dialogs/SettingsMenuDialog.java | 1 + 6 files changed, 18 insertions(+), 17 deletions(-) diff --git a/core/assets/bundles/bundle.properties b/core/assets/bundles/bundle.properties index 0ee7e3bd4e..73fee4471d 100644 --- a/core/assets/bundles/bundle.properties +++ b/core/assets/bundles/bundle.properties @@ -643,6 +643,7 @@ setting.screenshake.name = Screen Shake setting.effects.name = Display Effects setting.destroyedblocks.name = Display Destroyed Blocks setting.conveyorpathfinding.name = Conveyor Placement Pathfinding +setting.coreselect.name = Allow Schematic Cores setting.sensitivity.name = Controller Sensitivity setting.saveinterval.name = Save Interval setting.seconds = {0} seconds diff --git a/core/src/mindustry/content/Blocks.java b/core/src/mindustry/content/Blocks.java index 8fe9cdb52f..58ff4a7c35 100644 --- a/core/src/mindustry/content/Blocks.java +++ b/core/src/mindustry/content/Blocks.java @@ -1234,7 +1234,7 @@ public class Blocks implements ContentList{ //region storage coreShard = new CoreBlock("core-shard"){{ - requirements(Category.effect, BuildVisibility.debugOnly, ItemStack.with(Items.titanium, 4000)); + requirements(Category.effect, BuildVisibility.debugOnly, ItemStack.with()); alwaysUnlocked = true; health = 1100; @@ -1243,7 +1243,7 @@ public class Blocks implements ContentList{ }}; coreFoundation = new CoreBlock("core-foundation"){{ - requirements(Category.effect, BuildVisibility.debugOnly, ItemStack.with(Items.titanium, 400, Items.silicon, 3000)); + requirements(Category.effect, BuildVisibility.debugOnly, ItemStack.with()); health = 2000; itemCapacity = 9000; @@ -1251,7 +1251,7 @@ public class Blocks implements ContentList{ }}; coreNucleus = new CoreBlock("core-nucleus"){{ - requirements(Category.effect, BuildVisibility.debugOnly, ItemStack.with(Items.titanium, 4000, Items.silicon, 2000, Items.surgealloy, 3000)); + requirements(Category.effect, BuildVisibility.debugOnly, ItemStack.with()); health = 4000; itemCapacity = 13000; diff --git a/core/src/mindustry/content/Loadouts.java b/core/src/mindustry/content/Loadouts.java index 16252b686f..145da6120e 100644 --- a/core/src/mindustry/content/Loadouts.java +++ b/core/src/mindustry/content/Loadouts.java @@ -3,8 +3,6 @@ package mindustry.content; import mindustry.ctype.*; import mindustry.game.*; -import java.io.*; - public class Loadouts implements ContentList{ public static Schematic basicShard, @@ -14,13 +12,9 @@ public class Loadouts implements ContentList{ @Override public void load(){ - try{ - basicShard = Schematics.readBase64("bXNjaAB4nD2K2wqAIBiD5ymibnoRn6YnEP1BwUMoBL19FuJ2sbFvUFgYZDaJsLeQrkinN9UJHImsNzlYE7WrIUastuSbnlKx2VJJt+8IQGGKdfO/8J5yrGJSMegLg+YUIA=="); - advancedShard = Schematics.readBase64("bXNjaAB4nD2LjQqAIAyET7OMIOhFfJqeYMxBgSkYCL199gu33fFtB4tOwUTaBCP5QpHFzwtl32DahBeKK1NwPq8hoOcUixwpY+CUxe3XIwBbB/pa6tadVCUP02hgHvp5vZq/0b7pBHPYFOQ="); - basicFoundation = Schematics.readBase64("bXNjaAB4nD1OSQ6DMBBzFhVu8BG+0X8MQyoiJTNSukj8nlCi2Adbtg/GA4OBF8oB00rvyE/9ykafqOIw58A7SWRKy1ZiShhZ5RcOLZhYS1hefQ1gRIeptH9jq/qW2lvc1d2tgWsOfVX/tOwE86AYBA=="); - basicNucleus = Schematics.readBase64("bXNjaAB4nD2MUQqAIBBEJy0s6qOLdJXuYNtCgikYBd2+LNmdj308hkGHtkId7M4YFns4mk/yfB4a48602eDI+mlNznu0FMPFd0wYKCaewl8F0EOueqM+yKSLVfJrNKWnSw/FZGzEGXFG9sy/px4gEBW1"); - }catch(IOException e){ - throw new RuntimeException(e); - } + basicShard = Schematics.readBase64("bXNjaAB4nD2K2wqAIBiD5ymibnoRn6YnEP1BwUMoBL19FuJ2sbFvUFgYZDaJsLeQrkinN9UJHImsNzlYE7WrIUastuSbnlKx2VJJt+8IQGGKdfO/8J5yrGJSMegLg+YUIA=="); + advancedShard = Schematics.readBase64("bXNjaAB4nD2LjQqAIAyET7OMIOhFfJqeYMxBgSkYCL199gu33fFtB4tOwUTaBCP5QpHFzwtl32DahBeKK1NwPq8hoOcUixwpY+CUxe3XIwBbB/pa6tadVCUP02hgHvp5vZq/0b7pBHPYFOQ="); + basicFoundation = Schematics.readBase64("bXNjaAB4nD1OSQ6DMBBzFhVu8BG+0X8MQyoiJTNSukj8nlCi2Adbtg/GA4OBF8oB00rvyE/9ykafqOIw58A7SWRKy1ZiShhZ5RcOLZhYS1hefQ1gRIeptH9jq/qW2lvc1d2tgWsOfVX/tOwE86AYBA=="); + basicNucleus = Schematics.readBase64("bXNjaAB4nD2MUQqAIBBEJy0s6qOLdJXuYNtCgikYBd2+LNmdj308hkGHtkId7M4YFns4mk/yfB4a48602eDI+mlNznu0FMPFd0wYKCaewl8F0EOueqM+yKSLVfJrNKWnSw/FZGzEGXFG9sy/px4gEBW1"); } } diff --git a/core/src/mindustry/game/Schematics.java b/core/src/mindustry/game/Schematics.java index b30658692e..072f063e1f 100644 --- a/core/src/mindustry/game/Schematics.java +++ b/core/src/mindustry/game/Schematics.java @@ -339,7 +339,8 @@ public class Schematics implements Loadable{ for(int cy = oy; cy <= oy2; cy++){ Tile tile = world.ltile(cx, cy); - if(tile != null && tile.entity != null && !counted.contains(tile.pos()) && !(tile.block() instanceof BuildBlock) && tile.entity.block.isVisible()){ + if(tile != null && tile.entity != null && !counted.contains(tile.pos()) && !(tile.block() instanceof BuildBlock) + && (tile.entity.block.isVisible() || (tile.entity.block instanceof CoreBlock && Core.settings.getBool("coreselect")))){ int config = tile.entity.config(); if(tile.block().posConfig){ config = Pos.get(Pos.x(config) + offsetX, Pos.y(config) + offsetY); @@ -368,8 +369,12 @@ public class Schematics implements Loadable{ //region IO methods /** Loads a schematic from base64. May throw an exception. */ - public static Schematic readBase64(String schematic) throws IOException{ - return read(new ByteArrayInputStream(Base64Coder.decode(schematic))); + public static Schematic readBase64(String schematic){ + try{ + return read(new ByteArrayInputStream(Base64Coder.decode(schematic))); + }catch(IOException e){ + throw new RuntimeException(e); + } } public static Schematic read(Fi file) throws IOException{ diff --git a/core/src/mindustry/ui/dialogs/SchematicsDialog.java b/core/src/mindustry/ui/dialogs/SchematicsDialog.java index d12bc4af54..1747cdf2a0 100644 --- a/core/src/mindustry/ui/dialogs/SchematicsDialog.java +++ b/core/src/mindustry/ui/dialogs/SchematicsDialog.java @@ -163,7 +163,7 @@ public class SchematicsDialog extends FloatingDialog{ setup(); ui.showInfoFade("$schematic.saved"); showInfo(s); - }catch(Exception e){ + }catch(Throwable e){ ui.showException(e); } }).marginLeft(12f).disabled(b -> Core.app.getClipboardText() == null || !Core.app.getClipboardText().startsWith(schematicBaseStart)); diff --git a/core/src/mindustry/ui/dialogs/SettingsMenuDialog.java b/core/src/mindustry/ui/dialogs/SettingsMenuDialog.java index 4c01c10abb..3ce8457ec1 100644 --- a/core/src/mindustry/ui/dialogs/SettingsMenuDialog.java +++ b/core/src/mindustry/ui/dialogs/SettingsMenuDialog.java @@ -229,6 +229,7 @@ public class SettingsMenuDialog extends SettingsDialog{ game.checkPref("savecreate", true); game.checkPref("blockreplace", true); game.checkPref("conveyorpathfinding", true); + game.checkPref("coreselect", false); game.checkPref("hints", true); if(!mobile){ game.checkPref("buildautopause", false); From 566052cabfc8d1b9917e47b206455816d5ab5f0f Mon Sep 17 00:00:00 2001 From: Anuken Date: Sun, 29 Dec 2019 12:24:51 -0500 Subject: [PATCH 31/78] Fixed #1272 --- core/assets/scripts/global.js | 1 + core/src/mindustry/game/Schematics.java | 1 + core/src/mindustry/mod/ClassAccess.java | 2 +- tools/src/mindustry/tools/ScriptStubGenerator.java | 3 ++- 4 files changed, 5 insertions(+), 2 deletions(-) diff --git a/core/assets/scripts/global.js b/core/assets/scripts/global.js index 862ded3759..9ba7fc5e4c 100755 --- a/core/assets/scripts/global.js +++ b/core/assets/scripts/global.js @@ -25,6 +25,7 @@ importPackage(Packages.arc.func) importPackage(Packages.arc.graphics) importPackage(Packages.arc.graphics.g2d) importPackage(Packages.arc.math) +importPackage(Packages.arc.math.geom) importPackage(Packages.arc.scene) importPackage(Packages.arc.scene.actions) importPackage(Packages.arc.scene.event) diff --git a/core/src/mindustry/game/Schematics.java b/core/src/mindustry/game/Schematics.java index 072f063e1f..fd6e10022d 100644 --- a/core/src/mindustry/game/Schematics.java +++ b/core/src/mindustry/game/Schematics.java @@ -249,6 +249,7 @@ public class Schematics implements Loadable{ public void placeLoadout(Schematic schem, int x, int y){ Stile coreTile = schem.tiles.find(s -> s.block instanceof CoreBlock); + if(coreTile == null) throw new IllegalArgumentException("Schematic has no core tile. Exiting."); int ox = x - coreTile.x, oy = y - coreTile.y; schem.tiles.each(st -> { Tile tile = world.tile(st.x + ox, st.y + oy); diff --git a/core/src/mindustry/mod/ClassAccess.java b/core/src/mindustry/mod/ClassAccess.java index 06ff74766c..2d1e32cfad 100644 --- a/core/src/mindustry/mod/ClassAccess.java +++ b/core/src/mindustry/mod/ClassAccess.java @@ -3,5 +3,5 @@ package mindustry.mod; import arc.struct.*; //obviously autogenerated, do not touch public class ClassAccess{ - public static final ObjectSet allowedClassNames = ObjectSet.with("arc.Core", "arc.func.Boolc", "arc.func.Boolf", "arc.func.Boolf2", "arc.func.Boolp", "arc.func.Cons", "arc.func.Cons2", "arc.func.Floatc", "arc.func.Floatc2", "arc.func.Floatc4", "arc.func.Floatf", "arc.func.Floatp", "arc.func.Func", "arc.func.Func2", "arc.func.Func3", "arc.func.Intc", "arc.func.Intc2", "arc.func.Intc4", "arc.func.Intf", "arc.func.Intp", "arc.func.Prov", "arc.graphics.Color", "arc.graphics.Pixmap", "arc.graphics.Texture", "arc.graphics.TextureData", "arc.graphics.g2d.Draw", "arc.graphics.g2d.Fill", "arc.graphics.g2d.Lines", "arc.graphics.g2d.TextureAtlas", "arc.graphics.g2d.TextureAtlas$AtlasRegion", "arc.graphics.g2d.TextureRegion", "arc.math.Angles", "arc.math.Mathf", "arc.scene.Action", "arc.scene.Element", "arc.scene.Group", "arc.scene.Scene", "arc.scene.actions.Actions", "arc.scene.actions.AddAction", "arc.scene.actions.AddListenerAction", "arc.scene.actions.AfterAction", "arc.scene.actions.AlphaAction", "arc.scene.actions.ColorAction", "arc.scene.actions.DelayAction", "arc.scene.actions.DelegateAction", "arc.scene.actions.FloatAction", "arc.scene.actions.IntAction", "arc.scene.actions.LayoutAction", "arc.scene.actions.MoveByAction", "arc.scene.actions.MoveToAction", "arc.scene.actions.OriginAction", "arc.scene.actions.ParallelAction", "arc.scene.actions.RelativeTemporalAction", "arc.scene.actions.RemoveAction", "arc.scene.actions.RemoveActorAction", "arc.scene.actions.RemoveListenerAction", "arc.scene.actions.RepeatAction", "arc.scene.actions.RotateByAction", "arc.scene.actions.RotateToAction", "arc.scene.actions.RunnableAction", "arc.scene.actions.ScaleByAction", "arc.scene.actions.ScaleToAction", "arc.scene.actions.SequenceAction", "arc.scene.actions.SizeByAction", "arc.scene.actions.SizeToAction", "arc.scene.actions.TemporalAction", "arc.scene.actions.TimeScaleAction", "arc.scene.actions.TouchableAction", "arc.scene.actions.TranslateByAction", "arc.scene.actions.VisibleAction", "arc.scene.event.ChangeListener", "arc.scene.event.ChangeListener$ChangeEvent", "arc.scene.event.ClickListener", "arc.scene.event.DragListener", "arc.scene.event.DragScrollListener", "arc.scene.event.ElementGestureListener", "arc.scene.event.EventListener", "arc.scene.event.FocusListener", "arc.scene.event.FocusListener$FocusEvent", "arc.scene.event.FocusListener$FocusEvent$Type", "arc.scene.event.HandCursorListener", "arc.scene.event.IbeamCursorListener", "arc.scene.event.InputEvent", "arc.scene.event.InputEvent$Type", "arc.scene.event.InputListener", "arc.scene.event.SceneEvent", "arc.scene.event.Touchable", "arc.scene.event.VisibilityEvent", "arc.scene.event.VisibilityListener", "arc.scene.style.BaseDrawable", "arc.scene.style.Drawable", "arc.scene.style.NinePatchDrawable", "arc.scene.style.ScaledNinePatchDrawable", "arc.scene.style.Style", "arc.scene.style.TextureRegionDrawable", "arc.scene.style.TiledDrawable", "arc.scene.style.TransformDrawable", "arc.scene.ui.Button", "arc.scene.ui.Button$ButtonStyle", "arc.scene.ui.ButtonGroup", "arc.scene.ui.CheckBox", "arc.scene.ui.CheckBox$CheckBoxStyle", "arc.scene.ui.ColorImage", "arc.scene.ui.Dialog", "arc.scene.ui.Dialog$DialogStyle", "arc.scene.ui.Image", "arc.scene.ui.ImageButton", "arc.scene.ui.ImageButton$ImageButtonStyle", "arc.scene.ui.KeybindDialog", "arc.scene.ui.KeybindDialog$KeybindDialogStyle", "arc.scene.ui.Label", "arc.scene.ui.Label$LabelStyle", "arc.scene.ui.ProgressBar", "arc.scene.ui.ProgressBar$ProgressBarStyle", "arc.scene.ui.ScrollPane", "arc.scene.ui.ScrollPane$ScrollPaneStyle", "arc.scene.ui.SettingsDialog", "arc.scene.ui.SettingsDialog$SettingsTable", "arc.scene.ui.SettingsDialog$SettingsTable$CheckSetting", "arc.scene.ui.SettingsDialog$SettingsTable$Setting", "arc.scene.ui.SettingsDialog$SettingsTable$SliderSetting", "arc.scene.ui.SettingsDialog$StringProcessor", "arc.scene.ui.Slider", "arc.scene.ui.Slider$SliderStyle", "arc.scene.ui.TextArea", "arc.scene.ui.TextArea$TextAreaListener", "arc.scene.ui.TextButton", "arc.scene.ui.TextButton$TextButtonStyle", "arc.scene.ui.TextField", "arc.scene.ui.TextField$DefaultOnscreenKeyboard", "arc.scene.ui.TextField$OnscreenKeyboard", "arc.scene.ui.TextField$TextFieldClickListener", "arc.scene.ui.TextField$TextFieldFilter", "arc.scene.ui.TextField$TextFieldListener", "arc.scene.ui.TextField$TextFieldStyle", "arc.scene.ui.TextField$TextFieldValidator", "arc.scene.ui.Tooltip", "arc.scene.ui.Tooltip$Tooltips", "arc.scene.ui.Touchpad", "arc.scene.ui.Touchpad$TouchpadStyle", "arc.scene.ui.TreeElement", "arc.scene.ui.TreeElement$Node", "arc.scene.ui.TreeElement$TreeStyle", "arc.scene.ui.layout.Cell", "arc.scene.ui.layout.Collapser", "arc.scene.ui.layout.HorizontalGroup", "arc.scene.ui.layout.Scl", "arc.scene.ui.layout.Stack", "arc.scene.ui.layout.Table", "arc.scene.ui.layout.Table$DrawRect", "arc.scene.ui.layout.VerticalGroup", "arc.scene.ui.layout.WidgetGroup", "arc.scene.utils.ArraySelection", "arc.scene.utils.Cullable", "arc.scene.utils.Disableable", "arc.scene.utils.DragAndDrop", "arc.scene.utils.DragAndDrop$Payload", "arc.scene.utils.DragAndDrop$Source", "arc.scene.utils.DragAndDrop$Target", "arc.scene.utils.Elements", "arc.scene.utils.Layout", "arc.scene.utils.Selection", "arc.struct.Array", "arc.struct.Array$ArrayIterable", "arc.struct.ArrayMap", "arc.struct.ArrayMap$Entries", "arc.struct.ArrayMap$Keys", "arc.struct.ArrayMap$Values", "arc.struct.AtomicQueue", "arc.struct.BinaryHeap", "arc.struct.BinaryHeap$Node", "arc.struct.Bits", "arc.struct.BooleanArray", "arc.struct.ByteArray", "arc.struct.CharArray", "arc.struct.ComparableTimSort", "arc.struct.DelayedRemovalArray", "arc.struct.EnumSet", "arc.struct.EnumSet$EnumSetIterator", "arc.struct.FloatArray", "arc.struct.GridBits", "arc.struct.GridMap", "arc.struct.IdentityMap", "arc.struct.IdentityMap$Entries", "arc.struct.IdentityMap$Entry", "arc.struct.IdentityMap$Keys", "arc.struct.IdentityMap$Values", "arc.struct.IntArray", "arc.struct.IntFloatMap", "arc.struct.IntFloatMap$Entries", "arc.struct.IntFloatMap$Entry", "arc.struct.IntFloatMap$Keys", "arc.struct.IntFloatMap$Values", "arc.struct.IntIntMap", "arc.struct.IntIntMap$Entries", "arc.struct.IntIntMap$Entry", "arc.struct.IntIntMap$Keys", "arc.struct.IntIntMap$Values", "arc.struct.IntMap", "arc.struct.IntMap$Entries", "arc.struct.IntMap$Entry", "arc.struct.IntMap$Keys", "arc.struct.IntMap$Values", "arc.struct.IntQueue", "arc.struct.IntSet", "arc.struct.IntSet$IntSetIterator", "arc.struct.LongArray", "arc.struct.LongMap", "arc.struct.LongMap$Entries", "arc.struct.LongMap$Entry", "arc.struct.LongMap$Keys", "arc.struct.LongMap$Values", "arc.struct.LongQueue", "arc.struct.ObjectFloatMap", "arc.struct.ObjectFloatMap$Entries", "arc.struct.ObjectFloatMap$Entry", "arc.struct.ObjectFloatMap$Keys", "arc.struct.ObjectFloatMap$Values", "arc.struct.ObjectIntMap", "arc.struct.ObjectIntMap$Entries", "arc.struct.ObjectIntMap$Entry", "arc.struct.ObjectIntMap$Keys", "arc.struct.ObjectIntMap$Values", "arc.struct.ObjectMap", "arc.struct.ObjectMap$Entries", "arc.struct.ObjectMap$Entry", "arc.struct.ObjectMap$Keys", "arc.struct.ObjectMap$Values", "arc.struct.ObjectSet", "arc.struct.ObjectSet$ObjectSetIterator", "arc.struct.OrderedMap", "arc.struct.OrderedMap$OrderedMapEntries", "arc.struct.OrderedMap$OrderedMapKeys", "arc.struct.OrderedMap$OrderedMapValues", "arc.struct.OrderedSet", "arc.struct.OrderedSet$OrderedSetIterator", "arc.struct.PooledLinkedList", "arc.struct.PooledLinkedList$Item", "arc.struct.Queue", "arc.struct.Queue$QueueIterable", "arc.struct.ShortArray", "arc.struct.SnapshotArray", "arc.struct.Sort", "arc.struct.SortedIntList", "arc.struct.SortedIntList$Iterator", "arc.struct.SortedIntList$Node", "arc.struct.StringMap", "arc.struct.TimSort", "arc.util.I18NBundle", "arc.util.Time", "java.io.PrintStream", "java.lang.Object", "java.lang.Runnable", "java.lang.String", "java.lang.System", "mindustry.Vars", "mindustry.ai.BlockIndexer", "mindustry.ai.Pathfinder", "mindustry.ai.Pathfinder$PathData", "mindustry.ai.Pathfinder$PathTarget", "mindustry.ai.Pathfinder$PathTileStruct", "mindustry.ai.WaveSpawner", "mindustry.content.Blocks", "mindustry.content.Bullets", "mindustry.content.Fx", "mindustry.content.Items", "mindustry.content.Liquids", "mindustry.content.Loadouts", "mindustry.content.Mechs", "mindustry.content.StatusEffects", "mindustry.content.TechTree", "mindustry.content.TechTree$TechNode", "mindustry.content.TypeIDs", "mindustry.content.UnitTypes", "mindustry.content.Zones", "mindustry.core.ContentLoader", "mindustry.core.Control", "mindustry.core.FileTree", "mindustry.core.GameState", "mindustry.core.GameState$State", "mindustry.core.Logic", "mindustry.core.NetServer$TeamAssigner", "mindustry.core.Platform", "mindustry.core.Renderer", "mindustry.core.UI", "mindustry.core.Version", "mindustry.core.World", "mindustry.core.World$Raycaster", "mindustry.ctype.Content", "mindustry.ctype.Content$ModContentInfo", "mindustry.ctype.ContentList", "mindustry.ctype.ContentType", "mindustry.ctype.MappableContent", "mindustry.ctype.UnlockableContent", "mindustry.editor.DrawOperation", "mindustry.editor.DrawOperation$OpType", "mindustry.editor.DrawOperation$TileOpStruct", "mindustry.editor.EditorTile", "mindustry.editor.EditorTool", "mindustry.editor.MapEditor", "mindustry.editor.MapEditor$Context", "mindustry.editor.MapEditorDialog", "mindustry.editor.MapGenerateDialog", "mindustry.editor.MapInfoDialog", "mindustry.editor.MapLoadDialog", "mindustry.editor.MapRenderer", "mindustry.editor.MapResizeDialog", "mindustry.editor.MapSaveDialog", "mindustry.editor.MapView", "mindustry.editor.OperationStack", "mindustry.editor.WaveInfoDialog", "mindustry.entities.Damage", "mindustry.entities.Damage$PropCellStruct", "mindustry.entities.Effects", "mindustry.entities.Effects$Effect", "mindustry.entities.Effects$EffectContainer", "mindustry.entities.Effects$EffectProvider", "mindustry.entities.Effects$EffectRenderer", "mindustry.entities.Effects$ScreenshakeProvider", "mindustry.entities.Entities", "mindustry.entities.EntityCollisions", "mindustry.entities.EntityGroup", "mindustry.entities.Predict", "mindustry.entities.TargetPriority", "mindustry.entities.Units", "mindustry.entities.bullet.ArtilleryBulletType", "mindustry.entities.bullet.BasicBulletType", "mindustry.entities.bullet.BombBulletType", "mindustry.entities.bullet.BulletType", "mindustry.entities.bullet.FlakBulletType", "mindustry.entities.bullet.HealBulletType", "mindustry.entities.bullet.LiquidBulletType", "mindustry.entities.bullet.MassDriverBolt", "mindustry.entities.bullet.MissileBulletType", "mindustry.entities.effect.Decal", "mindustry.entities.effect.Fire", "mindustry.entities.effect.GroundEffectEntity", "mindustry.entities.effect.GroundEffectEntity$GroundEffect", "mindustry.entities.effect.ItemTransfer", "mindustry.entities.effect.Lightning", "mindustry.entities.effect.Puddle", "mindustry.entities.effect.RubbleDecal", "mindustry.entities.effect.ScorchDecal", "mindustry.entities.traits.AbsorbTrait", "mindustry.entities.traits.BelowLiquidTrait", "mindustry.entities.traits.BuilderMinerTrait", "mindustry.entities.traits.BuilderTrait", "mindustry.entities.traits.BuilderTrait$BuildDataStatic", "mindustry.entities.traits.BuilderTrait$BuildRequest", "mindustry.entities.traits.DamageTrait", "mindustry.entities.traits.DrawTrait", "mindustry.entities.traits.Entity", "mindustry.entities.traits.HealthTrait", "mindustry.entities.traits.KillerTrait", "mindustry.entities.traits.MinerTrait", "mindustry.entities.traits.MoveTrait", "mindustry.entities.traits.SaveTrait", "mindustry.entities.traits.Saveable", "mindustry.entities.traits.ScaleTrait", "mindustry.entities.traits.ShooterTrait", "mindustry.entities.traits.SolidTrait", "mindustry.entities.traits.SpawnerTrait", "mindustry.entities.traits.SyncTrait", "mindustry.entities.traits.TargetTrait", "mindustry.entities.traits.TeamTrait", "mindustry.entities.traits.TimeTrait", "mindustry.entities.traits.TypeTrait", "mindustry.entities.traits.VelocityTrait", "mindustry.entities.type.BaseEntity", "mindustry.entities.type.BaseUnit", "mindustry.entities.type.Bullet", "mindustry.entities.type.DestructibleEntity", "mindustry.entities.type.EffectEntity", "mindustry.entities.type.Player", "mindustry.entities.type.SolidEntity", "mindustry.entities.type.TileEntity", "mindustry.entities.type.TimedEntity", "mindustry.entities.type.Unit", "mindustry.entities.type.base.BaseDrone", "mindustry.entities.type.base.BuilderDrone", "mindustry.entities.type.base.FlyingUnit", "mindustry.entities.type.base.GroundUnit", "mindustry.entities.type.base.HoverUnit", "mindustry.entities.type.base.MinerDrone", "mindustry.entities.type.base.RepairDrone", "mindustry.entities.units.StateMachine", "mindustry.entities.units.Statuses", "mindustry.entities.units.Statuses$StatusEntry", "mindustry.entities.units.UnitCommand", "mindustry.entities.units.UnitDrops", "mindustry.entities.units.UnitState", "mindustry.game.DefaultWaves", "mindustry.game.Difficulty", "mindustry.game.EventType", "mindustry.game.EventType$BlockBuildBeginEvent", "mindustry.game.EventType$BlockBuildEndEvent", "mindustry.game.EventType$BlockDestroyEvent", "mindustry.game.EventType$BlockInfoEvent", "mindustry.game.EventType$BuildSelectEvent", "mindustry.game.EventType$ClientLoadEvent", "mindustry.game.EventType$CommandIssueEvent", "mindustry.game.EventType$ContentReloadEvent", "mindustry.game.EventType$CoreItemDeliverEvent", "mindustry.game.EventType$DepositEvent", "mindustry.game.EventType$DisposeEvent", "mindustry.game.EventType$GameOverEvent", "mindustry.game.EventType$LaunchEvent", "mindustry.game.EventType$LaunchItemEvent", "mindustry.game.EventType$LineConfirmEvent", "mindustry.game.EventType$LoseEvent", "mindustry.game.EventType$MapMakeEvent", "mindustry.game.EventType$MapPublishEvent", "mindustry.game.EventType$MechChangeEvent", "mindustry.game.EventType$PlayEvent", "mindustry.game.EventType$PlayerBanEvent", "mindustry.game.EventType$PlayerChatEvent", "mindustry.game.EventType$PlayerConnect", "mindustry.game.EventType$PlayerIpBanEvent", "mindustry.game.EventType$PlayerIpUnbanEvent", "mindustry.game.EventType$PlayerJoin", "mindustry.game.EventType$PlayerLeave", "mindustry.game.EventType$PlayerUnbanEvent", "mindustry.game.EventType$ResearchEvent", "mindustry.game.EventType$ResetEvent", "mindustry.game.EventType$ResizeEvent", "mindustry.game.EventType$ServerLoadEvent", "mindustry.game.EventType$StateChangeEvent", "mindustry.game.EventType$TapConfigEvent", "mindustry.game.EventType$TapEvent", "mindustry.game.EventType$TileChangeEvent", "mindustry.game.EventType$Trigger", "mindustry.game.EventType$TurretAmmoDeliverEvent", "mindustry.game.EventType$UnitCreateEvent", "mindustry.game.EventType$UnitDestroyEvent", "mindustry.game.EventType$UnlockEvent", "mindustry.game.EventType$WaveEvent", "mindustry.game.EventType$WinEvent", "mindustry.game.EventType$WithdrawEvent", "mindustry.game.EventType$WorldLoadEvent", "mindustry.game.EventType$ZoneConfigureCompleteEvent", "mindustry.game.EventType$ZoneRequireCompleteEvent", "mindustry.game.Gamemode", "mindustry.game.GlobalData", "mindustry.game.LoopControl", "mindustry.game.MusicControl", "mindustry.game.Objective", "mindustry.game.Objectives", "mindustry.game.Objectives$Launched", "mindustry.game.Objectives$Unlock", "mindustry.game.Objectives$Wave", "mindustry.game.Objectives$ZoneObjective", "mindustry.game.Objectives$ZoneWave", "mindustry.game.Rules", "mindustry.game.Saves", "mindustry.game.Saves$SaveSlot", "mindustry.game.Schematic", "mindustry.game.Schematic$Stile", "mindustry.game.Schematics", "mindustry.game.SoundLoop", "mindustry.game.SpawnGroup", "mindustry.game.Stats", "mindustry.game.Stats$Rank", "mindustry.game.Stats$RankResult", "mindustry.game.Team", "mindustry.game.Teams", "mindustry.game.Teams$BrokenBlock", "mindustry.game.Teams$TeamData", "mindustry.game.Tutorial", "mindustry.game.Tutorial$TutorialStage", "mindustry.gen.BufferItem", "mindustry.gen.Call", "mindustry.gen.Call", "mindustry.gen.Icon", "mindustry.gen.Icon", "mindustry.gen.MethodHash", "mindustry.gen.Musics", "mindustry.gen.Musics", "mindustry.gen.PathTile", "mindustry.gen.PropCell", "mindustry.gen.RemoteReadClient", "mindustry.gen.RemoteReadServer", "mindustry.gen.Serialization", "mindustry.gen.Sounds", "mindustry.gen.Sounds", "mindustry.gen.Tex", "mindustry.gen.Tex", "mindustry.gen.TileOp", "mindustry.graphics.BlockRenderer", "mindustry.graphics.Bloom", "mindustry.graphics.CacheLayer", "mindustry.graphics.Drawf", "mindustry.graphics.FloorRenderer", "mindustry.graphics.IndexedRenderer", "mindustry.graphics.Layer", "mindustry.graphics.LightRenderer", "mindustry.graphics.MenuRenderer", "mindustry.graphics.MinimapRenderer", "mindustry.graphics.MultiPacker", "mindustry.graphics.MultiPacker$PageType", "mindustry.graphics.OverlayRenderer", "mindustry.graphics.Pal", "mindustry.graphics.Pixelator", "mindustry.graphics.Shaders", "mindustry.input.Binding", "mindustry.input.DesktopInput", "mindustry.input.InputHandler", "mindustry.input.InputHandler$PlaceLine", "mindustry.input.MobileInput", "mindustry.input.PlaceMode", "mindustry.input.Placement", "mindustry.input.Placement$DistanceHeuristic", "mindustry.input.Placement$NormalizeDrawResult", "mindustry.input.Placement$NormalizeResult", "mindustry.input.Placement$TileHueristic", "mindustry.maps.Map", "mindustry.maps.Maps", "mindustry.maps.Maps$MapProvider", "mindustry.maps.Maps$ShuffleMode", "mindustry.maps.Maps$ShuffleMode", "mindustry.maps.filters.BlendFilter", "mindustry.maps.filters.ClearFilter", "mindustry.maps.filters.DistortFilter", "mindustry.maps.filters.FilterOption", "mindustry.maps.filters.FilterOption$BlockOption", "mindustry.maps.filters.FilterOption$SliderOption", "mindustry.maps.filters.GenerateFilter", "mindustry.maps.filters.GenerateFilter$GenerateInput", "mindustry.maps.filters.GenerateFilter$GenerateInput$TileProvider", "mindustry.maps.filters.MedianFilter", "mindustry.maps.filters.MirrorFilter", "mindustry.maps.filters.NoiseFilter", "mindustry.maps.filters.OreFilter", "mindustry.maps.filters.OreMedianFilter", "mindustry.maps.filters.RiverNoiseFilter", "mindustry.maps.filters.ScatterFilter", "mindustry.maps.filters.TerrainFilter", "mindustry.maps.generators.BasicGenerator", "mindustry.maps.generators.BasicGenerator$DistanceHeuristic", "mindustry.maps.generators.BasicGenerator$TileHueristic", "mindustry.maps.generators.Generator", "mindustry.maps.generators.MapGenerator", "mindustry.maps.generators.MapGenerator$Decoration", "mindustry.maps.generators.RandomGenerator", "mindustry.maps.zonegen.DesertWastesGenerator", "mindustry.maps.zonegen.OvergrowthGenerator", "mindustry.type.Category", "mindustry.type.ErrorContent", "mindustry.type.Item", "mindustry.type.ItemStack", "mindustry.type.ItemType", "mindustry.type.Liquid", "mindustry.type.LiquidStack", "mindustry.type.Mech", "mindustry.type.Publishable", "mindustry.type.StatusEffect", "mindustry.type.StatusEffect$TransitionHandler", "mindustry.type.TypeID", "mindustry.type.UnitType", "mindustry.type.Weapon", "mindustry.type.WeatherEvent", "mindustry.type.Zone", "mindustry.ui.Bar", "mindustry.ui.BorderImage", "mindustry.ui.Cicon", "mindustry.ui.ContentDisplay", "mindustry.ui.Fonts", "mindustry.ui.GridImage", "mindustry.ui.IconSize", "mindustry.ui.IntFormat", "mindustry.ui.ItemDisplay", "mindustry.ui.ItemImage", "mindustry.ui.ItemsDisplay", "mindustry.ui.Links", "mindustry.ui.Links$LinkEntry", "mindustry.ui.LiquidDisplay", "mindustry.ui.Minimap", "mindustry.ui.MobileButton", "mindustry.ui.MultiReqImage", "mindustry.ui.ReqImage", "mindustry.ui.Styles", "mindustry.ui.dialogs.AboutDialog", "mindustry.ui.dialogs.AdminsDialog", "mindustry.ui.dialogs.BansDialog", "mindustry.ui.dialogs.ColorPicker", "mindustry.ui.dialogs.ContentInfoDialog", "mindustry.ui.dialogs.ControlsDialog", "mindustry.ui.dialogs.CustomGameDialog", "mindustry.ui.dialogs.CustomRulesDialog", "mindustry.ui.dialogs.DatabaseDialog", "mindustry.ui.dialogs.DeployDialog", "mindustry.ui.dialogs.DeployDialog$View", "mindustry.ui.dialogs.DeployDialog$ZoneNode", "mindustry.ui.dialogs.DiscordDialog", "mindustry.ui.dialogs.FileChooser", "mindustry.ui.dialogs.FileChooser$FileHistory", "mindustry.ui.dialogs.FloatingDialog", "mindustry.ui.dialogs.GameOverDialog", "mindustry.ui.dialogs.HostDialog", "mindustry.ui.dialogs.JoinDialog", "mindustry.ui.dialogs.JoinDialog$Server", "mindustry.ui.dialogs.LanguageDialog", "mindustry.ui.dialogs.LoadDialog", "mindustry.ui.dialogs.LoadoutDialog", "mindustry.ui.dialogs.MapPlayDialog", "mindustry.ui.dialogs.MapsDialog", "mindustry.ui.dialogs.MinimapDialog", "mindustry.ui.dialogs.ModsDialog", "mindustry.ui.dialogs.PaletteDialog", "mindustry.ui.dialogs.PausedDialog", "mindustry.ui.dialogs.SaveDialog", "mindustry.ui.dialogs.SchematicsDialog", "mindustry.ui.dialogs.SchematicsDialog$SchematicImage", "mindustry.ui.dialogs.SchematicsDialog$SchematicInfoDialog", "mindustry.ui.dialogs.SettingsMenuDialog", "mindustry.ui.dialogs.TechTreeDialog", "mindustry.ui.dialogs.TechTreeDialog$LayoutNode", "mindustry.ui.dialogs.TechTreeDialog$TechTreeNode", "mindustry.ui.dialogs.TechTreeDialog$View", "mindustry.ui.dialogs.TraceDialog", "mindustry.ui.dialogs.ZoneInfoDialog", "mindustry.ui.fragments.BlockConfigFragment", "mindustry.ui.fragments.BlockInventoryFragment", "mindustry.ui.fragments.ChatFragment", "mindustry.ui.fragments.FadeInFragment", "mindustry.ui.fragments.Fragment", "mindustry.ui.fragments.HudFragment", "mindustry.ui.fragments.LoadingFragment", "mindustry.ui.fragments.MenuFragment", "mindustry.ui.fragments.OverlayFragment", "mindustry.ui.fragments.PlacementFragment", "mindustry.ui.fragments.PlayerListFragment", "mindustry.ui.fragments.ScriptConsoleFragment", "mindustry.ui.layout.BranchTreeLayout", "mindustry.ui.layout.BranchTreeLayout$TreeAlignment", "mindustry.ui.layout.BranchTreeLayout$TreeLocation", "mindustry.ui.layout.RadialTreeLayout", "mindustry.ui.layout.TreeLayout", "mindustry.ui.layout.TreeLayout$TreeNode", "mindustry.world.Block", "mindustry.world.BlockStorage", "mindustry.world.Build", "mindustry.world.CachedTile", "mindustry.world.DirectionalItemBuffer", "mindustry.world.DirectionalItemBuffer$BufferItemStruct", "mindustry.world.Edges", "mindustry.world.ItemBuffer", "mindustry.world.LegacyColorMapper", "mindustry.world.LegacyColorMapper$LegacyBlock", "mindustry.world.Pos", "mindustry.world.StaticTree", "mindustry.world.Tile", "mindustry.world.WorldContext", "mindustry.world.blocks.Attributes", "mindustry.world.blocks.Autotiler", "mindustry.world.blocks.Autotiler$AutotilerHolder", "mindustry.world.blocks.BlockPart", "mindustry.world.blocks.BuildBlock", "mindustry.world.blocks.BuildBlock$BuildEntity", "mindustry.world.blocks.DoubleOverlayFloor", "mindustry.world.blocks.Floor", "mindustry.world.blocks.ItemSelection", "mindustry.world.blocks.LiquidBlock", "mindustry.world.blocks.OreBlock", "mindustry.world.blocks.OverlayFloor", "mindustry.world.blocks.PowerBlock", "mindustry.world.blocks.RespawnBlock", "mindustry.world.blocks.Rock", "mindustry.world.blocks.StaticWall", "mindustry.world.blocks.TreeBlock", "mindustry.world.blocks.defense.DeflectorWall", "mindustry.world.blocks.defense.DeflectorWall$DeflectorEntity", "mindustry.world.blocks.defense.Door", "mindustry.world.blocks.defense.Door$DoorEntity", "mindustry.world.blocks.defense.ForceProjector", "mindustry.world.blocks.defense.ForceProjector$ForceEntity", "mindustry.world.blocks.defense.ForceProjector$ShieldEntity", "mindustry.world.blocks.defense.MendProjector", "mindustry.world.blocks.defense.MendProjector$MendEntity", "mindustry.world.blocks.defense.OverdriveProjector", "mindustry.world.blocks.defense.OverdriveProjector$OverdriveEntity", "mindustry.world.blocks.defense.ShockMine", "mindustry.world.blocks.defense.SurgeWall", "mindustry.world.blocks.defense.Wall", "mindustry.world.blocks.defense.turrets.ArtilleryTurret", "mindustry.world.blocks.defense.turrets.BurstTurret", "mindustry.world.blocks.defense.turrets.ChargeTurret", "mindustry.world.blocks.defense.turrets.ChargeTurret$LaserTurretEntity", "mindustry.world.blocks.defense.turrets.CooledTurret", "mindustry.world.blocks.defense.turrets.DoubleTurret", "mindustry.world.blocks.defense.turrets.ItemTurret", "mindustry.world.blocks.defense.turrets.ItemTurret$ItemEntry", "mindustry.world.blocks.defense.turrets.ItemTurret$ItemTurretEntity", "mindustry.world.blocks.defense.turrets.LaserTurret", "mindustry.world.blocks.defense.turrets.LaserTurret$LaserTurretEntity", "mindustry.world.blocks.defense.turrets.LiquidTurret", "mindustry.world.blocks.defense.turrets.PowerTurret", "mindustry.world.blocks.defense.turrets.Turret", "mindustry.world.blocks.defense.turrets.Turret$AmmoEntry", "mindustry.world.blocks.defense.turrets.Turret$TurretEntity", "mindustry.world.blocks.distribution.ArmoredConveyor", "mindustry.world.blocks.distribution.BufferedItemBridge", "mindustry.world.blocks.distribution.BufferedItemBridge$BufferedItemBridgeEntity", "mindustry.world.blocks.distribution.Conveyor", "mindustry.world.blocks.distribution.Conveyor$ConveyorEntity", "mindustry.world.blocks.distribution.Conveyor$ItemPos", "mindustry.world.blocks.distribution.ExtendingItemBridge", "mindustry.world.blocks.distribution.ItemBridge", "mindustry.world.blocks.distribution.ItemBridge$ItemBridgeEntity", "mindustry.world.blocks.distribution.Junction", "mindustry.world.blocks.distribution.Junction$JunctionEntity", "mindustry.world.blocks.distribution.MassDriver", "mindustry.world.blocks.distribution.MassDriver$DriverBulletData", "mindustry.world.blocks.distribution.MassDriver$DriverState", "mindustry.world.blocks.distribution.MassDriver$MassDriverEntity", "mindustry.world.blocks.distribution.OverflowGate", "mindustry.world.blocks.distribution.OverflowGate$OverflowGateEntity", "mindustry.world.blocks.distribution.Router", "mindustry.world.blocks.distribution.Router$RouterEntity", "mindustry.world.blocks.distribution.Sorter", "mindustry.world.blocks.distribution.Sorter$SorterEntity", "mindustry.world.blocks.liquid.ArmoredConduit", "mindustry.world.blocks.liquid.Conduit", "mindustry.world.blocks.liquid.Conduit$ConduitEntity", "mindustry.world.blocks.liquid.LiquidBridge", "mindustry.world.blocks.liquid.LiquidExtendingBridge", "mindustry.world.blocks.liquid.LiquidJunction", "mindustry.world.blocks.liquid.LiquidOverflowGate", "mindustry.world.blocks.liquid.LiquidRouter", "mindustry.world.blocks.liquid.LiquidTank", "mindustry.world.blocks.logic.LogicBlock", "mindustry.world.blocks.logic.MessageBlock", "mindustry.world.blocks.logic.MessageBlock$MessageBlockEntity", "mindustry.world.blocks.power.Battery", "mindustry.world.blocks.power.BurnerGenerator", "mindustry.world.blocks.power.ConditionalConsumePower", "mindustry.world.blocks.power.DecayGenerator", "mindustry.world.blocks.power.ImpactReactor", "mindustry.world.blocks.power.ImpactReactor$FusionReactorEntity", "mindustry.world.blocks.power.ItemLiquidGenerator", "mindustry.world.blocks.power.ItemLiquidGenerator$ItemLiquidGeneratorEntity", "mindustry.world.blocks.power.LightBlock", "mindustry.world.blocks.power.LightBlock$LightEntity", "mindustry.world.blocks.power.NuclearReactor", "mindustry.world.blocks.power.NuclearReactor$NuclearReactorEntity", "mindustry.world.blocks.power.PowerDiode", "mindustry.world.blocks.power.PowerDistributor", "mindustry.world.blocks.power.PowerGenerator", "mindustry.world.blocks.power.PowerGenerator$GeneratorEntity", "mindustry.world.blocks.power.PowerGraph", "mindustry.world.blocks.power.PowerNode", "mindustry.world.blocks.power.SingleTypeGenerator", "mindustry.world.blocks.power.SolarGenerator", "mindustry.world.blocks.power.ThermalGenerator", "mindustry.world.blocks.production.Cultivator", "mindustry.world.blocks.production.Cultivator$CultivatorEntity", "mindustry.world.blocks.production.Drill", "mindustry.world.blocks.production.Drill$DrillEntity", "mindustry.world.blocks.production.Fracker", "mindustry.world.blocks.production.Fracker$FrackerEntity", "mindustry.world.blocks.production.GenericCrafter", "mindustry.world.blocks.production.GenericCrafter$GenericCrafterEntity", "mindustry.world.blocks.production.GenericSmelter", "mindustry.world.blocks.production.Incinerator", "mindustry.world.blocks.production.Incinerator$IncineratorEntity", "mindustry.world.blocks.production.LiquidConverter", "mindustry.world.blocks.production.Pump", "mindustry.world.blocks.production.Separator", "mindustry.world.blocks.production.SolidPump", "mindustry.world.blocks.production.SolidPump$SolidPumpEntity", "mindustry.world.blocks.sandbox.ItemSource", "mindustry.world.blocks.sandbox.ItemSource$ItemSourceEntity", "mindustry.world.blocks.sandbox.ItemVoid", "mindustry.world.blocks.sandbox.LiquidSource", "mindustry.world.blocks.sandbox.LiquidSource$LiquidSourceEntity", "mindustry.world.blocks.sandbox.PowerSource", "mindustry.world.blocks.sandbox.PowerVoid", "mindustry.world.blocks.storage.CoreBlock", "mindustry.world.blocks.storage.CoreBlock$CoreEntity", "mindustry.world.blocks.storage.LaunchPad", "mindustry.world.blocks.storage.StorageBlock", "mindustry.world.blocks.storage.StorageBlock$StorageBlockEntity", "mindustry.world.blocks.storage.Unloader", "mindustry.world.blocks.storage.Unloader$UnloaderEntity", "mindustry.world.blocks.storage.Vault", "mindustry.world.blocks.units.CommandCenter", "mindustry.world.blocks.units.CommandCenter$CommandCenterEntity", "mindustry.world.blocks.units.MechPad", "mindustry.world.blocks.units.MechPad$MechFactoryEntity", "mindustry.world.blocks.units.RallyPoint", "mindustry.world.blocks.units.RepairPoint", "mindustry.world.blocks.units.RepairPoint$RepairPointEntity", "mindustry.world.blocks.units.UnitFactory", "mindustry.world.blocks.units.UnitFactory$UnitFactoryEntity", "mindustry.world.consumers.Consume", "mindustry.world.consumers.ConsumeItemFilter", "mindustry.world.consumers.ConsumeItems", "mindustry.world.consumers.ConsumeLiquid", "mindustry.world.consumers.ConsumeLiquidBase", "mindustry.world.consumers.ConsumeLiquidFilter", "mindustry.world.consumers.ConsumePower", "mindustry.world.consumers.ConsumeType", "mindustry.world.consumers.Consumers", "mindustry.world.meta.Attribute", "mindustry.world.meta.BlockBars", "mindustry.world.meta.BlockFlag", "mindustry.world.meta.BlockGroup", "mindustry.world.meta.BlockStat", "mindustry.world.meta.BlockStats", "mindustry.world.meta.BuildVisibility", "mindustry.world.meta.PowerType", "mindustry.world.meta.Producers", "mindustry.world.meta.StatCategory", "mindustry.world.meta.StatUnit", "mindustry.world.meta.StatValue", "mindustry.world.meta.values.AmmoListValue", "mindustry.world.meta.values.BooleanValue", "mindustry.world.meta.values.BoosterListValue", "mindustry.world.meta.values.ItemFilterValue", "mindustry.world.meta.values.ItemListValue", "mindustry.world.meta.values.LiquidFilterValue", "mindustry.world.meta.values.LiquidValue", "mindustry.world.meta.values.NumberValue", "mindustry.world.meta.values.StringValue", "mindustry.world.modules.BlockModule", "mindustry.world.modules.ConsumeModule", "mindustry.world.modules.ItemModule", "mindustry.world.modules.ItemModule$ItemCalculator", "mindustry.world.modules.ItemModule$ItemConsumer", "mindustry.world.modules.LiquidModule", "mindustry.world.modules.LiquidModule$LiquidCalculator", "mindustry.world.modules.LiquidModule$LiquidConsumer", "mindustry.world.modules.PowerModule", "mindustry.world.producers.Produce", "mindustry.world.producers.ProduceItem"); + public static final ObjectSet allowedClassNames = ObjectSet.with("arc.Core", "arc.func.Boolc", "arc.func.Boolf", "arc.func.Boolf2", "arc.func.Boolp", "arc.func.Cons", "arc.func.Cons2", "arc.func.Floatc", "arc.func.Floatc2", "arc.func.Floatc4", "arc.func.Floatf", "arc.func.Floatp", "arc.func.Func", "arc.func.Func2", "arc.func.Func3", "arc.func.Intc", "arc.func.Intc2", "arc.func.Intc4", "arc.func.Intf", "arc.func.Intp", "arc.func.Prov", "arc.graphics.Color", "arc.graphics.Pixmap", "arc.graphics.Texture", "arc.graphics.TextureData", "arc.graphics.g2d.Draw", "arc.graphics.g2d.Fill", "arc.graphics.g2d.Lines", "arc.graphics.g2d.TextureAtlas", "arc.graphics.g2d.TextureAtlas$AtlasRegion", "arc.graphics.g2d.TextureRegion", "arc.math.Affine2", "arc.math.Angles", "arc.math.Angles", "arc.math.Angles$ParticleConsumer", "arc.math.CumulativeDistribution", "arc.math.CumulativeDistribution$CumulativeValue", "arc.math.DelaunayTriangulator", "arc.math.EarClippingTriangulator", "arc.math.Extrapolator", "arc.math.FloatCounter", "arc.math.Interpolation", "arc.math.Interpolation$Bounce", "arc.math.Interpolation$BounceIn", "arc.math.Interpolation$BounceOut", "arc.math.Interpolation$Elastic", "arc.math.Interpolation$ElasticIn", "arc.math.Interpolation$ElasticOut", "arc.math.Interpolation$Exp", "arc.math.Interpolation$ExpIn", "arc.math.Interpolation$ExpOut", "arc.math.Interpolation$Pow", "arc.math.Interpolation$PowIn", "arc.math.Interpolation$PowOut", "arc.math.Interpolation$Swing", "arc.math.Interpolation$SwingIn", "arc.math.Interpolation$SwingOut", "arc.math.Mathf", "arc.math.Mathf", "arc.math.Matrix3", "arc.math.WindowedMean", "arc.math.geom.BSpline", "arc.math.geom.Bezier", "arc.math.geom.Bresenham2", "arc.math.geom.CatmullRomSpline", "arc.math.geom.Circle", "arc.math.geom.ConvexHull", "arc.math.geom.Ellipse", "arc.math.geom.FixedPosition", "arc.math.geom.Geometry", "arc.math.geom.Geometry$Raycaster", "arc.math.geom.Geometry$SolidChecker", "arc.math.geom.Intersector", "arc.math.geom.Intersector$MinimumTranslationVector", "arc.math.geom.Path", "arc.math.geom.Point2", "arc.math.geom.Point3", "arc.math.geom.Polygon", "arc.math.geom.Polyline", "arc.math.geom.Position", "arc.math.geom.QuadTree", "arc.math.geom.QuadTree$QuadTreeObject", "arc.math.geom.Rect", "arc.math.geom.Shape2D", "arc.math.geom.Spring1D", "arc.math.geom.Spring2D", "arc.math.geom.Vec2", "arc.math.geom.Vec3", "arc.math.geom.Vector", "arc.scene.Action", "arc.scene.Element", "arc.scene.Group", "arc.scene.Scene", "arc.scene.actions.Actions", "arc.scene.actions.AddAction", "arc.scene.actions.AddListenerAction", "arc.scene.actions.AfterAction", "arc.scene.actions.AlphaAction", "arc.scene.actions.ColorAction", "arc.scene.actions.DelayAction", "arc.scene.actions.DelegateAction", "arc.scene.actions.FloatAction", "arc.scene.actions.IntAction", "arc.scene.actions.LayoutAction", "arc.scene.actions.MoveByAction", "arc.scene.actions.MoveToAction", "arc.scene.actions.OriginAction", "arc.scene.actions.ParallelAction", "arc.scene.actions.RelativeTemporalAction", "arc.scene.actions.RemoveAction", "arc.scene.actions.RemoveActorAction", "arc.scene.actions.RemoveListenerAction", "arc.scene.actions.RepeatAction", "arc.scene.actions.RotateByAction", "arc.scene.actions.RotateToAction", "arc.scene.actions.RunnableAction", "arc.scene.actions.ScaleByAction", "arc.scene.actions.ScaleToAction", "arc.scene.actions.SequenceAction", "arc.scene.actions.SizeByAction", "arc.scene.actions.SizeToAction", "arc.scene.actions.TemporalAction", "arc.scene.actions.TimeScaleAction", "arc.scene.actions.TouchableAction", "arc.scene.actions.TranslateByAction", "arc.scene.actions.VisibleAction", "arc.scene.event.ChangeListener", "arc.scene.event.ChangeListener$ChangeEvent", "arc.scene.event.ClickListener", "arc.scene.event.DragListener", "arc.scene.event.DragScrollListener", "arc.scene.event.ElementGestureListener", "arc.scene.event.EventListener", "arc.scene.event.FocusListener", "arc.scene.event.FocusListener$FocusEvent", "arc.scene.event.FocusListener$FocusEvent$Type", "arc.scene.event.HandCursorListener", "arc.scene.event.IbeamCursorListener", "arc.scene.event.InputEvent", "arc.scene.event.InputEvent$Type", "arc.scene.event.InputListener", "arc.scene.event.SceneEvent", "arc.scene.event.Touchable", "arc.scene.event.VisibilityEvent", "arc.scene.event.VisibilityListener", "arc.scene.style.BaseDrawable", "arc.scene.style.Drawable", "arc.scene.style.NinePatchDrawable", "arc.scene.style.ScaledNinePatchDrawable", "arc.scene.style.Style", "arc.scene.style.TextureRegionDrawable", "arc.scene.style.TiledDrawable", "arc.scene.style.TransformDrawable", "arc.scene.ui.Button", "arc.scene.ui.Button$ButtonStyle", "arc.scene.ui.ButtonGroup", "arc.scene.ui.CheckBox", "arc.scene.ui.CheckBox$CheckBoxStyle", "arc.scene.ui.ColorImage", "arc.scene.ui.Dialog", "arc.scene.ui.Dialog$DialogStyle", "arc.scene.ui.Image", "arc.scene.ui.ImageButton", "arc.scene.ui.ImageButton$ImageButtonStyle", "arc.scene.ui.KeybindDialog", "arc.scene.ui.KeybindDialog$KeybindDialogStyle", "arc.scene.ui.Label", "arc.scene.ui.Label$LabelStyle", "arc.scene.ui.ProgressBar", "arc.scene.ui.ProgressBar$ProgressBarStyle", "arc.scene.ui.ScrollPane", "arc.scene.ui.ScrollPane$ScrollPaneStyle", "arc.scene.ui.SettingsDialog", "arc.scene.ui.SettingsDialog$SettingsTable", "arc.scene.ui.SettingsDialog$SettingsTable$CheckSetting", "arc.scene.ui.SettingsDialog$SettingsTable$Setting", "arc.scene.ui.SettingsDialog$SettingsTable$SliderSetting", "arc.scene.ui.SettingsDialog$StringProcessor", "arc.scene.ui.Slider", "arc.scene.ui.Slider$SliderStyle", "arc.scene.ui.TextArea", "arc.scene.ui.TextArea$TextAreaListener", "arc.scene.ui.TextButton", "arc.scene.ui.TextButton$TextButtonStyle", "arc.scene.ui.TextField", "arc.scene.ui.TextField$DefaultOnscreenKeyboard", "arc.scene.ui.TextField$OnscreenKeyboard", "arc.scene.ui.TextField$TextFieldClickListener", "arc.scene.ui.TextField$TextFieldFilter", "arc.scene.ui.TextField$TextFieldListener", "arc.scene.ui.TextField$TextFieldStyle", "arc.scene.ui.TextField$TextFieldValidator", "arc.scene.ui.Tooltip", "arc.scene.ui.Tooltip$Tooltips", "arc.scene.ui.Touchpad", "arc.scene.ui.Touchpad$TouchpadStyle", "arc.scene.ui.TreeElement", "arc.scene.ui.TreeElement$Node", "arc.scene.ui.TreeElement$TreeStyle", "arc.scene.ui.layout.Cell", "arc.scene.ui.layout.Collapser", "arc.scene.ui.layout.HorizontalGroup", "arc.scene.ui.layout.Scl", "arc.scene.ui.layout.Stack", "arc.scene.ui.layout.Table", "arc.scene.ui.layout.Table$DrawRect", "arc.scene.ui.layout.VerticalGroup", "arc.scene.ui.layout.WidgetGroup", "arc.scene.utils.ArraySelection", "arc.scene.utils.Cullable", "arc.scene.utils.Disableable", "arc.scene.utils.DragAndDrop", "arc.scene.utils.DragAndDrop$Payload", "arc.scene.utils.DragAndDrop$Source", "arc.scene.utils.DragAndDrop$Target", "arc.scene.utils.Elements", "arc.scene.utils.Layout", "arc.scene.utils.Selection", "arc.struct.Array", "arc.struct.Array$ArrayIterable", "arc.struct.ArrayMap", "arc.struct.ArrayMap$Entries", "arc.struct.ArrayMap$Keys", "arc.struct.ArrayMap$Values", "arc.struct.AtomicQueue", "arc.struct.BinaryHeap", "arc.struct.BinaryHeap$Node", "arc.struct.Bits", "arc.struct.BooleanArray", "arc.struct.ByteArray", "arc.struct.CharArray", "arc.struct.ComparableTimSort", "arc.struct.DelayedRemovalArray", "arc.struct.EnumSet", "arc.struct.EnumSet$EnumSetIterator", "arc.struct.FloatArray", "arc.struct.GridBits", "arc.struct.GridMap", "arc.struct.IdentityMap", "arc.struct.IdentityMap$Entries", "arc.struct.IdentityMap$Entry", "arc.struct.IdentityMap$Keys", "arc.struct.IdentityMap$Values", "arc.struct.IntArray", "arc.struct.IntFloatMap", "arc.struct.IntFloatMap$Entries", "arc.struct.IntFloatMap$Entry", "arc.struct.IntFloatMap$Keys", "arc.struct.IntFloatMap$Values", "arc.struct.IntIntMap", "arc.struct.IntIntMap$Entries", "arc.struct.IntIntMap$Entry", "arc.struct.IntIntMap$Keys", "arc.struct.IntIntMap$Values", "arc.struct.IntMap", "arc.struct.IntMap$Entries", "arc.struct.IntMap$Entry", "arc.struct.IntMap$Keys", "arc.struct.IntMap$Values", "arc.struct.IntQueue", "arc.struct.IntSet", "arc.struct.IntSet$IntSetIterator", "arc.struct.LongArray", "arc.struct.LongMap", "arc.struct.LongMap$Entries", "arc.struct.LongMap$Entry", "arc.struct.LongMap$Keys", "arc.struct.LongMap$Values", "arc.struct.LongQueue", "arc.struct.ObjectFloatMap", "arc.struct.ObjectFloatMap$Entries", "arc.struct.ObjectFloatMap$Entry", "arc.struct.ObjectFloatMap$Keys", "arc.struct.ObjectFloatMap$Values", "arc.struct.ObjectIntMap", "arc.struct.ObjectIntMap$Entries", "arc.struct.ObjectIntMap$Entry", "arc.struct.ObjectIntMap$Keys", "arc.struct.ObjectIntMap$Values", "arc.struct.ObjectMap", "arc.struct.ObjectMap$Entries", "arc.struct.ObjectMap$Entry", "arc.struct.ObjectMap$Keys", "arc.struct.ObjectMap$Values", "arc.struct.ObjectSet", "arc.struct.ObjectSet$ObjectSetIterator", "arc.struct.OrderedMap", "arc.struct.OrderedMap$OrderedMapEntries", "arc.struct.OrderedMap$OrderedMapKeys", "arc.struct.OrderedMap$OrderedMapValues", "arc.struct.OrderedSet", "arc.struct.OrderedSet$OrderedSetIterator", "arc.struct.PooledLinkedList", "arc.struct.PooledLinkedList$Item", "arc.struct.Queue", "arc.struct.Queue$QueueIterable", "arc.struct.ShortArray", "arc.struct.SnapshotArray", "arc.struct.Sort", "arc.struct.SortedIntList", "arc.struct.SortedIntList$Iterator", "arc.struct.SortedIntList$Node", "arc.struct.StringMap", "arc.struct.TimSort", "arc.util.I18NBundle", "arc.util.Interval", "arc.util.Time", "java.io.DataInput", "java.io.DataInputStream", "java.io.DataOutput", "java.io.DataOutputStream", "java.io.PrintStream", "java.lang.Object", "java.lang.Runnable", "java.lang.String", "java.lang.System", "mindustry.Vars", "mindustry.ai.BlockIndexer", "mindustry.ai.Pathfinder", "mindustry.ai.Pathfinder$PathData", "mindustry.ai.Pathfinder$PathTarget", "mindustry.ai.Pathfinder$PathTileStruct", "mindustry.ai.WaveSpawner", "mindustry.content.Blocks", "mindustry.content.Bullets", "mindustry.content.Fx", "mindustry.content.Items", "mindustry.content.Liquids", "mindustry.content.Loadouts", "mindustry.content.Mechs", "mindustry.content.StatusEffects", "mindustry.content.TechTree", "mindustry.content.TechTree$TechNode", "mindustry.content.TypeIDs", "mindustry.content.UnitTypes", "mindustry.content.Zones", "mindustry.core.ContentLoader", "mindustry.core.Control", "mindustry.core.FileTree", "mindustry.core.GameState", "mindustry.core.GameState$State", "mindustry.core.Logic", "mindustry.core.NetServer$TeamAssigner", "mindustry.core.Platform", "mindustry.core.Renderer", "mindustry.core.UI", "mindustry.core.Version", "mindustry.core.World", "mindustry.core.World$Raycaster", "mindustry.ctype.Content", "mindustry.ctype.Content$ModContentInfo", "mindustry.ctype.ContentList", "mindustry.ctype.ContentType", "mindustry.ctype.MappableContent", "mindustry.ctype.UnlockableContent", "mindustry.editor.DrawOperation", "mindustry.editor.DrawOperation$OpType", "mindustry.editor.DrawOperation$TileOpStruct", "mindustry.editor.EditorTile", "mindustry.editor.EditorTool", "mindustry.editor.MapEditor", "mindustry.editor.MapEditor$Context", "mindustry.editor.MapEditorDialog", "mindustry.editor.MapGenerateDialog", "mindustry.editor.MapInfoDialog", "mindustry.editor.MapLoadDialog", "mindustry.editor.MapRenderer", "mindustry.editor.MapResizeDialog", "mindustry.editor.MapSaveDialog", "mindustry.editor.MapView", "mindustry.editor.OperationStack", "mindustry.editor.WaveInfoDialog", "mindustry.entities.Damage", "mindustry.entities.Damage$PropCellStruct", "mindustry.entities.Effects", "mindustry.entities.Effects$Effect", "mindustry.entities.Effects$EffectContainer", "mindustry.entities.Effects$EffectProvider", "mindustry.entities.Effects$EffectRenderer", "mindustry.entities.Effects$ScreenshakeProvider", "mindustry.entities.Entities", "mindustry.entities.EntityCollisions", "mindustry.entities.EntityGroup", "mindustry.entities.Predict", "mindustry.entities.TargetPriority", "mindustry.entities.Units", "mindustry.entities.bullet.ArtilleryBulletType", "mindustry.entities.bullet.BasicBulletType", "mindustry.entities.bullet.BombBulletType", "mindustry.entities.bullet.BulletType", "mindustry.entities.bullet.FlakBulletType", "mindustry.entities.bullet.HealBulletType", "mindustry.entities.bullet.LiquidBulletType", "mindustry.entities.bullet.MassDriverBolt", "mindustry.entities.bullet.MissileBulletType", "mindustry.entities.effect.Decal", "mindustry.entities.effect.Fire", "mindustry.entities.effect.GroundEffectEntity", "mindustry.entities.effect.GroundEffectEntity$GroundEffect", "mindustry.entities.effect.ItemTransfer", "mindustry.entities.effect.Lightning", "mindustry.entities.effect.Puddle", "mindustry.entities.effect.RubbleDecal", "mindustry.entities.effect.ScorchDecal", "mindustry.entities.traits.AbsorbTrait", "mindustry.entities.traits.BelowLiquidTrait", "mindustry.entities.traits.BuilderMinerTrait", "mindustry.entities.traits.BuilderTrait", "mindustry.entities.traits.BuilderTrait$BuildDataStatic", "mindustry.entities.traits.BuilderTrait$BuildRequest", "mindustry.entities.traits.DamageTrait", "mindustry.entities.traits.DrawTrait", "mindustry.entities.traits.Entity", "mindustry.entities.traits.HealthTrait", "mindustry.entities.traits.KillerTrait", "mindustry.entities.traits.MinerTrait", "mindustry.entities.traits.MoveTrait", "mindustry.entities.traits.SaveTrait", "mindustry.entities.traits.Saveable", "mindustry.entities.traits.ScaleTrait", "mindustry.entities.traits.ShooterTrait", "mindustry.entities.traits.SolidTrait", "mindustry.entities.traits.SpawnerTrait", "mindustry.entities.traits.SyncTrait", "mindustry.entities.traits.TargetTrait", "mindustry.entities.traits.TeamTrait", "mindustry.entities.traits.TimeTrait", "mindustry.entities.traits.TypeTrait", "mindustry.entities.traits.VelocityTrait", "mindustry.entities.type.BaseEntity", "mindustry.entities.type.BaseUnit", "mindustry.entities.type.Bullet", "mindustry.entities.type.DestructibleEntity", "mindustry.entities.type.EffectEntity", "mindustry.entities.type.Player", "mindustry.entities.type.SolidEntity", "mindustry.entities.type.TileEntity", "mindustry.entities.type.TimedEntity", "mindustry.entities.type.Unit", "mindustry.entities.type.base.BaseDrone", "mindustry.entities.type.base.BuilderDrone", "mindustry.entities.type.base.FlyingUnit", "mindustry.entities.type.base.GroundUnit", "mindustry.entities.type.base.HoverUnit", "mindustry.entities.type.base.MinerDrone", "mindustry.entities.type.base.RepairDrone", "mindustry.entities.units.StateMachine", "mindustry.entities.units.Statuses", "mindustry.entities.units.Statuses$StatusEntry", "mindustry.entities.units.UnitCommand", "mindustry.entities.units.UnitDrops", "mindustry.entities.units.UnitState", "mindustry.game.DefaultWaves", "mindustry.game.Difficulty", "mindustry.game.EventType", "mindustry.game.EventType$BlockBuildBeginEvent", "mindustry.game.EventType$BlockBuildEndEvent", "mindustry.game.EventType$BlockDestroyEvent", "mindustry.game.EventType$BlockInfoEvent", "mindustry.game.EventType$BuildSelectEvent", "mindustry.game.EventType$ClientLoadEvent", "mindustry.game.EventType$CommandIssueEvent", "mindustry.game.EventType$ContentReloadEvent", "mindustry.game.EventType$CoreItemDeliverEvent", "mindustry.game.EventType$DepositEvent", "mindustry.game.EventType$DisposeEvent", "mindustry.game.EventType$GameOverEvent", "mindustry.game.EventType$LaunchEvent", "mindustry.game.EventType$LaunchItemEvent", "mindustry.game.EventType$LineConfirmEvent", "mindustry.game.EventType$LoseEvent", "mindustry.game.EventType$MapMakeEvent", "mindustry.game.EventType$MapPublishEvent", "mindustry.game.EventType$MechChangeEvent", "mindustry.game.EventType$PlayEvent", "mindustry.game.EventType$PlayerBanEvent", "mindustry.game.EventType$PlayerChatEvent", "mindustry.game.EventType$PlayerConnect", "mindustry.game.EventType$PlayerIpBanEvent", "mindustry.game.EventType$PlayerIpUnbanEvent", "mindustry.game.EventType$PlayerJoin", "mindustry.game.EventType$PlayerLeave", "mindustry.game.EventType$PlayerUnbanEvent", "mindustry.game.EventType$ResearchEvent", "mindustry.game.EventType$ResetEvent", "mindustry.game.EventType$ResizeEvent", "mindustry.game.EventType$ServerLoadEvent", "mindustry.game.EventType$StateChangeEvent", "mindustry.game.EventType$TapConfigEvent", "mindustry.game.EventType$TapEvent", "mindustry.game.EventType$TileChangeEvent", "mindustry.game.EventType$Trigger", "mindustry.game.EventType$TurretAmmoDeliverEvent", "mindustry.game.EventType$UnitCreateEvent", "mindustry.game.EventType$UnitDestroyEvent", "mindustry.game.EventType$UnlockEvent", "mindustry.game.EventType$WaveEvent", "mindustry.game.EventType$WinEvent", "mindustry.game.EventType$WithdrawEvent", "mindustry.game.EventType$WorldLoadEvent", "mindustry.game.EventType$ZoneConfigureCompleteEvent", "mindustry.game.EventType$ZoneRequireCompleteEvent", "mindustry.game.Gamemode", "mindustry.game.GlobalData", "mindustry.game.LoopControl", "mindustry.game.MusicControl", "mindustry.game.Objective", "mindustry.game.Objectives", "mindustry.game.Objectives$Launched", "mindustry.game.Objectives$Unlock", "mindustry.game.Objectives$Wave", "mindustry.game.Objectives$ZoneObjective", "mindustry.game.Objectives$ZoneWave", "mindustry.game.Rules", "mindustry.game.Saves", "mindustry.game.Saves$SaveSlot", "mindustry.game.Schematic", "mindustry.game.Schematic$Stile", "mindustry.game.Schematics", "mindustry.game.SoundLoop", "mindustry.game.SpawnGroup", "mindustry.game.Stats", "mindustry.game.Stats$Rank", "mindustry.game.Stats$RankResult", "mindustry.game.Team", "mindustry.game.Teams", "mindustry.game.Teams$BrokenBlock", "mindustry.game.Teams$TeamData", "mindustry.game.Tutorial", "mindustry.game.Tutorial$TutorialStage", "mindustry.gen.BufferItem", "mindustry.gen.Call", "mindustry.gen.Call", "mindustry.gen.Icon", "mindustry.gen.Icon", "mindustry.gen.MethodHash", "mindustry.gen.Musics", "mindustry.gen.Musics", "mindustry.gen.PathTile", "mindustry.gen.PropCell", "mindustry.gen.RemoteReadClient", "mindustry.gen.RemoteReadServer", "mindustry.gen.Serialization", "mindustry.gen.Sounds", "mindustry.gen.Sounds", "mindustry.gen.Tex", "mindustry.gen.Tex", "mindustry.gen.TileOp", "mindustry.graphics.BlockRenderer", "mindustry.graphics.Bloom", "mindustry.graphics.CacheLayer", "mindustry.graphics.Drawf", "mindustry.graphics.FloorRenderer", "mindustry.graphics.IndexedRenderer", "mindustry.graphics.Layer", "mindustry.graphics.LightRenderer", "mindustry.graphics.MenuRenderer", "mindustry.graphics.MinimapRenderer", "mindustry.graphics.MultiPacker", "mindustry.graphics.MultiPacker$PageType", "mindustry.graphics.OverlayRenderer", "mindustry.graphics.Pal", "mindustry.graphics.Pixelator", "mindustry.graphics.Shaders", "mindustry.input.Binding", "mindustry.input.DesktopInput", "mindustry.input.InputHandler", "mindustry.input.InputHandler$PlaceLine", "mindustry.input.MobileInput", "mindustry.input.PlaceMode", "mindustry.input.Placement", "mindustry.input.Placement$DistanceHeuristic", "mindustry.input.Placement$NormalizeDrawResult", "mindustry.input.Placement$NormalizeResult", "mindustry.input.Placement$TileHueristic", "mindustry.maps.Map", "mindustry.maps.Maps", "mindustry.maps.Maps$MapProvider", "mindustry.maps.Maps$ShuffleMode", "mindustry.maps.Maps$ShuffleMode", "mindustry.maps.filters.BlendFilter", "mindustry.maps.filters.ClearFilter", "mindustry.maps.filters.DistortFilter", "mindustry.maps.filters.FilterOption", "mindustry.maps.filters.FilterOption$BlockOption", "mindustry.maps.filters.FilterOption$SliderOption", "mindustry.maps.filters.GenerateFilter", "mindustry.maps.filters.GenerateFilter$GenerateInput", "mindustry.maps.filters.GenerateFilter$GenerateInput$TileProvider", "mindustry.maps.filters.MedianFilter", "mindustry.maps.filters.MirrorFilter", "mindustry.maps.filters.NoiseFilter", "mindustry.maps.filters.OreFilter", "mindustry.maps.filters.OreMedianFilter", "mindustry.maps.filters.RiverNoiseFilter", "mindustry.maps.filters.ScatterFilter", "mindustry.maps.filters.TerrainFilter", "mindustry.maps.generators.BasicGenerator", "mindustry.maps.generators.BasicGenerator$DistanceHeuristic", "mindustry.maps.generators.BasicGenerator$TileHueristic", "mindustry.maps.generators.Generator", "mindustry.maps.generators.MapGenerator", "mindustry.maps.generators.MapGenerator$Decoration", "mindustry.maps.generators.RandomGenerator", "mindustry.maps.zonegen.DesertWastesGenerator", "mindustry.maps.zonegen.OvergrowthGenerator", "mindustry.type.Category", "mindustry.type.ErrorContent", "mindustry.type.Item", "mindustry.type.ItemStack", "mindustry.type.ItemType", "mindustry.type.Liquid", "mindustry.type.LiquidStack", "mindustry.type.Mech", "mindustry.type.Publishable", "mindustry.type.StatusEffect", "mindustry.type.StatusEffect$TransitionHandler", "mindustry.type.TypeID", "mindustry.type.UnitType", "mindustry.type.Weapon", "mindustry.type.WeatherEvent", "mindustry.type.Zone", "mindustry.ui.Bar", "mindustry.ui.BorderImage", "mindustry.ui.Cicon", "mindustry.ui.ContentDisplay", "mindustry.ui.Fonts", "mindustry.ui.GridImage", "mindustry.ui.IconSize", "mindustry.ui.IntFormat", "mindustry.ui.ItemDisplay", "mindustry.ui.ItemImage", "mindustry.ui.ItemsDisplay", "mindustry.ui.Links", "mindustry.ui.Links$LinkEntry", "mindustry.ui.LiquidDisplay", "mindustry.ui.Minimap", "mindustry.ui.MobileButton", "mindustry.ui.MultiReqImage", "mindustry.ui.ReqImage", "mindustry.ui.Styles", "mindustry.ui.dialogs.AboutDialog", "mindustry.ui.dialogs.AdminsDialog", "mindustry.ui.dialogs.BansDialog", "mindustry.ui.dialogs.ColorPicker", "mindustry.ui.dialogs.ContentInfoDialog", "mindustry.ui.dialogs.ControlsDialog", "mindustry.ui.dialogs.CustomGameDialog", "mindustry.ui.dialogs.CustomRulesDialog", "mindustry.ui.dialogs.DatabaseDialog", "mindustry.ui.dialogs.DeployDialog", "mindustry.ui.dialogs.DeployDialog$View", "mindustry.ui.dialogs.DeployDialog$ZoneNode", "mindustry.ui.dialogs.DiscordDialog", "mindustry.ui.dialogs.FileChooser", "mindustry.ui.dialogs.FileChooser$FileHistory", "mindustry.ui.dialogs.FloatingDialog", "mindustry.ui.dialogs.GameOverDialog", "mindustry.ui.dialogs.HostDialog", "mindustry.ui.dialogs.JoinDialog", "mindustry.ui.dialogs.JoinDialog$Server", "mindustry.ui.dialogs.LanguageDialog", "mindustry.ui.dialogs.LoadDialog", "mindustry.ui.dialogs.LoadoutDialog", "mindustry.ui.dialogs.MapPlayDialog", "mindustry.ui.dialogs.MapsDialog", "mindustry.ui.dialogs.MinimapDialog", "mindustry.ui.dialogs.ModsDialog", "mindustry.ui.dialogs.PaletteDialog", "mindustry.ui.dialogs.PausedDialog", "mindustry.ui.dialogs.SaveDialog", "mindustry.ui.dialogs.SchematicsDialog", "mindustry.ui.dialogs.SchematicsDialog$SchematicImage", "mindustry.ui.dialogs.SchematicsDialog$SchematicInfoDialog", "mindustry.ui.dialogs.SettingsMenuDialog", "mindustry.ui.dialogs.TechTreeDialog", "mindustry.ui.dialogs.TechTreeDialog$LayoutNode", "mindustry.ui.dialogs.TechTreeDialog$TechTreeNode", "mindustry.ui.dialogs.TechTreeDialog$View", "mindustry.ui.dialogs.TraceDialog", "mindustry.ui.dialogs.ZoneInfoDialog", "mindustry.ui.fragments.BlockConfigFragment", "mindustry.ui.fragments.BlockInventoryFragment", "mindustry.ui.fragments.ChatFragment", "mindustry.ui.fragments.FadeInFragment", "mindustry.ui.fragments.Fragment", "mindustry.ui.fragments.HudFragment", "mindustry.ui.fragments.LoadingFragment", "mindustry.ui.fragments.MenuFragment", "mindustry.ui.fragments.OverlayFragment", "mindustry.ui.fragments.PlacementFragment", "mindustry.ui.fragments.PlayerListFragment", "mindustry.ui.fragments.ScriptConsoleFragment", "mindustry.ui.layout.BranchTreeLayout", "mindustry.ui.layout.BranchTreeLayout$TreeAlignment", "mindustry.ui.layout.BranchTreeLayout$TreeLocation", "mindustry.ui.layout.RadialTreeLayout", "mindustry.ui.layout.TreeLayout", "mindustry.ui.layout.TreeLayout$TreeNode", "mindustry.world.Block", "mindustry.world.BlockStorage", "mindustry.world.Build", "mindustry.world.CachedTile", "mindustry.world.DirectionalItemBuffer", "mindustry.world.DirectionalItemBuffer$BufferItemStruct", "mindustry.world.Edges", "mindustry.world.ItemBuffer", "mindustry.world.LegacyColorMapper", "mindustry.world.LegacyColorMapper$LegacyBlock", "mindustry.world.Pos", "mindustry.world.StaticTree", "mindustry.world.Tile", "mindustry.world.WorldContext", "mindustry.world.blocks.Attributes", "mindustry.world.blocks.Autotiler", "mindustry.world.blocks.Autotiler$AutotilerHolder", "mindustry.world.blocks.BlockPart", "mindustry.world.blocks.BuildBlock", "mindustry.world.blocks.BuildBlock$BuildEntity", "mindustry.world.blocks.DoubleOverlayFloor", "mindustry.world.blocks.Floor", "mindustry.world.blocks.ItemSelection", "mindustry.world.blocks.LiquidBlock", "mindustry.world.blocks.OreBlock", "mindustry.world.blocks.OverlayFloor", "mindustry.world.blocks.PowerBlock", "mindustry.world.blocks.RespawnBlock", "mindustry.world.blocks.Rock", "mindustry.world.blocks.StaticWall", "mindustry.world.blocks.TreeBlock", "mindustry.world.blocks.defense.DeflectorWall", "mindustry.world.blocks.defense.DeflectorWall$DeflectorEntity", "mindustry.world.blocks.defense.Door", "mindustry.world.blocks.defense.Door$DoorEntity", "mindustry.world.blocks.defense.ForceProjector", "mindustry.world.blocks.defense.ForceProjector$ForceEntity", "mindustry.world.blocks.defense.ForceProjector$ShieldEntity", "mindustry.world.blocks.defense.MendProjector", "mindustry.world.blocks.defense.MendProjector$MendEntity", "mindustry.world.blocks.defense.OverdriveProjector", "mindustry.world.blocks.defense.OverdriveProjector$OverdriveEntity", "mindustry.world.blocks.defense.ShockMine", "mindustry.world.blocks.defense.SurgeWall", "mindustry.world.blocks.defense.Wall", "mindustry.world.blocks.defense.turrets.ArtilleryTurret", "mindustry.world.blocks.defense.turrets.BurstTurret", "mindustry.world.blocks.defense.turrets.ChargeTurret", "mindustry.world.blocks.defense.turrets.ChargeTurret$LaserTurretEntity", "mindustry.world.blocks.defense.turrets.CooledTurret", "mindustry.world.blocks.defense.turrets.DoubleTurret", "mindustry.world.blocks.defense.turrets.ItemTurret", "mindustry.world.blocks.defense.turrets.ItemTurret$ItemEntry", "mindustry.world.blocks.defense.turrets.ItemTurret$ItemTurretEntity", "mindustry.world.blocks.defense.turrets.LaserTurret", "mindustry.world.blocks.defense.turrets.LaserTurret$LaserTurretEntity", "mindustry.world.blocks.defense.turrets.LiquidTurret", "mindustry.world.blocks.defense.turrets.PowerTurret", "mindustry.world.blocks.defense.turrets.Turret", "mindustry.world.blocks.defense.turrets.Turret$AmmoEntry", "mindustry.world.blocks.defense.turrets.Turret$TurretEntity", "mindustry.world.blocks.distribution.ArmoredConveyor", "mindustry.world.blocks.distribution.BufferedItemBridge", "mindustry.world.blocks.distribution.BufferedItemBridge$BufferedItemBridgeEntity", "mindustry.world.blocks.distribution.Conveyor", "mindustry.world.blocks.distribution.Conveyor$ConveyorEntity", "mindustry.world.blocks.distribution.Conveyor$ItemPos", "mindustry.world.blocks.distribution.ExtendingItemBridge", "mindustry.world.blocks.distribution.ItemBridge", "mindustry.world.blocks.distribution.ItemBridge$ItemBridgeEntity", "mindustry.world.blocks.distribution.Junction", "mindustry.world.blocks.distribution.Junction$JunctionEntity", "mindustry.world.blocks.distribution.MassDriver", "mindustry.world.blocks.distribution.MassDriver$DriverBulletData", "mindustry.world.blocks.distribution.MassDriver$DriverState", "mindustry.world.blocks.distribution.MassDriver$MassDriverEntity", "mindustry.world.blocks.distribution.OverflowGate", "mindustry.world.blocks.distribution.OverflowGate$OverflowGateEntity", "mindustry.world.blocks.distribution.Router", "mindustry.world.blocks.distribution.Router$RouterEntity", "mindustry.world.blocks.distribution.Sorter", "mindustry.world.blocks.distribution.Sorter$SorterEntity", "mindustry.world.blocks.liquid.ArmoredConduit", "mindustry.world.blocks.liquid.Conduit", "mindustry.world.blocks.liquid.Conduit$ConduitEntity", "mindustry.world.blocks.liquid.LiquidBridge", "mindustry.world.blocks.liquid.LiquidExtendingBridge", "mindustry.world.blocks.liquid.LiquidJunction", "mindustry.world.blocks.liquid.LiquidOverflowGate", "mindustry.world.blocks.liquid.LiquidRouter", "mindustry.world.blocks.liquid.LiquidTank", "mindustry.world.blocks.logic.LogicBlock", "mindustry.world.blocks.logic.MessageBlock", "mindustry.world.blocks.logic.MessageBlock$MessageBlockEntity", "mindustry.world.blocks.power.Battery", "mindustry.world.blocks.power.BurnerGenerator", "mindustry.world.blocks.power.ConditionalConsumePower", "mindustry.world.blocks.power.DecayGenerator", "mindustry.world.blocks.power.ImpactReactor", "mindustry.world.blocks.power.ImpactReactor$FusionReactorEntity", "mindustry.world.blocks.power.ItemLiquidGenerator", "mindustry.world.blocks.power.ItemLiquidGenerator$ItemLiquidGeneratorEntity", "mindustry.world.blocks.power.LightBlock", "mindustry.world.blocks.power.LightBlock$LightEntity", "mindustry.world.blocks.power.NuclearReactor", "mindustry.world.blocks.power.NuclearReactor$NuclearReactorEntity", "mindustry.world.blocks.power.PowerDiode", "mindustry.world.blocks.power.PowerDistributor", "mindustry.world.blocks.power.PowerGenerator", "mindustry.world.blocks.power.PowerGenerator$GeneratorEntity", "mindustry.world.blocks.power.PowerGraph", "mindustry.world.blocks.power.PowerNode", "mindustry.world.blocks.power.SingleTypeGenerator", "mindustry.world.blocks.power.SolarGenerator", "mindustry.world.blocks.power.ThermalGenerator", "mindustry.world.blocks.production.Cultivator", "mindustry.world.blocks.production.Cultivator$CultivatorEntity", "mindustry.world.blocks.production.Drill", "mindustry.world.blocks.production.Drill$DrillEntity", "mindustry.world.blocks.production.Fracker", "mindustry.world.blocks.production.Fracker$FrackerEntity", "mindustry.world.blocks.production.GenericCrafter", "mindustry.world.blocks.production.GenericCrafter$GenericCrafterEntity", "mindustry.world.blocks.production.GenericSmelter", "mindustry.world.blocks.production.Incinerator", "mindustry.world.blocks.production.Incinerator$IncineratorEntity", "mindustry.world.blocks.production.LiquidConverter", "mindustry.world.blocks.production.Pump", "mindustry.world.blocks.production.Separator", "mindustry.world.blocks.production.SolidPump", "mindustry.world.blocks.production.SolidPump$SolidPumpEntity", "mindustry.world.blocks.sandbox.ItemSource", "mindustry.world.blocks.sandbox.ItemSource$ItemSourceEntity", "mindustry.world.blocks.sandbox.ItemVoid", "mindustry.world.blocks.sandbox.LiquidSource", "mindustry.world.blocks.sandbox.LiquidSource$LiquidSourceEntity", "mindustry.world.blocks.sandbox.PowerSource", "mindustry.world.blocks.sandbox.PowerVoid", "mindustry.world.blocks.storage.CoreBlock", "mindustry.world.blocks.storage.CoreBlock$CoreEntity", "mindustry.world.blocks.storage.LaunchPad", "mindustry.world.blocks.storage.StorageBlock", "mindustry.world.blocks.storage.StorageBlock$StorageBlockEntity", "mindustry.world.blocks.storage.Unloader", "mindustry.world.blocks.storage.Unloader$UnloaderEntity", "mindustry.world.blocks.storage.Vault", "mindustry.world.blocks.units.CommandCenter", "mindustry.world.blocks.units.CommandCenter$CommandCenterEntity", "mindustry.world.blocks.units.MechPad", "mindustry.world.blocks.units.MechPad$MechFactoryEntity", "mindustry.world.blocks.units.RallyPoint", "mindustry.world.blocks.units.RepairPoint", "mindustry.world.blocks.units.RepairPoint$RepairPointEntity", "mindustry.world.blocks.units.UnitFactory", "mindustry.world.blocks.units.UnitFactory$UnitFactoryEntity", "mindustry.world.consumers.Consume", "mindustry.world.consumers.ConsumeItemFilter", "mindustry.world.consumers.ConsumeItems", "mindustry.world.consumers.ConsumeLiquid", "mindustry.world.consumers.ConsumeLiquidBase", "mindustry.world.consumers.ConsumeLiquidFilter", "mindustry.world.consumers.ConsumePower", "mindustry.world.consumers.ConsumeType", "mindustry.world.consumers.Consumers", "mindustry.world.meta.Attribute", "mindustry.world.meta.BlockBars", "mindustry.world.meta.BlockFlag", "mindustry.world.meta.BlockGroup", "mindustry.world.meta.BlockStat", "mindustry.world.meta.BlockStats", "mindustry.world.meta.BuildVisibility", "mindustry.world.meta.PowerType", "mindustry.world.meta.Producers", "mindustry.world.meta.StatCategory", "mindustry.world.meta.StatUnit", "mindustry.world.meta.StatValue", "mindustry.world.meta.values.AmmoListValue", "mindustry.world.meta.values.BooleanValue", "mindustry.world.meta.values.BoosterListValue", "mindustry.world.meta.values.ItemFilterValue", "mindustry.world.meta.values.ItemListValue", "mindustry.world.meta.values.LiquidFilterValue", "mindustry.world.meta.values.LiquidValue", "mindustry.world.meta.values.NumberValue", "mindustry.world.meta.values.StringValue", "mindustry.world.modules.BlockModule", "mindustry.world.modules.ConsumeModule", "mindustry.world.modules.ItemModule", "mindustry.world.modules.ItemModule$ItemCalculator", "mindustry.world.modules.ItemModule$ItemConsumer", "mindustry.world.modules.LiquidModule", "mindustry.world.modules.LiquidModule$LiquidCalculator", "mindustry.world.modules.LiquidModule$LiquidConsumer", "mindustry.world.modules.PowerModule", "mindustry.world.producers.Produce", "mindustry.world.producers.ProduceItem"); } \ No newline at end of file diff --git a/tools/src/mindustry/tools/ScriptStubGenerator.java b/tools/src/mindustry/tools/ScriptStubGenerator.java index d13bbbdd49..c60b6589fa 100644 --- a/tools/src/mindustry/tools/ScriptStubGenerator.java +++ b/tools/src/mindustry/tools/ScriptStubGenerator.java @@ -26,7 +26,7 @@ public class ScriptStubGenerator{ Array nameBlacklist = Array.with("ClientLauncher", "NetClient", "NetServer", "ClassAccess"); Array> whitelist = Array.with(Draw.class, Fill.class, Lines.class, Core.class, TextureAtlas.class, TextureRegion.class, Time.class, System.class, PrintStream.class, AtlasRegion.class, String.class, Mathf.class, Angles.class, Color.class, Runnable.class, Object.class, Icon.class, Tex.class, - Sounds.class, Musics.class, Call.class, Texture.class, TextureData.class, Pixmap.class, I18NBundle.class); + Sounds.class, Musics.class, Call.class, Texture.class, TextureData.class, Pixmap.class, I18NBundle.class, Interval.class, DataInput.class, DataOutput.class, DataInputStream.class, DataOutputStream.class); Array nopackage = Array.with("java.lang", "java"); String fileTemplate = "package mindustry.mod;\n" + @@ -49,6 +49,7 @@ public class ScriptStubGenerator{ .include(FilterBuilder.prefix("arc.func")) .include(FilterBuilder.prefix("arc.struct")) .include(FilterBuilder.prefix("arc.scene")) + .include(FilterBuilder.prefix("arc.math")) )); Array> classes = Array.with(reflections.getSubTypesOf(Object.class)); From 6edcbb9120a20ba2fcdae09db069017f72c6f1c9 Mon Sep 17 00:00:00 2001 From: Anuken Date: Sun, 29 Dec 2019 14:38:03 -0500 Subject: [PATCH 32/78] Bugfixes --- core/assets/bundles/bundle.properties | 1 + core/src/mindustry/entities/type/TileEntity.java | 8 ++++++++ core/src/mindustry/game/Rules.java | 2 ++ core/src/mindustry/input/DesktopInput.java | 4 ++-- core/src/mindustry/input/InputHandler.java | 4 ++-- core/src/mindustry/ui/dialogs/CustomRulesDialog.java | 1 + .../mindustry/ui/fragments/BlockInventoryFragment.java | 2 +- .../src/mindustry/ui/fragments/ScriptConsoleFragment.java | 4 ++-- .../src/mindustry/world/blocks/distribution/Junction.java | 7 +++---- core/src/mindustry/world/blocks/distribution/Sorter.java | 2 +- 10 files changed, 23 insertions(+), 12 deletions(-) diff --git a/core/assets/bundles/bundle.properties b/core/assets/bundles/bundle.properties index 73fee4471d..ca90137fbb 100644 --- a/core/assets/bundles/bundle.properties +++ b/core/assets/bundles/bundle.properties @@ -755,6 +755,7 @@ rules.enemyCheat = Infinite AI (Red Team) Resources rules.unitdrops = Unit Drops rules.unitbuildspeedmultiplier = Unit Production Speed Multiplier rules.unithealthmultiplier = Unit Health Multiplier +rules.blockhealthmultiplier = Block Health Multiplier rules.playerhealthmultiplier = Player Health Multiplier rules.playerdamagemultiplier = Player Damage Multiplier rules.unitdamagemultiplier = Unit Damage Multiplier diff --git a/core/src/mindustry/entities/type/TileEntity.java b/core/src/mindustry/entities/type/TileEntity.java index 4a2a5aee91..cf5a2f4bdb 100644 --- a/core/src/mindustry/entities/type/TileEntity.java +++ b/core/src/mindustry/entities/type/TileEntity.java @@ -1,5 +1,6 @@ package mindustry.entities.type; +import arc.math.*; import mindustry.annotations.Annotations.*; import arc.Events; import arc.struct.Array; @@ -165,9 +166,16 @@ public class TileEntity extends BaseEntity implements TargetTrait, HealthTrait{ Call.onTileDestroyed(tile); } + @Override public void damage(float damage){ if(dead) return; + if(Mathf.zero(state.rules.blockHealthMultiplier)){ + damage = health + 1; + }else{ + damage /= state.rules.blockHealthMultiplier; + } + float preHealth = health; Call.onTileDamage(tile, health - block.handleDamage(tile, damage)); diff --git a/core/src/mindustry/game/Rules.java b/core/src/mindustry/game/Rules.java index 06231e5318..0515d2ca60 100644 --- a/core/src/mindustry/game/Rules.java +++ b/core/src/mindustry/game/Rules.java @@ -34,6 +34,8 @@ public class Rules{ public float unitHealthMultiplier = 1f; /** How much health players start with. */ public float playerHealthMultiplier = 1f; + /** How much health blocks start with. */ + public float blockHealthMultiplier = 1f; /** How much damage player mechs deal. */ public float playerDamageMultiplier = 1f; /** How much damage any other units deal. */ diff --git a/core/src/mindustry/input/DesktopInput.java b/core/src/mindustry/input/DesktopInput.java index df735999d8..b1d483df37 100644 --- a/core/src/mindustry/input/DesktopInput.java +++ b/core/src/mindustry/input/DesktopInput.java @@ -136,7 +136,7 @@ public class DesktopInput extends InputHandler{ ui.listfrag.toggle(); } - if(player.getClosestCore() == null){ + if(player.getClosestCore() == null && !ui.chatfrag.shown()){ //move camera around float camSpeed = 6f; Core.camera.position.add(Tmp.v1.setZero().add(Core.input.axis(Binding.move_x), Core.input.axis(Binding.move_y)).nor().scl(Time.delta() * camSpeed)); @@ -157,7 +157,7 @@ public class DesktopInput extends InputHandler{ if(state.is(State.menu) || Core.scene.hasDialog()) return; //zoom camera - if(!Core.scene.hasScroll() && !ui.chatfrag.shown() && Math.abs(Core.input.axisTap(Binding.zoom)) > 0 && !Core.input.keyDown(Binding.rotateplaced) && (Core.input.keyDown(Binding.diagonal_placement) || ((!isPlacing() || !block.rotate) && selectRequests.isEmpty()))){ + if((!Core.scene.hasScroll() || Core.input.keyDown(Binding.diagonal_placement)) && !ui.chatfrag.shown() && Math.abs(Core.input.axisTap(Binding.zoom)) > 0 && !Core.input.keyDown(Binding.rotateplaced) && (Core.input.keyDown(Binding.diagonal_placement) || ((!isPlacing() || !block.rotate) && selectRequests.isEmpty()))){ renderer.scaleCamera(Core.input.axisTap(Binding.zoom)); } diff --git a/core/src/mindustry/input/InputHandler.java b/core/src/mindustry/input/InputHandler.java index 4a6ffb575b..e56244928e 100644 --- a/core/src/mindustry/input/InputHandler.java +++ b/core/src/mindustry/input/InputHandler.java @@ -92,7 +92,7 @@ public abstract class InputHandler implements InputProcessor, GestureListener{ @Remote(targets = Loc.both, forward = true, called = Loc.server) public static void transferInventory(Player player, Tile tile){ - if(player == null || player.timer == null || !player.timer.get(Player.timerTransfer, 40)) return; + if(player == null || player.timer == null) return; if(net.server() && (player.item().amount <= 0 || player.isTransferring|| !Units.canInteract(player, tile))){ throw new ValidateException(player, "Player cannot transfer an item."); } @@ -725,7 +725,7 @@ public abstract class InputHandler implements InputProcessor, GestureListener{ } public void tryDropItems(Tile tile, float x, float y){ - if(!droppingItem || player.item().amount <= 0 || canTapPlayer(x, y) || state.isPaused() || !player.timer.check(Player.timerTransfer, 40)){ + if(!droppingItem || player.item().amount <= 0 || canTapPlayer(x, y) || state.isPaused() ){ droppingItem = false; return; } diff --git a/core/src/mindustry/ui/dialogs/CustomRulesDialog.java b/core/src/mindustry/ui/dialogs/CustomRulesDialog.java index 54e4720d65..73eb5a9efa 100644 --- a/core/src/mindustry/ui/dialogs/CustomRulesDialog.java +++ b/core/src/mindustry/ui/dialogs/CustomRulesDialog.java @@ -142,6 +142,7 @@ public class CustomRulesDialog extends FloatingDialog{ check("$rules.reactorexplosions", b -> rules.reactorExplosions = b, () -> rules.reactorExplosions); number("$rules.buildcostmultiplier", false, f -> rules.buildCostMultiplier = f, () -> rules.buildCostMultiplier, () -> !rules.infiniteResources); number("$rules.buildspeedmultiplier", f -> rules.buildSpeedMultiplier = f, () -> rules.buildSpeedMultiplier); + number("$rules.blockhealthmultiplier", f -> rules.blockHealthMultiplier = f, () -> rules.blockHealthMultiplier); main.addButton("$configure", () -> loadoutDialog.show(Blocks.coreShard.itemCapacity, rules.loadout, diff --git a/core/src/mindustry/ui/fragments/BlockInventoryFragment.java b/core/src/mindustry/ui/fragments/BlockInventoryFragment.java index e77a240e36..c4cc71cc5a 100644 --- a/core/src/mindustry/ui/fragments/BlockInventoryFragment.java +++ b/core/src/mindustry/ui/fragments/BlockInventoryFragment.java @@ -36,7 +36,7 @@ public class BlockInventoryFragment extends Fragment{ @Remote(called = Loc.server, targets = Loc.both, forward = true) public static void requestItem(Player player, Tile tile, Item item, int amount){ - if(player == null || tile == null || !player.timer.get(Player.timerTransfer, 20) || !tile.interactable(player.getTeam())) return; + if(player == null || tile == null || !tile.interactable(player.getTeam())) return; if(!Units.canInteract(player, tile)) return; int removed = tile.block().removeStack(tile, item, amount); diff --git a/core/src/mindustry/ui/fragments/ScriptConsoleFragment.java b/core/src/mindustry/ui/fragments/ScriptConsoleFragment.java index 1f667602de..15149e064a 100644 --- a/core/src/mindustry/ui/fragments/ScriptConsoleFragment.java +++ b/core/src/mindustry/ui/fragments/ScriptConsoleFragment.java @@ -45,7 +45,7 @@ public class ScriptConsoleFragment extends Table{ font = Fonts.def; visible(() -> { - if(input.keyTap(Binding.console) && !Vars.net.client() && (scene.getKeyboardFocus() == chatfield || scene.getKeyboardFocus() == null)){ + if(input.keyTap(Binding.console) && (scene.getKeyboardFocus() == chatfield || scene.getKeyboardFocus() == null)){ shown = !shown; if(shown && !open && enableConsole){ toggle(); @@ -53,7 +53,7 @@ public class ScriptConsoleFragment extends Table{ clearChatInput(); } - return shown && !Vars.net.active(); + return shown; }); update(() -> { diff --git a/core/src/mindustry/world/blocks/distribution/Junction.java b/core/src/mindustry/world/blocks/distribution/Junction.java index 43356ca939..99c22057e1 100644 --- a/core/src/mindustry/world/blocks/distribution/Junction.java +++ b/core/src/mindustry/world/blocks/distribution/Junction.java @@ -58,7 +58,7 @@ public class Junction extends Block{ if(dest != null) dest = dest.link(); //skip blocks that don't want the item, keep waiting until they do - if(dest == null || !dest.block().acceptItem(item, dest, tile)){ + if(dest == null || !dest.block().acceptItem(item, dest, tile) || dest.getTeam() != tile.getTeam()){ continue; } @@ -82,10 +82,9 @@ public class Junction extends Block{ JunctionEntity entity = tile.ent(); int relative = source.relativeTo(tile.x, tile.y); - if(entity == null || relative == -1 || !entity.buffer.accepts(relative)) - return false; + if(entity == null || relative == -1 || !entity.buffer.accepts(relative)) return false; Tile to = tile.getNearby(relative); - return to != null && to.link().entity != null; + return to != null && to.link().entity != null && to.getTeam() == tile.getTeam(); } class JunctionEntity extends TileEntity{ diff --git a/core/src/mindustry/world/blocks/distribution/Sorter.java b/core/src/mindustry/world/blocks/distribution/Sorter.java index 89228d02de..1df5fe75e5 100644 --- a/core/src/mindustry/world/blocks/distribution/Sorter.java +++ b/core/src/mindustry/world/blocks/distribution/Sorter.java @@ -74,7 +74,7 @@ public class Sorter extends Block{ public boolean acceptItem(Item item, Tile tile, Tile source){ Tile to = getTileTarget(item, tile, source, false); - return to != null && to.block().acceptItem(item, to, tile); + return to != null && to.block().acceptItem(item, to, tile) && to.getTeam() == tile.getTeam(); } @Override From 811c22b84eb60665600f8fb94ee258f1ba7f82ed Mon Sep 17 00:00:00 2001 From: Anuken Date: Sun, 29 Dec 2019 15:40:56 -0500 Subject: [PATCH 33/78] Added camera movement while paused --- core/src/mindustry/core/Renderer.java | 12 +++++++----- core/src/mindustry/input/DesktopInput.java | 4 ++-- .../ui/fragments/ScriptConsoleFragment.java | 2 +- gradle.properties | 2 +- server/src/mindustry/server/ServerControl.java | 4 ++-- 5 files changed, 13 insertions(+), 11 deletions(-) diff --git a/core/src/mindustry/core/Renderer.java b/core/src/mindustry/core/Renderer.java index 9c284a5f06..7d5e6714b5 100644 --- a/core/src/mindustry/core/Renderer.java +++ b/core/src/mindustry/core/Renderer.java @@ -123,12 +123,14 @@ public class Renderer implements ApplicationListener{ if(player.isDead()){ TileEntity core = player.getClosestCore(); - if(core != null && player.spawner == null){ - camera.position.lerpDelta(core.x, core.y, 0.08f); - }else if(core != null){ - camera.position.lerpDelta(position, 0.08f); + if(core != null){ + if(player.spawner == null){ + camera.position.lerpDelta(core.x, core.y, 0.08f); + }else{ + camera.position.lerpDelta(position, 0.08f); + } } - }else if(control.input instanceof DesktopInput){ + }else if(control.input instanceof DesktopInput && !state.isPaused()){ camera.position.lerpDelta(position, 0.08f); } diff --git a/core/src/mindustry/input/DesktopInput.java b/core/src/mindustry/input/DesktopInput.java index b1d483df37..e2efcac160 100644 --- a/core/src/mindustry/input/DesktopInput.java +++ b/core/src/mindustry/input/DesktopInput.java @@ -136,9 +136,9 @@ public class DesktopInput extends InputHandler{ ui.listfrag.toggle(); } - if(player.getClosestCore() == null && !ui.chatfrag.shown()){ + if((player.getClosestCore() == null || state.isPaused()) && !ui.chatfrag.shown()){ //move camera around - float camSpeed = 6f; + float camSpeed = !Core.input.keyDown(Binding.dash) ? 3f : 8f; Core.camera.position.add(Tmp.v1.setZero().add(Core.input.axis(Binding.move_x), Core.input.axis(Binding.move_y)).nor().scl(Time.delta() * camSpeed)); } diff --git a/core/src/mindustry/ui/fragments/ScriptConsoleFragment.java b/core/src/mindustry/ui/fragments/ScriptConsoleFragment.java index 15149e064a..378359f631 100644 --- a/core/src/mindustry/ui/fragments/ScriptConsoleFragment.java +++ b/core/src/mindustry/ui/fragments/ScriptConsoleFragment.java @@ -53,7 +53,7 @@ public class ScriptConsoleFragment extends Table{ clearChatInput(); } - return shown; + return shown && Vars.net.active(); }); update(() -> { diff --git a/gradle.properties b/gradle.properties index 51de1f3142..8ed0e699dd 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,3 +1,3 @@ org.gradle.daemon=true org.gradle.jvmargs=-Xms256m -Xmx1024m -archash=fe82ca9037028044764cc4b02fdbf851e3d09f78 +archash=14b6027d79cda5e02d74a7c2f85eb7e768c7abeb diff --git a/server/src/mindustry/server/ServerControl.java b/server/src/mindustry/server/ServerControl.java index 352331f80c..d834ecd907 100644 --- a/server/src/mindustry/server/ServerControl.java +++ b/server/src/mindustry/server/ServerControl.java @@ -1,11 +1,11 @@ package mindustry.server; import arc.*; +import arc.files.*; import arc.struct.*; import arc.struct.Array.*; -import arc.files.*; -import arc.util.*; import arc.util.ArcAnnotate.*; +import arc.util.*; import arc.util.Timer; import arc.util.CommandHandler.*; import arc.util.Timer.*; From 670f085f780aafd66972ed0da68ea1775f1b604e Mon Sep 17 00:00:00 2001 From: Anuken Date: Sun, 29 Dec 2019 17:56:10 -0500 Subject: [PATCH 34/78] New, improved minimap / Bugfixes --- core/assets/scripts/base.js | 2 +- core/assets/scripts/global.js | 2 +- core/src/mindustry/core/UI.java | 6 +- core/src/mindustry/entities/type/Player.java | 9 +- core/src/mindustry/game/Team.java | 2 +- .../mindustry/graphics/MinimapRenderer.java | 27 ++-- .../mindustry/graphics/OverlayRenderer.java | 2 +- core/src/mindustry/input/DesktopInput.java | 13 +- core/src/mindustry/ui/Minimap.java | 4 +- .../ui/fragments/MinimapFragment.java | 115 ++++++++++++++++++ .../blocks/distribution/OverflowGate.java | 6 +- .../world/blocks/storage/CoreBlock.java | 2 +- .../src/mindustry/server/ServerControl.java | 2 +- 13 files changed, 159 insertions(+), 33 deletions(-) create mode 100644 core/src/mindustry/ui/fragments/MinimapFragment.java diff --git a/core/assets/scripts/base.js b/core/assets/scripts/base.js index a83a66c728..6ce3070968 100755 --- a/core/assets/scripts/base.js +++ b/core/assets/scripts/base.js @@ -16,5 +16,5 @@ const boolp = method => new Boolp(){get: method} const cons = method => new Cons(){get: method} const prov = method => new Prov(){get: method} const newEffect = (lifetime, renderer) => new Effects.Effect(lifetime, new Effects.EffectRenderer({render: renderer})) -Call = Packages.io.anuke.mindustry.gen.Call +Call = Packages.mindustry.gen.Call const Calls = Call //backwards compat \ No newline at end of file diff --git a/core/assets/scripts/global.js b/core/assets/scripts/global.js index 9ba7fc5e4c..22d746b420 100755 --- a/core/assets/scripts/global.js +++ b/core/assets/scripts/global.js @@ -18,7 +18,7 @@ const boolp = method => new Boolp(){get: method} const cons = method => new Cons(){get: method} const prov = method => new Prov(){get: method} const newEffect = (lifetime, renderer) => new Effects.Effect(lifetime, new Effects.EffectRenderer({render: renderer})) -Call = Packages.io.anuke.mindustry.gen.Call +Call = Packages.mindustry.gen.Call const Calls = Call //backwards compat importPackage(Packages.arc) importPackage(Packages.arc.func) diff --git a/core/src/mindustry/core/UI.java b/core/src/mindustry/core/UI.java index 1ce41f6e24..58cb23d802 100644 --- a/core/src/mindustry/core/UI.java +++ b/core/src/mindustry/core/UI.java @@ -43,6 +43,7 @@ public class UI implements ApplicationListener, Loadable{ public HudFragment hudfrag; public ChatFragment chatfrag; public ScriptConsoleFragment scriptfrag; + public MinimapFragment minimapfrag; public PlayerListFragment listfrag; public LoadingFragment loadfrag; @@ -68,7 +69,7 @@ public class UI implements ApplicationListener, Loadable{ public ContentInfoDialog content; public DeployDialog deploy; public TechTreeDialog tech; - public MinimapDialog minimap; + //public MinimapDialog minimap; public SchematicsDialog schematics; public ModsDialog mods; public ColorPicker picker; @@ -210,6 +211,7 @@ public class UI implements ApplicationListener, Loadable{ menufrag = new MenuFragment(); hudfrag = new HudFragment(); chatfrag = new ChatFragment(); + minimapfrag = new MinimapFragment(); listfrag = new PlayerListFragment(); loadfrag = new LoadingFragment(); scriptfrag = new ScriptConsoleFragment(); @@ -235,7 +237,6 @@ public class UI implements ApplicationListener, Loadable{ content = new ContentInfoDialog(); deploy = new DeployDialog(); tech = new TechTreeDialog(); - minimap = new MinimapDialog(); mods = new ModsDialog(); schematics = new SchematicsDialog(); @@ -254,6 +255,7 @@ public class UI implements ApplicationListener, Loadable{ hudfrag.build(hudGroup); menufrag.build(menuGroup); chatfrag.container().build(hudGroup); + minimapfrag.build(hudGroup); listfrag.build(hudGroup); scriptfrag.container().build(hudGroup); loadfrag.build(group); diff --git a/core/src/mindustry/entities/type/Player.java b/core/src/mindustry/entities/type/Player.java index af5165fc60..8366c01cc6 100644 --- a/core/src/mindustry/entities/type/Player.java +++ b/core/src/mindustry/entities/type/Player.java @@ -568,6 +568,7 @@ public class Player extends Unit implements BuilderMinerTrait, ShooterTrait{ protected void updateKeyboard(){ Tile tile = world.tileWorld(x, y); + boolean canMove = !Core.scene.hasKeyboard() || ui.minimapfrag.shown(); isBoosting = Core.input.keyDown(Binding.dash) && !mech.flying; @@ -594,8 +595,8 @@ public class Player extends Unit implements BuilderMinerTrait, ShooterTrait{ } if(Core.input.keyDown(Binding.mouse_move)){ - movement.x += Mathf.clamp((Core.input.mouseX() - Core.graphics.getWidth() / 2) * 0.005f, -1, 1) * speed; - movement.y += Mathf.clamp((Core.input.mouseY() - Core.graphics.getHeight() / 2) * 0.005f, -1, 1) * speed; + movement.x += Mathf.clamp((Core.input.mouseX() - Core.graphics.getWidth() / 2f) * 0.005f, -1, 1) * speed; + movement.y += Mathf.clamp((Core.input.mouseY() - Core.graphics.getHeight() / 2f) * 0.005f, -1, 1) * speed; } Vec2 vec = Core.input.mouseWorld(control.input.getMouseX(), control.input.getMouseY()); @@ -605,7 +606,7 @@ public class Player extends Unit implements BuilderMinerTrait, ShooterTrait{ movement.limit(speed).scl(Time.delta()); - if(!Core.scene.hasKeyboard()){ + if(canMove){ velocity.add(movement.x, movement.y); }else{ isShooting = false; @@ -614,7 +615,7 @@ public class Player extends Unit implements BuilderMinerTrait, ShooterTrait{ updateVelocityStatus(); moved = dst(prex, prey) > 0.001f; - if(!Core.scene.hasKeyboard()){ + if(canMove){ float baseLerp = mech.getRotationAlpha(this); if(!isShooting() || !mech.turnCursor){ if(!movement.isZero()){ diff --git a/core/src/mindustry/game/Team.java b/core/src/mindustry/game/Team.java index a6e9d1e20a..e6c05eb6e0 100644 --- a/core/src/mindustry/game/Team.java +++ b/core/src/mindustry/game/Team.java @@ -30,7 +30,7 @@ public class Team implements Comparable{ blue = new Team(5, "blue", Color.royal.cpy()); static{ - Mathf.random.setSeed(7); + Mathf.random.setSeed(8); //create the whole 256 placeholder teams for(int i = 6; i < all.length; i++){ new Team(i, "team#" + i, Color.HSVtoRGB(360f * Mathf.random(), 100f * Mathf.random(0.6f, 1f), 100f * Mathf.random(0.8f, 1f), 1f)); diff --git a/core/src/mindustry/graphics/MinimapRenderer.java b/core/src/mindustry/graphics/MinimapRenderer.java index 5d8af45304..36b8707490 100644 --- a/core/src/mindustry/graphics/MinimapRenderer.java +++ b/core/src/mindustry/graphics/MinimapRenderer.java @@ -9,6 +9,7 @@ import arc.math.*; import arc.math.geom.*; import arc.scene.ui.layout.*; import arc.util.*; +import arc.util.ArcAnnotate.*; import arc.util.pooling.*; import mindustry.entities.*; import mindustry.entities.type.*; @@ -42,7 +43,7 @@ public class MinimapRenderer implements Disposable{ return pixmap; } - public Texture getTexture(){ + public @Nullable Texture getTexture(){ return texture; } @@ -70,8 +71,13 @@ public class MinimapRenderer implements Disposable{ region = new TextureRegion(texture); } - public void drawEntities(float x, float y, float w, float h, boolean withLabels){ - updateUnitArray(); + public void drawEntities(float x, float y, float w, float h, float scaling, boolean withLabels){ + if(!withLabels){ + updateUnitArray(); + }else{ + units.clear(); + Units.all(units::add); + } float sz = baseSize * zoom; float dx = (Core.camera.position.x / tilesize); @@ -83,8 +89,8 @@ public class MinimapRenderer implements Disposable{ for(Unit unit : units){ if(unit.isDead()) continue; - float rx = (unit.x - rect.x) / rect.width * w; - float ry = (unit.y - rect.y) / rect.width * h; + float rx = !withLabels ? (unit.x - rect.x) / rect.width * w : unit.x / (world.width() * tilesize) * w; + float ry = !withLabels ? (unit.y - rect.y) / rect.width * h : unit.y / (world.height() * tilesize) * h; if(withLabels && unit instanceof Player){ Player pl = (Player) unit; @@ -94,18 +100,19 @@ public class MinimapRenderer implements Disposable{ } } - Draw.color(unit.getTeam().color); - Fill.rect(x + rx, y + ry, Scl.scl(baseSize / 2f), Scl.scl(baseSize / 2f)); + Draw.mixcol(unit.getTeam().color, 1f); + float scale = Scl.scl(1f) / 2f * scaling; + Draw.rect(unit.getIconRegion(), x + rx, y + ry, unit.getIconRegion().getWidth() * scale, unit.getIconRegion().getHeight() * scale, unit.rotation - 90); } - Draw.color(); + Draw.reset(); } public void drawEntities(float x, float y, float w, float h){ - drawEntities(x, y, w, h, true); + drawEntities(x, y, w, h, 1f, true); } - public TextureRegion getRegion(){ + public @Nullable TextureRegion getRegion(){ if(texture == null) return null; float sz = Mathf.clamp(baseSize * zoom, baseSize, Math.min(world.width(), world.height())); diff --git a/core/src/mindustry/graphics/OverlayRenderer.java b/core/src/mindustry/graphics/OverlayRenderer.java index c0cd917952..da8a808962 100644 --- a/core/src/mindustry/graphics/OverlayRenderer.java +++ b/core/src/mindustry/graphics/OverlayRenderer.java @@ -96,7 +96,7 @@ public class OverlayRenderer{ if(buildFadeTime > 0.005f){ state.teams.eachEnemyCore(player.getTeam(), core -> { float dst = core.dst(player); - if(dst < state.rules.enemyCoreBuildRadius * 1.5f){ + if(dst < state.rules.enemyCoreBuildRadius * 2.2f){ Draw.color(Color.darkGray); Lines.circle(core.x, core.y - 2, state.rules.enemyCoreBuildRadius); Draw.color(Pal.accent, core.getTeam().color, 0.5f + Mathf.absin(Time.time(), 10f, 0.5f)); diff --git a/core/src/mindustry/input/DesktopInput.java b/core/src/mindustry/input/DesktopInput.java index e2efcac160..c485b49ff2 100644 --- a/core/src/mindustry/input/DesktopInput.java +++ b/core/src/mindustry/input/DesktopInput.java @@ -140,18 +140,19 @@ public class DesktopInput extends InputHandler{ //move camera around float camSpeed = !Core.input.keyDown(Binding.dash) ? 3f : 8f; Core.camera.position.add(Tmp.v1.setZero().add(Core.input.axis(Binding.move_x), Core.input.axis(Binding.move_y)).nor().scl(Time.delta() * camSpeed)); + + if(Core.input.keyDown(Binding.mouse_move)){ + Core.camera.position.x += Mathf.clamp((Core.input.mouseX() - Core.graphics.getWidth() / 2f) * 0.005f, -1, 1) * camSpeed; + Core.camera.position.y += Mathf.clamp((Core.input.mouseY() - Core.graphics.getHeight() / 2f) * 0.005f, -1, 1) * camSpeed; + } } if(Core.input.keyRelease(Binding.select)){ player.isShooting = false; } - if(!state.is(State.menu) && Core.input.keyTap(Binding.minimap) && (scene.getKeyboardFocus() == ui.minimap || !scene.hasDialog()) && !Core.scene.hasKeyboard() && !(scene.getKeyboardFocus() instanceof TextField)){ - if(!ui.minimap.isShown()){ - ui.minimap.show(); - }else{ - ui.minimap.hide(); - } + if(!state.is(State.menu) && Core.input.keyTap(Binding.minimap) && !scene.hasDialog() && !(scene.getKeyboardFocus() instanceof TextField)){ + ui.minimapfrag.toggle(); } if(state.is(State.menu) || Core.scene.hasDialog()) return; diff --git a/core/src/mindustry/ui/Minimap.java b/core/src/mindustry/ui/Minimap.java index b724f4dd39..bbb81a7f00 100644 --- a/core/src/mindustry/ui/Minimap.java +++ b/core/src/mindustry/ui/Minimap.java @@ -36,7 +36,7 @@ public class Minimap extends Table{ Draw.rect(renderer.minimap.getRegion(), x + width / 2f, y + height / 2f, width, height); if(renderer.minimap.getTexture() != null){ - renderer.minimap.drawEntities(x, y, width, height, false); + renderer.minimap.drawEntities(x, y, width, height, 0.75f, false); } } }).size(140f); @@ -83,7 +83,7 @@ public class Minimap extends Table{ @Override public void clicked(InputEvent event, float x, float y){ - ui.minimap.show(); + ui.minimapfrag.toggle(); } }); diff --git a/core/src/mindustry/ui/fragments/MinimapFragment.java b/core/src/mindustry/ui/fragments/MinimapFragment.java new file mode 100644 index 0000000000..4a938b341a --- /dev/null +++ b/core/src/mindustry/ui/fragments/MinimapFragment.java @@ -0,0 +1,115 @@ +package mindustry.ui.fragments; + +import arc.*; +import arc.graphics.*; +import arc.graphics.g2d.*; +import arc.input.*; +import arc.math.*; +import arc.scene.*; +import arc.scene.event.*; +import arc.scene.ui.layout.*; +import mindustry.gen.*; +import mindustry.ui.*; + +import static mindustry.Vars.*; + +public class MinimapFragment extends Fragment{ + private boolean shown; + private float panx, pany, zoom = 1f, lastZoom = -1; + private float baseSize = Scl.scl(1000f); + private Element elem; + + @Override + public void build(Group parent){ + elem = parent.fill((x, y, w, h) -> { + w = Core.graphics.getWidth(); + h = Core.graphics.getHeight(); + float size = baseSize * zoom; + + Draw.color(Color.black); + Fill.crect(x, y, w, h); + + if(renderer.minimap.getTexture() != null){ + Draw.color(); + TextureRegion reg = Draw.wrap(renderer.minimap.getTexture()); + Draw.rect(reg, w/2f + panx*zoom, h/2f + pany*zoom, size, size); + renderer.minimap.drawEntities(w/2f + panx*zoom - size/2f, h/2f + pany*zoom - size/2f, size, size, zoom, true); + } + + Draw.reset(); + }); + + elem.visible(() -> shown); + elem.update(() -> { + elem.requestKeyboard(); + elem.requestScroll(); + elem.setFillParent(true); + elem.setBounds(0, 0, Core.graphics.getWidth(), Core.graphics.getHeight()); + + if(Core.input.keyTap(KeyCode.ESCAPE) || Core.input.keyTap(KeyCode.BACK)){ + shown = false; + } + }); + elem.touchable(Touchable.enabled); + + elem.addListener(new ElementGestureListener(){ + + @Override + public void zoom(InputEvent event, float initialDistance, float distance){ + if(lastZoom < 0){ + lastZoom = zoom; + } + + zoom = Mathf.clamp(distance / initialDistance * lastZoom, 0.25f, 10f); + } + + @Override + public void pan(InputEvent event, float x, float y, float deltaX, float deltaY){ + panx += deltaX / zoom; + pany += deltaY / zoom; + } + + @Override + public void touchDown(InputEvent event, float x, float y, int pointer, KeyCode button){ + super.touchDown(event, x, y, pointer, button); + } + + @Override + public void touchUp(InputEvent event, float x, float y, int pointer, KeyCode button){ + lastZoom = zoom; + } + }); + + elem.addListener(new InputListener(){ + + @Override + public boolean scrolled(InputEvent event, float x, float y, float amountX, float amountY){ + zoom = Mathf.clamp(zoom - amountY / 10f * zoom, 0.25f, 10f); + return true; + } + }); + + parent.fill(t -> { + t.setFillParent(true); + t.visible(() -> shown); + t.update(() -> t.setBounds(0, 0, Core.graphics.getWidth(), Core.graphics.getHeight())); + + t.add("$minimap").style(Styles.outlineLabel).pad(10f); + t.row(); + t.add().growY(); + t.row(); + + if(mobile){ + t.addImageTextButton("$back", Icon.backSmall, () -> shown = false).size(220f, 60f).pad(12f); + } + }); + } + + public boolean shown(){ + return shown; + } + + public void toggle(){ + shown = !shown; + } +} diff --git a/core/src/mindustry/world/blocks/distribution/OverflowGate.java b/core/src/mindustry/world/blocks/distribution/OverflowGate.java index 185fdf7834..b07ae8c7be 100644 --- a/core/src/mindustry/world/blocks/distribution/OverflowGate.java +++ b/core/src/mindustry/world/blocks/distribution/OverflowGate.java @@ -81,11 +81,11 @@ public class OverflowGate extends Block{ if(to == null) return null; Tile edge = Edges.getFacingEdge(tile, to); - if(!to.block().acceptItem(item, to, edge) || (to.block() instanceof OverflowGate)){ + if(!to.block().acceptItem(item, to, edge) || to.getTeam() != tile.getTeam() || (to.block() instanceof OverflowGate)){ Tile a = tile.getNearby(Mathf.mod(from - 1, 4)); Tile b = tile.getNearby(Mathf.mod(from + 1, 4)); - boolean ac = a != null && a.block().acceptItem(item, a, edge) && !(a.block() instanceof OverflowGate); - boolean bc = b != null && b.block().acceptItem(item, b, edge) && !(b.block() instanceof OverflowGate); + boolean ac = a != null && a.block().acceptItem(item, a, edge) && !(a.block() instanceof OverflowGate) && a.getTeam() == tile.getTeam(); + boolean bc = b != null && b.block().acceptItem(item, b, edge) && !(b.block() instanceof OverflowGate) && b.getTeam() == tile.getTeam(); if(!ac && !bc){ return null; diff --git a/core/src/mindustry/world/blocks/storage/CoreBlock.java b/core/src/mindustry/world/blocks/storage/CoreBlock.java index f9a5cf6c9b..4a8f500d77 100644 --- a/core/src/mindustry/world/blocks/storage/CoreBlock.java +++ b/core/src/mindustry/world/blocks/storage/CoreBlock.java @@ -151,7 +151,7 @@ public class CoreBlock extends StorageBlock{ @Override public void removed(Tile tile){ CoreEntity entity = tile.ent(); - int total = tile.entity.proximity().count(e -> e.entity.items == tile.entity.items); + int total = tile.entity.proximity().count(e -> e.entity != null && e.entity.items != null && e.entity.items == tile.entity.items); float fract = 1f / total / state.teams.cores(tile.getTeam()).size; tile.entity.proximity().each(e -> isContainer(e) && e.entity.items == tile.entity.items, t -> { diff --git a/server/src/mindustry/server/ServerControl.java b/server/src/mindustry/server/ServerControl.java index d834ecd907..f78f6fbab9 100644 --- a/server/src/mindustry/server/ServerControl.java +++ b/server/src/mindustry/server/ServerControl.java @@ -292,7 +292,7 @@ public class ServerControl implements ApplicationListener{ info("&ly {0} seconds until next wave.", (int)(state.wavetime / 60)); } - info(" &ly{0} FPS, {1} MB used.", (int)(60f / Time.delta()), Core.app.getJavaHeap() / 1024 / 1024); + info(" &ly{0} FPS, {1} MB used.", Core.graphics.getFramesPerSecond(), Core.app.getJavaHeap() / 1024 / 1024); if(playerGroup.size() > 0){ info(" &lyPlayers: {0}", playerGroup.size()); From b952ee0725b929167908cfccaccf4ae5658a841b Mon Sep 17 00:00:00 2001 From: Anuken Date: Sun, 29 Dec 2019 18:01:10 -0500 Subject: [PATCH 35/78] Tweaks --- core/src/mindustry/graphics/MinimapRenderer.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/core/src/mindustry/graphics/MinimapRenderer.java b/core/src/mindustry/graphics/MinimapRenderer.java index 36b8707490..01ac9ab09a 100644 --- a/core/src/mindustry/graphics/MinimapRenderer.java +++ b/core/src/mindustry/graphics/MinimapRenderer.java @@ -92,6 +92,11 @@ public class MinimapRenderer implements Disposable{ float rx = !withLabels ? (unit.x - rect.x) / rect.width * w : unit.x / (world.width() * tilesize) * w; float ry = !withLabels ? (unit.y - rect.y) / rect.width * h : unit.y / (world.height() * tilesize) * h; + Draw.mixcol(unit.getTeam().color, 1f); + float scale = Scl.scl(1f) / 2f * scaling; + Draw.rect(unit.getIconRegion(), x + rx, y + ry, unit.getIconRegion().getWidth() * scale, unit.getIconRegion().getHeight() * scale, unit.rotation - 90); + Draw.reset(); + if(withLabels && unit instanceof Player){ Player pl = (Player) unit; if(!pl.isLocal){ @@ -99,10 +104,6 @@ public class MinimapRenderer implements Disposable{ drawLabel(x + rx, y + ry, pl.name, unit.getTeam().color); } } - - Draw.mixcol(unit.getTeam().color, 1f); - float scale = Scl.scl(1f) / 2f * scaling; - Draw.rect(unit.getIconRegion(), x + rx, y + ry, unit.getIconRegion().getWidth() * scale, unit.getIconRegion().getHeight() * scale, unit.rotation - 90); } Draw.reset(); From 5af7cd1d55775a201e2eab7734c4197c17a8390b Mon Sep 17 00:00:00 2001 From: Prosta4okua <31485341+Prosta4okua@users.noreply.github.com> Date: Mon, 30 Dec 2019 01:50:59 +0200 Subject: [PATCH 36/78] Update bundle_uk_UA.properties (#1275) --- core/assets/bundles/bundle_uk_UA.properties | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/core/assets/bundles/bundle_uk_UA.properties b/core/assets/bundles/bundle_uk_UA.properties index a0c1edf720..e37aab78f7 100644 --- a/core/assets/bundles/bundle_uk_UA.properties +++ b/core/assets/bundles/bundle_uk_UA.properties @@ -12,6 +12,7 @@ link.itch.io.description = Itch.io сторінка, на якій можна з link.google-play.description = Завантажити для Android з Google Play link.f-droid.description = Перелік каталогу F-Droid link.wiki.description = Офіційна Mindustry wiki +link.feathub.description = Запропонувати нові функції linkfail = Не вдалося відкрити посилання!\nURL-адреса скопійована в буфер обміну. screenshot = Зняток мапи збережено в {0} screenshot.invalid = Мапа занадто велика, тому, мабуть, не вистачає пам’яті для знятку мапи. @@ -27,6 +28,13 @@ load.system = Система load.mod = Модифікації load.scripts = Скрипти +be.update = Доступна нова збірка Bleeding Edge: +be.update.confirm = Завантажити і перезавантажити зараз? +be.updating = Оновлення… +be.ignore = Ігнорувати +be.noupdates = Оновлень не знайдено. +be.check = Перевірити на наявність оновлень + schematic = Схема schematic.add = Зберегти схему… schematics = Схеми @@ -147,6 +155,7 @@ server.kicked.nameEmpty = Ваше ім’я має містити принай server.kicked.idInUse = Ви вже на цьому сервері! Підключення двох облікових записів не дозволяється. server.kicked.customClient = Цей сервер не підтримує користувацькі збірки. Завантажте офіційну версію. server.kicked.gameover = Гра завершена! +server.kicked.serverRestarting = Сервер перезавантажується server.versions = Ваша версія:[accent] {0}[]\nВерсія на сервері:[accent] {1}[] host.info = Кнопка [accent]Сервер[] розміщує сервер на порті [scarlet]6567[]. \nКористувачі, які знаходяться у тій же [lightgray]WiFi або локальній мережі[], повинні бачити ваш сервер у своєму списку серверів.\n\nЯкщо ви хочете, щоб люди могли приєднуватися з будь-якої точки через IP, то[accent] переадресація порту []обов’язкова.\n\n[lightgray]Примітка. Якщо у вас виникли проблеми з підключенням до вашої локальної гри, переконайтеся, що ви дозволили Mindustry доступ до вашої локальної мережі в налаштуваннях брандмауера. Зауважте, що публічні мережі іноді не дозволяють виявити сервер. join.info = Тут ви можете ввести [accent]IP сервера[] для підключення або знайти сервери у [accent]локальній мережі[] для підключення до них.\nПідтримується локальна мережа(LAN) і широкосмугова мережа(WAN).\n\n[lightgray] Примітка. Тут немає автоматичного глобального списку серверів; якщо ви хочете підключитися до когось через IP, вам доведеться попросити створювача сервера дати свій ip. @@ -317,7 +326,7 @@ waves.invalid = Недійсні хвилі у буфері обміну. waves.copied = Хвилі скопійовані. waves.none = Вороги не були встановлені.\nЗазначимо, що пусті хвилі будуть автоматично замінені звичайною хвилею. editor.default = [lightgray]<За замовчуванням> -details = Деталі… +details = Подробиці… edit = Редагувати… editor.name = Назва: editor.spawn = Створити бойову одиницю @@ -622,6 +631,7 @@ setting.screenshake.name = Тряска екрану setting.effects.name = Ефекти setting.destroyedblocks.name = Показувати зруйновані блоки setting.conveyorpathfinding.name = Пошук шляху для встановлення конвейерів +setting.coreselect.name = Дозволити схематичні ядра setting.sensitivity.name = Чутливість контролера setting.saveinterval.name = Інтервал збереження setting.seconds = {0} с @@ -732,6 +742,7 @@ rules.enemyCheat = Нескінченні ресурси для ШІ rules.unitdrops = Ресурс бойових одиниць rules.unitbuildspeedmultiplier = Множник швидкості виробництва бойових одиниць rules.unithealthmultiplier = Множник здоров’я бойових одиниць +rules.blockhealthmultiplier = Множник здоров’я блоків rules.playerhealthmultiplier = Множник здоров’я гравця rules.playerdamagemultiplier = Множник шкоди гравця rules.unitdamagemultiplier = Множник шкоди бойових одиниць @@ -1056,7 +1067,7 @@ tutorial.launch = Як тільки ви досягнете певної хви item.copper.description = Найбільш базовий будівельний матеріал. Широко використовується у всіх типах блоків. item.lead.description = Основний стартовий матеріал. Широко застосовується в електроніці та транспортуванні рідин. item.metaglass.description = Супер жорсткий склад скла. Широко застосовується для розподілу та зберігання рідини. -item.graphite.description = Мінералізований вуглець, що використовується для боєприпасів та електроізоляції. +item.graphite.description = Мінералізований вуглець, що використовується для боєприпасів та як компонент. item.sand.description = Поширений матеріал, який широко використовується при виплавці, як при сплавленні, так і в якості відходів. item.coal.description = Окам’янілі рослинні речовини, що утворюються задовго до посіву. Широко використовується для виробництва пального та ресурсів. item.titanium.description = Рідкісний надлегкий метал, який широко використовується для транспортування рідини, бурів і літаків. From 150d0bf513c6600eb72fdc1602bb6675f653a344 Mon Sep 17 00:00:00 2001 From: Prosta4okua <31485341+Prosta4okua@users.noreply.github.com> Date: Mon, 30 Dec 2019 01:51:22 +0200 Subject: [PATCH 37/78] [WIP]Update bundle_uk_UA.properties (#1220) * Update bundle_uk_UA.properties * Update bundle_uk_UA.properties * Update bundle_uk_UA.properties * Update bundle_uk_UA.properties * 17.12.2019 --- core/assets/bundles/bundle_uk_UA.properties | 112 ++++++++++---------- 1 file changed, 57 insertions(+), 55 deletions(-) diff --git a/core/assets/bundles/bundle_uk_UA.properties b/core/assets/bundles/bundle_uk_UA.properties index e37aab78f7..8decca67f5 100644 --- a/core/assets/bundles/bundle_uk_UA.properties +++ b/core/assets/bundles/bundle_uk_UA.properties @@ -10,7 +10,7 @@ link.dev-builds.description = Нестабільні версії link.trello.description = Офіційна дошка Trello для запланованих функцій link.itch.io.description = Itch.io сторінка, на якій можна завантажити гру link.google-play.description = Завантажити для Android з Google Play -link.f-droid.description = Перелік каталогу F-Droid +link.f-droid.description = Завантажити для Android з F-Droid link.wiki.description = Офіційна Mindustry wiki link.feathub.description = Запропонувати нові функції linkfail = Не вдалося відкрити посилання!\nURL-адреса скопійована в буфер обміну. @@ -45,7 +45,7 @@ schematic.importfile = Імпортувати файл schematic.browseworkshop = Переглянути в Майстерні schematic.copy = Копіювати в буфер обміну schematic.copy.import = Імпортувати з клавіатури -schematic.shareworkshop = Поширити в Майстерні +schematic.shareworkshop = Поширити в Майстерню schematic.flip = [accent][[{0}][]/[accent][[{1}][]: Відобразити схему schematic.saved = Схема збережена. schematic.delete.confirm = Ця схема буде повністю випалена. @@ -75,7 +75,7 @@ customgame = Користувацька гра newgame = Нова гра none = <нічого> minimap = Мінімапа -position = Позиція +position = Місцерозташування close = Закрити website = Веб-сайт quit = Вихід @@ -105,22 +105,25 @@ mod.author = [LIGHT_GRAY]Автор:[] {0} mods.alpha = [scarlet](Альфа) mods = Модифікації mods.none = [LIGHT_GRAY]Модифікацій не знайдено! -mods.guide = Посібник зі створення модифицій +mods.guide = Посібник з модифицій mods.report = Повідомити про ваду mods.openfolder = Відкрити теку модифікацій mod.enabled = [lightgray]Увімкнено mod.disabled = [scarlet]Вимкнено -mod.disable = Вимкнути +mod.disable = Вимкн. mod.delete.error = Неможливо видалити модифікацію. Файл, можливо, використовується. -mod.requiresversion = [scarlet]Необхідна версія гри: [accent]{0} +mod.requiresversion = [scarlet]Необхідна мінімальна версія гри: [accent]{0} +mod.erroredcontent = [scarlet]Помилки при завантаженнні +mod.errors = Сталася помилка при завантаження змісту. +mod.noerrorplay = [scarlet]Ви маєте модифікації з помилками.[] Або вимкніть проблемні модифікації, або виправте їх. mod.missingdependencies = [scarlet]Відсутні залежності: {0} mod.nowdisabled = [scarlet]Модифікації «{0}» не вистачає залежних модифікацій:[accent] {1}\n[lightgray]Ці модифікації потрібно завантажити спочатку.\nЦя модифікація буде автоматично вимкнена. -mod.enable = Увімкнути +mod.enable = Увімк. mod.requiresrestart = А тепер гра закриється, щоб застосувати зміни модифікацій. mod.reloadrequired = [scarlet]Потрібно перезавантаження mod.import = Імпортувати модифікацію -mod.import.github = Імпортувати модификацію з GitHub -mod.item.remove =Цей предмет є частиною модифікації [accent] '«{0}»[]. Щоб видалити його, видаліть цю модифікацію. +mod.import.github = Завантажити мод з GitHub +mod.item.remove = Цей предмет є частиною модифікації [accent] «{0}»[]. Щоб видалити його, видаліть цю модифікацію. mod.remove.confirm = Цю модифікацію буде видалено. mod.author = [LIGHT_GRAY]Автор:[] {0} mod.missing = Це збереження містить модифікації, які ви нещодавно оновили або більше не встановлювали. Збереження може зіпсуватися. Ви впевнені, що хочете завантажити його?\n[lightgray]Модифікації:\n{0} @@ -141,7 +144,7 @@ players = Гравців: {0} players.single = {0} гравець на сервері server.closing = [accent]Закриття сервера… server.kicked.kick = Ви були вигнані з сервера! -server.kicked.whitelist = Ви не в білому спискі сервері. +server.kicked.whitelist = Ви не в білому спискі сервера! server.kicked.serverClose = Сервер закрито. server.kicked.vote = Вас було вигнано із сервера за допомогою голосування. Прощавайте. server.kicked.clientOutdated = Застарілий клієнт! Оновіть свою гру! @@ -218,8 +221,8 @@ save.delete.confirm = Ви дійсно хочете видалити це зб save.delete = Видалити save.export = Експортувати збереження save.import.invalid = [accent]Це збереження недійсне! -save.import.fail = [crimson]Не вдалося імпортувати збереження: [accent]{0} -save.export.fail = [crimson]Не вдалося експортувати збереження: [accent]{0} +save.import.fail = [crimson]Не вдалося завантажити збереження: [accent]{0} +save.export.fail = [crimson]Не вдалося вивантажити збереження: [accent]{0} save.import = Імпортувати збереження save.newslot = Ім’я збереження: save.rename = Перейменувати @@ -249,12 +252,12 @@ cancel = Скасувати openlink = Відкрити посилання copylink = Скопіювати посилання back = Назад -data.export = Експортувати дані -data.import = Импортувати дані -data.exported = Дані імпортовано. +data.export = Вивантажити дані +data.import = Завантажити дані +data.exported = Дані вивантажено. data.invalid = Це не дійсні ігрові дані. -data.import.confirm = Імпорт зовнішніх даних перезапише[scarlet] ВСІ[] ваші поточні ігрові дані.\n[accent]Це неможливо скасувати![]\n\nЩойно дані імпортуються, гра негайно закриється. -classic.export = Експортувати класичні дані +data.import.confirm = Вивантаження зовнішніх даних перезапише[scarlet] ВСІ[] ваші поточні ігрові дані.\n[accent]Це неможливо скасувати![]\n\nЩойно дані імпортуються, гра негайно закриється. +classic.export = Вивантажити класичні дані classic.export.text = Класичне (версія 3.5 збірка 40) збереження або мапа були знайдені. Ви хочете експортувати ці дані в домашню теку телефону, для використання у застосунку Mindustry Classic? quit.confirm = Ви впевнені, що хочете вийти? quit.confirm.tutorial = Ви впевнені, що хочете вийти з навчання? @@ -334,7 +337,7 @@ editor.removeunit = Видалити бойову одиницю editor.teams = Команди editor.errorload = Помилка завантаження зображення:\n[accent] {0} editor.errorsave = Помилка збереження зображення:\n[accent]{0} -editor.errorimage = Це зображення, а не мапа. Не змінюйте розширення, очікуючи, що це запрацює.\n\nЯкщо Ви хочете імпортувати застарілку мапу, то використовуйте кнопку «Імпортувати застаріле зображення» у редакторі. +editor.errorimage = Це зображення, а не мапа. Не змінюйте розширення, очікуючи, що це запрацює.\n\nЯкщо ви хочете імпортувати застарілку мапу, то використовуйте кнопку «Імпортувати застаріле зображення» у редакторі. editor.errorlegacy = Ця мапа занадто стара і використовує попередній формат мапи, який більше не підтримується. editor.errornot = Це не мапа. editor.errorheader = Цей файл мапи недійсний або пошкоджений. @@ -435,8 +438,8 @@ abandon = Покинути abandon.text = Ця зона і всі її ресурси будуть втрачені. locked = Заблоковано complete = [lightgray]Досягнута: -requirement.wave = Досягніть хвилі {0} у {1} -requirement.core = Знишьте вороже ядро у {0} +requirement.wave = Досягніть хвилі {0} у зоні «{1}» +requirement.core = Знищьте вороже ядро у {0} requirement.unlock = Розблокуйте {0} resume = Відновити зону:\n[lightgray]{0} bestwave = [lightgray]Найкраща хвиля: {0} @@ -445,16 +448,16 @@ launch.title = Запуск вдалий launch.next = [lightgray]наступна можливість на {0}-тій хвилі launch.unable2 = [scarlet]ЗАПУСК неможливий.[] launch.confirm = Це видалить всі ресурси у Вашому ядрі.\nВи не зможете повернутися до цієї бази. -launch.skip.confirm = Якщо Ви пропустите зараз, Ви не зможете не запускати до більш пізніх хвиль. +launch.skip.confirm = Якщо ви пропустите зараз, Ви не зможете не запускати до більш пізніх хвиль. uncover = Розкрити configure = Вивантажити конфігурацію bannedblocks = Заборонені блоки addall = Додати все -configure.locked = [lightgray]Можливість розблокувати вивантаження ресурсів буде доступна на {0}-тій хвилі. +configure.locked = {0}[lightgray]Тільки після цього можливість розблокувати вивантаження ресурсів буде доступна. configure.invalid = Кількість повинна бути числом між 0 та {0}. zone.unlocked = Зона «[lightgray]{0}» тепер розблокована. -zone.requirement.complete = Ви досягли {0}-тої хвилі,\nВимоги до зони «{1}» виконані. -zone.config.unlocked = Loadout unlocked:[lightgray]\n{0} +zone.requirement.complete = Ви досягли {0}-тої хвилі. \nВимоги до зони «{1}» виконані. +zone.config.unlocked = Вивантаження розблоковано:[lightgray]\n{0} zone.resources = Виявлені ресурси: zone.objective = [lightgray]Мета: [accent]{0} zone.objective.survival = Вижити @@ -471,7 +474,7 @@ error.mapnotfound = Файл мапи не знайдено error.io = Мережева помилка введення-виведення error.any = Невідома мережева помилка error.bloom = Не вдалося ініціалізувати цвітіння.\nВаш пристрій, мабуть, не підтримує це. -zone.groundZero.name = Нульова земля +zone.groundZero.name = Відправний пункт zone.desertWastes.name = Пустельні відходи zone.craters.name = Кратери zone.frozenForest.name = Крижаний ліс @@ -502,7 +505,7 @@ zone.crags.description = <вставити опис тут> settings.language = Мова settings.data = Ігрові дані settings.reset = Скинути за замовчуванням -settings.rebind = Зміна +settings.rebind = Змінити settings.resetKey = Скинути settings.controls = Керування settings.game = Гра @@ -524,7 +527,7 @@ blocks.output = Вихід blocks.booster = Прискорювач block.unknown = [lightgray]??? blocks.powercapacity = Місткість енергії -blocks.powershot = Енергія/постріл +blocks.powershot = Енергія за постріл blocks.damage = Шкода blocks.targetsair = Повітряні мішені blocks.targetsground = Наземні мішені @@ -536,7 +539,7 @@ blocks.liquidcapacity = Місткість рідини blocks.powerrange = Діапазон передачі енергії blocks.powerconnections = Максимальна кількість з’єднань blocks.poweruse = Енергії використовує -blocks.powerdamage = Енергія/урон +blocks.powerdamage = Енергія/шкода blocks.itemcapacity = Місткість предметів blocks.basepowergeneration = Базова генерація енергії blocks.productiontime = Час виробництва @@ -860,7 +863,7 @@ block.core-nucleus.name = Ядро «Атом» block.deepwater.name = Глибоководдя block.water.name = Вода block.tainted-water.name = Забруднена вода -block.darksand-tainted-water.name = Темний пісок з забрудненою водою +block.darksand-tainted-water.name = Темний пісок із забрудненою водою block.tar.name = Дьоготь block.stone.name = Камінь block.sand.name = Пісок @@ -1044,26 +1047,25 @@ unit.eradicator.name = Випалювач unit.lich.name = Лич unit.reaper.name = Жнець tutorial.next = [lightgray]<Натисніть для продовження> -tutorial.intro = Ви розпочали[scarlet] навчання по Mindustry.[]\nРозпочніть з[accent] видобування міді[]. Використовуйте [[WASD] для руху.\n[accent] Утримуйте [[Ctrl] під час прокрутки миші[] для приближення і віддалення. Наблизьтесь, а потім натисність на мідну жилу біля вашого ядра, щоб зробити це.\n\n[accent]{0}/{1} міді +tutorial.intro = Ви розпочали[scarlet] навчання по Mindustry.[]\nРозпочніть з [accent]видобутку міді[]. Використовуйте [[WASD] для руху.\n[accent]Прокручуйте миш[] для приближення і віддалення. Наблизьтесь до мідної жили біля вашого ядра, а потім натисніть на неї, щоб розпочати видобуток.\n\n[accent]{0}/{1} міді tutorial.intro.mobile = Ви розпочали[scarlet] навчання по Mindustry.[]\nПроведіть екраном, щоб рухатися.\n[accent] Зведіть або розведіть 2 пальця [] для приближення і віддалення відповідно.\nз[accent] видобування міді.[] Наблизьтесь, а потім натисність на мідну жилу біля вашого ядра, щоб зробити це.\n\n[accent]{0}/{1} міді -tutorial.drill = Добування вручну неефективне.\n[accent]Бури []можуть добувати автоматично.\nНатисніть на вкладку свердла знизу зправа.\nВиберіть[accent] механічний бур[]. Розмістіть його на мідній жилі натисканням.\nВи також можете вибрати бур, натиснувши [accent][[2][], а потім натиснути [accent][[1][] швидко, незалежно від того, яка вкладка відкрита.\n[accent]Натисніть ПКМ[], щоб зупинити будування.tutorial.drill.mobile = Добування вручну неефективне.\n[accent]Бури []можуть добувати автоматично.\nНатисність на вкладку сведла знизу зправа.\nВиберіть[accent] механічний бур[]. Розмістіть його на мідній жилі натисканням, потім натисність на [accent] галочку[] нижче, щоб підтвердити розміщення .\nНатисніть[accent] клавішу X[], щоб скасувати розміщення. -tutorial.drill.mobile = Добування вручну неефективне.\n[accent]Бури []можуть добувати автоматично.\nНатисність на вкладку сведла знизу зправа.\nВиберіть[accent] механічний бур[]. Розмістіть його на мідній жилі натисканням, потім натисність на [accent] галочку[] нижче, щоб підтвердити розміщення.\nPress the[accent] X button[] to cancel placement. -tutorial.blockinfo = Кожен блок має різні характеристики. Кожний бур може видобувати тільки певні руди.\nЩоб переглянути інформацію та характеристики блока,[accent] натисність на кнопку «?», коли Ви вибрали блок у меню будування.[]\n\n[accent]Перегляньте характеристику Механічного бура прямо зараз.[] -tutorial.conveyor = [accent]Конвеєри[] використовуються для транспортування предметів до ядра.\nЗробіть лінію конвеєрів від бура до ядра.\n[accent]Утримуйте миш, щоб розмістити у лінію.[]\nУтримуйте[accent] CTRL[] під час вибору лінії для розміщення по діагоналі.\n\n[accent]{0}/{1} конвеєрів, які розміщені в лінію\n[accent]0/1 предмет доставлено -tutorial.conveyor.mobile = [accent]Конвеєри[] використовується для транспортування предметів до ядра.\nЗробіть лінію конвеєрів від бура до ядра.\n[accent] Розмістить у лінію, утримуючи палець кілька секунд[] і тягніть у напрямку, який Ви вибрали.\nВикористовуйте колесо прокрутки, щоб обертати блоки перед їх розміщенням\n[accent]{0}/{1} конвеєрів, які розміщені в лінію\n[accent]0/1 предмет доставлено -tutorial.turret = Оборонні споруди повинні бути побудовані для відбиття[lightgray] ворогів[].\nПобудуйте[accent] башточку «Подвійна»[] біля вашої бази. -tutorial.drillturret = «Подвійна» потребує [accent] мідні боєприпаси []для стрільби.\nРозмістіть бур біля башточки\nПроведіть конвеєри до башточки, щоб заповнити її боєприпасами.\n\n[accent]Доставлено боєприпасів: 0/1 -tutorial.pause = Під час бою ви можете[accent] поставити на павзу гру.[]\nВи можете зробити чергу на будування під час паузи.\n\n[accent]Натисність пробіл для павзи.tutorial.launch -tutorial.pause.mobile = Під час бою ви можете[accent] поставити на павзу гру.[]\nВи можете зробити чергу на будування під час паузи.\n\n[accent]атисніть кнопку зліва вгорі для павзи. +tutorial.drill = Добування вручну не є ефективним.\n[accent]Бури []можуть добувати автоматично.\nНатисніть на вкладку із зображенням свердла знизу праворуч.\nВиберіть[accent] механічний бур[]. Розмістіть його на мідній жилі натисканням.\nВи також можете вибрати бур, натиснувши [accent][[2][], а потім швидко натиснути [accent][[1][], незалежно від того, яка вкладка відкрита.\n[accent]Натисніть ПКМ[], щоб зупинити будування. +tutorial.drill.mobile = Добування вручну неефективне.\n[accent]Бури []можуть добувати автоматично.\nНатисність на вкладку із зображенням сведла знизу зправа.\nВиберіть[accent] механічний бур[]. Розмістіть його на мідній жилі натисканням, потім натисність на [accent]галочку[] нижче, щоб підтвердити розміщення .\nНатисніть [accent]кнопку X[], щоб скасувати розміщення. +tutorial.blockinfo = Кожен блок має різні характеристики. Кожний бур може видобувати тільки певні руди.\nЩоб переглянути інформацію та характеристики блока,[accent] натисність на кнопку «?», коли ви вибрали блок у меню будування.[]\n\n[accent]Перегляньте характеристику Механічного бура прямо зараз.[] +tutorial.conveyor = [accent]Конвеєри[] використовуються для транспортування предметів до ядра.\nЗробіть лінію конвеєрів від бура до ядра.\n[accent]Утримуйте миш, щоб розмістити у лінію.[]\nУтримуйте[accent] CTRL[] під час вибору лінії для розміщення по діагоналі.\\nПрокручуйте, щоб обертати блоки до їх установлення.\n[accent]Розмістіть 2 конвеєри у лінію, а потім доставте предмет в ядро.tutorial.conveyor.mobile = [accent]Конвеєри[] використовується для транспортування предметів до ядра.\nЗробіть лінію конвеєрів від бура до ядра.\n[accent] Розмістить у лінію, утримуючи палець кілька секунд[] і тягніть у напрямку, який Ви вибрали.\nВикористовуйте колесо прокрутки, щоб обертати блоки перед їх розміщенням\n[accent]{0}/{1} конвеєрів, які розміщені в лінію\n[accent]0/1 предмет доставлено +tutorial.turret = Оборонні споруди повинні бути побудовані для відбиття[lightgray] ворогів[].\nПобудуйте[accent] башту «Подвійна»[] біля вашої бази. +tutorial.drillturret = «Подвійна» потребує [accent]мідні боєприпаси[] для стрільби.\nРозмістіть бур біля башточки\nПроведіть конвеєри до башточки, щоб заповнити її боєприпасами.\n\n[accent]Доставлено боєприпасів: 0/1 +tutorial.pause = Під час бою ви можете[accent] поставити на павзу гру.[]\nВи можете зробити чергу на будування під час паузи.\n\n[accent]Натисність пробіл для павзи. +tutorial.pause.mobile = Під час бою ви можете[accent] поставити на павзу гру.[]\nВи можете зробити чергу на будування під час паузи.\n\n[accent]Натисніть кнопку вгорі ліворуч для павзи. tutorial.unpause = Тепер натисність пробіл, щоб зняти павзу. tutorial.unpause.mobile = Тепер натисність туди ще раз, щоб зняти павзу. -tutorial.breaking = Блоки часто повинні бути знищені.\n[accent]Утримуючи ПКМ[] Ви знищите всі виділені блоки.[]\n\n[accent]Необхідно знищити всі стіни з металобрухту ліворуч від вашого ядра використовуючи видалення у зоні. +tutorial.breaking = Блоки часто повинні бути знищені.\n[accent]Утримуючи ПКМ[] ви знищите всі виділені блоки.[]\n\n[accent]Необхідно знищити всі стіни з металобрухту ліворуч від вашого ядра використовуючи видалення у зоні. tutorial.breaking.mobile = Блоки часто повинні бути знищені.\n[accent]Виберіть режим руйнування[], потім натисніть на блок, щоб зламати його.\nЗнищіть область, утримуючи палець протягом декількох секунд [] і потягнувши в потрібному напрямку.\nНатисніть кнопку галочки, щоб підтвердити руйнування.\n\n[accent]Необхідно знищити всі стіни з металобрухту ліворуч від вашого ядра використовуючи видалення у зоні. -tutorial.withdraw = У деяких ситуаціях потрібно брати предмети безпосередньо з блоків.\nЩоб зробити це, [accent]натисність на блок[] з предметами на ньому, і потім [accent]натисніть на предмет[] в інвентарі.\nМожна вилучити кілька предметів [accent]натискаючи та утримуючи[].\n\n[accent]Вилучіть трохи міді з ядра.[] +tutorial.withdraw = У деяких ситуаціях потрібно брати предмети безпосередньо з блоків.\nЩоб зробити це, [accent]натисність на блок[] з предметами, і потім [accent]натисніть на предмет[] в інвентарі.\nМожна вилучити кілька предметів [accent]натискаючи та утримуючи[].\n\n[accent]Вилучіть трохи міді з ядра.[] tutorial.deposit = Покладіть предмети в блоки, перетягнувши з вашого корабля в потрібний блок.\n\n[accent]Покладіть мідь назад у ядро.[] -tutorial.waves = [lightgray] Ворог[] з’явився.\n\nЗахистіть ядро від двух хвиль.[accent] Натисніть[], щоб стріляти.\nСтворіть більше башточок і бурів. Добудьте більше міді. -tutorial.waves.mobile = [lightgray] Ворог[] з’явився.\n\nЗахистіть ядро від двух хвиль. Ваш корабель буде автоматично атакувати ворогів.\nСтворіть більше башточок і бурів. Добудьте більше міді. -tutorial.launch = Як тільки ви досягнете певної хвилі, Ви зможете[accent] запустити ядро[], залишивши захисні сили позаду та [accent]отримати всі ресурси у вашому ядрі.[]\nЦі отримані ресурси можуть бути використані для дослідження нових технологій.\n\n[accent]Натисніть кнопку запуску. +tutorial.waves = [lightgray] Ворог[] з’явився.\n\nЗахистіть ядро від двух хвиль.[accent] Натисніть ЛКМ[], щоб стріляти.\nСтворіть більше башт і бурів. Добудьте більше міді. +tutorial.waves.mobile = [lightgray] Ворог[] з’явився.\n\nЗахистіть ядро від двух хвиль. Ваш корабель буде автоматично атакувати ворогів.\nСтворіть більше башт і бурів. Добудьте більше міді. +tutorial.launch = Як тільки ви досягнете певної хвилі, ви зможете[accent] запустити ядро[], залишивши захисні сили позаду та [accent]отримати всі ресурси у вашому ядрі.[]\nЦі отримані ресурси можуть бути використані для дослідження нових технологій.\n\n[accent]Натисніть кнопку запуску. item.copper.description = Найбільш базовий будівельний матеріал. Широко використовується у всіх типах блоків. item.lead.description = Основний стартовий матеріал. Широко застосовується в електроніці та транспортуванні рідин. item.metaglass.description = Супер жорсткий склад скла. Широко застосовується для розподілу та зберігання рідини. @@ -1085,11 +1087,11 @@ liquid.slag.description = Різні види розплавленого мет liquid.oil.description = Рідина, яка використовується у виробництві сучасних матеріалів. Може бути перетворена в вугілля в якості палива або використана як куля. liquid.cryofluid.description = Інертна, не роз’їдаюча рідина, створена з води та титану. Володіє надзвичайно високою пропускною спроможністю. Широко використовується в якості охолоджуючої рідини. mech.alpha-mech.description = Стандартний керований мех. Заснований на бойовій одиниці «Кинджал», з оновленими бронею та можливостями будування. Наносить більше шкоди, ніж «Дротик». -mech.delta-mech.description = Швидкий, легкоброньований мех, зроблений для тактики «атакуй і біжи». Наносить мало шкоди будівлям, але може дуже швидко вбити великі групи підрозділів противника своєю дуговою блискавкою. +mech.delta-mech.description = Швидкий, легкоброньований мех, зроблений для тактики «атакуй і втікай». Наносить мало шкоди будівлям, але може дуже швидко вбити великі групи підрозділів противника своєю дуговою блискавкою. mech.tau-mech.description = Мех підтримки. Ремонтує союзні блоки, стріляючи по них. Може зцілювати союзників у радіусі його ремонтної здатності. mech.omega-mech.description = Об’ємний і добре броньований мех, зроблений для фронтових штурмів. Його броня може перекрити до 90% пошкоджень, що надходять. mech.dart-ship.description = Стандартний корабель управління. Швидко видобуває ресурси. Достатньо швидкий і легкий, але має мало наступальних можливостей. -mech.javelin-ship.description = Корабель для стратегії атакуй та біжи». Хоча спочатку він повільний, потім вже може розганятися до великих швидкостей і літати над ворожими форпостами, завдаючи великої кількості шкоди своїми блискавками та ракетами. +mech.javelin-ship.description = Корабель, який використовується для стратегії «атакуй та втікай». Хоча спочатку він повільний, потім вже може розганятися до великих швидкостей і літати над ворожими форпостами, завдаючи великої кількості шкоди своїми блискавками та ракетами. mech.trident-ship.description = Важкий бомбардувальник, побудований для будування та знищення ворожих укріплень. Дуже добре броньований. mech.glaive-ship.description = Великий, добре броньований бойовий корабель. Оснащений запальним ретранслятором. Високо маневрений. unit.draug.description = Примітивний дрон, який добуває ресурси. Дешевий для виробництва. Автоматично видобуває мідь і свинець поблизу. Доставляє видобуті ресурси до найближчого ядра. @@ -1100,7 +1102,7 @@ unit.crawler.description = Наземна одиниця, що складаєт unit.titan.description = Вдосконалений броньований наземний блок. Нападає як на наземні, так і повітряні цілі. Оснащений двома мініатюрними вогнеметами класу Випалювач. unit.fortress.description = Артилерійний мех. Оснащений двома модифікованими гарматами типу «Град» для дальнього нападу на ворожі структури та підрозділи. unit.eruptor.description = Важкий мех, призначеней для знесення конструкцій. Вистрілює потік шлаків у ворожі укріплення, розплавляючи їх і підпалюючи летючі речовини. -unit.wraith.description = Швидкий перехоплювач, який використовується для тактики «атакуй і біжи». Пріоритет — енергетичні генератори. +unit.wraith.description = Швидкий перехоплювач, який використовується для тактики «атакуй і втікай». Пріоритет — генератори енергії. unit.ghoul.description = Важкий килимовий бомбардувальник. Пробиває ворожі структури, орієнтуючись на віжливу інфраструктуру. unit.revenant.description = Важкий ракетний масив. block.message.description = Зберігає повідомлення. Використовується для комунікаціх між союзниками. @@ -1114,19 +1116,19 @@ block.alloy-smelter.description = Поєднує титан, свинець, к block.cryofluidmixer.description = Змішує воду і дрібний порошок титану титану в кріогенну рідину. Основне використання у торієвому реактору. block.blast-mixer.description = Подрібнює і змішує скупчення спор з піратитом для отримання вибухової суміші. block.pyratite-mixer.description = Змішує вугілля, свинець та пісок у легкозаймистий піратит. -block.melter.description = Розплавляє брухт у шлак для подальшої переробки або використання у башточках «Хвиля». +block.melter.description = Розплавляє брухт у шлак для подальшої переробки або використання у баштах «Хвиля». block.separator.description = Відокремлює шлак на його мінеральні компоненти. Виводить охолоджений результат. -block.spore-press.description = Стискає спорові стручки під сильним тиском для синтезу нафти +block.spore-press.description = Стискає спорові стручки під сильним тиском для синтезу нафти. block.pulverizer.description = Подрібнює брухт дрібного піску. block.coal-centrifuge.description = Нафта перетворюється у шматки вугілля. block.incinerator.description = Випаровує будь-який зайвий предмет або рідину, які він отримує. block.power-void.description = Знищує будь-яку енергію, до якої він під’єднаний. Тільки пісочниця -block.power-source.description = Нескінченно виводить енергію. Тільки пісочниця -block.item-source.description = Нескінченно виводить предмети. Тільки пісочниця -block.item-void.description = Знищує будь-які предмети. Тільки пісочниця -block.liquid-source.description = Нескінченно виводить рідини. Тільки пісочниця -block.copper-wall.description = Дешевий захисний блок.\nКорисна для захисту ядра та башточок у перші кілька хвиль. -block.copper-wall-large.description = Дешевий захисний блок.\nКорисна для захисту ядра та башточок у перші кілька хвиль.\nОхоплює кілька плиток. +block.power-source.description = Нескінченно виводить енергію. +block.item-source.description = Нескінченно виводить предмети. +block.item-void.description = Знищує будь-які предмети. +block.liquid-source.description = Нескінченно виводить рідини. +block.copper-wall.description = Дешевий захисний блок.\nКорисна для захисту ядра та башто у перші кілька хвиль. +block.copper-wall-large.description = Дешевий захисний блок.\nКорисна для захисту ядра та башт у перші кілька хвиль.\nОхоплює кілька плиток. block.titanium-wall.description = Відносно сильний захисний блок.\nЗабезпечує помірний захист від ворогів. block.titanium-wall-large.description = Відносно сильний захисний блок.\nЗабезпечує помірний захист від ворогів.\nОхоплює кілька плиток. block.plastanium-wall.description = Особливий тип стіни, який поглинає електричні дуги і блокує автоматичні з'єднання енергетичних вузлів. From 698e83a28a6a26038951c975d16edf8bbca70979 Mon Sep 17 00:00:00 2001 From: SpiffyBadGaster <58719310+SpiffyBadGaster@users.noreply.github.com> Date: Mon, 30 Dec 2019 06:51:30 +0700 Subject: [PATCH 38/78] Make translation better (#1222) * Make translation better * Make something better * Fix that javaline * Make Translate better Not finish * Make Translate better Not finish --- core/assets/bundles/bundle_th.properties | 69 ++++++++++++------------ 1 file changed, 34 insertions(+), 35 deletions(-) diff --git a/core/assets/bundles/bundle_th.properties b/core/assets/bundles/bundle_th.properties index 90b72d7312..6be91f3bad 100644 --- a/core/assets/bundles/bundle_th.properties +++ b/core/assets/bundles/bundle_th.properties @@ -29,7 +29,7 @@ load.mod = มอด schematic = Schematic schematic.add = กำลังบันทึก Schematic... schematics = Schematics -schematic.replace = มี schematic ที่ใช้ชื่อนี้แล้ว. แทนที่มัน? +schematic.replace = มี schematic ที่ใช้ชื่อนี้แล้ว. แทนที่เลยไม? schematic.import = นำเข้า Schematic... schematic.exportfile = ส่งออก File schematic.importfile = นำเข้า File @@ -60,7 +60,7 @@ level.mode = เกมโหมด: showagain = ไม่แสดงอีกในครั้งต่อไป coreattack = < Core กำลังถูกโจมตี! > nearpoint = [[ [scarlet]ออกจากดรอปพอยท์ด่วน IMMEDIATELY[] ]\nการทำลายล้างกำลังใกล้เข้ามา -database = Core Database +database = ฐานข้อมูหลัง savegame = เซฟเกม loadgame = โหลดเกม joingame = เข้าร่วมเกม @@ -116,7 +116,7 @@ noname = ใส่ชื่อ[accent] ผู้เล่น[] ก่อน. filename = ชื่อไฟล์: unlocked = content ใหม่ปลดล็อค! completed = [accent]สำเร็จ -techtree = สายวิจัย +techtree = ความคืบหน้าในการวิจัย research.list = [lightgray]วิจัย: research = วิจัย researched = [lightgray]{0} วิจัยแล้ว. @@ -126,9 +126,9 @@ server.closing = [accent]กำลังปิดเซิฟเวอร์... server.kicked.kick = คุณถูกเตะออกจากเซิฟเวอร์! server.kicked.whitelist = คุณไม่ได้อยู่ใน whitelisted server.kicked.serverClose = เซิฟเวอร์ถูกปิด. -server.kicked.vote = คุณถูกโหวตเตะออก. บายบาย. -server.kicked.clientOutdated = client ล่าสมัย! กรุณาอัปเดตเกมของคุณ! -server.kicked.serverOutdated = server ล่าสมัย! โปรดถามเจ้าของเซิฟเพื่ออัปเดต! +server.kicked.vote = คุณถูกโหวตเตะออก. บัยบาย. +server.kicked.clientOutdated = client เก่า! กรุณาอัปเดตเกมของคุณ! +server.kicked.serverOutdated = server เก่า! โปรดถามเจ้าของเซิฟเพื่ออัปเดต! server.kicked.banned = คุณถูกแบนในเซิฟเวอร์นี้ server.kicked.typeMismatch = เซิฟเวอร์นี้ไม่เข้ากับ build type ของคุณ. server.kicked.playerLimit = เซิฟเวอร์เต็ม. กรุณารอให้เซิฟเวอร์ว่างก่อน. @@ -598,7 +598,7 @@ category.items = ไอเท็ม category.crafting = นำเข้า/ส่งออก category.shooting = การยิง category.optional = การเพิ่มประสิทธิภาพทางเลือก -setting.landscape.name = ล็อค Landscape +setting.landscape.name = ล็อค Landscape แนวนอน setting.shadows.name = เงา setting.blockreplace.name = แนะนำบล็อคโดยอัตโนมัติ setting.linear.name = การกรองเชิงเส้น @@ -761,26 +761,26 @@ item.scrap.name = เศษเหล็ก liquid.water.name = น้ำ liquid.slag.name = กากแร่ liquid.oil.name = น้ำมัน -liquid.cryofluid.name = ไครโยฟลูอิด +liquid.cryofluid.name = โครโรฟิวล์ mech.alpha-mech.name = อัลฟ้า mech.alpha-mech.weapon = เฮฟวี้รีพีทเตอร์ mech.alpha-mech.ability = รีเจเนเรชั่น mech.delta-mech.name = เดลต้า mech.delta-mech.weapon = เครื่องกำเนิดประกายไฟฟ้า -mech.delta-mech.ability = ปล่อย +mech.delta-mech.ability = ปล่อยสายฟ้า mech.tau-mech.name = เทา mech.tau-mech.weapon = รีสตัคเลเซอร์ mech.tau-mech.ability = เบิสต์ซ่อมแซม mech.omega-mech.name = โอเมก้า -mech.omega-mech.weapon = ฝูงขีปนาวุธ +mech.omega-mech.weapon = ขีปนาวุธมหาปลัย mech.omega-mech.ability = ตัวเสริมเกราะ mech.dart-ship.name = ลูกดอก (Dart) mech.dart-ship.weapon = รีพีตเตอร์ -mech.javelin-ship.name = หอก (Javelin) +mech.javelin-ship.name = จาวาลีน (Javelin) mech.javelin-ship.weapon = ขีปนาวุธเบิสต์ mech.javelin-ship.ability = ดิสชาร์จบูสเตอร์ mech.trident-ship.name = ตรีศูล (Trident) -mech.trident-ship.weapon = ห้องเก็บระเบิด +mech.trident-ship.weapon = ตัวปล่อยระเบิด mech.glaive-ship.name = เกลฟว์ mech.glaive-ship.weapon = รีพีตเตอร์ไฟ item.explosiveness = [lightgray]ค่าการระเบิด: {0}% @@ -809,8 +809,8 @@ block.sandrocks.name = หินทราย block.spore-pine.name = ต้นสนสปอร์ block.sporerocks.name = หินสปอร์ block.rock.name = หิน -block.snowrock.name = หินหิมะ -block.snow-pine.name = ต้นสนหิมะ +block.snowrock.name = ก้อนหิมะ +block.snow-pine.name = ต้นสนที่คลุมหิมะ block.shale.name = หินดินดาน block.shale-boulder.name = ก้อนหินดินดาน block.moss.name = ตะไคร่น้ำ @@ -905,9 +905,8 @@ block.cryofluidmixer.name = เครื่องผสมไครโยฟล block.melter.name = เตาหลอม block.incinerator.name = เตาเผาขยะ block.spore-press.name = เครื่องอัดสปอร์ -block.separator.name = -เครื่องแยก -block.coal-centrifuge.name = เครื่องปั่นเหวี่งถ่านหิน +block.separator.name = เครื่องแยก +block.coal-centrifuge.name = เครื่องผลิตถ่านหิน block.power-node.name = โหนดพลังงาน block.power-node-large.name = โหนดพลังงานขนาดใหญ่ block.surge-tower.name = เสาเสิร์จ @@ -916,7 +915,7 @@ block.battery.name = แบตเตอรี่ block.battery-large.name = แบตเตอรี่ขนาดใหญ่ block.combustion-generator.name = เครื่องกำเนิดไฟฟ้าเผาไหม้ block.turbine-generator.name = เครื่องกำเนิดไฟฟ้าไอน้ำ -block.differential-generator.name = เครื่องกำเนิดไฟฟ้าดิฟเฟอเร่นเชี่ยว +block.differential-generator.name = เครื่องกำเนิดไฟฟ้าดิฟเฟอเร่นเตอร์ block.impact-reactor.name = เตาปฏิกรณ์อิมแพ็ค block.mechanical-drill.name = เครื่องขุดเชิงกล block.pneumatic-drill.name = เครื่องขุดนิวมาติก @@ -930,7 +929,7 @@ block.trident-ship-pad.name = ฐานปล่อยยานตรีศู block.glaive-ship-pad.name = ฐานปล่อยยานเกลฟว์ block.omega-mech-pad.name = ฐานปล่อยเม็คโอเมก้า block.tau-mech-pad.name = ฐานปล่อยเม็คเทา (Tau) -block.conduit.name = รางน้ำ +block.conduit.name = ท่อน้ำ block.mechanical-pump.name = ปั๊มเชิงกล block.item-source.name = จุดกำเนิดไอเท็ม block.item-void.name = จุดลบไอเท็ม @@ -943,8 +942,8 @@ block.wave.name = เวฟ block.swarmer.name = สวอร์มเมอร์ block.salvo.name = ซาวโว block.ripple.name = ริปเปิ้ล -block.phase-conveyor.name = สายพานเฟส -block.bridge-conveyor.name = สะพานสายพาน +block.phase-conveyor.name = สายพานความเร็วแสง +block.bridge-conveyor.name = สะพาน block.plastanium-compressor.name = เครื่องอัดพลาสตาเนียม block.pyratite-mixer.name = เครื่องผสมไพราไทต์ block.blast-mixer.name = เครื่องผสมสารประกอบระเบิด @@ -964,11 +963,11 @@ block.fortress-factory.name = โรงงานผลิตฟอร์เท block.revenant-factory.name = โรงงานผลิตยานไฟต์เตอร์เรเวแนนท์ block.repair-point.name = จุดซ่อมแซม block.pulse-conduit.name = รางน้ำโพวส์ -block.phase-conduit.name = รางน้ำเฟส +block.phase-conduit.name = ท่อน้ำความเร็วแสง block.liquid-router.name = เร้าเตอร์ของเหลว -block.liquid-tank.name = แทงค์เก็บของเหลว +block.liquid-tank.name = แทงค์น้ำ block.liquid-junction.name = ทางแยกของเหลว -block.bridge-conduit.name = สะพานรางน้ำ +block.bridge-conduit.name = ท่อน้ำยกระดับ block.rotary-pump.name = ปั๊มโรตารี้ block.thorium-reactor.name = เตาปฏิกรณ์ทอเรี่ยม block.mass-driver.name = แมสไดรฟ์เวอร์ @@ -982,8 +981,8 @@ block.surge-wall.name = กำแพงเสิร์จ block.surge-wall-large.name = กำแพงเสิร์จขนาดใหญ่ block.cyclone.name = ไซโคลน block.fuse.name = ฟิวส์ -block.shock-mine.name = กับระเบิดไฟฟ้าซ็อต -block.overdrive-projector.name = โอเวอร์ไดรฟ์โปรเจ็คเตอร์ +block.shock-mine.name = กับระเบิดไฟฟ้า +block.overdrive-projector.name = เครื่องเร่งประสิทธิภาพ block.force-projector.name = ฟอร์สโปรเจ็คเตอร์ block.arc.name = อาร์ค block.rtg-generator.name = เครื่องกำเนิดไฟฟ้า อาร์ทีจี @@ -1013,7 +1012,7 @@ unit.eruptor.name = อีรัฟเตอร์ unit.chaos-array.name = เคออสอาเรย์ unit.eradicator.name = อีเรดิเคเตอร์ unit.lich.name = ลิช -unit.reaper.name = รีฟเฟอร์ +unit.reaper.name = รีฟเปอร์ tutorial.next = [lightgray]<กดเพื่อดำเนินการต่อ> tutorial.intro = คุณได้เข้าสู่[scarlet] การสอนเล่นของ Mindustry.[]\nใช้ [[WASD] เพื่อเคลื่อนที่.\n[accent]กด [[Ctrl] ค้างระหว่างกลิ้งลูกกลิ้งเม้าส์[] เพื่อซูมเข้าและออก.\nเริ่มด้วยการ[accent] ขุดทองแดง[]. เคลื่อนที่ไปใกล้มัน, แล้วกดที่สายแร่ทองแดงใกล้ๆกับ core ของคุณ\n\n[accent]ทองแดง {0}/{1} ชิ้น tutorial.intro.mobile = คุณได้เข้าสู่[scarlet] การสอนเล่นของ Mindustry.[]\nเลื่อนหน้าจอเพื่อเคลื่อนที่.\n[accent]ใส่สองนิ้ว []เพื่อซูมเข้าและออก.\nเริ่มด้วยการ[accent] ขุดทองแดง[]. เคลื่อนที่ไปใกล้มัน, แล้วกดที่สายแร่ทองแดงใกล้ๆกับ core ของคุณ\n\n[accent]ทองแดง {0}/{1} ชิ้น @@ -1110,7 +1109,7 @@ block.phase-wall-large.description = A wall coated with special phase-based refl block.surge-wall.description = บล็อคป้องกันที่มีทนทานสูง.\nสะสมพลังงานจากกระสุน, แล้วปล่อยออกมาแบบสุ่ม. block.surge-wall-large.description = บล็อคป้องกันที่มีทนทานสูง.\nสะสมพลังงานจากกระสุน, แล้วปล่อยออกมาแบบสุ่ม.\nคลอบคลุมหลายช่อง. block.door.description = ประตูขนาดเล็ก. สามารถเปิดได้โดยการกด. -block.door-large.description = ประตูขนาดใหญ่. สามารถเปิดได้โดยการกด.\nคลอบคลุมหลายช่อง. +block.door-large.description = ประตูขนาดใหญ่. สามารถเปิดและปิดได้โดยการกด.\nคลอบคลุมหลายช่อง. block.mender.description = ซ่อมแซมบล็อคในวงของมันเป็นระยะๆ. ช่วยซ่อมแซมแนวป้องกันระหว่าง wave.\nสามารถใช้ซิลิก้อนเพื่อเพิ่มรัศมีและประสิทธิภาพได้ block.mend-projector.description = เมนเดอร์ที่ได้รับการอัปเกรด. ซ่อมแซมบล็อคในระยะของมัน.\nสามารถใช้ใยเฟสเพื่อเพิ่มระยะและประสิทธิภาพได้. block.overdrive-projector.description = เพิ่มความเร็วของสิ่งก่อสร้างรอบๆ.\nสามารถใช้ใยเฟสเพื่อเพิ่มระยะและประสิทธิภาพ. @@ -1123,7 +1122,7 @@ block.bridge-conveyor.description = บล็อคขนส่งไอเท block.phase-conveyor.description = บล็อคขนส่งไอเท็มขั้นสูง. ใช้พลังงานเพื่อส่งไอเท็มไปยังสายพานเฟสอีกอัน ข้ามได้หลายช่อง. block.sorter.description = แยกไอเท็ม. ถ้าไอเท็มตรงกับที่เลือกไว้, จะผ่านได้. แต่ถ้าไม่ตรง, ไอเท็มจะออกทางซ้ายหรือขวา (ใช้ทางที่ไอเท็มเข้าเป็นหลัก) block.inverted-sorter.description = แยกไอเท็มคล้ายเครื่องแยกธรรมดา, แต่ไอเท็มที่เลือกจะออกข้างแทน. -block.router.description = รับไอเท็มแล้วส่งออก 3 ทางเท่ากัน. มีประโยชน์สำหรับแยกไอเท็มจากแหล่งเดียวไปหลายที่.\n\n[scarlet]อย่าวางไว้ติดกับทางส่งไอเท็มเข้าเพราะของออกจะไปอุดตันได้.[] +block.router.description = รับไอเท็มแล้วส่งออก 3 ทางเท่าๆกัน. มีประโยชน์สำหรับแยกไอเท็มจากแหล่งเดียวไปหลายที่.\n\n[scarlet]อย่าวางไว้ติดกับทางส่งไอเท็มเข้าเพราะของออกจะไปอุดตันได้.[] block.distributor.description = เร้าเตอร์ขั้นสูง. แยกไอเท็มออก 7 ทางอย่างเท่าๆกัน. block.overflow-gate.description = ของจะออกจากข้างๆเมื่อทางข้างหน้ถูกบล็อคเท่านั้น. block.mass-driver.description = บล็อคขนส่งไอเท็มขั้นสุดยอด. รวบรวมไอเท็มจำนวนหนึ่งแล้วยิงไปหาแมสไดรเวอร์อีกอันที่อยู่ไกลออกไป. ต้องใช้พลังงานในการใช้งาน. @@ -1150,7 +1149,7 @@ block.differential-generator.description = ผลิตไฟฟ้าจำน block.rtg-generator.description = เครื่องกำเนิดไฟฟ้าที่ใช้ง่ายและไว้ใจได้. ใช้ความร้อนจากการสลายของสารกัมมัตภาพรังสีเพื่อใช้ผลิตพลังงานอย่างช้าๆ. block.solar-panel.description = ให้พลังงานจากแสงอาทิตย์จำนวนน้อย. block.solar-panel-large.description = เวอร์ชั่นของแผงโซล่าเซลล์ที่มีประสิทธิภาพมากขึ้นกว่าแผงโซล่าเซลล์ธรรมดา. -block.thorium-reactor.description = ผลิตพลังงานจำนวนมากจากทอเรี่ยม. ตำเป็นต้องใช้สารหล่อเย็นตลอดเวลา. จะระเบิดอย่างรุนแรงหากไม่ได้รับสารหล่อเย็นในจำนวนที่ต้องการ. จำนวนพลังงานที่ผลิตขึ้นอยู่กับความเต็ม และผลิตพลังงานเริ่มต้นที่ความสามารถสูงสุด. +block.thorium-reactor.description = ผลิตพลังงานจำนวนมากจากทอเรี่ยม. จำเป็นต้องใช้สารหล่อเย็นตลอดเวลา. จะระเบิดอย่างรุนแรงหากไม่ได้รับสารหล่อเย็นในจำนวนที่ต้องการ. จำนวนพลังงานที่ผลิตขึ้นอยู่กับความเต็ม และผลิตพลังงานเริ่มต้นที่ความสามารถสูงสุด. block.impact-reactor.description = เครื่องกำเนิดไฟฟ้าขั้นสูง, สามารถผลิตไฟฟ้าได้จำนวนมหาศาลที่ประสิทธิภาพสูงสุด. จำเป็นต้องใช้พลังงานจำนวนมากในการสตาร์ทเครื่อง. block.mechanical-drill.description = เครื่องขุดราคาถูก. เมื่อวางบนบล็อคที่ถูกต้อง, จะส่งไอเท็มของมันออกมาเรื่อยๆแบบไม่มีที่สิ้นสุด. ขุดได้แค่ทรัพยากรพื้นฐาน. block.pneumatic-drill.description = เครื่องขุดได้รับการปรับปรุง, สามารถขุดไทเทเนี่ยมได้. ขุดไวกว่าเครื่องขุดเชิงกล. @@ -1186,16 +1185,16 @@ block.draug-factory.description = ผลิตโดรนขุดเจาะ block.spirit-factory.description = ผลิตโดรนซ่อมแซมสปิริต. block.phantom-factory.description = ผลิตโดรนก่อสร้างขั้นสูง. block.wraith-factory.description = ผลิตยูนิตเร็ว โจมตีแบบ hit-and-run (จู่โจมแล้วหนี) -block.ghoul-factory.description = ผลิตยานทิ้งระเบิดปูพรมหนัก (heavy carpet bomber) +block.ghoul-factory.description = ผลิตยานทิ้งระเบิดแบบโหดๆ (heavy carpet bomber) block.revenant-factory.description = ผลิตยูนิตที่ใช้ขีปนาวุธเป็นหลัก. block.dagger-factory.description = ผลิตยูนิตภาคพื้นดินพื้นฐาน. -block.crawler-factory.description = ผลิตยูนิตพลีชีพเร็ว. +block.crawler-factory.description = ผลิตยูนิตที่ระเบิดตัวเอง. block.titan-factory.description = ผลิตยูนิตภาคพื้นดินเสริมเกราะขั้นสูง. -block.fortress-factory.description = ผลิตยูนิตหนักติดปืนใหญ่. +block.fortress-factory.description = ผลิตยูนิตที่ถึกและติดปืนใหญ่. block.repair-point.description = ซ่อมแซมยูนิตที่อยู่ในรัศมีอย่างต่อเนื่อง. block.dart-mech-pad.description = ใช้เปลี่ยนร่างเป็นเป็นเม็คโจมตีพื้นฐาน.\nใช้โดยการกดเมื่อยืนทับมัน. -block.delta-mech-pad.description = ใช้เปลี่ยนร่างเป็นเป็นเม็คเกราะบางโจมตีแบบ hit-and-run (จู่โจมแล้วหนี).\nใช้โดยการกดเมื่อยืนทับมัน. -block.tau-mech-pad.description = ใช้เปลี่ยนร่างเป็นเป็นเม็คสนับสนุนขั้นสูง.\nใช้โดยการกดเมื่อยืนทับมัน. +block.delta-mech-pad.description = ใช้เปลี่ยนร่างเป็นเป็นเม็คเกราะบางโจมตีแบบ hit-and-run (จูค).\nใช้โดยการกดเมื่อยืนทับมัน. +block.tau-mech-pad.description = ใช้เปลี่ยนร่างเป็นตัวที่ฮีลได้ดีมาก.\nใช้โดยการกดเมื่อยืนทับมัน. block.omega-mech-pad.description = ใช้เปลี่ยนร่างเป็นเป็นเม็คใช้ขีปนาวุธเกราะหนา.\nใช้โดยการกดเมื่อยืนทับมัน. block.javelin-ship-pad.description = ใช้เปลี่ยนร่างเป็นเป็นอินเทอร์เซ็ปเตอร์เร็วแบะเกราะบาง.\nใช้โดยการกดเมื่อยืนทับมัน. block.trident-ship-pad.description = ใช้เปลี่ยนร่างเป็นเป็นยานทิ้งระเบิดสนับสนุน.\nใช้โดยการกดเมื่อยืนทับมัน. From fe63b46b67b00faabaab77282ca3815f96dea07a Mon Sep 17 00:00:00 2001 From: PlayerBrasil13 <55503822+PlayerBrasil13@users.noreply.github.com> Date: Sun, 29 Dec 2019 20:51:37 -0300 Subject: [PATCH 39/78] Update bundle_pt_BR.properties (#1232) --- core/assets/bundles/bundle_pt_BR.properties | 31 +++++++++++++-------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/core/assets/bundles/bundle_pt_BR.properties b/core/assets/bundles/bundle_pt_BR.properties index 1e05466d91..28ead4e5ef 100644 --- a/core/assets/bundles/bundle_pt_BR.properties +++ b/core/assets/bundles/bundle_pt_BR.properties @@ -26,6 +26,7 @@ load.image = Imagens load.content = Conteúdo load.system = Sistema load.mod = Mods +load.scripts = Scripts schematic = Esquema schematic.add = Salvar Esquema... @@ -99,19 +100,24 @@ mod.enabled = [lightgray]Ativado mod.disabled = [scarlet]Desativado mod.disable = Desati-\nvar mod.delete.error = Incapaz de deletar o Mod. O arquivo talvez esteja em uso. -mod.requiresversion = [scarlet]Requer versão [accent]{0} [scarlet]do jogo. +mod.requiresversion = [scarlet]Requer no mínimo versão [accent]{0} [scarlet]do jogo. mod.missingdependencies = [scarlet]Dependências ausentes: {0} +mod.erroredcontent = [scarlet]Erros no Conteúdo +mod.errors = Erros ocorreram ao carregar o conteúdo. +mod.noerrorplay = [scarlet]Você tem mods com erros.[] Desative os mods afetados ou conserte os erros antes de jogar. mod.nowdisabled = [scarlet]O Mod '{0}' está com dependências ausentes:[accent] {1}\n[lightgray]Esses Mods precisam ser baixados primeiro.\nEsse Mod será desativado automaticamente. mod.enable = Ativar mod.requiresrestart = O jogo irá fechar para aplicar as mudanças do Mod. mod.reloadrequired = [scarlet]Recarregamento necessário mod.import = Importar Mod mod.import.github = Importar Mod do GitHub -mod.remove.confirm = Esse Mod será deletado. +mod.item.remove = Este item é parte do mod[accent] '{0}'[]. Para removê-lo, desinstale esse mod. +mod.remove.confirm = Este mod será deletado. mod.author = [LIGHT_GRAY]Author:[] {0} -mod.missing = Esse jogo salvo foi criado antes de você atualizar ou desinstalar um mod. O jogo salvo pode se corromper. Você tem certeza que quer carregar?\n[lightgray]Mods:\n{0} +mod.missing = Esse jogo salvo foi criado antes de você atualizar ou desinstalar um mod. Pode ocorrer uma corrupção no salvamento. Você tem certeza que quer carregar?\n[lightgray]Mods:\n{0} mod.preview.missing = Antes de publicar esse mod na Oficina, você deve adicionar uma imagem de pré-visualização.\nColoque uma imagem com o nome[accent] preview.png[] na pasta do Mod e tente novamente. mod.folder.missing = Somente Mods no formato de pasta serão publicados na Oficina.\nPara converter qualquer Mod em uma pasta, Simplesmente descompacte seu arquivo numa pasta e delete a compactação antiga, então reinicie seu jogo ou recarregue os Mods. +mod.scripts.unsupported = Seu dispositivo não suporta scripts de mods. Alguns mods não funcionarão corretamente. about.button = Sobre name = Nome: @@ -189,9 +195,9 @@ disconnect.data = Falha ao abrir os dados do mundo! cantconnect = Impossível conectar ([accent]{0}[]). connecting = [accent]Conectando... connecting.data = [accent]Carregando dados do mundo... -server.port = Porte: +server.port = Port: server.addressinuse = Senha em uso! -server.invalidport = Numero de porta invalido! +server.invalidport = Numero de port inválido! server.error = [crimson]Erro ao hospedar o servidor: [accent]{0} save.new = Novo salvamento save.overwrite = Você tem certeza que quer sobrescrever este salvamento? @@ -591,12 +597,14 @@ unit.persecond = por segundo unit.timesspeed = x Velocidade unit.percent = % unit.items = itens +unit.thousands = k +unit.millions = m category.general = Geral -category.power = Poder +category.power = Energia category.liquids = Líquidos category.items = Itens -category.crafting = Construindo -category.shooting = Atirando +category.crafting = Entrada/Saída +category.shooting = Atiradores category.optional = Melhoras opcionais setting.landscape.name = Travar panorama setting.shadows.name = Sombras @@ -805,6 +813,7 @@ mech.trident-ship.name = Tridente mech.trident-ship.weapon = Carga de bombas mech.glaive-ship.name = Glaive mech.glaive-ship.weapon = Repetidor de fogo +item.corestorable = [lightgray]Armazenável no núcleo: {0} item.explosiveness = [LIGHT_GRAY]Explosibilidade: {0} item.flammability = [LIGHT_GRAY]Inflamabilidade: {0} item.radioactivity = [LIGHT_GRAY]Radioatividade: {0} @@ -1039,7 +1048,7 @@ unit.eradicator.name = Erradicador unit.lich.name = Lich unit.reaper.name = Ceifador tutorial.next = [lightgray] -tutorial.intro = Você entrou no[scarlet] Tutorial do Mindustry.[]\nComeçe[accent] minerando cobre[]. Toque em um veio de minério de cobre para fazer isso.\n\n[accent]{0}/{1} copper +tutorial.intro = Você entrou no[scarlet] Tutorial do Mindustry.[]\nUse[accent] [[WASD][] para se mover.\n[accent]Roda do mouse[] para aumentar e diminuir o zoom.\nComece[accent] minerando cobre[]. Toque em um veio de minério de cobre para fazer isso.\n\n[accent]{0}/{1} copper tutorial.intro.mobile = You have entered the[scarlet] Mindustry Tutorial.[]\nSwipe the screen to move.\n[accent]Pinch with 2 fingers [] to zoom in and out.\nBegin by[accent] mining copper[]. Move close to it, then tap a copper ore vein near your core to do this.\n\n[accent]{0}/{1} copper tutorial.drill = Minerar manualmente é ineficiente.\n[accent]Brocas []podem minerar automaticamente.\nColoque uma num veio de cobre. tutorial.drill.mobile = Minerar manualmente é ineficiente.\n[accent]Brocas []podem minerar automaticamente.\nToque na aba de brocas no canto inferior direito.\nSelecione a[accent] broca mecânica[].\nToque em um veio de cobre para colocá-la, então pressione a[accent] marca de verificação[] abaixo para confirmar sua seleção.\nPressione o[accent] botão "X"[] para cancelar o posicionamento. @@ -1138,9 +1147,9 @@ block.door-large.description = Uma grande porta. Pode ser aberta e fechada ao to block.mender.description = Periodicamente repara blocos vizinhos. Mantem as defesas reparadas em e entre ondas.\nPode usar silício para aumentar o alcance e a eficiência. block.mend-projector.description = Uma versão melhorada do reparador. Repara blocos vizinhos.\nPode usar tecido de fase para aumentar o alcance e a eficiência. block.overdrive-projector.description = Aumenta a velocidade de construções vizinhas.\nPode usar tecido de fase para aumentar o alcance e a eficiência. -block.force-projector.description = Cria um campo de forca hexagonal em volta de si mesmo, Protegendo construções e unidades dentro de dano por balas. +block.force-projector.description = Cria um campo de força hexagonal ao redor de si, protegendo construções e unidades.\nSuperaquece se suportar muito dano. Pode usar líquidos para evitar superaquecimento. Pode-se usar tecido de fase para aumentar o tamanho do escudo. block.shock-mine.description = Danifica inimigos em cima da mina. Quase invisivel ao inimigo. -block.conveyor.description = Bloco de transporte de item basico. Move os itens a frente e os deposita automaticamente em torretas ou construtores. Rotacionavel. +block.conveyor.description = Bloco de transporte de item basico. Move os itens a frente e os deposita automaticamente em torretas ou construtores. Rotacionável. block.titanium-conveyor.description = Bloco de transporte de item avançado. Move itens mais rapidos que esteiras padrões. block.junction.description = Funciona como uma ponte Para duas esteiras que estejam se cruzando. Util em situações que tenha duas esteiras diferentes carregando materiais diferentes para lugares diferentes. block.bridge-conveyor.description = Bloco de transporte de itens avancado. Possibilita o transporte de itens acima de 3 blocos de construção ou paredes. From e200dcee33466c5000d20b8f8b029e5ec52d7268 Mon Sep 17 00:00:00 2001 From: GioIacca9 <39232448+GioIacca9@users.noreply.github.com> Date: Mon, 30 Dec 2019 00:51:45 +0100 Subject: [PATCH 40/78] Update bundle_it.properties (#1240) --- core/assets/bundles/bundle_it.properties | 211 ++++++++++++----------- 1 file changed, 109 insertions(+), 102 deletions(-) diff --git a/core/assets/bundles/bundle_it.properties b/core/assets/bundles/bundle_it.properties index 75351ad9a8..ef97566b90 100644 --- a/core/assets/bundles/bundle_it.properties +++ b/core/assets/bundles/bundle_it.properties @@ -12,11 +12,12 @@ link.itch.io.description = Pagina di itch.io con download per PC e versione web link.google-play.description = Elenco di Google Play Store link.f-droid.description = Catalogo F-Droid link.wiki.description = Wiki ufficiale di Mindustry +link.feathub.description = Suggerisci nuove funzionalità linkfail = Impossibile aprire il link! L'URL è stato copiato. screenshot = Screenshot salvato a {0} -screenshot.invalid = Mappa troppo grossa, probabilmente non c'è abbastanza memoria libera. +screenshot.invalid = Mappa troppo pesante, probabilmente non c'è abbastanza spazio sul disco. gameover = Il Nucleo è stato distrutto. -gameover.pvp = La squadra [accent] {0}[] ha vinto! +gameover.pvp = La squadra[accent] {0}[] ha vinto! highscore = [YELLOW]Nuovo record! copied = Copiato. @@ -26,7 +27,7 @@ load.image = Immagini load.content = Contenuti load.system = Sistema load.mod = Mods -load.scripts = Testi +load.scripts = Scripts schematic = Schematica schematic.add = Salva Schematica... @@ -54,7 +55,7 @@ stat.delivered = Riorse lanciate: stat.rank = Livello finale: [accent]{0} launcheditems = [accent]Oggetti Lanciati -launchinfo = [unlaunched][[LAUNCH] il tuo Nucleo per ottenere gli oggetti indicati in blu. +launchinfo = [unlaunched][LANCIA] il tuo Nucleo per ottenere gli oggetti indicati in blu. map.delete = Sei sicuro di voler eliminare la mappa"[accent]{0}[]"? level.highscore = Miglior Punteggio: [accent]{0} level.select = Selezione del Livello @@ -68,7 +69,7 @@ loadgame = Carica joingame = Unisciti al Gioco customgame = Gioco Personalizzato newgame = Nuova partita -none = +none = < niente > minimap = Minimappa position = Posizione close = Chiuso @@ -88,30 +89,32 @@ committingchanges = Applico le modifiche done = Fatto feature.unsupported = Il tuo dispositivo non supporta questa funzione. -mods.alphainfo = Tieni a mente che queste Mod sono in alpha, e[scarlet] possono contenere molti bug[].\Segnala tutti i problemi che trovi su GitHub o Discord di Mindustry. +mods.alphainfo = Tieni a mente che queste mods sono in alpha, e[scarlet] possono contenere molti bug[].\Segnala tutti i problemi che trovi su GitHub o Discord di Mindustry. mods.alpha = [accent](Alpha) mods = Mods -mods.none = [LIGHT_GRAY]Nessuna Mod trovata! +mods.none = [LIGHT_GRAY]Nessuna mod trovata! mods.guide = Guida per il modding! mods.report = Segnala un Bug -mods.openfolder = Apri Cartella Mod +mods.openfolder = Apri Cartella Mods mod.enabled = [lightgray]Abilitato mod.disabled = [scarlet]Disabilitato mod.disable = Disabilita -mod.delete.error = Impossibile eliminare questa Mod. Il file potrebbe essere in uso. +mod.delete.error = Impossibile eliminare questa mod. Il file potrebbe essere in uso. +mod.requiresversion = [scarlet]Versione minima richiesta: [accent]{0} mod.missingdependencies = [scarlet]Dipendenze mancanti: {0} -mod.nowdisabled = [scarlet]Alla Mod '{0}' mancano delle dipendenze:[accent] {1}\n[lightgray]Queste Mod devono essere scaricate prima.\nQuesta Mod verrà disabilitata automaticamente. +mod.nowdisabled = [scarlet]Alla mod '{0}' mancano delle dipendenze:[accent] {1}\n[lightgray]Queste mods devono essere scaricate prima.\nQuesta mod verrà disabilitata automaticamente. mod.enable = Abilita mod.requiresrestart = Il gioco verrà chiuso per applicare i cambiamenti. mod.reloadrequired = [scarlet]Riavvio necessario -mod.import = Importa una Mod -mod.import.github = Importa una Mod da GitHub -mod.item.remove = Questo item fa parte della Mod[accent] '{0}'[]. Per rimuoverlo, disinstalla questa Mod. -mod.remove.confirm = Questa Mod verrà eliminata. +mod.import = Importa una mod +mod.import.github = Importa una mod da GitHub +mod.item.remove = Questo item fa parte della mod[accent] '{0}'[]. Per rimuoverlo, disinstalla questa mod. +mod.remove.confirm = Questa mod verrà eliminata. mod.author = [LIGHT_GRAY]Autore:[] {0} -mod.missing = Questo salvataggio contiene Mod che hai recentemente aggiornato o non hai più installate. Il salvataggio potrebbe corrompersi. Sei sicuro di volerlo caricare?\n[lightgray]Mods:\n{0} -mod.preview.missing = Prima di pubblicare questa Mod nel Workshop, devi aggiungere un immagine di copertina.\nMetti un immagine[accent] con nome preview.png[] nella cartella della Mod e riprova. -mod.folder.missing = Solo le Mod in una cartella possono essere pubblicate nel Workshop.\nPer convertire una Mod in una cartella, decomprimi i suoi file in una cartella ed elimina il vecchio zip, quindi riavvia il gioco o ricarica le tue mods. +mod.missing = Questo salvataggio contiene delle mods che hai recentemente aggiornato o non hai più installate. Il salvataggio potrebbe corrompersi. Sei sicuro di volerlo caricare?\n[lightgray]Mods:\n{0} +mod.preview.missing = Prima di pubblicare questa mod nel Workshop, devi aggiungere un immagine di copertina.\nMetti un immagine[accent] con nome preview.png[] nella cartella della mods e riprova. +mod.folder.missing = Solo le mods in una cartella possono essere pubblicate nel Workshop.\nPer convertire una mod in una cartella, decomprimi i suoi file in una cartella ed elimina il vecchio zip, quindi riavvia il gioco o ricarica le tue mods. +mod.scripts.unsupported = Il tuo dispositivo non supporta gli script per le mods. Alcune mods non funzioneranno correttamente. about.button = Info name = Nome: @@ -142,12 +145,12 @@ server.kicked.idInUse = Sei già su questo server! Non è permesso connettersi c server.kicked.customClient = Questo server non supporta i client personalizzati. Scarica la versione ufficiale dal sito. server.kicked.gameover = Game over! server.versions = Your version:[accent] {0}[]\nVersione server:[accent] {1}[] -host.info = Il pulsante [accent]host [] ospita un server sulla porta [scarlet]6567[].[] Chiunque sulla stessa [LIGHT_GRAY]rete wifi o locale[] dovrebbe essere in grado di vedere il server nell'elenco server.\n\n Se vuoi che le persone siano in grado di connettersi ovunque tramite il tuo IP, è richiesto il [accent]port forwarding[]. \n\n[LIGHT_GRAY]Nota: se qualcuno sta riscontrando problemi durante la connessione al gioco LAN, assicurati di aver consentito a Mindustry di accedere alla rete locale nelle impostazioni del firewall. -join.info = Qui è possibile inserire l'[accent]IP del server[] a cui connettersi, o scoprire [accent]un server sulla rete locale[] disponibile.\nSono supportati sia il multiplayer LAN che WAN. \n\n[LIGHT_GRAY]Nota: non esiste un elenco automatico dei server globali; se desideri connetterti a qualcuno tramite il suo IP, è necessario chiedere all'host il proprio IP. +host.info = Il pulsante [accent]host[] ospita un server sulla porta [scarlet]6567[].[] Chiunque sulla stessa [LIGHT_GRAY]rete wifi o locale[] dovrebbe essere in grado di vedere il server nell'elenco server.\nSe vuoi che le persone siano in grado di connettersi ovunque tramite il tuo IP, è richiesto il [accent]port forwarding[].\n\n[LIGHT_GRAY]Nota: se qualcuno sta riscontrando problemi durante la connessione al gioco LAN, assicurati di aver consentito a Mindustry di accedere alla rete locale nelle impostazioni del firewall. +join.info = Qui è possibile inserire l'[accent]IP del server[] a cui connettersi, o scoprire [accent]un server sulla rete locale[] disponibile.\nSono supportati sia il multiplayer LAN che WAN.\n\n[LIGHT_GRAY]Nota: non esiste un elenco automatico dei server globali; se desideri connetterti a qualcuno tramite il suo IP, è necessario chiedere all'host il proprio IP. hostserver = Ospita Server invitefriends = Invita amici hostserver.mobile = Ospita\nServer -host = Host +host = Ospita hosting = [accent] Apertura del server... hosts.refresh = Aggiorna hosts.discovering = Ricerca partite LAN @@ -213,7 +216,7 @@ selectslot = Seleziona un salvataggio. slot = [accent]Slot {0} editmessage = Modifica Messaggio save.corrupted = [orang]Salvataggio corrotto o non valido! -empty = +empty = < vuoto > on = On off = Off save.autosave = Salvataggio Automatico: {0} @@ -280,7 +283,7 @@ publishing = [accent]Pubblicazione... publish.confirm = Are you sure you want to publish this?\n\n[lightgray]Make sure you agree to the Workshop EULA first, or your items will not show up! publish.error = Error publishing item: {0} steam.error = Failed to initialize Steam services.\nError: {0} -editor.brush = Pennello +editor.brush = Dimensioni Pennello editor.openin = Apri nell'editor editor.oregen = Generazione dei minerali editor.oregen.info = Generazione dei minerali: @@ -297,7 +300,7 @@ editor.newmap = Nuova mappa workshop = Workshop waves.title = Ondate waves.remove = Rimuovi -waves.never = +waves.never = < mai > waves.every = sempre waves.waves = ondata/e waves.perspawn = per spawn @@ -309,14 +312,14 @@ waves.copy = Copia negli appunti waves.load = Carica dagli appunti waves.invalid = Onde dagli appunti non valide. waves.copied = Onde copiate. -waves.none = Nessun nemico definiti.\n Nota che le disposizioni di ondate vuote verranno automaticamente rimpiazzate con la disposizione predefinita. -editor.default = [LIGHT_GRAY] +waves.none = Nessun nemico definiti.\nNota che le disposizioni di ondate vuote verranno automaticamente rimpiazzate con la disposizione predefinita. +editor.default = [LIGHT_GRAY]< Predefinito > details = Dettagli... edit = Modifica... editor.name = Nome: editor.spawn = Piazza un'unità editor.removeunit = Rimuovi un'unità -editor.teams = Squadre +editor.teams = Colore Squadre editor.errorload = Errore nel caricamento di:\n[accent]{0} editor.errorsave = Errore nel salvataggio di:\n[accent]{0} editor.errorimage = Quella è un'immagine, non una mappa.\n\nSe vuoi importare una mappa vecchia clicca su "Importa una mappa vecchia" nell'editor. @@ -335,14 +338,14 @@ editor.saved = Salvato! editor.save.noname = La tua mappa non ha un nome! Impostane uno nelle informazioni della mappa. editor.save.overwrite = La tua mappa sovrascrive quelle incluse! Imposta un nome diverso nelle informazioni della mappa. editor.import.exists = [scarlet]Impossibile importare:[] esiste già una mappa chiamata '{0}' che non può essere sovrascritta! -editor.import = Importando... +editor.import = Importa editor.importmap = Importa mappa editor.importmap.description = Importa mappa preesistente editor.importfile = Importa file editor.importfile.description = Importa un file mappa esterno editor.importimage = Importa mappa terreno editor.importimage.description = Importa immagine esterna terreno -editor.export = Esportazione... +editor.export = Esporta editor.exportfile = Esporta file editor.exportfile.description = Esporta file mappa editor.exportimage = Esporta immagine @@ -437,8 +440,8 @@ launch.confirm = Questo trasporterà tutte le risorse nel tuo Nucleo.\nNon riusc launch.skip.confirm = Se salti adesso non riuscirai a decollare fino alle ondate successive uncover = Scopri configure = Configura l'equipaggiamento -bannedblocks = Blocchi banditi -addall = Aggiungi tutti +bannedblocks = Blocchi Banditi +addall = Aggiungi Tutti configure.locked = [LIGHT_GRAY]Arriva all'ondata {0}\nper configurare l'equipaggiamento. configure.invalid = Il valore dev'essere un numero compresto tra 0 e {0}. zone.unlocked = [LIGHT_GRAY]{0} sbloccata. @@ -448,14 +451,14 @@ zone.resources = Risorse Trovate: zone.objective = [lightgray]Obiettivo: [accent]{0} zone.objective.survival = Sopravvivere zone.objective.attack = Distruggere il Nucleo Nemico -add = Aggiungi... +add = Aggiungi boss.health = Vita del Boss -connectfail = [crimson] Impossibile connettersi al server: [accent] {0} +connectfail = [crimson]Impossibile connettersi al server:[accent] {0} error.unreachable = Server irraggiungibile. L'indirizzo è scritto correttamente? -error.invalidaddress = Indirizzo invalido. -error.timedout = Timeout!\n Assicurati che l'host abbia il port forwarding impostato e che l'indirizzo sia corretto! -error.mismatch = Errore pacchetti:\nPossibile discordanza della versione client / server.\n Assicurati che tu e l'host possiediate l'ultima versione di Mindustry! +error.invalidaddress = Indirizzo non valido. +error.timedout = Timeout!\nAssicurati che l'host abbia il port forwarding impostato e che l'indirizzo sia corretto! +error.mismatch = Errore pacchetti:\nPossibile discordanza della versione client/server.\nAssicurati che tu e l'host possiediate l'ultima versione di Mindustry! error.alreadyconnected = Già connesso. error.mapnotfound = Mappa non trovata error.io = Errore I/O di rete. @@ -478,7 +481,7 @@ zone.crags.name = Dirupi zone.fungalPass.name = Passaggio Fungoso zone.groundZero.description = La posizione ottimale per cominciare. Bassa minaccia nemica. Poche risorse.\nRaccogli quanto più piombo e rame possibile.\nProcedi. -zone.frozenForest.description = Anche qui, più vicino alle montagne, le spore si sono diffuse. Le temperature rigide non possono contenerle per sempre.\n Inizia la scoperta dell'energia. Costruisci generatori a combustione. Impara a usare i riparatori. +zone.frozenForest.description = Anche qui, più vicino alle montagne, le spore si sono diffuse. Le temperature rigide non possono contenerle per sempre.\nInizia la scoperta dell'energia. Costruisci generatori a combustione. Impara a usare i riparatori. zone.desertWastes.description = Questi rifiuti sono vasti, imprevedibili ed attraversati da strutture settoriali abbandonate.\n\nIl carbone è presente nella regione. Bruciatelo per ottenere energia o sintetizzate la grafite.\n\n[lightgray]Questa posizione di atterraggio non può essere garantita. zone.saltFlats.description = Alle periferie del deserto si trovano le saline. Poche risorse possono essere trovate in questa posizione.\n\nIl nemico ha eretto un complesso di archiviazione delle risorse qui. Sradicare il loro Nucleo. Non lasciare nulla in piedi. zone.craters.description = L'acqua si è accumulata in questo cratere, reliquia delle vecchie guerre. Recupera l'area. Raccogli la sabbia. Fondi il vetro metallico. Pompa l'acqua per raffreddare torrette e trivelle. @@ -487,20 +490,21 @@ zone.stainedMountains.description = Più nell'entroterra si trovano le montagne, zone.overgrowth.description = Quest'area è invasa, più vicina alla fonte delle spore.\nIl nemico ha stabilito qui un avamposto. Costruisci unità col pugnale. Distruggilo. Riprenditi ciò che è stato perso. zone.tarFields.description = La periferia di una zona di produzione di petrolio, tra le montagne e il deserto. Una delle poche aree con riserve di catrame utilizzabili.\nAnche se abbandonata, questa zona ha alcune pericolose forze nemiche nelle vicinanze. Non sottovalutarlo.\n\n[lightgray]Ricerca la tecnologia di lavorazione del petrolio, se possibile. zone.desolateRift.description = Una zona estremamente pericolosa. Risorse abbondanti, ma poco spazio. Alto rischio di distruzione. Lascia il prima possibile. Non lasciarti ingannare dalla lunga distanza tra gli attacchi nemici. -zone.nuclearComplex.description = Un ex impianto per la produzione e la lavorazione del torio, ridotto in rovina.\n[lightgray] Ricerca il torio ed i suoi numerosi usi.\n\nIl nemico è presente qui in gran numero, alla costante ricerca di aggressori. +zone.nuclearComplex.description = Un ex impianto per la produzione e la lavorazione del torio, ridotto in rovina.\n[lightgray]Ricerca il torio ed i suoi numerosi usi.\n\nIl nemico è presente qui in gran numero, alla costante ricerca di aggressori. zone.fungalPass.description = Un'area di transizione tra alte montagne e terre più basse, piene di spore. Qui si trova una piccola base di ricognizione nemica.\nDistruggila.\nUsa le unità Pugnale e Strisciatore. Elimina i due nuclei. -zone.impact0078.description = -zone.crags.description = +zone.impact0078.description = < inserisci descrizione > +zone.crags.description = < inserisci descrizione > settings.language = Lingua settings.data = Importa/Esporta salvataggio settings.reset = Ripristina Impostazioni settings.rebind = Modifica +settings.resetKey = Ripristina settings.controls = Controlli settings.game = Gioco settings.sound = Suoni settings.graphics = Grafica -settings.cleardata = Elimina Dati di Gioco... +settings.cleardata = Elimina Dati di Gioco settings.clear.confirm = Sei sicuro di voler cancellare i dati?\nQuesta operazione non può essere annullata! settings.clearall.confirm = [scarlet]ATTENZIONE![]\nQuesto cancellerà tutti i dati, inclusi salvataggi, mappe, oggetti sbloccati ed impostazioni.\nDopo aver premuto su 'ok' il gioco eliminerà i dati e si chiuderà automaticamente. paused = [accent]< In Pausa > @@ -513,7 +517,7 @@ error.title = [crimson]Si è verificato un errore error.crashtitle = Si è verificato un errore blocks.input = Ingresso blocks.output = Uscita -blocks.booster = Booster +blocks.booster = Potenziamenti block.unknown = [LIGHT_GRAY]??? blocks.powercapacity = Capacità Energetica blocks.powershot = Danno/Colpo @@ -675,23 +679,23 @@ keybind.dash.name = Scatto keybind.schematic_select.name = Seleziona Regione keybind.schematic_menu.name = Menu Schematica keybind.schematic_flip_x.name = Ruota Schematica Orizzontalmente -keybind.schematic_flip_y.name = Flip Schematic Verticalmente +keybind.schematic_flip_y.name = Ruota Schematica Verticalmente keybind.category_prev.name = Categoria Precedente keybind.category_next.name = Categoria Successiva keybind.block_select_left.name = Seleziona Blocco Sinistra keybind.block_select_right.name = Seleziona Blocco Destra keybind.block_select_up.name = Seleziona Blocco Su keybind.block_select_down.name = Seleziona Blocco Giù -keybind.block_select_01.name = Categoria/Seleziona Blocco 1 -keybind.block_select_02.name = Categoria/Seleziona Blocco 2 -keybind.block_select_03.name = Categoria/Seleziona Blocco 3 -keybind.block_select_04.name = Categoria/Seleziona Blocco 4 -keybind.block_select_05.name = Categoria/Seleziona Blocco 5 -keybind.block_select_06.name = Categoria/Seleziona Blocco 6 -keybind.block_select_07.name = Categoria/Seleziona Blocco 7 -keybind.block_select_08.name = Categoria/Seleziona Blocco 8 -keybind.block_select_09.name = Categoria/Seleziona Blocco 9 -keybind.block_select_10.name = Categoria/Seleziona Blocco 10 +keybind.block_select_01.name = Seleziona Categoria/Blocco 1 +keybind.block_select_02.name = Seleziona Categoria/Blocco 2 +keybind.block_select_03.name = Seleziona Categoria/Blocco 3 +keybind.block_select_04.name = Seleziona Categoria/Blocco 4 +keybind.block_select_05.name = Seleziona Categoria/Blocco 5 +keybind.block_select_06.name = Seleziona Categoria/Blocco 6 +keybind.block_select_07.name = Seleziona Categoria/Blocco 7 +keybind.block_select_08.name = Seleziona Categoria/Blocco 8 +keybind.block_select_09.name = Seleziona Categoria/Blocco 9 +keybind.block_select_10.name = Seleziona Categoria/Blocco 10 keybind.fullscreen.name = Schermo Intero keybind.select.name = Seleziona/Spara keybind.diagonal_placement.name = Posizionamento Diagonale @@ -708,7 +712,7 @@ keybind.chat.name = Chat keybind.player_list.name = Lista dei Giocatori keybind.console.name = Console keybind.rotate.name = Ruota -keybind.rotateplaced.name = Ruota Blocco Esistente (Premuto) +keybind.rotateplaced.name = Ruota Blocco Esistente (premuto) keybind.toggle_menus.name = Mostra/Nascondi HUD keybind.chat_history_prev.name = Scorri Chat vero l'alto keybind.chat_history_next.name = Scorri Chat verso il basso @@ -987,12 +991,13 @@ block.titan-factory.name = Fabbrica Mech Titano block.fortress-factory.name = Fabbrica Mech Fortezza block.revenant-factory.name = Fabbrica Combattenti Superstiti block.repair-point.name = Punto di Riparazione -block.pulse-conduit.name = Condotto Attiva -block.phase-conduit.name = Condotta di Fase +block.pulse-conduit.name = Condotto a Impulsi +block.plated-conduit.name = Condotto Placcato +block.phase-conduit.name = Condotto di Fase block.liquid-router.name = Distributore di Liquidi block.liquid-tank.name = Serbatoio block.liquid-junction.name = Giunzione Liquida -block.bridge-conduit.name = Condotta Sopraelevata +block.bridge-conduit.name = Condotto Sopraelevato block.rotary-pump.name = Pompa a Turbina block.thorium-reactor.name = Reattore al Torio block.mass-driver.name = Lancia Materiali @@ -1038,31 +1043,31 @@ unit.chaos-array.name = Matrice del Caos unit.eradicator.name = Estirpatore unit.lich.name = Lich unit.reaper.name = Mietitore -tutorial.next = [lightgray] -tutorial.intro = Sei entrato nel[scarlet] Tutorial di Mindustry.[]\nInizia[accent] scavando rame[]. Clicca un minerale di rame vicino al tuo Nucleo per farlo.\n\n[accent]{0}/{1} rame -tutorial.intro.mobile = You have entered the[scarlet] Mindustry Tutorial.[]\nSwipe the screen to move.\n[accent]Pinch with 2 fingers [] to zoom in and out.\nBegin by[accent] mining copper[]. Move close to it, then tap a copper ore vein near your core to do this.\n\n[accent]{0}/{1} copper +tutorial.next = [lightgray]< Clicca per continuare > +tutorial.intro = Sei entrato nel[scarlet] Tutorial di Mindustry.[]\nInizia[accent] scavando del rame[]. Clicca un minerale di rame vicino al tuo Nucleo per farlo.\n\n[accent]{0}/{1} rame +tutorial.intro.mobile = Sei entrato nel[scarlet] Tutorial di Mindustry.[]\nScorri sullo schermo per muoverti.\n[accent]Avvicina due dita[] per eseguire lo zoom in/out.\nInizia [accent] scavando del rame[]. Clicca un minerale di rame vicino al tuo Nucleo per farlo.\n\n[accent]{0}/{1} rame tutorial.drill = Ora crea una trivella.\n[accent]Le trivelle []scavano da sole e sono più efficienti. Piazzane una su un minerale di rame. -tutorial.drill.mobile = Ora crea una trivella. \n[accent] Le trivelle []scavano da sole e sono più efficienti. \n Toccare la scheda della trivella in basso a destra. \n Selezionare la trivella meccanica [accent] []. \n Posizionarlo su una vena di rame toccando, quindi premere il segno di spunta [accent] [] in basso per confermare la selezione. \n Premere il tasto X [accent] [] per annullare il posizionamento. +tutorial.drill.mobile = Ora crea una trivella.\n[accent] Le trivelle []scavano da sole e sono più efficienti.\nTocca la scheda della trivella in basso a destra.\nSeleziona la [accent]Trivella Meccanica[].\nPiazzala su una vena di rame toccando, quindi premi il [accent]segno di spunta[] in basso per confermare la selezione.\nCon il tasto [accent]X[] puoi annullare il posizionamento. tutorial.blockinfo = Ogni blocco ha statistiche diverse. Alcuni minerali richiedono trivelle specifiche.\nPer controllare le informazioni e le statistiche di un blocco, [accent] tocca "?" mentre lo selezioni nel database. []\n\n[accent]Accedi ora alle statistiche della trivella meccanica. [] -tutorial.conveyor = [accent]I nastri trasportatori []sono usati per trasportare oggetti al Nucleo. \nCrea una linea di nastri dalla trivella al Nucleo. -tutorial.conveyor.mobile = [accent] I nastri trasportatori [] sono usati per trasportare oggetti nel nocciolo. \nCrea una linea di nastri trasportatori dalla trivella al nocciolo. \n[accent] Posizionati in una linea tenendo premuto il dito per alcuni secondi [] e trascinando in una direzione. \n\n [accent] {0} / {1} nastri trasportatori disposti in linea \n [accent] 0/1 oggetti consegnati -tutorial.turret = Costruisci delle torrette per respingere il nemico [LIGHT_GRAY] []. \nCostruisci una torretta Duo vicino alla tua base. +tutorial.conveyor = [accent]I nastri trasportatori []sono usati per trasportare oggetti al Nucleo.\nCrea una linea di nastri dalla trivella al Nucleo. +tutorial.conveyor.mobile = [accent]I nastri trasportatori[] sono usati per trasportare oggetti nel Nucleo.\nCrea una linea di nastri trasportatori dalla trivella al Nucleo.\n[accent]Piazzali in linea tenendo premuto per qualche secondo e trascinando il dito in una direzione.\n\n[accent]Piazza 2 nastri trasportatori con lo strumento linea, quindi trasporta un oggetto fino al Nucleo. +tutorial.turret = Costruisci delle torrette per respingere il nemico [LIGHT_GRAY] [].\nCostruisci una torretta Duo vicino alla tua base. tutorial.drillturret = La Torretta Duo richiede[accent] munizioni di rame[] per sparare.\nPosiziona una trivella e collega un nastro alla torretta per rifornirla di munizioni con il rame estratto. -tutorial.pause = Durante la battaglia, puoi mettere in pausa il gioco [accent]. []\nPuoi disporre gli edifici mentre sei in pausa. \n\n[accent]Premi spazio per mettere in pausa. -tutorial.pause.mobile = Durante la battaglia, puoi mettere in pausa il gioco [accent]. []\nPuoi disporre gli edifici mentre sei in pausa. \n\n[accent] Premi questo pulsante in alto a sinistra per mettere in pausa. +tutorial.pause = Durante la battaglia puoi[accent] mettere in pausa il gioco.[]\nPuoi disporre gli edifici mentre il gioco è in pausa.\n\nPer mettere in pausa, premi [accent]spazio[]. +tutorial.pause.mobile = Durante la battaglia puoi[accent] mettere in pausa il gioco.[]\nPuoi disporre gli edifici mentre il gioco è in pausa.\n\nPer mettere in pausa, premi il bottone in alto a sinistra. tutorial.unpause = Ora premi di nuovo spazio per annullare la pausa. tutorial.unpause.mobile = Ora premilo di nuovo per annullare la pausa. -tutorial.breaking = I blocchi spesso devono essere distrutti. \n [accent]Tieni premuto il tasto destro del mouse [] per distruggere tutti i blocchi in una selezione. []\n[accent]Distruggi tutti i blocchi di scarto a sinistra del tuo Nucleo usando la selezione dell'area . -tutorial.breaking.mobile = I blocchi spesso devono essere distrutti. \n [accent] Seleziona la modalità di decostruzione [], quindi tocca un blocco per iniziare a smantellarlo. \n Distruggi un'area tenendo premuto il dito per alcuni secondi [] e trascinando in una direzione.\nPremi il pulsante con il segno di spunta per confermare la rimozione. \n\n [accent] Distruggi tutti i blocchi di scarto a sinistra del tuo Nucleo usando la selezione dell'area. -tutorial.withdraw = In alcune situazioni, è necessario prendere gli oggetti direttamente dai blocchi.\nPer fare ciò, [accent] tocca un blocco []con oggetti al suo interno, quindi [accent] tocca l'oggetto [] nell'inventario. \nPuoi prelevare più oggetti insieme[accent]tenendo premuto il tasto sinistro del mouse[].\n[accent]Preleva un po' di rame dal Nucleo. [] -tutorial.deposit = Deposita tutti gli oggetti che trasporti trascinandoli dalla tua nave al blocco di destinazione. \n[accent]Rimetti il rame nel Nucleo. [] +tutorial.breaking = I blocchi spesso devono essere distrutti.\n[accent]Tieni premuto il tasto destro del mouse [] per distruggere tutti i blocchi in una selezione.[]\n[accent]Distruggi tutti i blocchi di scarto a sinistra del tuo Nucleo usando la selezione dell'area. +tutorial.breaking.mobile = I blocchi spesso devono essere distrutti.\n[accent]Seleziona la modalità di decostruzione[], quindi tocca un blocco per iniziare a smantellarlo.\nDistruggi un'area tenendo premuto il dito per alcuni secondi[] e trascinando in una direzione.\nPremi il pulsante con il segno di spunta per confermare la rimozione.\n\n[accent]Distruggi tutti i blocchi di scarto a sinistra del tuo Nucleo usando la selezione dell'area. +tutorial.withdraw = In alcune situazioni, è necessario prendere gli oggetti direttamente dai blocchi.\nPer fare ciò, [accent] tocca un blocco []con oggetti al suo interno, quindi [accent] tocca l'oggetto [] nell'inventario.\nPuoi prelevare più oggetti insieme[accent]tenendo premuto il tasto sinistro del mouse[].\n[accent]Preleva un po' di rame dal Nucleo. [] +tutorial.deposit = Deposita tutti gli oggetti che trasporti trascinandoli dalla tua nave al blocco di destinazione.\n[accent]Rimetti il rame nel Nucleo. [] tutorial.waves = Il nemico [LIGHT_GRAY] si avvicina.\nDifendi il tuo Nucleo per 2 ondate. Costruisci più torrette. Puoi sparare tenendo premuto il tasto sinistro del mouse. -tutorial.waves.mobile = Il [lightgray] nemico si avvicina.\n\n Difendi il Nucleo per 2 ondate. La tua nave sparerà automaticamente contro i nemici.\nCostruisci più torrette. -tutorial.launch = Una volta raggiunta un'ondata specifica, sarai in grado di [accent] decollare con il Nucleo [], lasciando la zona e abbandonando le tue difese e le tue strutture\nOtterrai [accent]tutte le risorse nel tuo Nucleo[] e potrai quindi usarle per ricercare nuove tecnologie.\n\n [accent]Decolla e conferma per terminare il tutorial. +tutorial.waves.mobile = Il [lightgray]nemico si avvicina.\n\nDifendi il Nucleo per 2 ondate. La tua nave sparerà automaticamente contro i nemici.\nCostruisci più torrette. +tutorial.launch = Una volta raggiunta un'ondata specifica, sarai in grado di [accent] decollare con il Nucleo [], lasciando la zona e abbandonando le tue difese e le tue strutture\nOtterrai [accent]tutte le risorse nel tuo Nucleo[] e potrai quindi usarle per ricercare nuove tecnologie.\n\n[accent]Decolla e conferma per terminare il tutorial. -item.copper.description = Un utile materiale, usato dappertutto -item.lead.description = Un materiale di base, molto usato nei blocchi di trasporto. -item.metaglass.description = Un durissimo composto di vetro. Estensivamente usato per trasporto di liquidi ed immagazzinamento. +item.copper.description = Un materiale utile, usato dappertutto. +item.lead.description = Un materiale di base, molto usato nei blocchi per il trasporto. +item.metaglass.description = Un durissimo composto di vetro. Ampiamente usato per trasporto di liquidi ed immagazzinamento. item.graphite.description = Carbone mineralizzato, utilizzato per munizioni ed isolamento elettrico. item.sand.description = Un materiale di base che viene usato molto nei processi di fusione, sia come lega che come reagente. item.coal.description = Un combustibile comune facilmente ottenibile. @@ -1079,7 +1084,7 @@ item.pyratite.description = Una sostanza molto infiammabile che viene utilizzata liquid.water.description = Il liquido più utile. Comunemente usato per il raffreddamento di macchinari ed il trattamento dei rifiuti. liquid.slag.description = Diversi tipi di metalli fusi, mescolati insieme. Può essere separato nei suoi minerali costituenti o spruzzato sulle unità nemiche come un'arma. liquid.oil.description = Un liquido usato nella produzione avanzata.\nPuò essere convertito in carbone per uso combustibile o spruzzato ed incendiato come arma. -liquid.cryofluid.description = Un liquido inerte e non corrosivo creato da acqua e titanio.\nIl liquido più efficiente per il raffreddamento. +liquid.cryofluid.description = Un liquido inerte e non corrosivo creato da acqua e titanio.\nÈ il liquido più efficiente per il raffreddamento. mech.alpha-mech.description = Il mech standard. È abbastanza veloce e produce abbastanza danni, può anche generare 3 droni per aumentare il suo danno complessivo. mech.delta-mech.description = Un mech veloce, poco armato fatto per giocare a tocca e fuga con il nemico. Fa poco danno alle strutture, ma può uccidere un gran nummero di nemici grazie alle sue armi ad alto voltaggio. mech.tau-mech.description = Un mech di supporto. Cura i blocchi danneggiati sparandogli contro. Può spegnere fuochi e curare i compagni di squadra. @@ -1099,7 +1104,7 @@ unit.eruptor.description = Un mech pesante progettato per abbattere le strutture unit.wraith.description = Un'unità d'intercezione rapida ed efficiente. unit.ghoul.description = Un bombardiere pesante. Utilizza composti esplosivi o pirite come munizioni. unit.revenant.description = Un pesante lanciamissili volante. -block.message.description = Stores a message. Used for communication between allies. +block.message.description = Memorizza un messaggio. Utilizzato per la comunicazione tra alleati. block.graphite-press.description = Comprime pezzi di carbone in fogli di grafite puri. block.multi-press.description = Una versione aggiornata della pressa per grafite. Impiega acqua ed energia per elaborare il carbone in modo rapido ed efficiente. block.silicon-smelter.description = Fonde sabbia e carbone riscaldati per ottenere silicio. @@ -1108,7 +1113,7 @@ block.plastanium-compressor.description = Produce plastanio da petrolio e titani block.phase-weaver.description = Produce tessuto di fase da torio radioattivo ed elevate quantità di sabbia. block.alloy-smelter.description = Produce leghe di sovratensione da titanio, piombo, silicio e rame. block.cryofluidmixer.description = Combina acqua e titanio in criofluido che è molto più efficiente per il raffreddamento. -block.blast-mixer.description = Frantuma e mescola le spore con la pirite per produrre Composto Esplosivo. +block.blast-mixer.description = Frantuma e mescola le spore con la pirite per produrre composto esplosivo. block.pyratite-mixer.description = Mescola carbone, piombo e sabbia in pirite altamente infiammabile. block.melter.description = Riscalda la pietra a temperature molto elevate per ottenere scoria liquida. block.separator.description = Sottopone le scoria a centrifugazione per ottenere i vari minerali contenuti. @@ -1122,23 +1127,23 @@ block.item-source.description = Produce oggetti infiniti, esiste solo nella moda block.item-void.description = Elimina gli oggetti che vi entrano senza bisogno di energia, esiste solo nella modalità creativa. block.liquid-source.description = Emette continuamente liquidi. Esiste solo nella modalità creativa. block.copper-wall.description = Un blocco difensivo economico.\nUtile per proteggere il Nucleo e le torrette nelle prime ondate. -block.copper-wall-large.description = Un blocco difensivo economico.\nUtile per proteggere il Nucleo e le torrette nelle prime ondate. \nOccupa più tessere. +block.copper-wall-large.description = Un blocco difensivo economico.\nUtile per proteggere il Nucleo e le torrette nelle prime ondate.\nOccupa più tessere. block.titanium-wall.description = Un blocco difensivo moderatamente forte.\nFornisce una protezione moderata dai nemici. -block.titanium-wall-large.description = Un blocco difensivo moderatamente forte.\nFornisce una protezione moderata dai nemici. \nOccupa più blocchi +block.titanium-wall-large.description = Un blocco difensivo moderatamente forte.\nFornisce una protezione moderata dai nemici.\nOccupa più tessere block.plastanium-wall.description = Un tipo speciale di muro che assorbe gli archi elettrici e blocca le connessioni automatiche del nodo d'energia. -block.plastanium-wall-large.description = Un tipo speciale di muro che assorbe gli archi elettrici e blocca le connessioni automatiche dei nodi d'energia.\nSi estende su più blocchi. +block.plastanium-wall-large.description = Un tipo speciale di muro che assorbe gli archi elettrici e blocca le connessioni automatiche dei nodi d'energia.\nSi estende su più tessere. block.thorium-wall.description = Un forte blocco difensivo.\nBuona protezione dai nemici. -block.thorium-wall-large.description = Un forte blocco difensivo.\nBuona protezione dai nemici.\nOccupa più blocchi +block.thorium-wall-large.description = Un forte blocco difensivo.\nBuona protezione dai nemici.\nOccupa più tessere. block.phase-wall.description = Non è forte come un muro di torio, ma devia i proiettili a meno che non siano troppo potenti. -block.phase-wall-large.description = Non è forte come un muro di torio, ma devia i proiettili a meno che non siano troppo potenti.\nOccupa più blocchi -block.surge-wall.description = Il blocco difensivo più forte. \nHa una piccola possibilità di innescare un fulmine verso l'attaccante. -block.surge-wall-large.description = Il blocco difensivo più forte. \n Ha una piccola possibilità di innescare un fulmine verso l'attaccante.\nOccupa più blocchi -block.door.description = Una piccola porta che può essere aperta e chiusa toccandola. \nSe aperta, i nemici possono sparare ed attraversare. -block.door-large.description = Una grande porta che può essere aperta e chiusa toccandola. \nSe aperta, i nemici possono sparare ed attraversare. \nOccupa più blocchi +block.phase-wall-large.description = Non è forte come un muro di torio, ma devia i proiettili a meno che non siano troppo potenti.\nOccupa più tessere. +block.surge-wall.description = Il blocco difensivo più forte.\nHa una piccola possibilità di innescare un fulmine verso l'attaccante. +block.surge-wall-large.description = Il blocco difensivo più forte.\nHa una piccola possibilità di innescare un fulmine verso l'attaccante.\nOccupa più tessere. +block.door.description = Una piccola porta che può essere aperta e chiusa toccandola.\nSe aperta, i nemici possono sparare ed attraversare. +block.door-large.description = Una grande porta che può essere aperta e chiusa toccandola.\nSe aperta, i nemici possono sparare ed attraversare.\nOccupa più tessere. block.mender.description = Ripara periodicamente blocchi nelle vicinanze.\nUtilizza del silicio per aumentarne portata ed efficienza. block.mend-projector.description = Ripara periodicamente blocchi nelle vicinanze.\nUtilizza del tessuto di fase per aumentarne portata ed efficienza. block.overdrive-projector.description = Aumenta la velocità di edifici vicini come trivelle e nastri trasportatori. -block.force-projector.description = Crea un campo di forza esagonale attorno a sé, proteggendo gli edifici e le unità all'interno da danni causati da proiettili +block.force-projector.description = Crea un campo di forza esagonale attorno a sé, proteggendo gli edifici e le unità all'interno da danni causati da proiettili. block.shock-mine.description = Danneggia i nemici che la calpestano. Quasi invisibile al nemico. block.conveyor.description = Nastro di base. Sposta gli oggetti in avanti e li deposita automaticamente in altri blocchi. Ruotabile. block.titanium-conveyor.description = Nastro avanzato. Sposta gli oggetti più velocemente dei nastri standard. @@ -1149,22 +1154,24 @@ block.sorter.description = Divide gli oggetti. Se l'oggetto corrisponde a quello block.inverted-sorter.description = Elabora gli oggetti come uno smistatore standard, ma in uscita dà gli elementi selezionati ai lati. block.router.description = Accetta gli elementi da una direzione e li emette fino a 3 altre direzioni allo stesso modo. Utile per suddividere i materiali da una fonte a più destinazioni. block.distributor.description = Un distributore avanzato che divide gli oggetti in altre 7 direzioni allo stesso modo. -block.overflow-gate.description = Una combinazione di un incrocio e di un distributore , che distribuisce sui suoi lati se in nastro difronte si satura. -block.mass-driver.description = Ultimo blocco di trasporto di oggetti. Raccoglie diversi oggetti e poi li spara su un'altra Lancia Materiali a lungo raggio. -block.mechanical-pump.description = Una pompa economica con potenza lenta, ma nessun consumo di energia. +block.overflow-gate.description = Una combinazione di un incrocio e di un distributore, che distribuisce sui suoi lati se in nastro difronte si satura. +block.mass-driver.description = Ultimo blocco di trasporto di oggetti. Raccoglie diversi oggetti e poi li spara su un'altra Lìlancia materiali a lungo raggio. +block.mechanical-pump.description = Una pompa economica a bassa efficienza, ma nessun consumo di energia. block.rotary-pump.description = Una pompa avanzata che raddoppia la velocità consumando energia. block.thermal-pump.description = La pompa migliore. Tre volte più veloce di una pompa meccanica e l'unica pompa in grado di recuperare la lava. block.conduit.description = Condotto di base. Funziona come un nastro trasportatore, ma per i liquidi. Ideale per estrattori, pompe o altri condotti. block.pulse-conduit.description = Condotto avanzato. Trasporta più liquido e più velocemente dei condotti standard. +block.plated-conduit.description = Trasferisce i liquidi alla stessa velocità del Condotto a Impulsi, ma è più resistente. Non accetta liquidi dai lati da parte di condotti diversi.\nMeno perdite. block.liquid-router.description = Accetta i liquidi da una direzione e li emette fino a 3 altre direzioni allo stesso modo. Può anche immagazzinare una certa quantità di liquido. Utile per suddividere i liquidi da una fonte verso più destinazioni. block.liquid-tank.description = Conserva una grande quantità di liquidi. Usalo per creare zone cuscinetto quando c'è una domanda non costante di materiali o come protezione per il raffreddamento di blocchi vitali. block.liquid-junction.description = Permette di incrociare condotti che trasportano liquidi diversi in posizioni diverse. block.bridge-conduit.description = Consente il trasporto di liquidi fino a 3 tessere da un altro condotto sopraelevato.\nPuò passare sopra ad altri blocchi od edifici. block.phase-conduit.description = Condotto avanzato. Consuma energia per teletrasportare i liquidi in un altro condotto di fase collegato. block.power-node.description = Trasmette energia tra i nodi collegati. È possibile creare fino a quattro collegamenti.\nClicca sul nodo per configurare i collegamenti. -block.power-node-large.description = Ha un raggio maggiore rispetto al nodo energetico e si possono creare un massimo di sei collegamenti.\nClicca sul nodo per configurare i collegamenti. +block.power-node-large.description = Ha un raggio maggiore rispetto al Nodo Energetico e si possono creare un massimo di sei collegamenti.\nClicca sul nodo per configurare i collegamenti. block.surge-tower.description = Un nodo di alimentazione a lungo raggio solo due connessioni disponibili.\nClicca sul nodo per configurare i collegamenti. -block.battery.description = Accumula energia ogni volta che c'è abbondanza e fornisce energia ogni volta che c'è carenza, purché rimanga carica. +block.diode.description = L'energia della batteria può attraversare questo blocco in una sola direzione, ma solo se l'altra parte ha meno energia. +block.battery.description = Accumula energia ogni volta che c'è abbondanza e fornisce energia ogni volta che c'è carenza, purché sia carica. block.battery-large.description = Immagazzina molta più energia di una normale batteria. block.combustion-generator.description = Genera energia bruciando combustibile. block.thermal-generator.description = Genera una grande quantità di energia dalla lava. @@ -1172,10 +1179,10 @@ block.turbine-generator.description = Più efficiente di un generatore a combust block.differential-generator.description = Genera grandi quantità di energia. Utilizza la differenza di temperatura tra criofluido e pirite in combustione. block.rtg-generator.description = Un generatore che sfrutta il calore del decadimento di materiale radioattivo per produrre energia.\nNon richiede raffreddamento ma fornisce meno energia di un reattore al torio. block.solar-panel.description = Fornisce una piccola quantità di energia dal sole. -block.solar-panel-large.description = Fornisce un'alimentazione molto migliore rispetto a un pannello solare standard, ma è anche molto più costoso da costruire. +block.solar-panel-large.description = Fornisce un'alimentazione migliore rispetto a un pannello solare standard, ma è anche molto più costoso da costruire. block.thorium-reactor.description = Genera enormi quantità di energia dal torio altamente radioattivo. Richiede un raffreddamento costante. Esploderà violentemente se vengono fornite quantità insufficienti di refrigerante. block.impact-reactor.description = Un generatore avanzato, in grado di creare enormi quantità di energia alla massima efficienza. Richiede un significativo apporto di energia per avviare il processo. -block.mechanical-drill.description = Una trivella economica. Se posizionato su riquadri appropriati, estrae minerali a un ritmo lento e costante. +block.mechanical-drill.description = Una trivella economica. Se posizionata su slot appropriati, estrae minerali a un ritmo lento e costante. block.pneumatic-drill.description = Una trivella migliorata più veloce ed in grado di elaborare materiali più duri sfruttando la pressione dell'aria. block.laser-drill.description = Consente di perforare ancora più velocemente attraverso la tecnologia laser, ma richiede energia. Inoltre, con questa trivella è possibile recuperare il torio radioattivo. block.blast-drill.description = La trivella migliore. Richiede grandi quantità di energia. @@ -1187,7 +1194,7 @@ block.core-foundation.description = La seconda versione del Nucleo. Meglio coraz block.core-nucleus.description = La terza ed ultima versione del Nucleo. Estremamente ben corazzato. Immagazzina enormi quantità di risorse. block.vault.description = Immagazzina una grande quantità di oggetti. Usalo per creare zone cuscinetto quando c'è una domanda non costante di materiali. Uno [LIGHT_GRAY]scaricatore[] può essere utilizzato per recuperare elementi dal deposito. block.container.description = Immagazzina una piccola quantità di oggetti. Usalo per creare zone cuscinetto quando c'è una domanda non costante di materiali. Uno [LIGHT_GRAY]scaricatore[] può essere utilizzato per recuperare elementi dal contenitore. -block.unloader.description = Scarica gli oggetti da un contenitore, caveau o Nucleo su un trasportatore o direttamente in un blocco adiacente. L'oggetto da scaricare può essere scelto toccando lo scaricatore. +block.unloader.description = Scarica gli oggetti da un contenitore, deposito o Nucleo su un nastro trasportatore o direttamente in un blocco adiacente. L'oggetto da scaricare può essere scelto toccando lo scaricatore. block.launch-pad.description = Lancia oggetti nel tuo Nucleo senza necessità di un lasciare la zona. block.launch-pad-large.description = Una versione migliore dell'Ascensore Spaziale, immagazzina più oggetti. Lancia oggetti più frequentemente. block.duo.description = Una torretta piccola ed economica. @@ -1204,7 +1211,7 @@ block.ripple.description = Una grande torretta di artiglieria che spara più col block.cyclone.description = Una grande torretta a fuoco rapido. block.spectre.description = Una grande torretta che spara due potenti proiettili contemporaneamente. block.meltdown.description = Una grande torretta che spara un potente laser a lungo raggio. -block.command-center.description = Da istruzioni alle unità alleate nella mappa. Comanda la ricongizione, l'attacco del Nucleo nemico o la ritirata verso il proprio Nucleo o fabbrica.\nQuando non è presente un Nucleo nemico, le unità pattuglieranno anche se viene ordinato un attacco. +block.command-center.description = Dà istruzioni alle unità alleate nella mappa. Comanda la ricongizione, l'attacco del Nucleo nemico o la ritirata verso il proprio Nucleo o fabbrica.\nQuando non è presente un Nucleo nemico, le unità pattuglieranno anche se viene ordinato un attacco. block.draug-factory.description = Produce droni per la raccolta mineraria. block.spirit-factory.description = Produce droni che riparano blocchi. block.phantom-factory.description = Produce droni avanzati che seguono il giocatore e lo assistono nella costruzione. @@ -1216,10 +1223,10 @@ block.crawler-factory.description = Produce unità di sciame veloci ed autodistr block.titan-factory.description = Produce unità terrestri avanzate e corazzate. block.fortress-factory.description = Produce unità di terra di artiglieria pesante. block.repair-point.description = Cura continuamente l'unità danneggiata più vicina. -block.dart-mech-pad.description = Trasforma la tua nave in un mech di attacco di base. \nUsa il blocco toccando due volte mentre ti trovi su di esso. -block.delta-mech-pad.description = Trasforma la tua nave in un mech veloce e leggermente corazzato, ideale per colpire e scappare. \nUsa il blocco toccando due volte mentre ti ci trovi sopra. -block.tau-mech-pad.description = Trasforma la tua nave in un mech di supporto in grado di curare edifici ed unità alleate. \n Usa il blocco toccando due volte mentre sei in piedi su di esso. -block.omega-mech-pad.description = Trasforma la tua nave in un mech voluminoso e ben corazzato, creato per gli assalti in prima linea. \nUsa il blocco toccando due volte mentre sei in piedi su di esso. +block.dart-mech-pad.description = Trasforma la tua nave in un mech di attacco di base.\nUsa il blocco toccando due volte mentre ti trovi su di esso. +block.delta-mech-pad.description = Trasforma la tua nave in un mech veloce e leggermente corazzato, ideale per colpire e scappare.\nUsa il blocco toccando due volte mentre ti trovi su di esso. +block.tau-mech-pad.description = Trasforma la tua nave in un mech di supporto in grado di curare edifici ed unità alleate.\nUsa il blocco toccando due volte mentre ti trovi su di esso. +block.omega-mech-pad.description = Trasforma la tua nave in un mech voluminoso e ben corazzato, creato per gli assalti in prima linea.\nUsa il blocco toccando due volte mentre ti trovi su di esso. block.javelin-ship-pad.description = Trasforma la tua nave in un intercettore forte e veloce con armi elettriche.\nUsa il blocco toccando due volte mentre ti trovi su di esso. -block.trident-ship-pad.description = Trasforma la tua nave in un bombardiere pesante e ben corazzato. \nUsa il blocco toccando due volte mentre ti trovi su di esso. -block.glaive-ship-pad.description = Trasforma la tua nave in una nave grande e ben corazzata. \nUsa il blocco toccando due volte mentre ti trovi su di esso. +block.trident-ship-pad.description = Trasforma la tua nave in un bombardiere pesante e ben corazzato.\nUsa il blocco toccando due volte mentre ti trovi su di esso. +block.glaive-ship-pad.description = Trasforma la tua nave in una nave grande e ben corazzata.\nUsa il blocco toccando due volte mentre ti trovi su di esso. From 2b46b0e38e8a69d979dd95570a2bcdc1b0eebca0 Mon Sep 17 00:00:00 2001 From: Predator127 <41844491+Predator127@users.noreply.github.com> Date: Sun, 29 Dec 2019 20:51:52 -0300 Subject: [PATCH 41/78] Update bundle_pt_BR.properties (#1253) * Update bundle_pt_BR.properties Hi there! my name is Zero! also known as Hanko, I've translated for a long time since then. I've been lookin through the new translations since i've been out for quite a long time, but dont think i forgot that i was a translator! * Update bundle_pt_BR.properties --- core/assets/bundles/bundle_pt_BR.properties | 46 ++++++++++----------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/core/assets/bundles/bundle_pt_BR.properties b/core/assets/bundles/bundle_pt_BR.properties index 28ead4e5ef..49d4681ea2 100644 --- a/core/assets/bundles/bundle_pt_BR.properties +++ b/core/assets/bundles/bundle_pt_BR.properties @@ -10,11 +10,11 @@ link.dev-builds.description = Desenvolvimentos instáveis link.trello.description = Trello oficial para atualizações planejadas link.itch.io.description = Página da Itch.io com os downloads link.google-play.description = Página da google play store -link.f-droid.description = F-Droid catalogue listing +link.f-droid.description = Listamento de catalogo do F-Droide link.wiki.description = Wiki oficial do Mindustry linkfail = Falha ao abrir o link\nO Url foi copiado para a área de transferência. screenshot = Screenshot salvo para {0} -screenshot.invalid = Mapa grande demais, Potencialmente sem memória suficiente para captura de tela. +screenshot.invalid = Mapa grande demais, Voce pode estar potencialmente sem memória suficiente para captura de tela. gameover = O núcleo foi destruído. gameover.pvp = O time[accent] {0}[] ganhou! highscore = [YELLOW]Novo recorde! @@ -42,8 +42,8 @@ schematic.shareworkshop = Compartilhar na Oficina schematic.flip = [accent][[{0}][]/[accent][[{1}][]: Virar o Esquema schematic.saved = Esquema salvo. schematic.delete.confirm = Esse Esquema será totalmente erradicado. -schematic.rename = Rename Schematic -schematic.info = {0}x{1}, {2} blocks +schematic.rename = Renomear esquema +schematic.info = {0}x{1}, {2} blocos stat.wave = Hordas derrotadas:[accent] {0} stat.enemiesDestroyed = Inimigos Destruídos:[accent] {0} @@ -279,11 +279,11 @@ workshop.error = Erro buscando os detalhes da Oficina: {0} map.publish.confirm = Você tem certeza de que quer publicar este mapa?\n\n[lightgray]Tenha certeza de que você concorda com o EULA da oficina primeiro, ou seus mapas não serão mostrados! workshop.menu = Selecione oquê você gostaria de fazer com esse Item. workshop.info = Informação do Item -changelog = Changelog (optional): +changelog = Mudanças (opcional): eula = EULA da Steam -missing = This item has been deleted or moved.\n[lightgray]The workshop listing has now been automatically un-linked. -publishing = [accent]Publishing... -publish.confirm = você tem certeza de que quer publicar isso?\n\n[lightgray]Primeiramente tenha certeza de que você concorda com o EULA da Oficina, ou seus itens não irão aparecer! +missing = Este item foi deletado ou movido.\n[lightgray]O listamento da oficina foi automaticamente des-ligado. +publishing = [accent]Publicando... +publish.confirm = Você tem certeza de que quer publicar isso?\n\n[lightgray]Primeiramente tenha certeza de que você concorda com o EULA da Oficina, ou seus itens não irão aparecer! publish.error = Erro publicando o Item: {0} steam.error = Falha em iniciar os serviços da Steam.\nError: {0} @@ -370,11 +370,11 @@ toolmode.replaceall = Substituir tudo toolmode.replaceall.description = Substituir todos os blocos no mapa toolmode.orthogonal = Linha reta toolmode.orthogonal.description = Desenha apenas linhas retas. -toolmode.square = Square +toolmode.square = Quadrado toolmode.square.description = Pincel quadrado. toolmode.eraseores = Apagar minérios toolmode.eraseores.description = Apaga apenas minérios. -toolmode.fillteams = Encher times +toolmode.fillteams = Preencher times toolmode.fillteams.description = Muda o time do qual todos os blocos pertencem. toolmode.drawteams = Desenhar times toolmode.drawteams.description = Muda o time do qual o bloco pertence. @@ -496,8 +496,8 @@ zone.tarFields.description = Nos arredores de uma zona de produção de petróle zone.desolateRift.description = Uma zona extremamente perigosa. Recursos abundantes, porém pouco espaço. Alto risco de destruição. Saia o mais rápido possível. Não seja enganado pelo longo espaço de tempo entre os ataques inimigos. zone.nuclearComplex.description = Uma antiga instalação para produção e processamento de tório, reduzido a ruínas.\n[lightgray]Pesquise o tório e seus muitos usos.\n\nO inimigo está presente aqui em grandes números, constantemente à procura de atacantes. zone.fungalPass.description = Uma area de transição entre montanhas altas e baixas, terras cheias de esporos. Uma pequena base de reconhecimento inimiga está localizada aqui.\nDestrua-a.\nUse as unidades crawler e dagger. Destrua os dois núcleos. -zone.impact0078.description = -zone.crags.description = +zone.impact0078.description = +zone.crags.description = settings.language = Idioma settings.data = Dados do jogo @@ -512,7 +512,7 @@ settings.cleardata = Apagar dados... settings.clear.confirm = Certeza que quer limpar a os dados?\nOque é feito não pode ser desfeito! settings.clearall.confirm = [scarlet]Aviso![]\nIsso vai limpar todo os arquivos, incluindo jogos salvos, mapas, teclas personalizadas e desbloqueados.\nQuando apertar 'ok' todos os arquivos serão apagados e o jogo irá sair automaticamente. paused = Pausado -clear = Clear +clear = Limpo banned = [scarlet]Banido yes = Sim no = Não @@ -521,7 +521,7 @@ error.title = [crimson]Ocorreu um Erro. error.crashtitle = Ocorreu um Erro blocks.input = Entrada blocks.output = Saída -blocks.booster = Booster +blocks.booster = Apoio block.unknown = [LIGHT_GRAY]??? blocks.powercapacity = Capacidade de Energia blocks.powershot = Energia/tiro @@ -659,7 +659,7 @@ setting.chatopacity.name = Opacidade do chat setting.lasersopacity.name = Opacidade do laser setting.playerchat.name = Mostrar chat em jogo public.confirm = Você quer fazer sua partida pública?\n[accent]Qualquer um será capaz de entrar na sua partida.\n[lightgray]Isso pode ser mudado depois em Configurações->Jogo->Visibilidade da partida pública. -public.beta = Note that beta versions of the game cannot make public lobbies. +public.beta = Note que as versões beta do jogo não podem fazer salas publicas. uiscale.reset = A escala da IU foi mudada.\nPressione "OK" para confirmar esta escala.\n[scarlet]Revertendo e saindo em[accent] {0}[] settings... uiscale.cancel = Cancelar e sair setting.bloom.name = Bloom @@ -727,10 +727,10 @@ keybind.zoom_minimap.name = Zoom do minimapa mode.help.title = Descrição dos modos mode.survival.name = Sobrevivência mode.survival.description = O modo normal. Recursos limitados e hordas automáticas. -mode.sandbox.name = Sandbox +mode.sandbox.name = Caixa de areia mode.sandbox.description = Recursos infinitos e sem tempo para ataques. mode.editor.name = Editor -mode.pvp.name = JXJ +mode.pvp.name = JxJ mode.pvp.description = Lutar contra outros jogadores locais. mode.attack.name = Ataque mode.attack.description = Sem hordas, com o objetivo de destruir a base inimiga. @@ -989,9 +989,9 @@ block.spirit-factory.name = Fábrica de drone de reparo Spirit block.phantom-factory.name = Fábrica de drone de construção Phantom block.wraith-factory.name = Fábrica de lutadores Wraith block.ghoul-factory.name = Fábrica de Bombardeiros Ghoul -block.dagger-factory.name = Fábrica de mech Dagger -block.crawler-factory.name = Fábrica de mech Crawler -block.titan-factory.name = Fábrica de mech titan +block.dagger-factory.name = Fábrica de Mecas Dagger +block.crawler-factory.name = Fábrica de Mecas Crawler +block.titan-factory.name = Fábrica de Mecas Titan block.fortress-factory.name = Fábrica de mech Fortress block.revenant-factory.name = Fábrica de lutadores Revenant block.repair-point.name = Ponto de Reparo @@ -1056,7 +1056,7 @@ tutorial.blockinfo = Cada bloco tem diferentes status. Cada broca pode extrair c tutorial.conveyor = [accent]Esteiras[] São usadas para transportar itens até o núcleo.\nFaça uma linha de Esteiras da mineradora até o núcleo. tutorial.conveyor.mobile = [accent]Esteiras[] são usadas para transportar itens até o núcleo.\nFaça uma linha de esteiras da broca até o núcleo.\n[accent] Coloque uma linha segurando por alguns segundos[] e arrastando em uma direção.\n\n[accent]{0}/{1} esteiras colocadas em linha\n[accent]0/1 itens entregues tutorial.turret = Estruturas defensivas devem ser construidas para repelir[LIGHT_GRAY] o inimigo[].\nConstrua uma torre dupla perto de sua base. -tutorial.drillturret = Torretas duplas precisam de[accent] cobre[] como munição para atirar.\nColoque uma broca próxima à torre para carregá-la com o cobre minerado. +tutorial.drillturret = Torres duplas precisam de[accent] cobre[] como munição para atirar.\nColoque uma broca próxima à torre para carregá-la com o cobre minerado. tutorial.pause = Durante uma batalha, você pode[accent] pausar o jogo.[]\nVocê pode enfileirar construções enquanto o jogo está pausado.\n\n[accent]Pressione a barra de espaço para pausar. tutorial.pause.mobile = Durante uma batalha, você pode[accent] pausar o jogo.[]\nVocê pode enfileirar construções enquanto o jogo está pausado.\n\n[accent]Pressione este botão no canto superior direito para pausar. tutorial.unpause = Agora pressione novamente a barra de espaço para despausar. @@ -1111,7 +1111,7 @@ unit.revenant.description = Uma matriz de mísseis pesada e flutuante. block.message.description = Armazena uma mensagem. Usado para comunicação entre aliados. block.graphite-press.description = Comprime pedaços de carvão em lâminas de grafite puro. block.multi-press.description = Uma versão melhorada da prensa de grafite. Usa água e energia para processar carvão rápida e eficientemente. -block.silicon-smelter.description = Reduz areia com carvão puro. Produz silício silicio. +block.silicon-smelter.description = Reduz areia a silicio usando carvão puro. Produz silício. block.kiln.description = Derrete chumbo e areia no composto conhecido como metavidro. Requer pequenas quantidades de energia. block.plastanium-compressor.description = Produz plastânio usando petróleo e titânio. block.phase-weaver.description = Produz tecido de fase usando tório radioativo e areia. Requer massivas quantidades de energia para funcionar. @@ -1185,7 +1185,7 @@ block.rtg-generator.description = Um Gerador termoelétrico de radioisótopos qu block.solar-panel.description = Gera pequenas quantidades de energia do sol. block.solar-panel-large.description = Uma versão significantemente mais eficiente que o painel solar padrão. block.thorium-reactor.description = Gera altas quantidades de energia do torio radioativo. Requer resfriamento constante. Vai explodir violentamente Se resfriamento insuficiente for fornecido. -block.impact-reactor.description = An advanced generator, capable of creating massive amounts of power at peak efficiency. Requires a significant power input to kickstart the process. +block.impact-reactor.description = Um gerador avançado, capaz de criar quantidades enormes de energia em seu poder total. Requer uma entrada significativa de energia ao iniciar. block.mechanical-drill.description = Uma broca barata. Quando colocado em blocos apropriados, retira itens em um ritmo lento e indefinitavamente. block.pneumatic-drill.description = Uma broca improvisada que é mais rápida e capaz de processar materiais mais duros usando a pressão do ar block.laser-drill.description = Possibilita a mineração ainda mais rapida usando tecnologia a laser, Mas requer poder adcionalmente torio radioativo pode ser recuperado com essa mineradora From ae5685ae46121539cec4bc513bb4e8e1e38e7458 Mon Sep 17 00:00:00 2001 From: Ali-C-Ila <56729449+Ali-C-Ila@users.noreply.github.com> Date: Mon, 30 Dec 2019 07:51:58 +0800 Subject: [PATCH 42/78] Update bundle_zh_TW.properties (#1263) * Update bundle_zh_TW.properties * Update bundle_zh_TW.properties * Update bundle_zh_TW.properties --- core/assets/bundles/bundle_zh_TW.properties | 33 +++++++++++---------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/core/assets/bundles/bundle_zh_TW.properties b/core/assets/bundles/bundle_zh_TW.properties index 1a50de946d..de6c8c12e1 100644 --- a/core/assets/bundles/bundle_zh_TW.properties +++ b/core/assets/bundles/bundle_zh_TW.properties @@ -89,6 +89,7 @@ uploadingpreviewfile = 上傳預覽文件 committingchanges = 提交變更 done = 完成 feature.unsupported = 您的設備不支持此功能。 + mods.alphainfo = 請記住,模組仍處於Alpha狀態,[scarlet]可能會有很多BUG[].\n向Mindustry GitHub或Discord報告發現的任何問題。 mods.alpha = [accent](Alpha) mods = 模組 @@ -98,7 +99,6 @@ mods.report = 回報錯誤 mods.openfolder = 開啟模組資料夾 mod.enabled = [lightgray]已啟用 mod.disabled = [scarlet]已禁用 -mod.enable = 啟用 mod.disable = 禁用 mod.delete.error = 無法刪除模組,檔案可能在使用中。 mod.requiresversion = [scarlet]最低遊戲版本要求:[accent]{0} @@ -107,6 +107,7 @@ mod.erroredcontent = [scarlet]內容錯誤 mod.errors = 載入內容時發生錯誤 mod.noerrorplay = [scarlet]你使用了有錯誤的模組。[] 遊戲前請先禁用相關模組或修正錯誤。 mod.nowdisabled = [scarlet]「{0}」模組缺少必須項目:[accent] {1}\n[lightgray]必須先下載這些模組。\n此模組將被自動禁用。 +mod.enable = 啟用 mod.requiresrestart = 遊戲將立即關閉以套用模組變更。 mod.reloadrequired = [scarlet]需要重新載入 mod.import = 匯入模組 @@ -286,6 +287,7 @@ publishing = [accent]發佈中... publish.confirm = 您確定要發布嗎?\n\n[lightgray]首先確定您同意Workshop EULA,否則您的項目將不會顯示! publish.error = 發佈項目時出錯: {0} steam.error = Steam 服務初始化失敗.\n錯誤: {0} + editor.brush = 粉刷 editor.openin = 在編輯器中開啟 editor.oregen = 礦石生成 @@ -605,7 +607,6 @@ category.items = 物品 category.crafting = 需求 category.shooting = 射擊 category.optional = 可選的強化 - setting.landscape.name = 鎖定水平畫面 setting.shadows.name = 陰影 setting.blockreplace.name = 方塊建造建議 @@ -671,6 +672,7 @@ category.multiplayer.name = 多人 command.attack = 攻擊 command.rally = 集結 command.retreat = 撤退 +placement.blockselectkeys = \n[lightgray]按鍵:[{0}, keybind.clear_building.name = 清除建築指令 keybind.press = 按一下按鍵... keybind.press.axis = 按一下軸向或按鍵... @@ -678,6 +680,8 @@ keybind.screenshot.name = 地圖截圖 keybind.toggle_power_lines.name = 顯示能量激光 keybind.move_x.name = 水平移動 keybind.move_y.name = 垂直移動 +keybind.mouse_move.name = 跟隨滑鼠 +keybind.dash.name = 衝刺 keybind.schematic_select.name = 選擇區域 keybind.schematic_menu.name = 藍圖目錄 keybind.schematic_flip_x.name = X軸翻轉 @@ -710,7 +714,6 @@ keybind.menu.name = 主選單 keybind.pause.name = 暫停遊戲 keybind.pause_building.name = 暫停/恢復建造 keybind.minimap.name = 小地圖 -keybind.dash.name = 衝刺 keybind.chat.name = 聊天 keybind.player_list.name = 玩家列表 keybind.console.name = 終端機 @@ -724,7 +727,7 @@ keybind.drop_unit.name = 放下單位 keybind.zoom_minimap.name = 縮放小地圖 mode.help.title = 模式說明 mode.survival.name = 生存 -mode.survival.description = 一般模式。有限的資源與自動來襲的波次。 +mode.survival.description = 一般模式。有限的資源與自動來襲的波次。\n[gray]地圖中需要敵人生成點。 mode.sandbox.name = 沙盒 mode.sandbox.description = 無限的資源與不倒數計時的波次。 mode.editor.name = 編輯 @@ -742,11 +745,11 @@ rules.attack = 攻擊模式 rules.enemyCheat = 電腦無限資源 rules.unitdrops = 單位掉落物 rules.unitbuildspeedmultiplier = 單位建設速度倍數 -rules.unithealthmultiplier = 單位耐久度倍數 -rules.playerhealthmultiplier = 玩家耐久度倍數 +rules.unithealthmultiplier = 單位生命值倍數 +rules.playerhealthmultiplier = 玩家生命值倍數 rules.playerdamagemultiplier = 玩家傷害倍數 rules.unitdamagemultiplier = 單位傷害倍數 -rules.enemycorebuildradius = 敵人核心無建設半徑︰[lightgray](格) +rules.enemycorebuildradius = 敵人核心禁止建設半徑︰[lightgray](格) rules.respawntime = 重生時間︰[lightgray](秒) rules.wavespacing = 波次間距︰[lightgray](秒) rules.buildcostmultiplier = 建設成本倍數 @@ -790,7 +793,6 @@ liquid.water.name = 水 liquid.slag.name = 熔渣 liquid.oil.name = 原油 liquid.cryofluid.name = 冷凍液 - mech.alpha-mech.name = 阿爾法 mech.alpha-mech.weapon = 重型機關槍 mech.alpha-mech.ability = 自修復 @@ -813,21 +815,22 @@ mech.trident-ship.weapon = 轟炸艙 mech.glaive-ship.name = 偃月刀 mech.glaive-ship.weapon = 火焰機關槍 item.corestorable = [lightgray]核心可儲存: {0} -item.explosiveness = [lightgray]爆炸性:{0} -item.flammability = [lightgray]易燃性:{0} -item.radioactivity = [lightgray]放射性:{0} -unit.health = [lightgray]耐久度:{0} +item.explosiveness = [lightgray]爆炸性:{0}% +item.flammability = [lightgray]易燃性:{0}% +item.radioactivity = [lightgray]放射性:{0}% +unit.health = [lightgray]生命值:{0} unit.speed = [lightgray]速度:{0} mech.weapon = [lightgray]武器:{0} mech.health = [lightgray]血量:{0} mech.itemcapacity = [lightgray]物品容量:{0} -mech.minespeed = [lightgray]採礦速度:{0} +mech.minespeed = [lightgray]採礦速度:{0}% mech.minepower = [lightgray]採礦能力:{0} mech.ability = [lightgray]能力:{0} mech.buildspeed = [lightgray]建造速度: {0}% liquid.heatcapacity = [lightgray]熱容量:{0} liquid.viscosity = [lightgray]粘性:{0} liquid.temperature = [lightgray]溫度:{0} + block.sand-boulder.name = 沙礫 block.grass.name = 草 block.salt.name = 鹽 @@ -1048,7 +1051,7 @@ unit.reaper.name = 收掠者 tutorial.next = [lightgray]<按下以繼續> tutorial.intro = 您已進入[scarlet] Mindustry 教學。[]\n使用[[WASD鍵]來移動.\n滾動滾輪來放大縮小畫面.\n從[accent]開採銅礦[]開始吧靠近它,然後在靠近核心的位置點擊銅礦。\n\n[accent]{0}/{1}銅礦 tutorial.intro.mobile = 您已進入[scarlet] Mindustry 教學。[]\n滑動螢幕即可移動。\n[accent]用兩指捏[]來縮放畫面。\n從[accent]開採銅礦[]開始吧。靠近它,然後在靠近核心的位置點擊銅礦。\n\n[accent]{0}/{1}銅礦 -tutorial.drill = 手動挖掘礦石的效率很低。\n[accent]鑽頭[]能夠自動挖掘礦石。\n在銅礦脈上放置一個鑽頭。 +tutorial.drill = 手動挖掘礦石的效率很低。\n[accent]鑽頭[]能夠自動挖掘礦石。\n在銅礦脈上放置一個鑽頭。\n不論在哪個選單,您也可以用快速按下按鍵[accent][[2][]然後[accent][[1][]來選擇鑽頭。\n[accent]滑鼠右擊[]停止建造。 tutorial.drill.mobile = 手動挖掘礦石的效率很低。\n[accent]鑽頭[]能夠自動挖掘礦石。\n點選右下角的鑽頭選項\n選擇[accent]機械鑽頭[].\n通過點擊將其放置在銅礦上,然後按下下方的[accent]確認標誌[]確認您的選擇\n按下[accent] X 按鈕[] 取消放置. tutorial.blockinfo = 每個方塊都有不同的屬性。每個鑽頭只能開採特定的礦石。\n查看方塊的資訊和屬性,[accent]在建造目錄時按下"?"鈕。[]\n\n[accent]立即訪問機械鑽頭的屬性資料。[] tutorial.conveyor = [accent]輸送帶[]能夠將物品運輸到核心。\n製作一條從鑽頭開始到核心的輸送帶。 @@ -1068,7 +1071,7 @@ tutorial.launch = 一旦您達到特定的波數, 您就可以[accent] 發射 item.copper.description = 最基本的結構材料。在各種類型的方塊中廣泛使用。 item.lead.description = 一種基本的起始材料。被廣泛用於電子設備和液體運輸方塊。 item.metaglass.description = 一種超高強度的玻璃。廣泛用於液體分配和存儲。 -item.graphite.description = 礦化的碳,用於彈藥和電氣絕緣。 +item.graphite.description = 礦化的碳,用於彈藥和電氣元件。 item.sand.description = 一種常見的材料,廣泛用於冶煉,包括製作合金和作為助熔劑。 item.coal.description = 遠在「播種」事件前就形成的植物化石。一種常見並容易獲得的燃料。 item.titanium.description = 一種罕見的超輕金屬,被廣泛運用於運輸液體、鑽頭和飛行載具。 From 9d2e3569960a3a771eeb45f501a93e36c3e96737 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Ga=C5=A1par=C3=ADk?= Date: Mon, 30 Dec 2019 00:52:06 +0100 Subject: [PATCH 43/78] Update bundle_cs.properties (#1267) Rewamping Czech translation. First part. --- core/assets/bundles/bundle_cs.properties | 350 ++++++++++++----------- 1 file changed, 183 insertions(+), 167 deletions(-) diff --git a/core/assets/bundles/bundle_cs.properties b/core/assets/bundles/bundle_cs.properties index 2160901318..1161de677c 100644 --- a/core/assets/bundles/bundle_cs.properties +++ b/core/assets/bundles/bundle_cs.properties @@ -1,241 +1,257 @@ credits.text = Vytvořil [ROYAL]Anuken[] - [SKY]anukendev@gmail.com[] -credits = Kredity -contributors = Překladatelé a Sponzoři -discord = Připoj se k Mindustry na Discordu! -link.discord.description = Oficiální Mindustry chatroom na Discordu! -link.reddit.description = The Mindustry subreddit +credits = Titulky +contributors = Překladatelé a sponzoři +discord = Připoj se k Mindustry na Discord serveru! +link.discord.description = Oficiální kanál Mindustry na serveru Discord +link.reddit.description = Mindustry na Redditu link.github.description = Zdrojový kód hry link.changelog.description = Seznam úprav -link.dev-builds.description = Nestabilní verze vývoje hry -link.trello.description = Oficiální Trello board pro plánované funkce -link.itch.io.description = itch.io stránka pro stažení PC nebo webové verze -link.google-play.description = Google Play store -link.wiki.description = Oficiální Mindustry wiki -linkfail = Nepodařilo se otevřít odkaz!\nURL byla zkopírována do schránky. +link.dev-builds.description = Nestabilní vývojová verze hry +link.trello.description = Oficiální nástěnka na Trello s plány rozvoje hry +link.itch.io.description = Stránka na itch.io s odkazy na stažení hry +link.google-play.description = Obchod Google Play +link.f-droid.description = Katalog F-Droid +link.wiki.description = Oficiální Wiki Mindustry +link.feathub.description = Navrhni něco nového do hry! +linkfail = Nepodařilo se otevřít odkaz!\nAdresa URL byla zkopírována do schránky. screenshot = Snímek obrazovky uložen {0} -screenshot.invalid = Mapa je moc velká, nemusí být dost paměti pro snímek obrazovky. +screenshot.invalid = Mapa je moc velká, nemusí být dost paměti pro získání snímku obrazovky. gameover = Konec hry -gameover.pvp = [accent] {0}[] Tým Vyhrál! +gameover.pvp = [accent]{0}[] tým vyhrál! highscore = [accent]Nový rekord! -copied = Copied. +copied = Zkopírováno. + load.sound = Zvuky load.map = Mapy load.image = Obrázky load.content = Obsah -load.system = System -load.mod = Módy -schematic = Schematic -schematic.add = Save Schematic... -schematics = Schematics -schematic.replace = A schematic by that name already exists. Replace it? -schematic.import = Import Schematic... -schematic.exportfile = Export File -schematic.importfile = Import File -schematic.browseworkshop = Browse Workshop -schematic.copy = Copy to Clipboard -schematic.copy.import = Import from Clipboard -schematic.shareworkshop = Share on Workshop -schematic.flip = [accent][[{0}][]/[accent][[{1}][]: Flip Schematic -schematic.saved = Schematic saved. -schematic.delete.confirm = This schematic will be utterly eradicated. -schematic.rename = Rename Schematic -schematic.info = {0}x{1}, {2} blocks -stat.wave = Vln poraženo:[accent] {0} -stat.enemiesDestroyed = Nepřátel zničeno:[accent] {0} -stat.built = Budov postaveno:[accent] {0} -stat.destroyed = Budov zničeno:[accent] {0} -stat.deconstructed = Budov rozebráno:[accent] {0} -stat.delivered = Materiálu odesláno: -stat.rank = Závěrečné hodnocení: [accent]{0} -launcheditems = [accent]Odeslané předměty -launchinfo = [unlaunched][[LAUNCH] your core to obtain the items indicated in blue. -map.delete = Jsi si jistý že chceš smazat mapu "[accent]{0}[]"? -level.highscore = Nejvyšší skóre: [accent]{0} -level.select = Výběr levelu +load.system = Systém +load.mod = Modifikace +load.scripts = Skripty + +schematic = Šablona +schematic.add = Uložit šablonu... +schematics = Šablony +schematic.replace = Šablona tohoto jména již exisruje. Přeješ si ji nahradit? +schematic.import = Importovat šablonu... +schematic.exportfile = Exportovat soubor +schematic.importfile = Importovat soubor +schematic.browseworkshop = Procházet dílnu +schematic.copy = Zkopírovat do schránky +schematic.copy.import = Importovat ze schránky +schematic.shareworkshop = Sdílet v dílně +schematic.flip = [accent][[{0}][]/[accent][[{1}][]: Obrátit šablonu +schematic.saved = Šablona byla uložena. +schematic.delete.confirm = Tato šablona bude beze zbytku smazána. +schematic.rename = Přejmenovat šablonu +schematic.info = {0}x{1}, {2} bloků + +stat.wave = Vln poraženo :[accent]{0} +stat.enemiesDestroyed = Nepřátel zničeno :[accent]{0}[] +stat.built = Budov postaveno: [accent]{0}[] +stat.destroyed = Budov zničeno: [accent]{0}[] +stat.deconstructed = Budov rozebráno: [accent]{0}[] +stat.delivered = Materiálu vysláno: +stat.rank = Závěrečné hodnocení: [accent]{0}[] + +launcheditems = [accent]Vyslané předměty[] +launchinfo = [unlaunched][Je třeba [LAUNCH] Tvé jádro, abys získal věci vyznačené modře. +map.delete = Jsi si jistý, že chceš smazat mapu "[accent]{0}[]"? +level.highscore = Nejvyšší skóre: [accent]{0}[] +level.select = Výběr úrovně level.mode = Herní mód: -showagain = Znovu neukazovat ! +showagain = Znovu neukazovat coreattack = < Jádro je pod útokem! > -nearpoint = [[ [scarlet]IHNED OPUSŤTE PROSTOR VÝSADKŮ[] ]\nNebezpečí okamžité smrti -database = Databáze objektů +nearpoint = [ [scarlet]IHNED OPUSŤTE PROSTOR VÝSADKU[] ]\nNebezpečí okamžité smrti! +database = Databáze objektů ve hře savegame = Uložit hru loadgame = Načíst hru joingame = Připojit se ke hře customgame = Vlastní hra newgame = Nová hra none = <žádný> -minimap = Minimapa -position = Position +minimap = Mapička +position = Pozice close = Zavřít -website = Web. stránky +website = Webové stránky quit = Ukončit save.quit = Uložit a ukončit maps = Mapy maps.browse = Procházet mapy continue = Pokračovat -maps.none = [LIGHT_GRAY]Žádné mapy nebyly nalezeny! +maps.none = [LIGHT_GRAY]Mapy nebyly nalezeny. invalid = Neplatné -preparingconfig = Připravuji Config -preparingcontent = Připravuji obsah -uploadingcontent = Nahrávám obsah -uploadingpreviewfile = Nahrávám prohlížecí soubor +pickcolor = Vyber barvu +preparingconfig = Připravuji konfiguraci +preparingcontent = Připravuji obsah hry +uploadingcontent = Nahrávám obsah hry +uploadingpreviewfile = Nahrávám soubor s náhledem committingchanges = Provádím změny done = Hotovo -feature.unsupported = Your device does not support this feature. -mods.alphainfo = Keep in mind that mods are in alpha, and[scarlet] may be very buggy[].\nReport any issues you find to the Mindustry GitHub or Discord. -mods.alpha = [accent](Alpha) -mods = Mods -mods.none = [LIGHT_GRAY]No mods found! -mods.guide = Modding Guide -mods.report = Report Bug -mods.openfolder = Open Mod Folder -mod.enabled = [lightgray]Enabled -mod.disabled = [scarlet]Disabled -mod.disable = Disable -mod.delete.error = Unable to delete mod. File may be in use. -mod.missingdependencies = [scarlet]Missing dependencies: {0} -mod.nowdisabled = [scarlet]Mod '{0}' is missing dependencies:[accent] {1}\n[lightgray]These mods need to be downloaded first.\nThis mod will be automatically disabled. -mod.enable = Enable -mod.requiresrestart = The game will now close to apply the mod changes. -mod.reloadrequired = [scarlet]Reload Required -mod.import = Import Mod -mod.import.github = Import GitHub Mod -mod.remove.confirm = This mod will be deleted. -mod.author = [LIGHT_GRAY]Author:[] {0} -mod.missing = This save contains mods that you have recently updated or no longer have installed. Save corruption may occur. Are you sure you want to load it?\n[lightgray]Mods:\n{0} -mod.preview.missing = Before publishing this mod in the workshop, you must add an image preview.\nPlace an image named[accent] preview.png[] into the mod's folder and try again. -mod.folder.missing = Only mods in folder form can be published on the workshop.\nTo convert any mod into a folder, simply unzip its file into a folder and delete the old zip, then restart your game or reload your mods. +feature.unsupported = Tvoje zařízení nepodporuje tuto vlastnost hry. + +mods.alphainfo = Měj na paměti, že modifikace jsou stále v alfa fázi vývoje a mohou být [scarlet]velmi chybové[].\nNahlaš, prosím, jakékoliv závady na GitHub nebo Discord serveru Mindustry. Děkujeme! +mods.alpha = [accent](Alfa)[] +mods = Modifikace +mods.none = [LIGHT_GRAY]Modifikace nebyly nalezeny.[] +mods.guide = Průvodce modifikacemi +mods.report = Nahlásit závadu +mods.openfolder = Otevřít složku s modifikacemi +mod.enabled = [lightgray]Povoleno[] +mod.disabled = [scarlet]Zakázáno[] +mod.disable = Zakázat +mod.delete.error = Nebylo možnost smazat modifikaci. Soubor může být používán. +mod.requiresversion = [scarlet]Minimální požadovaná verze hry:: [accent]{0}[] +mod.missingdependencies = [scarlet]Chybějící závislosti: {0} +mod.erroredcontent = [scarlet]Chyby v obsahu +mod.errors = Při načítání obsahu hry se vyskytly problémy. +mod.noerrorplay = [scarlet]Máš modifikace s chybami.[] Buď zakaž dotčené modifikace, nebo oprav chyby před tím, než začneš hrát. +mod.nowdisabled = [scarlet]Modifikaci '{0}' chybí tyto závislosti: [accent]{1}\n[lightgray]Tyto modifikace je třeba nejprve stáhnout.\nTato modifikace bude nyní automaticky zakázána. +mod.enable = Povolit +mod.requiresrestart = Hra bude ukončena, aby bylo možné nasadit modifikace. +mod.reloadrequired = [scarlet]Je vyžadováno znovuspuštění hry. +mod.import = Importovat modifikaci +mod.import.github = Import modifikaci z GitHubu +mod.item.remove = Tato položka je součástí [accent]'{0}'[] modifikace. Pokud ji chcete odstranit, odinstalujte tuto modifikaci. +mod.remove.confirm = Tato modifikace bude odstraněna. +mod.author = [LIGHT_GRAY]Autor:[] {0} +mod.missing = Toto uložení hra obsahuje modifikace, které byly nedávno aktualizovány, nebo již nejsou nainstalovány. Použití tohoto uložení může vést k chybám. Jsi si jist, že chceš nahrát toto uložení hry?\n[lightgray]Modifikace:\n{0} +mod.preview.missing = Než vystavíš svou modifikaci v dílně, musíš přidat obrázek pro náhled.\nUmísti obrázek pojmenovaný [accent]preview.png[] do složky modifikace a zkus to znovu. +mod.folder.missing = V dílně mohou být publikovány pouze modifikace ve formě složky.\nAbys převedl modifikaci na formu složky, jednoduše rozbal zip soubor do složky a smaž starý zip soubor. Potom znovu spusť hru nebo znovu načti modifikace. +mod.scripts.unsupported = Tvoje zařízení nepodporuje skripty. Některé modifikace nemusí správně fungovat. + about.button = O hře name = Jméno: -noname = Nejdřív si vyber[accent] herní jméno[]. -filename = Jméno složky: -unlocked = Nový blok odemčen! +noname = Nejdřív si vyber [accent]jméno ve hře[]. +filename = Název souboru: +unlocked = Byl odemmknut nový blok! completed = [accent]Dokončeno techtree = Technologie research.list = [LIGHT_GRAY]Výzkum: research = Výzkum -researched = [LIGHT_GRAY]{0} vyzkoumán(o). -players = {0} hráčů online -players.single = {0} hráč online -server.closing = [accent]Zavírám server... +researched = Výzkumu dokončeno: [LIGHT_GRAY]{0}[]. +players = Hráčů: {0} +players.single = Hráč: {0} +server.closing = [accent]Ukončuji server... server.kicked.kick = Byl jsi vykopnut ze serveru! -server.kicked.whitelist = Na server ti nebyl udělen přístup. -server.kicked.serverClose = Server je zavřený. -server.kicked.vote = Byl jsi odhlasován a vykopnut. Sbohem. -server.kicked.clientOutdated = Zastaralý klient hry! Aktualizuj si hru! -server.kicked.serverOutdated = Zastaralý server! Řekni hostiteli o aktualizaci! -server.kicked.banned = Jsi zabanován na tomto serveru. -server.kicked.typeMismatch = Tento server není kompatibilní s verzí tvého klienta -server.kicked.playerLimit = Tento server je plný, vyčkej na volné místo. -server.kicked.recentKick = Před nedávnem jsi byl vykopnut.\nPočkej než se znovu připojíš. -server.kicked.nameInUse = Někdo se stejným jménem\nje aktuálně na serveru. -server.kicked.nameEmpty = Tvé jméno je neplatné. -server.kicked.idInUse = Již jsi na tomhle serveru připojen! Připojování se dvěma účty není povoleno. -server.kicked.customClient = Tento server nepodporuje vlastní verze hry. Stáhni si oficiální verzi. +server.kicked.whitelist = Na server Ti nebyl udělen přístup. +server.kicked.serverClose = Server není otevřený. +server.kicked.vote = Bylo odhlasováno, že budeš vykopnut ze serveru. Tak čau. +server.kicked.clientOutdated = Byl detekována zastaralá verze klienta hry. Aktualizuj si hru! +server.kicked.serverOutdated = Byl detekována zastaralá verze serveru. Požádej hostitele o aktualizaci! +server.kicked.banned = Byl Ti zakázán přístup na tento server. +server.kicked.typeMismatch = Tento server není kompatibilní s verzí Tvého klienta. +server.kicked.playerLimit = Tento server je plný, vyčkej prosím, až se uvolní místo. +server.kicked.recentKick = Před nedávnem jsi byl vykopnut z tohoto serveru.\nPočkej proto chvíli, než se zkusíš znovu připojit. +server.kicked.nameInUse = Někdo se stejným jménem jako Ty\nje aktuálně přihlášen na serveru. +server.kicked.nameEmpty = Tvé jméno není platné. Možná je prostě jen není nastaveno? +server.kicked.idInUse = Na tomhle serveru jsi již připojen. Připojování se pod dvěma účty není dovoleno! +server.kicked.customClient = Tento server nepodporuje upravené verze hry. Stáhni si, prosím. oficiální verzi. server.kicked.gameover = Konec hry! -server.versions = Verze klienta:[accent] {0}[]\nVerze serveru:[accent] {1}[] -host.info = [accent]hostitel[] hostuje server na portu [scarlet]6567[]. \nKdokoliv na stejné [LIGHT_GRAY]wifi nebo místní síti[] by měl vidět server ve svém listu serverů.\n\nJestli chcete aby se uživatelé připojovali odkudkoliv pomocí IP, [accent]přesměrování portů[] je nutné.\n\n[LIGHT_GRAY]Poznámka: Jestli někdo má problém s připojením ke své LAN hře, ujistěte se že má Mindustry povolený přístup k místní síti v nastavení Firewallu. -join.info = Tady můžeš vložit [accent]IP serveru[] ke kterému se chceš připojit, nebo objevit [accent]Servery Místní sítě[] ke kterým se chceš připojit.\nLAN i Multiplayer jsou podporovány.\n\n[LIGHT_GRAY]Poznámka: Není žádný globální seznam serverů; Pokud se budeš chtít připojit k někomu pomocí IP, budeš jí muset znát od hostitele. -hostserver = Hostovat hru +server.versions = Verze klienta: [accent]{0}[]\nVerze serveru: [accent]{1}[] +host.info = Tento [accent]hostitel[] hostuje server na portu [scarlet]6567[]. \nKdokoliv na stejné [LIGHT_GRAY]síti Wifi nebo LAN (místní)[] by měl vidět server ve svém listu serverů.\n\nJestliže chcete, aby se uživatelé připojovali odkudkoliv pomocí adresy IP, může být nezbytné nastavit [accent]přesměrování portů[].\n\n[LIGHT_GRAY]Poznámka: Jestliže má někdo problém s připojením k LAN hře, ujisti se, že má program Mindustry povolený přístup k místní síti v nastavení místního firewallu. +join.info = Zde můžeš vložit [accent]adresu IP serveru[], ke kterému se chceš připojit, nebo zkusit nalézt [accent]servery v místní síti[], ke kterým se můžeš připojit.\nJsou podporovány režimy hry více hráčů přes LAN i WAN.\n\n[LIGHT_GRAY]Poznámka: Neexistuje automatický globální seznam serverů Mindustry. Pokud se chceš k někomu připojit pomocí adresy IP, budeš ji muset znát od hostitele. +hostserver = Hostovat hru více hráčů invitefriends = Pozvat přátele -hostserver.mobile = Hostovat\nHru +hostserver.mobile = Hostovat\nhru host = Hostitel hosting = [accent]Otevírám server... hosts.refresh = Obnovit -hosts.discovering = Hledám hry LAN +hosts.discovering = Hledám hry v místní síti (LAN) hosts.discovering.any = Hledám hry -server.refreshing = Obnovuji servery -hosts.none = [lightgray]Žádné místní hry nebyly nalezeny! -host.invalid = [scarlet]Nejde se připojit k hostiteli. +server.refreshing = Aktualizuji stav serverů +hosts.none = [lightgray]Žádné místní hry nebyly nalezeny![] +host.invalid = [scarlet]Nejde se připojit k hostiteli.[] trace = Vystopovat hráče -trace.playername = Jméno hráče: [accent]{0} -trace.ip = IP: [accent]{0} -trace.id = Unikátní ID: [accent]{0} -trace.mobile = Mobilní klient: [accent]{0} -trace.modclient = Vlastní Klient: [accent]{0} -invalidid = Neplatná IP klienta! Poslat zprávu o chybě. -server.bans = Bany. -server.bans.none = Žádní hráči s banem nebyli nalezeni. -server.admins = Admini -server.admins.none = Žádní admini nebyli nalezeni. +trace.playername = Jméno hráče: [accent]{0}[] +trace.ip = Adresa IP: [accent]{0}[] +trace.id = Unikátní ID: [accent]{0}[] +trace.mobile = Mobilní klient hry: [accent]{0}[] +trace.modclient = Upravený klient hry: [accent]{0}[] +invalidid = Neplatná adresa IP klienta! Zašli prosím zprávu o chybě. +server.bans = Zákazy +server.bans.none = Žádní hráči se zákazem nebyli nalezeni. +server.admins = Správci +server.admins.none = Žádní správci nebyli nalezeni. server.add = Přidat server -server.delete = Jsi si jistý že chceš smazat tento server? +server.delete = Jsi si jistý, že chceš smazat tento server? server.edit = Upravit server -server.outdated = [crimson]Zastaralý server![] -server.outdated.client = [crimson]Zastaralý klient![] -server.version = [lightgray]Verze: {0} {1} -server.custombuild = [yellow]Vlastní verze -confirmban = Jsi si jistý že chceš zabanovat tohoto hráče? -confirmkick = Jsi si jistý že chceš vykopnout tohoto hráče? -confirmvotekick = Jsi si jistý že chceš hlasovat pro vykopnutí tohoto hráče? -confirmunban = Jsi si jistý že chceš odbanovat tohoto hráče -confirmadmin = Jsi si jistý že chceš tohoto hráče pasovat na admina? -confirmunadmin = Jsi si jistý že chceš odebrat práva tomuto hráči? +server.outdated = [crimson]Zastaralá verze serveru![] +server.outdated.client = [crimson]Zastaralá verze klienta![] +server.version = [lightgray]Verze: {0} {1}[] +server.custombuild = [yellow]Upravená verze hry[] +confirmban = Jsi si jistý, že chceš zakázat tohoto hráče? +confirmkick = Jsi si jistý, že chceš vykopnout tohoto hráče? +confirmvotekick = Jsi si jistý, že chceš hlasovat pro vykopnutí tohoto hráče? +confirmunban = Jsi si jistý, že chceš zrušit zákaz pro tohoto hráče? +confirmadmin = Jsi si jistý, že chceš tohoto hráče povýšit na admina? +confirmunadmin = Jsi si jistý, že chceš odebrat správcovská práva tomuto hráči? joingame.title = Připojit se ke hře -joingame.ip = Adresa: -disconnect = Odpojen. +joingame.ip = Adresa IP: +disconnect = Odpojeno. disconnect.error = Chyba připojení. disconnect.closed = Připojení bylo uzavřeno. disconnect.timeout = Vypršel čas pro připojení. -disconnect.data = Chyba načtení dat světa! -cantconnect = Není možno připojit se ke hře ([accent]{0}[]). +disconnect.data = Chyba načtení dat ze serveru! +cantconnect = Není možno se připojit ke hře ([accent]{0}[]). connecting = [accent]Připojuji se... -connecting.data = [accent]Načítám data světa... +connecting.data = [accent]Načítám data ze serveru... server.port = Port: server.addressinuse = Adresu již někdo používá! server.invalidport = Neplatné číslo portu! -server.error = [crimson]Chyba při hostování serveru: [accent]{0} -save.new = Nové uložení -save.overwrite = Jsi si jistý že chceš přepsat\ntento ukládaci slot? +server.error = [crimson]Chyba při hostování serveru.[] +save.new = Nové uložení hry +save.overwrite = Jsi si jistý, že chceš přepsat\ntuto pozici pro uložení hry? overwrite = Přepsat -save.none = Žádné uložené pozice nebyly nalezeny -saveload = [accent]Ukládám... +save.none = Žádné uložené pozice nebyly nalezeny. +saveload = [accent]Ukládám...[] savefail = Nepodařilo se uložit hru! -save.delete.confirm = Jsi si jistý že chceš smazat toto uložení? +save.delete.confirm = Jsi si jistý, že chceš smazat toto uložení hry? save.delete = Smazat -save.export = Exportovat uložení -save.import.invalid = [accent]Toto uložení je neplatné! -save.import.fail = [crimson]Nepodařilo se importovat uložení: [accent]{0} -save.export.fail = [crimson]Nepodařilo se exportovat uložení: [accent]{0} -save.import = Importovat uložení +save.export = Exportovat uložení hry +save.import.invalid = [accent]Toto uložení není v pořádku![] +save.import.fail = [crimson]Nepodařilo se importovat uložení hry: [accent]{0}[] +save.export.fail = [crimson]Nepodařilo se exportovat uložení hry: [accent]{0}[] +save.import = Importovat uložení hry save.newslot = Uložit hru: save.rename = Přejmenovat save.rename.text = Nové jméno: -selectslot = Vyber uložení. -slot = [accent]Slot {0} +selectslot = Vyber pozici pro uložení hry. +slot = [accent]Pozice {0}[] editmessage = Upravit zprávu -save.corrupted = [accent]Uložení je poškozené nebo neplatné\nPokud jsi právě aktualizoval svou hru, je to možná změnou formátu pro ukládání a [scarlet]NE[] chyba hry. +save.corrupted = [accent]Uložení je poškozené nebo neplatné. empty = on = On off = Off save.autosave = Automatické uložení: {0} save.map = Mapa: {0} -save.wave = Vlna {0} +save.wave = Vlna: {0} save.mode = Herní mod: {0} save.date = Naposledy uloženo: {0} save.playtime = Herní čas: {0} warning = Varování. confirm = Potvrdit delete = Smazat -view.workshop = Prohlédnout ve workshopu -workshop.listing = Edit Workshop Listing +view.workshop = Prohlédnout v dílně +workshop.listing = Upravit popis v dílně ok = OK open = Otevřít -customize = Přizpůsobit +customize = Přizpůsobit pravidla cancel = Zrušit -openlink = Otevřít Odkaz -copylink = Zkopírovat Odkaz +openlink = Otevřít odkaz +copylink = Zkopírovat odkaz back = Zpět -data.export = Exportuj Data -data.import = Importuj Data +data.export = Exportuj data +data.import = Importuj data data.exported = Data exportována. -data.invalid = Neplatná herní data. -data.import.confirm = Import externích dat smaže[scarlet] všechna[] vaše současná herní data.\n[accent]To nelze vrátit zpět![]\n\nPo importu data se hra ukončí. -classic.export = Exportovat klasická data -classic.export.text = [accent]Mindustry[] právě mělo významně velkou aktualizaci.\nKlasické (v3.5 build 40) uložení nebo mapa byly detekovány. Chtěl by jsi exportovat toto uložení do domácího adresáře tvého zařízení , pro pozdější použití v klasické verzi Mindustry ? -quit.confirm = Jsi si jistý že chceš ukončit ? -quit.confirm.tutorial = Jste si vážně jist?\nTutoriál se dá znovu spustit v[accent] Nastavení->Hra->Spusť Tutoriál.[] +data.invalid = Herní data nejsou v pořádku. +data.import.confirm = Import externích dat smaže [scarlet]všechna[] Tvoje současná herní data.\n[accent]Toto nelze vrátit zpět![]\n\nPo importu dat se hra bezprostředně sama ukončí. +classic.export = Exportovat data pro verzi Classic +classic.export.text = [accent]Mindustry[] mělo významnou aktualizaci.\nByly detekovány uložení hry nebo mapy pro předchozí verzi Classic (v3.5 build 40). Chtěl bys exportovat tato uložení do domovského zařízení Tvého telefonu, pro pozdější použití v této verzi Mindustry Classic? +quit.confirm = Jsi si jistý, že chceš ukončit hru? +quit.confirm.tutorial = Jste si vážně jistý?\Výuka se dá znovu spustit v [accent]Nastavení->Hra->Spusť výuku[]. loading = [accent]Načítám... -reloading = [accent]načítám módy ... +reloading = [accent]Načítám modifikace... saving = [accent]Ukládám... cancelbuilding = [accent][[{0}][] to clear plan selectschematic = [accent][[{0}][] to select+copy @@ -642,9 +658,9 @@ keybind.screenshot.name = Sníměk mapy keybind.move_x.name = Pohyb na X keybind.move_y.name = Pohyb na Y keybind.schematic_select.name = Select Region -keybind.schematic_menu.name = Schematic Menu -keybind.schematic_flip_x.name = Flip Schematic X -keybind.schematic_flip_y.name = Flip Schematic Y +keybind.schematic_menu.name = Šablona Menu +keybind.schematic_flip_x.name = Flip Šablona X +keybind.schematic_flip_y.name = Flip Šablona Y keybind.fullscreen.name = Toggle Fullscreen keybind.select.name = Vybrat/Střílet keybind.diagonal_placement.name = Diagonal Placement @@ -1152,7 +1168,7 @@ block.phantom-factory.description = Produkuje pokročilé drony kteří jsou pod block.wraith-factory.description = Produkuje rychlé, udeř a uteč stíhače. block.ghoul-factory.description = Produkuje těžké kobercové bombardéry. block.revenant-factory.description = Produkuje vzdušné, težké laserové stíhače.. -block.dagger-factory.description = Produkuje standartní pozemní jednotky. +block.dagger-factory.description = Produkuje standardní pozemní jednotky. block.crawler-factory.description = Produces fast self-destructing swarm units. block.titan-factory.description = Produkuje pokročilé, orněné pozemní jednotky. block.fortress-factory.description = Produkuje těžké artilérní, pozmení jednotky. From 565064cd64a1eaf84b4e27699abc90d57ddae3ce Mon Sep 17 00:00:00 2001 From: FarmerThanos <59265546+FarmerThanos@users.noreply.github.com> Date: Mon, 30 Dec 2019 00:52:44 +0100 Subject: [PATCH 44/78] Updated bundle_pl.properties (#1273) * Updated bundle_pl.properties Corrected some translations, translated some options and added a description to the Battery Diode. * Update bundle_pl.properties Reverted some changes --- core/assets/bundles/bundle_pl.properties | 64 ++++++++++++------------ 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/core/assets/bundles/bundle_pl.properties b/core/assets/bundles/bundle_pl.properties index fd97dca25f..8c17577654 100644 --- a/core/assets/bundles/bundle_pl.properties +++ b/core/assets/bundles/bundle_pl.properties @@ -624,7 +624,7 @@ setting.difficulty.name = Poziom trudności setting.screenshake.name = Wstrząsy ekranu setting.effects.name = Wyświetlanie efektów setting.destroyedblocks.name = Wyświetl zniszczone bloki -setting.conveyorpathfinding.name = Conveyor Placement Pathfinding +setting.conveyorpathfinding.name = Znajdowanie Ścieżki Stawianych Taśmociągów setting.sensitivity.name = Czułość kontrolera setting.saveinterval.name = Interwał automatycznego zapisywania setting.seconds = {0} sekund @@ -633,7 +633,7 @@ setting.milliseconds = {0} millisekund setting.fullscreen.name = Pełny ekran setting.borderlesswindow.name = Bezramkowe okno[lightgray] (może wymagać restartu) setting.fps.name = Pokazuj FPS oraz ping -setting.blockselectkeys.name = Show Block Select Keys +setting.blockselectkeys.name = Pokazuj Klawisze Wyboru Bloków setting.vsync.name = Synchronizacja pionowa setting.pixelate.name = Pikselacja [lightgray](wyłącza animacje) setting.minimap.name = Pokaż Minimapę @@ -653,7 +653,7 @@ public.confirm = Czy chcesz ustawić swoją grę jako publiczną?\n[accent]Każd public.beta = Wersje beta gry nie mogą tworzyć publicznych pokoi. uiscale.reset = Skala interfejsu uległa zmianie.\nNaciśnij "OK" by potwierdzić zmiany.\n[scarlet]Cofanie zmian i wyjście z gry za[accent] {0}[] uiscale.cancel = Anuluj i Wyjdź -setting.bloom.name = Bloom +setting.bloom.name = Rozproszenie keybind.title = Zmień keybinds.mobile = [scarlet]Większość skrótów klawiszowych nie funkcjonuje w wersji mobilnej. Tylko podstawowe poruszanie się jest wspierane. category.general.name = Ogólne @@ -667,10 +667,10 @@ keybind.clear_building.name = Wyczyść budynek keybind.press = Naciśnij wybrany klawisz... keybind.press.axis = Naciśnij oś lub klawisz... keybind.screenshot.name = Zrzut ekranu mapy -keybind.toggle_power_lines.name = Toggle Power Lines +keybind.toggle_power_lines.name = Przełącz Linie Energetyczne keybind.move_x.name = Poruszanie w poziomie keybind.move_y.name = Poruszanie w pionie -keybind.mouse_move.name = Follow Mouse +keybind.mouse_move.name = Podążaj Za Myszką keybind.dash.name = Dash keybind.schematic_select.name = Wybierz region keybind.schematic_menu.name = Menu schematów @@ -678,20 +678,20 @@ keybind.schematic_flip_x.name = Obróć schemat horyzontalnie keybind.schematic_flip_y.name = Obróć schemat wertykalnie keybind.category_prev.name = Poprzednia kategoria keybind.category_next.name = Następna kategoria -keybind.block_select_left.name = Block Select Left -keybind.block_select_right.name = Block Select Right -keybind.block_select_up.name = Block Select Up -keybind.block_select_down.name = Block Select Down -keybind.block_select_01.name = Category/Block Select 1 -keybind.block_select_02.name = Category/Block Select 2 -keybind.block_select_03.name = Category/Block Select 3 -keybind.block_select_04.name = Category/Block Select 4 -keybind.block_select_05.name = Category/Block Select 5 -keybind.block_select_06.name = Category/Block Select 6 -keybind.block_select_07.name = Category/Block Select 7 -keybind.block_select_08.name = Category/Block Select 8 -keybind.block_select_09.name = Category/Block Select 9 -keybind.block_select_10.name = Category/Block Select 10 +keybind.block_select_left.name = Wybór Bloku Lewo +keybind.block_select_right.name = Wybór Bloku Prawo +keybind.block_select_up.name = Wybór Bloku Góra +keybind.block_select_down.name = Wybór Bloku Dół +keybind.block_select_01.name = Kategoria/Wybór Bloku 1 +keybind.block_select_02.name = Kategoria/Wybór Bloku 2 +keybind.block_select_03.name = Kategoria/Wybór Bloku 3 +keybind.block_select_04.name = Kategoria/Wybór Bloku 4 +keybind.block_select_05.name = Kategoria/Wybór Bloku 5 +keybind.block_select_06.name = Kategoria/Wybór Bloku 6 +keybind.block_select_07.name = Kategoria/Wybór Bloku 7 +keybind.block_select_08.name = Kategoria/Wybór Bloku 8 +keybind.block_select_09.name = Kategoria/Wybór Bloku 9 +keybind.block_select_10.name = Kategoria/Wybór Bloku 10 keybind.fullscreen.name = Przełącz Pełny Ekran keybind.select.name = Zaznacz keybind.diagonal_placement.name = Budowa po skosie @@ -708,7 +708,7 @@ keybind.chat.name = Czat keybind.player_list.name = Lista graczy keybind.console.name = Konsola keybind.rotate.name = Obracanie -keybind.rotateplaced.name = Rotate Existing (Hold) +keybind.rotateplaced.name = Obróć istniejące (Trzymaj) keybind.toggle_menus.name = Zmiana widoczności menu keybind.chat_history_prev.name = Przewiń wiadomości w górę keybind.chat_history_next.name = Przewiń wiadomości w dół @@ -908,11 +908,11 @@ block.scorch.name = Płomień block.scatter.name = Flak block.hail.name = Grad block.lancer.name = Lansjer -block.conveyor.name = Przenośnik -block.titanium-conveyor.name = Przenośnik Tytanowy -block.armored-conveyor.name = Przenośnik Opancerzony +block.conveyor.name = Taśmociąg +block.titanium-conveyor.name = Taśmociąg Tytanowy +block.armored-conveyor.name = Opancerzony Taśmociąg block.armored-conveyor.description = Przesyła przedmioty z taką samą szybkością jak Przenośnik Tytanowy, ale jest bardziej odporny. Wejściami bocznymi mogą być tylko inne przenośniki. -block.junction.name = Węzeł +block.junction.name = Skrzyżowanie block.router.name = Rozdzielacz block.distributor.name = Dystrybutor block.sorter.name = Sortownik @@ -930,8 +930,8 @@ block.incinerator.name = Spalacz block.spore-press.name = Prasa Zarodników block.separator.name = Rozdzielacz block.coal-centrifuge.name = Wirówka węglowa -block.power-node.name = Węzeł Prądu -block.power-node-large.name = Duży Węzeł Prądu +block.power-node.name = Węzeł Prądowy +block.power-node-large.name = Duży Węzeł Prądowy block.surge-tower.name = Wieża Energetyczna block.diode.name = Dioda baterii block.battery.name = Bateria @@ -958,8 +958,8 @@ block.item-source.name = Źródło przedmiotów block.item-void.name = Próżnia przedmiotów block.liquid-source.name = Źródło płynów block.power-void.name = Próżnia prądu -block.power-source.name = Nieskończony Prąd -block.unloader.name = Ekstraktor +block.power-source.name = Węzeł Nieskończonego Prądu +block.unloader.name = Wyładowywacz block.vault.name = Magazyn block.wave.name = Strumień block.swarmer.name = Działo Rojowe @@ -990,11 +990,11 @@ block.plated-conduit.name = Opancerzona rura block.phase-conduit.name = Rura Fazowa block.liquid-router.name = Rozdzielacz Płynów block.liquid-tank.name = Zbiornik Płynów -block.liquid-junction.name = Łącznik Płynów -block.bridge-conduit.name = Most Płynów +block.liquid-junction.name = Skrzyżowanie Rurowe +block.bridge-conduit.name = Most Rurowy block.rotary-pump.name = Wirowa Pompa block.thorium-reactor.name = Reaktor Torowy -block.mass-driver.name = Katapulta Masy +block.mass-driver.name = Katapulta Masowa block.blast-drill.name = Wiertło Wybuchowe block.thermal-pump.name = Pompa Termalna block.thermal-generator.name = Generator Termalny @@ -1164,7 +1164,7 @@ block.phase-conduit.description = Zaawansowany blok do przenoszenia cieczy. Uży block.power-node.description = Przesyła moc do połączonych węzłów. Można podłączyć do czterech źródeł zasilania, zlewów lub węzłów. Zasila też bloki które go dotykają. block.power-node-large.description = Posiada większy zasięg niż zwykły węzeł prądu. Można podłączyć do sześciu źródeł zasilania, zlewów lub węzłów. block.surge-tower.description = Węzęł prądu z bardzo dużym zasięgiem, posiadający mniej możliwych podłączeń. -block.diode.description = Battery power can flow through this block in only one direction, but only if the other side has less power stored. +block.diode.description = Prąd baterii może tylko przepłynąc przez ten blok w jedną strone, jeśli druga strona ma mniej prądu. block.battery.description = Przechowuje energię przy nadwyżce produkcji oraz dostarcza energię kiedy jest jej brak, dopóki jest w niej miejsce. block.battery-large.description = Przechowuje o wiele wiecej prądu niż standardowa bateria. block.combustion-generator.description = Wytwarza energię poprzez spalanie łatwopalnych materiałów. From ec59b0436324c56f41ab5feb5d8275834e359988 Mon Sep 17 00:00:00 2001 From: Wina <58987087+ActualWina@users.noreply.github.com> Date: Sun, 29 Dec 2019 20:55:51 -0300 Subject: [PATCH 45/78] Full SPA translation for Steam (Achievements included) (#1229) * Full description translated * Create achievements.vdf * Create short-description.txt --- .../metadata/steam/spanish/achievements.vdf | 109 ++++++++++++++++++ .../metadata/steam/spanish/description.txt | 61 ++++++++++ .../steam/spanish/short-description.txt | 1 + 3 files changed, 171 insertions(+) create mode 100644 fastlane/metadata/steam/spanish/achievements.vdf create mode 100644 fastlane/metadata/steam/spanish/description.txt create mode 100644 fastlane/metadata/steam/spanish/short-description.txt diff --git a/fastlane/metadata/steam/spanish/achievements.vdf b/fastlane/metadata/steam/spanish/achievements.vdf new file mode 100644 index 0000000000..fb67d82c9d --- /dev/null +++ b/fastlane/metadata/steam/spanish/achievements.vdf @@ -0,0 +1,109 @@ +"lang" +{ + "Language" "spanish" + "Tokens" + { + "NEW_ACHIEVEMENT_20_0_NAME" "Verificado" + "NEW_ACHIEVEMENT_20_0_DESC" "Completa el tutorial." + "NEW_ACHIEVEMENT_20_1_NAME" "Scrapper" + "NEW_ACHIEVEMENT_20_1_DESC" "Destruye 1,000 unidades enemigas." + "NEW_ACHIEVEMENT_20_2_NAME" "Purga" + "NEW_ACHIEVEMENT_20_2_DESC" "Destruye 100,000 unidades enemigas." + "NEW_ACHIEVEMENT_20_3_NAME" "Transporte Atmosférico" + "NEW_ACHIEVEMENT_20_3_DESC" "Lanza 10,000 items en total." + "NEW_ACHIEVEMENT_20_5_NAME" "Envíos Sin Fin" + "NEW_ACHIEVEMENT_20_5_DESC" "Lanza un total de 1,000,000 ítems." + "NEW_ACHIEVEMENT_20_6_NAME" "Conquistador" + "NEW_ACHIEVEMENT_20_6_DESC" "Gana 10 partidas en modo Invasión" + "NEW_ACHIEVEMENT_20_7_NAME" "Campeón" + "NEW_ACHIEVEMENT_20_7_DESC" "Gana 10 partidas PvP Multijugador." + "NEW_ACHIEVEMENT_20_8_NAME" "Rápido" + "NEW_ACHIEVEMENT_20_8_DESC" "Destruye el núcleo enemigo en 5 oleadas o menos." + "NEW_ACHIEVEMENT_20_9_NAME" "Lluvia de núcleos" + "NEW_ACHIEVEMENT_20_9_DESC" "Lanza tu núcleo a una zona 30 veces." + "NEW_ACHIEVEMENT_20_10_NAME" "Tenaz" + "NEW_ACHIEVEMENT_20_10_DESC" "Sobrevive 100 oleadas." + "NEW_ACHIEVEMENT_20_11_NAME" "Unvanquished" + "NEW_ACHIEVEMENT_20_11_DESC" "Sobrevive 500 oleadas." + "NEW_ACHIEVEMENT_20_12_NAME" "Investigador" + "NEW_ACHIEVEMENT_20_12_DESC" "Investiga todo el árbol de tecnologías." + "NEW_ACHIEVEMENT_20_13_NAME" "Cambiaformas" + "NEW_ACHIEVEMENT_20_13_DESC" "Desbloquea y transformate en todos los mecanoides del juego." + "NEW_ACHIEVEMENT_20_14_NAME" "Sobrecarga" + "NEW_ACHIEVEMENT_20_14_DESC" "Ataca a un enemigo con electricidad mientras este recibe agua." + "NEW_ACHIEVEMENT_20_15_NAME" "Desviación" + "NEW_ACHIEVEMENT_20_15_DESC" "Destruye una unidad haciendo rebotar su propia bala." + "NEW_ACHIEVEMENT_20_17_NAME" "Un grave, grave error" + "NEW_ACHIEVEMENT_20_17_DESC" "Investiga el enrutador." + "NEW_ACHIEVEMENT_20_18_NAME" "Creador" + "NEW_ACHIEVEMENT_20_18_DESC" "Coloca 10,000 bloques." + "NEW_ACHIEVEMENT_20_19_NAME" "Raze" + "NEW_ACHIEVEMENT_20_19_DESC" "Destruye 1,000 bloques enemigos." + "NEW_ACHIEVEMENT_20_20_NAME" "Un desastre espectacular" + "NEW_ACHIEVEMENT_20_20_DESC" "Causa que un reactor de torio se sobre caliente y explote." + "NEW_ACHIEVEMENT_20_21_NAME" "Mapper" + "NEW_ACHIEVEMENT_20_21_DESC" "Crea un nuevo mapa 10 veces." + "NEW_ACHIEVEMENT_20_22_NAME" "Buscador" + "NEW_ACHIEVEMENT_20_22_DESC" "Descarga un mapa de la Workshop." + "NEW_ACHIEVEMENT_20_23_NAME" "Creador" + "NEW_ACHIEVEMENT_20_23_DESC" "Publca un mapa en la Workshop." + "NEW_ACHIEVEMENT_20_24_NAME" "Slayer" + "NEW_ACHIEVEMENT_20_24_DESC" "Derrota un boss." + "NEW_ACHIEVEMENT_20_25_NAME" "Explorador" + "NEW_ACHIEVEMENT_20_25_DESC" "Desbloquea todas las zonas de la campaña." + "NEW_ACHIEVEMENT_20_26_NAME" "Minucioso" + "NEW_ACHIEVEMENT_20_26_DESC" "Alcanza el requisito de configuración en todas las zonas." + "NEW_ACHIEVEMENT_20_29_NAME" "Material II" + "NEW_ACHIEVEMENT_20_29_DESC" "Desbloquea el Torio." + "NEW_ACHIEVEMENT_20_31_NAME" "Material I" + "NEW_ACHIEVEMENT_20_31_DESC" "Desbloquea el Titanio." + "NEW_ACHIEVEMENT_21_0_NAME" "Kamikaze" + "NEW_ACHIEVEMENT_21_0_DESC" "LLena tu mecanoide de explosivos y muere, creando una explosión." + "NEW_ACHIEVEMENT_21_1_NAME" "Así comienza" + "NEW_ACHIEVEMENT_21_1_DESC" "Construye una fábrica de drones Daga." + "NEW_ACHIEVEMENT_21_2_NAME" "Asalto Directo" + "NEW_ACHIEVEMENT_21_2_DESC" "Utiliza el comando ataque desde el centro de comando." + "NEW_ACHIEVEMENT_21_3_NAME" "Swarm" + "NEW_ACHIEVEMENT_21_3_DESC" "Consigue 100 unidades activas al mismo tiempo." + "NEW_ACHIEVEMENT_21_4_NAME" "Flock" + "NEW_ACHIEVEMENT_21_4_DESC" "Consigue 10 drones fantasmales activos al mismo tiempo." + "NEW_ACHIEVEMENT_21_5_NAME" "Ejército volátil" + "NEW_ACHIEVEMENT_21_5_DESC" "Consigue 50 Crawlers activos al mismo tiempo." + "NEW_ACHIEVEMENT_21_6_NAME" "Legiones" + "NEW_ACHIEVEMENT_21_6_DESC" "Construye 1,000 unidades en total." + "NEW_ACHIEVEMENT_21_7_NAME" "Super" + "NEW_ACHIEVEMENT_21_7_DESC" "Consigue el rango S en cualquier zona." + "NEW_ACHIEVEMENT_21_8_NAME" "Super Super" + "NEW_ACHIEVEMENT_21_8_DESC" "Consigue el rango SS en cualquier zona." + "NEW_ACHIEVEMENT_21_9_NAME" "Deberías haber hecho caso" + "NEW_ACHIEVEMENT_21_9_DESC" "Muere en la zona del punto de exclusión." + "NEW_ACHIEVEMENT_21_10_NAME" "Solo aprieta Shift" + "NEW_ACHIEVEMENT_21_10_DESC" "Muere ahogado, como sea." + "NEW_ACHIEVEMENT_21_11_NAME" "Coleccionista" + "NEW_ACHIEVEMENT_21_11_DESC" "Llena el núcleo con la máxima cantidad de todos los recursos." + "NEW_ACHIEVEMENT_21_12_NAME" "10 son multitud" + "NEW_ACHIEVEMENT_21_12_DESC" "Hostea un servidor con 10 jugadores." + "NEW_ACHIEVEMENT_21_13_NAME" "Invencible" + "NEW_ACHIEVEMENT_21_13_DESC" "Construye el Meltdown y el Espectro." + "NEW_ACHIEVEMENT_21_14_NAME" "Liftoff" + "NEW_ACHIEVEMENT_21_14_DESC" "Use the Launch Pad." + "NEW_ACHIEVEMENT_21_15_NAME" "Complacencia" + "NEW_ACHIEVEMENT_21_15_DESC" "Saltea lanzar dos veces, luego deja que los enemigos destruyan tu núcleo." + "NEW_ACHIEVEMENT_21_16_NAME" "Herejía" + "NEW_ACHIEVEMENT_21_16_DESC" "Construye dos enrutadores, uno al lado del otro." + "NEW_ACHIEVEMENT_21_17_NAME" "Guardián solitario" + "NEW_ACHIEVEMENT_21_17_DESC" "Sobrevive 10 oleadas sin colocar ni un solo bloque." + "NEW_ACHIEVEMENT_21_18_NAME" "Incinerador" + "NEW_ACHIEVEMENT_21_18_DESC" "Usa pirotita para cargar una torreta." + "NEW_ACHIEVEMENT_21_19_NAME" "Eficiente" + "NEW_ACHIEVEMENT_21_19_DESC" "Refrigera una torreta con líquido criogénico." + "NEW_ACHIEVEMENT_21_20_NAME" "Modo Clásico" + "NEW_ACHIEVEMENT_21_20_DESC" "Activa el modo pixelado." + "NEW_ACHIEVEMENT_21_21_NAME" "Estudiante" + "NEW_ACHIEVEMENT_21_21_DESC" "Abre la wiki desde el juego." + "NEW_ACHIEVEMENT_21_22_NAME" "Comienzo a lo grande" + "NEW_ACHIEVEMENT_21_22_DESC" "Lanzate a una zona con mas de 10.000 recursos configurados." + "NEW_ACHIEVEMENT_21_23_NAME" "Ignición" + "NEW_ACHIEVEMENT_21_23_DESC" "Alimenta con energía un generador de impacto." + } +} diff --git a/fastlane/metadata/steam/spanish/description.txt b/fastlane/metadata/steam/spanish/description.txt new file mode 100644 index 0000000000..979f2ad430 --- /dev/null +++ b/fastlane/metadata/steam/spanish/description.txt @@ -0,0 +1,61 @@ +Crea elaboradas cadenas de suministros para cargar tus torretas, produce materiales para crear estructuras y defiendelas de oleadas de enemigos. Juega con tus amigos en un multijugador cooperativo multiplataforma, o pelea contra ellos en batallas PvP por equipos. + +[img]{STEAM_APP_IMAGE}/extras/ezgif-4-0e70c282f775.gif[/img] + +[h2]Gameplay[/h2] + +[list] +[*] Crea taladros y cintas transportadoras para enviar recursos a tu núcleo +[*] Usa bloques de producción para crear materiales avanzados +[*] Construye drones para minar recursos automaticamente, construir y defender tu base de forma eficiente +[*] Distribuye liquidos y apaga posibles incendios +[*] Potencia la producción refrigerando y lubricando tus defensas y bloques de construcción +[/list] + +[h2]Campaña[/h2] + +[list] +[*] Avanza a través de 12 zonas completamente rejugables con puntos de aparición randomizados +[*] Obtén y lanza recursos para investigar nuevas tecnologías +[*] Investiga nuevos bloques para facilitar tu progreso +[*] Configura los recursos iniciales de cada área a tus necesidades +[*] Gran variedad de misiones y objetivos +[*] Juega con tus amigos y completa niveles con ellos +[*] Mas de 120 bloques por investigar y descubrir +[*] 19 tipos de drones, mecanoides y naves +[*] Mas de 50 logros para completar +[/list] + +[h2][h2]Modos de juego[/h2][/h2] + +[list] +[*] [b]Supervivencia[/b]: Construye torretas para defenderte de tus enemigos con un estilo de Tower Defense. Sobrevive tanto como puedas, lanzando tu núcleo (opcionalmente) para utilizar los recursos con propósitos de investigación. Prepara tu base para el ataque de intermitentes bosses áereos. +[*] [b]Invasión[/b]: Construye fábricas de unidades para destruir el núcleo enemigo, mientras resistes oleadas periódicamente. Utiliza distintos tipos de unidades de ataque y soporte para ayudarte en la conquista. +[*] [b]PvP[/b]: Compite contra otros jugadores en hasta 4 equipos diferentes para destruir el núcleo de los demás. Crea unidades o ataca directamente con mecanoides la base de tus enemigos. +[*] [b]Sandbox[/b]: Juega libremente con recursos infinitos y sin enemigos molestando. Usa bloques exclusivos de sandbox para facilitar la prueba de diseños. Crea oleadas a gusto. +[/list] + +[h2]Partidas personalizadas y multijugador multiplataforma[/h2] + +[list] +[*] 12 mapas integrados para partidas personalizadas, además de los de la campaña +[*] Juega en cooperativo, Sandbox o PvP +[*] Únete a un servidor dedicado, o invita amigos a tu partida privada +[*] Reglas personalizadas: Cambia costos y tiempos de tus estructuras. Regula la fuerza de tus enemigos y cada cuanto aparecen, entre otras opciones +[*] Modos de juego combinados: Juega PvP y PvE al mismo tiempo +[/list] + +[h2]Editor de mapas[/h2] + +[list] +[*] Dibuja terreno con una interfaz completa de editor +[*] Edita y visualiza estructuras in-game +[*] Configura los modos de las herramientas +[*] Poderoso algoritmo de generacion, aplica filtros de terreno. +[*] Aplica distorsión, simetria, suavidad, generación de terreno y más a tus mapas +[*] Randomiza la generacion de ores y terreno, para que cada partida sea distinta +[*] Configura las oleadas a tu gusto +[*] Comparte mapas en la Steam Workshop +[*] Personaliza las reglas de los mapas +[*] Usa mas de 75 bloques ambientales, para darle un estilo único a tus mapas +[/list] diff --git a/fastlane/metadata/steam/spanish/short-description.txt b/fastlane/metadata/steam/spanish/short-description.txt new file mode 100644 index 0000000000..0966131f11 --- /dev/null +++ b/fastlane/metadata/steam/spanish/short-description.txt @@ -0,0 +1 @@ +Un Tower Defense abierto centrado en la gestión de recursos. From 39db62e3a5dab87adecc7593a1cf811509874896 Mon Sep 17 00:00:00 2001 From: Anuken Date: Sun, 29 Dec 2019 18:56:29 -0500 Subject: [PATCH 46/78] Minimap tweaks --- core/src/mindustry/core/Control.java | 2 +- core/src/mindustry/ui/fragments/MinimapFragment.java | 8 +++----- gradle/wrapper/gradle-wrapper.properties | 2 +- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/core/src/mindustry/core/Control.java b/core/src/mindustry/core/Control.java index 458cb313ae..7c86601bb3 100644 --- a/core/src/mindustry/core/Control.java +++ b/core/src/mindustry/core/Control.java @@ -456,7 +456,7 @@ public class Control implements ApplicationListener, Loadable{ state.set(state.is(State.playing) ? State.paused : State.playing); } - if(Core.input.keyTap(Binding.menu) && !ui.restart.isShown()){ + if(Core.input.keyTap(Binding.menu) && !ui.restart.isShown() && !ui.minimapfrag.shown()){ if(ui.chatfrag.shown()){ ui.chatfrag.hide(); }else if(!ui.paused.isShown() && !scene.hasDialog()){ diff --git a/core/src/mindustry/ui/fragments/MinimapFragment.java b/core/src/mindustry/ui/fragments/MinimapFragment.java index 4a938b341a..7e93832cb4 100644 --- a/core/src/mindustry/ui/fragments/MinimapFragment.java +++ b/core/src/mindustry/ui/fragments/MinimapFragment.java @@ -9,6 +9,7 @@ import arc.scene.*; import arc.scene.event.*; import arc.scene.ui.layout.*; import mindustry.gen.*; +import mindustry.input.*; import mindustry.ui.*; import static mindustry.Vars.*; @@ -46,7 +47,7 @@ public class MinimapFragment extends Fragment{ elem.setFillParent(true); elem.setBounds(0, 0, Core.graphics.getWidth(), Core.graphics.getHeight()); - if(Core.input.keyTap(KeyCode.ESCAPE) || Core.input.keyTap(KeyCode.BACK)){ + if(Core.input.keyTap(Binding.menu)){ shown = false; } }); @@ -98,10 +99,7 @@ public class MinimapFragment extends Fragment{ t.row(); t.add().growY(); t.row(); - - if(mobile){ - t.addImageTextButton("$back", Icon.backSmall, () -> shown = false).size(220f, 60f).pad(12f); - } + t.addImageTextButton("$back", Icon.backSmall, () -> shown = false).size(220f, 60f).pad(10f); }); } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 6ce793f21e..5028f28f8e 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.0-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.4-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists From 689b0b8c6101f9b0933cfdbcfab8da43a222f81e Mon Sep 17 00:00:00 2001 From: Anuken Date: Sun, 29 Dec 2019 20:04:08 -0500 Subject: [PATCH 47/78] Fixed games never ending --- core/src/mindustry/core/Logic.java | 2 +- fastlane/metadata/android/en-US/changelogs/102.1.txt | 5 +++++ fastlane/metadata/android/en-US/changelogs/102.txt | 5 +++++ fastlane/metadata/android/en-US/changelogs/29561.txt | 5 +++++ fastlane/metadata/android/en-US/changelogs/29564.txt | 5 +++++ fastlane/metadata/android/en-US/changelogs/29567.txt | 5 +++++ 6 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 fastlane/metadata/android/en-US/changelogs/102.1.txt create mode 100644 fastlane/metadata/android/en-US/changelogs/102.txt create mode 100644 fastlane/metadata/android/en-US/changelogs/29561.txt create mode 100644 fastlane/metadata/android/en-US/changelogs/29564.txt create mode 100644 fastlane/metadata/android/en-US/changelogs/29567.txt diff --git a/core/src/mindustry/core/Logic.java b/core/src/mindustry/core/Logic.java index 12761439b7..e7c84adbc8 100644 --- a/core/src/mindustry/core/Logic.java +++ b/core/src/mindustry/core/Logic.java @@ -261,7 +261,7 @@ public class Logic implements ApplicationListener{ } } - if(!net.client() && !world.isInvalidMap() && !state.isEditor() && !state.rules.canGameOver){ + if(!net.client() && !world.isInvalidMap() && !state.isEditor() && state.rules.canGameOver){ checkGameOver(); } } diff --git a/fastlane/metadata/android/en-US/changelogs/102.1.txt b/fastlane/metadata/android/en-US/changelogs/102.1.txt new file mode 100644 index 0000000000..f8244a4b0b --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/102.1.txt @@ -0,0 +1,5 @@ +- Added new map view w/ panning and scrolling +- Added block health rule +- Added more internal teams for alternative gamemodes +- Added features for improved server modding +- Major internal change: package is now "mindustry" instead of "io.anuke.mindustry" (will break plugins) diff --git a/fastlane/metadata/android/en-US/changelogs/102.txt b/fastlane/metadata/android/en-US/changelogs/102.txt new file mode 100644 index 0000000000..f8244a4b0b --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/102.txt @@ -0,0 +1,5 @@ +- Added new map view w/ panning and scrolling +- Added block health rule +- Added more internal teams for alternative gamemodes +- Added features for improved server modding +- Major internal change: package is now "mindustry" instead of "io.anuke.mindustry" (will break plugins) diff --git a/fastlane/metadata/android/en-US/changelogs/29561.txt b/fastlane/metadata/android/en-US/changelogs/29561.txt new file mode 100644 index 0000000000..f8244a4b0b --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/29561.txt @@ -0,0 +1,5 @@ +- Added new map view w/ panning and scrolling +- Added block health rule +- Added more internal teams for alternative gamemodes +- Added features for improved server modding +- Major internal change: package is now "mindustry" instead of "io.anuke.mindustry" (will break plugins) diff --git a/fastlane/metadata/android/en-US/changelogs/29564.txt b/fastlane/metadata/android/en-US/changelogs/29564.txt new file mode 100644 index 0000000000..f8244a4b0b --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/29564.txt @@ -0,0 +1,5 @@ +- Added new map view w/ panning and scrolling +- Added block health rule +- Added more internal teams for alternative gamemodes +- Added features for improved server modding +- Major internal change: package is now "mindustry" instead of "io.anuke.mindustry" (will break plugins) diff --git a/fastlane/metadata/android/en-US/changelogs/29567.txt b/fastlane/metadata/android/en-US/changelogs/29567.txt new file mode 100644 index 0000000000..f8244a4b0b --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/29567.txt @@ -0,0 +1,5 @@ +- Added new map view w/ panning and scrolling +- Added block health rule +- Added more internal teams for alternative gamemodes +- Added features for improved server modding +- Major internal change: package is now "mindustry" instead of "io.anuke.mindustry" (will break plugins) From bcd5b811bb7772240d8281a4b45593084029fa3f Mon Sep 17 00:00:00 2001 From: Anuken Date: Sun, 29 Dec 2019 21:05:02 -0500 Subject: [PATCH 48/78] a brief experiment --- servers.json | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/servers.json b/servers.json index 0637a088a0..81ea4bf021 100644 --- a/servers.json +++ b/servers.json @@ -1 +1,5 @@ -[] \ No newline at end of file +[ + { + "address": "mindustry.us.to" + } +] From ee4f06a9c217c1b8f45c6e4b4b77d759841bdfdf Mon Sep 17 00:00:00 2001 From: Anuken Date: Sun, 29 Dec 2019 21:45:59 -0500 Subject: [PATCH 49/78] Bugfixes --- core/src/mindustry/ai/BlockIndexer.java | 34 ++++++++++++++----- core/src/mindustry/entities/Units.java | 8 +---- .../mindustry/graphics/MinimapRenderer.java | 4 +-- core/src/mindustry/input/DesktopInput.java | 2 +- .../ui/fragments/MinimapFragment.java | 9 ++--- .../android/en-US/changelogs/29570.txt | 5 +++ 6 files changed, 39 insertions(+), 23 deletions(-) create mode 100644 fastlane/metadata/android/en-US/changelogs/29570.txt diff --git a/core/src/mindustry/ai/BlockIndexer.java b/core/src/mindustry/ai/BlockIndexer.java index b010562595..9e72b7ef86 100644 --- a/core/src/mindustry/ai/BlockIndexer.java +++ b/core/src/mindustry/ai/BlockIndexer.java @@ -5,11 +5,11 @@ import arc.func.*; import arc.math.*; import arc.math.geom.*; import arc.struct.*; +import arc.util.*; import mindustry.content.*; import mindustry.entities.type.*; import mindustry.game.EventType.*; import mindustry.game.*; -import mindustry.game.Teams.*; import mindustry.type.*; import mindustry.world.*; import mindustry.world.blocks.*; @@ -34,6 +34,8 @@ public class BlockIndexer{ private ObjectSet[] damagedTiles = new ObjectSet[Team.all().length]; /**All ores available on this map.*/ private ObjectSet allOres = new ObjectSet<>(); + /**Stores teams that are present here as tiles.*/ + private ObjectSet activeTeams = new ObjectSet<>(); /** Maps teams to a map of flagged tiles by type. */ private ObjectSet[][] flagMap = new ObjectSet[Team.all().length][BlockFlag.all.length]; @@ -104,10 +106,11 @@ public class BlockIndexer{ } private GridBits structQuadrant(Team t){ - if(structQuadrants[t.id] == null){ - structQuadrants[t.id] = new GridBits(Mathf.ceil(world.width() / (float)quadrantSize), Mathf.ceil(world.height() / (float)quadrantSize)); + int id = Pack.u(t.id); + if(structQuadrants[id] == null){ + structQuadrants[id] = new GridBits(Mathf.ceil(world.width() / (float)quadrantSize), Mathf.ceil(world.height() / (float)quadrantSize)); } - return structQuadrants[t.id]; + return structQuadrants[id]; } /** Updates all the structure quadrants for a newly activated team. */ @@ -184,6 +187,19 @@ public class BlockIndexer{ set.add(entity.tile); } + public TileEntity findEnemyTile(Team team, float x, float y, float range, Boolf pred){ + for(Team enemy : activeTeams){ + if(!team.isEnemy(enemy)) continue; + + TileEntity entity = indexer.findTile(enemy, x, y, range, pred, true); + if(entity != null){ + return entity; + } + } + + return null; + } + public TileEntity findTile(Team team, float x, float y, float range, Boolf pred){ return findTile(team, x, y, range, pred, false); } @@ -263,6 +279,7 @@ public class BlockIndexer{ } typeMap.put(tile.pos(), new TileIndex(tile.block().flags, tile.getTeam())); } + activeTeams.add(tile.getTeam()); if(ores == null) return; @@ -301,13 +318,12 @@ public class BlockIndexer{ //this quadrant is now 'dirty', re-scan the whole thing int quadrantX = tile.x / quadrantSize; int quadrantY = tile.y / quadrantSize; - int index = quadrantX + quadrantY * quadWidth(); - for(TeamData data : state.teams.getActive()){ - GridBits bits = structQuadrant(data.team); + for(Team team : activeTeams){ + GridBits bits = structQuadrant(team); //fast-set this quadrant to 'occupied' if the tile just placed is already of this team - if(tile.getTeam() == data.team && tile.entity != null && tile.block().targetable){ + if(tile.getTeam() == team && tile.entity != null && tile.block().targetable){ bits.set(quadrantX, quadrantY); continue; //no need to process futher } @@ -319,7 +335,7 @@ public class BlockIndexer{ for(int y = quadrantY * quadrantSize; y < world.height() && y < (quadrantY + 1) * quadrantSize; y++){ Tile result = world.ltile(x, y); //when a targetable block is found, mark this quadrant as occupied and stop searching - if(result.entity != null && result.getTeam() == data.team){ + if(result.entity != null && result.getTeam() == team){ bits.set(quadrantX, quadrantY); break outer; } diff --git a/core/src/mindustry/entities/Units.java b/core/src/mindustry/entities/Units.java index fac56dcc0e..67fe01dc9e 100644 --- a/core/src/mindustry/entities/Units.java +++ b/core/src/mindustry/entities/Units.java @@ -83,13 +83,7 @@ public class Units{ public static TileEntity findEnemyTile(Team team, float x, float y, float range, Boolf pred){ if(team == Team.derelict) return null; - for(Team enemy : team.enemies()){ - TileEntity entity = indexer.findTile(enemy, x, y, range, pred, true); - if(entity != null){ - return entity; - } - } - return null; + return indexer.findEnemyTile(team, x, y, range, pred); } /** Returns the closest target enemy. First, units are checked, then tile entities. */ diff --git a/core/src/mindustry/graphics/MinimapRenderer.java b/core/src/mindustry/graphics/MinimapRenderer.java index 01ac9ab09a..c34bb246ec 100644 --- a/core/src/mindustry/graphics/MinimapRenderer.java +++ b/core/src/mindustry/graphics/MinimapRenderer.java @@ -93,8 +93,8 @@ public class MinimapRenderer implements Disposable{ float ry = !withLabels ? (unit.y - rect.y) / rect.width * h : unit.y / (world.height() * tilesize) * h; Draw.mixcol(unit.getTeam().color, 1f); - float scale = Scl.scl(1f) / 2f * scaling; - Draw.rect(unit.getIconRegion(), x + rx, y + ry, unit.getIconRegion().getWidth() * scale, unit.getIconRegion().getHeight() * scale, unit.rotation - 90); + float scale = Scl.scl(1f) / 2f * scaling * 32f; + Draw.rect(unit.getIconRegion(), x + rx, y + ry, scale, scale, unit.rotation - 90); Draw.reset(); if(withLabels && unit instanceof Player){ diff --git a/core/src/mindustry/input/DesktopInput.java b/core/src/mindustry/input/DesktopInput.java index c485b49ff2..8838dee9c9 100644 --- a/core/src/mindustry/input/DesktopInput.java +++ b/core/src/mindustry/input/DesktopInput.java @@ -136,7 +136,7 @@ public class DesktopInput extends InputHandler{ ui.listfrag.toggle(); } - if((player.getClosestCore() == null || state.isPaused()) && !ui.chatfrag.shown()){ + if(((player.getClosestCore() == null && player.isDead()) || state.isPaused()) && !ui.chatfrag.shown()){ //move camera around float camSpeed = !Core.input.keyDown(Binding.dash) ? 3f : 8f; Core.camera.position.add(Tmp.v1.setZero().add(Core.input.axis(Binding.move_x), Core.input.axis(Binding.move_y)).nor().scl(Time.delta() * camSpeed)); diff --git a/core/src/mindustry/ui/fragments/MinimapFragment.java b/core/src/mindustry/ui/fragments/MinimapFragment.java index 7e93832cb4..d13fed8936 100644 --- a/core/src/mindustry/ui/fragments/MinimapFragment.java +++ b/core/src/mindustry/ui/fragments/MinimapFragment.java @@ -17,7 +17,7 @@ import static mindustry.Vars.*; public class MinimapFragment extends Fragment{ private boolean shown; private float panx, pany, zoom = 1f, lastZoom = -1; - private float baseSize = Scl.scl(1000f); + private float baseSize = Scl.scl(5f); private Element elem; @Override @@ -25,16 +25,17 @@ public class MinimapFragment extends Fragment{ elem = parent.fill((x, y, w, h) -> { w = Core.graphics.getWidth(); h = Core.graphics.getHeight(); - float size = baseSize * zoom; + float size = baseSize * zoom * world.width(); Draw.color(Color.black); Fill.crect(x, y, w, h); if(renderer.minimap.getTexture() != null){ Draw.color(); + float ratio = (float)renderer.minimap.getTexture().getHeight() / renderer.minimap.getTexture().getWidth(); TextureRegion reg = Draw.wrap(renderer.minimap.getTexture()); - Draw.rect(reg, w/2f + panx*zoom, h/2f + pany*zoom, size, size); - renderer.minimap.drawEntities(w/2f + panx*zoom - size/2f, h/2f + pany*zoom - size/2f, size, size, zoom, true); + Draw.rect(reg, w/2f + panx*zoom, h/2f + pany*zoom, size, size * ratio); + renderer.minimap.drawEntities(w/2f + panx*zoom - size/2f, h/2f + pany*zoom - size/2f * ratio, size, size * ratio, zoom, true); } Draw.reset(); diff --git a/fastlane/metadata/android/en-US/changelogs/29570.txt b/fastlane/metadata/android/en-US/changelogs/29570.txt new file mode 100644 index 0000000000..f8244a4b0b --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/29570.txt @@ -0,0 +1,5 @@ +- Added new map view w/ panning and scrolling +- Added block health rule +- Added more internal teams for alternative gamemodes +- Added features for improved server modding +- Major internal change: package is now "mindustry" instead of "io.anuke.mindustry" (will break plugins) From 6f6166539056151a3f2248fc9fad8cce0ba5bbf7 Mon Sep 17 00:00:00 2001 From: Anuken Date: Sun, 29 Dec 2019 21:51:44 -0500 Subject: [PATCH 50/78] Fixed some block indexing --- core/src/mindustry/ai/BlockIndexer.java | 2 +- fastlane/metadata/android/en-US/changelogs/102.2.txt | 5 +++++ fastlane/metadata/android/en-US/changelogs/29573.txt | 5 +++++ 3 files changed, 11 insertions(+), 1 deletion(-) create mode 100644 fastlane/metadata/android/en-US/changelogs/102.2.txt create mode 100644 fastlane/metadata/android/en-US/changelogs/29573.txt diff --git a/core/src/mindustry/ai/BlockIndexer.java b/core/src/mindustry/ai/BlockIndexer.java index 9e72b7ef86..7a100b7778 100644 --- a/core/src/mindustry/ai/BlockIndexer.java +++ b/core/src/mindustry/ai/BlockIndexer.java @@ -225,7 +225,7 @@ public class BlockIndexer{ TileEntity e = other.entity; float ndst = Mathf.dst(x, y, e.x, e.y); - if(ndst < range && (closest == null || ndst < dst || (usePriority && closest.block.priority.ordinal() < e.block.priority.ordinal()))){ + if(ndst < range && (closest == null || ndst < dst || (usePriority && closest.block.priority.ordinal() <= e.block.priority.ordinal()))){ dst = ndst; closest = e; } diff --git a/fastlane/metadata/android/en-US/changelogs/102.2.txt b/fastlane/metadata/android/en-US/changelogs/102.2.txt new file mode 100644 index 0000000000..f8244a4b0b --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/102.2.txt @@ -0,0 +1,5 @@ +- Added new map view w/ panning and scrolling +- Added block health rule +- Added more internal teams for alternative gamemodes +- Added features for improved server modding +- Major internal change: package is now "mindustry" instead of "io.anuke.mindustry" (will break plugins) diff --git a/fastlane/metadata/android/en-US/changelogs/29573.txt b/fastlane/metadata/android/en-US/changelogs/29573.txt new file mode 100644 index 0000000000..f8244a4b0b --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/29573.txt @@ -0,0 +1,5 @@ +- Added new map view w/ panning and scrolling +- Added block health rule +- Added more internal teams for alternative gamemodes +- Added features for improved server modding +- Major internal change: package is now "mindustry" instead of "io.anuke.mindustry" (will break plugins) From 905d7abadbb823f06bec3d71e726a189f0b73d3f Mon Sep 17 00:00:00 2001 From: Anuken Date: Sun, 29 Dec 2019 23:49:09 -0500 Subject: [PATCH 51/78] Bugfixes --- core/src/mindustry/ui/fragments/PlayerListFragment.java | 2 +- core/src/mindustry/world/blocks/RespawnBlock.java | 3 ++- core/src/mindustry/world/blocks/units/MechPad.java | 2 +- fastlane/metadata/android/en-US/video.txt | 0 fastlane/metadata/android/es-ES/video.txt | 1 - fastlane/metadata/android/ja-JP/video.txt | 0 fastlane/metadata/android/ru-RU/video.txt | 0 fastlane/metadata/android/uk/video.txt | 0 8 files changed, 4 insertions(+), 4 deletions(-) delete mode 100644 fastlane/metadata/android/en-US/video.txt delete mode 100644 fastlane/metadata/android/es-ES/video.txt delete mode 100644 fastlane/metadata/android/ja-JP/video.txt delete mode 100644 fastlane/metadata/android/ru-RU/video.txt delete mode 100644 fastlane/metadata/android/uk/video.txt diff --git a/core/src/mindustry/ui/fragments/PlayerListFragment.java b/core/src/mindustry/ui/fragments/PlayerListFragment.java index a9cca9fb85..ea6f6087c1 100644 --- a/core/src/mindustry/ui/fragments/PlayerListFragment.java +++ b/core/src/mindustry/ui/fragments/PlayerListFragment.java @@ -130,7 +130,7 @@ public class PlayerListFragment extends Fragment{ t.addImageButton(Icon.zoomSmall, Styles.clearPartiali, () -> Call.onAdminRequest(user, AdminAction.trace)); }).padRight(12).size(bs + 10f, bs); - }else if((!user.isLocal && !user.isAdmin) && net.client() && playerGroup.size() >= 3){ //votekick + }else if((!user.isLocal && !user.isAdmin) && net.client() && playerGroup.size() >= 3 && player.getTeam() != user.getTeam()){ //votekick button.add().growY(); button.addImageButton(Icon.banSmall, Styles.clearPartiali, diff --git a/core/src/mindustry/world/blocks/RespawnBlock.java b/core/src/mindustry/world/blocks/RespawnBlock.java index 581dec8b21..b27b0af621 100644 --- a/core/src/mindustry/world/blocks/RespawnBlock.java +++ b/core/src/mindustry/world/blocks/RespawnBlock.java @@ -5,6 +5,7 @@ import arc.math.*; import mindustry.entities.type.*; import mindustry.graphics.*; import mindustry.type.*; +import mindustry.ui.*; import mindustry.world.*; import static mindustry.Vars.net; @@ -20,7 +21,7 @@ public class RespawnBlock{ Draw.reset(); if(player != null){ - TextureRegion region = player.getIconRegion(); + TextureRegion region = to.icon(Cicon.full); Draw.color(0f, 0f, 0f, 0.4f * progress); Draw.rect("circle-shadow", tile.drawx(), tile.drawy(), region.getWidth() / 3f, region.getWidth() / 3f); diff --git a/core/src/mindustry/world/blocks/units/MechPad.java b/core/src/mindustry/world/blocks/units/MechPad.java index 9ff7223dc6..0dadebc018 100644 --- a/core/src/mindustry/world/blocks/units/MechPad.java +++ b/core/src/mindustry/world/blocks/units/MechPad.java @@ -112,7 +112,7 @@ public class MechPad extends Block{ MechFactoryEntity entity = tile.ent(); if(entity.player != null){ - RespawnBlock.drawRespawn(tile, entity.heat, entity.progress, entity.time, entity.player, (!entity.sameMech && entity.player.mech == mech ? mech : Mechs.starter)); + RespawnBlock.drawRespawn(tile, entity.heat, entity.progress, entity.time, entity.player, (!entity.sameMech && entity.player.mech == mech ? Mechs.starter : mech)); } } diff --git a/fastlane/metadata/android/en-US/video.txt b/fastlane/metadata/android/en-US/video.txt deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/fastlane/metadata/android/es-ES/video.txt b/fastlane/metadata/android/es-ES/video.txt deleted file mode 100644 index 8b13789179..0000000000 --- a/fastlane/metadata/android/es-ES/video.txt +++ /dev/null @@ -1 +0,0 @@ - diff --git a/fastlane/metadata/android/ja-JP/video.txt b/fastlane/metadata/android/ja-JP/video.txt deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/fastlane/metadata/android/ru-RU/video.txt b/fastlane/metadata/android/ru-RU/video.txt deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/fastlane/metadata/android/uk/video.txt b/fastlane/metadata/android/uk/video.txt deleted file mode 100644 index e69de29bb2..0000000000 From 73461e03648c78a1ab137adcd3086de3b5eede9b Mon Sep 17 00:00:00 2001 From: Anuken Date: Mon, 30 Dec 2019 11:36:50 -0500 Subject: [PATCH 52/78] Added config for showing connect/disconnect messages --- core/src/mindustry/core/NetServer.java | 4 ++-- core/src/mindustry/net/Administration.java | 1 + core/src/mindustry/world/blocks/BuildBlock.java | 6 +++--- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/core/src/mindustry/core/NetServer.java b/core/src/mindustry/core/NetServer.java index b37ab7a57a..4880ad242d 100644 --- a/core/src/mindustry/core/NetServer.java +++ b/core/src/mindustry/core/NetServer.java @@ -443,7 +443,7 @@ public class NetServer implements ApplicationListener{ if(!player.con.hasDisconnected){ if(player.con.hasConnected){ Events.fire(new PlayerLeave(player)); - Call.sendMessage("[accent]" + player.name + "[accent] has disconnected."); + if(Config.showConnectMessages.bool()) Call.sendMessage("[accent]" + player.name + "[accent] has disconnected."); Call.onPlayerDisconnect(player.id); } @@ -581,7 +581,7 @@ public class NetServer implements ApplicationListener{ player.add(); player.con.hasConnected = true; - Call.sendMessage("[accent]" + player.name + "[accent] has connected."); + if(Config.showConnectMessages.bool()) Call.sendMessage("[accent]" + player.name + "[accent] has connected."); Log.info("&lm[{1}] &y{0} has connected. ", player.name, player.uuid); Events.fire(new PlayerJoin(player)); diff --git a/core/src/mindustry/net/Administration.java b/core/src/mindustry/net/Administration.java index 57a728a020..cdec5b81fd 100644 --- a/core/src/mindustry/net/Administration.java +++ b/core/src/mindustry/net/Administration.java @@ -320,6 +320,7 @@ public class Administration{ name("The server name as displayed on clients.", "Server", "servername"), port("The port to host on.", Vars.port), autoUpdate("Whether to auto-update and exit when a new bleeding-edge update arrives.", false), + showConnectMessages("Whether to display connect/disconnect messages.", true), startCommands("Commands run at startup. This should be a comma-separated list.", ""), crashReport("Whether to send crash reports.", false, "crashreport"), logging("Whether to log everything to files.", true), diff --git a/core/src/mindustry/world/blocks/BuildBlock.java b/core/src/mindustry/world/blocks/BuildBlock.java index 79061db553..bb1ea11468 100644 --- a/core/src/mindustry/world/blocks/BuildBlock.java +++ b/core/src/mindustry/world/blocks/BuildBlock.java @@ -257,7 +257,7 @@ public class BuildBlock extends Block{ if(cblock != null){ ItemStack[] requirements = cblock.requirements; if(requirements.length != accumulator.length || totalAccumulator.length != requirements.length){ - setDeconstruct(previous); + setDeconstruct(cblock); } //make sure you take into account that you can't deconstruct more than there is deconstructed @@ -342,12 +342,12 @@ public class BuildBlock extends Block{ this.progress = 1f; if(previous.buildCost >= 0.01f){ this.cblock = previous; - this.accumulator = new float[previous.requirements.length]; - this.totalAccumulator = new float[previous.requirements.length]; this.buildCost = previous.buildCost * state.rules.buildCostMultiplier; }else{ this.buildCost = 20f; //default no-requirement build cost is 20 } + this.accumulator = new float[previous.requirements.length]; + this.totalAccumulator = new float[previous.requirements.length]; } @Override From 44ef5148b477756d4c5ae39ff006126b979adb24 Mon Sep 17 00:00:00 2001 From: Anuken Date: Mon, 30 Dec 2019 12:47:40 -0500 Subject: [PATCH 53/78] Reduced drone lag --- .../entities/effect/ItemTransfer.java | 2 +- .../mindustry/entities/traits/MinerTrait.java | 21 +++++++++++++++++-- core/src/mindustry/entities/type/Player.java | 5 +++++ core/src/mindustry/world/Tile.java | 2 +- 4 files changed, 26 insertions(+), 4 deletions(-) diff --git a/core/src/mindustry/entities/effect/ItemTransfer.java b/core/src/mindustry/entities/effect/ItemTransfer.java index ea8366c812..2018d15a69 100644 --- a/core/src/mindustry/entities/effect/ItemTransfer.java +++ b/core/src/mindustry/entities/effect/ItemTransfer.java @@ -44,7 +44,7 @@ public class ItemTransfer extends TimedEntity implements DrawTrait{ create(item, x, y, to, () -> to.addItem(item)); } - @Remote(called = Loc.server) + @Remote(called = Loc.server, unreliable = true) public static void transferItemTo(Item item, int amount, float x, float y, Tile tile){ if(tile == null || tile.entity == null || tile.entity.items == null) return; for(int i = 0; i < Mathf.clamp(amount / 3, 1, 8); i++){ diff --git a/core/src/mindustry/entities/traits/MinerTrait.java b/core/src/mindustry/entities/traits/MinerTrait.java index 4881d3720a..5b3d51c21d 100644 --- a/core/src/mindustry/entities/traits/MinerTrait.java +++ b/core/src/mindustry/entities/traits/MinerTrait.java @@ -7,6 +7,7 @@ import arc.math.*; import arc.util.Time; import mindustry.content.*; import mindustry.entities.Effects; +import mindustry.entities.effect.*; import mindustry.entities.type.*; import mindustry.gen.Call; import mindustry.graphics.*; @@ -38,11 +39,26 @@ public interface MinerTrait extends Entity{ /** Returns whether or not this builder can mine a specific item type. */ boolean canMine(Item item); + /** @return whether to offload mined items immediately at the core. if false, items are collected and dropped in a burst. */ + default boolean offloadImmediately(){ + return false; + } + default void updateMining(){ Unit unit = (Unit)this; Tile tile = getMineTile(); TileEntity core = unit.getClosestCore(); + if(core != null && tile != null && tile.drop() != null && !unit.acceptsItem(tile.drop()) && unit.dst(core) < mineTransferRange){ + int accepted = core.tile.block().acceptStack(unit.item().item, unit.item().amount, core.tile, unit); + if(accepted > 0){ + Call.transferItemTo(unit.item().item, accepted, + tile.worldx() + Mathf.range(tilesize / 2f), + tile.worldy() + Mathf.range(tilesize / 2f), core.tile); + unit.clearItem(); + } + } + if(tile == null || core == null || tile.block() != Blocks.air || dst(tile.worldx(), tile.worldy()) > getMiningRange() || tile.drop() == null || !unit.acceptsItem(tile.drop()) || !canMine(tile.drop())){ setMineTile(null); @@ -52,12 +68,13 @@ public interface MinerTrait extends Entity{ if(Mathf.chance(Time.delta() * (0.06 - item.hardness * 0.01) * getMinePower())){ - if(unit.dst(core) < mineTransferRange && core.tile.block().acceptStack(item, 1, core.tile, unit) == 1){ + if(unit.dst(core) < mineTransferRange && core.tile.block().acceptStack(item, 1, core.tile, unit) == 1 && offloadImmediately()){ Call.transferItemTo(item, 1, tile.worldx() + Mathf.range(tilesize / 2f), tile.worldy() + Mathf.range(tilesize / 2f), core.tile); }else if(unit.acceptsItem(item)){ - Call.transferItemToUnit(item, + //this is clientside, since items are synced anyway + ItemTransfer.transferItemToUnit(item, tile.worldx() + Mathf.range(tilesize / 2f), tile.worldy() + Mathf.range(tilesize / 2f), unit); diff --git a/core/src/mindustry/entities/type/Player.java b/core/src/mindustry/entities/type/Player.java index 8366c01cc6..4077da0e4e 100644 --- a/core/src/mindustry/entities/type/Player.java +++ b/core/src/mindustry/entities/type/Player.java @@ -119,6 +119,11 @@ public class Player extends Unit implements BuilderMinerTrait, ShooterTrait{ heal(); } + @Override + public boolean offloadImmediately(){ + return true; + } + @Override public TypeID getTypeID(){ return TypeIDs.player; diff --git a/core/src/mindustry/world/Tile.java b/core/src/mindustry/world/Tile.java index 119af5b8df..fe319fd02e 100644 --- a/core/src/mindustry/world/Tile.java +++ b/core/src/mindustry/world/Tile.java @@ -376,7 +376,7 @@ public class Tile implements Position, TargetTrait{ return state.teams.canInteract(team, getTeam()); } - public Item drop(){ + public @Nullable Item drop(){ return overlay == Blocks.air || overlay.itemDrop == null ? floor.itemDrop : overlay.itemDrop; } From f2e1d17ce9f58d2e98e4adc1bc738bf53d0782fc Mon Sep 17 00:00:00 2001 From: Anuken Date: Mon, 30 Dec 2019 12:49:27 -0500 Subject: [PATCH 54/78] Made junction harder to spam --- core/src/mindustry/content/Blocks.java | 2 +- gradle.properties | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core/src/mindustry/content/Blocks.java b/core/src/mindustry/content/Blocks.java index 58ff4a7c35..9eec1f928b 100644 --- a/core/src/mindustry/content/Blocks.java +++ b/core/src/mindustry/content/Blocks.java @@ -902,6 +902,7 @@ public class Blocks implements ContentList{ speed = 26; capacity = 12; health = 30; + buildCostMultiplier = 4f; }}; itemBridge = new BufferedItemBridge("bridge-conveyor"){{ @@ -930,7 +931,6 @@ public class Blocks implements ContentList{ router = new Router("router"){{ requirements(Category.distribution, ItemStack.with(Items.copper, 3)); - }}; distributor = new Router("distributor"){{ diff --git a/gradle.properties b/gradle.properties index 8ed0e699dd..40485198b7 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,3 +1,3 @@ org.gradle.daemon=true org.gradle.jvmargs=-Xms256m -Xmx1024m -archash=14b6027d79cda5e02d74a7c2f85eb7e768c7abeb +archash=4882a25c74ada2c0aff9dbcf2cef0ab1b7936b67 From 51bd74fcc1599552929f9717b6e8bc936a6edd66 Mon Sep 17 00:00:00 2001 From: Anuken Date: Mon, 30 Dec 2019 12:55:35 -0500 Subject: [PATCH 55/78] Build time increase of basic blocks --- core/src/mindustry/content/Blocks.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/core/src/mindustry/content/Blocks.java b/core/src/mindustry/content/Blocks.java index 9eec1f928b..f0fc54314d 100644 --- a/core/src/mindustry/content/Blocks.java +++ b/core/src/mindustry/content/Blocks.java @@ -898,11 +898,11 @@ public class Blocks implements ContentList{ }}; junction = new Junction("junction"){{ - requirements(Category.distribution, ItemStack.with(Items.copper, 1), true); + requirements(Category.distribution, ItemStack.with(Items.copper, 2), true); speed = 26; capacity = 12; health = 30; - buildCostMultiplier = 4f; + buildCostMultiplier = 6f; }}; itemBridge = new BufferedItemBridge("bridge-conveyor"){{ @@ -922,15 +922,18 @@ public class Blocks implements ContentList{ sorter = new Sorter("sorter"){{ requirements(Category.distribution, ItemStack.with(Items.lead, 2, Items.copper, 2)); + buildCostMultiplier = 3f; }}; invertedSorter = new Sorter("inverted-sorter"){{ requirements(Category.distribution, ItemStack.with(Items.lead, 2, Items.copper, 2)); + buildCostMultiplier = 3f; invert = true; }}; router = new Router("router"){{ requirements(Category.distribution, ItemStack.with(Items.copper, 3)); + buildCostMultiplier = 2f; }}; distributor = new Router("distributor"){{ @@ -940,6 +943,7 @@ public class Blocks implements ContentList{ overflowGate = new OverflowGate("overflow-gate"){{ requirements(Category.distribution, ItemStack.with(Items.lead, 2, Items.copper, 4)); + buildCostMultiplier = 3f; }}; massDriver = new MassDriver("mass-driver"){{ From 1de294cae553de957684af7659ef35dcb712ef37 Mon Sep 17 00:00:00 2001 From: Anuken Date: Mon, 30 Dec 2019 13:00:28 -0500 Subject: [PATCH 56/78] Bugfixes --- core/src/mindustry/world/blocks/BuildBlock.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/mindustry/world/blocks/BuildBlock.java b/core/src/mindustry/world/blocks/BuildBlock.java index bb1ea11468..345300343f 100644 --- a/core/src/mindustry/world/blocks/BuildBlock.java +++ b/core/src/mindustry/world/blocks/BuildBlock.java @@ -171,7 +171,7 @@ public class BuildBlock extends Block{ return; } - if(entity.previous == null) return; + if(entity.previous == null || entity.cblock == null) return; if(Core.atlas.isFound(entity.previous.icon(mindustry.ui.Cicon.full))){ Draw.rect(entity.previous.icon(Cicon.full), tile.drawx(), tile.drawy(), entity.previous.rotate ? tile.rotation() * 90 : 0); From e7d813ab5b340d3e982d837be884008610ee7ca2 Mon Sep 17 00:00:00 2001 From: Anuken Date: Mon, 30 Dec 2019 13:03:29 -0500 Subject: [PATCH 57/78] Votekick config --- core/src/mindustry/core/NetServer.java | 5 +++++ core/src/mindustry/net/Administration.java | 1 + 2 files changed, 6 insertions(+) diff --git a/core/src/mindustry/core/NetServer.java b/core/src/mindustry/core/NetServer.java index 4880ad242d..27e1ed1198 100644 --- a/core/src/mindustry/core/NetServer.java +++ b/core/src/mindustry/core/NetServer.java @@ -321,6 +321,11 @@ public class NetServer implements ApplicationListener{ VoteSession[] currentlyKicking = {null}; clientCommands.register("votekick", "[player...]", "Vote to kick a player, with a cooldown.", (args, player) -> { + if(!Config.enableVotekick.bool()){ + player.sendMessage("[scarlet]Vote-kick is disabled on this server."); + return; + } + if(playerGroup.size() < 3){ player.sendMessage("[scarlet]At least 3 players are needed to start a votekick."); return; diff --git a/core/src/mindustry/net/Administration.java b/core/src/mindustry/net/Administration.java index cdec5b81fd..8d037b99dd 100644 --- a/core/src/mindustry/net/Administration.java +++ b/core/src/mindustry/net/Administration.java @@ -321,6 +321,7 @@ public class Administration{ port("The port to host on.", Vars.port), autoUpdate("Whether to auto-update and exit when a new bleeding-edge update arrives.", false), showConnectMessages("Whether to display connect/disconnect messages.", true), + enableVotekick("Whether votekick is enabled.", true), startCommands("Commands run at startup. This should be a comma-separated list.", ""), crashReport("Whether to send crash reports.", false, "crashreport"), logging("Whether to log everything to files.", true), From 62947b9417286064c426d22152bc07f96e505057 Mon Sep 17 00:00:00 2001 From: CinExPL <41754972+CinExPL@users.noreply.github.com> Date: Tue, 31 Dec 2019 05:03:46 +0100 Subject: [PATCH 58/78] Update bundle_pl.properties (#1285) - reverted back some changes made by @FarmerThanos, - fixed some errors, - compared to english file. --- core/assets/bundles/bundle_pl.properties | 123 +++++++++++++---------- 1 file changed, 72 insertions(+), 51 deletions(-) diff --git a/core/assets/bundles/bundle_pl.properties b/core/assets/bundles/bundle_pl.properties index 8c17577654..ceef56533a 100644 --- a/core/assets/bundles/bundle_pl.properties +++ b/core/assets/bundles/bundle_pl.properties @@ -12,13 +12,14 @@ link.itch.io.description = Strona itch.io z oficjanymi wersjami do pobrania link.google-play.description = Strona na sklepie Google Play link.f-droid.description = F-Droid catalogue listing link.wiki.description = Oficjana Wiki Mindustry +link.feathub.description = Zaproponuj nowe funkcje linkfail = Nie udało się otworzyć linku!\nURL został skopiowany. screenshot = Zapisano zdjęcie w {0} screenshot.invalid = Zrzut ekranu jest zbyt duży. Najprawdopodobniej brakuje miejsca w pamięci urządzenia. gameover = Koniec Gry gameover.pvp = Zwyciężyła drużyna [accent]{0}[]! highscore = [YELLOW] Nowy rekord! -copied = Copied. +copied = Skopiowano. load.sound = Dźwięki load.map = Mapy @@ -26,6 +27,14 @@ load.image = Obrazy load.content = Treść load.system = System load.mod = Mody +load.scripts = Skrypty + +be.update = Nowa wersja Bleeding Edge jest dostępna: +be.update.confirm = Pobrać i zainstalować teraz? +be.updating = Aktualizowanie... +be.ignore = Zignoruj +be.noupdates = Nie znaleziono aktualizacji. +be.check = Sprawdź aktualizacje schematic = Schemat schematic.add = Zapisz schemat... @@ -80,7 +89,6 @@ continue = Kontynuuj maps.none = [lightgray]Nie znaleziono żadnych map! invalid = Nieprawidłowy pickcolor = Wybierz kolor - preparingconfig = Przygotowywanie Konfiguracji preparingcontent = Przygotowywanie Zawartości uploadingcontent = Przesyłanie Zawartości @@ -100,22 +108,28 @@ mod.enabled = [lightgray]Włączony mod.disabled = [scarlet]Wyłączony mod.disable = Wyłącz mod.delete.error = Nie udało się usunąć moda. Plik może być w użyciu. +mod.requiresversion = [scarlet]Wymaga gry w wersji co najmniej: [accent]{0} mod.missingdependencies = [scarlet]Brakujące zależności: {0} +mod.erroredcontent = [scarlet]Content Errors +mod.errors = Wystąpił błąd podczas ładowania treści. +mod.noerrorplay = [scarlet]Twoje mody zawierają błędy.[] Wyłącz je lub napraw błędy przed rozpoczęciem gry. mod.nowdisabled = [scarlet]Brakuje zależności dla moda '{0}':[accent] {1}\n[lightgray]Najpierw trzeba ściągnąć te mody.\nMod zostanie automatycznie wyłączony. mod.enable = Włącz mod.requiresrestart = Gra się wyłączy aby wprowadzić zmiany moda. mod.reloadrequired = [scarlet]Wymagany restart mod.import = Importuj Mod mod.import.github = Importuj mod z GitHuba +mod.item.remove = Ten przedmiot jest częścią moda[accent] '{0}'[]. Aby usunąć go, odinstaluj modyfikację. mod.remove.confirm = Ten mod zostanie usunięty. mod.author = [LIGHT_GRAY]Autor:[] {0} mod.missing = Ten zapis zawiera mody, które zostały niedawno zaktualizowane, bądź nie są już zainstalowane. Zapis może zostać uszkodzony. Czy jesteś pewien, że chcesz go załadować?\n[lightgray]Mody:\n{0} mod.preview.missing = Przed opublikowaniem tego moda na Warsztacie musisz dodać zdjęcie podglądowe.\nDodaj zdjęcie o nazwie[accent] preview.png[] do folderu moda i spróbuj jeszcze raz. -mod.folder.missing = Jedynie mody w formie folderów mogą się znaleźć na Warsztacie.\nBy zamienić moda w folder, wyciągnij go z archiwum, umieść w folderze i usuń archiwum. Później uruchom ponownie grę bądź załaduj ponownie mody. +mod.folder.missing = Jedynie mody w formie folderów mogą się znaleźć na Warsztacie.\nBy zamienić moda w folder, wyciągnij go z archiwum, umieść w folderze i usuń archiwum. Później uruchom ponownie grę lub załaduj ponownie mody. +mod.scripts.unsupported = Twoje urządzenie nie wspiera skryptów. Niektóre mody mogą nie działać poprawnie. about.button = O Grze name = Nazwa: -noname = Najpierw wybierz[accent] nazwę gracza[] +noname = Najpierw wybierz[accent] nazwę gracza[]. filename = Nazwa Pliku: unlocked = Odblokowano nową zawartość! completed = [accent]Ukończony @@ -123,8 +137,8 @@ techtree = Drzewo Technologiczne research.list = [lightgray]Badania: research = Badaj researched = [lightgray]{0} zbadane. -players = {0} graczy online -players.single = {0} gracz online +players = {0} graczy +players.single = {0} gracz server.closing = [accent] Zamykanie serwera... server.kicked.kick = Zostałeś wyrzucony z serwera! server.kicked.whitelist = Nie ma cię tu na białej liście. @@ -141,6 +155,7 @@ server.kicked.nameEmpty = Wybrana przez Ciebie nazwa jest nieprawidłowa. server.kicked.idInUse = Jesteś już na serwerze! Łączenie się z dwóch kont nie jest dozwolone. server.kicked.customClient = Ten serwer nie wspomaga wersji deweloperskich. Pobierz oficjalną wersję. server.kicked.gameover = Koniec gry! +server.kicked.serverRestarting = Restart serwera. server.versions = Twoja wersja gry:[accent] {0}[]\nWersja gry serwera:[accent] {1}[] host.info = Przycisk [accent]host[] hostuje serwer na porcie [scarlet]6567[]. \nKażdy w tej samej sieci [lightgray]wifi lub hotspocie[] powinien zobaczyć twój serwer.\n\nJeśli chcesz, aby każdy z twoim IP mógł dołączyć, musisz wykonać [accent]przekierowywanie portów[].\n\n[lightgray]Notka: Jeśli ktokolwiek ma problem z dołączeniem do gry lokalnej, upewnij się, że udostępniłeś Mindustry dostęp do sieci w ustawieniach zapory (firewall). Zauważ, że niektóre sieci publiczne mogą nie zezwalać na wykrycie serwerów. join.info = Tutaj możesz wpisać [accent]adres IP serwera[], aby dołączyć lub wyszukać [accent]serwerów w lokalnej sieci[], do których możesz dołączyć .\nGra wieloosobowa na LAN i WAN jest wspomagana.\n\n[lightgray]Notka: Nie ma automatycznej listy wszystkich serwerów; jeśli chcesz dołączyć przez IP, musisz zapytać hosta o IP. @@ -240,7 +255,7 @@ data.exported = Dane wyeksportowane. data.invalid = Nieprawidłowe dane gry. data.import.confirm = Zaimportowanie zewnętrznych danych usunie[scarlet] wszystkie[] obecne dane gry.\n[accent]Nie można tego cofnąć![]\n\nGdy dane zostaną zimportowane, gra automatycznie się wyłączy. classic.export = Eksportuj Dane Wersji Klasycznej -classic.export.text = [accent]Mindustry[] otrzymało ostatnio ważną aktualizację.\nWykryto zapis lub mapę z wersji classic (v3.5 build 40) - czy chciałbyś eksportować te zapisy do katalogu domowego swojego telefonu, do użycia w aplikacji Mindustry Classic? +classic.export.text = [accent]Mindustry[] otrzymało ostatnio ważną aktualizację.\nWykryto zapis lub mapę z wersji classic (v3.5 build 40) - czy chciałbyś eksportować te zapisy do katalogu domowego swojego telefonu, aby móc używać ich w Mindustry Classic? quit.confirm = Czy na pewno chcesz wyjść? quit.confirm.tutorial = Czy jesteś pewien tego co robisz?\nSamouczek może zostać powtórzony w[accent] Ustawienia->Gra->Ponów samouczek.[] loading = [accent]Ładowanie... @@ -248,7 +263,7 @@ reloading = [accent]Przeładowywanie Modów... saving = [accent]Zapisywanie... cancelbuilding = [accent][[{0}][] by wyczyścić plan selectschematic = [accent][[{0}][] by wybrać+skopiować -pausebuilding = [accent][[{0}][] by wtrzymać budowę +pausebuilding = [accent][[{0}][] by wstrzymać budowę resumebuilding = [scarlet][[{0}][] by kontynuować budowę wave = [accent]Fala {0} wave.waiting = Fala za {0} @@ -414,7 +429,6 @@ load = Wczytaj save = Zapisz fps = FPS: {0} ping = Ping: {0}ms - language.restart = Uruchom grę ponownie, aby ustawiony język zaczął funkcjonować. settings = Ustawienia tutorial = Poradnik @@ -456,7 +470,7 @@ boss.health = Zdrowie Bossa connectfail = [crimson]Nie można połączyć się z serwerem:\n\n[accent]{0} error.unreachable = Serwer niedostępny.\nCzy adres jest wpisany poprawnie? error.invalidaddress = Niepoprawny adres. -error.timedout = Przekroczono limit czasu!/nUpewnij się, że host ma ustawione przekierowanie portu oraz poprawność wpisanego adresu! +error.timedout = Przekroczono limit czasu!\nUpewnij się, że host ma ustawione przekierowanie portu oraz poprawność wpisanego adresu! error.mismatch = Błąd pakietu:\nprawdopodobne niedopasowanie klienta/serwera.\nUpewnij się, że ty i host macie najnowszą wersję Mindustry! error.alreadyconnected = Jesteś już połączony. error.mapnotfound = Plik mapy nie został znaleziony! @@ -493,10 +507,12 @@ zone.nuclearComplex.description = Dawny zakład produkcji i przetwarzania toru, zone.fungalPass.description = Przejściowy obszar pomiędzy wysokimi górami a nisko znajdującymi się, ogarniętymi przez zarodniki równinami. Znajduje się tu mała postawiona przez wrogów baza zwiadowcza.\nZniszcz ją.\nUżyj jednostek Nóż i Pełzak. Zniszcz oba rdzenie. zone.impact0078.description = zone.crags.description = + settings.language = Język settings.data = Dane Gry settings.reset = Przywróć Domyślne settings.rebind = Zmień +settings.resetKey = Resetuj settings.controls = Sterowanie settings.game = Gra settings.sound = Dźwięk @@ -563,8 +579,8 @@ bar.heat = Ciepło bar.power = Prąd bar.progress = Postęp Budowy bar.spawned = Jednostki: {0}/{1} -bar.input = Input -bar.output = Output +bar.input = Wejście +bar.output = Wyjście bullet.damage = [stat]{0}[lightgray] Obrażenia bullet.splashdamage = [stat]{0}[lightgray] Obrażenia obszarowe ~[stat] {1}[lightgray] kratki @@ -590,6 +606,8 @@ unit.persecond = /sekundę unit.timesspeed = x prędkość unit.percent = % unit.items = przedmioty +unit.thousands = tys. +unit.millions = mln category.general = Główne category.power = Prąd category.liquids = Płyny @@ -621,19 +639,20 @@ setting.difficulty.normal = Normalny setting.difficulty.hard = Trudny setting.difficulty.insane = Szalony setting.difficulty.name = Poziom trudności -setting.screenshake.name = Wstrząsy ekranu +setting.screenshake.name = Siła wstrząsów ekranu setting.effects.name = Wyświetlanie efektów setting.destroyedblocks.name = Wyświetl zniszczone bloki -setting.conveyorpathfinding.name = Znajdowanie Ścieżki Stawianych Taśmociągów +setting.conveyorpathfinding.name = Ustalanie ścieżki przenośników +setting.coreselect.name = Zezwalaj na schematyczne rdzenie setting.sensitivity.name = Czułość kontrolera setting.saveinterval.name = Interwał automatycznego zapisywania setting.seconds = {0} sekund setting.blockselecttimeout.name = Block Select Timeout -setting.milliseconds = {0} millisekund +setting.milliseconds = {0} milisekund setting.fullscreen.name = Pełny ekran setting.borderlesswindow.name = Bezramkowe okno[lightgray] (może wymagać restartu) setting.fps.name = Pokazuj FPS oraz ping -setting.blockselectkeys.name = Pokazuj Klawisze Wyboru Bloków +setting.blockselectkeys.name = Pokazuj skróty klawiszowe bloków setting.vsync.name = Synchronizacja pionowa setting.pixelate.name = Pikselacja [lightgray](wyłącza animacje) setting.minimap.name = Pokaż Minimapę @@ -653,7 +672,7 @@ public.confirm = Czy chcesz ustawić swoją grę jako publiczną?\n[accent]Każd public.beta = Wersje beta gry nie mogą tworzyć publicznych pokoi. uiscale.reset = Skala interfejsu uległa zmianie.\nNaciśnij "OK" by potwierdzić zmiany.\n[scarlet]Cofanie zmian i wyjście z gry za[accent] {0}[] uiscale.cancel = Anuluj i Wyjdź -setting.bloom.name = Rozproszenie +setting.bloom.name = Efekt Bloom keybind.title = Zmień keybinds.mobile = [scarlet]Większość skrótów klawiszowych nie funkcjonuje w wersji mobilnej. Tylko podstawowe poruszanie się jest wspierane. category.general.name = Ogólne @@ -662,15 +681,15 @@ category.multiplayer.name = Wielu graczy command.attack = Atakuj command.rally = Zbierz command.retreat = Wycofaj -placement.blockselectkeys = \n[lightgray]Key: [{0}, +placement.blockselectkeys = \n[lightgray]Klawisz: [{0}, keybind.clear_building.name = Wyczyść budynek keybind.press = Naciśnij wybrany klawisz... keybind.press.axis = Naciśnij oś lub klawisz... keybind.screenshot.name = Zrzut ekranu mapy -keybind.toggle_power_lines.name = Przełącz Linie Energetyczne +keybind.toggle_power_lines.name = Zmień widoczność linii energetycznych keybind.move_x.name = Poruszanie w poziomie keybind.move_y.name = Poruszanie w pionie -keybind.mouse_move.name = Podążaj Za Myszką +keybind.mouse_move.name = Podążaj Za Myszą keybind.dash.name = Dash keybind.schematic_select.name = Wybierz region keybind.schematic_menu.name = Menu schematów @@ -678,20 +697,20 @@ keybind.schematic_flip_x.name = Obróć schemat horyzontalnie keybind.schematic_flip_y.name = Obróć schemat wertykalnie keybind.category_prev.name = Poprzednia kategoria keybind.category_next.name = Następna kategoria -keybind.block_select_left.name = Wybór Bloku Lewo -keybind.block_select_right.name = Wybór Bloku Prawo -keybind.block_select_up.name = Wybór Bloku Góra -keybind.block_select_down.name = Wybór Bloku Dół -keybind.block_select_01.name = Kategoria/Wybór Bloku 1 -keybind.block_select_02.name = Kategoria/Wybór Bloku 2 -keybind.block_select_03.name = Kategoria/Wybór Bloku 3 -keybind.block_select_04.name = Kategoria/Wybór Bloku 4 -keybind.block_select_05.name = Kategoria/Wybór Bloku 5 -keybind.block_select_06.name = Kategoria/Wybór Bloku 6 -keybind.block_select_07.name = Kategoria/Wybór Bloku 7 -keybind.block_select_08.name = Kategoria/Wybór Bloku 8 -keybind.block_select_09.name = Kategoria/Wybór Bloku 9 -keybind.block_select_10.name = Kategoria/Wybór Bloku 10 +keybind.block_select_left.name = Block Select Left +keybind.block_select_right.name = Block Select Right +keybind.block_select_up.name = Block Select Up +keybind.block_select_down.name = Block Select Down +keybind.block_select_01.name = Wybór bloku/kategorii 1 +keybind.block_select_02.name = Wybór bloku/kategorii 2 +keybind.block_select_03.name = Wybór bloku/kategorii 3 +keybind.block_select_04.name = Wybór bloku/kategorii 4 +keybind.block_select_05.name = Wybór bloku/kategorii 5 +keybind.block_select_06.name = Wybór bloku/kategorii 6 +keybind.block_select_07.name = Wybór bloku/kategorii 7 +keybind.block_select_08.name = Wybór bloku/kategorii 8 +keybind.block_select_09.name = Wybór bloku/kategorii 9 +keybind.block_select_10.name = Wybór bloku/kategorii 10 keybind.fullscreen.name = Przełącz Pełny Ekran keybind.select.name = Zaznacz keybind.diagonal_placement.name = Budowa po skosie @@ -708,7 +727,7 @@ keybind.chat.name = Czat keybind.player_list.name = Lista graczy keybind.console.name = Konsola keybind.rotate.name = Obracanie -keybind.rotateplaced.name = Obróć istniejące (Trzymaj) +keybind.rotateplaced.name = Rotate Existing (Hold) keybind.toggle_menus.name = Zmiana widoczności menu keybind.chat_history_prev.name = Przewiń wiadomości w górę keybind.chat_history_next.name = Przewiń wiadomości w dół @@ -736,6 +755,7 @@ rules.enemyCheat = Nieskończone zasoby komputera-przeciwnika (czerwonego zespo rules.unitdrops = Surowce ze zniszczonych jednostek rules.unitbuildspeedmultiplier = Mnożnik prędkości tworzenia jednostek rules.unithealthmultiplier = Mnożnik życia jednostek +rules.blockhealthmultiplier = Mnożnik życia bloków rules.playerhealthmultiplier = Mnożnik życia gracza rules.playerdamagemultiplier = Mnożnik obrażeń gracza rules.unitdamagemultiplier = Mnożnik obrażeń jednostek @@ -804,6 +824,7 @@ mech.trident-ship.name = Trójząb mech.trident-ship.weapon = Wnęka bombowa mech.glaive-ship.name = Glewia mech.glaive-ship.weapon = Zapalający Karabin +item.corestorable = [lightgray]Przechowywalne w rdzeniu: {0} item.explosiveness = [lightgray]Wybuchowość: {0} item.flammability = [lightgray]Palność: {0} item.radioactivity = [lightgray]Promieniotwórczość: {0} @@ -908,11 +929,11 @@ block.scorch.name = Płomień block.scatter.name = Flak block.hail.name = Grad block.lancer.name = Lansjer -block.conveyor.name = Taśmociąg -block.titanium-conveyor.name = Taśmociąg Tytanowy -block.armored-conveyor.name = Opancerzony Taśmociąg +block.conveyor.name = Przenośnik +block.titanium-conveyor.name = Przenośnik Tytanowy +block.armored-conveyor.name = Przenośnik Opancerzony block.armored-conveyor.description = Przesyła przedmioty z taką samą szybkością jak Przenośnik Tytanowy, ale jest bardziej odporny. Wejściami bocznymi mogą być tylko inne przenośniki. -block.junction.name = Skrzyżowanie +block.junction.name = Węzeł block.router.name = Rozdzielacz block.distributor.name = Dystrybutor block.sorter.name = Sortownik @@ -930,8 +951,8 @@ block.incinerator.name = Spalacz block.spore-press.name = Prasa Zarodników block.separator.name = Rozdzielacz block.coal-centrifuge.name = Wirówka węglowa -block.power-node.name = Węzeł Prądowy -block.power-node-large.name = Duży Węzeł Prądowy +block.power-node.name = Węzeł Prądu +block.power-node-large.name = Duży Węzeł Prądu block.surge-tower.name = Wieża Energetyczna block.diode.name = Dioda baterii block.battery.name = Bateria @@ -958,8 +979,8 @@ block.item-source.name = Źródło przedmiotów block.item-void.name = Próżnia przedmiotów block.liquid-source.name = Źródło płynów block.power-void.name = Próżnia prądu -block.power-source.name = Węzeł Nieskończonego Prądu -block.unloader.name = Wyładowywacz +block.power-source.name = Nieskończony Prąd +block.unloader.name = Ekstraktor block.vault.name = Magazyn block.wave.name = Strumień block.swarmer.name = Działo Rojowe @@ -990,11 +1011,11 @@ block.plated-conduit.name = Opancerzona rura block.phase-conduit.name = Rura Fazowa block.liquid-router.name = Rozdzielacz Płynów block.liquid-tank.name = Zbiornik Płynów -block.liquid-junction.name = Skrzyżowanie Rurowe -block.bridge-conduit.name = Most Rurowy +block.liquid-junction.name = Łącznik Płynów +block.bridge-conduit.name = Most Płynów block.rotary-pump.name = Wirowa Pompa block.thorium-reactor.name = Reaktor Torowy -block.mass-driver.name = Katapulta Masowa +block.mass-driver.name = Katapulta Masy block.blast-drill.name = Wiertło Wybuchowe block.thermal-pump.name = Pompa Termalna block.thermal-generator.name = Generator Termalny @@ -1124,8 +1145,8 @@ block.copper-wall.description = Tani blok obronny.\nPrzydatny do ochrony rdzenia block.copper-wall-large.description = Tani blok obronny.\nPrzydatny do ochrony rdzenia i wieżyczek w pierwszych kilku falach.\nObejmuje wiele kratek. block.titanium-wall.description = Umiarkowanie silny blok obronny.\nZapewnia umiarkowaną ochronę przed wrogami. block.titanium-wall-large.description = Umiarkowanie silny blok obronny.\nZapewnia umiarkowaną ochronę przed wrogami.\nObejmuje wiele kratek. -block.plastanium-wall.description = A special type of wall that absorbs electric arcs and blocks automatic power node connections. -block.plastanium-wall-large.description = A special type of wall that absorbs electric arcs and blocks automatic power node connections.\nSpans multiple tiles. +block.plastanium-wall.description = Specjajny typ ściany, który pochłania łuki elektryczne oraz blokuje automatyczne łączenie węzłów. +block.plastanium-wall-large.description = Specjajny typ ściany, który pochłania łuki elektryczne oraz blokuje automatyczne łączenie węzłów.\nObejmuje wiele kratek. block.thorium-wall.description = Silny blok obronny.\nDobra ochrona przed wrogami. block.thorium-wall-large.description = Silny blok obronny.\nDobra ochrona przed wrogami.\nObejmuje wiele kratek. block.phase-wall.description = Ściana pokryta specjalną mieszanką opartą o Włókna Fazowe, która odbija większość pocisków. @@ -1164,7 +1185,7 @@ block.phase-conduit.description = Zaawansowany blok do przenoszenia cieczy. Uży block.power-node.description = Przesyła moc do połączonych węzłów. Można podłączyć do czterech źródeł zasilania, zlewów lub węzłów. Zasila też bloki które go dotykają. block.power-node-large.description = Posiada większy zasięg niż zwykły węzeł prądu. Można podłączyć do sześciu źródeł zasilania, zlewów lub węzłów. block.surge-tower.description = Węzęł prądu z bardzo dużym zasięgiem, posiadający mniej możliwych podłączeń. -block.diode.description = Prąd baterii może tylko przepłynąc przez ten blok w jedną strone, jeśli druga strona ma mniej prądu. +block.diode.description = Energia może przepływać przez ten blok tylko w jednym kierunku, ale tylko kiedy inne strony mają zmagazynowane mniej energii. block.battery.description = Przechowuje energię przy nadwyżce produkcji oraz dostarcza energię kiedy jest jej brak, dopóki jest w niej miejsce. block.battery-large.description = Przechowuje o wiele wiecej prądu niż standardowa bateria. block.combustion-generator.description = Wytwarza energię poprzez spalanie łatwopalnych materiałów. @@ -1205,7 +1226,7 @@ block.ripple.description = Duża wieża artyleryjska, która strzela jednocześn block.cyclone.description = Duża szybkostrzelna wieża. block.spectre.description = Duże działo dwulufowe, które strzela potężnymi pociskami przebijającymi pancerz w jednostki naziemne i powietrzne. block.meltdown.description = Duże działo laserowe, które strzela potężnymi wiązkami dalekiego zasięgu. Wymaga chłodzenia. -block.command-center.description = Wydaje polecenia ruchu sojuszniczym jednostkom na całej mapie.\nPowoduje patrolowanie jednostek, atakowanie wrogiego rdzenia lub wycofanie się do rdzenia / fabryki. Gdy nie ma rdzenia wroga, jednostki będą domyślnie patrolować pod dowództwem ataku. +block.command-center.description = Wydaje polecenia ruchu sojuszniczym jednostkom na całej mapie.\nPowoduje patrolowanie jednostek, atakowanie wrogiego rdzenia lub wycofanie się do rdzenia/fabryki. Gdy nie ma rdzenia wroga, jednostki będą domyślnie patrolować pod dowództwem ataku. block.draug-factory.description = Produkuje drony wydobywcze Draug. block.spirit-factory.description = Produkuje lekkie drony, które naprawiają bloki. block.phantom-factory.description = Produkuje zaawansowane drony które pomagają przy budowie. @@ -1217,7 +1238,7 @@ block.crawler-factory.description = Produkuje szybkie jednostki lądowe typu "ka block.titan-factory.description = Produkuje zaawansowane, opancerzone jednostki lądowe. block.fortress-factory.description = Produkuje naziemne jednostki ciężkiej artylerii. block.repair-point.description = Bez przerw ulecza najbliższą zniszczoną jednostkę w jego zasięgu. -block.dart-mech-pad.description = Umożliwia transformacje w podstawowego mecha bojowego.\nUżyj klikając podczas stania na nim. +block.dart-mech-pad.description = Umożliwia transformację w podstawowego mecha bojowego.\nUżyj klikając podczas stania na nim. block.delta-mech-pad.description = Opuść swój obecny statek i zamień go na szybki, lekko opancerzony mech stworzony do ataków typu uderz-uciekaj.\nUżyj, klikając dwukrotnie podczas stania na lądowisku. block.tau-mech-pad.description = Opuść swój obecny statek i zamień go na mech wsparcia który może leczyć sojusznicze struktury i jednostki.\nUżyj, klikając dwukrotnie podczas stania na lądowisku. block.omega-mech-pad.description = Opuść swój obecny statek i zamień go na masywny, dobrze opancerzony mech, przeznaczony do ataków na froncie.\nUżyj, klikając dwukrotnie podczas stania na lądowisku. From a78c0defc77f41fff883babc35b74a0062231604 Mon Sep 17 00:00:00 2001 From: Anuken Date: Tue, 31 Dec 2019 10:29:18 -0500 Subject: [PATCH 59/78] Fixed #1289 --- core/src/mindustry/core/Logic.java | 4 ++-- server/src/mindustry/server/ServerControl.java | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/core/src/mindustry/core/Logic.java b/core/src/mindustry/core/Logic.java index e7c84adbc8..7d5419a912 100644 --- a/core/src/mindustry/core/Logic.java +++ b/core/src/mindustry/core/Logic.java @@ -47,8 +47,8 @@ public class Logic implements ApplicationListener{ //blocks that get broken are appended to the team's broken block queue Tile tile = event.tile; Block block = tile.block(); - //skip null entities or nukes, for obvious reasons - if(tile.entity == null || tile.block() instanceof NuclearReactor) return; + //skip null entities or nukes, for obvious reasons; also skip client since they can't modify these requests + if(tile.entity == null || tile.block() instanceof NuclearReactor || net.client()) return; if(block instanceof BuildBlock){ diff --git a/server/src/mindustry/server/ServerControl.java b/server/src/mindustry/server/ServerControl.java index f78f6fbab9..8d2feb74b0 100644 --- a/server/src/mindustry/server/ServerControl.java +++ b/server/src/mindustry/server/ServerControl.java @@ -190,7 +190,7 @@ public class ServerControl implements ApplicationListener{ }); handler.register("version", "Displays server version info.", arg -> { - info("&lmVersion: &lyMindustry {0}-{1} {2} / build {3}", Version.number, Version.modifier, Version.type, Version.build); + info("&lmVersion: &lyMindustry {0}-{1} {2} / build {3}", Version.number, Version.modifier, Version.type, Version.build + (Version.revision == 0 ? "" : "." + Version.revision)); info("&lmJava Version: &ly{0}", System.getProperty("java.version")); }); From 7a29877a2d7f154195ef1ea9d352dfadc2073a15 Mon Sep 17 00:00:00 2001 From: Anuken Date: Tue, 31 Dec 2019 19:19:04 -0500 Subject: [PATCH 60/78] Bugfixes --- core/src/mindustry/entities/type/Unit.java | 2 +- .../mindustry/world/blocks/production/GenericCrafter.java | 8 -------- gradle.properties | 2 +- 3 files changed, 2 insertions(+), 10 deletions(-) diff --git a/core/src/mindustry/entities/type/Unit.java b/core/src/mindustry/entities/type/Unit.java index ab02f24c83..6a037d6f36 100644 --- a/core/src/mindustry/entities/type/Unit.java +++ b/core/src/mindustry/entities/type/Unit.java @@ -226,7 +226,7 @@ public abstract class Unit extends DestructibleEntity implements SaveTrait, Targ float radScl = 1.5f; for(Unit en : arr){ - if(en.isFlying() != isFlying() || (en instanceof Player && en.getTeam() != getTeam())) continue; + if(en.isFlying() != isFlying() || (en instanceof Player && en.getTeam() != getTeam()) || (this instanceof Player && en.isFlying())) continue; float dst = dst(en); float scl = Mathf.clamp(1f - dst / (getSize()/(radScl*2f) + en.getSize()/(radScl*2f))); moveVector.add(Tmp.v1.set((x - en.x) * scl, (y - en.y) * scl).limit(0.4f)); diff --git a/core/src/mindustry/world/blocks/production/GenericCrafter.java b/core/src/mindustry/world/blocks/production/GenericCrafter.java index 7261effb4c..ee0e9a3c30 100644 --- a/core/src/mindustry/world/blocks/production/GenericCrafter.java +++ b/core/src/mindustry/world/blocks/production/GenericCrafter.java @@ -149,14 +149,6 @@ public class GenericCrafter extends Block{ return itemCapacity; } - public Item outputItem(){ - return outputItem == null ? null : outputItem.item; - } - - public Liquid outputLiquid(){ - return outputLiquid == null ? null : outputLiquid.liquid; - } - public static class GenericCrafterEntity extends TileEntity{ public float progress; public float totalProgress; diff --git a/gradle.properties b/gradle.properties index 40485198b7..aa36264bb8 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,3 +1,3 @@ org.gradle.daemon=true org.gradle.jvmargs=-Xms256m -Xmx1024m -archash=4882a25c74ada2c0aff9dbcf2cef0ab1b7936b67 +archash=7bfc46fe8c7810fbef1b6f6bbb19c8b999856813 From fdee9c7b50d4dd7880d0b4a26e7daec341f9b9d3 Mon Sep 17 00:00:00 2001 From: Anuken Date: Wed, 1 Jan 2020 10:45:02 -0500 Subject: [PATCH 61/78] Update README.md --- README.md | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 555f3b3e09..0dbca644f0 100644 --- a/README.md +++ b/README.md @@ -49,11 +49,6 @@ If the terminal returns `Permission denied` or `Command not found` on Mac/Linux, Gradle may take up to several minutes to download files. Be patient.
After building, the output .JAR file should be in `/desktop/build/libs/Mindustry.jar` for desktop builds, and in `/server/build/libs/server-release.jar` for server builds. -### Feature Requests - -[![Feature Requests](https://feathub.com/Anuken/Mindustry?format=svg)](https://feathub.com/Anuken/Mindustry) - - ### Downloads [Get it on F-Droid](https://f-droid.org/packages/io.anuke.mindustry/) + +### Feature Requests + +[![Feature Requests](https://feathub.com/Anuken/Mindustry?format=svg)](https://feathub.com/Anuken/Mindustry) From ddb0d7eff2127da55cc80013fc80dad11751015c Mon Sep 17 00:00:00 2001 From: Anuken Date: Wed, 1 Jan 2020 12:16:23 -0500 Subject: [PATCH 62/78] Fixed #1304 --- core/src/mindustry/mod/ContentParser.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/src/mindustry/mod/ContentParser.java b/core/src/mindustry/mod/ContentParser.java index 3ea54d6160..aa6048d833 100644 --- a/core/src/mindustry/mod/ContentParser.java +++ b/core/src/mindustry/mod/ContentParser.java @@ -333,8 +333,8 @@ public class ContentParser{ } private void readBundle(ContentType type, String name, JsonValue value){ - UnlockableContent cont = Vars.content.getByName(type, name) instanceof UnlockableContent ? - Vars.content.getByName(type, name) : null; + UnlockableContent cont = locate(type, name) instanceof UnlockableContent ? + locate(type, name) : null; String entryName = cont == null ? type + "." + currentMod.name + "-" + name + "." : type + "." + cont.name + "."; I18NBundle bundle = Core.bundle; From 70e6e52eba4ac61adc5d2ad48e08c8890d5a3965 Mon Sep 17 00:00:00 2001 From: Anuken Date: Thu, 2 Jan 2020 14:04:12 -0500 Subject: [PATCH 63/78] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0dbca644f0..2f0cab8ff3 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ See [CONTRIBUTING](CONTRIBUTING.md). Bleeding-edge live builds are generated automatically for every commit. You can see them [here](https://github.com/Anuken/MindustryBuilds/releases). Old builds might still be on [jenkins](https://jenkins.hellomouse.net/job/mindustry/). If you'd rather compile on your own, follow these instructions. -First, make sure you have [Java 8](https://www.java.com/en/download/) and [JDK 8](https://adoptopenjdk.net/) installed. Open a terminal in the root directory, `cd` to the Mindustry folder and run the following commands: +First, make sure you have [JDK 8](https://adoptopenjdk.net/) installed. Open a terminal in the root directory, `cd` to the Mindustry folder and run the following commands: #### Windows From d161ba442f5fb3262acca1431e3d12bed76cde01 Mon Sep 17 00:00:00 2001 From: KSean222 <44050761+KSean222@users.noreply.github.com> Date: Fri, 3 Jan 2020 05:07:38 +1000 Subject: [PATCH 64/78] Set primitive wrapping to false for scripts (#1302) * Set primitive wrapping to false for scripts * Added one newline cause why not --- core/src/mindustry/mod/Scripts.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/src/mindustry/mod/Scripts.java b/core/src/mindustry/mod/Scripts.java index 7a39b774a7..5ac96fbb0a 100644 --- a/core/src/mindustry/mod/Scripts.java +++ b/core/src/mindustry/mod/Scripts.java @@ -21,7 +21,8 @@ public class Scripts implements Disposable{ context.setClassShutter(type -> (ClassAccess.allowedClassNames.contains(type) || type.startsWith("$Proxy") || type.startsWith("adapter") || type.contains("PrintStream") || type.startsWith("mindustry")) && !type.equals("mindustry.mod.ClassAccess")); - + context.getWrapFactory().setJavaPrimitiveWrap(false); + scope = new ImporterTopLevel(context); wrapper = Core.files.internal("scripts/wrapper.js").readString(); From cb76e8083635545ddf999fd71069f292f46c8166 Mon Sep 17 00:00:00 2001 From: Anuken Date: Thu, 2 Jan 2020 14:08:41 -0500 Subject: [PATCH 65/78] Bugfixes --- core/src/mindustry/input/MobileInput.java | 4 +++- core/src/mindustry/mod/ClassAccess.java | 2 +- core/src/mindustry/world/blocks/BuildBlock.java | 2 +- gradle.properties | 2 +- tools/src/mindustry/tools/ScriptStubGenerator.java | 3 ++- 5 files changed, 8 insertions(+), 5 deletions(-) diff --git a/core/src/mindustry/input/MobileInput.java b/core/src/mindustry/input/MobileInput.java index 81f657c876..3b8e881085 100644 --- a/core/src/mindustry/input/MobileInput.java +++ b/core/src/mindustry/input/MobileInput.java @@ -439,10 +439,12 @@ public class MobileInput extends InputHandler implements GestureListener{ @Override public boolean touchDown(int screenX, int screenY, int pointer, KeyCode button){ - if(state.is(State.menu) || player.isDead()) return false; + if(state.is(State.menu)) return false; down = true; + if(player.isDead()) return false; + //get tile on cursor Tile cursor = tileAt(screenX, screenY); diff --git a/core/src/mindustry/mod/ClassAccess.java b/core/src/mindustry/mod/ClassAccess.java index 2d1e32cfad..7046227686 100644 --- a/core/src/mindustry/mod/ClassAccess.java +++ b/core/src/mindustry/mod/ClassAccess.java @@ -3,5 +3,5 @@ package mindustry.mod; import arc.struct.*; //obviously autogenerated, do not touch public class ClassAccess{ - public static final ObjectSet allowedClassNames = ObjectSet.with("arc.Core", "arc.func.Boolc", "arc.func.Boolf", "arc.func.Boolf2", "arc.func.Boolp", "arc.func.Cons", "arc.func.Cons2", "arc.func.Floatc", "arc.func.Floatc2", "arc.func.Floatc4", "arc.func.Floatf", "arc.func.Floatp", "arc.func.Func", "arc.func.Func2", "arc.func.Func3", "arc.func.Intc", "arc.func.Intc2", "arc.func.Intc4", "arc.func.Intf", "arc.func.Intp", "arc.func.Prov", "arc.graphics.Color", "arc.graphics.Pixmap", "arc.graphics.Texture", "arc.graphics.TextureData", "arc.graphics.g2d.Draw", "arc.graphics.g2d.Fill", "arc.graphics.g2d.Lines", "arc.graphics.g2d.TextureAtlas", "arc.graphics.g2d.TextureAtlas$AtlasRegion", "arc.graphics.g2d.TextureRegion", "arc.math.Affine2", "arc.math.Angles", "arc.math.Angles", "arc.math.Angles$ParticleConsumer", "arc.math.CumulativeDistribution", "arc.math.CumulativeDistribution$CumulativeValue", "arc.math.DelaunayTriangulator", "arc.math.EarClippingTriangulator", "arc.math.Extrapolator", "arc.math.FloatCounter", "arc.math.Interpolation", "arc.math.Interpolation$Bounce", "arc.math.Interpolation$BounceIn", "arc.math.Interpolation$BounceOut", "arc.math.Interpolation$Elastic", "arc.math.Interpolation$ElasticIn", "arc.math.Interpolation$ElasticOut", "arc.math.Interpolation$Exp", "arc.math.Interpolation$ExpIn", "arc.math.Interpolation$ExpOut", "arc.math.Interpolation$Pow", "arc.math.Interpolation$PowIn", "arc.math.Interpolation$PowOut", "arc.math.Interpolation$Swing", "arc.math.Interpolation$SwingIn", "arc.math.Interpolation$SwingOut", "arc.math.Mathf", "arc.math.Mathf", "arc.math.Matrix3", "arc.math.WindowedMean", "arc.math.geom.BSpline", "arc.math.geom.Bezier", "arc.math.geom.Bresenham2", "arc.math.geom.CatmullRomSpline", "arc.math.geom.Circle", "arc.math.geom.ConvexHull", "arc.math.geom.Ellipse", "arc.math.geom.FixedPosition", "arc.math.geom.Geometry", "arc.math.geom.Geometry$Raycaster", "arc.math.geom.Geometry$SolidChecker", "arc.math.geom.Intersector", "arc.math.geom.Intersector$MinimumTranslationVector", "arc.math.geom.Path", "arc.math.geom.Point2", "arc.math.geom.Point3", "arc.math.geom.Polygon", "arc.math.geom.Polyline", "arc.math.geom.Position", "arc.math.geom.QuadTree", "arc.math.geom.QuadTree$QuadTreeObject", "arc.math.geom.Rect", "arc.math.geom.Shape2D", "arc.math.geom.Spring1D", "arc.math.geom.Spring2D", "arc.math.geom.Vec2", "arc.math.geom.Vec3", "arc.math.geom.Vector", "arc.scene.Action", "arc.scene.Element", "arc.scene.Group", "arc.scene.Scene", "arc.scene.actions.Actions", "arc.scene.actions.AddAction", "arc.scene.actions.AddListenerAction", "arc.scene.actions.AfterAction", "arc.scene.actions.AlphaAction", "arc.scene.actions.ColorAction", "arc.scene.actions.DelayAction", "arc.scene.actions.DelegateAction", "arc.scene.actions.FloatAction", "arc.scene.actions.IntAction", "arc.scene.actions.LayoutAction", "arc.scene.actions.MoveByAction", "arc.scene.actions.MoveToAction", "arc.scene.actions.OriginAction", "arc.scene.actions.ParallelAction", "arc.scene.actions.RelativeTemporalAction", "arc.scene.actions.RemoveAction", "arc.scene.actions.RemoveActorAction", "arc.scene.actions.RemoveListenerAction", "arc.scene.actions.RepeatAction", "arc.scene.actions.RotateByAction", "arc.scene.actions.RotateToAction", "arc.scene.actions.RunnableAction", "arc.scene.actions.ScaleByAction", "arc.scene.actions.ScaleToAction", "arc.scene.actions.SequenceAction", "arc.scene.actions.SizeByAction", "arc.scene.actions.SizeToAction", "arc.scene.actions.TemporalAction", "arc.scene.actions.TimeScaleAction", "arc.scene.actions.TouchableAction", "arc.scene.actions.TranslateByAction", "arc.scene.actions.VisibleAction", "arc.scene.event.ChangeListener", "arc.scene.event.ChangeListener$ChangeEvent", "arc.scene.event.ClickListener", "arc.scene.event.DragListener", "arc.scene.event.DragScrollListener", "arc.scene.event.ElementGestureListener", "arc.scene.event.EventListener", "arc.scene.event.FocusListener", "arc.scene.event.FocusListener$FocusEvent", "arc.scene.event.FocusListener$FocusEvent$Type", "arc.scene.event.HandCursorListener", "arc.scene.event.IbeamCursorListener", "arc.scene.event.InputEvent", "arc.scene.event.InputEvent$Type", "arc.scene.event.InputListener", "arc.scene.event.SceneEvent", "arc.scene.event.Touchable", "arc.scene.event.VisibilityEvent", "arc.scene.event.VisibilityListener", "arc.scene.style.BaseDrawable", "arc.scene.style.Drawable", "arc.scene.style.NinePatchDrawable", "arc.scene.style.ScaledNinePatchDrawable", "arc.scene.style.Style", "arc.scene.style.TextureRegionDrawable", "arc.scene.style.TiledDrawable", "arc.scene.style.TransformDrawable", "arc.scene.ui.Button", "arc.scene.ui.Button$ButtonStyle", "arc.scene.ui.ButtonGroup", "arc.scene.ui.CheckBox", "arc.scene.ui.CheckBox$CheckBoxStyle", "arc.scene.ui.ColorImage", "arc.scene.ui.Dialog", "arc.scene.ui.Dialog$DialogStyle", "arc.scene.ui.Image", "arc.scene.ui.ImageButton", "arc.scene.ui.ImageButton$ImageButtonStyle", "arc.scene.ui.KeybindDialog", "arc.scene.ui.KeybindDialog$KeybindDialogStyle", "arc.scene.ui.Label", "arc.scene.ui.Label$LabelStyle", "arc.scene.ui.ProgressBar", "arc.scene.ui.ProgressBar$ProgressBarStyle", "arc.scene.ui.ScrollPane", "arc.scene.ui.ScrollPane$ScrollPaneStyle", "arc.scene.ui.SettingsDialog", "arc.scene.ui.SettingsDialog$SettingsTable", "arc.scene.ui.SettingsDialog$SettingsTable$CheckSetting", "arc.scene.ui.SettingsDialog$SettingsTable$Setting", "arc.scene.ui.SettingsDialog$SettingsTable$SliderSetting", "arc.scene.ui.SettingsDialog$StringProcessor", "arc.scene.ui.Slider", "arc.scene.ui.Slider$SliderStyle", "arc.scene.ui.TextArea", "arc.scene.ui.TextArea$TextAreaListener", "arc.scene.ui.TextButton", "arc.scene.ui.TextButton$TextButtonStyle", "arc.scene.ui.TextField", "arc.scene.ui.TextField$DefaultOnscreenKeyboard", "arc.scene.ui.TextField$OnscreenKeyboard", "arc.scene.ui.TextField$TextFieldClickListener", "arc.scene.ui.TextField$TextFieldFilter", "arc.scene.ui.TextField$TextFieldListener", "arc.scene.ui.TextField$TextFieldStyle", "arc.scene.ui.TextField$TextFieldValidator", "arc.scene.ui.Tooltip", "arc.scene.ui.Tooltip$Tooltips", "arc.scene.ui.Touchpad", "arc.scene.ui.Touchpad$TouchpadStyle", "arc.scene.ui.TreeElement", "arc.scene.ui.TreeElement$Node", "arc.scene.ui.TreeElement$TreeStyle", "arc.scene.ui.layout.Cell", "arc.scene.ui.layout.Collapser", "arc.scene.ui.layout.HorizontalGroup", "arc.scene.ui.layout.Scl", "arc.scene.ui.layout.Stack", "arc.scene.ui.layout.Table", "arc.scene.ui.layout.Table$DrawRect", "arc.scene.ui.layout.VerticalGroup", "arc.scene.ui.layout.WidgetGroup", "arc.scene.utils.ArraySelection", "arc.scene.utils.Cullable", "arc.scene.utils.Disableable", "arc.scene.utils.DragAndDrop", "arc.scene.utils.DragAndDrop$Payload", "arc.scene.utils.DragAndDrop$Source", "arc.scene.utils.DragAndDrop$Target", "arc.scene.utils.Elements", "arc.scene.utils.Layout", "arc.scene.utils.Selection", "arc.struct.Array", "arc.struct.Array$ArrayIterable", "arc.struct.ArrayMap", "arc.struct.ArrayMap$Entries", "arc.struct.ArrayMap$Keys", "arc.struct.ArrayMap$Values", "arc.struct.AtomicQueue", "arc.struct.BinaryHeap", "arc.struct.BinaryHeap$Node", "arc.struct.Bits", "arc.struct.BooleanArray", "arc.struct.ByteArray", "arc.struct.CharArray", "arc.struct.ComparableTimSort", "arc.struct.DelayedRemovalArray", "arc.struct.EnumSet", "arc.struct.EnumSet$EnumSetIterator", "arc.struct.FloatArray", "arc.struct.GridBits", "arc.struct.GridMap", "arc.struct.IdentityMap", "arc.struct.IdentityMap$Entries", "arc.struct.IdentityMap$Entry", "arc.struct.IdentityMap$Keys", "arc.struct.IdentityMap$Values", "arc.struct.IntArray", "arc.struct.IntFloatMap", "arc.struct.IntFloatMap$Entries", "arc.struct.IntFloatMap$Entry", "arc.struct.IntFloatMap$Keys", "arc.struct.IntFloatMap$Values", "arc.struct.IntIntMap", "arc.struct.IntIntMap$Entries", "arc.struct.IntIntMap$Entry", "arc.struct.IntIntMap$Keys", "arc.struct.IntIntMap$Values", "arc.struct.IntMap", "arc.struct.IntMap$Entries", "arc.struct.IntMap$Entry", "arc.struct.IntMap$Keys", "arc.struct.IntMap$Values", "arc.struct.IntQueue", "arc.struct.IntSet", "arc.struct.IntSet$IntSetIterator", "arc.struct.LongArray", "arc.struct.LongMap", "arc.struct.LongMap$Entries", "arc.struct.LongMap$Entry", "arc.struct.LongMap$Keys", "arc.struct.LongMap$Values", "arc.struct.LongQueue", "arc.struct.ObjectFloatMap", "arc.struct.ObjectFloatMap$Entries", "arc.struct.ObjectFloatMap$Entry", "arc.struct.ObjectFloatMap$Keys", "arc.struct.ObjectFloatMap$Values", "arc.struct.ObjectIntMap", "arc.struct.ObjectIntMap$Entries", "arc.struct.ObjectIntMap$Entry", "arc.struct.ObjectIntMap$Keys", "arc.struct.ObjectIntMap$Values", "arc.struct.ObjectMap", "arc.struct.ObjectMap$Entries", "arc.struct.ObjectMap$Entry", "arc.struct.ObjectMap$Keys", "arc.struct.ObjectMap$Values", "arc.struct.ObjectSet", "arc.struct.ObjectSet$ObjectSetIterator", "arc.struct.OrderedMap", "arc.struct.OrderedMap$OrderedMapEntries", "arc.struct.OrderedMap$OrderedMapKeys", "arc.struct.OrderedMap$OrderedMapValues", "arc.struct.OrderedSet", "arc.struct.OrderedSet$OrderedSetIterator", "arc.struct.PooledLinkedList", "arc.struct.PooledLinkedList$Item", "arc.struct.Queue", "arc.struct.Queue$QueueIterable", "arc.struct.ShortArray", "arc.struct.SnapshotArray", "arc.struct.Sort", "arc.struct.SortedIntList", "arc.struct.SortedIntList$Iterator", "arc.struct.SortedIntList$Node", "arc.struct.StringMap", "arc.struct.TimSort", "arc.util.I18NBundle", "arc.util.Interval", "arc.util.Time", "java.io.DataInput", "java.io.DataInputStream", "java.io.DataOutput", "java.io.DataOutputStream", "java.io.PrintStream", "java.lang.Object", "java.lang.Runnable", "java.lang.String", "java.lang.System", "mindustry.Vars", "mindustry.ai.BlockIndexer", "mindustry.ai.Pathfinder", "mindustry.ai.Pathfinder$PathData", "mindustry.ai.Pathfinder$PathTarget", "mindustry.ai.Pathfinder$PathTileStruct", "mindustry.ai.WaveSpawner", "mindustry.content.Blocks", "mindustry.content.Bullets", "mindustry.content.Fx", "mindustry.content.Items", "mindustry.content.Liquids", "mindustry.content.Loadouts", "mindustry.content.Mechs", "mindustry.content.StatusEffects", "mindustry.content.TechTree", "mindustry.content.TechTree$TechNode", "mindustry.content.TypeIDs", "mindustry.content.UnitTypes", "mindustry.content.Zones", "mindustry.core.ContentLoader", "mindustry.core.Control", "mindustry.core.FileTree", "mindustry.core.GameState", "mindustry.core.GameState$State", "mindustry.core.Logic", "mindustry.core.NetServer$TeamAssigner", "mindustry.core.Platform", "mindustry.core.Renderer", "mindustry.core.UI", "mindustry.core.Version", "mindustry.core.World", "mindustry.core.World$Raycaster", "mindustry.ctype.Content", "mindustry.ctype.Content$ModContentInfo", "mindustry.ctype.ContentList", "mindustry.ctype.ContentType", "mindustry.ctype.MappableContent", "mindustry.ctype.UnlockableContent", "mindustry.editor.DrawOperation", "mindustry.editor.DrawOperation$OpType", "mindustry.editor.DrawOperation$TileOpStruct", "mindustry.editor.EditorTile", "mindustry.editor.EditorTool", "mindustry.editor.MapEditor", "mindustry.editor.MapEditor$Context", "mindustry.editor.MapEditorDialog", "mindustry.editor.MapGenerateDialog", "mindustry.editor.MapInfoDialog", "mindustry.editor.MapLoadDialog", "mindustry.editor.MapRenderer", "mindustry.editor.MapResizeDialog", "mindustry.editor.MapSaveDialog", "mindustry.editor.MapView", "mindustry.editor.OperationStack", "mindustry.editor.WaveInfoDialog", "mindustry.entities.Damage", "mindustry.entities.Damage$PropCellStruct", "mindustry.entities.Effects", "mindustry.entities.Effects$Effect", "mindustry.entities.Effects$EffectContainer", "mindustry.entities.Effects$EffectProvider", "mindustry.entities.Effects$EffectRenderer", "mindustry.entities.Effects$ScreenshakeProvider", "mindustry.entities.Entities", "mindustry.entities.EntityCollisions", "mindustry.entities.EntityGroup", "mindustry.entities.Predict", "mindustry.entities.TargetPriority", "mindustry.entities.Units", "mindustry.entities.bullet.ArtilleryBulletType", "mindustry.entities.bullet.BasicBulletType", "mindustry.entities.bullet.BombBulletType", "mindustry.entities.bullet.BulletType", "mindustry.entities.bullet.FlakBulletType", "mindustry.entities.bullet.HealBulletType", "mindustry.entities.bullet.LiquidBulletType", "mindustry.entities.bullet.MassDriverBolt", "mindustry.entities.bullet.MissileBulletType", "mindustry.entities.effect.Decal", "mindustry.entities.effect.Fire", "mindustry.entities.effect.GroundEffectEntity", "mindustry.entities.effect.GroundEffectEntity$GroundEffect", "mindustry.entities.effect.ItemTransfer", "mindustry.entities.effect.Lightning", "mindustry.entities.effect.Puddle", "mindustry.entities.effect.RubbleDecal", "mindustry.entities.effect.ScorchDecal", "mindustry.entities.traits.AbsorbTrait", "mindustry.entities.traits.BelowLiquidTrait", "mindustry.entities.traits.BuilderMinerTrait", "mindustry.entities.traits.BuilderTrait", "mindustry.entities.traits.BuilderTrait$BuildDataStatic", "mindustry.entities.traits.BuilderTrait$BuildRequest", "mindustry.entities.traits.DamageTrait", "mindustry.entities.traits.DrawTrait", "mindustry.entities.traits.Entity", "mindustry.entities.traits.HealthTrait", "mindustry.entities.traits.KillerTrait", "mindustry.entities.traits.MinerTrait", "mindustry.entities.traits.MoveTrait", "mindustry.entities.traits.SaveTrait", "mindustry.entities.traits.Saveable", "mindustry.entities.traits.ScaleTrait", "mindustry.entities.traits.ShooterTrait", "mindustry.entities.traits.SolidTrait", "mindustry.entities.traits.SpawnerTrait", "mindustry.entities.traits.SyncTrait", "mindustry.entities.traits.TargetTrait", "mindustry.entities.traits.TeamTrait", "mindustry.entities.traits.TimeTrait", "mindustry.entities.traits.TypeTrait", "mindustry.entities.traits.VelocityTrait", "mindustry.entities.type.BaseEntity", "mindustry.entities.type.BaseUnit", "mindustry.entities.type.Bullet", "mindustry.entities.type.DestructibleEntity", "mindustry.entities.type.EffectEntity", "mindustry.entities.type.Player", "mindustry.entities.type.SolidEntity", "mindustry.entities.type.TileEntity", "mindustry.entities.type.TimedEntity", "mindustry.entities.type.Unit", "mindustry.entities.type.base.BaseDrone", "mindustry.entities.type.base.BuilderDrone", "mindustry.entities.type.base.FlyingUnit", "mindustry.entities.type.base.GroundUnit", "mindustry.entities.type.base.HoverUnit", "mindustry.entities.type.base.MinerDrone", "mindustry.entities.type.base.RepairDrone", "mindustry.entities.units.StateMachine", "mindustry.entities.units.Statuses", "mindustry.entities.units.Statuses$StatusEntry", "mindustry.entities.units.UnitCommand", "mindustry.entities.units.UnitDrops", "mindustry.entities.units.UnitState", "mindustry.game.DefaultWaves", "mindustry.game.Difficulty", "mindustry.game.EventType", "mindustry.game.EventType$BlockBuildBeginEvent", "mindustry.game.EventType$BlockBuildEndEvent", "mindustry.game.EventType$BlockDestroyEvent", "mindustry.game.EventType$BlockInfoEvent", "mindustry.game.EventType$BuildSelectEvent", "mindustry.game.EventType$ClientLoadEvent", "mindustry.game.EventType$CommandIssueEvent", "mindustry.game.EventType$ContentReloadEvent", "mindustry.game.EventType$CoreItemDeliverEvent", "mindustry.game.EventType$DepositEvent", "mindustry.game.EventType$DisposeEvent", "mindustry.game.EventType$GameOverEvent", "mindustry.game.EventType$LaunchEvent", "mindustry.game.EventType$LaunchItemEvent", "mindustry.game.EventType$LineConfirmEvent", "mindustry.game.EventType$LoseEvent", "mindustry.game.EventType$MapMakeEvent", "mindustry.game.EventType$MapPublishEvent", "mindustry.game.EventType$MechChangeEvent", "mindustry.game.EventType$PlayEvent", "mindustry.game.EventType$PlayerBanEvent", "mindustry.game.EventType$PlayerChatEvent", "mindustry.game.EventType$PlayerConnect", "mindustry.game.EventType$PlayerIpBanEvent", "mindustry.game.EventType$PlayerIpUnbanEvent", "mindustry.game.EventType$PlayerJoin", "mindustry.game.EventType$PlayerLeave", "mindustry.game.EventType$PlayerUnbanEvent", "mindustry.game.EventType$ResearchEvent", "mindustry.game.EventType$ResetEvent", "mindustry.game.EventType$ResizeEvent", "mindustry.game.EventType$ServerLoadEvent", "mindustry.game.EventType$StateChangeEvent", "mindustry.game.EventType$TapConfigEvent", "mindustry.game.EventType$TapEvent", "mindustry.game.EventType$TileChangeEvent", "mindustry.game.EventType$Trigger", "mindustry.game.EventType$TurretAmmoDeliverEvent", "mindustry.game.EventType$UnitCreateEvent", "mindustry.game.EventType$UnitDestroyEvent", "mindustry.game.EventType$UnlockEvent", "mindustry.game.EventType$WaveEvent", "mindustry.game.EventType$WinEvent", "mindustry.game.EventType$WithdrawEvent", "mindustry.game.EventType$WorldLoadEvent", "mindustry.game.EventType$ZoneConfigureCompleteEvent", "mindustry.game.EventType$ZoneRequireCompleteEvent", "mindustry.game.Gamemode", "mindustry.game.GlobalData", "mindustry.game.LoopControl", "mindustry.game.MusicControl", "mindustry.game.Objective", "mindustry.game.Objectives", "mindustry.game.Objectives$Launched", "mindustry.game.Objectives$Unlock", "mindustry.game.Objectives$Wave", "mindustry.game.Objectives$ZoneObjective", "mindustry.game.Objectives$ZoneWave", "mindustry.game.Rules", "mindustry.game.Saves", "mindustry.game.Saves$SaveSlot", "mindustry.game.Schematic", "mindustry.game.Schematic$Stile", "mindustry.game.Schematics", "mindustry.game.SoundLoop", "mindustry.game.SpawnGroup", "mindustry.game.Stats", "mindustry.game.Stats$Rank", "mindustry.game.Stats$RankResult", "mindustry.game.Team", "mindustry.game.Teams", "mindustry.game.Teams$BrokenBlock", "mindustry.game.Teams$TeamData", "mindustry.game.Tutorial", "mindustry.game.Tutorial$TutorialStage", "mindustry.gen.BufferItem", "mindustry.gen.Call", "mindustry.gen.Call", "mindustry.gen.Icon", "mindustry.gen.Icon", "mindustry.gen.MethodHash", "mindustry.gen.Musics", "mindustry.gen.Musics", "mindustry.gen.PathTile", "mindustry.gen.PropCell", "mindustry.gen.RemoteReadClient", "mindustry.gen.RemoteReadServer", "mindustry.gen.Serialization", "mindustry.gen.Sounds", "mindustry.gen.Sounds", "mindustry.gen.Tex", "mindustry.gen.Tex", "mindustry.gen.TileOp", "mindustry.graphics.BlockRenderer", "mindustry.graphics.Bloom", "mindustry.graphics.CacheLayer", "mindustry.graphics.Drawf", "mindustry.graphics.FloorRenderer", "mindustry.graphics.IndexedRenderer", "mindustry.graphics.Layer", "mindustry.graphics.LightRenderer", "mindustry.graphics.MenuRenderer", "mindustry.graphics.MinimapRenderer", "mindustry.graphics.MultiPacker", "mindustry.graphics.MultiPacker$PageType", "mindustry.graphics.OverlayRenderer", "mindustry.graphics.Pal", "mindustry.graphics.Pixelator", "mindustry.graphics.Shaders", "mindustry.input.Binding", "mindustry.input.DesktopInput", "mindustry.input.InputHandler", "mindustry.input.InputHandler$PlaceLine", "mindustry.input.MobileInput", "mindustry.input.PlaceMode", "mindustry.input.Placement", "mindustry.input.Placement$DistanceHeuristic", "mindustry.input.Placement$NormalizeDrawResult", "mindustry.input.Placement$NormalizeResult", "mindustry.input.Placement$TileHueristic", "mindustry.maps.Map", "mindustry.maps.Maps", "mindustry.maps.Maps$MapProvider", "mindustry.maps.Maps$ShuffleMode", "mindustry.maps.Maps$ShuffleMode", "mindustry.maps.filters.BlendFilter", "mindustry.maps.filters.ClearFilter", "mindustry.maps.filters.DistortFilter", "mindustry.maps.filters.FilterOption", "mindustry.maps.filters.FilterOption$BlockOption", "mindustry.maps.filters.FilterOption$SliderOption", "mindustry.maps.filters.GenerateFilter", "mindustry.maps.filters.GenerateFilter$GenerateInput", "mindustry.maps.filters.GenerateFilter$GenerateInput$TileProvider", "mindustry.maps.filters.MedianFilter", "mindustry.maps.filters.MirrorFilter", "mindustry.maps.filters.NoiseFilter", "mindustry.maps.filters.OreFilter", "mindustry.maps.filters.OreMedianFilter", "mindustry.maps.filters.RiverNoiseFilter", "mindustry.maps.filters.ScatterFilter", "mindustry.maps.filters.TerrainFilter", "mindustry.maps.generators.BasicGenerator", "mindustry.maps.generators.BasicGenerator$DistanceHeuristic", "mindustry.maps.generators.BasicGenerator$TileHueristic", "mindustry.maps.generators.Generator", "mindustry.maps.generators.MapGenerator", "mindustry.maps.generators.MapGenerator$Decoration", "mindustry.maps.generators.RandomGenerator", "mindustry.maps.zonegen.DesertWastesGenerator", "mindustry.maps.zonegen.OvergrowthGenerator", "mindustry.type.Category", "mindustry.type.ErrorContent", "mindustry.type.Item", "mindustry.type.ItemStack", "mindustry.type.ItemType", "mindustry.type.Liquid", "mindustry.type.LiquidStack", "mindustry.type.Mech", "mindustry.type.Publishable", "mindustry.type.StatusEffect", "mindustry.type.StatusEffect$TransitionHandler", "mindustry.type.TypeID", "mindustry.type.UnitType", "mindustry.type.Weapon", "mindustry.type.WeatherEvent", "mindustry.type.Zone", "mindustry.ui.Bar", "mindustry.ui.BorderImage", "mindustry.ui.Cicon", "mindustry.ui.ContentDisplay", "mindustry.ui.Fonts", "mindustry.ui.GridImage", "mindustry.ui.IconSize", "mindustry.ui.IntFormat", "mindustry.ui.ItemDisplay", "mindustry.ui.ItemImage", "mindustry.ui.ItemsDisplay", "mindustry.ui.Links", "mindustry.ui.Links$LinkEntry", "mindustry.ui.LiquidDisplay", "mindustry.ui.Minimap", "mindustry.ui.MobileButton", "mindustry.ui.MultiReqImage", "mindustry.ui.ReqImage", "mindustry.ui.Styles", "mindustry.ui.dialogs.AboutDialog", "mindustry.ui.dialogs.AdminsDialog", "mindustry.ui.dialogs.BansDialog", "mindustry.ui.dialogs.ColorPicker", "mindustry.ui.dialogs.ContentInfoDialog", "mindustry.ui.dialogs.ControlsDialog", "mindustry.ui.dialogs.CustomGameDialog", "mindustry.ui.dialogs.CustomRulesDialog", "mindustry.ui.dialogs.DatabaseDialog", "mindustry.ui.dialogs.DeployDialog", "mindustry.ui.dialogs.DeployDialog$View", "mindustry.ui.dialogs.DeployDialog$ZoneNode", "mindustry.ui.dialogs.DiscordDialog", "mindustry.ui.dialogs.FileChooser", "mindustry.ui.dialogs.FileChooser$FileHistory", "mindustry.ui.dialogs.FloatingDialog", "mindustry.ui.dialogs.GameOverDialog", "mindustry.ui.dialogs.HostDialog", "mindustry.ui.dialogs.JoinDialog", "mindustry.ui.dialogs.JoinDialog$Server", "mindustry.ui.dialogs.LanguageDialog", "mindustry.ui.dialogs.LoadDialog", "mindustry.ui.dialogs.LoadoutDialog", "mindustry.ui.dialogs.MapPlayDialog", "mindustry.ui.dialogs.MapsDialog", "mindustry.ui.dialogs.MinimapDialog", "mindustry.ui.dialogs.ModsDialog", "mindustry.ui.dialogs.PaletteDialog", "mindustry.ui.dialogs.PausedDialog", "mindustry.ui.dialogs.SaveDialog", "mindustry.ui.dialogs.SchematicsDialog", "mindustry.ui.dialogs.SchematicsDialog$SchematicImage", "mindustry.ui.dialogs.SchematicsDialog$SchematicInfoDialog", "mindustry.ui.dialogs.SettingsMenuDialog", "mindustry.ui.dialogs.TechTreeDialog", "mindustry.ui.dialogs.TechTreeDialog$LayoutNode", "mindustry.ui.dialogs.TechTreeDialog$TechTreeNode", "mindustry.ui.dialogs.TechTreeDialog$View", "mindustry.ui.dialogs.TraceDialog", "mindustry.ui.dialogs.ZoneInfoDialog", "mindustry.ui.fragments.BlockConfigFragment", "mindustry.ui.fragments.BlockInventoryFragment", "mindustry.ui.fragments.ChatFragment", "mindustry.ui.fragments.FadeInFragment", "mindustry.ui.fragments.Fragment", "mindustry.ui.fragments.HudFragment", "mindustry.ui.fragments.LoadingFragment", "mindustry.ui.fragments.MenuFragment", "mindustry.ui.fragments.OverlayFragment", "mindustry.ui.fragments.PlacementFragment", "mindustry.ui.fragments.PlayerListFragment", "mindustry.ui.fragments.ScriptConsoleFragment", "mindustry.ui.layout.BranchTreeLayout", "mindustry.ui.layout.BranchTreeLayout$TreeAlignment", "mindustry.ui.layout.BranchTreeLayout$TreeLocation", "mindustry.ui.layout.RadialTreeLayout", "mindustry.ui.layout.TreeLayout", "mindustry.ui.layout.TreeLayout$TreeNode", "mindustry.world.Block", "mindustry.world.BlockStorage", "mindustry.world.Build", "mindustry.world.CachedTile", "mindustry.world.DirectionalItemBuffer", "mindustry.world.DirectionalItemBuffer$BufferItemStruct", "mindustry.world.Edges", "mindustry.world.ItemBuffer", "mindustry.world.LegacyColorMapper", "mindustry.world.LegacyColorMapper$LegacyBlock", "mindustry.world.Pos", "mindustry.world.StaticTree", "mindustry.world.Tile", "mindustry.world.WorldContext", "mindustry.world.blocks.Attributes", "mindustry.world.blocks.Autotiler", "mindustry.world.blocks.Autotiler$AutotilerHolder", "mindustry.world.blocks.BlockPart", "mindustry.world.blocks.BuildBlock", "mindustry.world.blocks.BuildBlock$BuildEntity", "mindustry.world.blocks.DoubleOverlayFloor", "mindustry.world.blocks.Floor", "mindustry.world.blocks.ItemSelection", "mindustry.world.blocks.LiquidBlock", "mindustry.world.blocks.OreBlock", "mindustry.world.blocks.OverlayFloor", "mindustry.world.blocks.PowerBlock", "mindustry.world.blocks.RespawnBlock", "mindustry.world.blocks.Rock", "mindustry.world.blocks.StaticWall", "mindustry.world.blocks.TreeBlock", "mindustry.world.blocks.defense.DeflectorWall", "mindustry.world.blocks.defense.DeflectorWall$DeflectorEntity", "mindustry.world.blocks.defense.Door", "mindustry.world.blocks.defense.Door$DoorEntity", "mindustry.world.blocks.defense.ForceProjector", "mindustry.world.blocks.defense.ForceProjector$ForceEntity", "mindustry.world.blocks.defense.ForceProjector$ShieldEntity", "mindustry.world.blocks.defense.MendProjector", "mindustry.world.blocks.defense.MendProjector$MendEntity", "mindustry.world.blocks.defense.OverdriveProjector", "mindustry.world.blocks.defense.OverdriveProjector$OverdriveEntity", "mindustry.world.blocks.defense.ShockMine", "mindustry.world.blocks.defense.SurgeWall", "mindustry.world.blocks.defense.Wall", "mindustry.world.blocks.defense.turrets.ArtilleryTurret", "mindustry.world.blocks.defense.turrets.BurstTurret", "mindustry.world.blocks.defense.turrets.ChargeTurret", "mindustry.world.blocks.defense.turrets.ChargeTurret$LaserTurretEntity", "mindustry.world.blocks.defense.turrets.CooledTurret", "mindustry.world.blocks.defense.turrets.DoubleTurret", "mindustry.world.blocks.defense.turrets.ItemTurret", "mindustry.world.blocks.defense.turrets.ItemTurret$ItemEntry", "mindustry.world.blocks.defense.turrets.ItemTurret$ItemTurretEntity", "mindustry.world.blocks.defense.turrets.LaserTurret", "mindustry.world.blocks.defense.turrets.LaserTurret$LaserTurretEntity", "mindustry.world.blocks.defense.turrets.LiquidTurret", "mindustry.world.blocks.defense.turrets.PowerTurret", "mindustry.world.blocks.defense.turrets.Turret", "mindustry.world.blocks.defense.turrets.Turret$AmmoEntry", "mindustry.world.blocks.defense.turrets.Turret$TurretEntity", "mindustry.world.blocks.distribution.ArmoredConveyor", "mindustry.world.blocks.distribution.BufferedItemBridge", "mindustry.world.blocks.distribution.BufferedItemBridge$BufferedItemBridgeEntity", "mindustry.world.blocks.distribution.Conveyor", "mindustry.world.blocks.distribution.Conveyor$ConveyorEntity", "mindustry.world.blocks.distribution.Conveyor$ItemPos", "mindustry.world.blocks.distribution.ExtendingItemBridge", "mindustry.world.blocks.distribution.ItemBridge", "mindustry.world.blocks.distribution.ItemBridge$ItemBridgeEntity", "mindustry.world.blocks.distribution.Junction", "mindustry.world.blocks.distribution.Junction$JunctionEntity", "mindustry.world.blocks.distribution.MassDriver", "mindustry.world.blocks.distribution.MassDriver$DriverBulletData", "mindustry.world.blocks.distribution.MassDriver$DriverState", "mindustry.world.blocks.distribution.MassDriver$MassDriverEntity", "mindustry.world.blocks.distribution.OverflowGate", "mindustry.world.blocks.distribution.OverflowGate$OverflowGateEntity", "mindustry.world.blocks.distribution.Router", "mindustry.world.blocks.distribution.Router$RouterEntity", "mindustry.world.blocks.distribution.Sorter", "mindustry.world.blocks.distribution.Sorter$SorterEntity", "mindustry.world.blocks.liquid.ArmoredConduit", "mindustry.world.blocks.liquid.Conduit", "mindustry.world.blocks.liquid.Conduit$ConduitEntity", "mindustry.world.blocks.liquid.LiquidBridge", "mindustry.world.blocks.liquid.LiquidExtendingBridge", "mindustry.world.blocks.liquid.LiquidJunction", "mindustry.world.blocks.liquid.LiquidOverflowGate", "mindustry.world.blocks.liquid.LiquidRouter", "mindustry.world.blocks.liquid.LiquidTank", "mindustry.world.blocks.logic.LogicBlock", "mindustry.world.blocks.logic.MessageBlock", "mindustry.world.blocks.logic.MessageBlock$MessageBlockEntity", "mindustry.world.blocks.power.Battery", "mindustry.world.blocks.power.BurnerGenerator", "mindustry.world.blocks.power.ConditionalConsumePower", "mindustry.world.blocks.power.DecayGenerator", "mindustry.world.blocks.power.ImpactReactor", "mindustry.world.blocks.power.ImpactReactor$FusionReactorEntity", "mindustry.world.blocks.power.ItemLiquidGenerator", "mindustry.world.blocks.power.ItemLiquidGenerator$ItemLiquidGeneratorEntity", "mindustry.world.blocks.power.LightBlock", "mindustry.world.blocks.power.LightBlock$LightEntity", "mindustry.world.blocks.power.NuclearReactor", "mindustry.world.blocks.power.NuclearReactor$NuclearReactorEntity", "mindustry.world.blocks.power.PowerDiode", "mindustry.world.blocks.power.PowerDistributor", "mindustry.world.blocks.power.PowerGenerator", "mindustry.world.blocks.power.PowerGenerator$GeneratorEntity", "mindustry.world.blocks.power.PowerGraph", "mindustry.world.blocks.power.PowerNode", "mindustry.world.blocks.power.SingleTypeGenerator", "mindustry.world.blocks.power.SolarGenerator", "mindustry.world.blocks.power.ThermalGenerator", "mindustry.world.blocks.production.Cultivator", "mindustry.world.blocks.production.Cultivator$CultivatorEntity", "mindustry.world.blocks.production.Drill", "mindustry.world.blocks.production.Drill$DrillEntity", "mindustry.world.blocks.production.Fracker", "mindustry.world.blocks.production.Fracker$FrackerEntity", "mindustry.world.blocks.production.GenericCrafter", "mindustry.world.blocks.production.GenericCrafter$GenericCrafterEntity", "mindustry.world.blocks.production.GenericSmelter", "mindustry.world.blocks.production.Incinerator", "mindustry.world.blocks.production.Incinerator$IncineratorEntity", "mindustry.world.blocks.production.LiquidConverter", "mindustry.world.blocks.production.Pump", "mindustry.world.blocks.production.Separator", "mindustry.world.blocks.production.SolidPump", "mindustry.world.blocks.production.SolidPump$SolidPumpEntity", "mindustry.world.blocks.sandbox.ItemSource", "mindustry.world.blocks.sandbox.ItemSource$ItemSourceEntity", "mindustry.world.blocks.sandbox.ItemVoid", "mindustry.world.blocks.sandbox.LiquidSource", "mindustry.world.blocks.sandbox.LiquidSource$LiquidSourceEntity", "mindustry.world.blocks.sandbox.PowerSource", "mindustry.world.blocks.sandbox.PowerVoid", "mindustry.world.blocks.storage.CoreBlock", "mindustry.world.blocks.storage.CoreBlock$CoreEntity", "mindustry.world.blocks.storage.LaunchPad", "mindustry.world.blocks.storage.StorageBlock", "mindustry.world.blocks.storage.StorageBlock$StorageBlockEntity", "mindustry.world.blocks.storage.Unloader", "mindustry.world.blocks.storage.Unloader$UnloaderEntity", "mindustry.world.blocks.storage.Vault", "mindustry.world.blocks.units.CommandCenter", "mindustry.world.blocks.units.CommandCenter$CommandCenterEntity", "mindustry.world.blocks.units.MechPad", "mindustry.world.blocks.units.MechPad$MechFactoryEntity", "mindustry.world.blocks.units.RallyPoint", "mindustry.world.blocks.units.RepairPoint", "mindustry.world.blocks.units.RepairPoint$RepairPointEntity", "mindustry.world.blocks.units.UnitFactory", "mindustry.world.blocks.units.UnitFactory$UnitFactoryEntity", "mindustry.world.consumers.Consume", "mindustry.world.consumers.ConsumeItemFilter", "mindustry.world.consumers.ConsumeItems", "mindustry.world.consumers.ConsumeLiquid", "mindustry.world.consumers.ConsumeLiquidBase", "mindustry.world.consumers.ConsumeLiquidFilter", "mindustry.world.consumers.ConsumePower", "mindustry.world.consumers.ConsumeType", "mindustry.world.consumers.Consumers", "mindustry.world.meta.Attribute", "mindustry.world.meta.BlockBars", "mindustry.world.meta.BlockFlag", "mindustry.world.meta.BlockGroup", "mindustry.world.meta.BlockStat", "mindustry.world.meta.BlockStats", "mindustry.world.meta.BuildVisibility", "mindustry.world.meta.PowerType", "mindustry.world.meta.Producers", "mindustry.world.meta.StatCategory", "mindustry.world.meta.StatUnit", "mindustry.world.meta.StatValue", "mindustry.world.meta.values.AmmoListValue", "mindustry.world.meta.values.BooleanValue", "mindustry.world.meta.values.BoosterListValue", "mindustry.world.meta.values.ItemFilterValue", "mindustry.world.meta.values.ItemListValue", "mindustry.world.meta.values.LiquidFilterValue", "mindustry.world.meta.values.LiquidValue", "mindustry.world.meta.values.NumberValue", "mindustry.world.meta.values.StringValue", "mindustry.world.modules.BlockModule", "mindustry.world.modules.ConsumeModule", "mindustry.world.modules.ItemModule", "mindustry.world.modules.ItemModule$ItemCalculator", "mindustry.world.modules.ItemModule$ItemConsumer", "mindustry.world.modules.LiquidModule", "mindustry.world.modules.LiquidModule$LiquidCalculator", "mindustry.world.modules.LiquidModule$LiquidConsumer", "mindustry.world.modules.PowerModule", "mindustry.world.producers.Produce", "mindustry.world.producers.ProduceItem"); + public static final ObjectSet allowedClassNames = ObjectSet.with("arc.Core", "arc.func.Boolc", "arc.func.Boolf", "arc.func.Boolf2", "arc.func.Boolp", "arc.func.Cons", "arc.func.Cons2", "arc.func.Floatc", "arc.func.Floatc2", "arc.func.Floatc4", "arc.func.Floatf", "arc.func.Floatp", "arc.func.Func", "arc.func.Func2", "arc.func.Func3", "arc.func.Intc", "arc.func.Intc2", "arc.func.Intc4", "arc.func.Intf", "arc.func.Intp", "arc.func.Prov", "arc.graphics.Color", "arc.graphics.Pixmap", "arc.graphics.Texture", "arc.graphics.TextureData", "arc.graphics.g2d.Draw", "arc.graphics.g2d.Fill", "arc.graphics.g2d.Lines", "arc.graphics.g2d.TextureAtlas", "arc.graphics.g2d.TextureAtlas$AtlasRegion", "arc.graphics.g2d.TextureRegion", "arc.math.Affine2", "arc.math.Angles", "arc.math.Angles", "arc.math.Angles$ParticleConsumer", "arc.math.CumulativeDistribution", "arc.math.CumulativeDistribution$CumulativeValue", "arc.math.DelaunayTriangulator", "arc.math.EarClippingTriangulator", "arc.math.Extrapolator", "arc.math.FloatCounter", "arc.math.Interpolation", "arc.math.Interpolation$Bounce", "arc.math.Interpolation$BounceIn", "arc.math.Interpolation$BounceOut", "arc.math.Interpolation$Elastic", "arc.math.Interpolation$ElasticIn", "arc.math.Interpolation$ElasticOut", "arc.math.Interpolation$Exp", "arc.math.Interpolation$ExpIn", "arc.math.Interpolation$ExpOut", "arc.math.Interpolation$Pow", "arc.math.Interpolation$PowIn", "arc.math.Interpolation$PowOut", "arc.math.Interpolation$Swing", "arc.math.Interpolation$SwingIn", "arc.math.Interpolation$SwingOut", "arc.math.Mathf", "arc.math.Mathf", "arc.math.Matrix3", "arc.math.WindowedMean", "arc.math.geom.BSpline", "arc.math.geom.Bezier", "arc.math.geom.Bresenham2", "arc.math.geom.CatmullRomSpline", "arc.math.geom.Circle", "arc.math.geom.ConvexHull", "arc.math.geom.Ellipse", "arc.math.geom.FixedPosition", "arc.math.geom.Geometry", "arc.math.geom.Geometry$Raycaster", "arc.math.geom.Geometry$SolidChecker", "arc.math.geom.Intersector", "arc.math.geom.Intersector$MinimumTranslationVector", "arc.math.geom.Path", "arc.math.geom.Point2", "arc.math.geom.Point3", "arc.math.geom.Polygon", "arc.math.geom.Polyline", "arc.math.geom.Position", "arc.math.geom.QuadTree", "arc.math.geom.QuadTree$QuadTreeObject", "arc.math.geom.Rect", "arc.math.geom.Shape2D", "arc.math.geom.Spring1D", "arc.math.geom.Spring2D", "arc.math.geom.Vec2", "arc.math.geom.Vec3", "arc.math.geom.Vector", "arc.scene.Action", "arc.scene.Element", "arc.scene.Group", "arc.scene.Scene", "arc.scene.actions.Actions", "arc.scene.actions.AddAction", "arc.scene.actions.AddListenerAction", "arc.scene.actions.AfterAction", "arc.scene.actions.AlphaAction", "arc.scene.actions.ColorAction", "arc.scene.actions.DelayAction", "arc.scene.actions.DelegateAction", "arc.scene.actions.FloatAction", "arc.scene.actions.IntAction", "arc.scene.actions.LayoutAction", "arc.scene.actions.MoveByAction", "arc.scene.actions.MoveToAction", "arc.scene.actions.OriginAction", "arc.scene.actions.ParallelAction", "arc.scene.actions.RelativeTemporalAction", "arc.scene.actions.RemoveAction", "arc.scene.actions.RemoveActorAction", "arc.scene.actions.RemoveListenerAction", "arc.scene.actions.RepeatAction", "arc.scene.actions.RotateByAction", "arc.scene.actions.RotateToAction", "arc.scene.actions.RunnableAction", "arc.scene.actions.ScaleByAction", "arc.scene.actions.ScaleToAction", "arc.scene.actions.SequenceAction", "arc.scene.actions.SizeByAction", "arc.scene.actions.SizeToAction", "arc.scene.actions.TemporalAction", "arc.scene.actions.TimeScaleAction", "arc.scene.actions.TouchableAction", "arc.scene.actions.TranslateByAction", "arc.scene.actions.VisibleAction", "arc.scene.event.ChangeListener", "arc.scene.event.ChangeListener$ChangeEvent", "arc.scene.event.ClickListener", "arc.scene.event.DragListener", "arc.scene.event.DragScrollListener", "arc.scene.event.ElementGestureListener", "arc.scene.event.EventListener", "arc.scene.event.FocusListener", "arc.scene.event.FocusListener$FocusEvent", "arc.scene.event.FocusListener$FocusEvent$Type", "arc.scene.event.HandCursorListener", "arc.scene.event.IbeamCursorListener", "arc.scene.event.InputEvent", "arc.scene.event.InputEvent$Type", "arc.scene.event.InputListener", "arc.scene.event.SceneEvent", "arc.scene.event.Touchable", "arc.scene.event.VisibilityEvent", "arc.scene.event.VisibilityListener", "arc.scene.style.BaseDrawable", "arc.scene.style.Drawable", "arc.scene.style.NinePatchDrawable", "arc.scene.style.ScaledNinePatchDrawable", "arc.scene.style.Style", "arc.scene.style.TextureRegionDrawable", "arc.scene.style.TiledDrawable", "arc.scene.style.TransformDrawable", "arc.scene.ui.Button", "arc.scene.ui.Button$ButtonStyle", "arc.scene.ui.ButtonGroup", "arc.scene.ui.CheckBox", "arc.scene.ui.CheckBox$CheckBoxStyle", "arc.scene.ui.ColorImage", "arc.scene.ui.Dialog", "arc.scene.ui.Dialog$DialogStyle", "arc.scene.ui.Image", "arc.scene.ui.ImageButton", "arc.scene.ui.ImageButton$ImageButtonStyle", "arc.scene.ui.KeybindDialog", "arc.scene.ui.KeybindDialog$KeybindDialogStyle", "arc.scene.ui.Label", "arc.scene.ui.Label$LabelStyle", "arc.scene.ui.ProgressBar", "arc.scene.ui.ProgressBar$ProgressBarStyle", "arc.scene.ui.ScrollPane", "arc.scene.ui.ScrollPane$ScrollPaneStyle", "arc.scene.ui.SettingsDialog", "arc.scene.ui.SettingsDialog$SettingsTable", "arc.scene.ui.SettingsDialog$SettingsTable$CheckSetting", "arc.scene.ui.SettingsDialog$SettingsTable$Setting", "arc.scene.ui.SettingsDialog$SettingsTable$SliderSetting", "arc.scene.ui.SettingsDialog$StringProcessor", "arc.scene.ui.Slider", "arc.scene.ui.Slider$SliderStyle", "arc.scene.ui.TextArea", "arc.scene.ui.TextArea$TextAreaListener", "arc.scene.ui.TextButton", "arc.scene.ui.TextButton$TextButtonStyle", "arc.scene.ui.TextField", "arc.scene.ui.TextField$DefaultOnscreenKeyboard", "arc.scene.ui.TextField$OnscreenKeyboard", "arc.scene.ui.TextField$TextFieldClickListener", "arc.scene.ui.TextField$TextFieldFilter", "arc.scene.ui.TextField$TextFieldListener", "arc.scene.ui.TextField$TextFieldStyle", "arc.scene.ui.TextField$TextFieldValidator", "arc.scene.ui.Tooltip", "arc.scene.ui.Tooltip$Tooltips", "arc.scene.ui.Touchpad", "arc.scene.ui.Touchpad$TouchpadStyle", "arc.scene.ui.TreeElement", "arc.scene.ui.TreeElement$Node", "arc.scene.ui.TreeElement$TreeStyle", "arc.scene.ui.layout.Cell", "arc.scene.ui.layout.Collapser", "arc.scene.ui.layout.HorizontalGroup", "arc.scene.ui.layout.Scl", "arc.scene.ui.layout.Stack", "arc.scene.ui.layout.Table", "arc.scene.ui.layout.Table$DrawRect", "arc.scene.ui.layout.VerticalGroup", "arc.scene.ui.layout.WidgetGroup", "arc.scene.utils.ArraySelection", "arc.scene.utils.Cullable", "arc.scene.utils.Disableable", "arc.scene.utils.DragAndDrop", "arc.scene.utils.DragAndDrop$Payload", "arc.scene.utils.DragAndDrop$Source", "arc.scene.utils.DragAndDrop$Target", "arc.scene.utils.Elements", "arc.scene.utils.Layout", "arc.scene.utils.Selection", "arc.struct.Array", "arc.struct.Array$ArrayIterable", "arc.struct.ArrayMap", "arc.struct.ArrayMap$Entries", "arc.struct.ArrayMap$Keys", "arc.struct.ArrayMap$Values", "arc.struct.AtomicQueue", "arc.struct.BinaryHeap", "arc.struct.BinaryHeap$Node", "arc.struct.Bits", "arc.struct.BooleanArray", "arc.struct.ByteArray", "arc.struct.CharArray", "arc.struct.ComparableTimSort", "arc.struct.DelayedRemovalArray", "arc.struct.EnumSet", "arc.struct.EnumSet$EnumSetIterator", "arc.struct.FloatArray", "arc.struct.GridBits", "arc.struct.GridMap", "arc.struct.IdentityMap", "arc.struct.IdentityMap$Entries", "arc.struct.IdentityMap$Entry", "arc.struct.IdentityMap$Keys", "arc.struct.IdentityMap$Values", "arc.struct.IntArray", "arc.struct.IntFloatMap", "arc.struct.IntFloatMap$Entries", "arc.struct.IntFloatMap$Entry", "arc.struct.IntFloatMap$Keys", "arc.struct.IntFloatMap$Values", "arc.struct.IntIntMap", "arc.struct.IntIntMap$Entries", "arc.struct.IntIntMap$Entry", "arc.struct.IntIntMap$Keys", "arc.struct.IntIntMap$Values", "arc.struct.IntMap", "arc.struct.IntMap$Entries", "arc.struct.IntMap$Entry", "arc.struct.IntMap$Keys", "arc.struct.IntMap$Values", "arc.struct.IntQueue", "arc.struct.IntSet", "arc.struct.IntSet$IntSetIterator", "arc.struct.LongArray", "arc.struct.LongMap", "arc.struct.LongMap$Entries", "arc.struct.LongMap$Entry", "arc.struct.LongMap$Keys", "arc.struct.LongMap$Values", "arc.struct.LongQueue", "arc.struct.ObjectFloatMap", "arc.struct.ObjectFloatMap$Entries", "arc.struct.ObjectFloatMap$Entry", "arc.struct.ObjectFloatMap$Keys", "arc.struct.ObjectFloatMap$Values", "arc.struct.ObjectIntMap", "arc.struct.ObjectIntMap$Entries", "arc.struct.ObjectIntMap$Entry", "arc.struct.ObjectIntMap$Keys", "arc.struct.ObjectIntMap$Values", "arc.struct.ObjectMap", "arc.struct.ObjectMap$Entries", "arc.struct.ObjectMap$Entry", "arc.struct.ObjectMap$Keys", "arc.struct.ObjectMap$Values", "arc.struct.ObjectSet", "arc.struct.ObjectSet$ObjectSetIterator", "arc.struct.OrderedMap", "arc.struct.OrderedMap$OrderedMapEntries", "arc.struct.OrderedMap$OrderedMapKeys", "arc.struct.OrderedMap$OrderedMapValues", "arc.struct.OrderedSet", "arc.struct.OrderedSet$OrderedSetIterator", "arc.struct.PooledLinkedList", "arc.struct.PooledLinkedList$Item", "arc.struct.Queue", "arc.struct.Queue$QueueIterable", "arc.struct.ShortArray", "arc.struct.SnapshotArray", "arc.struct.Sort", "arc.struct.SortedIntList", "arc.struct.SortedIntList$Iterator", "arc.struct.SortedIntList$Node", "arc.struct.StringMap", "arc.struct.TimSort", "arc.util.I18NBundle", "arc.util.Interval", "arc.util.Time", "java.io.DataInput", "java.io.DataInputStream", "java.io.DataOutput", "java.io.DataOutputStream", "java.io.PrintStream", "java.lang.Boolean", "java.lang.Byte", "java.lang.Character", "java.lang.Double", "java.lang.Float", "java.lang.Integer", "java.lang.Long", "java.lang.Object", "java.lang.Runnable", "java.lang.Short", "java.lang.String", "java.lang.System", "mindustry.Vars", "mindustry.ai.BlockIndexer", "mindustry.ai.Pathfinder", "mindustry.ai.Pathfinder$PathData", "mindustry.ai.Pathfinder$PathTarget", "mindustry.ai.Pathfinder$PathTileStruct", "mindustry.ai.WaveSpawner", "mindustry.content.Blocks", "mindustry.content.Bullets", "mindustry.content.Fx", "mindustry.content.Items", "mindustry.content.Liquids", "mindustry.content.Loadouts", "mindustry.content.Mechs", "mindustry.content.StatusEffects", "mindustry.content.TechTree", "mindustry.content.TechTree$TechNode", "mindustry.content.TypeIDs", "mindustry.content.UnitTypes", "mindustry.content.Zones", "mindustry.core.ContentLoader", "mindustry.core.Control", "mindustry.core.FileTree", "mindustry.core.GameState", "mindustry.core.GameState$State", "mindustry.core.Logic", "mindustry.core.NetServer$TeamAssigner", "mindustry.core.Platform", "mindustry.core.Renderer", "mindustry.core.UI", "mindustry.core.Version", "mindustry.core.World", "mindustry.core.World$Raycaster", "mindustry.ctype.Content", "mindustry.ctype.Content$ModContentInfo", "mindustry.ctype.ContentList", "mindustry.ctype.ContentType", "mindustry.ctype.MappableContent", "mindustry.ctype.UnlockableContent", "mindustry.editor.DrawOperation", "mindustry.editor.DrawOperation$OpType", "mindustry.editor.DrawOperation$TileOpStruct", "mindustry.editor.EditorTile", "mindustry.editor.EditorTool", "mindustry.editor.MapEditor", "mindustry.editor.MapEditor$Context", "mindustry.editor.MapEditorDialog", "mindustry.editor.MapGenerateDialog", "mindustry.editor.MapInfoDialog", "mindustry.editor.MapLoadDialog", "mindustry.editor.MapRenderer", "mindustry.editor.MapResizeDialog", "mindustry.editor.MapSaveDialog", "mindustry.editor.MapView", "mindustry.editor.OperationStack", "mindustry.editor.WaveInfoDialog", "mindustry.entities.Damage", "mindustry.entities.Damage$PropCellStruct", "mindustry.entities.Effects", "mindustry.entities.Effects$Effect", "mindustry.entities.Effects$EffectContainer", "mindustry.entities.Effects$EffectProvider", "mindustry.entities.Effects$EffectRenderer", "mindustry.entities.Effects$ScreenshakeProvider", "mindustry.entities.Entities", "mindustry.entities.EntityCollisions", "mindustry.entities.EntityGroup", "mindustry.entities.Predict", "mindustry.entities.TargetPriority", "mindustry.entities.Units", "mindustry.entities.bullet.ArtilleryBulletType", "mindustry.entities.bullet.BasicBulletType", "mindustry.entities.bullet.BombBulletType", "mindustry.entities.bullet.BulletType", "mindustry.entities.bullet.FlakBulletType", "mindustry.entities.bullet.HealBulletType", "mindustry.entities.bullet.LiquidBulletType", "mindustry.entities.bullet.MassDriverBolt", "mindustry.entities.bullet.MissileBulletType", "mindustry.entities.effect.Decal", "mindustry.entities.effect.Fire", "mindustry.entities.effect.GroundEffectEntity", "mindustry.entities.effect.GroundEffectEntity$GroundEffect", "mindustry.entities.effect.ItemTransfer", "mindustry.entities.effect.Lightning", "mindustry.entities.effect.Puddle", "mindustry.entities.effect.RubbleDecal", "mindustry.entities.effect.ScorchDecal", "mindustry.entities.traits.AbsorbTrait", "mindustry.entities.traits.BelowLiquidTrait", "mindustry.entities.traits.BuilderMinerTrait", "mindustry.entities.traits.BuilderTrait", "mindustry.entities.traits.BuilderTrait$BuildDataStatic", "mindustry.entities.traits.BuilderTrait$BuildRequest", "mindustry.entities.traits.DamageTrait", "mindustry.entities.traits.DrawTrait", "mindustry.entities.traits.Entity", "mindustry.entities.traits.HealthTrait", "mindustry.entities.traits.KillerTrait", "mindustry.entities.traits.MinerTrait", "mindustry.entities.traits.MoveTrait", "mindustry.entities.traits.SaveTrait", "mindustry.entities.traits.Saveable", "mindustry.entities.traits.ScaleTrait", "mindustry.entities.traits.ShooterTrait", "mindustry.entities.traits.SolidTrait", "mindustry.entities.traits.SpawnerTrait", "mindustry.entities.traits.SyncTrait", "mindustry.entities.traits.TargetTrait", "mindustry.entities.traits.TeamTrait", "mindustry.entities.traits.TimeTrait", "mindustry.entities.traits.TypeTrait", "mindustry.entities.traits.VelocityTrait", "mindustry.entities.type.BaseEntity", "mindustry.entities.type.BaseUnit", "mindustry.entities.type.Bullet", "mindustry.entities.type.DestructibleEntity", "mindustry.entities.type.EffectEntity", "mindustry.entities.type.Player", "mindustry.entities.type.SolidEntity", "mindustry.entities.type.TileEntity", "mindustry.entities.type.TimedEntity", "mindustry.entities.type.Unit", "mindustry.entities.type.base.BaseDrone", "mindustry.entities.type.base.BuilderDrone", "mindustry.entities.type.base.FlyingUnit", "mindustry.entities.type.base.GroundUnit", "mindustry.entities.type.base.HoverUnit", "mindustry.entities.type.base.MinerDrone", "mindustry.entities.type.base.RepairDrone", "mindustry.entities.units.StateMachine", "mindustry.entities.units.Statuses", "mindustry.entities.units.Statuses$StatusEntry", "mindustry.entities.units.UnitCommand", "mindustry.entities.units.UnitDrops", "mindustry.entities.units.UnitState", "mindustry.game.DefaultWaves", "mindustry.game.Difficulty", "mindustry.game.EventType", "mindustry.game.EventType$BlockBuildBeginEvent", "mindustry.game.EventType$BlockBuildEndEvent", "mindustry.game.EventType$BlockDestroyEvent", "mindustry.game.EventType$BlockInfoEvent", "mindustry.game.EventType$BuildSelectEvent", "mindustry.game.EventType$ClientLoadEvent", "mindustry.game.EventType$CommandIssueEvent", "mindustry.game.EventType$ContentReloadEvent", "mindustry.game.EventType$CoreItemDeliverEvent", "mindustry.game.EventType$DepositEvent", "mindustry.game.EventType$DisposeEvent", "mindustry.game.EventType$GameOverEvent", "mindustry.game.EventType$LaunchEvent", "mindustry.game.EventType$LaunchItemEvent", "mindustry.game.EventType$LineConfirmEvent", "mindustry.game.EventType$LoseEvent", "mindustry.game.EventType$MapMakeEvent", "mindustry.game.EventType$MapPublishEvent", "mindustry.game.EventType$MechChangeEvent", "mindustry.game.EventType$PlayEvent", "mindustry.game.EventType$PlayerBanEvent", "mindustry.game.EventType$PlayerChatEvent", "mindustry.game.EventType$PlayerConnect", "mindustry.game.EventType$PlayerIpBanEvent", "mindustry.game.EventType$PlayerIpUnbanEvent", "mindustry.game.EventType$PlayerJoin", "mindustry.game.EventType$PlayerLeave", "mindustry.game.EventType$PlayerUnbanEvent", "mindustry.game.EventType$ResearchEvent", "mindustry.game.EventType$ResetEvent", "mindustry.game.EventType$ResizeEvent", "mindustry.game.EventType$ServerLoadEvent", "mindustry.game.EventType$StateChangeEvent", "mindustry.game.EventType$TapConfigEvent", "mindustry.game.EventType$TapEvent", "mindustry.game.EventType$TileChangeEvent", "mindustry.game.EventType$Trigger", "mindustry.game.EventType$TurretAmmoDeliverEvent", "mindustry.game.EventType$UnitCreateEvent", "mindustry.game.EventType$UnitDestroyEvent", "mindustry.game.EventType$UnlockEvent", "mindustry.game.EventType$WaveEvent", "mindustry.game.EventType$WinEvent", "mindustry.game.EventType$WithdrawEvent", "mindustry.game.EventType$WorldLoadEvent", "mindustry.game.EventType$ZoneConfigureCompleteEvent", "mindustry.game.EventType$ZoneRequireCompleteEvent", "mindustry.game.Gamemode", "mindustry.game.GlobalData", "mindustry.game.LoopControl", "mindustry.game.MusicControl", "mindustry.game.Objective", "mindustry.game.Objectives", "mindustry.game.Objectives$Launched", "mindustry.game.Objectives$Unlock", "mindustry.game.Objectives$Wave", "mindustry.game.Objectives$ZoneObjective", "mindustry.game.Objectives$ZoneWave", "mindustry.game.Rules", "mindustry.game.Saves", "mindustry.game.Saves$SaveSlot", "mindustry.game.Schematic", "mindustry.game.Schematic$Stile", "mindustry.game.Schematics", "mindustry.game.SoundLoop", "mindustry.game.SpawnGroup", "mindustry.game.Stats", "mindustry.game.Stats$Rank", "mindustry.game.Stats$RankResult", "mindustry.game.Team", "mindustry.game.Teams", "mindustry.game.Teams$BrokenBlock", "mindustry.game.Teams$TeamData", "mindustry.game.Tutorial", "mindustry.game.Tutorial$TutorialStage", "mindustry.gen.BufferItem", "mindustry.gen.Call", "mindustry.gen.Call", "mindustry.gen.Icon", "mindustry.gen.Icon", "mindustry.gen.MethodHash", "mindustry.gen.Musics", "mindustry.gen.Musics", "mindustry.gen.PathTile", "mindustry.gen.PropCell", "mindustry.gen.RemoteReadClient", "mindustry.gen.RemoteReadServer", "mindustry.gen.Serialization", "mindustry.gen.Sounds", "mindustry.gen.Sounds", "mindustry.gen.Tex", "mindustry.gen.Tex", "mindustry.gen.TileOp", "mindustry.graphics.BlockRenderer", "mindustry.graphics.Bloom", "mindustry.graphics.CacheLayer", "mindustry.graphics.Drawf", "mindustry.graphics.FloorRenderer", "mindustry.graphics.IndexedRenderer", "mindustry.graphics.Layer", "mindustry.graphics.LightRenderer", "mindustry.graphics.MenuRenderer", "mindustry.graphics.MinimapRenderer", "mindustry.graphics.MultiPacker", "mindustry.graphics.MultiPacker$PageType", "mindustry.graphics.OverlayRenderer", "mindustry.graphics.Pal", "mindustry.graphics.Pixelator", "mindustry.graphics.Shaders", "mindustry.input.Binding", "mindustry.input.DesktopInput", "mindustry.input.InputHandler", "mindustry.input.InputHandler$PlaceLine", "mindustry.input.MobileInput", "mindustry.input.PlaceMode", "mindustry.input.Placement", "mindustry.input.Placement$DistanceHeuristic", "mindustry.input.Placement$NormalizeDrawResult", "mindustry.input.Placement$NormalizeResult", "mindustry.input.Placement$TileHueristic", "mindustry.maps.Map", "mindustry.maps.Maps", "mindustry.maps.Maps$MapProvider", "mindustry.maps.Maps$ShuffleMode", "mindustry.maps.Maps$ShuffleMode", "mindustry.maps.filters.BlendFilter", "mindustry.maps.filters.ClearFilter", "mindustry.maps.filters.DistortFilter", "mindustry.maps.filters.FilterOption", "mindustry.maps.filters.FilterOption$BlockOption", "mindustry.maps.filters.FilterOption$SliderOption", "mindustry.maps.filters.GenerateFilter", "mindustry.maps.filters.GenerateFilter$GenerateInput", "mindustry.maps.filters.GenerateFilter$GenerateInput$TileProvider", "mindustry.maps.filters.MedianFilter", "mindustry.maps.filters.MirrorFilter", "mindustry.maps.filters.NoiseFilter", "mindustry.maps.filters.OreFilter", "mindustry.maps.filters.OreMedianFilter", "mindustry.maps.filters.RiverNoiseFilter", "mindustry.maps.filters.ScatterFilter", "mindustry.maps.filters.TerrainFilter", "mindustry.maps.generators.BasicGenerator", "mindustry.maps.generators.BasicGenerator$DistanceHeuristic", "mindustry.maps.generators.BasicGenerator$TileHueristic", "mindustry.maps.generators.Generator", "mindustry.maps.generators.MapGenerator", "mindustry.maps.generators.MapGenerator$Decoration", "mindustry.maps.generators.RandomGenerator", "mindustry.maps.zonegen.DesertWastesGenerator", "mindustry.maps.zonegen.OvergrowthGenerator", "mindustry.type.Category", "mindustry.type.ErrorContent", "mindustry.type.Item", "mindustry.type.ItemStack", "mindustry.type.ItemType", "mindustry.type.Liquid", "mindustry.type.LiquidStack", "mindustry.type.Mech", "mindustry.type.Publishable", "mindustry.type.StatusEffect", "mindustry.type.StatusEffect$TransitionHandler", "mindustry.type.TypeID", "mindustry.type.UnitType", "mindustry.type.Weapon", "mindustry.type.WeatherEvent", "mindustry.type.Zone", "mindustry.ui.Bar", "mindustry.ui.BorderImage", "mindustry.ui.Cicon", "mindustry.ui.ContentDisplay", "mindustry.ui.Fonts", "mindustry.ui.GridImage", "mindustry.ui.IconSize", "mindustry.ui.IntFormat", "mindustry.ui.ItemDisplay", "mindustry.ui.ItemImage", "mindustry.ui.ItemsDisplay", "mindustry.ui.Links", "mindustry.ui.Links$LinkEntry", "mindustry.ui.LiquidDisplay", "mindustry.ui.Minimap", "mindustry.ui.MobileButton", "mindustry.ui.MultiReqImage", "mindustry.ui.ReqImage", "mindustry.ui.Styles", "mindustry.ui.dialogs.AboutDialog", "mindustry.ui.dialogs.AdminsDialog", "mindustry.ui.dialogs.BansDialog", "mindustry.ui.dialogs.ColorPicker", "mindustry.ui.dialogs.ContentInfoDialog", "mindustry.ui.dialogs.ControlsDialog", "mindustry.ui.dialogs.CustomGameDialog", "mindustry.ui.dialogs.CustomRulesDialog", "mindustry.ui.dialogs.DatabaseDialog", "mindustry.ui.dialogs.DeployDialog", "mindustry.ui.dialogs.DeployDialog$View", "mindustry.ui.dialogs.DeployDialog$ZoneNode", "mindustry.ui.dialogs.DiscordDialog", "mindustry.ui.dialogs.FileChooser", "mindustry.ui.dialogs.FileChooser$FileHistory", "mindustry.ui.dialogs.FloatingDialog", "mindustry.ui.dialogs.GameOverDialog", "mindustry.ui.dialogs.HostDialog", "mindustry.ui.dialogs.JoinDialog", "mindustry.ui.dialogs.JoinDialog$Server", "mindustry.ui.dialogs.LanguageDialog", "mindustry.ui.dialogs.LoadDialog", "mindustry.ui.dialogs.LoadoutDialog", "mindustry.ui.dialogs.MapPlayDialog", "mindustry.ui.dialogs.MapsDialog", "mindustry.ui.dialogs.MinimapDialog", "mindustry.ui.dialogs.ModsDialog", "mindustry.ui.dialogs.PaletteDialog", "mindustry.ui.dialogs.PausedDialog", "mindustry.ui.dialogs.SaveDialog", "mindustry.ui.dialogs.SchematicsDialog", "mindustry.ui.dialogs.SchematicsDialog$SchematicImage", "mindustry.ui.dialogs.SchematicsDialog$SchematicInfoDialog", "mindustry.ui.dialogs.SettingsMenuDialog", "mindustry.ui.dialogs.TechTreeDialog", "mindustry.ui.dialogs.TechTreeDialog$LayoutNode", "mindustry.ui.dialogs.TechTreeDialog$TechTreeNode", "mindustry.ui.dialogs.TechTreeDialog$View", "mindustry.ui.dialogs.TraceDialog", "mindustry.ui.dialogs.ZoneInfoDialog", "mindustry.ui.fragments.BlockConfigFragment", "mindustry.ui.fragments.BlockInventoryFragment", "mindustry.ui.fragments.ChatFragment", "mindustry.ui.fragments.FadeInFragment", "mindustry.ui.fragments.Fragment", "mindustry.ui.fragments.HudFragment", "mindustry.ui.fragments.LoadingFragment", "mindustry.ui.fragments.MenuFragment", "mindustry.ui.fragments.MinimapFragment", "mindustry.ui.fragments.OverlayFragment", "mindustry.ui.fragments.PlacementFragment", "mindustry.ui.fragments.PlayerListFragment", "mindustry.ui.fragments.ScriptConsoleFragment", "mindustry.ui.layout.BranchTreeLayout", "mindustry.ui.layout.BranchTreeLayout$TreeAlignment", "mindustry.ui.layout.BranchTreeLayout$TreeLocation", "mindustry.ui.layout.RadialTreeLayout", "mindustry.ui.layout.TreeLayout", "mindustry.ui.layout.TreeLayout$TreeNode", "mindustry.world.Block", "mindustry.world.BlockStorage", "mindustry.world.Build", "mindustry.world.CachedTile", "mindustry.world.DirectionalItemBuffer", "mindustry.world.DirectionalItemBuffer$BufferItemStruct", "mindustry.world.Edges", "mindustry.world.ItemBuffer", "mindustry.world.LegacyColorMapper", "mindustry.world.LegacyColorMapper$LegacyBlock", "mindustry.world.Pos", "mindustry.world.StaticTree", "mindustry.world.Tile", "mindustry.world.WorldContext", "mindustry.world.blocks.Attributes", "mindustry.world.blocks.Autotiler", "mindustry.world.blocks.Autotiler$AutotilerHolder", "mindustry.world.blocks.BlockPart", "mindustry.world.blocks.BuildBlock", "mindustry.world.blocks.BuildBlock$BuildEntity", "mindustry.world.blocks.DoubleOverlayFloor", "mindustry.world.blocks.Floor", "mindustry.world.blocks.ItemSelection", "mindustry.world.blocks.LiquidBlock", "mindustry.world.blocks.OreBlock", "mindustry.world.blocks.OverlayFloor", "mindustry.world.blocks.PowerBlock", "mindustry.world.blocks.RespawnBlock", "mindustry.world.blocks.Rock", "mindustry.world.blocks.StaticWall", "mindustry.world.blocks.TreeBlock", "mindustry.world.blocks.defense.DeflectorWall", "mindustry.world.blocks.defense.DeflectorWall$DeflectorEntity", "mindustry.world.blocks.defense.Door", "mindustry.world.blocks.defense.Door$DoorEntity", "mindustry.world.blocks.defense.ForceProjector", "mindustry.world.blocks.defense.ForceProjector$ForceEntity", "mindustry.world.blocks.defense.ForceProjector$ShieldEntity", "mindustry.world.blocks.defense.MendProjector", "mindustry.world.blocks.defense.MendProjector$MendEntity", "mindustry.world.blocks.defense.OverdriveProjector", "mindustry.world.blocks.defense.OverdriveProjector$OverdriveEntity", "mindustry.world.blocks.defense.ShockMine", "mindustry.world.blocks.defense.SurgeWall", "mindustry.world.blocks.defense.Wall", "mindustry.world.blocks.defense.turrets.ArtilleryTurret", "mindustry.world.blocks.defense.turrets.BurstTurret", "mindustry.world.blocks.defense.turrets.ChargeTurret", "mindustry.world.blocks.defense.turrets.ChargeTurret$LaserTurretEntity", "mindustry.world.blocks.defense.turrets.CooledTurret", "mindustry.world.blocks.defense.turrets.DoubleTurret", "mindustry.world.blocks.defense.turrets.ItemTurret", "mindustry.world.blocks.defense.turrets.ItemTurret$ItemEntry", "mindustry.world.blocks.defense.turrets.ItemTurret$ItemTurretEntity", "mindustry.world.blocks.defense.turrets.LaserTurret", "mindustry.world.blocks.defense.turrets.LaserTurret$LaserTurretEntity", "mindustry.world.blocks.defense.turrets.LiquidTurret", "mindustry.world.blocks.defense.turrets.PowerTurret", "mindustry.world.blocks.defense.turrets.Turret", "mindustry.world.blocks.defense.turrets.Turret$AmmoEntry", "mindustry.world.blocks.defense.turrets.Turret$TurretEntity", "mindustry.world.blocks.distribution.ArmoredConveyor", "mindustry.world.blocks.distribution.BufferedItemBridge", "mindustry.world.blocks.distribution.BufferedItemBridge$BufferedItemBridgeEntity", "mindustry.world.blocks.distribution.Conveyor", "mindustry.world.blocks.distribution.Conveyor$ConveyorEntity", "mindustry.world.blocks.distribution.Conveyor$ItemPos", "mindustry.world.blocks.distribution.ExtendingItemBridge", "mindustry.world.blocks.distribution.ItemBridge", "mindustry.world.blocks.distribution.ItemBridge$ItemBridgeEntity", "mindustry.world.blocks.distribution.Junction", "mindustry.world.blocks.distribution.Junction$JunctionEntity", "mindustry.world.blocks.distribution.MassDriver", "mindustry.world.blocks.distribution.MassDriver$DriverBulletData", "mindustry.world.blocks.distribution.MassDriver$DriverState", "mindustry.world.blocks.distribution.MassDriver$MassDriverEntity", "mindustry.world.blocks.distribution.OverflowGate", "mindustry.world.blocks.distribution.OverflowGate$OverflowGateEntity", "mindustry.world.blocks.distribution.Router", "mindustry.world.blocks.distribution.Router$RouterEntity", "mindustry.world.blocks.distribution.Sorter", "mindustry.world.blocks.distribution.Sorter$SorterEntity", "mindustry.world.blocks.liquid.ArmoredConduit", "mindustry.world.blocks.liquid.Conduit", "mindustry.world.blocks.liquid.Conduit$ConduitEntity", "mindustry.world.blocks.liquid.LiquidBridge", "mindustry.world.blocks.liquid.LiquidExtendingBridge", "mindustry.world.blocks.liquid.LiquidJunction", "mindustry.world.blocks.liquid.LiquidOverflowGate", "mindustry.world.blocks.liquid.LiquidRouter", "mindustry.world.blocks.liquid.LiquidTank", "mindustry.world.blocks.logic.LogicBlock", "mindustry.world.blocks.logic.MessageBlock", "mindustry.world.blocks.logic.MessageBlock$MessageBlockEntity", "mindustry.world.blocks.power.Battery", "mindustry.world.blocks.power.BurnerGenerator", "mindustry.world.blocks.power.ConditionalConsumePower", "mindustry.world.blocks.power.DecayGenerator", "mindustry.world.blocks.power.ImpactReactor", "mindustry.world.blocks.power.ImpactReactor$FusionReactorEntity", "mindustry.world.blocks.power.ItemLiquidGenerator", "mindustry.world.blocks.power.ItemLiquidGenerator$ItemLiquidGeneratorEntity", "mindustry.world.blocks.power.LightBlock", "mindustry.world.blocks.power.LightBlock$LightEntity", "mindustry.world.blocks.power.NuclearReactor", "mindustry.world.blocks.power.NuclearReactor$NuclearReactorEntity", "mindustry.world.blocks.power.PowerDiode", "mindustry.world.blocks.power.PowerDistributor", "mindustry.world.blocks.power.PowerGenerator", "mindustry.world.blocks.power.PowerGenerator$GeneratorEntity", "mindustry.world.blocks.power.PowerGraph", "mindustry.world.blocks.power.PowerNode", "mindustry.world.blocks.power.SingleTypeGenerator", "mindustry.world.blocks.power.SolarGenerator", "mindustry.world.blocks.power.ThermalGenerator", "mindustry.world.blocks.production.Cultivator", "mindustry.world.blocks.production.Cultivator$CultivatorEntity", "mindustry.world.blocks.production.Drill", "mindustry.world.blocks.production.Drill$DrillEntity", "mindustry.world.blocks.production.Fracker", "mindustry.world.blocks.production.Fracker$FrackerEntity", "mindustry.world.blocks.production.GenericCrafter", "mindustry.world.blocks.production.GenericCrafter$GenericCrafterEntity", "mindustry.world.blocks.production.GenericSmelter", "mindustry.world.blocks.production.Incinerator", "mindustry.world.blocks.production.Incinerator$IncineratorEntity", "mindustry.world.blocks.production.LiquidConverter", "mindustry.world.blocks.production.Pump", "mindustry.world.blocks.production.Separator", "mindustry.world.blocks.production.SolidPump", "mindustry.world.blocks.production.SolidPump$SolidPumpEntity", "mindustry.world.blocks.sandbox.ItemSource", "mindustry.world.blocks.sandbox.ItemSource$ItemSourceEntity", "mindustry.world.blocks.sandbox.ItemVoid", "mindustry.world.blocks.sandbox.LiquidSource", "mindustry.world.blocks.sandbox.LiquidSource$LiquidSourceEntity", "mindustry.world.blocks.sandbox.PowerSource", "mindustry.world.blocks.sandbox.PowerVoid", "mindustry.world.blocks.storage.CoreBlock", "mindustry.world.blocks.storage.CoreBlock$CoreEntity", "mindustry.world.blocks.storage.LaunchPad", "mindustry.world.blocks.storage.StorageBlock", "mindustry.world.blocks.storage.StorageBlock$StorageBlockEntity", "mindustry.world.blocks.storage.Unloader", "mindustry.world.blocks.storage.Unloader$UnloaderEntity", "mindustry.world.blocks.storage.Vault", "mindustry.world.blocks.units.CommandCenter", "mindustry.world.blocks.units.CommandCenter$CommandCenterEntity", "mindustry.world.blocks.units.MechPad", "mindustry.world.blocks.units.MechPad$MechFactoryEntity", "mindustry.world.blocks.units.RallyPoint", "mindustry.world.blocks.units.RepairPoint", "mindustry.world.blocks.units.RepairPoint$RepairPointEntity", "mindustry.world.blocks.units.UnitFactory", "mindustry.world.blocks.units.UnitFactory$UnitFactoryEntity", "mindustry.world.consumers.Consume", "mindustry.world.consumers.ConsumeItemFilter", "mindustry.world.consumers.ConsumeItems", "mindustry.world.consumers.ConsumeLiquid", "mindustry.world.consumers.ConsumeLiquidBase", "mindustry.world.consumers.ConsumeLiquidFilter", "mindustry.world.consumers.ConsumePower", "mindustry.world.consumers.ConsumeType", "mindustry.world.consumers.Consumers", "mindustry.world.meta.Attribute", "mindustry.world.meta.BlockBars", "mindustry.world.meta.BlockFlag", "mindustry.world.meta.BlockGroup", "mindustry.world.meta.BlockStat", "mindustry.world.meta.BlockStats", "mindustry.world.meta.BuildVisibility", "mindustry.world.meta.PowerType", "mindustry.world.meta.Producers", "mindustry.world.meta.StatCategory", "mindustry.world.meta.StatUnit", "mindustry.world.meta.StatValue", "mindustry.world.meta.values.AmmoListValue", "mindustry.world.meta.values.BooleanValue", "mindustry.world.meta.values.BoosterListValue", "mindustry.world.meta.values.ItemFilterValue", "mindustry.world.meta.values.ItemListValue", "mindustry.world.meta.values.LiquidFilterValue", "mindustry.world.meta.values.LiquidValue", "mindustry.world.meta.values.NumberValue", "mindustry.world.meta.values.StringValue", "mindustry.world.modules.BlockModule", "mindustry.world.modules.ConsumeModule", "mindustry.world.modules.ItemModule", "mindustry.world.modules.ItemModule$ItemCalculator", "mindustry.world.modules.ItemModule$ItemConsumer", "mindustry.world.modules.LiquidModule", "mindustry.world.modules.LiquidModule$LiquidCalculator", "mindustry.world.modules.LiquidModule$LiquidConsumer", "mindustry.world.modules.PowerModule", "mindustry.world.producers.Produce", "mindustry.world.producers.ProduceItem"); } \ No newline at end of file diff --git a/core/src/mindustry/world/blocks/BuildBlock.java b/core/src/mindustry/world/blocks/BuildBlock.java index 345300343f..14187850ba 100644 --- a/core/src/mindustry/world/blocks/BuildBlock.java +++ b/core/src/mindustry/world/blocks/BuildBlock.java @@ -173,7 +173,7 @@ public class BuildBlock extends Block{ if(entity.previous == null || entity.cblock == null) return; - if(Core.atlas.isFound(entity.previous.icon(mindustry.ui.Cicon.full))){ + if(Core.atlas.isFound(entity.previous.icon(Cicon.full))){ Draw.rect(entity.previous.icon(Cicon.full), tile.drawx(), tile.drawy(), entity.previous.rotate ? tile.rotation() * 90 : 0); } } diff --git a/gradle.properties b/gradle.properties index aa36264bb8..1456cfdefc 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,3 +1,3 @@ org.gradle.daemon=true org.gradle.jvmargs=-Xms256m -Xmx1024m -archash=7bfc46fe8c7810fbef1b6f6bbb19c8b999856813 +archash=e151bac7925323f24932ff3ae3f9eacfd6d3a268 diff --git a/tools/src/mindustry/tools/ScriptStubGenerator.java b/tools/src/mindustry/tools/ScriptStubGenerator.java index c60b6589fa..aadb1309bc 100644 --- a/tools/src/mindustry/tools/ScriptStubGenerator.java +++ b/tools/src/mindustry/tools/ScriptStubGenerator.java @@ -26,7 +26,8 @@ public class ScriptStubGenerator{ Array nameBlacklist = Array.with("ClientLauncher", "NetClient", "NetServer", "ClassAccess"); Array> whitelist = Array.with(Draw.class, Fill.class, Lines.class, Core.class, TextureAtlas.class, TextureRegion.class, Time.class, System.class, PrintStream.class, AtlasRegion.class, String.class, Mathf.class, Angles.class, Color.class, Runnable.class, Object.class, Icon.class, Tex.class, - Sounds.class, Musics.class, Call.class, Texture.class, TextureData.class, Pixmap.class, I18NBundle.class, Interval.class, DataInput.class, DataOutput.class, DataInputStream.class, DataOutputStream.class); + Sounds.class, Musics.class, Call.class, Texture.class, TextureData.class, Pixmap.class, I18NBundle.class, Interval.class, DataInput.class, DataOutput.class, + DataInputStream.class, DataOutputStream.class, Integer.class, Float.class, Double.class, Long.class, Boolean.class, Short.class, Byte.class, Character.class); Array nopackage = Array.with("java.lang", "java"); String fileTemplate = "package mindustry.mod;\n" + From 5f3c10e3978de22a1392d09468c9ec32db0085e4 Mon Sep 17 00:00:00 2001 From: Anuken Date: Thu, 2 Jan 2020 14:33:21 -0500 Subject: [PATCH 66/78] arc --- gradle.properties | 2 +- tools/src/mindustry/tools/ScriptStubGenerator.java | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/gradle.properties b/gradle.properties index 1456cfdefc..13b714378d 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,3 +1,3 @@ org.gradle.daemon=true org.gradle.jvmargs=-Xms256m -Xmx1024m -archash=e151bac7925323f24932ff3ae3f9eacfd6d3a268 +archash=b3d3fc19560148f16b58ac7e04903f9db4f56912 diff --git a/tools/src/mindustry/tools/ScriptStubGenerator.java b/tools/src/mindustry/tools/ScriptStubGenerator.java index aadb1309bc..be1d9dd27d 100644 --- a/tools/src/mindustry/tools/ScriptStubGenerator.java +++ b/tools/src/mindustry/tools/ScriptStubGenerator.java @@ -31,8 +31,7 @@ public class ScriptStubGenerator{ Array nopackage = Array.with("java.lang", "java"); String fileTemplate = "package mindustry.mod;\n" + - "\n" + - "import arc.struct.*;\n" + + "\nimport arc.struct.*;\n" + "//obviously autogenerated, do not touch\n" + "public class ClassAccess{\n" + "\tpublic static final ObjectSet allowedClassNames = ObjectSet.with($ALLOWED_CLASS_NAMES$);\n" + From 7fa61eaf3ba0572dc9a408685de12e22a5976228 Mon Sep 17 00:00:00 2001 From: Anuken Date: Thu, 2 Jan 2020 22:09:33 -0500 Subject: [PATCH 67/78] Added server MOTD --- core/src/mindustry/core/NetServer.java | 4 ++++ core/src/mindustry/net/Administration.java | 3 ++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/core/src/mindustry/core/NetServer.java b/core/src/mindustry/core/NetServer.java index 27e1ed1198..774489a4a5 100644 --- a/core/src/mindustry/core/NetServer.java +++ b/core/src/mindustry/core/NetServer.java @@ -589,6 +589,10 @@ public class NetServer implements ApplicationListener{ if(Config.showConnectMessages.bool()) Call.sendMessage("[accent]" + player.name + "[accent] has connected."); Log.info("&lm[{1}] &y{0} has connected. ", player.name, player.uuid); + if(!Config.motd.string().equalsIgnoreCase("off")){ + player.sendMessage(Config.motd.string()); + } + Events.fire(new PlayerJoin(player)); } diff --git a/core/src/mindustry/net/Administration.java b/core/src/mindustry/net/Administration.java index 8d037b99dd..9f068095d9 100644 --- a/core/src/mindustry/net/Administration.java +++ b/core/src/mindustry/net/Administration.java @@ -330,7 +330,8 @@ public class Administration{ socketInputPort("The port for socket input.", 6859, () -> Events.fire(Trigger.socketConfigChanged)), socketInputAddress("The bind address for socket input.", "localhost", () -> Events.fire(Trigger.socketConfigChanged)), allowCustomClients("Whether custom clients are allowed to connect.", !headless, "allow-custom"), - whitelist("Whether the whitelist is used.", false); + whitelist("Whether the whitelist is used.", false), + motd("The message displayed to people on connection.", "off"); public static final Config[] all = values(); From 439605f6e828e33f4a3afaec98b274dca10107d1 Mon Sep 17 00:00:00 2001 From: Simon Woodburry-Forget Date: Sat, 4 Jan 2020 00:32:03 -0500 Subject: [PATCH 68/78] use findAll to iterate through mod content (#1313) --- core/src/mindustry/mod/Mods.java | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/core/src/mindustry/mod/Mods.java b/core/src/mindustry/mod/Mods.java index e4907ed26c..ef4af6a8ec 100644 --- a/core/src/mindustry/mod/Mods.java +++ b/core/src/mindustry/mod/Mods.java @@ -512,10 +512,8 @@ public class Mods implements Loadable{ for(ContentType type : ContentType.all){ Fi folder = contentRoot.child(type.name().toLowerCase() + "s"); if(folder.exists()){ - for(Fi file : folder.list()){ - if(file.extension().equals("json") || file.extension().equals("hjson")){ - runs.add(new LoadRun(type, file, mod)); - } + for(Fi file : folder.findAll(f -> f.extension().equals("json") || f.extension().equals("hjson"))){ + runs.add(new LoadRun(type, file, mod)); } } } From 197769a9feb48be93c5998b2c0317abdf8c4a3b7 Mon Sep 17 00:00:00 2001 From: Anuken Date: Sat, 4 Jan 2020 12:10:03 -0500 Subject: [PATCH 69/78] Fixed #1319 --- core/src/mindustry/game/Schematics.java | 3 +++ core/src/mindustry/world/blocks/distribution/MassDriver.java | 3 ++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/core/src/mindustry/game/Schematics.java b/core/src/mindustry/game/Schematics.java index fd6e10022d..7a96ed672b 100644 --- a/core/src/mindustry/game/Schematics.java +++ b/core/src/mindustry/game/Schematics.java @@ -142,6 +142,7 @@ public class Schematics implements Loadable{ ui.showException(e); } } + all.sort(); } public void savePreview(Schematic schematic, Fi file){ @@ -280,6 +281,7 @@ public class Schematics implements Loadable{ ui.showException(e); Log.err(e); } + all.sort(); } public void remove(Schematic s){ @@ -292,6 +294,7 @@ public class Schematics implements Loadable{ previews.get(s).dispose(); previews.remove(s); } + all.sort(); } /** Creates a schematic from a world selection. */ diff --git a/core/src/mindustry/world/blocks/distribution/MassDriver.java b/core/src/mindustry/world/blocks/distribution/MassDriver.java index 1156857289..2974fe457f 100644 --- a/core/src/mindustry/world/blocks/distribution/MassDriver.java +++ b/core/src/mindustry/world/blocks/distribution/MassDriver.java @@ -262,6 +262,7 @@ public class MassDriver extends Block{ } protected boolean shooterValid(Tile tile, Tile other){ + if(other == null) return true; if(!(other.block() instanceof MassDriver)) return false; MassDriverEntity entity = other.ent(); @@ -274,7 +275,7 @@ public class MassDriver extends Block{ if(entity == null || entity.link == -1) return false; Tile link = world.tile(entity.link); - return link != null && link.block() instanceof MassDriver && tile.dst(link) <= range; + return link != null && link.block() instanceof MassDriver && link.getTeam() == tile.getTeam() && tile.dst(link) <= range; } public static class DriverBulletData implements Poolable{ From 1dd0295c45e6ea6f0967f291b41ff3a58ab7202c Mon Sep 17 00:00:00 2001 From: DeltaNedas <39013340+DeltaNedas@users.noreply.github.com> Date: Sat, 4 Jan 2020 17:15:43 +0000 Subject: [PATCH 70/78] make turnCursor: false mechs not cross eyed (#1301) * create new branch * add targetDistance to weapons for mechs players will use if turnCursor is false --- core/src/mindustry/entities/type/Player.java | 2 +- core/src/mindustry/type/Weapon.java | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/core/src/mindustry/entities/type/Player.java b/core/src/mindustry/entities/type/Player.java index 4077da0e4e..6f28acb17c 100644 --- a/core/src/mindustry/entities/type/Player.java +++ b/core/src/mindustry/entities/type/Player.java @@ -637,7 +637,7 @@ public class Player extends Unit implements BuilderMinerTrait, ShooterTrait{ if(!state.isEditor() && isShooting() && mech.canShoot(this)){ if(!mech.turnCursor){ //shoot forward ignoring cursor - mech.weapon.update(this, x + Angles.trnsx(rotation, 1f), y + Angles.trnsy(rotation, 1f)); + mech.weapon.update(this, x + Angles.trnsx(rotation, mech.weapon.targetDistance), y + Angles.trnsy(rotation, mech.weapon.targetDistance)); }else{ mech.weapon.update(this, pointerX, pointerY); } diff --git a/core/src/mindustry/type/Weapon.java b/core/src/mindustry/type/Weapon.java index 0e3583a552..175abd1d24 100644 --- a/core/src/mindustry/type/Weapon.java +++ b/core/src/mindustry/type/Weapon.java @@ -55,6 +55,8 @@ public class Weapon{ public float shotDelay = 0; /** whether shooter rotation is ignored when shooting. */ public boolean ignoreRotation = false; + /** if turnCursor is false for a mech, how far away will the weapon target. */ + public float targetDistance = 1f; public Sound shootSound = Sounds.pew; From 5f1ea4b098b4158388acb143a47bfc63643e52a1 Mon Sep 17 00:00:00 2001 From: Dave <16521341+davidmfritz@users.noreply.github.com> Date: Sat, 4 Jan 2020 18:39:57 +0100 Subject: [PATCH 71/78] UX improvements for showTextInput (#1290) * Added keyDown support for showTextInput (Enter, Escape, Back) * Removed unnecessary "this" * Added cursor autofocus on showTextInput --- core/src/mindustry/core/UI.java | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/core/src/mindustry/core/UI.java b/core/src/mindustry/core/UI.java index 58cb23d802..f1b578cc9c 100644 --- a/core/src/mindustry/core/UI.java +++ b/core/src/mindustry/core/UI.java @@ -307,7 +307,19 @@ public class UI implements ApplicationListener, Loadable{ hide(); }).disabled(b -> field.getText().isEmpty()); buttons.addButton("$cancel", this::hide); - }}.show(); + keyDown(KeyCode.ENTER, () -> { + String text = field.getText(); + if(!text.isEmpty()){ + confirmed.get(text); + hide(); + } + }); + keyDown(KeyCode.ESCAPE, this::hide); + keyDown(KeyCode.BACK, this::hide); + show(); + Core.scene.setKeyboardFocus(field); + field.setCursorPosition(def.length()); + }}; } } From eb70283355101fb1a5b832ac051e35e0742b0f02 Mon Sep 17 00:00:00 2001 From: Patrick 'Quezler' Mounier Date: Sat, 4 Jan 2020 18:40:12 +0100 Subject: [PATCH 72/78] Use current directory explicitly for bundle updator (#1316) --- tools/src/mindustry/tools/BundleLauncher.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/src/mindustry/tools/BundleLauncher.java b/tools/src/mindustry/tools/BundleLauncher.java index 668d4665fe..1f73b26f28 100644 --- a/tools/src/mindustry/tools/BundleLauncher.java +++ b/tools/src/mindustry/tools/BundleLauncher.java @@ -15,7 +15,7 @@ public class BundleLauncher{ OrderedMap base = new OrderedMap<>(); PropertiesUtils.load(base, new InputStreamReader(new FileInputStream(file))); Array removals = new Array<>(); - Fi.get("").walk(child -> { + Fi.get(".").walk(child -> { if(child.name().equals("bundle.properties") || child.isDirectory() || child.toString().contains("output")) return; From 8af3b877b58e55800f59866b52f0e90b279aeb8a Mon Sep 17 00:00:00 2001 From: Anuken Date: Sat, 4 Jan 2020 15:12:29 -0500 Subject: [PATCH 73/78] Fixed #1320 --- core/src/mindustry/game/Teams.java | 4 ++-- gradle.properties | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/core/src/mindustry/game/Teams.java b/core/src/mindustry/game/Teams.java index dc44d47240..e4fa1f1ef3 100644 --- a/core/src/mindustry/game/Teams.java +++ b/core/src/mindustry/game/Teams.java @@ -80,7 +80,7 @@ public class Teams{ /** Returns whether a team is active, e.g. whether it has any cores remaining. */ public boolean isActive(Team team){ //the enemy wave team is always active - return team == state.rules.waveTeam || get(team).cores.size > 0; + return get(team).active(); } /** Returns whether {@param other} is an enemy of {@param #team}. */ @@ -150,7 +150,7 @@ public class Teams{ } public boolean active(){ - return team == state.rules.waveTeam || cores.size > 0; + return (team == state.rules.waveTeam && state.rules.waves) || cores.size > 0; } public boolean hasCore(){ diff --git a/gradle.properties b/gradle.properties index 13b714378d..015c89b285 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,3 +1,3 @@ org.gradle.daemon=true org.gradle.jvmargs=-Xms256m -Xmx1024m -archash=b3d3fc19560148f16b58ac7e04903f9db4f56912 +archash=919a8f30e16d6b3d8fa96d438c5ff621899b4368 From 71da1f1135930e468f2262d8640be81253509dde Mon Sep 17 00:00:00 2001 From: Anuken Date: Sun, 5 Jan 2020 00:08:48 -0500 Subject: [PATCH 74/78] Added mod listing data class --- core/src/mindustry/mod/ModListing.java | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 core/src/mindustry/mod/ModListing.java diff --git a/core/src/mindustry/mod/ModListing.java b/core/src/mindustry/mod/ModListing.java new file mode 100644 index 0000000000..d0c1d80094 --- /dev/null +++ b/core/src/mindustry/mod/ModListing.java @@ -0,0 +1,19 @@ +package mindustry.mod; + +/** Mod listing as a data class. */ +public class ModListing{ + public String repo, name, author, lastUpdated, description; + public int stars; + + @Override + public String toString(){ + return "ModListing{" + + "repo='" + repo + '\'' + + ", name='" + name + '\'' + + ", author='" + author + '\'' + + ", lastUpdated='" + lastUpdated + '\'' + + ", description='" + description + '\'' + + ", stars=" + stars + + '}'; + } +} From 9d9e31948d57011c0e48eaf8e589e9243917081a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Du=C5=A1ek?= Date: Sun, 5 Jan 2020 23:41:41 +0100 Subject: [PATCH 75/78] Add - tutorial localized, description coverage++, fix broken translations (#1327) --- core/assets/bundles/bundle_cs.properties | 263 ++++++++++++----------- core/assets/contributors | 1 + 2 files changed, 133 insertions(+), 131 deletions(-) diff --git a/core/assets/bundles/bundle_cs.properties b/core/assets/bundles/bundle_cs.properties index 1161de677c..e2154fc185 100644 --- a/core/assets/bundles/bundle_cs.properties +++ b/core/assets/bundles/bundle_cs.properties @@ -7,7 +7,7 @@ link.reddit.description = Mindustry na Redditu link.github.description = Zdrojový kód hry link.changelog.description = Seznam úprav link.dev-builds.description = Nestabilní vývojová verze hry -link.trello.description = Oficiální nástěnka na Trello s plány rozvoje hry +link.trello.description = Oficiální Trello nástěnka s plánovanými novinkami link.itch.io.description = Stránka na itch.io s odkazy na stažení hry link.google-play.description = Obchod Google Play link.f-droid.description = Katalog F-Droid @@ -32,27 +32,27 @@ load.scripts = Skripty schematic = Šablona schematic.add = Uložit šablonu... schematics = Šablony -schematic.replace = Šablona tohoto jména již exisruje. Přeješ si ji nahradit? +schematic.replace = Šablona tohoto jména již existuje. Chceš ji nahradit? schematic.import = Importovat šablonu... schematic.exportfile = Exportovat soubor schematic.importfile = Importovat soubor schematic.browseworkshop = Procházet dílnu schematic.copy = Zkopírovat do schránky schematic.copy.import = Importovat ze schránky -schematic.shareworkshop = Sdílet v dílně -schematic.flip = [accent][[{0}][]/[accent][[{1}][]: Obrátit šablonu +schematic.shareworkshop = Sdílet skrze Steam Workshop +schematic.flip = [accent][[{0}][]/[accent][[{1}][]: Převrátit šablonu schematic.saved = Šablona byla uložena. -schematic.delete.confirm = Tato šablona bude beze zbytku smazána. +schematic.delete.confirm = Šablona bude kompletně vyhlazena. schematic.rename = Přejmenovat šablonu schematic.info = {0}x{1}, {2} bloků -stat.wave = Vln poraženo :[accent]{0} -stat.enemiesDestroyed = Nepřátel zničeno :[accent]{0}[] -stat.built = Budov postaveno: [accent]{0}[] -stat.destroyed = Budov zničeno: [accent]{0}[] -stat.deconstructed = Budov rozebráno: [accent]{0}[] +stat.wave = Vln poraženo:[accent] {0} +stat.enemiesDestroyed = Nepřátel zničeno:[accent] {0} +stat.built = Budov postaveno:[accent] {0} +stat.destroyed = Budov zničeno:[accent] {0} +stat.deconstructed = Budov rozebráno:[accent] {0} stat.delivered = Materiálu vysláno: -stat.rank = Závěrečné hodnocení: [accent]{0}[] +stat.rank = Celková známka: [accent]{0} launcheditems = [accent]Vyslané předměty[] launchinfo = [unlaunched][Je třeba [LAUNCH] Tvé jádro, abys získal věci vyznačené modře. @@ -249,7 +249,7 @@ data.import.confirm = Import externích dat smaže [scarlet]všechna[] Tvoje sou classic.export = Exportovat data pro verzi Classic classic.export.text = [accent]Mindustry[] mělo významnou aktualizaci.\nByly detekovány uložení hry nebo mapy pro předchozí verzi Classic (v3.5 build 40). Chtěl bys exportovat tato uložení do domovského zařízení Tvého telefonu, pro pozdější použití v této verzi Mindustry Classic? quit.confirm = Jsi si jistý, že chceš ukončit hru? -quit.confirm.tutorial = Jste si vážně jistý?\Výuka se dá znovu spustit v [accent]Nastavení->Hra->Spusť výuku[]. +quit.confirm.tutorial = Jsi si jistý?\nTutoriál je možné znovu spustit v [accent]Nastavení->Hra->Zopáknout si výuku[]. loading = [accent]Načítám... reloading = [accent]Načítám modifikace... saving = [accent]Ukládám... @@ -262,8 +262,8 @@ wave.waiting = [LIGHT_GRAY]Vlna za {0} wave.waveInProgress = [LIGHT_GRAY]Vlna v pohybu waiting = [LIGHT_GRAY]Čekám... waiting.players = Čekání na hráče... -wave.enemies = [LIGHT_GRAY]{0} Nepřátel zbývá -wave.enemy = [LIGHT_GRAY]{0} Nepřítel zbývá +wave.enemies = [LIGHT_GRAY]{0} zbývajících nepřátel +wave.enemy = [LIGHT_GRAY]{0} zbývající nepřítel loadimage = Nahrát obrázek saveimage = Uložit obrázek unknown = Neznámý @@ -436,12 +436,12 @@ launch = Vyslat launch.title = Vyslání úspěšné launch.next = [LIGHT_GRAY]další možnost až ve vlně {0} launch.unable2 = [scarlet]Není možno vyslat.[] -launch.confirm = Toto vyšle veškeré suroviny ve tvém jádru .\nJiž se na tuto základnu nebudeš moci vrátit. -launch.skip.confirm = Jestli teď zůstaneš, budeš moci odejít až v pozdější fázi. +launch.confirm = Chystáš se opustit tuto základnu. Kliknutím na OK vyšleš veškeré suroviny ve tvém jádře.\nJiž se na tuto základnu nebudeš moci vrátit. +launch.skip.confirm = Jestli teď zůstaneš, budeš moci odejít až v pozdější vlně. uncover = Odkrýt configure = Přizpůsobit vybavení -bannedblocks = Banned Blocks -addall = Add All +bannedblocks = Zakázané bloky +addall = Přidat vše configure.locked = [LIGHT_GRAY]Dosáhni vlny {0}\nk nastavení svého vybavení. configure.invalid = Hodnota musí být mezi 0 a{0}. zone.unlocked = [LIGHT_GRAY]{0} odemčeno. @@ -687,18 +687,18 @@ keybind.drop_unit.name = Zahodit jednotku keybind.zoom_minimap.name = Přiblížit minimapu mode.help.title = Popis módů mode.survival.name = Survival -mode.survival.description = Normální mód .Limitované suroviny a automatické přepínání vln. +mode.survival.description = Normální mód. Limitované suroviny a automatické přepínání vln. mode.sandbox.name = Sandbox mode.sandbox.description = Nekonečné zdroje a žádný čas pro vlny nepřátel. mode.editor.name = Editor mode.pvp.name = PvP mode.pvp.description = Bojuj proti ostatním hráčům v lokální síti. mode.attack.name = Útok -mode.attack.description = Bez vln znič nepř@telsou základnu. +mode.attack.description = Bez vln znič nepřátelskou základnu. mode.custom = Custom Rules rules.infiniteresources = Nekonečno surovin rules.wavetimer = Časovač vln -rules.waves = Wlny +rules.waves = Vlny rules.attack = Attack Mode rules.enemyCheat = Infinite AI Resources rules.unitdrops = Unit Drops @@ -724,7 +724,7 @@ rules.title.enemy = Nepřátelé rules.title.unit = Jednotky content.item.name = Předměty content.liquid.name = Tekutiny -content.unit.name = jednotky +content.unit.name = Jednotky content.block.name = Blocks content.mech.name = Mechy item.copper.name = Měď @@ -742,7 +742,7 @@ item.sand.name = Písek item.blast-compound.name = Výbušná směs item.pyratite.name = Pyratite item.metaglass.name = Tvrzené sklo -item.scrap.name = Scrap +item.scrap.name = Šrot liquid.water.name = Voda liquid.slag.name = Rostavené železo liquid.oil.name = Ropa @@ -754,20 +754,20 @@ mech.delta-mech.name = Delta mech.delta-mech.weapon = Obloukový generátor mech.delta-mech.ability = Průtok mech.tau-mech.name = Tau -mech.tau-mech.weapon = Restruktní Laser +mech.tau-mech.weapon = Restruktní laser mech.tau-mech.ability = Opravná dávka mech.omega-mech.name = Omega mech.omega-mech.weapon = Rojové střely -mech.omega-mech.ability = Obrněná Konfigurace +mech.omega-mech.ability = Obrněná konfigurace mech.dart-ship.name = Šipka mech.dart-ship.weapon = Opakovač mech.javelin-ship.name = Oštěp -mech.javelin-ship.weapon = Dávka Raket -mech.javelin-ship.ability = Výbojový Posilovač +mech.javelin-ship.weapon = Dávka raket +mech.javelin-ship.ability = Výbojový posilovač mech.trident-ship.name = Trojzubec mech.trident-ship.weapon = Bombová zátoka mech.glaive-ship.name = Glaiva -mech.glaive-ship.weapon = Plamenný Opakovač +mech.glaive-ship.weapon = Plamenný opakovač item.explosiveness = [LIGHT_GRAY]Výbušnost: {0}% item.flammability = [LIGHT_GRAY]Zápalnost: {0}% item.radioactivity = [LIGHT_GRAY]Radioaktivita: {0}% @@ -783,34 +783,35 @@ mech.buildspeed = [LIGHT_GRAY]Rychlost stavění: {0}% liquid.heatcapacity = [LIGHT_GRAY]Kapacita teploty: {0} liquid.viscosity = [LIGHT_GRAY]Viskozita: {0} liquid.temperature = [LIGHT_GRAY]Teplota: {0} -block.sand-boulder.name = Sand Boulder + +block.sand-boulder.name = Balvan písku block.grass.name = Tráva -block.salt.name = sůl +block.salt.name = Sůl block.saltrocks.name = Solný kámen -block.pebbles.name = Pebbles +block.pebbles.name = Oblázky block.tendrils.name = Tendrils block.sandrocks.name = Písečný kámen -block.spore-pine.name = Spore Pine -block.sporerocks.name = Spore Rocks -block.rock.name = Rock +block.spore-pine.name = Spórová borovice +block.sporerocks.name = Spórové kamení +block.rock.name = Kámen block.snowrock.name = Sněhový kámen -block.snow-pine.name = Snow Pine -block.shale.name = Shale -block.shale-boulder.name = Shale Boulder +block.snow-pine.name = Sněžná borovice +block.shale.name = Břidlice +block.shale-boulder.name = Břidličný balvan block.moss.name = Mech -block.shrubs.name = Shrubs -block.spore-moss.name = Spore Moss -block.shalerocks.name = Shale Rocks +block.shrubs.name = Křoví +block.spore-moss.name = Spórový mech +block.shalerocks.name = Břidlicové kamení block.scrap-wall.name = Stará zeď block.scrap-wall-large.name = Velá stará zeď -block.scrap-wall-huge.name = obří stará zeď +block.scrap-wall-huge.name = Obří stará zeď block.scrap-wall-gigantic.name = Gigantická stará zeď block.thruster.name = Thruster -block.kiln.name = Kiln +block.kiln.name = Pec block.graphite-press.name = Graphitový lis -block.multi-press.name = Všětraný lys -block.constructing = {0} [LIGHT_GRAY](Constructing) -block.spawn.name = Nepřátelský Spawn +block.multi-press.name = Všětraný lis +block.constructing = {0} [LIGHT_GRAY](Ve výstavbě) +block.spawn.name = Nepřátelský spawn block.core-shard.name = Core: Shard block.core-foundation.name = Core: Foundation block.core-nucleus.name = Core: Nucleus @@ -852,14 +853,14 @@ block.dark-panel-6.name = Dark Panel 6 block.dark-metal.name = Dark Metal block.ignarock.name = Igna Rock block.hotrock.name = Hot Rock -block.magmarock.name = Magma Rock -block.cliffs.name = Cliffs +block.magmarock.name = Magmatický kámen +block.cliffs.name = Útesy block.copper-wall.name = Měděná zeď block.copper-wall-large.name = Velká měděná zeď -block.titanium-wall.name = Titanium Zeď -block.titanium-wall-large.name = Velká Titanium Zeď -block.plastanium-wall.name = Plastanium Zeď -block.plastanium-wall-large.name = Velká Plastanium Zeď +block.titanium-wall.name = Titaniová zeď +block.titanium-wall-large.name = Velká titaniová zeď +block.plastanium-wall.name = Plastaniová zeď +block.plastanium-wall-large.name = Velká plastaniová zeď block.phase-wall.name = Fázová stěna block.phase-wall-large.name = Velká fázová stěna block.thorium-wall.name = Thoriová stěna @@ -873,14 +874,14 @@ block.hail.name = Hail block.lancer.name = Lancer block.conveyor.name = Dopravník block.titanium-conveyor.name = Titániový dopravník -block.armored-conveyor.name = Armored Conveyor -block.armored-conveyor.description = Moves items at the same speed as titanium conveyors, but possesses more armor. Does not accept inputs from the sides from anything but other conveyors. +block.armored-conveyor.name = Obrněný dopravník +block.armored-conveyor.description = Přepravuje předměty stejně rychle jako titaniový přepravník. Je obrněný a déle vydrží, avšak nepřijímá předměty z boku z ničeho jiného než jiných přepravníků. block.junction.name = Křižovatka block.router.name = Směrovač block.distributor.name = Distributor block.sorter.name = Dělička -block.inverted-sorter.name = Inverted Sorter -block.message.name = Message +block.inverted-sorter.name = Obrácená třídička +block.message.name = Zpráva block.overflow-gate.name = Brána přetečení block.silicon-smelter.name = Silicon Smelter block.phase-weaver.name = Tkalcovna pro fázovou tkaninu @@ -927,24 +928,24 @@ block.salvo.name = Salva block.ripple.name = Vlnění block.phase-conveyor.name = Fázový přepravník block.bridge-conveyor.name = Mostový přepravník -block.plastanium-compressor.name = Kompresor na Plastanium +block.plastanium-compressor.name = Kompresor na plastanium block.pyratite-mixer.name = Pyratit mixér block.blast-mixer.name = Výbušninový mixér block.solar-panel.name = Solární panel block.solar-panel-large.name = Velký solární panel -block.oil-extractor.name = Ropný Extraktor +block.oil-extractor.name = Ropný extraktor block.command-center.name = Řídící středisko block.draug-factory.name = Draug Miner Drone Factory -block.spirit-factory.name = Továrna na Spirit Drony -block.phantom-factory.name = Továrna na Fantom Drony +block.spirit-factory.name = Továrna na Spirit drony +block.phantom-factory.name = Továrna na Fantom drony block.wraith-factory.name = Továrna na Wraithy -block.ghoul-factory.name = Továrna na Ghůl Bombardéry -block.dagger-factory.name = Továrna na Dagger Mechy -block.crawler-factory.name = Crawler Mech Factory -block.titan-factory.name = Továrna na Titán Mechy -block.fortress-factory.name = Továrna na Fortress Mechy +block.ghoul-factory.name = Továrna na Ghůl bombardéry +block.dagger-factory.name = Továrna na Dagger mechy +block.crawler-factory.name = Továrna na Crawler mechy +block.titan-factory.name = Továrna na Titán mechy +block.fortress-factory.name = Továrna na Fortress mechy block.revenant-factory.name = Továrna na Revenanty -block.repair-point.name = Opravný Bod +block.repair-point.name = Opravný bod block.pulse-conduit.name = Pulzní potrubí block.phase-conduit.name = Fázové potrubí block.liquid-router.name = Směrovač tekutin @@ -952,23 +953,23 @@ block.liquid-tank.name = Nádrž na tekutiny block.liquid-junction.name = Křižovatka tekutin block.bridge-conduit.name = Mostové potrubí block.rotary-pump.name = Rotační pumpa -block.thorium-reactor.name = Thoriový Reaktor -block.mass-driver.name = Hromadný Distributor +block.thorium-reactor.name = Thoriový reaktor +block.mass-driver.name = Hromadný distributor block.blast-drill.name = Tlakovzdušný vrt block.thermal-pump.name = Termální pumpa -block.thermal-generator.name = Termální Generátor +block.thermal-generator.name = Termální generátor block.alloy-smelter.name = Slitinová pec block.mender.name = Mender block.mend-projector.name = Opravný projektor block.surge-wall.name = Impulzní stěna -block.surge-wall-large.name = Velká Impulzní stěna +block.surge-wall-large.name = Velká impulzní stěna block.cyclone.name = Cyklón block.fuse.name = Fůze block.shock-mine.name = Šoková mina block.overdrive-projector.name = Vysokorychlostní projektor block.force-projector.name = Silový projektor block.arc.name = Oblouk -block.rtg-generator.name = RTG Generátor +block.rtg-generator.name = RTG generátor block.spectre.name = Spektr block.meltdown.name = Meltdown block.container.name = Kontejnér @@ -981,14 +982,14 @@ team.orange.name = oranžová team.derelict.name = derelict team.green.name = zelená team.purple.name = fialová -unit.spirit.name = Spirit Dron +unit.spirit.name = Spirit dron unit.draug.name = Draug Miner Drone -unit.phantom.name = Fantom Dron +unit.phantom.name = Fantom dron unit.dagger.name = Dagger unit.crawler.name = Crawler unit.titan.name = Titán -unit.ghoul.name = Ghůl Bombardér -unit.wraith.name = Bojovník Wraith +unit.ghoul.name = Ghůl bombardér +unit.wraith.name = Wraith unit.fortress.name = Pevnost unit.revenant.name = Revenant unit.eruptor.name = Eruptor @@ -996,31 +997,31 @@ unit.chaos-array.name = Chaos Array unit.eradicator.name = Eradicator unit.lich.name = Lich unit.reaper.name = Reaper -tutorial.next = [lightgray] -tutorial.intro = You have entered the[scarlet] Mindustry Tutorial.[]\nBegin by[accent] mining copper[]. Tap a copper ore vein near your core to do this.\n\n[accent]{0}/{1} copper -tutorial.intro.mobile = You have entered the[scarlet] Mindustry Tutorial.[]\nSwipe the screen to move.\n[accent]Pinch with 2 fingers [] to zoom in and out.\nBegin by[accent] mining copper[]. Move close to it, then tap a copper ore vein near your core to do this.\n\n[accent]{0}/{1} copper -tutorial.drill = Manuální těžba je neefektivní.\n[accent]Vrty []budou těžit automaticky.\npolož jeden na měděnou rudu. -tutorial.drill.mobile = Mining manually is inefficient.\n[accent]Drills []can mine automatically.\nTap the drill tab in the bottom right.\nSelect the[accent] mechanical drill[].\nPlace it on a copper vein by tapping, then press the[accent] checkmark[] below to confirm your selection.\nPress the[accent] X button[] to cancel placement. -tutorial.blockinfo = Each block has different stats. Each drill can only mine certain ores.\nTo check a block's info and stats,[accent] tap the "?" button while selecting it in the build menu.[]\n\n[accent]Access the Mechanical Drill's stats now.[] +tutorial.next = [lightgray] +tutorial.intro = Vítej v [scarlet] Mindustry Tutoriálu.[]\nZačni [accent] těžením mědi[] - klikni na měděnou žílu v blízkosti jádra.\n\n[accent]{0}/{1} copper +tutorial.intro.mobile = Vítej v [scarlet] Mindustry Tutoriálu.[]\nPohybuj se táhnutím do stran.\nPřibližuj a oddaluj [accent]2 prsty [].\nZačni [accent] těžením mědi[] - přibliž se k měděné žíle v blízkosti jádra a klepni na ni.\n\n[accent]{0}/{1} mědi +tutorial.drill = Manuální těžba je neefektivní.\n[accent]Vrty []budou těžit automaticky.\nPostav jeden na měděnou rudu. +tutorial.drill.mobile = Manuální těžba je neefektivní.\n[accent]Vrty []budou těžit automaticky.\nKlepni na vrt v záložce dole vpravo.\nVyber [accent] mechanický vrt[].\nPolož ho klepnutím na měděnou žílu a následně potvrď [accent] fajfkou[] níže.\nStiskni [accent] X [] pro zrušení stavby. +tutorial.blockinfo = Každý blok má jiné vlastnosti. Každý vrt může těžit pouze některé suroviny.\nNa tyto vlastnosti se můžeš podívat [accent] klepnutím na "?" ve stavebním menu.[]\n\n[accent] Nyní se podívej na vlastnosti mechanického vrtu.[] tutorial.conveyor = [accent]Dopravníky[] jsou zapotřebí k dopravě materiálu k jádru.\nVytvoř řadu dopravníku od vrtu až k jádru. -tutorial.conveyor.mobile = [accent]Conveyors[] are used to transport items to the core.\nMake a line of conveyors from the drill to the core.\n[accent] Place in a line by holding down your finger for a few seconds[] and dragging in a direction.\n\n[accent]{0}/{1} conveyors placed in line\n[accent]0/1 items delivered +tutorial.conveyor.mobile = [accent]Dopravníky[] jsou zapotřebí k dopravě materiálu k jádru.\nVytvoř řadu dopravníku od vrtu až k jádru.\n[accent] Pokládej dopravníky v řadě dlouhým stiskem prstu[] a táhnutím v požadovaném směru.\n\n[accent]{0}/{1} přepravníků položeno v řadě\n[accent]0/1 předmětů doručeno tutorial.turret = Defenzivní stavby musí být postaveny za účelem obrany vůči[LIGHT_GRAY] nepříteli[].\nPostav střílnu Duo blízko svého jádra. -tutorial.drillturret = Duo střílny požadují[accent] měd jako střelivo []ke střelbě.\nPolož vrt blízko střílny pro zásobování mědí. -tutorial.pause = During battle, you are able to[accent] pause the game.[]\nYou may queue buildings while paused.\n\n[accent]Press space to pause. -tutorial.pause.mobile = During battle, you are able to[accent] pause the game.[]\nYou may queue buildings while paused.\n\n[accent]Press this button in the top left to pause. -tutorial.unpause = Now press space again to unpause. -tutorial.unpause.mobile = Now press it again to unpause. -tutorial.breaking = Blocks frequently need to be destroyed.\n[accent]Hold down right-click[] to destroy all blocks in a selection.[]\n\n[accent]Destroy all the scrap blocks to the left of your core using area selection. -tutorial.breaking.mobile = Blocks frequently need to be destroyed.\n[accent]Select deconstruction mode[], then tap a block to begin breaking it.\nDestroy an area by holding down your finger for a few seconds[] and dragging in a direction.\nPress the checkmark button to confirm breaking.\n\n[accent]Destroy all the scrap blocks to the left of your core using area selection. -tutorial.withdraw = In some situations, taking items directly from blocks is necessary.\nTo do this, [accent]tap a block[] with items in it, then [accent]tap the item[] in the inventory.\nMultiple items can be withdrawn by [accent]tapping and holding[].\n\n[accent]Withdraw some copper from the core.[] -tutorial.deposit = Deposit items into blocks by dragging from your ship to the destination block.\n\n[accent]Deposit your copper back into the core.[] -tutorial.waves = [LIGHT_GRAY] nepřítel[] je přibližuje.\n\nBraň své jádro po dobu dvou vln, postav více střílen. -tutorial.waves.mobile = The[lightgray] enemy[] approaches.\n\nDefend the core for 2 waves. Your ship will automatically fire at enemies.\nBuild more turrets and drills. Mine more copper. -tutorial.launch = Once you reach a specific wave, you are able to[accent] launch the core[], leaving your defenses behind and[accent] obtaining all the resources in your core.[]\nThese resources can then be used to research new technology.\n\n[accent]Press the launch button. +tutorial.drillturret = Duo střílny požadují[accent] měděnou munici []jako střelivo.\nPolož mechanický vrt blízko střílny pro zásobování mědí. +tutorial.pause = Během boje můžeš[accent] pauznout hru.[]\nBěhem pauzy je možné plánovat stavbu budov.\n\n[accent]Pauzni mezerníkem. +tutorial.pause.mobile = Během boje můžeš[accent] pauznout hru.[]\nBěhem pauzy je možné plánovat stavbu budov.\n\n[accent]Pauzu dáš tímhle tlačítkem vlevo nahoře. +tutorial.unpause = Teď zmáčkni mezerník znova a odpauzuj hru. +tutorial.unpause.mobile = Teď ho zmáčkni znova a odpauzuj hru. +tutorial.breaking = Často je nutné bloky i ničit.\n[accent]Drž pravé tlačítko[] a táhni pro výběr oblasti bloků ke zničení.[]\n\n[accent]Znič všechny bloky šrotu vlevo od tvého jádra. +tutorial.breaking.mobile = Často je nutné bloky i ničit.\n[accent]Vyber rozebírací mód[] a klepni na blok, který chceš zničit.\nZnič celou oblast delším stiskem prstu[] a táhnutím v nějakém směru.\nZmáčkni fajfku pro potvrzení zničení.\n\n[accent]Znič všechny bloky šrotu vlevo od tvého jádra. +tutorial.withdraw = Někdy je třeba odebírat předměty přímo z bloků.\n[accent]Klikni na blok[], ve kterém jsou předměty a pak [accent]klikni na předmět[] z jeho inventáře.\nVícero předmětů může být odebráno [accent]kliknutím a držením[].\n\n[accent]Odeber nějakou měď z jádra.[] +tutorial.deposit = Vložit předměty dovnitř bloku můžeš přetažením z tvé lodi na cílový blok.\n\n[accent]Vlož svou měď zpět do jádra.[] +tutorial.waves = [LIGHT_GRAY] Nepřítel[] se přibližuje.\n\nUbraň své jádro po dobu 2 vln, postav více střílen. +tutorial.waves.mobile = [lightgray] Nepřítel[] se přibližuje.\n\nUbraň své jádro po dobu 2 vln. Tvá loď bude automaticky střílet po nepřátelských jednotkách.\nPostav více střílen a vrtů. Natěž více mědi. +tutorial.launch = Jakmile dosáhneš určité vlny, budeš moci[accent] vyslat jádro[]. Opustíš tím svou základnu a[accent] získáš suroviny uložené v jádře.[]\nZískané suroviny mohou být použity pro výzkum nových technologií.\n\n[accent]Stiskni tlačítko vyslat jádro. item.copper.description = Užitečný strukturální materiál. Používá se rozsáhle v ostatních typech bloků. item.lead.description = Základní počáteční materiál. Požívá se rozsáhle v elektronice a v blocích pro transport tekutin. -item.metaglass.description = Vemi důležitá suočást všeho so se týká tekutin -item.graphite.description = Stlačený uhlík nedílná součást většiny infrastruktur +item.metaglass.description = Vemi důležitá součást všeho co se týká tekutin +item.graphite.description = Stlačený uhlík, používaný jako munice a v elektronických komponentách. item.sand.description = Běžný materiál rozšířeně používaný v spalování slitin. item.coal.description = Běžné a snadno dostupné palivo, pochází z Ostravy. item.titanium.description = Vzácný, velice lehký kov, používá se rozsáhle v trasportu tekutin, vrtech a letounech. @@ -1038,29 +1039,29 @@ liquid.slag.description = Rostavený scrap pou žívá se k vírobě olova mědi liquid.oil.description = Může být spálen, vybouchnout nebo použit jako chlazení. liquid.cryofluid.description = Nejefektivnější tekutina pro chlazení. mech.alpha-mech.description = Standartní mech. Má slušnou rychlost a poškození; Může vytvořit až 3 drony Pro zvýšenou ofenzivní způsobilost. -mech.delta-mech.description = Rychlý, Lehce obrněný mech vytvořený pro udeř a uteč akce. Působí malé poškození vůči struktůrám, ale může zneškodnit velkou skupinu nepřátelských jednotek velmi rychle svýmy elektro-obloukovými zbraněmi +mech.delta-mech.description = Rychlý, lehce obrněný mech vytvořený pro udeř a uteč akce. Působí malé poškození vůči struktůrám, ale může zneškodnit velkou skupinu nepřátelských jednotek velmi rychle svýmy elektro-obloukovými zbraněmi mech.tau-mech.description = Podpůrný mech. Léčí spojenecké stavby a jednotky střelbou do nich. Může léčit i spojence ve svém poli působení. mech.omega-mech.description = Objemný a velice dovře obrněný mech, určen pro útok v přední linii. Jeho schopnost obrnění blokuje až 90% příchozího poškození. -mech.dart-ship.description = Standartní loď. Poměrně rychlý a lehký, má malou ofenzívu a pomalou rychlost těžení. +mech.dart-ship.description = Standartní loď. Poměrně rychlá a lehká, má malou ofenzívu a pomalou rychlost těžení. mech.javelin-ship.description = Loď stylu udeř a uteč. Zpočátku pomalý ale umí akcelerovat do obrovské rychlosti a létat u nepřátelských základen a působit značné škody svými elektrickými zbraněmi a raketami. mech.trident-ship.description = Těžký bombardér. Docela dobře obrněný. -mech.glaive-ship.description = Obrovská, Dobře obrněná střelecká loď. Vybavena zápalným opakovačem. Dobrá akcelerace a maximální rychlost. -unit.draug.description = A primitive mining drone. Cheap to produce. Expendable. Automatically mines copper and lead in the vicinity. Delivers mined resources to the closest core. +mech.glaive-ship.description = Obrovská, dobře obrněná střelecká loď. Vybavena zápalným opakovačem. Dobrá akcelerace a maximální rychlost. +unit.draug.description = Jednoduchý těžící dron. Levný a postradatelný. Automaticky těží měď a olovo v blízkosti. Natěžené suroviny donese do nejbližšího jádra. unit.spirit.description = Startovní dron. Standartně se objevuje u jádra. Automaticky těží rudy a opravuje stavby. unit.phantom.description = Pokročilý dron. Automaticky těží rudy a opravuje stavby. Podstatně víc efektivní než Spirit dron. unit.dagger.description = Základní pozemní jednotka. Efektivní ve velkém počtu. -unit.crawler.description = A ground unit consisting of a stripped-down frame with high explosives strapped on top. Not particular durable. Explodes on contact with enemies. +unit.crawler.description = Pozemní jednotka zkonstruovaná z okřesané železné kostry a připlácnutých výbušnin. Vydrží málo a exploduje při kontaktu. unit.titan.description = Pokročilá, obrněná pozemní jednotka. Útočí jak na pozemní tak vzdušné nepřátelské jednotky. unit.fortress.description = Težká, pozemní artilérní jednotka. -unit.eruptor.description = A heavy mech designed to take down structures. Fires a stream of slag at enemy fortifications, melting them and setting volatiles on fire. +unit.eruptor.description = Těžký protibudovní mech. Střílí proud žhavé kapaliny na nepřátelské budovy. Zapaluje a roztavuje vše v cestě. unit.wraith.description = Rychlý, udeř a uteč stíhací letoun. unit.ghoul.description = Těžký, kobercový bombardér. unit.revenant.description = A heavy, hovering missile array. -block.message.description = Stores a message. Used for communication between allies. -block.graphite-press.description = Compresses chunks of coal into pure sheets of graphite. -block.multi-press.description = An upgraded version of the graphite press. Employs water and power to process coal quickly and efficiently. +block.message.description = Ukládá zprávu. Používá se pro komunikaci mezi spojenci. +block.graphite-press.description = Přeměňuje neforemné kusy uhlí do ušlechtilých výlisků graphitu. +block.multi-press.description = Vylepšená verze graphitového lisu. Využívá vodu a energii k rychlejšímu a efektivnějšímu zpracování uhlí. block.silicon-smelter.description = Redukuje písek s vysoce čistým koksem za účelem výroby křemíku. -block.kiln.description = Smelts sand and lead into metaglass. Requires small amounts of power. +block.kiln.description = Přetavuje písek a olovo do metaskla. Vyžaduje malé množství energie. block.plastanium-compressor.description = Produkuje plastánium za pomocí titánia a ropy. block.phase-weaver.description = Produkuje fázovou tkaninu z radioaktivního thoria a velkého množství písku. block.alloy-smelter.description = Produkuje impulzní slitinu z titánia, olova, křemíku a mědi. @@ -1069,7 +1070,7 @@ block.blast-mixer.description = Používá ropu k přeměně pyratitu do méně block.pyratite-mixer.description = Míchá uhlí, olovo a písek do velice hořlavého pyratitu. block.melter.description = Taví kámen při velice vysokých teplotách na lávu. block.separator.description = Vystaví kámen velkému tlaku vody k získání různých materiálů obsažené v kameni. -block.spore-press.description = Compresses spore pods into oil. +block.spore-press.description = Vylisuje ze spórů ropu. block.pulverizer.description = Drtí kámen na písek. Užitečné když se v oblasti nenalézá písek. block.coal-centrifuge.description = Solidifes oil into chunks of coal. block.incinerator.description = Zbaví tě přebytku předmětů. @@ -1080,10 +1081,10 @@ block.item-void.description = Likviduje jakéhokoliv vstupní předmět bež pou block.liquid-source.description = Nekonečný zdroj tekutin. Jen pro Sandbox. block.copper-wall.description = Levný defenzivní blok.\nUžitečný k obraně tvého jádra a střílen v prvotních vlnách nepřátel. block.copper-wall-large.description = Levný defenzivní blok.\nUžitečný k obraně tvého jádra a střílen v prvotních vlnách nepřátel.\nZabírá více polí. -block.titanium-wall.description = A moderately strong defensive block.\nProvides moderate protection from enemies. -block.titanium-wall-large.description = A moderately strong defensive block.\nProvides moderate protection from enemies.\nSpans multiple tiles. -block.plastanium-wall.description = A special type of wall that absorbs electric arcs and blocks automatic power node connections. -block.plastanium-wall-large.description = A special type of wall that absorbs electric arcs and blocks automatic power node connections.\nSpans multiple tiles. +block.titanium-wall.description = Středně dobrý obranný blok.\nPoskytuje středně dobrou obranu proti nepřátelům. +block.titanium-wall-large.description = Středně dobrý obranný blok.\nPoskytuje středně dobrou obranu proti nepřátelům.\nZabírá více polí. +block.plastanium-wall.description = Speciální typ zdi, která je schopná absorbovat elektrické oblouky a blokuje energetické připojení. +block.plastanium-wall-large.description = Speciální typ zdi, která je schopná absorbovat elektrické oblouky a blokuje energetické připojení.\nZabírá více polí. block.thorium-wall.description = Sílný defenzivní blok.\nDobrá obrana vůči nepřátelům. block.thorium-wall-large.description = Sílný defenzivní blok.\nDobrá obrana vůči nepřátelům..\nZabírá více polí. block.phase-wall.description = Né tak silná jako zeď Thoria ale odráží nepřátelské projektily dokud nejsou moc silné. @@ -1092,7 +1093,7 @@ block.surge-wall.description = Nejsilnější defenzivní blok.\nMá malou šanc block.surge-wall-large.description = Nejsilnější defenzivní blok.\nMá malou šanci vystřelit elektrický paprsek vůči útočníkovi.\nZabírá více polí. block.door.description = Malé dveře, které se dají otevřít nebo zavřít kliknutím na ně.\nKdyž otevřené nepřátelé mohou střílet a dostat se skrz. block.door-large.description = Velké dveře, které se dají otevřít nebo zavřít kliknutím na ně.\nKdyž otevřené nepřátelé mohou střílet a dostat se skrz.\nZabírá více polí. -block.mender.description = Periodically repairs blocks in its vicinity. Keeps defenses repaired in-between waves.\nOptionally uses silicon to boost range and efficiency. +block.mender.description = Pravidelně opravuje bloky ve svém okolí. Mezi vlnami opraví zátarasy.\nVolitelně lze využít křemíku pro posílení dosahu a efektivity. block.mend-projector.description = Kontinuálně léčí bloky v poli svého působení. block.overdrive-projector.description = Zrychluje funkce blízkých struktůr jako jsou vrty a dopravníky. block.force-projector.description = Vytvoří okolo sebe šestihrané silové pole, chrání jednotky a budovy uvnitř sebe vůči střelám. @@ -1120,13 +1121,13 @@ block.bridge-conduit.description = Pokročilý blok přepravy tekutin. Dovoluje block.phase-conduit.description = Pokročilý blok přepravy tekutin. Používá energii k teleportu tekutin do druhého bodu přez několik polí. block.power-node.description = Vysílá energii mezi propojenými uzly. Dokáže se propojit až se čtyřmi uzly či stavbami najednou. Uzel bude dostávat zásobu energie a bude ji distribuovat mezi připojené bloky. block.power-node-large.description = Má větší dosah než standartní energetický uzel and a dokáže propojit až 6 staveb nebo uzly. -block.surge-tower.description = An extremely long-range power node with fewer available connections. +block.surge-tower.description = Energetický uzel s extrémním dosahem, ale méně dostupnými přípojkami. block.battery.description = Ukládá energii kdykoliv kdy je nadbytek ,poskytuje energii kdykolik když je pokles energie v síti, tak dlouho doku zbývá kapacita. block.battery-large.description = Uloží více energie než standartní baterie. block.combustion-generator.description = Generuje energii spalováním ropy nebo jinných hořlavých materiálů. block.thermal-generator.description = Generuje obrovské množství energie z lávy. block.turbine-generator.description = Více efektivní než spalovací generátor, ale vyžaduje dodatečný přísun vody. -block.differential-generator.description = Generates large amounts of energy. Utilizes the temperature difference between cryofluid and burning pyratite. +block.differential-generator.description = Generuje velké množství energie. Využívá teplotního rozdílu mezi chladící kapalinou a hořícím pyratitem. block.rtg-generator.description = Rádioizotopní Termoelektrický Generátor nevyžaduje chlazení, za to generuje méně energie než Thoriový generátor. block.solar-panel.description = Poskytuje malé množství energie ze slunce. block.solar-panel-large.description = Poskytuje mnohem lepší zdroj energie než standartní solární panel, za to je mnohem nákladnější na stavbu. @@ -1139,17 +1140,17 @@ block.blast-drill.description = Ultimátní vrt, vyžaduje velké množství ene block.water-extractor.description = Extrahuje vodu ze země. Vhodný k použití když se v oblasti nenachází zdroj vody. block.cultivator.description = Kultivuje půdu vodou za účelem získání biohmoty. block.oil-extractor.description = Vyžaduje velké množství energie na extrakci ropy z písku. Použíj ho když se v oblasti nenachází žádný zdroj ropy. -block.core-shard.description = The first iteration of the core capsule. Once destroyed, all contact to the region is lost. Do not let this happen. -block.core-foundation.description = The second version of the core. Better armored. Stores more resources. -block.core-nucleus.description = The third and final iteration of the core capsule. Extremely well armored. Stores massive amounts of resources. -block.vault.description = Ukládá velké množství předmětů každého typu. Připojené kontejnéry, trezory nebo jádra se budou chovat jako samostatné skladovací jednotky. [LIGHT_GRAY] Odbavovač[] lže použít pro odbavení předmětů z trezoru. +block.core-shard.description = První verze jádra. V případě, že je zničeno, veškerý kontakt s regionem je ztracen. Nedopusťte aby se to stalo. +block.core-foundation.description = Druhá, lépe obrněná verze jádra. Pojme více surovin. +block.core-nucleus.description = Třetí a finální iterace vývoje jádra. Extrémně obrněná, extrémně prostorná. +block.vault.description = Ukládá velké množství předmětů každého typu. Připojené kontejnéry, trezory nebo jádra se budou chovat jako samostatné skladovací jednotky. [LIGHT_GRAY] Odbavovač[] lze použít pro odbavení předmětů z trezoru. block.container.description = Ukládá malé množství předmětů každého typu. Připojené kontejnéry, trezory nebo jádra se budou chovat jako samostatné skladovací jednotky. [LIGHT_GRAY] Odbavovač[] lze použít pro odbavení předmětů z kontejnéru. -block.unloader.description = Vykládá předměty z kontejnéru, trezoru nebo jádra na dopravník nebo přímo do produktivních bloků. Druh předmětu pro vykládání lze měti kliknutím na odbavovač. -block.launch-pad.description = Launches batches of items without any need for a core launch. Unfinished. -block.launch-pad-large.description = An improved version of the launch pad. Stores more items. Launches more frequently. +block.unloader.description = Vykládá předměty z kontejnéru, trezoru nebo jádra na dopravník nebo přímo do produktivních bloků. Druh předmětu pro vykládání lze změnit kliknutím na odbavovač. +block.launch-pad.description = Posílá dávky předmětů do vesmíru bez nutnosti vysílat jádro. Nedokončený. +block.launch-pad-large.description = Vylepšený Launch Pad. Větší úložný prostor, častěji vysílán do vesmíru. block.duo.description = Malá, levná střílna. -block.scatter.description = A medium-sized anti-air turret. Sprays clumps of lead or scrap flak at enemy units. -block.scorch.description = Burns any ground enemies close to it. Highly effective at close range. +block.scatter.description = Protivzdušná střílna střední velikosti. Střílí hrstky olova nebo šrotu. +block.scorch.description = Spálí nepřátele v blízkosti na prach. Velmi efektivní na malé vzdálenosti. block.hail.description = Malá artilérní střílna. block.wave.description = Středně vělká, rychle pálící střílna, která střílí krystalizované bubliny. block.lancer.description = Středně velká střílna, která střílí nabité elektrické paprsky. @@ -1161,8 +1162,8 @@ block.ripple.description = Velká artilérní střílna, která vystřelí něko block.cyclone.description = Velká rychle pálící střílna. block.spectre.description = Velká střílna, která vystřelí dva mocné projektily naráz. block.meltdown.description = Velká střílna, která vystřelí mocný paprsek dalekého dosahu. -block.command-center.description = Issues movement commands to allied units across the map.\nCauses units to patrol, attack an enemy core or retreat to the core/factory. When no enemy core is present, units will default to patrolling under the attack command. -block.draug-factory.description = Produces Draug mining drones. +block.command-center.description = Umožňuje zadávat příkazy k pohybu spojeneckých jednotek po mapě.\nUmožňuje výběr mezi patrolováním, útokem na nepřítele, či návratem k jádru nebo továrně. Pokud se na mapě nenachází nepřátelské jádro, jednotky budou patrolovat v útočném režimu. +block.draug-factory.description = Produkuje těžící Draug drony. block.spirit-factory.description = Produkuje lehké drony, kteří teží minerály a opravují budovy block.phantom-factory.description = Produkuje pokročilé drony kteří jsou podstatně efektivnější jak spirit droni. block.wraith-factory.description = Produkuje rychlé, udeř a uteč stíhače. @@ -1173,10 +1174,10 @@ block.crawler-factory.description = Produces fast self-destructing swarm units. block.titan-factory.description = Produkuje pokročilé, orněné pozemní jednotky. block.fortress-factory.description = Produkuje těžké artilérní, pozmení jednotky. block.repair-point.description = Kontinuálně léčí nejbližší budovy a jednotky. -block.dart-mech-pad.description = Provides transformation into a basic attack mech.\nUse by tapping while standing on it. -block.delta-mech-pad.description = Zanech zde své aktuální plavidlo a změn ho na rychlého, lehce obrněného mecha určeného pro udeř a uteč operace.\nPoužíj ho poklikáním když se nacházíš nad ním. -block.tau-mech-pad.description = Zanech zde své aktuální plavidlo a změn ho na na podpůrného mecha, který léčí spojenecké budovy a jednotky.\nPoužíj ho poklikáním když se nacházíš nad ním. -block.omega-mech-pad.description = Zanech zde své aktuální plavidlo a změn ho na objemného dobře obrněného mecha, určeného pro útok v přední linii.\nPoužíj ho poklikáním když se nacházíš nad ním. -block.javelin-ship-pad.description = Zanech zde své aktuální plavidlo a změn ho na silný a rychlý stíhač s bleskovými zbraněmi.\nPoužíj ho poklikáním když se nacházíš nad ním. -block.trident-ship-pad.description = Zanech zde své aktuální plavidlo a změň ho do docela dobře obrněného těžkého bombardéru.\nPoužíj ho poklikáním když se nacházíš nad ním. -block.glaive-ship-pad.description = Zanech zde své aktuální plavidlo a změn ho na velkou, dobře obrněnou střeleckou loď.\nPoužíj ho poklikáním když se nacházíš nad ním. +block.dart-mech-pad.description = Zanech zde své aktuální plavidlo a vyměň ho za základního útočného mecha.\nAktivuj kliknutím, když se nacházíš nad platformou. +block.delta-mech-pad.description = Zanech zde své aktuální plavidlo a vyměň ho za rychlého, lehce obrněného mecha určeného pro udeř a uteč operace.\nAktivuj kliknutím, když se nacházíš nad platformou. +block.tau-mech-pad.description = Zanech zde své aktuální plavidlo a vyměň ho za na podpůrného mecha, který léčí spojenecké budovy a jednotky.\nAktivuj kliknutím, když se nacházíš nad platformou. +block.omega-mech-pad.description = Zanech zde své aktuální plavidlo a vyměň ho za objemného dobře obrněného mecha, určeného pro útok v přední linii.\nAktivuj kliknutím, když se nacházíš nad platformou. +block.javelin-ship-pad.description = Zanech zde své aktuální plavidlo a vyměň ho za silný a rychlý stíhač s bleskovými zbraněmi.\nAktivuj kliknutím, když se nacházíš nad platformou. +block.trident-ship-pad.description = Zanech zde své aktuální plavidlo a vyměň ho za docela dobře obrněného těžkého bombardéru.\nAktivuj kliknutím, když se nacházíš nad platformou. +block.glaive-ship-pad.description = Zanech zde své aktuální plavidlo a vyměň ho za velkou, dobře obrněnou střeleckou loď.\nAktivuj kliknutím, když se nacházíš nad platformou. diff --git a/core/assets/contributors b/core/assets/contributors index 09337c529a..afe1bc3b45 100644 --- a/core/assets/contributors +++ b/core/assets/contributors @@ -84,3 +84,4 @@ amrsoll Draco Quezler Alicila +Daniel Dusek From 03286b29e8a888dbdfbbabdc55b37670b597bcfa Mon Sep 17 00:00:00 2001 From: Anuken Date: Mon, 6 Jan 2020 08:37:19 -0500 Subject: [PATCH 76/78] Changed Cyrillic font --- core/assets/fonts/font.ttf | Bin 8477164 -> 8478980 bytes gradle.properties | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/core/assets/fonts/font.ttf b/core/assets/fonts/font.ttf index 7a323554549d97153856cd083446eb2634c3f3e1..6b585dcbddc2e412c81599f66c5cba61a13e825f 100644 GIT binary patch delta 181743 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

2e@LT4Oc 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 RO{igen^0r5AG2(U6#!)3<*on# diff --git a/gradle.properties b/gradle.properties index 015c89b285..806d8ee368 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,3 +1,3 @@ org.gradle.daemon=true org.gradle.jvmargs=-Xms256m -Xmx1024m -archash=919a8f30e16d6b3d8fa96d438c5ff621899b4368 +archash=e18f0f1074ef97fc72053c57d82c39183420575d From dd3c4d06ac2dfd19e907e552f282949449f278f0 Mon Sep 17 00:00:00 2001 From: Patrick 'Quezler' Mounier Date: Mon, 6 Jan 2020 17:32:18 +0100 Subject: [PATCH 77/78] Mass driver place range assist (#1331) --- .../world/blocks/distribution/MassDriver.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/core/src/mindustry/world/blocks/distribution/MassDriver.java b/core/src/mindustry/world/blocks/distribution/MassDriver.java index 2974fe457f..f55c31fd28 100644 --- a/core/src/mindustry/world/blocks/distribution/MassDriver.java +++ b/core/src/mindustry/world/blocks/distribution/MassDriver.java @@ -162,6 +162,16 @@ public class MassDriver extends Block{ @Override public void drawPlace(int x, int y, int rotation, boolean valid){ Drawf.dashCircle(x * tilesize, y*tilesize, range, Pal.accent); + + // check if a mass driver is selected while placing this driver + if(!control.input.frag.config.isShown()) return; + Tile selected = control.input.frag.config.getSelectedTile(); + if(!(selected.block() instanceof MassDriver) || !(selected.dst(x * tilesize, y * tilesize) <= range)) return; + + // if so, draw a dotted line towards it while it is in range + Lines.stroke(2f, Pal.placing); + Lines.dashLine(x * tilesize, y * tilesize, selected.drawx(), selected.drawy(), (int)range / tilesize / 4); + Draw.reset(); } @Override From 7f23803db121e9f9a14fddbda0ccee6dde1f5083 Mon Sep 17 00:00:00 2001 From: Anuken Date: Mon, 6 Jan 2020 16:25:08 -0500 Subject: [PATCH 78/78] Visual changes --- .../world/blocks/distribution/MassDriver.java | 16 ++++++++++++---- .../mindustry/world/blocks/power/PowerDiode.java | 2 +- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/core/src/mindustry/world/blocks/distribution/MassDriver.java b/core/src/mindustry/world/blocks/distribution/MassDriver.java index f55c31fd28..eacef7d0eb 100644 --- a/core/src/mindustry/world/blocks/distribution/MassDriver.java +++ b/core/src/mindustry/world/blocks/distribution/MassDriver.java @@ -163,14 +163,22 @@ public class MassDriver extends Block{ public void drawPlace(int x, int y, int rotation, boolean valid){ Drawf.dashCircle(x * tilesize, y*tilesize, range, Pal.accent); - // check if a mass driver is selected while placing this driver + //check if a mass driver is selected while placing this driver if(!control.input.frag.config.isShown()) return; Tile selected = control.input.frag.config.getSelectedTile(); - if(!(selected.block() instanceof MassDriver) || !(selected.dst(x * tilesize, y * tilesize) <= range)) return; + if(selected == null || !(selected.block() instanceof MassDriver) || !(selected.dst(x * tilesize, y * tilesize) <= range)) return; - // if so, draw a dotted line towards it while it is in range + //if so, draw a dotted line towards it while it is in range + float sin = Mathf.absin(Time.time(), 6f, 1f); + Tmp.v1.set(x * tilesize + offset(), y * tilesize + offset()).sub(selected.drawx(), selected.drawy()).limit((size / 2f + 1) * tilesize + sin + 0.5f); + float x2 = x * tilesize - Tmp.v1.x, y2 = y * tilesize - Tmp.v1.y, + x1 = selected.drawx() + Tmp.v1.x, y1 = selected.drawy() + Tmp.v1.y; + int segs = (int)(selected.dst(x * tilesize, y * tilesize) / tilesize); + + Lines.stroke(4f, Pal.gray); + Lines.dashLine(x1, y1, x2, y2, segs); Lines.stroke(2f, Pal.placing); - Lines.dashLine(x * tilesize, y * tilesize, selected.drawx(), selected.drawy(), (int)range / tilesize / 4); + Lines.dashLine(x1, y1, x2, y2, segs); Draw.reset(); } diff --git a/core/src/mindustry/world/blocks/power/PowerDiode.java b/core/src/mindustry/world/blocks/power/PowerDiode.java index 282e716286..eea5b46d72 100644 --- a/core/src/mindustry/world/blocks/power/PowerDiode.java +++ b/core/src/mindustry/world/blocks/power/PowerDiode.java @@ -27,7 +27,7 @@ public class PowerDiode extends Block{ public void update(Tile tile){ super.update(tile); - if(tile.front() == null || tile.back() == null || !tile.back().block().hasPower || !tile.front().block().hasPower) return; + if(tile.front() == null || tile.back() == null || !tile.back().block().hasPower || !tile.front().block().hasPower || tile.back().getTeam() != tile.front().getTeam()) return; PowerGraph backGraph = tile.back().entity.power.graph; PowerGraph frontGraph = tile.front().entity.power.graph;