From 52bd079c0a97ea2dd1d52c5d2a477392c94310cd Mon Sep 17 00:00:00 2001 From: Anuken Date: Wed, 10 Oct 2018 23:43:48 -0400 Subject: [PATCH 01/11] Multithreading cleanup --- build.gradle | 2 +- .../io/anuke/mindustry/ai/WaveSpawner.java | 1 - .../anuke/mindustry/core/ContentLoader.java | 2 +- core/src/io/anuke/mindustry/core/Control.java | 6 +- core/src/io/anuke/mindustry/core/UI.java | 2 +- .../io/anuke/mindustry/entities/Units.java | 13 +- .../io/anuke/mindustry/graphics/Trail.java | 2 +- .../anuke/mindustry/input/InputHandler.java | 9 +- .../io/anuke/mindustry/input/MobileInput.java | 23 +- .../pathfinding/AStarPathFinder.java | 267 ------------------ core/src/io/anuke/mindustry/net/Net.java | 14 +- .../src/io/anuke/mindustry/net/NetworkIO.java | 2 - .../ui/fragments/PlayerListFragment.java | 7 +- core/src/io/anuke/mindustry/world/Build.java | 28 +- core/src/io/anuke/mindustry/world/Edges.java | 8 +- .../world/blocks/distribution/Conveyor.java | 8 +- .../src/io/anuke/kryonet/ByteSerializer.java | 10 +- kryonet/src/io/anuke/kryonet/KryoClient.java | 5 +- 18 files changed, 50 insertions(+), 359 deletions(-) delete mode 100644 core/src/io/anuke/mindustry/maps/generation/pathfinding/AStarPathFinder.java diff --git a/build.gradle b/build.gradle index e90d91b5cc..1a06394775 100644 --- a/build.gradle +++ b/build.gradle @@ -27,7 +27,7 @@ allprojects { appName = 'Mindustry' gdxVersion = '1.9.8' roboVMVersion = '2.3.0' - uCoreVersion = '628ced32dbceefe9096c6acc9639cd39b1a867f4' + uCoreVersion = '03c4093f724e63069e097393991592db308728e0' getVersionString = { String buildVersion = getBuildVersion() diff --git a/core/src/io/anuke/mindustry/ai/WaveSpawner.java b/core/src/io/anuke/mindustry/ai/WaveSpawner.java index 10133dcf50..e1a8638030 100644 --- a/core/src/io/anuke/mindustry/ai/WaveSpawner.java +++ b/core/src/io/anuke/mindustry/ai/WaveSpawner.java @@ -111,7 +111,6 @@ public class WaveSpawner{ if(group.type.isFlying){ FlyerSpawn spawn = flySpawns.get(flyCount); - //TODO verify flyer spawn float margin = 40f; //how far away from the edge flying units spawn spawnX = world.width() * tilesize / 2f + Mathf.sqrwavex(spawn.angle) * (world.width() / 2f * tilesize + margin); diff --git a/core/src/io/anuke/mindustry/core/ContentLoader.java b/core/src/io/anuke/mindustry/core/ContentLoader.java index e9c3c2aaf8..030b22f349 100644 --- a/core/src/io/anuke/mindustry/core/ContentLoader.java +++ b/core/src/io/anuke/mindustry/core/ContentLoader.java @@ -176,7 +176,7 @@ public class ContentLoader{ } public void dispose(){ - //TODO clear all content. + //clear all content, currently not needed } public void handleContent(Content content){ diff --git a/core/src/io/anuke/mindustry/core/Control.java b/core/src/io/anuke/mindustry/core/Control.java index 935a140fa9..f284d772d9 100644 --- a/core/src/io/anuke/mindustry/core/Control.java +++ b/core/src/io/anuke/mindustry/core/Control.java @@ -27,6 +27,7 @@ import io.anuke.ucore.entities.Entities; import io.anuke.ucore.entities.EntityQuery; import io.anuke.ucore.modules.Module; import io.anuke.ucore.util.Atlas; +import io.anuke.ucore.util.Timer; import static io.anuke.mindustry.Vars.*; @@ -43,6 +44,7 @@ public class Control extends Module{ public final Saves saves; public final Unlocks unlocks; + private Timer timerRPC= new Timer(), timerUnlock = new Timer(); private boolean hiscore = false; private boolean wasPaused = false; private InputHandler[] inputs = {}; @@ -348,12 +350,12 @@ public class Control extends Module{ } //auto-update rpc every 5 seconds - if(Timers.get("rpcUpdate", 60 * 5)){ + if(timerRPC.get(60 * 5)){ Platform.instance.updateRPC(); } //check unlocks every 2 seconds - if(!state.mode.infiniteResources && Timers.get("timerCheckUnlock", 120)){ + if(!state.mode.infiniteResources && timerUnlock.get(120)){ checkUnlockableBlocks(); //save if the unlocks changed diff --git a/core/src/io/anuke/mindustry/core/UI.java b/core/src/io/anuke/mindustry/core/UI.java index e880e6d609..9798d8f78c 100644 --- a/core/src/io/anuke/mindustry/core/UI.java +++ b/core/src/io/anuke/mindustry/core/UI.java @@ -117,7 +117,7 @@ public class UI extends SceneModule{ } @Override - public synchronized void update(){ + public void update(){ if(Graphics.drawing()) Graphics.end(); act(); diff --git a/core/src/io/anuke/mindustry/entities/Units.java b/core/src/io/anuke/mindustry/entities/Units.java index 5d5eee141c..aceb4f356f 100644 --- a/core/src/io/anuke/mindustry/entities/Units.java +++ b/core/src/io/anuke/mindustry/entities/Units.java @@ -54,14 +54,17 @@ public class Units{ return invalidateTarget(target, targeter.team, targeter.x, targeter.y, targeter.getWeapon().getAmmo().getRange()); } - /** - * Returns whether there are any entities on this tile. - */ + /**Returns whether there are any entities on this tile.*/ public static boolean anyEntities(Tile tile){ Block type = tile.block(); rect.setSize(type.size * tilesize, type.size * tilesize); rect.setCenter(tile.drawx(), tile.drawy()); + return anyEntities(rect); + } + + public static boolean anyEntities(Rectangle rect){ + boolResult = false; Units.getNearby(rect, unit -> { @@ -78,9 +81,7 @@ public class Units{ return boolResult; } - /** - * Returns whether there are any entities on this tile, with the hitbox expanded. - */ + /**Returns whether there are any entities on this tile, with the hitbox expanded.*/ public static boolean anyEntities(Tile tile, float expansion, Predicate pred){ Block type = tile.block(); rect.setSize(type.size * tilesize + expansion, type.size * tilesize + expansion); diff --git a/core/src/io/anuke/mindustry/graphics/Trail.java b/core/src/io/anuke/mindustry/graphics/Trail.java index f0f0d8bef4..1d5f3fade1 100644 --- a/core/src/io/anuke/mindustry/graphics/Trail.java +++ b/core/src/io/anuke/mindustry/graphics/Trail.java @@ -10,7 +10,7 @@ import io.anuke.ucore.graphics.Lines; import io.anuke.ucore.util.Mathf; /** - * Class that renders a trail. + * Class that renders a colored trail. */ public class Trail{ private final static float maxJump = 15f; diff --git a/core/src/io/anuke/mindustry/input/InputHandler.java b/core/src/io/anuke/mindustry/input/InputHandler.java index 8e19f2c9b0..6d940fd5b7 100644 --- a/core/src/io/anuke/mindustry/input/InputHandler.java +++ b/core/src/io/anuke/mindustry/input/InputHandler.java @@ -330,8 +330,11 @@ public abstract class InputHandler extends InputAdapter{ public boolean validPlace(int x, int y, Block type, int rotation){ for(Tile tile : state.teams.get(player.getTeam()).cores){ if(tile.distanceTo(x * tilesize, y * tilesize) < coreBuildRange){ - return Build.validPlace(player.getTeam(), x, y, type, rotation) && - Vector2.dst(player.x, player.y, x * tilesize, y * tilesize) < Player.placeDistance; + //TODO terrible hack + try{ + return Build.validPlace(player.getTeam(), x, y, type, rotation) && + Vector2.dst(player.x, player.y, x * tilesize, y * tilesize) < Player.placeDistance; + }catch(Exception e){return false;} } } @@ -343,12 +346,10 @@ public abstract class InputHandler extends InputAdapter{ } public void placeBlock(int x, int y, Recipe recipe, int rotation){ - //todo multiplayer support player.addBuildRequest(new BuildRequest(x, y, rotation, recipe)); } public void breakBlock(int x, int y){ - //todo multiplayer support Tile tile = world.tile(x, y).target(); player.addBuildRequest(new BuildRequest(tile.x, tile.y)); } diff --git a/core/src/io/anuke/mindustry/input/MobileInput.java b/core/src/io/anuke/mindustry/input/MobileInput.java index ce25fe6951..d1acae94aa 100644 --- a/core/src/io/anuke/mindustry/input/MobileInput.java +++ b/core/src/io/anuke/mindustry/input/MobileInput.java @@ -28,7 +28,6 @@ import io.anuke.mindustry.ui.dialogs.FloatingDialog; import io.anuke.mindustry.world.Block; import io.anuke.mindustry.world.Tile; import io.anuke.ucore.core.*; -import io.anuke.ucore.entities.Entities; import io.anuke.ucore.graphics.Draw; import io.anuke.ucore.graphics.Lines; import io.anuke.ucore.scene.Group; @@ -84,19 +83,17 @@ public class MobileInput extends InputHandler implements GestureListener{ /** Check and assign targets for a specific position. */ void checkTargets(float x, float y){ - synchronized(Entities.entityLock){ - Unit unit = Units.getClosestEnemy(player.getTeam(), x, y, 20f, u -> true); + Unit unit = Units.getClosestEnemy(player.getTeam(), x, y, 20f, u -> true); - if(unit != null){ - threads.run(() -> player.target = unit); - }else{ - Tile tile = world.tileWorld(x, y); - if(tile != null) tile = tile.target(); + if(unit != null){ + threads.run(() -> player.target = unit); + }else{ + Tile tile = world.tileWorld(x, y); + if(tile != null) tile = tile.target(); - if(tile != null && state.teams.areEnemies(player.getTeam(), tile.getTeam())){ - TileEntity entity = tile.entity; - threads.run(() -> player.target = entity); - } + if(tile != null && state.teams.areEnemies(player.getTeam(), tile.getTeam())){ + TileEntity entity = tile.entity; + threads.run(() -> player.target = entity); } } } @@ -550,7 +547,7 @@ public class MobileInput extends InputHandler implements GestureListener{ //ignore off-screen taps if(cursor == null || ui.hasMouse(x, y)) return false; - checkTargets(worldx, worldy); + threads.run(() -> checkTargets(worldx, worldy)); //remove if request present if(hasRequest(cursor)){ diff --git a/core/src/io/anuke/mindustry/maps/generation/pathfinding/AStarPathFinder.java b/core/src/io/anuke/mindustry/maps/generation/pathfinding/AStarPathFinder.java deleted file mode 100644 index 90c13e3063..0000000000 --- a/core/src/io/anuke/mindustry/maps/generation/pathfinding/AStarPathFinder.java +++ /dev/null @@ -1,267 +0,0 @@ -package io.anuke.mindustry.maps.generation.pathfinding; - -import com.badlogic.gdx.math.GridPoint2; -import com.badlogic.gdx.utils.Array; -import com.badlogic.gdx.utils.BinaryHeap; -import io.anuke.mindustry.content.fx.Fx; -import io.anuke.mindustry.world.Tile; -import io.anuke.ucore.core.Effects; -import io.anuke.ucore.function.Consumer; -import io.anuke.ucore.function.Predicate; -import io.anuke.ucore.util.Structs; -import io.anuke.ucore.util.Geometry; - -//TODO -public class AStarPathFinder extends TilePathfinder{ - NodeRecord[] records; - BinaryHeap openList; - NodeRecord current; - Predicate goal; - - private int searchId; - private Tile end; - - private static final byte UNVISITED = 0; - private static final byte OPEN = 1; - private static final byte CLOSED = 2; - - private static final boolean debug = false; - - public AStarPathFinder(Tile[][] tiles) { - super(tiles); - this.records = new NodeRecord[tiles.length * tiles[0].length]; - this.openList = new BinaryHeap<>(); - } - - @Override - public void search(Tile start, Tile end, Array out){ - - } - - public void search(Tile start, Tile end, Predicate pred, Array out){ - this.goal = pred; - searchNodePath(start, end, out); - } - - public boolean searchNodePath(Tile startNode, Tile endNode, Array outPath) { - this.end = endNode; - - // Perform AStar - boolean found = search(startNode, endNode); - - if (found) { - // Create a path made of nodes - generateNodePath(startNode, outPath); - } - - return found; - } - - protected boolean search(Tile startNode, Tile endNode) { - - initSearch(startNode, endNode); - - // Iterate through processing each node - do { - // Retrieve the node with smallest estimated total cost from the open list - current = openList.pop(); - current.category = CLOSED; - - // Terminate if we reached the goal node - if (current.node == endNode || goal.test(current.node)) return true; - - visitChildren(endNode); - - } while (openList.size > 0); - - // We've run out of nodes without finding the goal, so there's no solution - return false; - } -/* - public boolean search(PathFinderRequest request, long timeToRun) { - - long lastTime = TimeUtils.nanoTime(); - - // We have to initialize the search if the status has just changed - if (request.statusChanged) { - initSearch(request.startNode, request.endNode); - request.statusChanged = false; - } - - // Iterate through processing each node - do { - - // Check the available time - long currentTime = TimeUtils.nanoTime(); - timeToRun -= currentTime - lastTime; - if (timeToRun <= PathFinderQueue.TIME_TOLERANCE) return false; - - // Retrieve the node with smallest estimated total cost from the open list - current = openList.pop(); - current.category = CLOSED; - - // Terminate if we reached the goal node; we've found a path. - if (current.node == request.endNode) { - request.pathFound = true; - - generateNodePath(request.startNode, request.resultPath); - - return true; - } - - // Visit current node's children - visitChildren(request.endNode); - - // Store the current time - lastTime = currentTime; - - } while (openList.size > 0); - - // The open list is empty and we've not found a path. - request.pathFound = false; - return true; - }*/ - - protected void initSearch(Tile startNode, Tile endNode) { - - // Increment the search id - if (++searchId < 0) searchId = 1; - - // Initialize the open list - openList.clear(); - - // Initialize the record for the start node and add it to the open list - NodeRecord startRecord = getNodeRecord(startNode); - startRecord.node = startNode; - startRecord.from = null; - startRecord.costSoFar = 0; - addToOpenList(startRecord, estimate(startNode, endNode)); - - current = null; - } - - protected void visitChildren(Tile endNode) { - if(debug) Effects.effect(Fx.spawn, current.node.worldx(), current.node.worldy()); - - nodes(current.node, node -> { - float addCost = estimate(current.node, node); - - float nodeCost = current.costSoFar + addCost; - - float nodeHeuristic; - NodeRecord nodeRecord = getNodeRecord(node); - - if (nodeRecord.category == CLOSED) { // The node is closed - - // If we didn't find a shorter route, skip - if (nodeRecord.costSoFar <= nodeCost){ - return; - } - - // We can use the node's old cost values to calculate its heuristic - // without calling the possibly expensive heuristic function - nodeHeuristic = nodeRecord.getEstimatedTotalCost() - nodeRecord.costSoFar; - } else if (nodeRecord.category == OPEN) { // The node is open - - //If our route is no better, then skip - if (nodeRecord.costSoFar <= nodeCost){ - return; - } - - // Remove it from the open list (it will be re-added with the new cost) - openList.remove(nodeRecord); - - // We can use the node's old cost values to calculate its heuristic - // without calling the possibly expensive heuristic function - nodeHeuristic = nodeRecord.getEstimatedTotalCost() - nodeRecord.costSoFar; - } else { // the node is unvisited - - // We'll need to calculate the heuristic value using the function, - // since we don't have a node record with a previously calculated value - nodeHeuristic = estimate(node, endNode); - } - - // Update node record's cost and connection - nodeRecord.costSoFar = nodeCost; - nodeRecord.from = current.node; - - // Add it to the open list with the estimated total cost - addToOpenList(nodeRecord, nodeCost + nodeHeuristic); - }); - } - - protected void nodes(Tile current, Consumer cons){ - if(obstacle(current)) return; - for(GridPoint2 p : Geometry.d4){ - int wx = current.x + p.x, wy = current.y + p.y; - Tile n = Structs.inBounds(wx, wy, tiles) ? tiles[wx][wy] : null; - if(!obstacle(n)) cons.accept(n); - } - } - - protected boolean obstacle(Tile tile){ - return tile == null || (tile.solid() && end.target() != tile && tile.target() != end) || !tile.block().alwaysReplace; - } - - protected float estimate(Tile tile, Tile other){ - return goal.test(other) || goal.test(tile) ? Float.MIN_VALUE : Math.abs(tile.worldx() - other.worldx()) + Math.abs(tile.worldy() - other.worldy()); - } - - protected void generateNodePath(Tile startNode, Array outPath) { - - // Work back along the path, accumulating nodes - outPath.clear(); - while (current.from != null) { - outPath.add(current.node); - current = records[(indexOf(current.from))]; - } - outPath.add(startNode); - - // Reverse the path - outPath.reverse(); - } - - protected void addToOpenList(NodeRecord nodeRecord, float estimatedTotalCost) { - openList.add(nodeRecord, estimatedTotalCost); - nodeRecord.category = OPEN; - } - - protected NodeRecord getNodeRecord(Tile node) { - if(records[indexOf(node)] == null){ - NodeRecord record = new NodeRecord(); - record.node = node; - record.searchId = searchId; - records[indexOf(node)] = record; - return record; - }else{ - NodeRecord record = records[indexOf(node)]; - if(record.searchId != searchId){ - record.category = UNVISITED; - record.searchId = searchId; - } - return record; - } - } - - private int indexOf(Tile node){ - return node.packedPosition(); - } - - static class NodeRecord extends BinaryHeap.Node { - Tile node; - Tile from; - - float costSoFar; - byte category; - - int searchId; - - public NodeRecord() { - super(0); - } - - public float getEstimatedTotalCost() { - return getValue(); - } - } -} \ No newline at end of file diff --git a/core/src/io/anuke/mindustry/net/Net.java b/core/src/io/anuke/mindustry/net/Net.java index 9755436487..a484d38765 100644 --- a/core/src/io/anuke/mindustry/net/Net.java +++ b/core/src/io/anuke/mindustry/net/Net.java @@ -26,8 +26,6 @@ import static io.anuke.mindustry.Vars.headless; import static io.anuke.mindustry.Vars.ui; public class Net{ - public static final Object packetPoolLock = new Object(); - private static boolean server; private static boolean active; private static boolean clientLoaded; @@ -239,16 +237,12 @@ public class Net{ if(clientLoaded || ((object instanceof Packet) && ((Packet) object).isImportant())){ if(clientListeners.get(object.getClass()) != null) clientListeners.get(object.getClass()).accept(object); - synchronized(packetPoolLock){ - Pooling.free(object); - } + Pooling.free(object); }else if(!((object instanceof Packet) && ((Packet) object).isUnimportant())){ packetQueue.add(object); Log.info("Queuing packet {0}.", object); }else{ - synchronized(packetPoolLock){ - Pooling.free(object); - } + Pooling.free(object); } }else{ Log.err("Unhandled packet type: '{0}'!", object); @@ -263,9 +257,7 @@ public class Net{ if(serverListeners.get(object.getClass()) != null){ if(serverListeners.get(object.getClass()) != null) serverListeners.get(object.getClass()).accept(connection, object); - synchronized(packetPoolLock){ - Pooling.free(object); - } + Pooling.free(object); }else{ Log.err("Unhandled packet type: '{0}'!", object.getClass()); } diff --git a/core/src/io/anuke/mindustry/net/NetworkIO.java b/core/src/io/anuke/mindustry/net/NetworkIO.java index a21aa53b1f..42dc986f16 100644 --- a/core/src/io/anuke/mindustry/net/NetworkIO.java +++ b/core/src/io/anuke/mindustry/net/NetworkIO.java @@ -153,8 +153,6 @@ public class NetworkIO{ Player player = players[0]; - //TODO !! use map name as the network map in Maps, so getMap() isn't null. - try(DataInputStream stream = new DataInputStream(is)){ float timerTime = stream.readFloat(); long timestamp = stream.readLong(); diff --git a/core/src/io/anuke/mindustry/ui/fragments/PlayerListFragment.java b/core/src/io/anuke/mindustry/ui/fragments/PlayerListFragment.java index 56e742cc43..a2e81930e1 100644 --- a/core/src/io/anuke/mindustry/ui/fragments/PlayerListFragment.java +++ b/core/src/io/anuke/mindustry/ui/fragments/PlayerListFragment.java @@ -17,12 +17,14 @@ import io.anuke.ucore.scene.ui.Image; import io.anuke.ucore.scene.ui.layout.Table; import io.anuke.ucore.scene.ui.layout.Unit; import io.anuke.ucore.util.Bundles; +import io.anuke.ucore.util.Timer; import static io.anuke.mindustry.Vars.*; public class PlayerListFragment extends Fragment{ private boolean visible = false; private Table content = new Table().marginRight(13f).marginLeft(13f); + private Timer timer = new Timer(); @Override public void build(Group parent){ @@ -34,7 +36,7 @@ public class PlayerListFragment extends Fragment{ return; } - if(visible && Timers.get("player-list-rebuild", 20)){ + if(visible && timer.get(20)){ rebuild(); } }); @@ -42,8 +44,7 @@ public class PlayerListFragment extends Fragment{ cont.table("pane", pane -> { pane.label(() -> Bundles.format(playerGroup.size() == 1 ? "text.players.single" : "text.players", playerGroup.size())); pane.row(); - pane.pane("clear", content) - .grow().get().setScrollingDisabled(true, false); + pane.pane("clear", content).grow().get().setScrollingDisabled(true, false); pane.row(); pane.table("pane", menu -> { diff --git a/core/src/io/anuke/mindustry/world/Build.java b/core/src/io/anuke/mindustry/world/Build.java index 332b7d3dd3..ed6f078218 100644 --- a/core/src/io/anuke/mindustry/world/Build.java +++ b/core/src/io/anuke/mindustry/world/Build.java @@ -11,7 +11,6 @@ import io.anuke.mindustry.type.ContentType; import io.anuke.mindustry.type.Recipe; import io.anuke.mindustry.world.blocks.BuildBlock.BuildEntity; import io.anuke.ucore.core.Events; -import io.anuke.ucore.entities.Entities; import io.anuke.ucore.util.Geometry; import static io.anuke.mindustry.Vars.*; @@ -113,30 +112,9 @@ public class Build{ return false; } - rect.setSize(type.size * tilesize, type.size * tilesize); - rect.setCenter(type.offset() + x * tilesize, type.offset() + y * tilesize); - - if(type.solid || type.solidifes){ - synchronized(Entities.entityLock){ - try{ - - rect.setSize(tilesize * type.size).setCenter(x * tilesize + type.offset(), y * tilesize + type.offset()); - boolean[] result = {false}; - - Units.getNearby(rect, e -> { - if(e == null) return; //not sure why this happens? - e.getHitbox(hitrect); - - if(rect.overlaps(hitrect) && !e.isFlying()){ - result[0] = true; - } - }); - - if(result[0]) return false; - }catch(Exception e){ - return false; - } - } + if((type.solid || type.solidifes) && + Units.anyEntities(rect.setSize(tilesize * type.size).setCenter(x * tilesize + type.offset(), y * tilesize + type.offset()))){ + return false; } //check for enemy cores diff --git a/core/src/io/anuke/mindustry/world/Edges.java b/core/src/io/anuke/mindustry/world/Edges.java index 8565b5a50d..3ccae39ba1 100644 --- a/core/src/io/anuke/mindustry/world/Edges.java +++ b/core/src/io/anuke/mindustry/world/Edges.java @@ -64,19 +64,15 @@ public class Edges{ return polygons[(int) (radius * 2) - 1]; } - public static synchronized GridPoint2[] getEdges(int size){ + public static GridPoint2[] getEdges(int size){ if(size < 0 || size > maxSize) throw new RuntimeException("Block size must be between 0 and " + maxSize); return edges[size - 1]; } - public static synchronized GridPoint2[] getInsideEdges(int size){ + public static GridPoint2[] getInsideEdges(int size){ if(size < 0 || size > maxSize) throw new RuntimeException("Block size must be between 0 and " + maxSize); return edgeInside[size - 1]; } - - public static synchronized int getEdgeAmount(int size){ - return getEdges(size).length; - } } diff --git a/core/src/io/anuke/mindustry/world/blocks/distribution/Conveyor.java b/core/src/io/anuke/mindustry/world/blocks/distribution/Conveyor.java index 9d2bfcf444..63a2680e43 100644 --- a/core/src/io/anuke/mindustry/world/blocks/distribution/Conveyor.java +++ b/core/src/io/anuke/mindustry/world/blocks/distribution/Conveyor.java @@ -198,7 +198,7 @@ public class Conveyor extends Block{ } @Override - public synchronized void update(Tile tile){ + public void update(Tile tile){ ConveyorEntity entity = tile.entity(); entity.minitem = 1f; @@ -274,7 +274,7 @@ public class Conveyor extends Block{ } @Override - public synchronized int removeStack(Tile tile, Item item, int amount){ + public int removeStack(Tile tile, Item item, int amount){ ConveyorEntity entity = tile.entity(); entity.noSleep(); int removed = 0; @@ -300,13 +300,13 @@ public class Conveyor extends Block{ } @Override - public synchronized int acceptStack(Item item, int amount, Tile tile, Unit source){ + public int acceptStack(Item item, int amount, Tile tile, Unit source){ ConveyorEntity entity = tile.entity(); return Math.min((int)(entity.minitem / itemSpace), amount); } @Override - public synchronized void handleStack(Item item, int amount, Tile tile, Unit source){ + public void handleStack(Item item, int amount, Tile tile, Unit source){ ConveyorEntity entity = tile.entity(); for(int i = amount - 1; i >= 0; i--){ diff --git a/kryonet/src/io/anuke/kryonet/ByteSerializer.java b/kryonet/src/io/anuke/kryonet/ByteSerializer.java index 55d8034913..c8155e458d 100644 --- a/kryonet/src/io/anuke/kryonet/ByteSerializer.java +++ b/kryonet/src/io/anuke/kryonet/ByteSerializer.java @@ -9,8 +9,6 @@ import io.anuke.ucore.util.Pooling; import java.nio.ByteBuffer; -import static io.anuke.mindustry.net.Net.packetPoolLock; - @SuppressWarnings("unchecked") public class ByteSerializer implements Serialization { @@ -36,11 +34,9 @@ public class ByteSerializer implements Serialization { if(id == -2){ return FrameworkSerializer.read(byteBuffer); }else{ - synchronized (packetPoolLock) { - Packet packet = Pooling.obtain((Class) Registrator.getByID(id).type, (Supplier) Registrator.getByID(id).constructor); - packet.read(byteBuffer); - return packet; - } + Packet packet = Pooling.obtain((Class) Registrator.getByID(id).type, (Supplier) Registrator.getByID(id).constructor); + packet.read(byteBuffer); + return packet; } } diff --git a/kryonet/src/io/anuke/kryonet/KryoClient.java b/kryonet/src/io/anuke/kryonet/KryoClient.java index 2fddd60cc6..df089edb46 100644 --- a/kryonet/src/io/anuke/kryonet/KryoClient.java +++ b/kryonet/src/io/anuke/kryonet/KryoClient.java @@ -28,7 +28,6 @@ import java.nio.channels.ClosedSelectorException; import java.util.List; import static io.anuke.mindustry.Vars.*; -import static io.anuke.mindustry.net.Net.packetPoolLock; public class KryoClient implements ClientProvider{ Client client; @@ -146,9 +145,7 @@ public class KryoClient implements ClientProvider{ client.sendUDP(object); } - synchronized (packetPoolLock) { - Pooling.free(object); - } + Pooling.free(object); } @Override From 22328772ca0a939ffd1423c2aea8d944252071bc Mon Sep 17 00:00:00 2001 From: Anuken Date: Thu, 11 Oct 2018 10:01:19 -0400 Subject: [PATCH 02/11] "Fixed" some bugs --- core/src/io/anuke/mindustry/ai/WaveSpawner.java | 2 +- core/src/io/anuke/mindustry/input/InputHandler.java | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/core/src/io/anuke/mindustry/ai/WaveSpawner.java b/core/src/io/anuke/mindustry/ai/WaveSpawner.java index e1a8638030..50d0fe7e1a 100644 --- a/core/src/io/anuke/mindustry/ai/WaveSpawner.java +++ b/core/src/io/anuke/mindustry/ai/WaveSpawner.java @@ -83,7 +83,7 @@ public class WaveSpawner{ int addGround = groundGroups - groundSpawns.size, addFly = flyGroups - flySpawns.size; //add extra groups if the total exceeds it - if(!dynamicSpawn){ + if(dynamicSpawn){ for(int i = 0; i < addGround; i++){ GroundSpawn spawn = new GroundSpawn(); findLocation(spawn); diff --git a/core/src/io/anuke/mindustry/input/InputHandler.java b/core/src/io/anuke/mindustry/input/InputHandler.java index 6d940fd5b7..efac9241b6 100644 --- a/core/src/io/anuke/mindustry/input/InputHandler.java +++ b/core/src/io/anuke/mindustry/input/InputHandler.java @@ -331,6 +331,7 @@ public abstract class InputHandler extends InputAdapter{ for(Tile tile : state.teams.get(player.getTeam()).cores){ if(tile.distanceTo(x * tilesize, y * tilesize) < coreBuildRange){ //TODO terrible hack + //this might actually screw things up on the logic thread. try{ return Build.validPlace(player.getTeam(), x, y, type, rotation) && Vector2.dst(player.x, player.y, x * tilesize, y * tilesize) < Player.placeDistance; From 859a3cbe6e8252a3d645827985ca154d80040575 Mon Sep 17 00:00:00 2001 From: Anuken Date: Fri, 19 Oct 2018 12:58:53 -0400 Subject: [PATCH 03/11] Fixed Java 10-related crash --- core/src/io/anuke/mindustry/graphics/BlockRenderer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/io/anuke/mindustry/graphics/BlockRenderer.java b/core/src/io/anuke/mindustry/graphics/BlockRenderer.java index 7779aa3958..33ac40ce03 100644 --- a/core/src/io/anuke/mindustry/graphics/BlockRenderer.java +++ b/core/src/io/anuke/mindustry/graphics/BlockRenderer.java @@ -25,7 +25,7 @@ public class BlockRenderer{ private FloorRenderer floorRenderer; - private Array requests = new Array<>(initialRequests); + private Array requests = new Array<>(true, initialRequests, BlockRequest.class); private IntSet teamChecks = new IntSet(); private int lastCamX, lastCamY, lastRangeX, lastRangeY; private Layer lastLayer; From 64bd306c6d7e747fb07c8ec35cedef8c7a4a7914 Mon Sep 17 00:00:00 2001 From: Anuken Date: Sat, 20 Oct 2018 09:02:29 -0400 Subject: [PATCH 04/11] Fixed crash --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index e22b8f4529..ded168978b 100644 --- a/build.gradle +++ b/build.gradle @@ -27,7 +27,7 @@ allprojects { appName = 'Mindustry' gdxVersion = '1.9.8' roboVMVersion = '2.3.0' - uCoreVersion = '53f99fbdc50910a15b4f55e9739385f47cf800cf' + uCoreVersion = '4d5571b3efc30975e0c073f87fae9ff5cb2ae4d7' getVersionString = { String buildVersion = getBuildVersion() From c0703a6a5e2c081c0881efedc44ea4cdaba3c996 Mon Sep 17 00:00:00 2001 From: Niko Date: Sat, 20 Oct 2018 15:33:35 +0200 Subject: [PATCH 05/11] Add german translations (#256) * Replace some English Text with german translations in bundle_de * Replace some English Text with german translations in bundle_de, renamed map to karte * Replace some English Text about Units and Fluids with german translations in bundle_de * Replace some English Text with german translations in bundle_de, renamed map to karte * Replace some mech and drone definitions with german translations in bundle_de * Replace almost all definitions with german translations in bundle_de * Merge branch 'master' into add_german_translations # Conflicts: # core/assets/bundles/bundle_de.properties * fix some typos in bundle_de --- core/assets/bundles/bundle_de.properties | 790 +++++++++++------------ 1 file changed, 395 insertions(+), 395 deletions(-) diff --git a/core/assets/bundles/bundle_de.properties b/core/assets/bundles/bundle_de.properties index 643145a6d9..249cadbdfb 100644 --- a/core/assets/bundles/bundle_de.properties +++ b/core/assets/bundles/bundle_de.properties @@ -13,28 +13,28 @@ text.about.button=Info text.name=Name: text.players={0} Spieler online text.players.single={0} Spieler online -text.server.mismatch=Paketfehler: Mögliche Client / Server-Version stimmt nicht überein. Stell sicher, dass du und der Host die neueste Version von Mindustry haben! +text.server.mismatch=Paketfehler: Mögliche Client / Server-Version stimmt nicht überein. Stell sicher, dass du und der Host die neueste Version von Mindustry haben! text.server.kicked.kick=Du wurdest vom Server gekickt! text.hostserver=Server hosten text.host=Host -text.hosting=[accent] Server wird geöffnet... -text.hosts.refresh=Aktualisieren +text.hosting=[accent] Server wird geöffnet... +text.hosts.refresh=Aktualisieren text.hosts.discovering=Suche nach LAN-Spielen text.server.refreshing=Server wird aktualisiert text.hosts.none=[lightgray] Keine LAN Spiele gefunden! text.host.invalid=[scarlet] Kann keine Verbindung zum Host herstellen. text.server.add=Server hinzufügen -text.server.delete=Bist du dir sicher das du diesen Server löschen möchtest? +text.server.delete=Bist du dir sicher das du diesen Server löschen möchtest? text.server.hostname=Host: {0} text.server.edit=Server bearbeiten text.joingame.title=Spiel beitreten text.joingame.ip=IP: text.disconnect=Verbindung unterbrochen. text.connecting=[accent] Verbindet... -text.connecting.data=[accent] Weltdaten werden geladen... +text.connecting.data=[accent] Welt Daten werden geladen... text.connectfail=[crimson] Verbindung zum Server konnte nicht hergestellt werden: [orange]{0} text.server.port=Port: -text.server.invalidport=Falscher Port! +text.server.invalidport=Falscher Port! text.server.error=[crimson] Fehler beim Hosten des Servers: [orange] {0} text.save.new=Neuer Spielstand text.save.overwrite=Möchten du diesen Spielstand wirklich überschreiben? @@ -58,7 +58,7 @@ text.save.corrupted=[orange] Datei beschädigt oder ungültig! text.empty= text.on=An text.off=Aus -text.save.autosave=Automatisches Speichern: {0} +text.save.autosave=Automatisches Speichern: {0} text.save.map=Karte: {0} text.save.wave=Welle: {0} text.save.date=Zuletzt gespeichert: {0} @@ -87,9 +87,9 @@ text.editor.loadimage=Bild\nladen text.editor.saveimage=Bild\nspeichern text.editor.unsaved=[crimson] Du hast Änderungen nicht gespeichert [] Möchtest du wirklich aufhören? text.editor.resizemap=Grösse der Karte ändern -text.editor.mapname=Map Name -text.editor.overwrite=[accent] Warnung! Dies überschreibt eine vorhandene Map. -text.editor.selectmap=Wähle eine Map zum Laden: +text.editor.mapname=Karten Name +text.editor.overwrite=[accent] Warnung! Dies überschreibt eine vorhandene Karte. +text.editor.selectmap=Wähle eine Karte zum Laden: text.width=Breite: text.height=Höhe: text.menu=Menü @@ -98,8 +98,8 @@ text.load=Laden text.save=Speichern text.settings=Einstellungen text.tutorial=Tutorial -text.editor=Bearbeiter -text.mapeditor=Karten Bearbeiter +text.editor=Editor +text.mapeditor=Karten Editor text.donate=Spenden text.settings.reset=Auf Standard zurücksetzen text.settings.controls=Steuerung @@ -108,22 +108,22 @@ text.settings.sound=Audio text.settings.graphics=Grafiken text.paused=Pausiert text.error.title=[crimson] Ein Fehler ist aufgetreten -text.error.crashtitle=EIn Fehler ist aufgetreten! +text.error.crashtitle=Ein Fehler ist aufgetreten! text.blocks.blockinfo=Blockinfo: -text.blocks.powercapacity=Energiekapazität -text.blocks.powershot=Energie / Schuss +text.blocks.powercapacity=Power Kapazität +text.blocks.powershot=Power / Schuss text.blocks.size=Grösse text.blocks.liquidcapacity=Flüssigkeitskapazität -text.blocks.maxitemssecond=Max Gegenstände / Sekunde -text.blocks.powerrange=Energiereichweite +text.blocks.maxitemssecond=Max Gegenstand / Sekunde +text.blocks.powerrange=Power Reichweite text.blocks.itemcapacity=Gegenstand Kapazität -text.blocks.inputliquid=Flüssigkeiten Eingabe -text.blocks.inputitem=Eingabe Gegenstand +text.blocks.inputliquid=Annahme von Flüssigkeit +text.blocks.inputitem=Verwendung von Gegenstand text.blocks.explosive=Hochexplosiv! text.blocks.health=Lebenspunkte text.blocks.inaccuracy=Ungenauigkeit text.blocks.shots=Schüsse -text.blocks.inputcapacity=Eingabekapazität +text.blocks.inputcapacity=Annahmekapazität text.blocks.outputcapacity=Ausgabekapazität setting.difficulty.easy=Leicht setting.difficulty.normal=Normal @@ -139,7 +139,7 @@ setting.saveinterval.name=Autosave Häufigkeit setting.seconds={0} Sekunden setting.fps.name=Zeige FPS setting.vsync.name=VSync -setting.lasers.name=Zeige Energielaser +setting.lasers.name=Zeige Powerlaser setting.healthbars.name=Zeige Objekt Lebensbalken setting.musicvol.name=Musiklautstärke setting.mutemusic.name=Musik stummschalten @@ -175,40 +175,40 @@ block.router.name=Verteiler block.junction.name=Kreuzung block.sorter.name=Sortierer block.smelter.name=Schmelzer -text.credits=Credits -text.link.discord.description=the official Mindustry discord chatroom -text.link.github.description=Game source code -text.link.dev-builds.description=Unstable development builds -text.link.trello.description=Official trello board for planned features -text.link.itch.io.description=itch.io page with PC downloads and web version +text.credits=Danksagungen +text.link.discord.description=Der offizielle Mindustry Discord Chatroom +text.link.github.description=Spiel Source Code +text.link.dev-builds.description=Entwicklungs- Builds (instabil) +text.link.trello.description=Offizielles Trello Board für geplante Features +text.link.itch.io.description=itch.io Seite mit downloads und der Web-Version des Spiels text.link.google-play.description=Google Play store listing -text.link.wiki.description=official Mindustry wiki -text.linkfail=Failed to open link!\nThe URL has been copied to your cliboard. -text.editor.web=The web version does not support the editor!\nDownload the game to use it. -text.web.unsupported=The web version does not support this feature! Download the game to use it. -text.map.delete=Are you sure you want to delete the map "[orange]{0}[]"? -text.construction.title=Block Construction Guide +text.link.wiki.description=offizelles Mindustry wiki +text.linkfail=Fehler beim Öffnen des Links!\nThe URL wurde in die Zwischenablage kopiert. +text.editor.web=Die Web-Version unterstützt den Editor nicht!\nLade das Spiel herunter um ihn zu benutzen. +text.web.unsupported=Die Web-Version unterstützt den editor nicht! Lade das Spiel herunter um ihn zu benutzen. +text.map.delete=Bist du sicher das du die Karte "[orange]{0}[]" löschen möchtest? +text.construction.title=Block Konstruktions-Anleitung text.construction=You've just selected [accent]block construction mode[].\n\nTo begin placing, simply tap a valid location near your ship.\nOnce you have selected some blocks, press the checkbox to confirm, and your ship will begin constructing them.\n\n- [accent]Remove blocks[] from your selection by tapping them.\n- [accent]Shift the selection[] by holding and dragging any block in the selection.\n- [accent]Place blocks in a line[] by tapping and holding an empty spot, then dragging in a direction.\n- [accent]Cancel construction or selection[] by pressing the X at the bottom left. -text.deconstruction.title=Block Deconstruction Guide +text.deconstruction.title=Block Dekonstructions Anleitung text.deconstruction=You've just selected [accent]block deconstruction mode[].\n\nTo begin breaking, simply tap a block near your ship.\nOnce you have selected some blocks, press the checkbox to confirm, and your ship will begin de-constructing them.\n\n- [accent]Remove blocks[] from your selection by tapping them.\n- [accent]Remove blocks in an area[] by tapping and holding an empty spot, then dragging in a direction.\n- [accent]Cancel deconstruction or selection[] by pressing the X at the bottom left. -text.showagain=Don't show again next session -text.unlocks=Unlocks -text.addplayers=Add/Remove Players -text.maps=Maps -text.maps.none=[LIGHT_GRAY]No maps found! -text.unlocked=New Block Unlocked! -text.unlocked.plural=New Blocks Unlocked! -text.server.closing=[accent]Closing server... -text.server.kicked.clientOutdated=Outdated client! Update your game! -text.server.kicked.serverOutdated=Outdated server! Ask the host to update! -text.server.kicked.banned=You are banned on this server. -text.server.kicked.recentKick=You have been kicked recently.\nWait before connecting again. -text.server.kicked.nameInUse=There is someone with that name\nalready on this server. -text.server.kicked.nameEmpty=Your name must contain at least one character or number. -text.server.kicked.idInUse=You are already on this server! Connecting with two accounts is not permitted. -text.server.kicked.customClient=This server does not support custom builds. Download an official version. -text.host.info=The [accent]host[] button hosts a server on ports [scarlet]6567[] and [scarlet]6568.[]\nAnybody on the same [LIGHT_GRAY]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[LIGHT_GRAY]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. -text.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[LIGHT_GRAY]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. +text.showagain=Zeige die nächste Session nicht nochmal +text.unlocks=Freigeschaltet +text.addplayers=Hinzufügen/Entfernen von Spielern +text.maps=Karten +text.maps.none=[LIGHT_GRAY]Keine Karten gefunden! +text.unlocked=Neuen Block freigeschaltet! +text.unlocked.plural=Neue Blöcke freigeschaltet! +text.server.closing=[accent]Schließe den Server... +text.server.kicked.clientOutdated=Veralteter Client! Aktualisiere dein Spiel! +text.server.kicked.serverOutdated=Veralteter Server! Bitte den Host um ein Update! +text.server.kicked.banned=Du wurdest vom Server verbannt. +text.server.kicked.recentKick=Du wurdest gerade gekickt.\nWarte bevor du dich wieder verbindest. +text.server.kicked.nameInUse=Da ist bereits ein Spieler \nmit diesem Namen auf dem Server. +text.server.kicked.nameEmpty=Dein Name muss zumindest ein Buchstaben oder eine Zahl enthalten. +text.server.kicked.idInUse=Du bist bereits auf dem Server! Anmeldungen mit zwei Accounts sind nicht gestattet. +text.server.kicked.customClient=Der Server akzeptiert keine Custom Builds von Mindustry. Lade dir die offizielle Version herunter. +text.host.info=Der [accent]host[] Knopf startet einen Server auf den Ports [scarlet]6567[] und [scarlet]6568.[]\nJeder im gleichen [LIGHT_GRAY]W-Lan oder lokalem Netzwerk[] sollte deinen Server in seiner Server Liste sehen können.\n\nWenn du Leuten die Verbindung über IP ermöglichen willst, benötigst du [accent]Port-Forwarding[].\n\n[LIGHT_GRAY]Hinweis: Falls es Probleme mit der Verbindung im Netzwerk gibt, stell sicher das Mindustry in deinen Firewall Einstellungen Zugriff auf das lokale Netzwerk hat. +text.join.info=Hier kannst du eine [accent]Server IP[] eingeben um dich zu verbinden oder Server im [accent]lokalem Netzwerk[] entdecken und dich mit ihnen verbinden.\nSowohl Spielen über das lokale Netzwerk als auch Spielen über das Internet werden unterstützt.\n\n[LIGHT_GRAY]Hinweis: Es gibt keine globale Server Liste; Wenn du dich mit jemand per IP verbinden willst musst du den Host nach seiner IP fragen. text.trace=Trace Player text.trace.playername=Player name: [accent]{0} text.trace.ip=IP: [accent]{0} @@ -222,378 +222,378 @@ text.trace.totalblocksplaced=Total blocks placed: [accent]{0} text.trace.lastblockplaced=Last block placed: [accent]{0} text.invalidid=Invalid client ID! Submit a bug report. text.server.bans=Bans -text.server.bans.none=No banned players found! +text.server.bans.none=Keine gebannten Spieler gefunden! text.server.admins=Admins -text.server.admins.none=No admins found! -text.server.outdated=[crimson]Outdated Server![] -text.server.outdated.client=[crimson]Outdated Client![] +text.server.admins.none=Keine Admins gefunden! +text.server.outdated=[crimson]Veralteter Server![] +text.server.outdated.client=[crimson]Veralteter Client![] text.server.version=[lightgray]Version: {0} text.server.custombuild=[yellow]Custom Build -text.confirmban=Are you sure you want to ban this player? -text.confirmunban=Are you sure you want to unban this player? -text.confirmadmin=Are you sure you want to make this player an admin? -text.confirmunadmin=Are you sure you want to remove admin status from this player? -text.disconnect.data=Failed to load world data! -text.server.addressinuse=Address already in use! -text.save.difficulty=Difficulty: {0} -text.copylink=Copy Link +text.confirmban=Bist du sicher das du diesen Spieler verbannen möchtest? +text.confirmunban=Bist du sicher, dass du die Verbannung des Spielers rückgängig machen willst? +text.confirmadmin=Bist du sicher, dass du diesen Spieler zu einem Admin machen möchtest? +text.confirmunadmin=Bis du sicher, dass dieser Spieler kein Admin mehr sein soll? +text.disconnect.data=Fehler beim Laden der Welt Daten! +text.server.addressinuse=Adresse bereits in Benutzung! +text.save.difficulty=Schwierigkeitsgrad: {0} +text.copylink=Kopiere Link text.changelog.title=Changelog -text.changelog.loading=Getting changelog... -text.changelog.error.android=[orange]Note that the changelog sometimes does not work on Android 4.4 and below!\nThis is due to an internal Android bug. -text.changelog.error.ios=[orange]The changelog is currently not supported in iOS. -text.changelog.error=[scarlet]Error getting changelog!\nCheck your internet connection. +text.changelog.loading=Lade Changelog... +text.changelog.error.android=[orange]Beachte: Das Changelog funktioniert manchmal nicht auf Android 4.4 (und älter)!\nDies resultiert aus einem Android bug. +text.changelog.error.ios=[orange]Das Changelog wird aktuell nicht von IOS unterstützt. +text.changelog.error=[scarlet]Fehler beim Laden des Changelog!\nPrüfe deine Internet Verbindung. text.changelog.current=[yellow][[Current version] text.changelog.latest=[orange][[Latest version] -text.saving=[accent]Saving... -text.unknown=Unknown +text.saving=[accent]Speichere... +text.unknown=Unbekannt text.custom=Custom text.builtin=Built-In -text.map.delete.confirm=Are you sure you want to delete this map? This action cannot be undone! -text.map.random=[accent]Random Map -text.map.nospawn=This map does not have any cores for the player to spawn in! Add a [ROYAL]blue[] core to this map in the editor. +text.map.delete.confirm=Bist du sicher das du diese Karte löschen willst? Die Aktion kann nicht rückgänig gemacht werden! +text.map.random=[accent]Zufällige Karte +text.map.nospawn=Diese Karte hat keine Kerne in denen die Spieler beginnen können! Füge einen [ROYAL]blue[] Kern zu dieser Karte im Editor hinzu. text.editor.slope=\\ -text.editor.openin=Open In Editor -text.editor.oregen=Ore Generation -text.editor.oregen.info=Ore Generation: -text.editor.mapinfo=Map Info +text.editor.openin=Öffne im Editor +text.editor.oregen=Erze generieren +text.editor.oregen.info=Erze generiert: +text.editor.mapinfo=Karten Info text.editor.author=Author: -text.editor.description=Description: +text.editor.description=Beschreibung: text.editor.name=Name: text.editor.teams=Teams -text.editor.elevation=Elevation -text.editor.saved=Saved! -text.editor.save.noname=Your map does not have a name! Set one in the 'map info' menu. -text.editor.save.overwrite=Your map overwrites a built-in map! Pick a different name in the 'map info' menu. -text.editor.import.exists=[scarlet]Unable to import:[] a built-in map named '{0}' already exists! +text.editor.elevation=Höhe +text.editor.saved=Gespeichert! +text.editor.save.noname=Deine Karte hat keinen Namen! Setze einen Namen im [accent]Karten Info[] Menu. +text.editor.save.overwrite=Deine Karte überschreibt eine built-in Karte! Wähle einen anderen Karten Namen im [accent]'Karten info'[] Menu. +text.editor.import.exists=[scarlet]Fehler beim Import:[] Ein built-in Karte namens '{0}' existiert bereits! text.editor.import=Import... -text.editor.importmap=Import Map -text.editor.importmap.description=Import an already existing map -text.editor.importfile=Import File -text.editor.importfile.description=Import an external map file -text.editor.importimage=Import Terrain Image -text.editor.importimage.description=Import an external map image file +text.editor.importmap=Importiere Karte +text.editor.importmap.description=Importiere von einer bestehende Karte +text.editor.importfile=Importiere Datei +text.editor.importfile.description=Importiere aus einer Karten Datei +text.editor.importimage=Importiere Terrain Bild +text.editor.importimage.description=Importiere aus einer Terrain Bild Datei text.editor.export=Export... -text.editor.exportfile=Export File -text.editor.exportfile.description=Export a map file -text.editor.exportimage=Export Terrain Image -text.editor.exportimage.description=Export a map image file -text.editor.overwrite.confirm=[scarlet]Warning![] A map with this name already exists. Are you sure you want to overwrite it? +text.editor.exportfile=Export in Datei +text.editor.exportfile.description=Exportiere in eine Karten Datei +text.editor.exportimage=Export in Terrain Bild Datei +text.editor.exportimage.description=Exportiere in eine Karten Bild Datei +text.editor.overwrite.confirm=[scarlet]Warnung![] Eine Karte mit diesem Namen existiert bereits. Bist du sicher das du sie überschreiben willst? text.fps=FPS: {0} text.tps=TPS: {0} text.ping=Ping: {0}ms -text.language.restart=Please restart your game for the language settings to take effect. -text.settings.language=Language -text.settings.rebind=Rebind -text.yes=Yes -text.no=No +text.language.restart=Bitte Starte dein Spiel neu, damit die Sprach-Einstellung aktiv werden. +text.settings.language=Sprache +text.settings.rebind=Zuweisen +text.yes=Ja +text.no=Nein text.info.title=[accent]Info -text.blocks.targetsair=Targets Air +text.blocks.targetsair=Visiert Luft Einheiten an text.blocks.itemspeed=Units Moved -text.blocks.shootrange=Range -text.blocks.poweruse=Power Use -text.blocks.inputitemcapacity=Input Item Capacity -text.blocks.outputitemcapacity=Input Item Capacity +text.blocks.shootrange=Reichweite +text.blocks.poweruse=Powerbedarf +text.blocks.inputitemcapacity= Annahme Kapazität +text.blocks.outputitemcapacity=Ausgabe Kapazität text.blocks.powertransferspeed=Power Transfer -text.blocks.craftspeed=Production Speed -text.blocks.inputliquidaux=Aux Liquid -text.blocks.inputitems=Input Items -text.blocks.outputitem=Output Item -text.blocks.drilltier=Drillables -text.blocks.drillspeed=Base Drill Speed -text.blocks.liquidoutput=Liquid Output -text.blocks.liquiduse=Liquid Use -text.blocks.coolant=Coolant -text.blocks.coolantuse=Coolant Use -text.blocks.inputliquidfuel=Fuel Liquid -text.blocks.liquidfueluse=Liquid Fuel Use -text.blocks.reload=Reload -text.blocks.inputfuel=Fuel -text.blocks.fuelburntime=Fuel Burn Time +text.blocks.craftspeed=Produktions-Geschwindigkeit +text.blocks.inputliquidaux=Aux Flüssigkeit +text.blocks.inputitems=Annahme von Gegenständen +text.blocks.outputitem=Ausgabe von Gegenständen +text.blocks.drilltier=Abbaubar +text.blocks.drillspeed=Grund Abbau Geschwindigkeit +text.blocks.liquidoutput=Flüssigkeits-Ausgabe +text.blocks.liquiduse=Flüssigkeits-Verwendung +text.blocks.coolant=Kühlmittel +text.blocks.coolantuse=Kühlmittel Verwendung +text.blocks.inputliquidfuel=Flüssigkraftstoff +text.blocks.liquidfueluse=Flüssigkraftstoff Benutzung +text.blocks.reload=Nachladen +text.blocks.inputfuel=Kraftstoff +text.blocks.fuelburntime=Kraftstoff Verbrennungs-Zeit text.unit.blocks=blocks -text.unit.powersecond=power units/second -text.unit.liquidsecond=liquid units/second -text.unit.itemssecond=items/second -text.unit.pixelssecond=pixels/second -text.unit.liquidunits=liquid units -text.unit.powerunits=power units -text.unit.degrees=degrees -text.unit.seconds=seconds +text.unit.powersecond=Power Einheit/Sekunde +text.unit.liquidsecond=flüssige Einheit/Sekunde +text.unit.itemssecond=Gegenstand/Sekunde +text.unit.pixelssecond=Pixel/Sekunde +text.unit.liquidunits=flüssige Einheiten +text.unit.powerunits=Power Einheiten +text.unit.degrees=grad +text.unit.seconds=Sekunden text.unit.none= -text.unit.items=items +text.unit.items=Gegenstände text.category.general=General text.category.power=Power -text.category.liquids=Liquids -text.category.items=Items -text.category.crafting=Crafting -text.category.shooting=Shooting -setting.fullscreen.name=Fullscreen +text.category.liquids=Flüssigkeiten +text.category.items=Gegenstände +text.category.crafting=Herstellung +text.category.shooting=Schießen +setting.fullscreen.name=Vollbild setting.multithread.name=Multithreading -setting.minimap.name=Show Minimap -text.keybind.title=Rebind Keys -keybind.chat.name=chat +setting.minimap.name=Zeige die Minimap +text.keybind.title=Tasten Zuweisen +keybind.chat.name=Chat keybind.player_list.name=player_list keybind.console.name=console -mode.text.help.title=Description of modes -mode.waves.description=the normal mode. limited resources and automatic incoming waves. -mode.sandbox.description=infinite resources and no timer for waves. -mode.freebuild.description=limited resources and no timer for waves. -content.item.name=Items -content.liquid.name=Liquids -content.recipe.name=Blocks -item.stone.description=A common raw material. Used for separating and refining into other materials, or melting into lava. -item.lead.name=Lead -item.lead.description=A basic starter material. Used extensively in electronics and liquid transportation blocks. -item.coal.description=A common and readily available fuel. -item.titanium.description=A rare super-light metal used extensively in liquid transportation, drills and aircraft. -item.thorium.description=A dense, radioactive metal used as structural support and nuclear fuel. -item.silicon.name=Silicon -item.silcion.description=An extremely useful semiconductor, with applications in solar panels and many complex electronics. +mode.text.help.title=Beschreibung der Modi +mode.waves.description=Der Normale Modus. Begrenzte Ressourcen und automatische Wellen. +mode.sandbox.description=unendliche Ressourcen und kein Timer für Wellen. +mode.freebuild.description=begrenzte Ressourcen und kein Timer für Wellen. +content.item.name=Gegenstand +content.liquid.name=Flüssigkeit +content.recipe.name=Blöcke +item.stone.description=Ein gängiger Rohstoff der für die Zerteilung und Verfeinerung in andere Gegenstände oder geschmolzen als Lava verwendet wird. +item.lead.name=Blei +item.lead.description=Ein grundliegendes Material. Häufig in Elektronik und Flüssigkeits-Transport Blöcken verwendet. +item.coal.description=Ein sehr häufiger vorkommender Kraftstoff. +item.titanium.description=Ein seltenes sehr leichtes Metal. Häufig in Flüssigkeits-Transport Blöcken, Abbauanlagen und Flugzeugen verwendet. +item.thorium.description=Ein dichtes radioaktives Metal, welches als strukturelle Unterstützung und nuklearer Kraftstoff verwendet wird. +item.silicon.name=Silikon +item.silcion.description=Ein sehr nützlicher Halbleiter. Findet Anwendung in Solar Anlagen und komplexer Elektronik. item.plastanium.name=Plastanium -item.plastanium.description=A light, ductile material used in advanced aircraft and fragmentation ammunition. -item.phase-matter.name=Phase Matter -item.surge-alloy.name=Surge Alloy -item.biomatter.name=Biomatter -item.biomatter.description=A clump of organic mush; used for conversion into oil or as a basic fuel. -item.sand.description=A common material that is used extensively in smelting, both in alloying and as a flux. -item.blast-compound.name=Blast Compound -item.blast-compound.description=A volatile compound used in bombs and explosives. While it can burned as fuel, this is not advised. +item.plastanium.description=Ein leichtes dehnbares Material welches in Flugzeugen und Splittermunition verwendet wird. +item.phase-matter.name=Phase Materie +item.surge-alloy.name=Gewalzte Legierung +item.biomatter.name=Biomasse +item.biomatter.description=Ein Klumpen organischer Brei. Wird für die Umwandlung in Öl oder als grundliegender Kraftstoff verwendet. +item.sand.description=Ein gäniges Material welches häufig in geschmolzener Form, flüssig oder als Legierung verwendet wird. +item.blast-compound.name=Explosive Mischung +item.blast-compound.description=Eine flüchtige Mischung die in Bomben und Sprengstoffen Verwendung findet. Es besteht die Möglichkeit es als Treibstoff zu verwenden, es wird dringend davon abgeraten. item.pyratite.name=Pyratite -item.pyratite.description=An extremely flammable substance used in incendiary weapons. +item.pyratite.description=Eine extrem leicht entflammen Substanz. Verwendet in Brand Waffen. liquid.cryofluid.name=Cryofluid -text.item.explosiveness=[LIGHT_GRAY]Explosiveness: {0} -text.item.flammability=[LIGHT_GRAY]Flammability: {0} -text.item.radioactivity=[LIGHT_GRAY]Radioactivity: {0} -text.item.fluxiness=[LIGHT_GRAY]Flux Power: {0} -text.liquid.heatcapacity=[LIGHT_GRAY]Heat Capacity: {0} -text.liquid.viscosity=[LIGHT_GRAY]Viscosity: {0} -text.liquid.temperature=[LIGHT_GRAY]Temperature: {0} -block.thorium-wall.name=Thorium Wall -block.thorium-wall-large.name=Large Thorium Wall +text.item.explosiveness=[LIGHT_GRAY]Explosivität: {0} +text.item.flammability=[LIGHT_GRAY]Entflammbarkeit: {0} +text.item.radioactivity=[LIGHT_GRAY]Radioaktivität: {0} +text.item.fluxiness=[LIGHT_GRAY]Fluss Power: {0} +text.liquid.heatcapacity=[LIGHT_GRAY]Hitze Kapazität: {0} +text.liquid.viscosity=[LIGHT_GRAY]Viskosität: {0} +text.liquid.temperature=[LIGHT_GRAY]Temperatur: {0} +block.thorium-wall.name=Thorium Mauer +block.thorium-wall-large.name=Große Thorium Mauer block.duo.name=Duo block.scorch.name=Scorch block.hail.name=Hail block.lancer.name=Lancer -block.titanium-conveyor.name=Titanium Conveyor -block.router.description=Splits items into all 4 directions. Can store items as a buffer. -block.distributor.name=Distributor -block.distributor.description=A splitter that can split items into 8 directions. -block.sorter.description=Sorts items. If an item matches the selection, it is allowed to pass. Otherwise, the item is outputted to the left and right. +block.titanium-conveyor.name=Titanium Transportband +block.router.description=Teilt Gegenstände in alle 4 Richtungen. Kann ebenfalls Gegenstände puffern. +block.distributor.name=Verteiler +block.distributor.description=Ein Teiler der Gegenstände in 8 Richtungen teilen kann. +block.sorter.description=Sortiert Gegenstände. Wenn ein Gegenstand der Auswahl entspricht darf er vorbei. Andernfalls wird er links oder rechts ausgegeben. block.overflow-gate.name=Overflow Gate -block.overflow-gate.description=A combination splitter and router that only outputs to the left and right if the front path is blocked. -block.bridgeconveyor.name=Bridge Conveyor -block.bridgeconveyor.description=A conveyor that can go over other blocks, for up to two total blocks. -block.arc-smelter.name=Arc Smelter -block.silicon-smelter.name=Silicon Smelter +block.overflow-gate.description=Eine Kombination aus Splitter und router der nur Gegenstände nach links oder rechts ausgibt falls der Weg gerade aus blockiert ist. +block.bridgeconveyor.name=Transportband Brücke +block.bridgeconveyor.description=Ein Transportband welches über Blöcke gehen kann. Insgesamt maximal zwei Blöcke hoch. +block.arc-smelter.name=Lichtbogen Schmelzer +block.silicon-smelter.name=Silikon Schmelzer block.phase-weaver.name=Phase Weaver -block.pulverizer.name=Pulverizer +block.pulverizer.name=Pulverisierer block.cryofluidmixer.name=Cryofluid Mixer -block.melter.name=Melter -block.incinerator.name=Incinerator -block.biomattercompressor.name=Biomatter Compressor -block.separator.name=Separator -block.centrifuge.name=Centrifuge -block.power-node.name=Power Node -block.power-node-large.name=Large Power Node -block.battery.name=Battery -block.battery-large.name=Large Battery -block.combustion-generator.name=Combustion Generator -block.turbine-generator.name=Turbine Generator -block.laser-drill.name=Laser Drill -block.water-extractor.name=Water Extractor -block.cultivator.name=Cultivator -block.mechanical-pump.name=Mechanical Pump -block.itemsource.name=Item Source -block.itemvoid.name=Item Void -block.liquidsource.name=Liquid Source +block.melter.name=Schmelzer +block.incinerator.name=Verbrennungsanlage +block.biomattercompressor.name=Biomassen Verdichter +block.separator.name=Seperierer +block.centrifuge.name=Zentrifuge +block.power-node.name=Power Knoten +block.power-node-large.name=Grosser Power Knoten +block.battery.name=Batterie +block.battery-large.name=Grosse Batterie +block.combustion-generator.name=Verbrennungs-Generator +block.turbine-generator.name=Turbinen Generator +block.laser-drill.name=Laser Bohrer +block.water-extractor.name=Wasser Extraktor +block.cultivator.name=Kultivierer +block.mechanical-pump.name=Mechanische Pumpe +block.itemsource.name=Gegenstands Quelle +block.itemvoid.name=Gegenstand Void +block.liquidsource.name=Flüssigkeits-Quelle block.powervoid.name=Power Void -block.powerinfinite.name=Power Infinite -block.unloader.name=Unloader -block.sortedunloader.name=Sorted Unloader -block.vault.name=Vault -block.wave.name=Wave +block.powerinfinite.name=Power Unendlich +block.unloader.name=Entlader +block.sortedunloader.name=Sortierender Entlader +block.vault.name=Tresor +block.wave.name=Welle block.swarmer.name=Swarmer block.salvo.name=Salvo block.ripple.name=Ripple -block.phase-conveyor.name=Phase Conveyor -block.bridge-conveyor.name=Bridge Conveyor -block.plastanium-compressor.name=Plastanium Compressor +block.phase-conveyor.name=Phase Transportband +block.bridge-conveyor.name=Brücken Transportband +block.plastanium-compressor.name=Plastanium Verdichter block.pyratite-mixer.name=Pyratite Mixer block.blast-mixer.name=Blast Mixer block.solidifer.name=Solidifer block.solar-panel.name=Solar Panel -block.solar-panel-large.name=Large Solar Panel -block.oil-extractor.name=Oil Extractor -block.repair-point.name=Repair Point -block.pulse-conduit.name=Pulse Conduit -block.phase-conduit.name=Phase Conduit +block.solar-panel-large.name=Grosses Solar Panel +block.oil-extractor.name=Oil Extraktor +block.repair-point.name=Reparatur Punkt +block.pulse-conduit.name=Pulse Rohr +block.phase-conduit.name=Phase Rohr block.liquid-router.name=Liquid Router block.liquid-tank.name=Liquid Tank -block.liquid-junction.name=Liquid Junction -block.bridge-conduit.name=Bridge Conduit -block.rotary-pump.name=Rotary Pump +block.liquid-junction.name=Liquid Kreuzung +block.bridge-conduit.name=Brücken Rohr +block.rotary-pump.name=Rotierende Pumpe text.save.old=This save is for an older version of the game, and can no longer be used.\n\n[LIGHT_GRAY]Save backwards compatibility will be implemented in the full 4.0 release. text.customgame=Custom Game -text.sectors=Sectors -text.sector=Selected Sector: [LIGHT_GRAY]{0} -text.sector.time=Time: [LIGHT_GRAY]{0} -text.sector.deploy=Deploy -text.sector.resume=Resume -text.sector.locked=[scarlet][[Incomplete] -text.sector.unexplored=[accent][[Unexplored] -text.close=Close -text.save.playtime=Playtime: {0} -text.editor.brush=Brush +text.sectors=Sektoren +text.sector=Ausgewählter Sektor: [LIGHT_GRAY]{0} +text.sector.time=Zeit: [LIGHT_GRAY]{0} +text.sector.deploy=Einsatz +text.sector.resume=Fortsetzen +text.sector.locked=[scarlet][[Unvollständig] +text.sector.unexplored=[accent][[Unerforscht] +text.close=Schließen +text.save.playtime=Spielzeit: {0} +text.editor.brush=Pinsel text.credits.text=Created by [ROYAL]Anuken[] - [SKY]anukendev@gmail.com[]\n\n[GRAY](In case you can't tell, this text is currently unfinished.\nTranslators, don't edit it yet!) -text.sector.gameover=This sector has been lost. Re-deploy? -text.sector.retry=Retry -text.wave.lasted=You lasted until wave [accent]{0}[]. +text.sector.gameover=Du hast diesen Sektor verloren. Erneuter Einsatz? +text.sector.retry=Erneut Versuchen +text.wave.lasted=Du hast es bis Welle[accent]{0}[] ausgehalten. setting.fpscap.name=Max FPS -setting.fpscap.none=None +setting.fpscap.none=kein setting.fpscap.text={0} FPS -block.command-center.name=Command Center +block.command-center.name=Kommando Zentrum text.mission=Mission:[LIGHT_GRAY] {0} -text.mission.wave=Survive [accent]{0}[] waves. -text.mission.battle=Destroy the enemy base. -text.none= -text.sector.corrupted=[orange]A save file for this sector was found, but loading failed.\nA new one has been created. -text.mission.complete=Mission complete! -text.mission.complete.body=Sector {0},{1} has been conquered. -text.mission.resource=Obtain {0}:\n[accent]{1}/{2}[] -text.unit.health=[LIGHT_GRAY]Health: {0} -text.unit.speed=[LIGHT_GRAY]Speed: {0} +text.mission.wave=Überlebe [accent]{0}[] Wellen. +text.mission.battle=Zerstöre die gegnerische Basis. +text.none= +text.sector.corrupted=[orange]Ein Spielstand für diesen Sektor wurde nicht gefunden.\nEin neuer Spielstand wurde erstellt. +text.mission.complete=Mission erfolgreich! +text.mission.complete.body=Sektor {0},{1} wurde erobert. +text.mission.resource=Sammele {0}:\n[accent]{1}/{2}[] +text.unit.health=[LIGHT_GRAY]Gesundheit: {0} +text.unit.speed=[LIGHT_GRAY]Geschwindigkeit: {0} block.mass-driver.name=Mass Driver -block.blast-drill.name=Blast Drill -unit.drone.description=The starter drone unit. Spawns in the core by default. Automatically mines ores, collects items and repairs blocks. -unit.fabricator.description=An advanced drone unit. Automatically mines ores, collects items and repairs blocks. Significantly more effective than a drone. +block.blast-drill.name=Spreng Bohrer +unit.drone.description=Die anfängliche Drohne. Sie wird gewöhnlich im Kern erzeugt. Baut automatisch Erz ab, sammelt Gegenstände und repariert Blöcke. +unit.fabricator.description=Eine forgeschrittene Drohne. Baut automatisch Erz ab, sammelt Gegenstände und repariert Blöcke. Signifikant effizienter als die Drohne. unit.titan.name=Titan -unit.titan.description=An advanced armored ground unit. Uses carbide as ammo. Attacks both ground and air targets. -unit.monsoon.description=A heavy carpet bomber. Uses blast compound or pyratite as ammo. -unit.interceptor.description=A fast, hit-and-run strike unit. Uses lead as ammo. -block.thermal-pump.name=Thermal Pump -block.thermal-generator.name=Thermal Generator -text.coreattack=< Core is under attack! > -text.continue=Continue -text.nextmission=Next Mission -text.server.kicked.serverClose=Server closed. -text.server.kicked.sectorComplete=Sector completed. -text.server.kicked.sectorComplete.text=Your mission is complete.\nThe server will now continue at the next sector. -text.map.invalid=Error loading map: corrupted or invalid map file. -block.deepwater.name=deepwater -block.water.name=water -block.lava.name=lava -block.oil.name=oil -block.blackstone.name=blackstone -block.stone.name=stone -block.dirt.name=dirt -block.sand.name=sand -block.ice.name=ice -block.snow.name=snow -block.grass.name=grass -block.shrub.name=shrub -block.rock.name=rock -block.blackrock.name=blackrock -block.icerock.name=icerock +unit.titan.description=Eine fortgeschrittene gepanzerte Bodeneinheit. Benutzt Carbide als Munition. Kann sowohl Boden als auch Luft Einheiten angreifen. +unit.monsoon.description=Ein schwerer Flächen Bomber. Benutzt Explosives Gemisch und Pyratite als munition. +unit.interceptor.description=Eine schnelle hit-and-run Angriffs Einheit. Benutzt Blei als Munition. +block.thermal-pump.name=Thermische Pumpe +block.thermal-generator.name=Thermischer Generator +text.coreattack=< Der Kern wird angegriffen! > +text.continue=Weiter +text.nextmission=Nächste Mission +text.server.kicked.serverClose=Server geschlossen. +text.server.kicked.sectorComplete=Sektor komplett. +text.server.kicked.sectorComplete.text=Deine Mission ist abgeschlossen.\nDer Server wird nun in einen neuen Sektor wechseln. +text.map.invalid=Fehler beim Laden der Karte: Beschädigtes oder invalide Karten Datei. +block.deepwater.name=Tiefes Wasser +block.water.name=Wasser +block.lava.name=Lava +block.oil.name=Öl +block.blackstone.name=Schwarzer Stein +block.stone.name=Stein +block.dirt.name=Dreck +block.sand.name=Sand +block.ice.name=Eis +block.snow.name=Schnee +block.grass.name=Grass +block.shrub.name=Busch +block.rock.name=Fels +block.blackrock.name=Schwarzer Fels +block.icerock.name=Eis Fels unit.dagger.name=Dagger -unit.dagger.description=A basic ground unit. Useful in swarms. -category.general.name=General +unit.dagger.description=Eine Standard Bodeneinheit. Nützlich in Schwärmen. +category.general.name=Allgemein category.view.name=View -category.multiplayer.name=Multiplayer -keybind.toggle_menus.name=Toggle menus -keybind.chat_history_prev.name=Chat history prev -keybind.chat_history_next.name=Chat history next +category.multiplayer.name=Mehrspieler +keybind.toggle_menus.name=Wechsele Menüs +keybind.chat_history_prev.name=Chat Historie zurück +keybind.chat_history_next.name=Chat Historie vor keybind.chat_scroll.name=Chat scroll keybind.drop_unit.name=drop unit keybind.zoom_minimap.name=Zoom minimap content.mech.name=Mechs -item.copper.name=Copper -item.copper.description=A useful structure material. Used extensively in all types of blocks. -item.dense-alloy.name=Dense Alloy -item.dense-alloy.description=A tough alloy made with lead and copper. Used in advanced transportation blocks and high-tier drills. +item.copper.name=Kupfer +item.copper.description=Ein nützliches Material. Wird in allen Arten von Blöcken verwendet. +item.dense-alloy.name=Dichte Legierung +item.dense-alloy.description=Eine Robuste Legierung aus Blei und Kupfer. Findet Verwendung in fortgeschrittenen Transport Blöcken und höherwertigen Bohrern. mech.alpha-mech.name=Alpha mech.alpha-mech.weapon=Heavy Repeater mech.alpha-mech.ability=Drone Swarm -mech.alpha-mech.description=The standard mech. Has decent speed and damage output; can create up to 3 drones for increased offensive capability. +mech.alpha-mech.description=Der Standart Mech. Ist angemessen Schnell und hat ordentlich Schaden. Kann für erweiterte Offensive Fähigkeiten bis zu 3 Drohnen erzeugen. mech.delta-mech.name=Delta -mech.delta-mech.weapon=Arc Generator -mech.delta-mech.ability=Discharge -mech.delta-mech.description=A fast, lightly-armored mech made for hit-and-run attacks. Does little damage against structures, but can kill large groups of enemy units very quickly with its arc lightning weapons. +mech.delta-mech.weapon=Lichtbogen Generator +mech.delta-mech.ability=Entladen +mech.delta-mech.description= Ein schneller, leicht gepanzerter Mech, der für hit-and-run Attacken gemacht wurde. Verursacht wenig Schaden gegen Gebäude aber tötet Gruppen von Gegnern durch seine Lichtbogen Blitz Waffen. mech.tau-mech.name=Tau -mech.tau-mech.weapon=Restruct Laser -mech.tau-mech.ability=Repair Burst -mech.tau-mech.description=The support mech. Heals allied blocks by shooting at them. Can extinguish fires and heal allies in a radius with its repair ability. +mech.tau-mech.weapon=Restrukt Laser +mech.tau-mech.ability=Reparier Burst +mech.tau-mech.description=Der Support Mech. Kann Blöcke durch Schüsse heilen. Kann Feuer löschen und verbündete in seinem Aktions Radius heilen. mech.omega-mech.name=Omega -mech.omega-mech.weapon=Swarm Missiles -mech.omega-mech.ability=Armored Configuration -mech.omega-mech.description=A bulky and well-armored mech, made for front-line assaults. Its armor ability can block up to 90% of incoming damage. +mech.omega-mech.weapon=Schwarm Raketen +mech.omega-mech.ability=Rüstungs Konfiguration +mech.omega-mech.description=Ein klobiger und gut gepanzerter Mech, der für den Angriff in der Front Line gemacht wurde. Seine Rüstungsfähigkeit ermöglicht es ihm 90% des Schadens abzuwehren. mech.dart-ship.name=Dart mech.dart-ship.weapon=Repeater -mech.dart-ship.description=The standard ship. Reasonably fast and light, but has little offensive capability and low mining speed. +mech.dart-ship.description=Das standard Schiff. Einigermaßen schnell und leicht. Hat nur wenig offensiv Kraft und geringe Abbaugeschwindigkeit. mech.javelin-ship.name=Javelin -mech.javelin-ship.description=A hit-and-run strike ship. While initially slow, it can accelerate to great speeds and fly by enemy outposts, dealing large amounts of damage with its lightning ability and missiles. +mech.javelin-ship.description=Ein hit-and-run Schiff. Anfänglich träge kann es auf hohe Geschwindigkeiten beschleunigen um an gegnerischen Aussenposten vorbei zu fliegen und dabei mit seinen Blitz Waffen und Raketen große Mengen an Schaden verursachen. mech.javelin-ship.weapon=Burst Missiles mech.javelin-ship.ability=Discharge Booster mech.trident-ship.name=Trident -mech.trident-ship.description=A heavy bomber. Reasonably well armored. +mech.trident-ship.description=Ein schwerer Bomber, solide gepanzert. mech.trident-ship.weapon=Bomb Bay mech.glaive-ship.name=Glaive -mech.glaive-ship.description=A large, well-armored gunship. Equipped with an incendiary repeater. Good acceleration and maximum speed. +mech.glaive-ship.description=Ein großes gut gepanzertes Gunship. Ausgerüstet mit einer Brand Waffe. Gute Beschleunigung und maximal Geschwindigkeit. mech.glaive-ship.weapon=Flame Repeater -text.mech.weapon=[LIGHT_GRAY]Weapon: {0} -text.mech.armor=[LIGHT_GRAY]Armor: {0} -text.mech.itemcapacity=[LIGHT_GRAY]Item Capacity: {0} -text.mech.minespeed=[LIGHT_GRAY]Mining Speed: {0} +text.mech.weapon=[LIGHT_GRAY]Waffe: {0} +text.mech.armor=[LIGHT_GRAY]Rüstung: {0} +text.mech.itemcapacity=[LIGHT_GRAY]Gegenstands Kapazität: {0} +text.mech.minespeed=[LIGHT_GRAY]Mining Geschwindigkeit: {0} text.mech.minepower=[LIGHT_GRAY]Mining Power: {0} -text.mech.ability=[LIGHT_GRAY]Ability: {0} -block.core.name=Core -block.metalfloor.name=Metal Floor -block.copper-wall.name=Copper Wall -block.copper-wall-large.name=Large Copper Wall -block.phase-wall.name=Phase Wall -block.phase-wall-large.name=Large Phase Wall -block.mechanical-drill.name=Mechanical Drill -block.pneumatic-drill.name=Pneumatic Drill -block.thorium-reactor.name=Thorium Reactor -block.alloy-smelter.name=Alloy Smtler +text.mech.ability=[LIGHT_GRAY]Fähigkeit: {0} +block.core.name=Kern +block.metalfloor.name=Metal Boden +block.copper-wall.name=Kupfer Mauer +block.copper-wall-large.name=Grosse Kupfer Mauer +block.phase-wall.name=Phase Mauer +block.phase-wall-large.name=Grosse Phase Mauer +block.mechanical-drill.name=Mechanischer Bohrer +block.pneumatic-drill.name=Pneumatischer Bohrer +block.thorium-reactor.name=Thorium Reaktor +block.alloy-smelter.name=Legierungs Schmeltzer block.mend-projector.name=Mend Projector unit.alpha-drone.name=Alpha Drone -text.construction.desktop=Desktop controls have been changed.\nTo deselect a block or stop building, [accent]use space[]. -keybind.press=Press a key... -keybind.press.axis=Press an axis or key... -keybind.deselect.name=Deselect -block.surge-wall.name=Surge Wall -block.surge-wall-large.name=Large Surge Wall +text.construction.desktop=Die Desktop Steuerung wurde geändert.\n Zum deselektieren eines Blocks oder das Bauen abzubrechen benutze die [accent] Space Taste[]. +keybind.press=Drücke eine Taste... +keybind.press.axis=Drücke eine Taste oder bewege eine Achse... +keybind.deselect.name=Deselektieren +block.surge-wall.name=Surge Mauer +block.surge-wall-large.name=Grosse Surge Mauer block.cyclone.name=Cyclone block.fuse.name=Fuse -text.confirmkick=Are you sure you want to kick this player? -text.settings.cleardata=Clear Game Data... -text.settings.clear.confirm=Are you sure you want to clear this data?\nWhat is done cannot be undone! -text.settings.clearall.confirm=[scarlet]WARNING![]\nThis will clear all data, including saves, maps, unlocks and keybinds.\nOnce you press 'ok' the game will wipe all data and automatically exit. -text.settings.clearsectors=Clear Sectors -text.settings.clearunlocks=Clear Unlocks -text.settings.clearall=Clear All -block.shock-mine.name=Shock Mine -block.overdrive-projector.name=Overdrive Projector -text.blocks.powerdamage=Power/Damage -mode.custom.warning=Note that blocks cannot be used in custom games until they are unlocked in sectors.\n\n[LIGHT_GRAY]If you have not unlocked any blocks, none will appear. -content.unit.name=Units -block.force-projector.name=Force Projector +text.confirmkick=Bist du sicher das du diesen Spieler kicken willst? +text.settings.cleardata=Spieldaten zurücksetzen... +text.settings.clear.confirm=Bist du sicher das du die Spieldaten zurücksetzen willst?\n Diese Aktion kann nicht rückgänig gemacht werden! +text.settings.clearall.confirm=[scarlet]Warnung![]\nDas wird jegliche Spieldaten zurücksetzen inklusive Speicherstände, Karten, Freischaltungen und Tastenbelegungen.\n Nachdem du 'OK' drückst wird alles zurückgesetzt und das Spiel schließt sich automatisch. +text.settings.clearsectors=Sektoren zurücksetzen +text.settings.clearunlocks=Freischaltungen zurücksetzen +text.settings.clearall=Alles zurücksetzen +block.shock-mine.name=Schock Mine +block.overdrive-projector.name=Overdrive Projektor +text.blocks.powerdamage=Power/Schaden +mode.custom.warning=Beachte das Blöcke auch in Eigenen Spielen nicht verwendet werden können, solange sie nicht in den Sektoren freigespielt wurden.\n\n[LIGHT_GRAY]Solange ein Block nicht freigeschaltet wurde, ist er nicht sichtbar. +content.unit.name=Einheiten +block.force-projector.name=Force Projektor block.arc.name=Arc block.rtg-generator.name=RTG Generator block.spectre.name=Spectre block.meltdown.name=Meltdown text.mission.info=Mission Info -text.mission.wave.enemies=Survive[accent] {0}/{1} []waves\n{2} Enemies -text.mission.wave.enemy=Survive[accent] {0}/{1} []waves\n{2} Enemy -text.mission.wave.menu=Survive[accent] {0} []waves -text.mission.resource.menu=Obtain {0} x{1} -text.mission.block=Create {0} -text.mission.unit=Create {0} Unit -text.mission.linknode=Link Power Node +text.mission.wave.enemies=Überlebe[accent] {0}/{1} []Wellen\n{2} Gegner +text.mission.wave.enemy=Überlebe[accent] {0}/{1} []Wellen\n{2} Gegner +text.mission.wave.menu=Überlebe[accent] {0} []Wellen +text.mission.resource.menu=Erlange {0} x{1} +text.mission.block=Erstelle {0} +text.mission.unit=Erstelle {0} Einheiten +text.mission.linknode=Verbinde Power Knoten text.mission.display=[accent]Mission:\n[LIGHT_GRAY]{0} text.hostserver.mobile=Host\nGame setting.difficulty.training=training -block.dense-alloy-wall.name=Dense Alloy Wall -block.dense-alloy-wall-large.name=Large Dense Alloy Wall +block.dense-alloy-wall.name=Dichte Legierungs Mauer +block.dense-alloy-wall-large.name=Grosse Dichte Legierungs Mauer block.dart-ship-pad.name=Dart Ship Pad block.delta-mech-pad.name=Delta Mech Pad block.javelin-ship-pad.name=Javelin Ship Pad @@ -601,74 +601,74 @@ block.trident-ship-pad.name=Trident Ship Pad block.glaive-ship-pad.name=Glaive Ship Pad block.omega-mech-pad.name=Omega Mech Pad block.tau-mech-pad.name=Tau Mech Pad -block.spirit-factory.name=Spirit Drone Factory -block.phantom-factory.name=Phantom Drone Factory -block.wraith-factory.name=Wraith Fighter Factory -block.ghoul-factory.name=Ghoul Bomber Factory -block.dagger-factory.name=Dagger Mech Factory -block.titan-factory.name=Titan Mech Factory -block.revenant-factory.name=Revenant Fighter Factory +block.spirit-factory.name=Spirit Drone Fabrik +block.phantom-factory.name=Phantom Drone Fabrik +block.wraith-factory.name=Wraith Fighter Fabrik +block.ghoul-factory.name=Ghoul Bomber Fabrik +block.dagger-factory.name=Dagger Mech Fabrik +block.titan-factory.name=Titan Mech Fabrik +block.revenant-factory.name=Revenant Fighter Fabrik unit.spirit.name=Spirit Drone -unit.spirit.description=The starter drone unit. Spawns in the core by default. Automatically mines ores, collects items and repairs blocks. +unit.spirit.description=Die anfängliche Drohne. Sie wird gewöhnlich im Kern erzeugt. Baut automatisch Erz ab, sammelt Gegenstände und repariert Blöcke. unit.phantom.name=Phantom Drone -unit.phantom.description=An advanced drone unit. Automatically mines ores, collects items and repairs blocks. Significantly more effective than a drone. +unit.phantom.description=Eine fortgeschrittene Drohne. Baut automatisch Erz ab, sammelt Gegenstände und repariert Blöcke. Signifikant effizienter als die Drohne. unit.ghoul.name=Ghoul Bomber -unit.ghoul.description=A heavy carpet bomber. Uses blast compound or pyratite as ammo. +unit.ghoul.description=Ein schwerer Flächen Bomber. Benutzt Explosives Gemisch und Pyratite als Munition. unit.wraith.name=Wraith Fighter -unit.wraith.description=A fast, hit-and-run interceptor unit. +unit.wraith.description=Eine schnelle Abfangjäger Einheit. unit.fortress.name=Fortress -unit.fortress.description=A heavy artillery ground unit. +unit.fortress.description=Eine schwere Artillerie Boden-Einheit. unit.revenant.name=Revenant -unit.revenant.description=A heavy laser platform. -tutorial.begin=Your mission here is to eradicate the[LIGHT_GRAY] enemy[].\n\nBegin by[accent] mining copper[]. Tap a copper ore vein near your core to do this. -tutorial.drill=Mining manually is inefficient.\n[accent]Drills []can mine automatically.\nPlace one on a copper vein. -tutorial.conveyor=[accent]Conveyors[] are used to transport items to the core.\nMake a line of conveyors from the drill to the core. -tutorial.morecopper=More copper is required.\n\nEither mine it manually, or place more drills. -tutorial.turret=Defensive structures must be built to repel the[LIGHT_GRAY] enemy[].\nBuild a duo turret near your base. -tutorial.drillturret=Duo turrets require[accent] copper ammo []to shoot.\nPlace a drill next to the turret to supply it with mined copper. -tutorial.waves=The[LIGHT_GRAY] enemy[] approaches.\n\nDefend your core for 2 waves. Build more turrets. -tutorial.lead=More ores are available. Explore and mine[accent] lead[].\n\nDrag from your unit to the core to transfer resources. -tutorial.smelter=Copper and lead are weak metals.\nSuperior[accent] Dense Alloy[] can be created in a smelter.\n\nBuild one. -tutorial.densealloy=The smelter will now produce alloy.\nGet some.\nImprove the production if necessary. -tutorial.siliconsmelter=The core will now create a[accent] spirit drone[] for mining and repairing blocks.\n\nFactories for other units can be created with [accent] silicon.\nMake a silicon smelter. -tutorial.silicondrill=Silicon requires[accent] coal[] and[accent] sand[].\nStart by making drills. -tutorial.generator=This technology requires power.\nCreate a[accent] combustion generator[] for it. -tutorial.generatordrill=Combustion generators need fuel.\nFuel it with coal from a drill. -tutorial.node=Power requires transport.\nCreate a[accent] power node[] next to your combustion generator to transfer its power. -tutorial.nodelink=Power can be transferred through contacting power blocks and generators, or by linked power nodes.\n\nLink power by tapping the node and selecting the generator and silicon smelter. -tutorial.silicon=Silicon is being produced. Get some.\n\nImproving the production system is advised. -tutorial.daggerfactory=Construct a[accent] dagger mech factory.[]\n\nThis will be used to create attack mechs. -tutorial.router=Factories need resources to function.\nCreate a router to split conveyor resources. -tutorial.dagger=Link power nodes to the factory.\nOnce requirements are met, a mech will be created.\n\nCreate more drills, generators and conveyors as necessary. -tutorial.battle=The[LIGHT_GRAY] enemy[] has revealed their core.\nDestroy it with your unit and dagger mechs. -text.missions=Missions:[LIGHT_GRAY] {0} -text.mission.command=Send Command {0} To Units -text.mission.mech=Switch to mech[accent] {0}[] -text.mission.create=Create[accent] {0}[] -text.wave.enemies=[LIGHT_GRAY]{0} Enemies Remaining -text.wave.enemy=[LIGHT_GRAY]{0} Enemy Remaining +unit.revenant.description=Eine schwere Laser Platform. +tutorial.begin=Deine Mission ist es den [LIGHT_GRAY]Gegner[] auszurotten.\n\n Beginne damit [accent] Kupfer abzubauen[]. Beginne in dem du auf ein Kupfer Vorkommen nahe deines Kerns klickst. +tutorial.drill=Manuelles Abbauen von Ressourcen ist ineffizient.\n[accent]Bohrer[] können automatisch abbauen.\n Platziere einen auf einem Kupfer Vorkommen. +tutorial.conveyor=[accent]Transportbänder[] werden dazu benutzt Gegenstände zum Kern zu transportieren.\n Erstelle eine Reihe von Transportbändern zum Kern. +tutorial.morecopper=Du brauchst [accent]mehr Kupfer[]!\n\nEntweder du baust es manuell ab, oder du platzierst weitere Bohrer. +tutorial.turret=Wir benötigen Verteidigung gegen den [LIGHT_GRAY] Gegner[].\n Baue einen Duo Turm nahe deiner Basis. +tutorial.drillturret=Der Duo Turm benötigt[accent] Kupfer[] als Munition. Platziere einen Bohrer neben dem Turm, um ihn mit Kupfer zu versorgen. +tutorial.waves=Der [LIGHT_GRAY] Gegner[] greift an.\n\nVerteidige deinen Kern 2 Wellen lang. Bau mehr Türme. +tutorial.lead=Mehr Erz ist verfügbar. Finde Blei und bau es ab.\n\n Klicke auf deine Einheit und ziehe die Maus auf den Kern um Ressourcen zu übertragen. +tutorial.smelter=Kupfer und Blei sind schwache Metalle.\n Super [accent]dichte Legierung [] kann in einem Schmeltzer erzeugt werden.\n\n Bau einen. +tutorial.densealloy=Der Schmeltzer wird nun Legierung produzieren.\n Produziere einige.\n Verbessere die Produktion sofern notwendig. +tutorial.siliconsmelter=Der Kern wird nun [accent]spirit drohnen[] erstellen. Diese Bauen Rohstoffe und reparieren Blöcke.\n\nFabriken für andere Einheiten benötigen [accent]Silikon[].\n Baue ein Silikon Schmeltzer. +tutorial.silicondrill=Silikon benötigt [accent]Kohle[] und [accent]Sand[].\n Fange damit an die Bohrer zu platzieren. +tutorial.generator=Diese Technologie benötigt power.\n Erstelle einen Verbrennungs-Generator dafür. +tutorial.generatordrill=Verbrennungs Generatoren benötigen Kraftstoff.\nBenutze Kohle aus einem Bohrer als Kraftstoff. +tutorial.node=Power muss transportiert werden.\nErstelle einen [accent]Power Knoten[] nahe deinem Verbrennungs Generator um seine Power zu transportieren. +tutorial.nodelink=Power kann über verbundene Power Blocks, Generatoren oder Power Knoten transferierd werden.\n\n Verbinde die Power in dem du auf den Knoten klickst und dann den Generator und den Silikon Schmeltzer auswählst. +tutorial.silicon=Silikon wird produziert. Produziere einiges.\n\n Verbesserungen am Produktionssystem werden empfohlen. +tutorial.daggerfactory=Konstruiere eine Dagger Mech Fabrik.\n\n Diese wird verwendet um Angreifende Mechs zu erstellen. +tutorial.router=Fabriken benötigen Ressourcen um zu funktionieren.\n Platziere ein Router um Gegenstände auf Transportbändern aufzuteilen. +tutorial.dagger=Verbinde die Fabrik mit einem Power Knoten. Wenn alle Voraussetzungen gegeben sind, beginnt die Fabrik Mechs zu konstruieren.\n\n Platziere mehr Bohrer und Transportbänder um die Versorgung der Fabrik zu sichern. +tutorial.battle=Der[LIGHT_GRAY] Gegner[] hat seinen Kern offenbart.\nZerstöre ihn mit deiner Einheit und den Dagger Mechs. +text.missions=Missionen:[LIGHT_GRAY] {0} +text.mission.command=Sende Command {0} an Einheiten +text.mission.mech=Wechsele zu Mech[accent] {0}[] +text.mission.create=Platziere[accent] {0}[] +text.wave.enemies=[LIGHT_GRAY]{0} Gegner Verbleiben +text.wave.enemy=[LIGHT_GRAY]{0} Gegner Verbleiben setting.autotarget.name=Auto-Target -command.attack=Attack -command.retreat=Retreat -command.patrol=Patrol -block.spawn.name=Enemy Spawn -block.fortress-factory.name=Fortress Mech Factory -text.gameover.pvp=The[accent] {0}[] team is victorious! -text.sector.abandon=Abandon -text.sector.abandon.confirm=Are you sure you want to abandon all progress at this sector?\nThis cannot be undone! -text.mission.main=Main Mission:[LIGHT_GRAY] {0} -text.waiting.players=Waiting for players... -text.map.nospawn.pvp=This map does not have any enemy cores for player to spawn into! Add[SCARLET] red[] cores to this map in the editor. +command.attack=Angreifen +command.retreat=Rückzug +command.patrol=Patrouillieren +block.spawn.name=Gegner Spawn +block.fortress-factory.name=Fortress Mech Fabrik +text.gameover.pvp=Das[accent] {0}[] Team ist Siegreich! +text.sector.abandon=Aufgeben +text.sector.abandon.confirm=Bist du sicher das du allen Fortschritt in diesem Sektor aufgeben willst?\n Diese Aktion kann nicht Rückgängig gemacht werden! +text.mission.main=Haupt Mission:[LIGHT_GRAY] {0} +text.waiting.players=Warte auf Spieler... +text.map.nospawn.pvp=Diese Karte hat keine gegnerischen Kerne wo Gegner starten könnten! Füge über den Editor [SCARLET] rote[] Kerne zu dieser Karte hinzu. text.blocks.basepowergeneration=Base Power Generation -text.blocks.liquidoutputspeed=Liquid Output Speed -mode.custom.warning.read=Just to make sure you've read it:\n[scarlet]UNLOCKS IN CUSTOM GAMES DO NOT CARRY OVER TO SECTORS OR OTHER MODES!\n\n[LIGHT_GRAY](I wish this wasn't necessary, but apparently it is) +text.blocks.liquidoutputspeed=Flüssigkeits-Ausgabe Geschwindigkeit +mode.custom.warning.read=Nur um sicherzugehen das du es gelesen hast:\n[scarlet]FREISCHALTUNGEN in Eigenen Spielen übertragen sich NICHT in Sektoren oder andere Modis!\n\n[LIGHT_GRAY](Ich wünschte der Hinweis wäre nicht notwendig, aber offensichtlich ist es das)[] mode.pvp.name=PvP -mode.pvp.description=fight against other players locally. +mode.pvp.description=Kämpfe gegen andere Spieler local. block.alpha-mech-pad.name=Alpha Mech Pad block.container.name=Container -team.blue.name=blue -team.red.name=red -team.orange.name=orange -team.none.name=gray -team.green.name=green -team.purple.name=purple +team.blue.name=Blau +team.red.name=Rot +team.orange.name=Orange +team.none.name=Grau +team.green.name=Grün +team.purple.name=Lila \ No newline at end of file From 412d92e78232c4f45cbba8da381e4c52009d92c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=ED=82=A4=EC=97=90=EB=A5=B4?= <44261958+Kieaer@users.noreply.github.com> Date: Sat, 20 Oct 2018 22:33:43 +0900 Subject: [PATCH 06/11] Update bundle_ko.properties (#255) --- core/assets/bundles/bundle_ko.properties | 449 ++++++++++++----------- 1 file changed, 231 insertions(+), 218 deletions(-) diff --git a/core/assets/bundles/bundle_ko.properties b/core/assets/bundles/bundle_ko.properties index 11745983fa..8fe8d74b13 100644 --- a/core/assets/bundles/bundle_ko.properties +++ b/core/assets/bundles/bundle_ko.properties @@ -5,18 +5,18 @@ text.link.github.description=게임 소스코드 text.link.dev-builds.description=개발중인 빌드 text.link.trello.description=다음 출시될 기능들을 게시한 공식 Trello 보드 text.link.itch.io.description=PC 버전 다운로드와 HTML5 버전이 있는 itch.io 사이트 -text.link.google-play.description=Google 플레이 스토어 등록 정보 -text.link.wiki.description=공식 Mindustry 위키 -text.linkfail=링크를 여는데 실패했습니다!URL이 기기의 클립보드에 복사되었습니다. -text.editor.web=HTML5 버전은 에디터 기능을 지원하지 않습니다!게임을 다운로드 한 뒤에 사용 해 주세요. -text.web.unsupported=HTML5 버전은 이 기능을 지원하지 않습니다!게임을 다운로드 한 뒤에 사용 해 주세요. +text.link.google-play.description=Google Play 스토어 정보 +text.link.wiki.description=공식 Mindustry 위키 (영어) +text.linkfail=링크를 여는데 실패했습니다! URL이 기기의 클립보드에 복사되었습니다. +text.editor.web=HTML5 버전은 에디터 기능을 지원하지 않습니다! 게임을 다운로드 한 뒤에 사용 해 주세요. +text.web.unsupported=HTML5 버전은 이 기능을 지원하지 않습니다! 게임을 다운로드 한 뒤에 사용 해 주세요. text.gameover=코어가 터졌습니다. 게임 오버! text.highscore=[YELLOW]최고점수 달성! -text.level.highscore=최고 점수:[accent]{0} +text.level.highscore=최고 점수 : [accent]{0} text.level.delete.title=삭제 확인 text.map.delete=정말로 "[orange]{0}[]" 맵을 삭제하시겠습니까? text.level.select=맵 선택 -text.level.mode=게임모드: +text.level.mode=게임모드 : text.construction.title=블록 배치 안내서 text.construction=[accent]블록 배치 모드[]를 선택하셨습니다.\n\n블록을 설치하고 싶으면, 자신의 건설 가능 범위 내에서 간단히 탭 하면 됩니다.\n일부 블록을 선택한 후에 확인 버튼을 누르면 배가 배치 작업을 진행할 것입니다.\n- [accent]블록을 삭제[]하고 싶다면 배치하고 싶은 영역을 탭 하세요. \n- [accent]블록을 넓게 배치[]하고 싶다면 배치하고 싶은 시작 영역을 길게 누르며 드래그 하면 됩니다.- [accent]블록을 한줄로 배치[]하고 싶다면 배치하고 싶은 시작 영역을 한번 탭 하고 길게 누르면서 드래그 하면 됩니다. \n- [accent]블록 배치 모드를 취소[]하고 싶다면 화면 하단 왼쪽에 있는 X 버튼을 누르면 됩니다. text.deconstruction.title=블록 삭제 안내서 @@ -31,23 +31,23 @@ text.quit=나가기 text.maps=맵 text.maps.none=[LIGHT_GRAY]맵을 찾을 수 없습니다! text.about.button=정보 -text.name=이름: +text.name=이름 : text.unlocked=새 블록 잠금 해제 text.unlocked.plural=새 블록 잠금 해제 text.players=현재 {0}명 접속중 text.players.single=현재 {0}명만 있음. text.server.mismatch=클라이언트와 서버 버전이 일치하지 않습니다. 자신이 서버를 호스트하거나 최신 버전을 사용 해 주세요! text.server.closing=[accent]서버 닫는중... -text.server.kicked.kick=당신은 서버에서 추방되었습니다! +text.server.kicked.kick=서버에서 추방되었습니다! text.server.kicked.clientOutdated=오래된 버전의 클라이언트 입니다! 게임을 업데이트 하세요! text.server.kicked.serverOutdated=오래된 버전의 서버입니다! 서버 호스트 관리자에게 문의하세요! -text.server.kicked.banned=당신은 서버에서 밴 망치를 맞아 차단당했습니다. -text.server.kicked.recentKick=당신은 방금 추방처리 되었습니다. 잠시 기다린 후에 접속 해 주세요. +text.server.kicked.banned=서버에서 영 좋지 않은 행위를 하여 영구 차단되었습니다. +text.server.kicked.recentKick=방금 추방처리 되었습니다. 잠시 기다린 후에 접속 해 주세요. text.server.kicked.nameInUse=이 닉네임이 이미 서버에서 사용중입니다. text.server.kicked.nameEmpty=닉네임에는 반드시 영어 또는 숫자가 있어야 합니다. -text.server.kicked.idInUse=당신은 이미 서버에 접속중입니다! 다중 계정은 허용되지 않습니다. -text.server.kicked.customClient=이 서버는 커스텀 빌드를 지원하지 않습니다. 공식 버전을 사용하세요. -text.host.info=[accent]호스트[] 버튼은 현재 네트워크의 [scarlet]6567[] 과 [scarlet]6568[] 포트를 사용합니다.\n[LIGHY_GRAY]같은 Wi-Fi 또는 로컬 네트워크[] 에서 서버 목록을 볼 수 있습니다.\n\n만약 플레이어들이 이 IP를 통해 어디에서나 연결할 수 있게 하고 싶다면, 공유기 설정에서 [accent]포트 포워딩[]을 해야 합니다.\n\n[LIGHT_GRAY]참고:LAN 게임 연결에 문제가 있는 사람이 있다면, 방화벽 설정에서 Mindustry 가 로컬 네트워크에 액세스하도록 허용했는지 확인 해 주세요. +text.server.kicked.idInUse=이미 서버에 접속중입니다! 다중 계정은 허용되지 않습니다. +text.server.kicked.customClient=이 서버는 직접 빌드한 버전을 지원하지 않습니다. 공식 버전을 사용하세요. +text.host.info=[accent]호스트[] 버튼은 현재 네트워크의 [scarlet]6567[] 과 [scarlet]6568[] 포트를 사용합니다.\n[LIGHY_GRAY]같은 Wi-Fi 또는 로컬 네트워크[] 에서 서버 목록을 볼 수 있습니다.\n\n만약 플레이어들이 이 IP를 통해 어디에서나 연결할 수 있게 하고 싶다면, 공유기 설정에서 [accent]포트 포워딩[]을 해야 합니다.\n\n[LIGHT_GRAY]참고 : LAN 게임 연결에 문제가 있는 사람이 있다면, 방화벽 설정에서 Mindustry 가 로컬 네트워크에 액세스하도록 허용했는지 확인 해 주세요. text.join.info=여기서 [accent]서버 IP[]를 입력하여 다른 서버에 접속할 수 있습니다.\n또는 [accent]로컬 네트워크(LAN)[] 서버를 검색하여 접속할 수 있습니다.\nLAN 및 WAN 멀티 플레이어 모두 지원됩니다.\n\n[LIGHT_GRAY]참고:여기에서는 자동으로 글로벌 서버를 추가하지 않습니다. IP로 다른 사람의 서버에 접속할려면 서버장에게 IP를 요청해야 합니다. text.hostserver=서버 열기 text.host=호스트 @@ -57,75 +57,75 @@ text.hosts.discovering=LAN 게임 찾기 text.server.refreshing=서버 목록 새로고치는중... text.hosts.none=[lightgray]LAN 게임을 찾을 수 없습니다! text.host.invalid=[scarlet]서버에 연결할 수 없습니다! -text.trace=플레이어 추적 -text.trace.playername=이름:[accent]{0} -text.trace.ip=IP:[accent]{0} -text.trace.id=고유 ID:[accent]{0} -text.trace.android=Android 클라이언트:[accent]{0} -text.trace.modclient=수정된 클라이언트:[accent]{0} -text.trace.totalblocksbroken=총 블럭 파괴 개수:[accent]{0} -text.trace.structureblocksbroken=구조 블럭 파괴 수:[accent]{0} -text.trace.lastblockbroken=마지막으로 파괴한 블럭:[accent]{0} -text.trace.totalblocksplaced=총 설치한 블럭 개수:[accent]{0} -text.trace.lastblockplaced=마지막으로 설치한 블록:[accent]{0} +text.trace=플레이어 정보 보기 +text.trace.playername=이름 : [accent]{0} +text.trace.ip=IP : [accent]{0} +text.trace.id=고유 ID : [accent]{0} +text.trace.android=Android 클라이언트 : [accent]{0} +text.trace.modclient=수정된 클라이언트 : [accent]{0} +text.trace.totalblocksbroken=총 블록 파괴 개수 : [accent]{0} +text.trace.structureblocksbroken=구조 블록 파괴 수 : [accent]{0} +text.trace.lastblockbroken=마지막으로 파괴한 블록 : [accent]{0} +text.trace.totalblocksplaced=총 설치한 블록 개수 : [accent]{0} +text.trace.lastblockplaced=마지막으로 설치한 블록 : [accent]{0} text.invalidid=잘못된 클라이언트 ID 입니다! 공식 Mindustry Discord 으로 버그 보고서를 제출 해 주세요. text.server.bans=차단된 유저 text.server.bans.none=차단된 플레이어가 없습니다. -text.server.admins=관리자 -text.server.admins.none=관리자가 없습니다! +text.server.admins=영자 +text.server.admins.none=영자가 없습니다! text.server.add=서버 추가 text.server.delete=이 서버를 삭제 하시겠습니까? -text.server.hostname=호스트:{0} +text.server.hostname=호스트 : {0} text.server.edit=서버 수정 text.server.outdated=[crimson]서버 버전이 낮습니다![] text.server.outdated.client=[Crimson]클라이언트 버전이 낮습니다![] -text.server.version=[lightgray]서버 버전:{0} +text.server.version=[lightgray]서버 버전 : {0} text.server.custombuild=[yellow]커스텀 서버 text.confirmban=이 플레이어를 차단하시겠습니까? -text.confirmunban=이 플레이어를 차단하시겠습니까? -text.confirmadmin=이 플레이어를 관리자로 설정 하시겠습니까? -text.confirmunadmin=이 플레이어의 관리자 상태를 해제하시겠습니까? +text.confirmunban=이 플레이어를 차단해제 하시겠습니까? +text.confirmadmin=이 플레이어를 영자로 만들겠습니까? +text.confirmunadmin=이 플레이어를 일반 유저로 만들겠습니까? text.joingame.title=게임 참가 -text.joingame.ip=IP: +text.joingame.ip=IP : text.disconnect=서버와 연결이 해제되었습니다. text.disconnect.data=맵 데이터를 받아오는데 실패했습니다. text.connecting=[accent]연결중... text.connecting.data=[accent]맵 데이터 다운로드중... text.connectfail=[crimson]{0}[orange] 서버에 연결하지 못했습니다.[] -text.server.port=포트: +text.server.port=포트 : text.server.addressinuse=이 주소는 이미 사용중입니다! text.server.invalidport=포트 번호가 잘못되었습니다. text.server.error=[crimson]{0}[orange]서버를 여는데 오류가 발생했습니다.[] -text.save.new=새로 저장\n -text.save.overwrite=이 저장 슬롯을 덮어씌우겠습니까?\n -text.overwrite=덮어쓰기\n -text.save.none=저장 파일을 찾지 못했습니다!\n -text.saveload=[accent]저장중...\n -text.savefail=게임을 저장하지 못했습니다!\n -text.save.delete.confirm=이 저장파일을 삭제 하시겠습니까?\n -text.save.delete=삭제\n -text.save.export=저장파일 내보내기\n -text.save.import.invalid=[orange]저장 상태가 정상이 아닙니다! -text.save.import.fail=[crimson]저장파일을 불러오지 못함:[orange]{0}\n -text.save.export.fail=[crimson]저장파일을 내보내지 못함:[orange]{0} -text.save.import=저장파일 불러오기\n -text.save.newslot=저장 파일이름 :\n -text.save.rename=이름 변경\n -text.save.rename.text=새 이름 :\n -text.selectslot=저장슬롯을 선택하십시오.\n -text.slot=[accent]{0}번째 슬롯\n -text.save.corrupted=[orange]세이브 파일이 손상되었거나 잘못된 파일입니다!만약 게임을 업데이트 했다면 이것은 아마 저장 형식 변경일 것이고, 이것은 버그가 [scarlet]아닙니다[].\n\n -text.empty=<비어있음>\n -text.on=켜기\n -text.off=끄기\n -text.save.autosave=자동저장:{0} -text.save.map=맵:{0} -text.save.wave={0}단계 -text.save.difficulty=난이도:{0} -text.save.date=마지막 저장 날짜:{0} +text.save.new=새로 저장 +text.save.overwrite=이 저장 슬롯을 덮어씌우겠습니까? +text.overwrite=덮어쓰기 +text.save.none=저장 파일을 찾지 못했습니다! +text.saveload=[accent]저장중... +text.savefail=게임을 저장하지 못했습니다! +text.save.delete.confirm=이 저장파일을 삭제 하시겠습니까? +text.save.delete=삭제 +text.save.export=저장파일 내보내기 +text.save.import.invalid=[orange]파일이 잘못되었습니다! +text.save.import.fail=[crimson]저장파일을 불러오지 못함 : [orange]{0} +text.save.export.fail=[crimson]저장파일을 내보내지 못함 : [orange]{0} +text.save.import=저장파일 불러오기 +text.save.newslot=저장 파일이름 : +text.save.rename=이름 변경 +text.save.rename.text=새 이름 : +text.selectslot=저장슬롯을 선택하십시오. +text.slot=[accent]{0}번째 슬롯 +text.save.corrupted=[orange]세이브 파일이 손상되었거나 잘못된 파일입니다! 만약 게임을 업데이트 했다면 이것은 아마 저장 형식 변경일 것이고, 이것은 버그가 [scarlet]아닙니다[]. +text.empty=<비어있음> +text.on=켜기 +text.off=끄기 +text.save.autosave=자동저장 : {0} +text.save.map=맵 : {0} +text.save.wave={0}단계[] +text.save.difficulty=난이도 : {0} +text.save.date=마지막 저장날짜 : {0} text.confirm=확인 -text.delete=삭제\n -text.ok=승인 +text.delete=삭제 +text.ok=확인 text.open=열기 text.cancel=취소 text.openlink=링크 열기 @@ -140,10 +140,10 @@ text.changelog.error=[scarlet]게임 변경사항을 가져오는 중 오류가 text.changelog.current=[orange][[현재 버전] text.changelog.latest=[orange][[최신 버전] text.loading=[accent]불러오는중... -text.saving=[accent]저장중...\n +text.saving=[accent]저장중... text.wave=[orange]{0}단계 text.wave.waiting=다음 단계 시작까지 {0}초 -text.waiting=대기중... +text.waiting=[LIGHT_GRAY]대기중... text.loadimage=사진 불러오기 text.saveimage=사진 저장 text.unknown=알 수 없음 @@ -151,18 +151,18 @@ text.custom=커스텀 text.builtin=내장 text.map.delete.confirm=이 맵을 삭제하시겠습니까? 이 명령은 취소할 수 없습니다! text.map.random=[accent]랜덤 맵 -text.map.nospawn=이 맵에는 플레이어가 스폰 할 코어가 없습니다! 맵 편집기에서 [ROYAL]파란색[]코어를 맵에 추가하세요. +text.map.nospawn=이 맵에 플레이어가 스폰 할 코어가 없습니다! 맵 편집기에서 [ROYAL]파란색[]코어를 맵에 추가하세요. text.editor.slope=\\ text.editor.openin=편집기 열기 text.editor.oregen=광물 무작위 생성 -text.editor.oregen.info=광물 무작위 생성: +text.editor.oregen.info=광물 무작위 생성 : text.editor.mapinfo=맵 정보 -text.editor.author=만든이: -text.editor.description=설명: -text.editor.name=이름: +text.editor.author=만든이 : +text.editor.description=설명 : +text.editor.name=이름 : text.editor.teams=팀 text.editor.elevation=높이 -text.editor.badsize=[orange]사진 크기가 잘못되었습니다![]유효한 맵 크기:{0} +text.editor.badsize=[orange]사진 크기가 잘못되었습니다![] 유효한 맵 크기 : {0} text.editor.errorimageload=[orange]{0}[] 파일을 불러오는데 오류가 발생했습니다. text.editor.errorimagesave=[orange]{0}[] 파일 저장중 오류가 발생했습니다. text.editor.generate=생성 @@ -172,7 +172,7 @@ text.editor.savemap=맵 저장 text.editor.saved=저장됨! text.editor.save.noname=지도에 이름이 없습니다! '맵 정보' 메뉴에서 설정하세요. text.editor.save.overwrite=이 맵의 이름은 기존에 있던 맵을 덮어씁니다! '맵 정보' 메뉴에서 다른 이름을 선택하세요. -text.editor.import.exists=[scarlet]맵을 불러올 수 없음:[] 기존에 있던 '{0}' 맵이 이미 존재합니다! +text.editor.import.exists=[scarlet]맵을 불러올 수 없음 : [] 기존에 있던 '{0}' 맵이 이미 존재합니다! text.editor.import=가져오기 text.editor.importmap=맵 가져오기 text.editor.importmap.description=이미 존재하는 맵 가져오기 @@ -187,22 +187,22 @@ text.editor.exportimage=지형 이미지 내보내기 text.editor.exportimage.description=맵 이미지 파일 내보내기 text.editor.loadimage=지형 가져오기 text.editor.saveimage=지형 내보내기 -text.editor.unsaved=[scarlet]변경사항을 저장하지 않았습니다![]\n정말로 나가시겠습니까?\n +text.editor.unsaved=[scarlet]변경사항을 저장하지 않았습니다![]\n정말로 나가시겠습니까? text.editor.resizemap=맵 크기 조정 -text.editor.mapname=맵 이름: -text.editor.overwrite=[accept]경고!이 명령은 기존 맵을 덮어씌우게 됩니다.\n +text.editor.mapname=맵 이름 : +text.editor.overwrite=[accept]경고!이 명령은 기존 맵을 덮어씌우게 됩니다. text.editor.overwrite.confirm=[scarlet]경고![] 이 이름을 가진 맵이 이미 있습니다. 덮어 쓰시겠습니까? -text.editor.selectmap=불러올 맵 선택: -text.width=넓이: -text.height=높이: +text.editor.selectmap=불러올 맵 선택 : +text.width=넓이 : +text.height=높이 : text.menu=메뉴 text.play=플레이 text.load=불러오기 text.save=저장 text.fps={0}FPS text.tps={0}TPS -text.ping={0}ms -text.language.restart=언어를 변경하려면 게임을 다시 시작 해 주세요. +text.ping=ping : {0}ms +text.language.restart=언어를 변경하려면 게임을 다시시작 해 주세요. text.settings.language=언어 text.settings=설정 text.tutorial=게임 방법 @@ -264,11 +264,9 @@ text.unit.powersecond=전력/초 text.unit.liquidsecond=액체/초 text.unit.itemssecond=개/초 text.unit.pixelssecond=초당 픽셀 -text.unit.liquidunits= text.unit.powerunits=전력 text.unit.degrees=도 text.unit.seconds=초 -text.unit.none= text.unit.items=아이템 text.category.general=일반 text.category.power=전력 @@ -279,8 +277,8 @@ text.category.shooting=사격 setting.difficulty.easy=쉬움 setting.difficulty.normal=보통 setting.difficulty.hard=어려움 -setting.difficulty.insane=[#1E90FF]K[#ADFF2F]O[#FFB6C1]R[#B0C4DE]E[#FF4500]A -setting.difficulty.name=난이도: +setting.difficulty.insane=이걸 할수있을까? +setting.difficulty.name=난이도 : setting.screenshake.name=화면 흔들기 setting.indicators.name=적 위치 표시 화살표 setting.effects.name=화면 효과 @@ -351,13 +349,13 @@ liquid.water.name=물 liquid.lava.name=용암 liquid.oil.name=석유 liquid.cryofluid.name=냉각수 -text.item.explosiveness=[LIGHT_GRAY]폭발력:{0} -text.item.flammability=[LIGHT_GRAY]인화성:{0} -text.item.radioactivity=[LIGHT_GRAY]방사능:{0} -text.item.fluxiness=[LIGHT_GRAY]플렉스 파워:{0} -text.liquid.heatcapacity=[LIGHT_GRAY]발열량:{0} -text.liquid.viscosity=[LIGHT_GRAY]점도:{0} -text.liquid.temperature=[LIGHT_GRAY]온도:{0} +text.item.explosiveness=[LIGHT_GRAY]폭발력 : {0} +text.item.flammability=[LIGHT_GRAY]인화성 : {0} +text.item.radioactivity=[LIGHT_GRAY]방사능 : {0} +text.item.fluxiness=[LIGHT_GRAY]플렉스 파워 : {0} +text.liquid.heatcapacity=[LIGHT_GRAY]발열량 : {0} +text.liquid.viscosity=[LIGHT_GRAY]점도 : {0} +text.liquid.temperature=[LIGHT_GRAY]온도 : {0} block.deepwater.name=깊은물 block.water.name=물 block.lava.name=용암 @@ -393,7 +391,7 @@ block.sorter.description=아이템을 넣어서 필터에 설정된 아이템일 block.overflow-gate.name=오버플로 게이트 block.overflow-gate.description=정면 경로가 차단된 경우 왼쪽과 오른쪽으로만 출력하는 복합 분배기입니다. block.bridgeconveyor.name=터널 -block.bridgeconveyor.description=최대 2블록을 건너 뛰고 자원을 운반하게 해 주는 블럭. +block.bridgeconveyor.description=최대 2블록을 건너 뛰고 자원을 운반하게 해 주는 블록. block.smelter.name=제련소 block.arc-smelter.name=대형 제련소 block.silicon-smelter.name=실리콘 제련소 @@ -448,41 +446,42 @@ block.rotary-pump.name=동력 펌프 text.save.old=이 저장파일은 이전 버전의 게임용이며, 지금은 사용할 수 없습니다. \n\n[LIGHT_GRAY]4.0 정식때 이전 게임버전에서 만든 저장파일과 호환됩니다. text.customgame=커스텀 게임 text.sectors=구역 -text.sector=선택된 구역:[LIGHT_GRAY]{0} -text.sector.time=시간:[LIGHT_GRAY]{0} -text.sector.deploy=배치 +text.sector=선택된 구역 : [LIGHT_GRAY]{0} +text.sector.time=시간 : [LIGHT_GRAY]{0} +text.sector.deploy=시작 text.sector.resume=계속하기 text.sector.locked=[scarlet][[완료안됨] text.sector.unexplored=[accent][[탐색안됨] text.close=닫기 -text.save.playtime=플레이시간:{0} +text.save.playtime=플레이시간 : {0} text.editor.brush=브러쉬 text.credits.text=Created by [ROYAL]Anuken[] - [SKY]anukendev@gmail.com[]\n\n[GRAY](In case you can't tell, this text is currently unfinished.\nTranslators, don't edit it yet!) text.sector.gameover=이 구역을 공략하는데 실패했습니다. 다시 배치하시겠습니까? -text.sector.retry=다시할꺼임 +text.sector.retry=다시할끄임 text.wave.lasted=[accent]{0}[] 까지 버티셨습니다. + setting.fpscap.name=최대 FPS setting.fpscap.none=없음 setting.fpscap.text={0} FPS + block.command-center.name=명령 본부 -text.mission=목표:[LIGHT_GRAY] {0} + +text.mission=목표 : [LIGHT_GRAY] {0} text.mission.wave=[accent]{0}[]단계가 될때까지 생존하세요. text.mission.battle=적 본부를 파괴하세요. text.none=<없음> text.sector.corrupted=[orange]저장 파일에서 구역을 발견했으나 불러오지 못했습니다.\n새로 생성되었습니다. text.mission.complete=미션 성공! text.mission.complete.body=구역 {0},{1} 탐색 성공. -text.mission.resource=Obtain {0}:\n[accent]{1}/{2}[] -text.unit.health=[LIGHT_GRAY]체력:{0} -text.unit.speed=[LIGHT_GRAY]속도:{0} +text.mission.resource={0} 자원을 {1}개 모으세요. +text.unit.health=[LIGHT_GRAY]체력 : {0} +text.unit.speed=[LIGHT_GRAY]속도 : {0} + block.mass-driver.name=물질 이동기 block.blast-drill.name=고속 발열 드릴 -unit.drone.description=초기형 드론 유닛입니다. 기본적으로 코어에서 1대를 스폰합니다. 자동으로 아이템을 수집/채광하며 블럭들을 수리합니다. -unit.fabricator.description=고급 드론 유닛입니다. 자동으로 아이템과 수집/채광/블록들을 수리하며, 일반 드론보다 더 빠르게 작업할 수 있습니다. + unit.titan.name=타이탄 unit.titan.description=고급 지상 유닛입니다. 합금을 탄약으로 사용하며 지상과 공중 둘다 공격할 수 있습니다. -unit.monsoon.description=자폭 유닛입니다. 폭발 화합물 또는 피러레이트를 탄약으로 사용합니다. -unit.interceptor.description=빠르고, 공격하고 튀는 방식을 사용합니다. 납을 탄약으로 사용합니다. unit.dagger.name=디거 unit.dagger.description=기본 지상 유닛입니다. 스웜과 같이 쓰면 유용합니다. block.thermal-pump.name=지열 펌프 @@ -504,50 +503,55 @@ keybind.chat_history_next.name=다음 채팅기록 keybind.chat_scroll.name=채팅 스크롤 keybind.drop_unit.name=유닛 드롭 keybind.zoom_minimap.name=미니맵 확대 -content.mech.name=Mechs -item.copper.name=Copper -item.copper.description=A useful structure material. Used extensively in all types of blocks. -item.dense-alloy.name=Dense Alloy -item.dense-alloy.description=A tough alloy made with lead and copper. Used in advanced transportation blocks and high-tier drills. -mech.alpha-mech.name=Alpha +content.mech.name=기체 + +item.copper.name=구리 +item.copper.description=기본 블록 재료입니다. 모든 유형의 블록에서 광범위하게 사용됩니다. +item.dense-alloy.name=합금 +item.dense-alloy.description=납과 구리로 만든 튼튼한 합금. 고급 수송 블록이나 상위 티어 블록을 건설하는데 사용됩니다. + +mech.alpha-mech.name=알파 mech.alpha-mech.weapon=Heavy Repeater mech.alpha-mech.ability=Drone Swarm -mech.alpha-mech.description=The standard mech. Has decent speed and damage output; can create up to 3 drones for increased offensive capability. -mech.delta-mech.name=Delta +mech.alpha-mech.description=표준 기체. 적절한 속도와 공격력을 갖추고 있으며, 공격 능력을 높이기 위해 최대 3대의 드론을 만들 수 있습니다. +mech.delta-mech.name=델타 mech.delta-mech.weapon=Arc Generator mech.delta-mech.ability=Discharge -mech.delta-mech.description=A fast, lightly-armored mech made for hit-and-run attacks. Does little damage against structures, but can kill large groups of enemy units very quickly with its arc lightning weapons. +mech.delta-mech.description=치고 빠지는 공격을 위해 만든 빠르고 가벼운 기체. 구조물에는 거의 피해를 주지 않지만, 번개 무기를 사용하여 많은 적군을 매우 빠르게 죽일 수 있습니다. mech.tau-mech.name=Tau mech.tau-mech.weapon=Restruct Laser mech.tau-mech.ability=Repair Burst -mech.tau-mech.description=The support mech. Heals allied blocks by shooting at them. Can extinguish fires and heal allies in a radius with its repair ability. -mech.omega-mech.name=Omega +mech.tau-mech.description=지원형 기체. 총을 발사하여 건물을 치료하고 회복 능력 사용으로 화재를 진압하거나 반경 내 아군을 치유시킵니다. +mech.omega-mech.name=오메가 mech.omega-mech.weapon=Swarm Missiles mech.omega-mech.ability=Armored Configuration -mech.omega-mech.description=A bulky and well-armored mech, made for front-line assaults. Its armor ability can block up to 90% of incoming damage. +mech.omega-mech.description=전방 공격용으로 만든 부피가 크고 튼튼한 기체. 방어 능력은 최대 90%의 피해를 흡수할 수 있습니다. + mech.dart-ship.name=Dart mech.dart-ship.weapon=Repeater -mech.dart-ship.description=The standard ship. Reasonably fast and light, but has little offensive capability and low mining speed. +mech.dart-ship.description=표준 비행선. 빠르고 가볍지만 공격력이 거의 없고 채광 속도가 느립니다. mech.javelin-ship.name=Javelin -mech.javelin-ship.description=A hit-and-run strike ship. While initially slow, it can accelerate to great speeds and fly by enemy outposts, dealing large amounts of damage with its lightning ability and missiles. +mech.javelin-ship.description=치고 빠지는 공격을 위한 비행선. 처음에는 느리지만, 가속도가 붙어 엄청난 속도로 미사일 피해를 입힐 수 있으며, 번개 능력을 사용할 수 있습니다. mech.javelin-ship.weapon=Burst Missiles mech.javelin-ship.ability=Discharge Booster mech.trident-ship.name=Trident -mech.trident-ship.description=A heavy bomber. Reasonably well armored. +mech.trident-ship.description=대형 공중 폭격기. 당연하게도 엄청 단단합니다. mech.trident-ship.weapon=Bomb Bay mech.glaive-ship.name=Glaive -mech.glaive-ship.description=A large, well-armored gunship. Equipped with an incendiary repeater. Good acceleration and maximum speed. +mech.glaive-ship.description=크고 잘 무장된 총을 가진 비행선. 방화용 리피터가 장착되어 있으며, 가속도와 최대속도가 높습니다. mech.glaive-ship.weapon=Flame Repeater -text.mech.weapon=[LIGHT_GRAY]Weapon: {0} -text.mech.armor=[LIGHT_GRAY]Armor: {0} -text.mech.itemcapacity=[LIGHT_GRAY]Item Capacity: {0} -text.mech.minespeed=[LIGHT_GRAY]Mining Speed: {0} -text.mech.minepower=[LIGHT_GRAY]Mining Power: {0} -text.mech.ability=[LIGHT_GRAY]Ability: {0} -block.core.name=Core + +text.mech.weapon=[LIGHT_GRAY]무기 : {0} +text.mech.armor=[LIGHT_GRAY]방어 : {0} +text.mech.itemcapacity=[LIGHT_GRAY]아이템 수용 용량 : {0} +text.mech.minespeed=[LIGHT_GRAY]채광 속도 : {0} +text.mech.minepower=[LIGHT_GRAY]채광 레벨 : {0} +text.mech.ability=[LIGHT_GRAY]능력 : {0} + +block.core.name=코어 block.metalfloor.name=Metal Floor -block.copper-wall.name=Copper Wall -block.copper-wall-large.name=Large Copper Wall +block.copper-wall.name=구리벽 +block.copper-wall-large.name=큰 구리벽 block.phase-wall.name=Phase Wall block.phase-wall-large.name=Large Phase Wall block.mechanical-drill.name=Mechanical Drill @@ -556,80 +560,85 @@ block.thorium-reactor.name=Thorium Reactor block.alloy-smelter.name=Alloy Smtler block.mend-projector.name=Mend Projector unit.alpha-drone.name=Alpha Drone -text.construction.desktop=Desktop controls have been changed.\nTo deselect a block or stop building, [accent]use space[]. -keybind.press=Press a key... -keybind.press.axis=Press an axis or key... -keybind.deselect.name=Deselect +text.construction.desktop=PC 에서의 조작 방법이 변경되었습니다.\n블록 선택을 해제하거나 건설을 중지하려면 [accent]스페이스 바[]를 누르세요. +keybind.press=키를 누르세요... +keybind.press.axis=축 또는 키를 누르세요... +keybind.deselect.name=선택해제 block.surge-wall.name=Surge Wall block.surge-wall-large.name=Large Surge Wall -block.cyclone.name=Cyclone -block.fuse.name=Fuse -text.confirmkick=Are you sure you want to kick this player? -text.settings.cleardata=Clear Game Data... -text.settings.clear.confirm=Are you sure you want to clear this data?\nWhat is done cannot be undone! -text.settings.clearall.confirm=[scarlet]WARNING![]\nThis will clear all data, including saves, maps, unlocks and keybinds.\nOnce you press 'ok' the game will wipe all data and automatically exit. -text.settings.clearsectors=Clear Sectors -text.settings.clearunlocks=Clear Unlocks -text.settings.clearall=Clear All +block.cyclone.name=사이클론 +block.fuse.name=퓨즈 +text.confirmkick=정말로 이 플레이어를 추방시키겠습니까? +text.settings.cleardata=게임 데이터 초기화... +text.settings.clear.confirm=정말로 초기화 하겠습니까?\n이 작업을 되돌릴 수 없습니다! +text.settings.clearall.confirm=[scarlet]경고![]\n이 작업은 저장된 맵, 맵파일, 잠금 해제된 목록과 키 매핑, 그리고 모든 데이터를 삭제합니다.\n확인 버튼을 다시 눌러 모든 데이터를 삭제하고 게임에서 나갑니다. +text.settings.clearsectors=구역 초기화 +text.settings.clearunlocks=잠금 해제 초기화 +text.settings.clearall=모두 초기화 block.shock-mine.name=Shock Mine block.overdrive-projector.name=Overdrive Projector -text.blocks.powerdamage=Power/Damage -mode.custom.warning=Note that blocks cannot be used in custom games until they are unlocked in sectors.\n\n[LIGHT_GRAY]If you have not unlocked any blocks, none will appear. -content.unit.name=Units +text.blocks.powerdamage=전력/데미지 +mode.custom.warning=[scarlet]서버에서 잠금해제한 블록은 저장되지 않습니다.[]\n\n구역을 플레이 하여 잠금해제하세요. +content.unit.name=유닛 block.force-projector.name=Force Projector block.arc.name=Arc block.rtg-generator.name=RTG Generator block.spectre.name=Spectre block.meltdown.name=Meltdown -text.mission.info=Mission Info -text.mission.wave.enemies=Survive[accent] {0}/{1} []waves\n{2} Enemies -text.mission.wave.enemy=Survive[accent] {0}/{1} []waves\n{2} Enemy -text.mission.wave.menu=Survive[accent] {0} []waves -text.mission.resource.menu=Obtain {0} x{1} -text.mission.block=Create {0} -text.mission.unit=Create {0} Unit -text.mission.linknode=Link Power Node -text.mission.display=[accent]Mission:\n[LIGHT_GRAY]{0} -text.hostserver.mobile=Host\nGame -setting.difficulty.training=training -block.dense-alloy-wall.name=Dense Alloy Wall -block.dense-alloy-wall-large.name=Large Dense Alloy Wall -block.dart-ship-pad.name=Dart Ship Pad -block.delta-mech-pad.name=Delta Mech Pad -block.javelin-ship-pad.name=Javelin Ship Pad -block.trident-ship-pad.name=Trident Ship Pad -block.glaive-ship-pad.name=Glaive Ship Pad -block.omega-mech-pad.name=Omega Mech Pad -block.tau-mech-pad.name=Tau Mech Pad -block.spirit-factory.name=Spirit Drone Factory -block.phantom-factory.name=Phantom Drone Factory + +text.mission.info=미션 정보 +text.mission.wave.enemies=[accent] {0}/{1} []단계동안 생존하세요.\n{2}마리 남음 +text.mission.wave.enemy=[accent] {0}/{1} []단계동안 생존하세요.\n{2}마리 남음 +text.mission.wave.menu=[accent] {0} []단계 +text.mission.resource.menu={0} {1}개 수집 +text.mission.block={0}를 만드세요. +text.mission.unit={0}유닛을 만드세요. +text.mission.linknode=전력 노드를 연결하세요. +text.mission.display=[accent]미션 : \n[LIGHT_GRAY]{0} +text.hostserver.mobile=게임\n호스트 + +setting.difficulty.training=훈련 + +block.dense-alloy-wall.name=합금 벽 +block.dense-alloy-wall-large.name=큰 합금 벽 +block.dart-ship-pad.name=다트 비행선 패드 +block.delta-mech-pad.name=델타 기체 패드 +block.javelin-ship-pad.name=자바린 비행선 패드 +block.trident-ship-pad.name=삼지창 비행선 패드 +block.glaive-ship-pad.name=글레브 비행선 패드 +block.omega-mech-pad.name=오메가 기체 패드 +block.tau-mech-pad.name=Tau 기체 패드 +block.spirit-factory.name=Spirit 드론 공장 +block.phantom-factory.name=팬텀 드론 공장 block.wraith-factory.name=Wraith Fighter Factory block.ghoul-factory.name=Ghoul Bomber Factory -block.dagger-factory.name=Dagger Mech Factory -block.titan-factory.name=Titan Mech Factory +block.dagger-factory.name=디거 기체 공장 +block.titan-factory.name=타이탄 기체 공장 block.revenant-factory.name=Revenant Fighter Factory -unit.spirit.name=Spirit Drone -unit.spirit.description=The starter drone unit. Spawns in the core by default. Automatically mines ores, collects items and repairs blocks. -unit.phantom.name=Phantom Drone -unit.phantom.description=An advanced drone unit. Automatically mines ores, collects items and repairs blocks. Significantly more effective than a drone. + +unit.spirit.name=스피릿 드론 +unit.spirit.description=기본 드론 유닛. 기본적으로 코어에서 1개가 스폰됩니다. 자동으로 채광하며 아이템을 수집하고, 블록을 수리합니다. +unit.phantom.name=팬텀 드론 +unit.phantom.description=첨단 드론 유닛. 광석을 자동으로 채광하며, 아이템을 수집하고 블록을 수리합니다. 일반 드론보다 훨씬 효과적입니다. unit.ghoul.name=Ghoul Bomber unit.ghoul.description=A heavy carpet bomber. Uses blast compound or pyratite as ammo. unit.wraith.name=Wraith Fighter -unit.wraith.description=A fast, hit-and-run interceptor unit. +unit.wraith.description=빠르고, 치고 빠지는 공격방식을 사용합니다. unit.fortress.name=Fortress -unit.fortress.description=A heavy artillery ground unit. +unit.fortress.description=중포 지상 부대 유닛. unit.revenant.name=Revenant unit.revenant.description=A heavy laser platform. -tutorial.begin=Your mission here is to eradicate the[LIGHT_GRAY] enemy[].\n\nBegin by[accent] mining copper[]. Tap a copper ore vein near your core to do this. -tutorial.drill=Mining manually is inefficient.\n[accent]Drills []can mine automatically.\nPlace one on a copper vein. -tutorial.conveyor=[accent]Conveyors[] are used to transport items to the core.\nMake a line of conveyors from the drill to the core. -tutorial.morecopper=More copper is required.\n\nEither mine it manually, or place more drills. -tutorial.turret=Defensive structures must be built to repel the[LIGHT_GRAY] enemy[].\nBuild a duo turret near your base. -tutorial.drillturret=Duo turrets require[accent] copper ammo []to shoot.\nPlace a drill next to the turret to supply it with mined copper. -tutorial.waves=The[LIGHT_GRAY] enemy[] approaches.\n\nDefend your core for 2 waves. Build more turrets. -tutorial.lead=More ores are available. Explore and mine[accent] lead[].\n\nDrag from your unit to the core to transfer resources. -tutorial.smelter=Copper and lead are weak metals.\nSuperior[accent] Dense Alloy[] can be created in a smelter.\n\nBuild one. -tutorial.densealloy=The smelter will now produce alloy.\nGet some.\nImprove the production if necessary. + +tutorial.begin=플레이어의 임무는 [LIGHT_GRAY]적군[]을 제거하는 것입니다.\n\n[accent]구리를 채광[]하는 것으로 시작합니다. 이것을 하기 위해 플레이어의 중심부 근처에 있는 구리 광맥을 누르세요. +tutorial.drill=수동으로 채광하는 것은 비효율 적입니다.\n[accent]드릴[]은 자동으로 채광 작업을 합니다.\n구리 광맥에 표시된 영역에 드릴을 하나를 놓으세요. +tutorial.conveyor=[accent]컨베이어[]를 사용하여 아이템을 코어로 운반합니다.\n드릴에서 코어까지 컨베이어 라인을 만드세요. +tutorial.morecopper=더 많은 구리가 필요합니다.\n\n수동으로 채광하거나, 드릴을 더 설치하세요. +tutorial.turret=방어 구조물은 [LIGHT_GRAY]적[]을 물리치기 위해 반드시 필요합니다.\n기지 근처에 듀오 터렛을 설치하세요. +tutorial.drillturret=듀오 터렛이 작동하기 위해서는[accent] 구리 탄약 []을 필요로 합니다.\n터렛 옆에 드릴을 설치하여 구리를 공급하세요. +tutorial.waves=[LIGHT_GRAY]적[]이 접근합니다.\n\n2단계 동안 코어를 보호하고 더 많은 터렛을 만드세요. +tutorial.lead=더 많은 광석을 이용할 수 있습니다. [accent]납[]을 찾아 탐색하세요.\n\n아이템을 코어로 전송할려면 플레이어 기체 또는 비행기에서 코어로 드래그 하세요. +tutorial.smelter=구리와 납은 약한 금속입니다.\n[accent]합금[]은 제련소에서 만들 수 있습니다.\n\n하나 만드세요. +tutorial.densealloy=이 제련소는 이제 합금을 생산할 것입니다.\n몇개 더 생산하세요.\n필요한 경우 더 만드세요. tutorial.siliconsmelter=The core will now create a[accent] spirit drone[] for mining and repairing blocks.\n\nFactories for other units can be created with [accent] silicon.\nMake a silicon smelter. tutorial.silicondrill=Silicon requires[accent] coal[] and[accent] sand[].\nStart by making drills. tutorial.generator=This technology requires power.\nCreate a[accent] combustion generator[] for it. @@ -638,37 +647,41 @@ tutorial.node=Power requires transport.\nCreate a[accent] power node[] next to y tutorial.nodelink=Power can be transferred through contacting power blocks and generators, or by linked power nodes.\n\nLink power by tapping the node and selecting the generator and silicon smelter. tutorial.silicon=Silicon is being produced. Get some.\n\nImproving the production system is advised. tutorial.daggerfactory=Construct a[accent] dagger mech factory.[]\n\nThis will be used to create attack mechs. -tutorial.router=Factories need resources to function.\nCreate a router to split conveyor resources. -tutorial.dagger=Link power nodes to the factory.\nOnce requirements are met, a mech will be created.\n\nCreate more drills, generators and conveyors as necessary. -tutorial.battle=The[LIGHT_GRAY] enemy[] has revealed their core.\nDestroy it with your unit and dagger mechs. -text.missions=Missions:[LIGHT_GRAY] {0} -text.mission.command=Send Command {0} To Units -text.mission.mech=Switch to mech[accent] {0}[] -text.mission.create=Create[accent] {0}[] -text.wave.enemies=[LIGHT_GRAY]{0} Enemies Remaining -text.wave.enemy=[LIGHT_GRAY]{0} Enemy Remaining -setting.autotarget.name=Auto-Target -command.attack=Attack -command.retreat=Retreat -command.patrol=Patrol -block.spawn.name=Enemy Spawn +tutorial.router=공장을 작동시키기 위해 자원이 필요합니다.\n컨베이어에 운반되고 있는 자원을 분할할 분배기를 만드세요. +tutorial.dagger=전력 노드를 공장에 연결하세요.\n일단 요구 사항이 충족되면 기체 생산을 시작합니다.\n\n필요에 따라 드릴 및 발전기, 컨베이어를 더 많이 만들 수 있습니다. +tutorial.battle=[LIGHT_GRAY]적[]의 코어가 드러났습니다.\n당신의 부대와 디거를 사용하여 파괴하세요. + +text.missions=목표 : [LIGHT_GRAY] {0} +text.mission.command=유닛에게 {0} 명령을 보내세요 +text.mission.mech=[accent] {0}[] 기체로 바꾸세요. +text.mission.create=[accent] {0}[] 를 만드세요. +text.wave.enemies=[LIGHT_GRAY]{0} 마리 남았음 +text.wave.enemy=[LIGHT_GRAY]{0} 마리 남음 + +setting.autotarget.name=자동 조준 + +command.attack=공격 +command.retreat=후퇴 +command.patrol=순찰 + +block.spawn.name=적 스폰지점 block.fortress-factory.name=Fortress Mech Factory -text.gameover.pvp=The[accent] {0}[] team is victorious! -text.sector.abandon=Abandon -text.sector.abandon.confirm=Are you sure you want to abandon all progress at this sector?\nThis cannot be undone! -text.mission.main=Main Mission:[LIGHT_GRAY] {0} -text.waiting.players=Waiting for players... -text.map.nospawn.pvp=This map does not have any enemy cores for player to spawn into! Add[SCARLET] red[] cores to this map in the editor. -text.blocks.basepowergeneration=Base Power Generation -text.blocks.liquidoutputspeed=Liquid Output Speed -mode.custom.warning.read=Just to make sure you've read it:\n[scarlet]UNLOCKS IN CUSTOM GAMES DO NOT CARRY OVER TO SECTORS OR OTHER MODES!\n\n[LIGHT_GRAY](I wish this wasn't necessary, but apparently it is) +text.gameover.pvp=[accent]{0}[] 팀이 승리했습니다! +text.sector.abandon=초기화 +text.sector.abandon.confirm=정말로 이 구역의 모든 진행상활을 초기화 하겠습니까?\n이 작업은 되돌릴 수 없습니다! +text.waiting.players=다른 플레이어를 기다리는 중.. +text.map.nospawn.pvp=이 맵에는 적팀 코어가 없습니다! 에디터에서 [scarlet]빨간팀[] 코어를 추가하세요. mode.pvp.name=PvP -mode.pvp.description=fight against other players locally. -block.alpha-mech-pad.name=Alpha Mech Pad -block.container.name=Container -team.blue.name=blue -team.red.name=red -team.orange.name=orange -team.none.name=gray -team.green.name=green -team.purple.name=purple +mode.pvp.description=몹이 아닌 실제 플레이어와 PvP를 합니다. +block.container.name=컨테이너 +team.blue.name=블루팀 +team.red.name=레드팀 +team.orange.name=오렌지팀 +team.none.name=공기팀 +team.green.name=그린팀 +team.purple.name=보라색팀 +block.alpha-mech-pad.name=알파 기체 패드 +text.blocks.basepowergeneration=기지 전력 생성기 +text.blocks.liquidoutputspeed=액체 출력속도 +text.unit.liquidunits=액체 +mode.custom.warning.read=꼭 읽어보시길 바랍니다 :\n[scarlet]커스텀 게임에서 잠금해제한 블록은 구역 플레이나 다른 모드에서 적용되지 않습니다!\n\n[LIGHT_GRAY](이게 필요하지 않았으면 좋겠는데) From b1cda57174fc7d82fbd34a9573be2f7cb9a4ea1e Mon Sep 17 00:00:00 2001 From: Anuken Date: Sat, 20 Oct 2018 11:25:58 -0400 Subject: [PATCH 07/11] Massively improved thread safety --- build.gradle | 2 +- core/src/io/anuke/mindustry/core/Control.java | 5 -- core/src/io/anuke/mindustry/core/Logic.java | 4 ++ .../io/anuke/mindustry/entities/Units.java | 47 ++++++++++++++----- .../anuke/mindustry/input/InputHandler.java | 9 +--- .../mindustry/ui/dialogs/AdminsDialog.java | 9 +++- .../ui/fragments/PlayerListFragment.java | 6 +-- .../io/anuke/kryonet/DefaultThreadImpl.java | 18 ++++++- 8 files changed, 69 insertions(+), 31 deletions(-) diff --git a/build.gradle b/build.gradle index 1a06394775..b417e31a49 100644 --- a/build.gradle +++ b/build.gradle @@ -27,7 +27,7 @@ allprojects { appName = 'Mindustry' gdxVersion = '1.9.8' roboVMVersion = '2.3.0' - uCoreVersion = '03c4093f724e63069e097393991592db308728e0' + uCoreVersion = '89250a4ec499609329c52e7742a251b9f4c6bd5b' getVersionString = { String buildVersion = getBuildVersion() diff --git a/core/src/io/anuke/mindustry/core/Control.java b/core/src/io/anuke/mindustry/core/Control.java index f284d772d9..ff30443419 100644 --- a/core/src/io/anuke/mindustry/core/Control.java +++ b/core/src/io/anuke/mindustry/core/Control.java @@ -23,7 +23,6 @@ import io.anuke.mindustry.type.ItemStack; import io.anuke.mindustry.type.Recipe; import io.anuke.mindustry.ui.dialogs.FloatingDialog; import io.anuke.ucore.core.*; -import io.anuke.ucore.entities.Entities; import io.anuke.ucore.entities.EntityQuery; import io.anuke.ucore.modules.Module; import io.anuke.ucore.util.Atlas; @@ -382,10 +381,6 @@ public class Control extends Module{ } } - if(!state.is(State.paused) || Net.active()){ - Entities.update(effectGroup); - Entities.update(groundEffectGroup); - } }else{ if(!state.is(State.paused) || Net.active()){ Timers.update(); diff --git a/core/src/io/anuke/mindustry/core/Logic.java b/core/src/io/anuke/mindustry/core/Logic.java index 81b610333e..0f06909d24 100644 --- a/core/src/io/anuke/mindustry/core/Logic.java +++ b/core/src/io/anuke/mindustry/core/Logic.java @@ -147,6 +147,10 @@ public class Logic extends Module{ if(!Entities.defaultGroup().isEmpty()) throw new RuntimeException("Do not add anything to the default group!"); + if(!headless){ + Entities.update(effectGroup); + Entities.update(groundEffectGroup); + } for(EntityGroup group : unitGroups){ Entities.update(group); diff --git a/core/src/io/anuke/mindustry/entities/Units.java b/core/src/io/anuke/mindustry/entities/Units.java index aceb4f356f..06c6e42fa9 100644 --- a/core/src/io/anuke/mindustry/entities/Units.java +++ b/core/src/io/anuke/mindustry/entities/Units.java @@ -11,6 +11,7 @@ import io.anuke.ucore.entities.EntityGroup; import io.anuke.ucore.entities.EntityQuery; import io.anuke.ucore.function.Consumer; import io.anuke.ucore.function.Predicate; +import io.anuke.ucore.util.Threads; import io.anuke.ucore.util.EnumSet; import static io.anuke.mindustry.Vars.*; @@ -20,10 +21,11 @@ import static io.anuke.mindustry.Vars.*; */ public class Units{ private static Rectangle rect = new Rectangle(); + private static Rectangle rectGraphics = new Rectangle(); private static Rectangle hitrect = new Rectangle(); private static Unit result; private static float cdist; - private static boolean boolResult; + private static boolean boolResult, boolResultGraphics; /** * Validates a target. @@ -63,22 +65,43 @@ public class Units{ return anyEntities(rect); } + /**Can be called from any thread.*/ public static boolean anyEntities(Rectangle rect){ + if(Threads.isLogic()){ + boolResult = false; - boolResult = false; + Units.getNearby(rect, unit -> { + if(boolResult) return; + if(!unit.isFlying()){ + unit.getHitbox(hitrect); - Units.getNearby(rect, unit -> { - if(boolResult) return; - if(!unit.isFlying()){ - unit.getHitbox(hitrect); - - if(hitrect.overlaps(rect)){ - boolResult = true; + if(hitrect.overlaps(rect)){ + boolResult = true; + } } - } - }); + }); - return boolResult; + return boolResult; + }else{ + for(EntityGroup g : unitGroups){ + g.forEach(u -> { + u.getHitbox(rectGraphics); + if(rectGraphics.overlaps(rect)){ + boolResultGraphics = true; + } + }); + if(boolResultGraphics) return true; + } + + playerGroup.forEach(u -> { + u.getHitbox(rectGraphics); + if(rectGraphics.overlaps(rect)){ + boolResultGraphics = true; + } + }); + + return boolResultGraphics; + } } /**Returns whether there are any entities on this tile, with the hitbox expanded.*/ diff --git a/core/src/io/anuke/mindustry/input/InputHandler.java b/core/src/io/anuke/mindustry/input/InputHandler.java index efac9241b6..eedcb45878 100644 --- a/core/src/io/anuke/mindustry/input/InputHandler.java +++ b/core/src/io/anuke/mindustry/input/InputHandler.java @@ -254,7 +254,6 @@ public abstract class InputHandler extends InputAdapter{ && tile.floor().drops != null && tile.floor().drops.item.hardness <= player.mech.drillPower && !tile.floor().playerUnmineable && player.inventory.canAcceptItem(tile.floor().drops.item) - && Units.getClosestEnemy(player.getTeam(), tile.worldx(), tile.worldy(), 40f, e -> true) == null //don't being mining when an enemy is near && tile.block() == Blocks.air && player.distanceTo(tile.worldx(), tile.worldy()) <= Player.mineDistance; } @@ -330,12 +329,8 @@ public abstract class InputHandler extends InputAdapter{ public boolean validPlace(int x, int y, Block type, int rotation){ for(Tile tile : state.teams.get(player.getTeam()).cores){ if(tile.distanceTo(x * tilesize, y * tilesize) < coreBuildRange){ - //TODO terrible hack - //this might actually screw things up on the logic thread. - try{ - return Build.validPlace(player.getTeam(), x, y, type, rotation) && - Vector2.dst(player.x, player.y, x * tilesize, y * tilesize) < Player.placeDistance; - }catch(Exception e){return false;} + return Build.validPlace(player.getTeam(), x, y, type, rotation) && + Vector2.dst(player.x, player.y, x * tilesize, y * tilesize) < Player.placeDistance; } } diff --git a/core/src/io/anuke/mindustry/ui/dialogs/AdminsDialog.java b/core/src/io/anuke/mindustry/ui/dialogs/AdminsDialog.java index dbfd1273f6..46f533c286 100644 --- a/core/src/io/anuke/mindustry/ui/dialogs/AdminsDialog.java +++ b/core/src/io/anuke/mindustry/ui/dialogs/AdminsDialog.java @@ -1,6 +1,5 @@ package io.anuke.mindustry.ui.dialogs; -import io.anuke.mindustry.entities.Player; import io.anuke.mindustry.net.Administration.PlayerInfo; import io.anuke.ucore.scene.ui.ScrollPane; import io.anuke.ucore.scene.ui.layout.Table; @@ -43,12 +42,18 @@ public class AdminsDialog extends FloatingDialog{ res.addImageButton("icon-cancel", 14 * 3, () -> { ui.showConfirm("$text.confirm", "$text.confirmunadmin", () -> { netServer.admins.unAdminPlayer(info.id); + playerGroup.forEach(player -> { + if(player.uuid.equals(info.id)){ + player.isAdmin = false; + } + }); + /* for(Player player : playerGroup.all()){ if(player.con != null){ player.isAdmin = false; break; } - } + }*/ setup(); }); }).size(h).pad(-14f); diff --git a/core/src/io/anuke/mindustry/ui/fragments/PlayerListFragment.java b/core/src/io/anuke/mindustry/ui/fragments/PlayerListFragment.java index a2e81930e1..e096bd519a 100644 --- a/core/src/io/anuke/mindustry/ui/fragments/PlayerListFragment.java +++ b/core/src/io/anuke/mindustry/ui/fragments/PlayerListFragment.java @@ -66,10 +66,10 @@ public class PlayerListFragment extends Fragment{ float h = 74f; - for(Player player : playerGroup.all()){ + playerGroup.forEach(player -> { NetConnection connection = gwt ? null : player.con; - if(connection == null && Net.server() && !player.isLocal) continue; + if(connection == null && Net.server() && !player.isLocal) return; Table button = new Table("button"); button.left(); @@ -134,7 +134,7 @@ public class PlayerListFragment extends Fragment{ content.add(button).padBottom(-6).width(350f).maxHeight(h + 14); content.row(); - } + }); content.marginBottom(5); } diff --git a/kryonet/src/io/anuke/kryonet/DefaultThreadImpl.java b/kryonet/src/io/anuke/kryonet/DefaultThreadImpl.java index ff2d80c4b2..9a50a4f51e 100644 --- a/kryonet/src/io/anuke/kryonet/DefaultThreadImpl.java +++ b/kryonet/src/io/anuke/kryonet/DefaultThreadImpl.java @@ -1,11 +1,27 @@ package io.anuke.kryonet; import io.anuke.mindustry.core.ThreadHandler.ThreadProvider; +import io.anuke.ucore.util.Threads; +import io.anuke.ucore.util.Threads.ThreadInfoProvider; import io.anuke.ucore.util.Log; -public class DefaultThreadImpl implements ThreadProvider { +public class DefaultThreadImpl implements ThreadProvider, ThreadInfoProvider{ private Thread thread; + public DefaultThreadImpl(){ + Threads.setThreadInfoProvider(this); + } + + @Override + public boolean isOnLogicThread(){ + return thread == null || isOnThread(); + } + + @Override + public boolean isOnGraphicsThread(){ + return thread == null || !isOnThread(); + } + @Override public boolean isOnThread() { return Thread.currentThread() == thread; From 6e3c600a49f3fd928664901ebedb4a2df7592dc0 Mon Sep 17 00:00:00 2001 From: Anuken Date: Sat, 20 Oct 2018 11:36:05 -0400 Subject: [PATCH 08/11] Crash fix --- core/src/io/anuke/mindustry/entities/Damage.java | 2 +- core/src/io/anuke/mindustry/entities/Units.java | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/core/src/io/anuke/mindustry/entities/Damage.java b/core/src/io/anuke/mindustry/entities/Damage.java index 579dddc3df..23f00d7e10 100644 --- a/core/src/io/anuke/mindustry/entities/Damage.java +++ b/core/src/io/anuke/mindustry/entities/Damage.java @@ -47,7 +47,7 @@ public class Damage{ for(int i = 0; i < waves; i++){ int f = i; Timers.run(i * 2f, () -> { - Damage.damage(x, y, Mathf.clamp(radius + explosiveness, 0, 50f) * ((f + 1f) / waves), explosiveness / 2f); + threads.run(() -> Damage.damage(x, y, Mathf.clamp(radius + explosiveness, 0, 50f) * ((f + 1f) / waves), explosiveness / 2f)); Effects.effect(ExplosionFx.blockExplosionSmoke, x + Mathf.range(radius), y + Mathf.range(radius)); }); } diff --git a/core/src/io/anuke/mindustry/entities/Units.java b/core/src/io/anuke/mindustry/entities/Units.java index 06c6e42fa9..2ef46be9c7 100644 --- a/core/src/io/anuke/mindustry/entities/Units.java +++ b/core/src/io/anuke/mindustry/entities/Units.java @@ -83,6 +83,8 @@ public class Units{ return boolResult; }else{ + boolResultGraphics = false; + for(EntityGroup g : unitGroups){ g.forEach(u -> { u.getHitbox(rectGraphics); From 83a5c3af8a691486587c9339ff1ff56c1bb63889 Mon Sep 17 00:00:00 2001 From: Anuken Date: Sat, 20 Oct 2018 11:41:10 -0400 Subject: [PATCH 09/11] Updated uCore with new threading changes --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index ded168978b..7c1f13efc6 100644 --- a/build.gradle +++ b/build.gradle @@ -27,7 +27,7 @@ allprojects { appName = 'Mindustry' gdxVersion = '1.9.8' roboVMVersion = '2.3.0' - uCoreVersion = '4d5571b3efc30975e0c073f87fae9ff5cb2ae4d7' + uCoreVersion = '97b03d5408d0cc836258f0af0f0a12dcb14a5ede' getVersionString = { String buildVersion = getBuildVersion() From 62bb8bce1c5911252867d6792f18b39d10dfbf79 Mon Sep 17 00:00:00 2001 From: Anuken Date: Sat, 20 Oct 2018 11:44:19 -0400 Subject: [PATCH 10/11] Added missing imports --- core/src/io/anuke/mindustry/core/Control.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/core/src/io/anuke/mindustry/core/Control.java b/core/src/io/anuke/mindustry/core/Control.java index aff70ff938..886cd28599 100644 --- a/core/src/io/anuke/mindustry/core/Control.java +++ b/core/src/io/anuke/mindustry/core/Control.java @@ -27,8 +27,12 @@ import io.anuke.ucore.core.*; import io.anuke.ucore.entities.EntityQuery; import io.anuke.ucore.modules.Module; import io.anuke.ucore.util.Atlas; +import io.anuke.ucore.util.Bundles; +import io.anuke.ucore.util.Strings; import io.anuke.ucore.util.Timer; +import java.io.IOException; + import static io.anuke.mindustry.Vars.*; /** From ef5478279b9387da51b3328a37d4a09a3d56eacc Mon Sep 17 00:00:00 2001 From: Anuken Date: Sat, 20 Oct 2018 11:48:59 -0400 Subject: [PATCH 11/11] Fixed 2 crashes --- core/src/io/anuke/mindustry/ai/Pathfinder.java | 3 ++- core/src/io/anuke/mindustry/game/Teams.java | 2 -- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/core/src/io/anuke/mindustry/ai/Pathfinder.java b/core/src/io/anuke/mindustry/ai/Pathfinder.java index b47040647f..7f9c77970c 100644 --- a/core/src/io/anuke/mindustry/ai/Pathfinder.java +++ b/core/src/io/anuke/mindustry/ai/Pathfinder.java @@ -14,6 +14,7 @@ import io.anuke.mindustry.world.meta.BlockFlag; import io.anuke.ucore.core.Events; import io.anuke.ucore.core.Timers; import io.anuke.ucore.util.Geometry; +import io.anuke.ucore.util.Structs; import static io.anuke.mindustry.Vars.state; import static io.anuke.mindustry.Vars.world; @@ -82,7 +83,7 @@ public class Pathfinder{ } public float getValueforTeam(Team team, int x, int y){ - return paths == null || team.ordinal() >= paths.length ? 0 : paths[team.ordinal()].weights[x][y]; + return paths == null || team.ordinal() >= paths.length ? 0 : Structs.inBounds(x, y, paths[team.ordinal()].weights) ? paths[team.ordinal()].weights[x][y] : 0; } private boolean passable(Tile tile, Team team){ diff --git a/core/src/io/anuke/mindustry/game/Teams.java b/core/src/io/anuke/mindustry/game/Teams.java index 1a3683d3a9..7b004b37d2 100644 --- a/core/src/io/anuke/mindustry/game/Teams.java +++ b/core/src/io/anuke/mindustry/game/Teams.java @@ -19,8 +19,6 @@ public class Teams{ * @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){ - if(map[team.ordinal()] != null) throw new RuntimeException("Can't define team information twice!"); - map[team.ordinal()] = new TeamData(team, EnumSet.of(enemies)); }