diff --git a/core/assets/scripts/base.js b/core/assets/scripts/base.js index 9b3fb5dcb4..a83a66c728 100755 --- a/core/assets/scripts/base.js +++ b/core/assets/scripts/base.js @@ -16,4 +16,5 @@ const boolp = method => new Boolp(){get: method} const cons = method => new Cons(){get: method} const prov = method => new Prov(){get: method} const newEffect = (lifetime, renderer) => new Effects.Effect(lifetime, new Effects.EffectRenderer({render: renderer})) -const Calls = Packages.io.anuke.mindustry.gen.Call \ No newline at end of file +Call = Packages.io.anuke.mindustry.gen.Call +const Calls = Call //backwards compat \ No newline at end of file diff --git a/core/assets/scripts/global.js b/core/assets/scripts/global.js index badba9d273..862ded3759 100755 --- a/core/assets/scripts/global.js +++ b/core/assets/scripts/global.js @@ -18,7 +18,8 @@ const boolp = method => new Boolp(){get: method} const cons = method => new Cons(){get: method} const prov = method => new Prov(){get: method} const newEffect = (lifetime, renderer) => new Effects.Effect(lifetime, new Effects.EffectRenderer({render: renderer})) -const Calls = Packages.io.anuke.mindustry.gen.Call +Call = Packages.io.anuke.mindustry.gen.Call +const Calls = Call //backwards compat importPackage(Packages.arc) importPackage(Packages.arc.func) importPackage(Packages.arc.graphics) diff --git a/core/src/mindustry/Vars.java b/core/src/mindustry/Vars.java index 3d034b1d6f..dfefeb2a68 100644 --- a/core/src/mindustry/Vars.java +++ b/core/src/mindustry/Vars.java @@ -61,10 +61,6 @@ public class Vars implements Loadable{ public static final Array defaultServers = Array.with(); /** maximum distance between mine and core that supports automatic transferring */ public static final float mineTransferRange = 220f; - /** team of the player by default */ - public static final Team defaultTeam = Team.sharded; - /** team of the enemy in waves/sectors */ - public static final Team waveTeam = Team.crux; /** whether to enable editing of units in the editor */ public static final boolean enableUnitEditing = false; /** max chat message length */ @@ -128,9 +124,9 @@ public class Vars implements Loadable{ public static Fi dataDirectory; /** data subdirectory used for screenshots */ public static Fi screenshotDirectory; - /** data subdirectory used for custom mmaps */ + /** data subdirectory used for custom maps */ public static Fi customMapDirectory; - /** data subdirectory used for custom mmaps */ + /** data subdirectory used for custom map previews */ public static Fi mapPreviewDirectory; /** tmp subdirectory for map conversion */ public static Fi tmpDirectory; @@ -184,7 +180,7 @@ public class Vars implements Loadable{ public static EntityGroup shieldGroup; public static EntityGroup puddleGroup; public static EntityGroup fireGroup; - public static EntityGroup[] unitGroups; + public static EntityGroup unitGroup; public static Player player; @@ -239,11 +235,7 @@ public class Vars implements Loadable{ puddleGroup = entities.add(Puddle.class).enableMapping(); shieldGroup = entities.add(ShieldEntity.class, false); fireGroup = entities.add(Fire.class).enableMapping(); - unitGroups = new EntityGroup[Team.all.length]; - - for(Team team : Team.all){ - unitGroups[team.ordinal()] = entities.add(BaseUnit.class).enableMapping(); - } + unitGroup = entities.add(BaseUnit.class).enableMapping(); for(EntityGroup group : entities.all()){ group.setRemoveListener(entity -> { diff --git a/core/src/mindustry/ai/BlockIndexer.java b/core/src/mindustry/ai/BlockIndexer.java index e64ad48064..b010562595 100644 --- a/core/src/mindustry/ai/BlockIndexer.java +++ b/core/src/mindustry/ai/BlockIndexer.java @@ -1,10 +1,10 @@ package mindustry.ai; import arc.*; -import arc.struct.*; import arc.func.*; import arc.math.*; import arc.math.geom.*; +import arc.struct.*; import mindustry.content.*; import mindustry.entities.type.*; import mindustry.game.EventType.*; @@ -28,15 +28,15 @@ public class BlockIndexer{ private final ObjectSet itemSet = new ObjectSet<>(); /** Stores all ore quadtrants on the map. */ private ObjectMap> ores = new ObjectMap<>(); - /** Tags all quadrants. */ + /** Maps each team ID to a quarant. A quadrant is a grid of bits, where each bit is set if and only if there is a block of that team in that quadrant. */ private GridBits[] structQuadrants; /** Stores all damaged tile entities by team. */ - private ObjectSet[] damagedTiles = new ObjectSet[Team.all.length]; + private ObjectSet[] damagedTiles = new ObjectSet[Team.all().length]; /**All ores available on this map.*/ private ObjectSet allOres = new ObjectSet<>(); /** Maps teams to a map of flagged tiles by type. */ - private ObjectSet[][] flagMap = new ObjectSet[Team.all.length][BlockFlag.all.length]; + private ObjectSet[][] flagMap = new ObjectSet[Team.all().length][BlockFlag.all.length]; /** Maps tile positions to their last known tile index data. */ private IntMap typeMap = new IntMap<>(); /** Empty set used for returning. */ @@ -59,8 +59,8 @@ public class BlockIndexer{ Events.on(WorldLoadEvent.class, event -> { scanOres.clear(); scanOres.addAll(Item.getAllOres()); - damagedTiles = new ObjectSet[Team.all.length]; - flagMap = new ObjectSet[Team.all.length][BlockFlag.all.length]; + damagedTiles = new ObjectSet[Team.all().length]; + flagMap = new ObjectSet[Team.all().length][BlockFlag.all.length]; for(int i = 0; i < flagMap.length; i++){ for(int j = 0; j < BlockFlag.all.length; j++){ @@ -73,10 +73,7 @@ public class BlockIndexer{ ores = null; //create bitset for each team type that contains each quadrant - structQuadrants = new GridBits[Team.all.length]; - for(int i = 0; i < Team.all.length; i++){ - structQuadrants[i] = new GridBits(Mathf.ceil(world.width() / (float)quadrantSize), Mathf.ceil(world.height() / (float)quadrantSize)); - } + structQuadrants = new GridBits[Team.all().length]; for(int x = 0; x < world.width(); x++){ for(int y = 0; y < world.height(); y++){ @@ -103,7 +100,31 @@ public class BlockIndexer{ } private ObjectSet[] getFlagged(Team team){ - return flagMap[team.ordinal()]; + return flagMap[team.id]; + } + + private GridBits structQuadrant(Team t){ + if(structQuadrants[t.id] == null){ + structQuadrants[t.id] = new GridBits(Mathf.ceil(world.width() / (float)quadrantSize), Mathf.ceil(world.height() / (float)quadrantSize)); + } + return structQuadrants[t.id]; + } + + /** Updates all the structure quadrants for a newly activated team. */ + public void updateTeamIndex(Team team){ + if(structQuadrants == null) return; + + //go through every tile... ouch + for(int x = 0; x < world.width(); x++){ + for(int y = 0; y < world.height(); y++){ + Tile tile = world.tile(x, y); + if(tile.getTeam() == team){ + int quadrantX = tile.x / quadrantSize; + int quadrantY = tile.y / quadrantSize; + structQuadrant(team).set(quadrantX, quadrantY); + } + } + } } /** @return whether this item is present on this map.*/ @@ -115,11 +136,11 @@ public class BlockIndexer{ public ObjectSet getDamaged(Team team){ returnArray.clear(); - if(damagedTiles[team.ordinal()] == null){ - damagedTiles[team.ordinal()] = new ObjectSet<>(); + if(damagedTiles[team.id] == null){ + damagedTiles[team.id] = new ObjectSet<>(); } - ObjectSet set = damagedTiles[team.ordinal()]; + ObjectSet set = damagedTiles[team.id]; for(Tile tile : set){ if((tile.entity == null || tile.entity.getTeam() != team || !tile.entity.damaged()) || tile.block() instanceof BuildBlock){ returnArray.add(tile); @@ -135,13 +156,13 @@ public class BlockIndexer{ /** Get all allied blocks with a flag. */ public ObjectSet getAllied(Team team, BlockFlag type){ - return flagMap[team.ordinal()][type.ordinal()]; + return flagMap[team.id][type.ordinal()]; } /** Get all enemy blocks with a flag. */ public Array getEnemy(Team team, BlockFlag type){ returnArray.clear(); - for(Team enemy : state.teams.enemiesOf(team)){ + for(Team enemy : team.enemies()){ if(state.teams.isActive(enemy)){ ObjectSet set = getFlagged(enemy)[type.ordinal()]; if(set != null){ @@ -155,11 +176,11 @@ public class BlockIndexer{ } public void notifyTileDamaged(TileEntity entity){ - if(damagedTiles[entity.getTeam().ordinal()] == null){ - damagedTiles[entity.getTeam().ordinal()] = new ObjectSet<>(); + if(damagedTiles[(int)entity.getTeam().id] == null){ + damagedTiles[(int)entity.getTeam().id] = new ObjectSet<>(); } - ObjectSet set = damagedTiles[entity.getTeam().ordinal()]; + ObjectSet set = damagedTiles[(int)entity.getTeam().id]; set.add(entity.tile); } @@ -282,16 +303,16 @@ public class BlockIndexer{ int quadrantY = tile.y / quadrantSize; int index = quadrantX + quadrantY * quadWidth(); - for(Team team : Team.all){ - TeamData data = state.teams.get(team); + for(TeamData data : state.teams.getActive()){ + GridBits bits = structQuadrant(data.team); //fast-set this quadrant to 'occupied' if the tile just placed is already of this team if(tile.getTeam() == data.team && tile.entity != null && tile.block().targetable){ - structQuadrants[data.team.ordinal()].set(quadrantX, quadrantY); + bits.set(quadrantX, quadrantY); continue; //no need to process futher } - structQuadrants[data.team.ordinal()].set(quadrantX, quadrantY, false); + bits.set(quadrantX, quadrantY, false); outer: for(int x = quadrantX * quadrantSize; x < world.width() && x < (quadrantX + 1) * quadrantSize; x++){ @@ -299,7 +320,7 @@ public class BlockIndexer{ Tile result = world.ltile(x, y); //when a targetable block is found, mark this quadrant as occupied and stop searching if(result.entity != null && result.getTeam() == data.team){ - structQuadrants[data.team.ordinal()].set(quadrantX, quadrantY); + bits.set(quadrantX, quadrantY); break outer; } } @@ -308,7 +329,7 @@ public class BlockIndexer{ } private boolean getQuad(Team team, int quadrantX, int quadrantY){ - return structQuadrants[team.ordinal()].get(quadrantX, quadrantY); + return structQuadrant(team).get(quadrantX, quadrantY); } private int quadWidth(){ diff --git a/core/src/mindustry/ai/Pathfinder.java b/core/src/mindustry/ai/Pathfinder.java index 4e1212ea6a..6a2515bb7a 100644 --- a/core/src/mindustry/ai/Pathfinder.java +++ b/core/src/mindustry/ai/Pathfinder.java @@ -27,9 +27,9 @@ public class Pathfinder implements Runnable{ /** unordered array of path data for iteration only. DO NOT iterate ot access this in the main thread.*/ private Array list = new Array<>(); /** Maps teams + flags to a valid path to get to that flag for that team. */ - private PathData[][] pathMap = new PathData[Team.all.length][PathTarget.all.length]; + private PathData[][] pathMap = new PathData[Team.all().length][PathTarget.all.length]; /** Grid map of created path data that should not be queued again. */ - private GridBits created = new GridBits(Team.all.length, PathTarget.all.length); + private GridBits created = new GridBits(Team.all().length, PathTarget.all.length); /** handles task scheduling on the update thread. */ private TaskQueue queue = new TaskQueue(); /** current pathfinding thread */ @@ -42,8 +42,8 @@ public class Pathfinder implements Runnable{ //reset and update internal tile array tiles = new int[world.width()][world.height()]; - pathMap = new PathData[Team.all.length][PathTarget.all.length]; - created = new GridBits(Team.all.length, PathTarget.all.length); + pathMap = new PathData[Team.all().length][PathTarget.all.length]; + created = new GridBits(Team.all().length, PathTarget.all.length); list = new Array<>(); for(int x = 0; x < world.width(); x++){ @@ -53,7 +53,7 @@ public class Pathfinder implements Runnable{ } //special preset which may help speed things up; this is optional - preloadPath(waveTeam, PathTarget.enemyCores); + preloadPath(state.rules.waveTeam, PathTarget.enemyCores); start(); }); @@ -84,8 +84,8 @@ public class Pathfinder implements Runnable{ } public int debugValue(Team team, int x, int y){ - if(pathMap[team.ordinal()][PathTarget.enemyCores.ordinal()] == null) return 0; - return pathMap[team.ordinal()][PathTarget.enemyCores.ordinal()].weights[x][y]; + if(pathMap[team.id][PathTarget.enemyCores.ordinal()] == null) return 0; + return pathMap[team.id][PathTarget.enemyCores.ordinal()].weights[x][y]; } /** Update a tile in the internal pathfinding grid. Causes a complete pathfinding reclaculation. */ @@ -149,12 +149,12 @@ public class Pathfinder implements Runnable{ public Tile getTargetTile(Tile tile, Team team, PathTarget target){ if(tile == null) return null; - PathData data = pathMap[team.ordinal()][target.ordinal()]; + PathData data = pathMap[team.id][target.ordinal()]; if(data == null){ //if this combination is not found, create it on request - if(!created.get(team.ordinal(), target.ordinal())){ - created.set(team.ordinal(), target.ordinal()); + if(!created.get(team.id, target.ordinal())){ + created.set(team.id, target.ordinal()); //grab targets since this is run on main thread IntArray targets = target.getTargets(team, new IntArray()); queue.post(() -> createPath(team, target, targets)); @@ -188,7 +188,7 @@ public class Pathfinder implements Runnable{ /** @return whether a tile can be passed through by this team. Pathfinding thread only.*/ private boolean passable(int x, int y, Team team){ int tile = tiles[x][y]; - return PathTile.passable(tile) || (PathTile.team(tile) != team.ordinal() && PathTile.team(tile) != Team.derelict.ordinal()); + return PathTile.passable(tile) || (PathTile.team(tile) != team.id && PathTile.team(tile) != (int)Team.derelict.id); } /** @@ -238,7 +238,7 @@ public class Pathfinder implements Runnable{ PathData path = new PathData(team, target, world.width(), world.height()); list.add(path); - pathMap[team.ordinal()][target.ordinal()] = path; + pathMap[team.id][target.ordinal()] = path; //grab targets from passed array synchronized(path.targets){ @@ -303,7 +303,7 @@ public class Pathfinder implements Runnable{ } //spawn points are also enemies. - if(state.rules.waves && team == defaultTeam){ + if(state.rules.waves && team == state.rules.defaultTeam){ for(Tile other : spawner.getGroundSpawns()){ out.add(other.pos()); } diff --git a/core/src/mindustry/ai/WaveSpawner.java b/core/src/mindustry/ai/WaveSpawner.java index ac4914a90b..3bd5bc5400 100644 --- a/core/src/mindustry/ai/WaveSpawner.java +++ b/core/src/mindustry/ai/WaveSpawner.java @@ -11,7 +11,7 @@ import mindustry.content.Blocks; import mindustry.content.Fx; import mindustry.entities.Damage; import mindustry.entities.Effects; -import mindustry.entities.type.BaseUnit; +import mindustry.entities.type.*; import mindustry.game.EventType.WorldLoadEvent; import mindustry.game.SpawnGroup; import mindustry.world.Tile; @@ -53,7 +53,7 @@ public class WaveSpawner{ eachFlyerSpawn((spawnX, spawnY) -> { for(int i = 0; i < spawned; i++){ - BaseUnit unit = group.createUnit(waveTeam); + BaseUnit unit = group.createUnit(state.rules.waveTeam); unit.set(spawnX + Mathf.range(spread), spawnY + Mathf.range(spread)); unit.add(); } @@ -66,7 +66,7 @@ public class WaveSpawner{ for(int i = 0; i < spawned; i++){ Tmp.v1.rnd(spread); - BaseUnit unit = group.createUnit(waveTeam); + BaseUnit unit = group.createUnit(state.rules.waveTeam); unit.set(spawnX + Tmp.v1.x, spawnY + Tmp.v1.y); Time.run(Math.min(i * 5, 60 * 2), () -> spawnEffect(unit)); @@ -78,7 +78,7 @@ public class WaveSpawner{ eachGroundSpawn((spawnX, spawnY, doShockwave) -> { if(doShockwave){ Time.run(20f, () -> Effects.effect(Fx.spawnShockwave, spawnX, spawnY, state.rules.dropZoneRadius)); - Time.run(40f, () -> Damage.damage(waveTeam, spawnX, spawnY, state.rules.dropZoneRadius, 99999999f, true)); + Time.run(40f, () -> Damage.damage(state.rules.waveTeam, spawnX, spawnY, state.rules.dropZoneRadius, 99999999f, true)); } }); @@ -90,11 +90,11 @@ public class WaveSpawner{ cons.accept(spawn.worldx(), spawn.worldy(), true); } - if(state.rules.attackMode && state.teams.isActive(waveTeam) && !state.teams.get(defaultTeam).cores.isEmpty()){ - Tile firstCore = state.teams.get(defaultTeam).cores.first(); - for(Tile core : state.teams.get(waveTeam).cores){ - Tmp.v1.set(firstCore).sub(core.worldx(), core.worldy()).limit(coreMargin + core.block().size*tilesize); - cons.accept(core.worldx() + Tmp.v1.x, core.worldy() + Tmp.v1.y, false); + if(state.rules.attackMode && state.teams.isActive(state.rules.waveTeam) && !state.teams.playerCores().isEmpty()){ + TileEntity firstCore = state.teams.playerCores().first(); + for(TileEntity core : state.rules.waveTeam.cores()){ + Tmp.v1.set(firstCore).sub(core.x, core.y).limit(coreMargin + core.block.size*tilesize); + cons.accept(core.x + Tmp.v1.x, core.y + Tmp.v1.y, false); } } } @@ -107,9 +107,9 @@ public class WaveSpawner{ cons.get(spawnX, spawnY); } - if(state.rules.attackMode && state.teams.isActive(waveTeam)){ - for(Tile core : state.teams.get(waveTeam).cores){ - cons.get(core.worldx(), core.worldy()); + if(state.rules.attackMode && state.teams.isActive(state.rules.waveTeam)){ + for(TileEntity core : state.teams.get(state.rules.waveTeam).cores){ + cons.get(core.x, core.y); } } } diff --git a/core/src/mindustry/content/Fx.java b/core/src/mindustry/content/Fx.java index 379e01f9a6..a116034e1a 100644 --- a/core/src/mindustry/content/Fx.java +++ b/core/src/mindustry/content/Fx.java @@ -1079,6 +1079,7 @@ public class Fx implements ContentList{ healBlockFull = new Effect(20, e -> { Draw.color(e.color); Draw.alpha(e.fout()); + Fill.square(e.x, e.y, e.rotation * tilesize / 2f); }); overdriveBlockFull = new Effect(60, e -> { diff --git a/core/src/mindustry/content/StatusEffects.java b/core/src/mindustry/content/StatusEffects.java index 525a14199c..6672727847 100644 --- a/core/src/mindustry/content/StatusEffects.java +++ b/core/src/mindustry/content/StatusEffects.java @@ -6,8 +6,7 @@ import mindustry.entities.Effects; import mindustry.ctype.ContentList; import mindustry.game.EventType.*; import mindustry.type.StatusEffect; - -import static mindustry.Vars.waveTeam; +import static mindustry.Vars.*; public class StatusEffects implements ContentList{ public static StatusEffect none, burning, freezing, wet, melting, tarred, overdrive, shielded, shocked, corroded, boss; @@ -48,7 +47,7 @@ public class StatusEffects implements ContentList{ init(() -> { trans(shocked, ((unit, time, newTime, result) -> { unit.damage(20f); - if(unit.getTeam() == waveTeam){ + if(unit.getTeam() == state.rules.waveTeam){ Events.fire(Trigger.shock); } result.set(this, time); diff --git a/core/src/mindustry/core/Control.java b/core/src/mindustry/core/Control.java index f525494963..458cb313ae 100644 --- a/core/src/mindustry/core/Control.java +++ b/core/src/mindustry/core/Control.java @@ -63,7 +63,7 @@ public class Control implements ApplicationListener, Loadable{ }); Events.on(PlayEvent.class, event -> { - player.setTeam(state.rules.pvp ? netServer.assignTeam(player, playerGroup.all()) : defaultTeam); + player.setTeam(netServer.assignTeam(player, playerGroup.all())); player.setDead(true); player.add(); @@ -256,9 +256,9 @@ public class Control implements ApplicationListener, Loadable{ world.loadGenerator(zone.generator); zone.rules.get(state.rules); state.rules.zone = zone; - for(Tile core : state.teams.get(defaultTeam).cores){ + for(TileEntity core : state.teams.playerCores()){ for(ItemStack stack : zone.getStartingItems()){ - core.entity.items.add(stack.item, stack.amount); + core.items.add(stack.item, stack.amount); } } state.set(State.playing); @@ -294,8 +294,8 @@ public class Control implements ApplicationListener, Loadable{ Geometry.circle(coreb.x, coreb.y, 10, (cx, cy) -> { Tile tile = world.ltile(cx, cy); - if(tile != null && tile.getTeam() == defaultTeam && !(tile.block() instanceof CoreBlock)){ - world.removeBlock(tile); + if(tile != null && tile.getTeam() == state.rules.defaultTeam && !(tile.block() instanceof CoreBlock)){ + tile.remove(); } }); @@ -305,13 +305,13 @@ public class Control implements ApplicationListener, Loadable{ zone.rules.get(state.rules); state.rules.zone = zone; - for(Tile core : state.teams.get(defaultTeam).cores){ + for(TileEntity core : state.teams.playerCores()){ for(ItemStack stack : zone.getStartingItems()){ - core.entity.items.add(stack.item, stack.amount); + core.items.add(stack.item, stack.amount); } } - Tile core = state.teams.get(defaultTeam).cores.first(); - core.entity.items.clear(); + TileEntity core = state.teams.playerCores().first(); + core.items.clear(); logic.play(); state.rules.waveTimer = false; @@ -434,9 +434,9 @@ public class Control implements ApplicationListener, Loadable{ input.update(); if(world.isZone()){ - for(Tile tile : state.teams.get(player.getTeam()).cores){ + for(TileEntity tile : state.teams.cores(player.getTeam())){ for(Item item : content.items()){ - if(tile.entity != null && tile.entity.items.has(item)){ + if(tile.items.has(item)){ data.unlockContent(item); } } diff --git a/core/src/mindustry/core/GameState.java b/core/src/mindustry/core/GameState.java index 73e3db8259..2b233789eb 100644 --- a/core/src/mindustry/core/GameState.java +++ b/core/src/mindustry/core/GameState.java @@ -2,7 +2,6 @@ package mindustry.core; import arc.*; import mindustry.entities.type.*; -import mindustry.entities.type.base.*; import mindustry.game.EventType.*; import mindustry.game.*; @@ -26,12 +25,8 @@ public class GameState{ /** Current game state. */ private State state = State.menu; - public int enemies(){ - return net.client() ? enemies : unitGroups[waveTeam.ordinal()].count(b -> !(b instanceof BaseDrone)); - } - public BaseUnit boss(){ - return unitGroups[waveTeam.ordinal()].find(BaseUnit::isBoss); + return unitGroup.find(u -> u.isBoss() && u.getTeam() == rules.waveTeam); } public void set(State astate){ diff --git a/core/src/mindustry/core/Logic.java b/core/src/mindustry/core/Logic.java index 434058ee72..17fedab303 100644 --- a/core/src/mindustry/core/Logic.java +++ b/core/src/mindustry/core/Logic.java @@ -1,8 +1,8 @@ package mindustry.core; import arc.*; -import mindustry.annotations.Annotations.*; import arc.util.*; +import mindustry.annotations.Annotations.*; import mindustry.content.*; import mindustry.core.GameState.*; import mindustry.ctype.*; @@ -107,9 +107,9 @@ public class Logic implements ApplicationListener{ //add starting items if(!world.isZone()){ - for(Team team : Team.all){ - if(!state.teams.get(team).cores.isEmpty()){ - TileEntity entity = state.teams.get(team).cores.first().entity; + for(TeamData team : state.teams.getActive()){ + if(team.hasCore()){ + TileEntity entity = team.core(); entity.items.clear(); for(ItemStack stack : state.rules.loadout){ entity.items.add(stack.item, stack.amount); @@ -143,23 +143,23 @@ public class Logic implements ApplicationListener{ } private void checkGameOver(){ - if(!state.rules.attackMode && state.teams.get(defaultTeam).cores.size == 0 && !state.gameOver){ + if(!state.rules.attackMode && state.teams.playerCores().size == 0 && !state.gameOver){ state.gameOver = true; - Events.fire(new GameOverEvent(waveTeam)); + Events.fire(new GameOverEvent(state.rules.waveTeam)); }else if(state.rules.attackMode){ Team alive = null; - for(Team team : Team.all){ - if(state.teams.get(team).cores.size > 0){ + for(TeamData team : state.teams.getActive()){ + if(team.hasCore()){ if(alive != null){ return; } - alive = team; + alive = team.team; } } if(alive != null && !state.gameOver){ - if(world.isZone() && alive == defaultTeam){ + if(world.isZone() && alive == state.rules.defaultTeam){ //in attack maps, a victorious game over is equivalent to a launch Call.launchZone(); }else{ @@ -176,7 +176,7 @@ public class Logic implements ApplicationListener{ ui.hudfrag.showLaunch(); } - for(Tile tile : state.teams.get(defaultTeam).cores){ + for(TileEntity tile : state.teams.playerCores()){ Effects.effect(Fx.launch, tile); } @@ -185,19 +185,18 @@ public class Logic implements ApplicationListener{ } Time.runTask(30f, () -> { - for(Tile tile : state.teams.get(defaultTeam).cores){ + for(TileEntity entity : state.teams.playerCores()){ for(Item item : content.items()){ - if(tile == null || tile.entity == null || tile.entity.items == null) continue; - data.addItem(item, tile.entity.items.get(item)); - Events.fire(new LaunchItemEvent(item, tile.entity.items.get(item))); + data.addItem(item, entity.items.get(item)); + Events.fire(new LaunchItemEvent(item, entity.items.get(item))); } - world.removeBlock(tile); + entity.tile.remove(); } state.launched = true; state.gameOver = true; Events.fire(new LaunchEvent()); //manually fire game over event now - Events.fire(new GameOverEvent(defaultTeam)); + Events.fire(new GameOverEvent(state.rules.defaultTeam)); }); } @@ -212,12 +211,15 @@ public class Logic implements ApplicationListener{ public void update(){ if(!state.is(State.menu)){ + if(!net.client()){ + state.enemies = unitGroup.count(b -> b.getTeam() == state.rules.waveTeam && b.countsAsEnemy()); + } if(!state.isPaused()){ Time.update(); if(state.rules.waves && state.rules.waveTimer && !state.gameOver){ - if(!state.rules.waitForWaveToEnd || unitGroups[waveTeam.ordinal()].size() == 0){ + if(!state.rules.waitForWaveToEnd || state.enemies == 0){ state.wavetime = Math.max(state.wavetime - Time.delta(), 0); } } @@ -232,20 +234,15 @@ public class Logic implements ApplicationListener{ } if(!state.isEditor()){ - for(EntityGroup group : unitGroups){ - group.update(); - } - + unitGroup.update(); puddleGroup.update(); shieldGroup.update(); bulletGroup.update(); tileGroup.update(); fireGroup.update(); }else{ - for(EntityGroup group : unitGroups){ - group.updateEvents(); - collisions.updatePhysics(group); - } + unitGroup.updateEvents(); + collisions.updatePhysics(unitGroup); } @@ -257,12 +254,8 @@ public class Logic implements ApplicationListener{ } if(!state.isEditor()){ - - for(EntityGroup group : unitGroups){ - if(group.isEmpty()) continue; - collisions.collideGroups(bulletGroup, group); - } - + //bulletGroup + collisions.collideGroups(bulletGroup, unitGroup); collisions.collideGroups(bulletGroup, playerGroup); } } diff --git a/core/src/mindustry/core/NetClient.java b/core/src/mindustry/core/NetClient.java index 65c6122d72..96daa07041 100644 --- a/core/src/mindustry/core/NetClient.java +++ b/core/src/mindustry/core/NetClient.java @@ -160,9 +160,17 @@ public class NetClient implements ApplicationListener{ throw new ValidateException(player, "Player has sent a message above the text limit."); } + String original = message; + //check if it's a command CommandResponse response = netServer.clientCommands.handleMessage(message, player); if(response.type == ResponseType.noCommand){ //no command to handle + message = netServer.admins.filterMessage(player, message); + //supress chat message if it's filtered out + if(message == null){ + return; + } + //server console logging Log.info("&y{0}: &lb{1}", player.name, message); @@ -190,7 +198,7 @@ public class NetClient implements ApplicationListener{ } } - Events.fire(new PlayerChatEvent(player, message)); + Events.fire(new PlayerChatEvent(player, message, original)); } public static String colorizeName(int id, String name){ diff --git a/core/src/mindustry/core/NetServer.java b/core/src/mindustry/core/NetServer.java index d00fc5a839..c74f14211c 100644 --- a/core/src/mindustry/core/NetServer.java +++ b/core/src/mindustry/core/NetServer.java @@ -17,11 +17,13 @@ import mindustry.entities.traits.*; import mindustry.entities.type.*; import mindustry.game.EventType.*; import mindustry.game.*; +import mindustry.game.Teams.*; import mindustry.gen.*; import mindustry.net.*; import mindustry.net.Administration.*; import mindustry.net.Packets.*; import mindustry.world.*; +import mindustry.world.blocks.storage.CoreBlock.*; import java.io.*; import java.nio.*; @@ -31,14 +33,31 @@ import static mindustry.Vars.*; public class NetServer implements ApplicationListener{ private final static int maxSnapshotSize = 430, timerBlockSync = 0; - private final static float serverSyncTime = 12, kickDuration = 30 * 1000, blockSyncTime = 60 * 10; + private final static float serverSyncTime = 12, kickDuration = 30 * 1000, blockSyncTime = 60 * 8; private final static Vec2 vector = new Vec2(); - private final static Rectangle viewport = new Rectangle(); + private final static Rect viewport = new Rect(); /** If a player goes away of their server-side coordinates by this distance, they get teleported back. */ private final static float correctDist = 16f; public final Administration admins = new Administration(); public final CommandHandler clientCommands = new CommandHandler("/"); + public TeamAssigner assigner = (player, players) -> { + if(state.rules.pvp){ + //find team with minimum amount of players and auto-assign player to that. + TeamData re = state.teams.getActive().min(data -> { + int count = 0; + for(Player other : players){ + if(other.getTeam() == data.team && other != player){ + count++; + } + } + return count; + }); + return re == null ? null : re.team; + } + + return state.rules.defaultTeam; + }; private boolean closing = false; private Interval timer = new Interval(); @@ -197,10 +216,8 @@ public class NetServer implements ApplicationListener{ con.player = player; //playing in pvp mode automatically assigns players to teams - if(state.rules.pvp){ - player.setTeam(assignTeam(player, playerGroup.all())); - Log.info("Auto-assigned player {0} to team {1}.", player.name, player.getTeam()); - } + player.setTeam(assignTeam(player, playerGroup.all())); + Log.info("Auto-assigned player {0} to team {1}.", player.name, player.getTeam()); sendWorldData(player); @@ -401,19 +418,7 @@ public class NetServer implements ApplicationListener{ } public Team assignTeam(Player current, Iterable players){ - //find team with minimum amount of players and auto-assign player to that. - return Structs.findMin(Team.all, team -> { - if(state.teams.isActive(team) && !state.teams.get(team).cores.isEmpty()){ - int count = 0; - for(Player other : players){ - if(other.getTeam() == team && other != current){ - count++; - } - } - return count; - } - return Integer.MAX_VALUE; - }); + return assigner.assign(current, players); } public void sendWorldData(Player player){ @@ -584,8 +589,8 @@ public class NetServer implements ApplicationListener{ public boolean isWaitingForPlayers(){ if(state.rules.pvp){ int used = 0; - for(Team t : Team.all){ - if(playerGroup.count(p -> p.getTeam() == t) > 0){ + for(TeamData t : state.teams.getActive()){ + if(playerGroup.count(p -> p.getTeam() == t.team) > 0){ used++; } } @@ -647,20 +652,20 @@ public class NetServer implements ApplicationListener{ public void writeEntitySnapshot(Player player) throws IOException{ syncStream.reset(); - ObjectSet cores = state.teams.get(player.getTeam()).cores; + Array cores = state.teams.cores(player.getTeam()); dataStream.writeByte(cores.size); - for(Tile tile : cores){ - dataStream.writeInt(tile.pos()); - tile.entity.items.write(dataStream); + for(CoreEntity entity : cores){ + dataStream.writeInt(entity.tile.pos()); + entity.items.write(dataStream); } dataStream.close(); byte[] stateBytes = syncStream.toByteArray(); //write basic state data. - Call.onStateSnapshot(player.con, state.wavetime, state.wave, state.enemies(), (short)stateBytes.length, net.compressSnapshot(stateBytes)); + Call.onStateSnapshot(player.con, state.wavetime, state.wave, state.enemies, (short)stateBytes.length, net.compressSnapshot(stateBytes)); viewport.setSize(player.con.viewWidth, player.con.viewHeight).setCenter(player.con.viewX, player.con.viewY); @@ -784,4 +789,8 @@ public class NetServer implements ApplicationListener{ e.printStackTrace(); } } + + public interface TeamAssigner{ + Team assign(Player player, Iterable players); + } } diff --git a/core/src/mindustry/core/Renderer.java b/core/src/mindustry/core/Renderer.java index 4dbb2ef4a1..d4983e992a 100644 --- a/core/src/mindustry/core/Renderer.java +++ b/core/src/mindustry/core/Renderer.java @@ -18,11 +18,10 @@ import mindustry.entities.effect.*; import mindustry.entities.effect.GroundEffectEntity.*; import mindustry.entities.traits.*; import mindustry.entities.type.*; -import mindustry.game.*; import mindustry.game.EventType.*; import mindustry.graphics.*; import mindustry.input.*; -import mindustry.ui.Cicon; +import mindustry.ui.*; import mindustry.world.blocks.defense.ForceProjector.*; import static arc.Core.*; @@ -42,7 +41,7 @@ public class Renderer implements ApplicationListener{ private float camerascale = targetscale; private float landscale = 0f, landTime; private float minZoomScl = Scl.scl(0.01f); - private Rectangle rect = new Rectangle(), rect2 = new Rectangle(); + private Rect rect = new Rect(), rect2 = new Rect(); private float shakeIntensity, shaketime; public Renderer(){ @@ -57,8 +56,8 @@ public class Renderer implements ApplicationListener{ Effects.setEffectProvider((effect, color, x, y, rotation, data) -> { if(effect == Fx.none) return; if(Core.settings.getBool("effects")){ - Rectangle view = camera.bounds(rect); - Rectangle pos = rect2.setSize(effect.size).setCenter(x, y); + Rect view = camera.bounds(rect); + Rect pos = rect2.setSize(effect.size).setCenter(x, y); if(view.overlaps(pos)){ @@ -344,11 +343,7 @@ public class Renderer implements ApplicationListener{ Draw.rect("circle-shadow", u.x, u.y, size * rad, size * rad); }; - for(EntityGroup group : unitGroups){ - if(!group.isEmpty()){ - group.draw(unit -> !unit.isDead(), draw::get); - } - } + unitGroup.draw(unit -> !unit.isDead(), draw::get); if(!playerGroup.isEmpty()){ playerGroup.draw(unit -> !unit.isDead(), draw::get); @@ -361,34 +356,21 @@ public class Renderer implements ApplicationListener{ float trnsX = -12, trnsY = -13; Draw.color(0, 0, 0, 0.22f); - for(EntityGroup group : unitGroups){ - if(!group.isEmpty()){ - group.draw(unit -> unit.isFlying() && !unit.isDead(), baseUnit -> baseUnit.drawShadow(trnsX, trnsY)); - } - } - - if(!playerGroup.isEmpty()){ - playerGroup.draw(unit -> unit.isFlying() && !unit.isDead(), player -> player.drawShadow(trnsX, trnsY)); - } + unitGroup.draw(unit -> unit.isFlying() && !unit.isDead(), baseUnit -> baseUnit.drawShadow(trnsX, trnsY)); + playerGroup.draw(unit -> unit.isFlying() && !unit.isDead(), player -> player.drawShadow(trnsX, trnsY)); Draw.color(); } private void drawAllTeams(boolean flying){ - for(Team team : Team.all){ - EntityGroup group = unitGroups[team.ordinal()]; + unitGroup.draw(u -> u.isFlying() == flying && !u.isDead(), Unit::drawUnder); + playerGroup.draw(p -> p.isFlying() == flying && !p.isDead(), Unit::drawUnder); - if(group.count(p -> p.isFlying() == flying) + playerGroup.count(p -> p.isFlying() == flying && p.getTeam() == team) == 0 && flying) continue; + unitGroup.draw(u -> u.isFlying() == flying && !u.isDead(), Unit::drawAll); + playerGroup.draw(p -> p.isFlying() == flying, Unit::drawAll); - unitGroups[team.ordinal()].draw(u -> u.isFlying() == flying && !u.isDead(), Unit::drawUnder); - playerGroup.draw(p -> p.isFlying() == flying && p.getTeam() == team && !p.isDead(), Unit::drawUnder); - - unitGroups[team.ordinal()].draw(u -> u.isFlying() == flying && !u.isDead(), Unit::drawAll); - playerGroup.draw(p -> p.isFlying() == flying && p.getTeam() == team, Unit::drawAll); - - unitGroups[team.ordinal()].draw(u -> u.isFlying() == flying && !u.isDead(), Unit::drawOver); - playerGroup.draw(p -> p.isFlying() == flying && p.getTeam() == team, Unit::drawOver); - } + unitGroup.draw(u -> u.isFlying() == flying && !u.isDead(), Unit::drawOver); + playerGroup.draw(p -> p.isFlying() == flying, Unit::drawOver); } public void scaleCamera(float amount){ diff --git a/core/src/mindustry/core/World.java b/core/src/mindustry/core/World.java index 3cdd2ca4f9..ea0e9aa054 100644 --- a/core/src/mindustry/core/World.java +++ b/core/src/mindustry/core/World.java @@ -1,15 +1,15 @@ package mindustry.core; import arc.*; -import arc.struct.*; import arc.math.*; import arc.math.geom.*; -import arc.util.*; +import arc.struct.*; import arc.util.ArcAnnotate.*; -import mindustry.content.*; +import arc.util.*; import mindustry.core.GameState.*; import mindustry.game.EventType.*; import mindustry.game.*; +import mindustry.game.Teams.*; import mindustry.io.*; import mindustry.maps.*; import mindustry.maps.filters.*; @@ -233,33 +233,22 @@ public class World{ invalidMap = false; if(!headless){ - if(state.teams.get(defaultTeam).cores.size == 0 && !checkRules.pvp){ + if(state.teams.playerCores().size == 0 && !checkRules.pvp){ ui.showErrorMessage("$map.nospawn"); invalidMap = true; }else if(checkRules.pvp){ //pvp maps need two cores to be valid - int teams = 0; - for(Team team : Team.all){ - if(state.teams.get(team).cores.size != 0){ - teams ++; - } - } - if(teams < 2){ + if(state.teams.getActive().count(TeamData::hasCore) < 2){ invalidMap = true; ui.showErrorMessage("$map.nospawn.pvp"); } }else if(checkRules.attackMode){ //attack maps need two cores to be valid - invalidMap = state.teams.get(waveTeam).cores.isEmpty(); + invalidMap = state.teams.get(state.rules.waveTeam).noCores(); if(invalidMap){ ui.showErrorMessage("$map.nospawn.attack"); } } }else{ - invalidMap = true; - for(Team team : Team.all){ - if(state.teams.get(team).cores.size != 0){ - invalidMap = false; - } - } + invalidMap = !state.teams.getActive().contains(TeamData::hasCore); if(invalidMap){ throw new MapException(map, "Map has no cores!"); @@ -275,36 +264,6 @@ public class World{ } } - public void removeBlock(Tile tile){ - if(tile == null) return; - tile.link().getLinkedTiles(other -> other.setBlock(Blocks.air)); - } - - public void setBlock(Tile tile, Block block, Team team){ - setBlock(tile, block, team, 0); - } - - public void setBlock(Tile tile, Block block, Team team, int rotation){ - tile.setBlock(block, team, rotation); - if(block.isMultiblock()){ - int offsetx = -(block.size - 1) / 2; - int offsety = -(block.size - 1) / 2; - - for(int dx = 0; dx < block.size; dx++){ - for(int dy = 0; dy < block.size; dy++){ - int worldx = dx + offsetx + tile.x; - int worldy = dy + offsety + tile.y; - if(!(worldx == tile.x && worldy == tile.y)){ - Tile toplace = world.tile(worldx, worldy); - if(toplace != null){ - toplace.setBlock(BlockPart.get(dx + offsetx, dy + offsety), team); - } - } - } - } - } - } - public void raycastEachWorld(float x0, float y0, float x1, float y1, Raycaster cons){ raycastEach(toTile(x0), toTile(y0), toTile(x1), toTile(y1), cons); } diff --git a/core/src/mindustry/editor/DrawOperation.java b/core/src/mindustry/editor/DrawOperation.java index 22a7ad5730..061a7aee84 100755 --- a/core/src/mindustry/editor/DrawOperation.java +++ b/core/src/mindustry/editor/DrawOperation.java @@ -69,7 +69,7 @@ public class DrawOperation{ }else if(type == OpType.rotation.ordinal()){ tile.rotation(to); }else if(type == OpType.team.ordinal()){ - tile.setTeam(Team.all[to]); + tile.setTeam(Team.get(to)); }else if(type == OpType.overlay.ordinal()){ tile.setOverlayID(to); } diff --git a/core/src/mindustry/editor/EditorTile.java b/core/src/mindustry/editor/EditorTile.java index f03c376630..6a2829b098 100644 --- a/core/src/mindustry/editor/EditorTile.java +++ b/core/src/mindustry/editor/EditorTile.java @@ -74,7 +74,7 @@ public class EditorTile extends Tile{ return; } - if(getTeamID() == team.ordinal()) return; + if(getTeamID() == team.id) return; op(OpType.team, getTeamID()); super.setTeam(team); } diff --git a/core/src/mindustry/editor/EditorTool.java b/core/src/mindustry/editor/EditorTool.java index 3e9fcd47dc..50442ff0f2 100644 --- a/core/src/mindustry/editor/EditorTool.java +++ b/core/src/mindustry/editor/EditorTool.java @@ -1,15 +1,14 @@ package mindustry.editor; -import arc.struct.IntArray; import arc.func.*; -import arc.math.Mathf; -import arc.math.geom.Bresenham2; -import arc.util.Structs; -import mindustry.Vars; -import mindustry.content.Blocks; -import mindustry.game.Team; +import arc.math.*; +import arc.math.geom.*; +import arc.struct.*; +import arc.util.*; +import mindustry.content.*; +import mindustry.game.*; import mindustry.world.*; -import mindustry.world.blocks.BlockPart; +import mindustry.world.blocks.*; public enum EditorTool{ zoom, @@ -80,7 +79,7 @@ public enum EditorTool{ editor.drawCircle(x, y, tile -> { if(mode == -1){ //erase block - Vars.world.removeBlock(tile); + tile.remove(); }else if(mode == 0){ //erase ore tile.clearOverlay(); @@ -141,7 +140,7 @@ public enum EditorTool{ if(tile.link().synthetic()){ Team dest = tile.getTeam(); if(dest == editor.drawTeam) return; - fill(editor, x, y, false, t -> t.getTeamID() == dest.ordinal() && t.link().synthetic(), t -> t.setTeam(editor.drawTeam)); + fill(editor, x, y, false, t -> t.getTeamID() == (int)dest.id && t.link().synthetic(), t -> t.setTeam(editor.drawTeam)); } } } diff --git a/core/src/mindustry/editor/MapEditor.java b/core/src/mindustry/editor/MapEditor.java index c83c754b4e..7cab015b1f 100644 --- a/core/src/mindustry/editor/MapEditor.java +++ b/core/src/mindustry/editor/MapEditor.java @@ -10,7 +10,6 @@ import arc.util.Structs; import mindustry.content.Blocks; import mindustry.game.Team; import mindustry.gen.TileOp; -import mindustry.io.LegacyMapIO; import mindustry.io.MapIO; import mindustry.maps.Map; import mindustry.world.*; @@ -65,7 +64,7 @@ public class MapEditor{ reset(); createTiles(pixmap.getWidth(), pixmap.getHeight()); - load(() -> LegacyMapIO.readPixmap(pixmap, tiles())); + load(() -> MapIO.readPixmap(pixmap, tiles())); renderer.resize(width(), height()); } @@ -86,7 +85,7 @@ public class MapEditor{ for(int x = 0; x < width(); x++){ for(int y = 0; y < height(); y++){ if(tiles[x][y].block().isMultiblock()){ - world.setBlock(tiles[x][y], tiles[x][y].block(), tiles[x][y].getTeam()); + tiles[x][y].set(tiles[x][y].block(), tiles[x][y].getTeam()); } } } @@ -176,7 +175,7 @@ public class MapEditor{ } } - world.setBlock(tile(x, y), drawBlock, drawTeam); + tile(x, y).set(drawBlock, drawTeam); }else{ boolean isFloor = drawBlock.isFloor() && drawBlock != Blocks.air; @@ -185,7 +184,7 @@ public class MapEditor{ //remove linked tiles blocking the way if(!isFloor && (tile.isLinked() || tile.block().isMultiblock())){ - world.removeBlock(tile.link()); + tile.link().remove(); } if(isFloor){ diff --git a/core/src/mindustry/editor/MapEditorDialog.java b/core/src/mindustry/editor/MapEditorDialog.java index 0ee0fca085..b9a28501b9 100644 --- a/core/src/mindustry/editor/MapEditorDialog.java +++ b/core/src/mindustry/editor/MapEditorDialog.java @@ -551,7 +551,7 @@ public class MapEditorDialog extends Dialog implements Disposable{ int i = 0; - for(Team team : Team.all){ + for(Team team : Team.base()){ ImageButton button = new ImageButton(Tex.whiteui, Styles.clearTogglePartiali); button.margin(4f); button.getImageCell().grow(); diff --git a/core/src/mindustry/editor/MapGenerateDialog.java b/core/src/mindustry/editor/MapGenerateDialog.java index 6a18ebc089..12f989c272 100644 --- a/core/src/mindustry/editor/MapGenerateDialog.java +++ b/core/src/mindustry/editor/MapGenerateDialog.java @@ -138,7 +138,7 @@ public class MapGenerateDialog extends FloatingDialog{ tile.rotation(write.rotation); tile.setFloor((Floor)content.block(write.floor)); tile.setBlock(content.block(write.block)); - tile.setTeam(Team.all[write.team]); + tile.setTeam(Team.get(write.team)); tile.setOverlay(content.block(write.ore)); } } @@ -367,7 +367,7 @@ public class MapGenerateDialog extends FloatingDialog{ GenTile tile = buffer1[px][py]; input.apply(x, y, content.block(tile.floor), content.block(tile.block), content.block(tile.ore)); filter.apply(input); - buffer2[px][py].set(input.floor, input.block, input.ore, Team.all[tile.team], tile.rotation); + buffer2[px][py].set(input.floor, input.block, input.ore, Team.get(tile.team), tile.rotation); } } for(int px = 0; px < pixmap.getWidth(); px++){ @@ -415,7 +415,7 @@ public class MapGenerateDialog extends FloatingDialog{ this.floor = floor.id; this.block = wall.id; this.ore = ore.id; - this.team = (byte)team.ordinal(); + this.team = (byte) team.id; this.rotation = (byte)rotation; } @@ -437,7 +437,7 @@ public class MapGenerateDialog extends FloatingDialog{ ctile.setBlock(content.block(block)); ctile.setOverlay(content.block(ore)); ctile.rotation(rotation); - ctile.setTeam(Team.all[team]); + ctile.setTeam(Team.get(team)); return ctile; } } diff --git a/core/src/mindustry/editor/MapView.java b/core/src/mindustry/editor/MapView.java index 4c99ffba61..6787f418ab 100644 --- a/core/src/mindustry/editor/MapView.java +++ b/core/src/mindustry/editor/MapView.java @@ -28,7 +28,7 @@ public class MapView extends Element implements GestureListener{ private boolean grid = false; private GridImage image = new GridImage(0, 0); private Vec2 vec = new Vec2(); - private Rectangle rect = new Rectangle(); + private Rect rect = new Rect(); private Vec2[][] brushPolygons = new Vec2[MapEditor.brushSizes.length][0]; private boolean drawing; diff --git a/core/src/mindustry/entities/Damage.java b/core/src/mindustry/entities/Damage.java index a5bc63bc52..335ac96385 100644 --- a/core/src/mindustry/entities/Damage.java +++ b/core/src/mindustry/entities/Damage.java @@ -22,8 +22,8 @@ import static mindustry.Vars.*; /** Utility class for damaging in an area. */ public class Damage{ - private static Rectangle rect = new Rectangle(); - private static Rectangle hitrect = new Rectangle(); + private static Rect rect = new Rect(); + private static Rect hitrect = new Rect(); private static Vec2 tr = new Vec2(); private static GridBits bits = new GridBits(30, 30); private static IntQueue propagation = new IntQueue(); @@ -88,7 +88,7 @@ public class Damage{ tr.trns(angle, length); Intc2 collider = (cx, cy) -> { Tile tile = world.ltile(cx, cy); - if(tile != null && !collidedBlocks.contains(tile.pos()) && tile.entity != null && tile.getTeamID() != team.ordinal() && tile.entity.collide(hitter)){ + if(tile != null && !collidedBlocks.contains(tile.pos()) && tile.entity != null && tile.getTeamID() != team.id && tile.entity.collide(hitter)){ tile.entity.collision(hitter); collidedBlocks.add(tile.pos()); hitter.getBulletType().hit(hitter, tile.worldx(), tile.worldy()); @@ -127,7 +127,7 @@ public class Damage{ Cons cons = e -> { e.hitbox(hitrect); - Rectangle other = hitrect; + Rect other = hitrect; other.y -= expand; other.x -= expand; other.width += expand * 2; @@ -259,7 +259,7 @@ public class Damage{ for(int dx = -trad; dx <= trad; dx++){ for(int dy = -trad; dy <= trad; dy++){ Tile tile = world.tile(Math.round(x / tilesize) + dx, Math.round(y / tilesize) + dy); - if(tile != null && tile.entity != null && (team == null || state.teams.areEnemies(team, tile.getTeam())) && Mathf.dst(dx, dy) <= trad){ + if(tile != null && tile.entity != null && (team == null ||team.isEnemy(tile.getTeam())) && Mathf.dst(dx, dy) <= trad){ tile.entity.damage(damage); } } diff --git a/core/src/mindustry/entities/EntityCollisions.java b/core/src/mindustry/entities/EntityCollisions.java index 6a7fefffd1..72e177d71e 100644 --- a/core/src/mindustry/entities/EntityCollisions.java +++ b/core/src/mindustry/entities/EntityCollisions.java @@ -17,11 +17,11 @@ public class EntityCollisions{ private static final float seg = 1f; //tile collisions - private Rectangle tmp = new Rectangle(); + private Rect tmp = new Rect(); private Vec2 vector = new Vec2(); private Vec2 l1 = new Vec2(); - private Rectangle r1 = new Rectangle(); - private Rectangle r2 = new Rectangle(); + private Rect r1 = new Rect(); + private Rect r2 = new Rect(); //entity collisions private Array arrOut = new Array<>(); @@ -57,7 +57,7 @@ public class EntityCollisions{ public void moveDelta(SolidTrait entity, float deltax, float deltay, boolean x){ - Rectangle rect = r1; + Rect rect = r1; entity.hitboxTile(rect); entity.hitboxTile(r2); rect.x += deltax; @@ -84,7 +84,7 @@ public class EntityCollisions{ entity.setY(entity.getY() + rect.y - r2.y); } - public boolean overlapsTile(Rectangle rect){ + public boolean overlapsTile(Rect rect){ rect.getCenter(vector); int r = 1; diff --git a/core/src/mindustry/entities/EntityGroup.java b/core/src/mindustry/entities/EntityGroup.java index d691949272..8c0ac76442 100644 --- a/core/src/mindustry/entities/EntityGroup.java +++ b/core/src/mindustry/entities/EntityGroup.java @@ -19,13 +19,13 @@ public class EntityGroup{ private final Array entitiesToRemove = new Array<>(false, 32); private final Array entitiesToAdd = new Array<>(false, 32); private final Array intersectArray = new Array<>(); - private final Rectangle intersectRect = new Rectangle(); + private final Rect intersectRect = new Rect(); private IntMap map; private QuadTree tree; private Cons removeListener; private Cons addListener; - private final Rectangle viewport = new Rectangle(); + private final Rect viewport = new Rect(); private int count = 0; public EntityGroup(int id, Class type, boolean useTree){ @@ -34,7 +34,7 @@ public class EntityGroup{ this.type = type; if(useTree){ - tree = new QuadTree<>(new Rectangle(0, 0, 0, 0)); + tree = new QuadTree<>(new Rect(0, 0, 0, 0)); } } @@ -180,7 +180,7 @@ public class EntityGroup{ /** Resizes the internal quadtree, if it is enabled.*/ public void resize(float x, float y, float w, float h){ if(useTree){ - tree = new QuadTree<>(new Rectangle(x, y, w, h)); + tree = new QuadTree<>(new Rect(x, y, w, h)); } } diff --git a/core/src/mindustry/entities/Units.java b/core/src/mindustry/entities/Units.java index 94a0cfbd12..fac56dcc0e 100644 --- a/core/src/mindustry/entities/Units.java +++ b/core/src/mindustry/entities/Units.java @@ -1,21 +1,18 @@ package mindustry.entities; -import arc.struct.EnumSet; -import arc.func.Cons; -import arc.func.Boolf; -import arc.math.Mathf; -import arc.math.geom.Geometry; -import arc.math.geom.Rectangle; -import mindustry.entities.traits.TargetTrait; +import arc.func.*; +import arc.math.*; +import arc.math.geom.*; +import mindustry.entities.traits.*; import mindustry.entities.type.*; -import mindustry.game.Team; -import mindustry.world.Tile; +import mindustry.game.*; +import mindustry.world.*; import static mindustry.Vars.*; /** Utility class for unit and team interactions.*/ public class Units{ - private static Rectangle hitrect = new Rectangle(); + private static Rect hitrect = new Rect(); private static Unit result; private static float cdist; private static boolean boolResult; @@ -86,7 +83,7 @@ public class Units{ public static TileEntity findEnemyTile(Team team, float x, float y, float range, Boolf pred){ if(team == Team.derelict) return null; - for(Team enemy : state.teams.enemiesOf(team)){ + for(Team enemy : team.enemies()){ TileEntity entity = indexer.findTile(enemy, x, y, range, pred, true); if(entity != null){ return entity; @@ -157,7 +154,11 @@ public class Units{ /** Iterates over all units in a rectangle. */ public static void nearby(Team team, float x, float y, float width, float height, Cons cons){ - unitGroups[team.ordinal()].intersect(x, y, width, height, cons); + unitGroup.intersect(x, y, width, height, u -> { + if(u.getTeam() == team){ + cons.get(u); + } + }); playerGroup.intersect(x, y, width, height, player -> { if(player.getTeam() == team){ cons.get(player); @@ -167,8 +168,8 @@ public class Units{ /** Iterates over all units in a circle around this position. */ public static void nearby(Team team, float x, float y, float radius, Cons cons){ - unitGroups[team.ordinal()].intersect(x - radius, y - radius, radius*2f, radius*2f, unit -> { - if(unit.withinDst(x, y, radius)){ + unitGroup.intersect(x - radius, y - radius, radius*2f, radius*2f, unit -> { + if(unit.getTeam() == team && unit.withinDst(x, y, radius)){ cons.get(unit); } }); @@ -182,45 +183,43 @@ public class Units{ /** Iterates over all units in a rectangle. */ public static void nearby(float x, float y, float width, float height, Cons cons){ - for(Team team : Team.all){ - unitGroups[team.ordinal()].intersect(x, y, width, height, cons); - } - + unitGroup.intersect(x, y, width, height, cons); playerGroup.intersect(x, y, width, height, cons); } /** Iterates over all units in a rectangle. */ - public static void nearby(Rectangle rect, Cons cons){ + public static void nearby(Rect rect, Cons cons){ nearby(rect.x, rect.y, rect.width, rect.height, cons); } /** Iterates over all units that are enemies of this team. */ public static void nearbyEnemies(Team team, float x, float y, float width, float height, Cons cons){ - EnumSet targets = state.teams.enemiesOf(team); - - for(Team other : targets){ - unitGroups[other.ordinal()].intersect(x, y, width, height, cons); - } + unitGroup.intersect(x, y, width, height, u -> { + if(team.isEnemy(u.getTeam())){ + cons.get(u); + } + }); playerGroup.intersect(x, y, width, height, player -> { - if(targets.contains(player.getTeam())){ + if(team.isEnemy(player.getTeam())){ cons.get(player); } }); } /** Iterates over all units that are enemies of this team. */ - public static void nearbyEnemies(Team team, Rectangle rect, Cons cons){ + public static void nearbyEnemies(Team team, Rect rect, Cons cons){ nearbyEnemies(team, rect.x, rect.y, rect.width, rect.height, cons); } /** Iterates over all units. */ public static void all(Cons cons){ - for(Team team : Team.all){ - unitGroups[team.ordinal()].all().each(cons); - } - + unitGroup.all().each(cons); playerGroup.all().each(cons); } + public static void each(Team team, Cons cons){ + unitGroup.all().each(t -> t.getTeam() == team, cons); + } + } diff --git a/core/src/mindustry/entities/bullet/ArtilleryBulletType.java b/core/src/mindustry/entities/bullet/ArtilleryBulletType.java index 3a098e8765..c59dedf99a 100644 --- a/core/src/mindustry/entities/bullet/ArtilleryBulletType.java +++ b/core/src/mindustry/entities/bullet/ArtilleryBulletType.java @@ -25,7 +25,7 @@ public class ArtilleryBulletType extends BasicBulletType{ } @Override - public void update(mindustry.entities.type.Bullet b){ + public void update(Bullet b){ super.update(b); if(b.timer.get(0, 3 + b.fslope() * 2f)){ diff --git a/core/src/mindustry/entities/bullet/FlakBulletType.java b/core/src/mindustry/entities/bullet/FlakBulletType.java index b68e3af59a..ead19859cc 100644 --- a/core/src/mindustry/entities/bullet/FlakBulletType.java +++ b/core/src/mindustry/entities/bullet/FlakBulletType.java @@ -1,13 +1,13 @@ package mindustry.entities.bullet; -import arc.math.geom.Rectangle; +import arc.math.geom.Rect; import arc.util.Time; import mindustry.content.Fx; import mindustry.entities.Units; import mindustry.entities.type.Bullet; public class FlakBulletType extends BasicBulletType{ - protected static Rectangle rect = new Rectangle(); + protected static Rect rect = new Rect(); protected float explodeRange = 30f; public FlakBulletType(float speed, float damage){ diff --git a/core/src/mindustry/entities/effect/Lightning.java b/core/src/mindustry/entities/effect/Lightning.java index 1e88c29df2..59b7f833fa 100644 --- a/core/src/mindustry/entities/effect/Lightning.java +++ b/core/src/mindustry/entities/effect/Lightning.java @@ -28,7 +28,7 @@ public class Lightning extends TimedEntity implements DrawTrait, TimeTrait{ public static final float lifetime = 10f; private static final RandomXS128 random = new RandomXS128(); - private static final Rectangle rect = new Rectangle(); + private static final Rect rect = new Rect(); private static final Array entities = new Array<>(); private static final IntSet hit = new IntSet(); private static final int maxChain = 8; diff --git a/core/src/mindustry/entities/effect/Puddle.java b/core/src/mindustry/entities/effect/Puddle.java index e2d5d2e10c..132c2d1379 100644 --- a/core/src/mindustry/entities/effect/Puddle.java +++ b/core/src/mindustry/entities/effect/Puddle.java @@ -27,8 +27,8 @@ public class Puddle extends SolidEntity implements SaveTrait, Poolable, DrawTrai private static final float maxLiquid = 70f; private static final int maxGeneration = 2; private static final Color tmp = new Color(); - private static final Rectangle rect = new Rectangle(); - private static final Rectangle rect2 = new Rectangle(); + private static final Rect rect = new Rect(); + private static final Rect rect2 = new Rect(); private static int seeds; private int loadedPosition = -1; @@ -151,13 +151,13 @@ public class Puddle extends SolidEntity implements SaveTrait, Poolable, DrawTrai } @Override - public void hitbox(Rectangle rectangle){ - rectangle.setCenter(x, y).setSize(tilesize); + public void hitbox(Rect rect){ + rect.setCenter(x, y).setSize(tilesize); } @Override - public void hitboxTile(Rectangle rectangle){ - rectangle.setCenter(x, y).setSize(0f); + public void hitboxTile(Rect rect){ + rect.setCenter(x, y).setSize(0f); } @Override diff --git a/core/src/mindustry/entities/traits/BuilderTrait.java b/core/src/mindustry/entities/traits/BuilderTrait.java index 2f302be8e6..02ae0bca5b 100644 --- a/core/src/mindustry/entities/traits/BuilderTrait.java +++ b/core/src/mindustry/entities/traits/BuilderTrait.java @@ -343,7 +343,7 @@ public interface BuilderTrait extends Entity, TeamTrait{ return this; } - public Rectangle bounds(Rectangle rect){ + public Rect bounds(Rect rect){ if(breaking){ return rect.set(-100f, -100f, 0f, 0f); }else{ diff --git a/core/src/mindustry/entities/traits/SolidTrait.java b/core/src/mindustry/entities/traits/SolidTrait.java index f799f13cba..afa2efd6b0 100644 --- a/core/src/mindustry/entities/traits/SolidTrait.java +++ b/core/src/mindustry/entities/traits/SolidTrait.java @@ -7,9 +7,9 @@ import mindustry.Vars; public interface SolidTrait extends QuadTreeObject, MoveTrait, VelocityTrait, Entity, Position{ - void hitbox(Rectangle rectangle); + void hitbox(Rect rect); - void hitboxTile(Rectangle rectangle); + void hitboxTile(Rect rect); Vec2 lastPosition(); diff --git a/core/src/mindustry/entities/type/BaseUnit.java b/core/src/mindustry/entities/type/BaseUnit.java index 46e2f8f63b..6062662e9b 100644 --- a/core/src/mindustry/entities/type/BaseUnit.java +++ b/core/src/mindustry/entities/type/BaseUnit.java @@ -126,6 +126,11 @@ public abstract class BaseUnit extends Unit implements ShooterTrait{ this.team = team; } + /** @return whether this unit counts toward the enemy amount in the wave UI. */ + public boolean countsAsEnemy(){ + return true; + } + public UnitType getType(){ return type; } @@ -180,23 +185,16 @@ public abstract class BaseUnit extends Unit implements ShooterTrait{ } } - public Tile getClosest(BlockFlag flag){ + public @Nullable Tile getClosest(BlockFlag flag){ return Geometry.findClosest(x, y, indexer.getAllied(team, flag)); } - public Tile getClosestSpawner(){ + public @Nullable Tile getClosestSpawner(){ return Geometry.findClosest(x, y, Vars.spawner.getGroundSpawns()); } - public TileEntity getClosestEnemyCore(){ - for(Team enemy : Vars.state.teams.enemiesOf(team)){ - Tile tile = Geometry.findClosest(x, y, Vars.state.teams.get(enemy).cores); - if(tile != null){ - return tile.entity; - } - } - - return null; + public @Nullable TileEntity getClosestEnemyCore(){ + return Vars.state.teams.closestEnemyCore(x, y, team); } public UnitState getStartState(){ @@ -354,18 +352,18 @@ public abstract class BaseUnit extends Unit implements ShooterTrait{ } @Override - public void hitbox(Rectangle rectangle){ - rectangle.setSize(type.hitsize).setCenter(x, y); + public void hitbox(Rect rect){ + rect.setSize(type.hitsize).setCenter(x, y); } @Override - public void hitboxTile(Rectangle rectangle){ - rectangle.setSize(type.hitsizeTile).setCenter(x, y); + public void hitboxTile(Rect rect){ + rect.setSize(type.hitsizeTile).setCenter(x, y); } @Override public EntityGroup targetGroup(){ - return unitGroups[team.ordinal()]; + return unitGroup; } @Override diff --git a/core/src/mindustry/entities/type/Bullet.java b/core/src/mindustry/entities/type/Bullet.java index 6afafb5f29..f7e676ecc9 100644 --- a/core/src/mindustry/entities/type/Bullet.java +++ b/core/src/mindustry/entities/type/Bullet.java @@ -246,13 +246,13 @@ public class Bullet extends SolidEntity implements DamageTrait, ScaleTrait, Pool } @Override - public void hitbox(Rectangle rectangle){ - rectangle.setSize(type.hitSize).setCenter(x, y); + public void hitbox(Rect rect){ + rect.setSize(type.hitSize).setCenter(x, y); } @Override - public void hitboxTile(Rectangle rectangle){ - rectangle.setSize(type.hitSize).setCenter(x, y); + public void hitboxTile(Rect rect){ + rect.setSize(type.hitSize).setCenter(x, y); } @Override diff --git a/core/src/mindustry/entities/type/Player.java b/core/src/mindustry/entities/type/Player.java index a6a74683bb..af5165fc60 100644 --- a/core/src/mindustry/entities/type/Player.java +++ b/core/src/mindustry/entities/type/Player.java @@ -41,7 +41,7 @@ public class Player extends Unit implements BuilderMinerTrait, ShooterTrait{ private static final int timerShootRight = 1; private static final float liftoffBoost = 0.2f; - private static final Rectangle rect = new Rectangle(); + private static final Rect rect = new Rect(); //region instance variables @@ -93,13 +93,13 @@ public class Player extends Unit implements BuilderMinerTrait, ShooterTrait{ } @Override - public void hitbox(Rectangle rectangle){ - rectangle.setSize(mech.hitsize).setCenter(x, y); + public void hitbox(Rect rect){ + rect.setSize(mech.hitsize).setCenter(x, y); } @Override - public void hitboxTile(Rectangle rectangle){ - rectangle.setSize(mech.hitsize * 2f / 3f).setCenter(x, y); + public void hitboxTile(Rect rect){ + rect.setSize(mech.hitsize * 2f / 3f).setCenter(x, y); } @Override diff --git a/core/src/mindustry/entities/type/TileEntity.java b/core/src/mindustry/entities/type/TileEntity.java index 85c6c9d2eb..4a2a5aee91 100644 --- a/core/src/mindustry/entities/type/TileEntity.java +++ b/core/src/mindustry/entities/type/TileEntity.java @@ -124,7 +124,8 @@ public class TileEntity extends BaseEntity implements TargetTrait, HealthTrait{ @CallSuper public void write(DataOutput stream) throws IOException{ stream.writeShort((short)health); - stream.writeByte(Pack.byteByte(tile.getTeamID(), tile.rotation())); //team + rotation + stream.writeByte(Pack.byteByte((byte)8, tile.rotation())); //rotation + marker to indicate that team is moved (8 isn't valid) + stream.writeByte(tile.getTeamID()); if(items != null) items.write(stream); if(power != null) power.write(stream); if(liquids != null) liquids.write(stream); @@ -134,11 +135,11 @@ public class TileEntity extends BaseEntity implements TargetTrait, HealthTrait{ @CallSuper public void read(DataInput stream, byte revision) throws IOException{ health = stream.readUnsignedShort(); - byte tr = stream.readByte(); - byte team = Pack.leftByte(tr); - byte rotation = Pack.rightByte(tr); + byte packedrot = stream.readByte(); + byte team = Pack.leftByte(packedrot) == 8 ? stream.readByte() : Pack.leftByte(packedrot); + byte rotation = Pack.rightByte(packedrot); - tile.setTeam(Team.all[team]); + tile.setTeam(Team.get(team)); tile.rotation(rotation); if(items != null) items.read(stream); @@ -277,7 +278,7 @@ public class TileEntity extends BaseEntity implements TargetTrait, HealthTrait{ Events.fire(new BlockDestroyEvent(tile)); block.breakSound.at(tile); block.onDestroyed(tile); - world.removeBlock(tile); + tile.remove(); remove(); } } diff --git a/core/src/mindustry/entities/type/Unit.java b/core/src/mindustry/entities/type/Unit.java index 1bec11c029..ab02f24c83 100644 --- a/core/src/mindustry/entities/type/Unit.java +++ b/core/src/mindustry/entities/type/Unit.java @@ -1,12 +1,12 @@ package mindustry.entities.type; import arc.*; -import arc.struct.*; import arc.graphics.*; import arc.graphics.g2d.*; import arc.math.*; import arc.math.geom.*; import arc.scene.ui.layout.*; +import arc.struct.*; import arc.util.*; import arc.util.ArcAnnotate.*; import mindustry.content.*; @@ -16,13 +16,11 @@ import mindustry.entities.traits.*; import mindustry.entities.units.*; import mindustry.game.EventType.*; import mindustry.game.*; -import mindustry.game.Teams.*; import mindustry.gen.*; import mindustry.graphics.*; import mindustry.net.*; import mindustry.type.*; import mindustry.ui.*; -import mindustry.ui.Cicon; import mindustry.world.*; import mindustry.world.blocks.*; @@ -90,7 +88,7 @@ public abstract class Unit extends DestructibleEntity implements SaveTrait, Targ if(isDead()) return false; if(other instanceof DamageTrait){ - return other instanceof TeamTrait && state.teams.areEnemies((((TeamTrait)other).getTeam()), team); + return other instanceof TeamTrait && (((TeamTrait)other).getTeam()).isEnemy(team); }else{ return other instanceof Unit && ((Unit)other).isFlying() == isFlying(); } @@ -158,7 +156,7 @@ public abstract class Unit extends DestructibleEntity implements SaveTrait, Targ this.item.amount = itemAmount; this.item.item = content.item(itemID); this.dead = dead; - this.team = Team.all[team]; + this.team = Team.get(team); this.health = health; this.x = x; this.y = y; @@ -169,7 +167,7 @@ public abstract class Unit extends DestructibleEntity implements SaveTrait, Targ public void writeSave(DataOutput stream, boolean net) throws IOException{ if(item.item == null) item.item = Items.copper; - stream.writeByte(team.ordinal()); + stream.writeByte(team.id); stream.writeBoolean(isDead()); stream.writeFloat(net ? interpolator.target.x : x); stream.writeFloat(net ? interpolator.target.y : y); @@ -217,13 +215,7 @@ public abstract class Unit extends DestructibleEntity implements SaveTrait, Targ float fsize = getSize() / radScl; moveVector.setZero(); float cx = x - fsize/2f, cy = y - fsize/2f; - - for(Team team : Team.all){ - if(team != getTeam() || !(this instanceof Player)){ - avoid(unitGroups[team.ordinal()].intersect(cx, cy, fsize, fsize)); - } - } - + avoid(unitGroup.intersect(cx, cy, fsize, fsize)); if(!(this instanceof Player)){ avoid(playerGroup.intersect(cx, cy, fsize, fsize)); } @@ -242,14 +234,7 @@ public abstract class Unit extends DestructibleEntity implements SaveTrait, Targ } public @Nullable TileEntity getClosestCore(){ - TeamData data = state.teams.get(team); - - Tile tile = Geometry.findClosest(x, y, data.cores); - if(tile == null){ - return null; - }else{ - return tile.entity; - } + return state.teams.closestCore(x, y, team); } public Floor getFloorOn(){ @@ -275,7 +260,7 @@ public abstract class Unit extends DestructibleEntity implements SaveTrait, Targ } //apply knockback based on spawns - if(getTeam() != waveTeam){ + if(getTeam() != state.rules.waveTeam){ float relativeSize = state.rules.dropZoneRadius + getSize()/2f + 1f; for(Tile spawn : spawner.getGroundSpawns()){ if(withinDst(spawn.worldx(), spawn.worldy(), relativeSize)){ diff --git a/core/src/mindustry/entities/type/base/BaseDrone.java b/core/src/mindustry/entities/type/base/BaseDrone.java index a1b5b1c321..02a8fd9d32 100644 --- a/core/src/mindustry/entities/type/base/BaseDrone.java +++ b/core/src/mindustry/entities/type/base/BaseDrone.java @@ -32,6 +32,10 @@ public abstract class BaseDrone extends FlyingUnit{ } }; + public boolean countsAsEnemy(){ + return false; + } + @Override public void onCommand(UnitCommand command){ //do nothing, normal commands are not applicable here diff --git a/core/src/mindustry/entities/type/base/BuilderDrone.java b/core/src/mindustry/entities/type/base/BuilderDrone.java index f84bdecbca..336be7be6e 100644 --- a/core/src/mindustry/entities/type/base/BuilderDrone.java +++ b/core/src/mindustry/entities/type/base/BuilderDrone.java @@ -1,10 +1,9 @@ package mindustry.entities.type.base; import arc.*; -import arc.struct.*; import arc.math.*; +import arc.struct.*; import arc.util.*; -import mindustry.*; import mindustry.entities.*; import mindustry.entities.traits.*; import mindustry.entities.type.*; @@ -114,12 +113,10 @@ public class BuilderDrone extends BaseDrone implements BuilderTrait{ public BuilderDrone(){ if(reset.check()){ Events.on(BuildSelectEvent.class, event -> { - EntityGroup group = unitGroups[event.team.ordinal()]; - if(!(event.tile.entity instanceof BuildEntity)) return; - for(BaseUnit unit : group.all()){ - if(unit instanceof BuilderDrone){ + for(BaseUnit unit : unitGroup.all()){ + if(unit instanceof BuilderDrone && unit.getTeam() == getTeam()){ BuilderDrone drone = (BuilderDrone)unit; if(drone.isBuilding()){ //stop building if opposite building begins. @@ -189,7 +186,7 @@ public class BuilderDrone extends BaseDrone implements BuilderTrait{ } if(timer.get(timerTarget, 80) && Units.closestEnemy(getTeam(), x, y, 100f, u -> !(u instanceof BaseDrone)) == null && !isBuilding()){ - TeamData data = Vars.state.teams.get(team); + TeamData data = team.data(); if(!data.brokenBlocks.isEmpty()){ BrokenBlock block = data.brokenBlocks.removeLast(); if(Build.validPlace(getTeam(), block.x, block.y, content.block(block.block), block.rotation)){ diff --git a/core/src/mindustry/entities/type/base/GroundUnit.java b/core/src/mindustry/entities/type/base/GroundUnit.java index 5f7c6d2768..56ba404a30 100644 --- a/core/src/mindustry/entities/type/base/GroundUnit.java +++ b/core/src/mindustry/entities/type/base/GroundUnit.java @@ -237,15 +237,15 @@ public class GroundUnit extends BaseUnit{ protected void moveAwayFromCore(){ Team enemy = null; - for(Team team : Vars.state.teams.enemiesOf(team)){ - if(Vars.state.teams.isActive(team)){ + for(Team team : team.enemies()){ + if(team.active()){ enemy = team; break; } } if(enemy == null){ - for(Team team : Vars.state.teams.enemiesOf(team)){ + for(Team team : team.enemies()){ enemy = team; break; } diff --git a/core/src/mindustry/entities/units/UnitDrops.java b/core/src/mindustry/entities/units/UnitDrops.java index b58171ee2f..f57ff0a75d 100644 --- a/core/src/mindustry/entities/units/UnitDrops.java +++ b/core/src/mindustry/entities/units/UnitDrops.java @@ -7,13 +7,14 @@ import mindustry.entities.type.BaseUnit; import mindustry.entities.type.TileEntity; import mindustry.gen.Call; import mindustry.type.Item; +import static mindustry.Vars.*; public class UnitDrops{ private static Item[] dropTable; public static void dropItems(BaseUnit unit){ //items only dropped in waves for enemy team - if(unit.getTeam() != Vars.waveTeam || !Vars.state.rules.unitDrops){ + if(unit.getTeam() != state.rules.waveTeam || !Vars.state.rules.unitDrops){ return; } diff --git a/core/src/mindustry/game/EventType.java b/core/src/mindustry/game/EventType.java index cf26f06fec..dfa1469fc1 100644 --- a/core/src/mindustry/game/EventType.java +++ b/core/src/mindustry/game/EventType.java @@ -62,10 +62,13 @@ public class EventType{ public static class PlayerChatEvent{ public final Player player; public final String message; + /** The original, unfiltered message. */ + public final String originalMessage; - public PlayerChatEvent(Player player, String message){ + public PlayerChatEvent(Player player, String message, String originalMessage){ this.player = player; this.message = message; + this.originalMessage = originalMessage; } } diff --git a/core/src/mindustry/game/Gamemode.java b/core/src/mindustry/game/Gamemode.java index 3cb2605c24..3679ba0ad2 100644 --- a/core/src/mindustry/game/Gamemode.java +++ b/core/src/mindustry/game/Gamemode.java @@ -4,7 +4,7 @@ import arc.*; import arc.func.*; import mindustry.maps.*; -import static mindustry.Vars.waveTeam; +import static mindustry.Vars.*; /** Defines preset rule sets. */ public enum Gamemode{ @@ -22,7 +22,7 @@ public enum Gamemode{ attack(rules -> { rules.unitDrops = true; rules.attackMode = true; - }, map -> map.teams.contains(waveTeam.ordinal())), + }, map -> map.teams.contains((int)state.rules.waveTeam.id)), pvp(rules -> { rules.pvp = true; rules.enemyCoreBuildRadius = 600f; diff --git a/core/src/mindustry/game/MusicControl.java b/core/src/mindustry/game/MusicControl.java index f258b6a520..26a44876ac 100644 --- a/core/src/mindustry/game/MusicControl.java +++ b/core/src/mindustry/game/MusicControl.java @@ -83,7 +83,7 @@ public class MusicControl{ /** Whether to play dark music.*/ private boolean isDark(){ - if(!state.teams.get(player.getTeam()).cores.isEmpty() && state.teams.get(player.getTeam()).cores.first().entity.healthf() < 0.85f){ + if(state.teams.get(player.getTeam()).hasCore() && state.teams.get(player.getTeam()).core().healthf() < 0.85f){ //core damaged -> dark return true; } @@ -94,7 +94,7 @@ public class MusicControl{ } //dark based on enemies - return Mathf.chance(state.enemies() / 70f + 0.1f); + return Mathf.chance(state.enemies / 70f + 0.1f); } /** Plays and fades in a music track. This must be called every frame. diff --git a/core/src/mindustry/game/Rules.java b/core/src/mindustry/game/Rules.java index 8b40abd1ae..93ceaf5cfe 100644 --- a/core/src/mindustry/game/Rules.java +++ b/core/src/mindustry/game/Rules.java @@ -78,6 +78,12 @@ public class Rules{ public boolean lighting = false; /** Ambient light color, used when lighting is enabled. */ public Color ambientLight = new Color(0.01f, 0.01f, 0.04f, 0.99f); + /** team of the player by default */ + public Team defaultTeam = Team.sharded; + /** team of the enemy in waves/sectors */ + public Team waveTeam = Team.crux; + /** special tags for additional info */ + public StringMap tags = new StringMap(); /** Copies this ruleset exactly. Not very efficient at all, do not use often. */ public Rules copy(){ diff --git a/core/src/mindustry/game/Schematics.java b/core/src/mindustry/game/Schematics.java index b9c56744a3..b30658692e 100644 --- a/core/src/mindustry/game/Schematics.java +++ b/core/src/mindustry/game/Schematics.java @@ -254,7 +254,7 @@ public class Schematics implements Loadable{ Tile tile = world.tile(st.x + ox, st.y + oy); if(tile == null) return; - world.setBlock(tile, st.block, defaultTeam); + tile.set(st.block, state.rules.defaultTeam); tile.rotation(st.rotation); if(st.block.posConfig){ tile.configureAny(Pos.get(tile.x - st.x + Pos.x(st.config), tile.y - st.y + Pos.y(st.config))); diff --git a/core/src/mindustry/game/Team.java b/core/src/mindustry/game/Team.java index 8e6d66ae1b..a6e9d1e20a 100644 --- a/core/src/mindustry/game/Team.java +++ b/core/src/mindustry/game/Team.java @@ -1,27 +1,102 @@ package mindustry.game; -import arc.Core; -import arc.graphics.Color; +import arc.*; +import arc.graphics.*; +import arc.math.*; +import arc.struct.*; +import arc.util.*; +import mindustry.game.Teams.*; import mindustry.graphics.*; +import mindustry.world.blocks.storage.CoreBlock.*; -public enum Team{ - derelict(Color.valueOf("4d4e58")), - sharded(Pal.accent), - crux(Color.valueOf("e82d2d")), - green(Color.valueOf("4dd98b")), - purple(Color.valueOf("9a4bdf")), - blue(Color.royal.cpy()); +import static mindustry.Vars.*; - public final static Team[] all = values(); +public class Team implements Comparable{ + public final byte id; public final Color color; - public final int intColor; + public String name; - Team(Color color){ + /** All 256 registered teams. */ + private static final Team[] all = new Team[256]; + /** The 6 base teams used in the editor. */ + private static final Team[] baseTeams = new Team[6]; + + public final static Team + derelict = new Team(0, "derelict", Color.valueOf("4d4e58")), + sharded = new Team(1, "sharded", Pal.accent.cpy()), + crux = new Team(2, "crux", Color.valueOf("e82d2d")), + green = new Team(3, "green", Color.valueOf("4dd98b")), + purple = new Team(4, "purple", Color.valueOf("9a4bdf")), + blue = new Team(5, "blue", Color.royal.cpy()); + + static{ + Mathf.random.setSeed(7); + //create the whole 256 placeholder teams + for(int i = 6; i < all.length; i++){ + new Team(i, "team#" + i, Color.HSVtoRGB(360f * Mathf.random(), 100f * Mathf.random(0.6f, 1f), 100f * Mathf.random(0.8f, 1f), 1f)); + } + Mathf.random.setSeed(new RandomXS128().nextLong()); + } + + public static Team get(int id){ + return all[Pack.u((byte)id)]; + } + + /** @return the 6 base team colors. */ + public static Team[] base(){ + return baseTeams; + } + + /** @return all the teams - do not use this for lookup! */ + public static Team[] all(){ + return all; + } + + protected Team(int id, String name, Color color){ + this.name = name; this.color = color; - intColor = Color.rgba8888(color); + this.id = (byte)id; + + int us = Pack.u(this.id); + if(us < 6) baseTeams[us] = this; + all[us] = this; + } + + public Array enemies(){ + return state.teams.enemiesOf(this); + } + + public TeamData data(){ + return state.teams.get(this); + } + + public CoreEntity core(){ + return data().core(); + } + + public boolean active(){ + return state.teams.isActive(this); + } + + public boolean isEnemy(Team other){ + return state.teams.areEnemies(this, other); + } + + public Array cores(){ + return state.teams.cores(this); } public String localized(){ - return Core.bundle.get("team." + name() + ".name"); + return Core.bundle.get("team." + name + ".name", name); + } + + @Override + public int compareTo(Team team){ + return Integer.compare(id, team.id); + } + + @Override + public String toString(){ + return name; } } diff --git a/core/src/mindustry/game/Teams.java b/core/src/mindustry/game/Teams.java index 2b03bbfaee..dc44d47240 100644 --- a/core/src/mindustry/game/Teams.java +++ b/core/src/mindustry/game/Teams.java @@ -1,61 +1,168 @@ package mindustry.game; +import arc.func.*; +import arc.math.geom.*; import arc.struct.*; -import mindustry.*; -import mindustry.world.*; +import arc.util.ArcAnnotate.*; +import arc.util.*; +import mindustry.entities.type.*; +import mindustry.world.blocks.storage.CoreBlock.*; + +import static mindustry.Vars.*; /** Class for various team-based utilities. */ public class Teams{ - private TeamData[] map = new TeamData[Team.all.length]; + /** Maps team IDs to team data. */ + private TeamData[] map = new TeamData[256]; + /** Active teams. */ + private Array active = new Array<>(); - /** - * Register a team. - * @param team The team type enum. - * @param enemies The array of enemies of this team. Any team not in this array is considered neutral. - */ - public void add(Team team, Team... enemies){ - map[team.ordinal()] = new TeamData(team, EnumSet.of(enemies)); + public @Nullable CoreEntity closestEnemyCore(float x, float y, Team team){ + for(TeamData data : active){ + if(areEnemies(team, data.team)){ + CoreEntity tile = Geometry.findClosest(x, y, data.cores); + if(tile != null){ + return tile; + } + } + } + return null; + } + + public @Nullable CoreEntity closestCore(float x, float y, Team team){ + return Geometry.findClosest(x, y, get(team).cores); + } + + public Array enemiesOf(Team team){ + return get(team).enemies; + } + + public boolean eachEnemyCore(Team team, Boolf ret){ + for(TeamData data : active){ + if(areEnemies(team, data.team)){ + for(CoreEntity tile : data.cores){ + if(ret.get(tile)){ + return true; + } + } + } + } + return false; + } + + public void eachEnemyCore(Team team, Cons ret){ + for(TeamData data : active){ + if(areEnemies(team, data.team)){ + for(TileEntity tile : data.cores){ + ret.get(tile); + } + } + } } /** Returns team data by type. */ public TeamData get(Team team){ - if(map[team.ordinal()] == null){ - add(team, Array.with(Team.all).select(t -> t != team).toArray(Team.class)); + if(map[Pack.u(team.id)] == null){ + map[Pack.u(team.id)] = new TeamData(team); } - return map[team.ordinal()]; + return map[Pack.u(team.id)]; + } + + public Array playerCores(){ + return get(state.rules.defaultTeam).cores; + } + + /** Do not modify! */ + public Array cores(Team team){ + return get(team).cores; } /** Returns whether a team is active, e.g. whether it has any cores remaining. */ public boolean isActive(Team team){ //the enemy wave team is always active - return team == Vars.waveTeam || get(team).cores.size > 0; - } - - /** Returns a set of all teams that are enemies of this team. */ - public EnumSet enemiesOf(Team team){ - return get(team).enemies; + return team == state.rules.waveTeam || get(team).cores.size > 0; } /** Returns whether {@param other} is an enemy of {@param #team}. */ public boolean areEnemies(Team team, Team other){ - return enemiesOf(team).contains(other); + //todo what about derelict? + return team != other; } - /** Allocates a new array with the active teams. - * Never call in the main game loop.*/ + public boolean canInteract(Team team, Team other){ + return team == other || other == Team.derelict; + } + + /** Do not modify. */ public Array getActive(){ - return Array.select(map, t -> t != null); + return active; } - public static class TeamData{ - public final ObjectSet cores = new ObjectSet<>(); - public final EnumSet enemies; + public void registerCore(CoreEntity core){ + TeamData data = get(core.getTeam()); + //add core if not present + if(!data.cores.contains(core)){ + data.cores.add(core); + } + + //register in active list if needed + if(data.active() && !active.contains(data)){ + active.add(data); + updateEnemies(); + indexer.updateTeamIndex(data.team); + } + } + + public void unregisterCore(CoreEntity entity){ + TeamData data = get(entity.getTeam()); + //remove core + data.cores.remove(entity); + //unregister in active list + if(!data.active()){ + active.remove(data); + updateEnemies(); + } + } + + private void updateEnemies(){ + if(!active.contains(get(state.rules.waveTeam))){ + active.add(get(state.rules.waveTeam)); + } + + for(TeamData data : active){ + data.enemies.clear(); + for(TeamData other : active){ + if(areEnemies(data.team, other.team)){ + data.enemies.add(other.team); + } + } + } + } + + public class TeamData{ + public final Array cores = new Array<>(); + public final Array enemies = new Array<>(); public final Team team; public Queue brokenBlocks = new Queue<>(); - public TeamData(Team team, EnumSet enemies){ + public TeamData(Team team){ this.team = team; - this.enemies = enemies; + } + + public boolean active(){ + return team == state.rules.waveTeam || cores.size > 0; + } + + public boolean hasCore(){ + return cores.size > 0; + } + + public boolean noCores(){ + return cores.isEmpty(); + } + + public CoreEntity core(){ + return cores.first(); } } diff --git a/core/src/mindustry/game/Tutorial.java b/core/src/mindustry/game/Tutorial.java index 924e68f63c..4b344bc945 100644 --- a/core/src/mindustry/game/Tutorial.java +++ b/core/src/mindustry/game/Tutorial.java @@ -10,6 +10,7 @@ import arc.scene.ui.*; import arc.scene.ui.layout.*; import arc.util.*; import mindustry.content.*; +import mindustry.entities.type.*; import mindustry.game.EventType.*; import mindustry.graphics.*; import mindustry.type.*; @@ -161,11 +162,11 @@ public class Tutorial{ }, withdraw(() -> event("withdraw")){ void begin(){ - state.teams.get(defaultTeam).cores.first().entity.items.add(Items.copper, 10); + state.teams.playerCores().first().items.add(Items.copper, 10); } }, deposit(() -> event("deposit")), - waves(() -> state.wave > 2 && state.enemies() <= 0 && !spawner.isSpawning()){ + waves(() -> state.wave > 2 && state.enemies <= 0 && !spawner.isSpawning()){ void begin(){ state.rules.waveTimer = true; logic.runWave(); @@ -239,18 +240,18 @@ public class Tutorial{ //utility static void placeBlocks(){ - Tile core = state.teams.get(defaultTeam).cores.first(); + TileEntity core = state.teams.playerCores().first(); for(int i = 0; i < blocksToBreak; i++){ - world.removeBlock(world.ltile(core.x + blockOffset, core.y + i)); - world.tile(core.x + blockOffset, core.y + i).setBlock(Blocks.scrapWall, defaultTeam); + world.ltile(core.tile.x + blockOffset, core.tile.y + i).remove(); + world.tile(core.tile.x + blockOffset, core.tile.y + i).setBlock(Blocks.scrapWall, state.rules.defaultTeam); } } static boolean blocksBroken(){ - Tile core = state.teams.get(defaultTeam).cores.first(); + TileEntity core = state.teams.playerCores().first(); for(int i = 0; i < blocksToBreak; i++){ - if(world.tile(core.x + blockOffset, core.y + i).block() == Blocks.scrapWall){ + if(world.tile(core.tile.x + blockOffset, core.tile.y + i).block() == Blocks.scrapWall){ return false; } } @@ -270,7 +271,7 @@ public class Tutorial{ } static int item(Item item){ - return state.teams.get(defaultTeam).cores.isEmpty() ? 0 : state.teams.get(defaultTeam).cores.first().entity.items.get(item); + return state.rules.defaultTeam.data().noCores() ? 0 : state.rules.defaultTeam.core().items.get(item); } static boolean toggled(String name){ diff --git a/core/src/mindustry/graphics/MinimapRenderer.java b/core/src/mindustry/graphics/MinimapRenderer.java index ffeadc98da..60f3d2974b 100644 --- a/core/src/mindustry/graphics/MinimapRenderer.java +++ b/core/src/mindustry/graphics/MinimapRenderer.java @@ -25,7 +25,7 @@ public class MinimapRenderer implements Disposable{ private Pixmap pixmap; private Texture texture; private TextureRegion region; - private Rectangle rect = new Rectangle(); + private Rect rect = new Rect(); private float zoom = 4; public MinimapRenderer(){ diff --git a/core/src/mindustry/graphics/OverlayRenderer.java b/core/src/mindustry/graphics/OverlayRenderer.java index 3001159c74..c0cd917952 100644 --- a/core/src/mindustry/graphics/OverlayRenderer.java +++ b/core/src/mindustry/graphics/OverlayRenderer.java @@ -10,20 +10,19 @@ import mindustry.*; import mindustry.content.*; import mindustry.entities.*; import mindustry.entities.type.*; -import mindustry.game.*; import mindustry.input.*; -import mindustry.type.Category; -import mindustry.ui.Cicon; +import mindustry.type.*; +import mindustry.ui.*; import mindustry.world.*; -import mindustry.world.blocks.units.MechPad; -import mindustry.world.meta.BlockFlag; +import mindustry.world.blocks.units.*; +import mindustry.world.meta.*; import static mindustry.Vars.*; public class OverlayRenderer{ private static final float indicatorLength = 14f; private static final float spawnerMargin = tilesize*11f; - private static final Rectangle rect = new Rectangle(); + private static final Rect rect = new Rect(); private float buildFadeTime; public void drawBottom(){ @@ -95,17 +94,15 @@ public class OverlayRenderer{ Lines.stroke(buildFadeTime * 2f); if(buildFadeTime > 0.005f){ - for(Team enemy : state.teams.enemiesOf(player.getTeam())){ - for(Tile core : state.teams.get(enemy).cores){ - float dst = Mathf.dst(player.x, player.y, core.drawx(), core.drawy()); - if(dst < state.rules.enemyCoreBuildRadius * 1.5f){ - Draw.color(Color.darkGray); - Lines.circle(core.drawx(), core.drawy() - 2, state.rules.enemyCoreBuildRadius); - Draw.color(Pal.accent, enemy.color, 0.5f + Mathf.absin(Time.time(), 10f, 0.5f)); - Lines.circle(core.drawx(), core.drawy(), state.rules.enemyCoreBuildRadius); - } + state.teams.eachEnemyCore(player.getTeam(), core -> { + float dst = core.dst(player); + if(dst < state.rules.enemyCoreBuildRadius * 1.5f){ + Draw.color(Color.darkGray); + Lines.circle(core.x, core.y - 2, state.rules.enemyCoreBuildRadius); + Draw.color(Pal.accent, core.getTeam().color, 0.5f + Mathf.absin(Time.time(), 10f, 0.5f)); + Lines.circle(core.x, core.y, state.rules.enemyCoreBuildRadius); } - } + }); } Lines.stroke(2f); diff --git a/core/src/mindustry/input/DesktopInput.java b/core/src/mindustry/input/DesktopInput.java index b156c3f7f4..c76968a56e 100644 --- a/core/src/mindustry/input/DesktopInput.java +++ b/core/src/mindustry/input/DesktopInput.java @@ -300,7 +300,7 @@ public class DesktopInput extends InputHandler{ } } - if(Core.input.keyTap(Binding.clear_building)){ + if(Core.input.keyTap(Binding.clear_building) || isPlacing()){ lastSchematic = null; selectRequests.clear(); } @@ -397,7 +397,7 @@ public class DesktopInput extends InputHandler{ } if(mode == placing && block != null){ - if(!overrideLineRotation && !Core.input.keyDown(Binding.diagonal_placement) && (selectX != cursorX || selectY != cursorY) && ((int) Core.input.axisTap(Binding.rotate) != 0)){ + if(!overrideLineRotation && !Core.input.keyDown(Binding.diagonal_placement) && (selectX != cursorX || selectY != cursorY) && ((int)Core.input.axisTap(Binding.rotate) != 0)){ rotation = ((int)((Angles.angle(selectX, selectY, cursorX, cursorY) + 45) / 90f)) % 4; overrideLineRotation = true; } diff --git a/core/src/mindustry/input/InputHandler.java b/core/src/mindustry/input/InputHandler.java index 2a4ce0343f..4a6ffb575b 100644 --- a/core/src/mindustry/input/InputHandler.java +++ b/core/src/mindustry/input/InputHandler.java @@ -44,7 +44,7 @@ public abstract class InputHandler implements InputProcessor, GestureListener{ /** Maximum line length. */ final static int maxLength = 100; final static Vec2 stackTrns = new Vec2(); - final static Rectangle r1 = new Rectangle(), r2 = new Rectangle(); + final static Rect r1 = new Rect(), r2 = new Rect(); /** Distance on the back from where items originate. */ final static float backTrns = 3f; @@ -402,7 +402,7 @@ public abstract class InputHandler implements InputProcessor, GestureListener{ } } - for(BrokenBlock req : state.teams.get(player.getTeam()).brokenBlocks){ + for(BrokenBlock req : player.getTeam().data().brokenBlocks){ Block block = content.block(req.block); if(block.bounds(req.x, req.y, Tmp.r2).overlaps(Tmp.r1)){ drawSelected(req.x, req.y, content.block(req.block), Pal.remove); diff --git a/core/src/mindustry/input/MobileInput.java b/core/src/mindustry/input/MobileInput.java index 5379caf113..81f657c876 100644 --- a/core/src/mindustry/input/MobileInput.java +++ b/core/src/mindustry/input/MobileInput.java @@ -77,7 +77,7 @@ public class MobileInput extends InputHandler implements GestureListener{ }else{ Tile tile = world.ltileWorld(x, y); - if(tile != null && tile.synthetic() && state.teams.areEnemies(player.getTeam(), tile.getTeam())){ + if(tile != null && tile.synthetic() && player.getTeam().isEnemy(tile.getTeam())){ TileEntity entity = tile.entity; player.setMineTile(null); player.target = entity; diff --git a/core/src/mindustry/io/JsonIO.java b/core/src/mindustry/io/JsonIO.java index 7c570bace8..ef37dd9d65 100644 --- a/core/src/mindustry/io/JsonIO.java +++ b/core/src/mindustry/io/JsonIO.java @@ -20,7 +20,7 @@ public class JsonIO{ @Override public void writeValue(Object value, Class knownType, Class elementType){ - if(value instanceof mindustry.ctype.MappableContent){ + if(value instanceof MappableContent){ try{ getWriter().value(((MappableContent)value).name); }catch(IOException e){ @@ -95,6 +95,18 @@ public class JsonIO{ } }); + json.setSerializer(Team.class, new Serializer(){ + @Override + public void write(Json json, Team object, Class knownType){ + json.writeValue(object.id); + } + + @Override + public Team read(Json json, JsonValue jsonData, Class type){ + return Team.get(jsonData.asInt()); + } + }); + json.setSerializer(Block.class, new Serializer(){ @Override public void write(Json json, Block object, Class knownType){ diff --git a/core/src/mindustry/io/LegacyMapIO.java b/core/src/mindustry/io/LegacyMapIO.java deleted file mode 100644 index d3f975e821..0000000000 --- a/core/src/mindustry/io/LegacyMapIO.java +++ /dev/null @@ -1,214 +0,0 @@ -package mindustry.io; - -import arc.struct.*; -import arc.files.*; -import arc.graphics.*; -import arc.util.*; -import arc.util.serialization.*; -import mindustry.content.*; -import mindustry.ctype.ContentType; -import mindustry.game.*; -import mindustry.io.MapIO.*; -import mindustry.maps.*; -import mindustry.world.*; -import mindustry.world.LegacyColorMapper.*; -import mindustry.world.blocks.*; - -import java.io.*; -import java.util.zip.*; - -import static mindustry.Vars.*; - -/** Map IO for the "old" .mmap format. - * Differentiate between legacy maps and new maps by checking the extension (or the header).*/ -public class LegacyMapIO{ - private static final ObjectMap fallback = ObjectMap.of("alpha-dart-mech-pad", "dart-mech-pad"); - private static final Json json = new Json(); - - /* Convert a map from the old format to the new format. */ - public static void convertMap(Fi in, Fi out) throws IOException{ - Map map = readMap(in, true); - - String waves = map.tags.get("waves", "[]"); - Array groups = new Array<>(json.fromJson(SpawnGroup[].class, waves)); - - Tile[][] tiles = world.createTiles(map.width, map.height); - for(int x = 0; x < map.width; x++){ - for(int y = 0; y < map.height; y++){ - tiles[x][y] = new CachedTile(); - tiles[x][y].x = (short)x; - tiles[x][y].y = (short)y; - } - } - state.rules.spawns = groups; - readTiles(map, tiles); - MapIO.writeMap(out, map); - } - - public static Map readMap(Fi file, boolean custom) throws IOException{ - try(DataInputStream stream = new DataInputStream(file.read(1024))){ - StringMap tags = new StringMap(); - - //meta is uncompressed - int version = stream.readInt(); - if(version != 1){ - throw new IOException("Outdated legacy map format"); - } - int build = stream.readInt(); - short width = stream.readShort(), height = stream.readShort(); - byte tagAmount = stream.readByte(); - - for(int i = 0; i < tagAmount; i++){ - String name = stream.readUTF(); - String value = stream.readUTF(); - tags.put(name, value); - } - - return new Map(file, width, height, tags, custom, version, build); - } - } - - public static void readTiles(Map map, Tile[][] tiles) throws IOException{ - readTiles(map, (x, y) -> tiles[x][y]); - } - - public static void readTiles(Map map, TileProvider tiles) throws IOException{ - readTiles(map.file, map.width, map.height, tiles); - } - - private static void readTiles(Fi file, int width, int height, Tile[][] tiles) throws IOException{ - readTiles(file, width, height, (x, y) -> tiles[x][y]); - } - - private static void readTiles(Fi file, int width, int height, TileProvider tiles) throws IOException{ - try(BufferedInputStream input = file.read(bufferSize)){ - - //read map - { - DataInputStream stream = new DataInputStream(input); - - stream.readInt(); //version - stream.readInt(); //build - stream.readInt(); //width + height - byte tagAmount = stream.readByte(); - - for(int i = 0; i < tagAmount; i++){ - stream.readUTF(); //key - stream.readUTF(); //val - } - } - - try(DataInputStream stream = new DataInputStream(new InflaterInputStream(input))){ - - try{ - byte mapped = stream.readByte(); - IntMap idmap = new IntMap<>(); - IntMap namemap = new IntMap<>(); - - for(int i = 0; i < mapped; i++){ - byte type = stream.readByte(); - short total = stream.readShort(); - - for(int j = 0; j < total; j++){ - String name = stream.readUTF(); - if(type == 1){ - Block res = content.getByName(ContentType.block, fallback.get(name, name)); - idmap.put(j, res == null ? Blocks.air : res); - namemap.put(j, fallback.get(name, name)); - } - } - } - - //read floor and create tiles first - for(int i = 0; i < width * height; i++){ - int x = i % width, y = i / width; - int floorid = stream.readUnsignedByte(); - int oreid = stream.readUnsignedByte(); - int consecutives = stream.readUnsignedByte(); - - Tile tile = tiles.get(x, y); - tile.setFloor((Floor)idmap.get(floorid)); - tile.setOverlay(idmap.get(oreid)); - - for(int j = i + 1; j < i + 1 + consecutives; j++){ - int newx = j % width, newy = j / width; - Tile newTile = tiles.get(newx, newy); - newTile.setFloor((Floor)idmap.get(floorid)); - newTile.setOverlay(idmap.get(oreid)); - } - - i += consecutives; - } - - //read blocks - for(int i = 0; i < width * height; i++){ - int x = i % width, y = i / width; - int id = stream.readUnsignedByte(); - Block block = idmap.get(id); - if(block == null) block = Blocks.air; - - Tile tile = tiles.get(x, y); - //the spawn block is saved in the block tile layer in older maps, shift it to the overlay - if(block != Blocks.spawn){ - tile.setBlock(block); - }else{ - tile.setOverlay(block); - } - - if(namemap.get(id, "").equals("part")){ - stream.readByte(); //link - }else if(tile.entity != null){ - byte tr = stream.readByte(); - stream.readShort(); //read health (which is actually irrelevant) - - byte team = Pack.leftByte(tr); - byte rotation = Pack.rightByte(tr); - - tile.setTeam(Team.all[team]); - tile.entity.health = tile.block().health; - tile.rotation(rotation); - - if(tile.block() == Blocks.liquidSource || tile.block() == Blocks.unloader || tile.block() == Blocks.sorter){ - stream.readByte(); //these blocks have an extra config byte, read it - } - }else{ //no entity/part, read consecutives - int consecutives = stream.readUnsignedByte(); - - for(int j = i + 1; j < i + 1 + consecutives; j++){ - int newx = j % width, newy = j / width; - tiles.get(newx, newy).setBlock(block); - } - - i += consecutives; - } - } - - }finally{ - content.setTemporaryMapper(null); - } - } - } - } - - /** Reads a pixmap in the 3.5 pixmap format. */ - public static void readPixmap(Pixmap pixmap, Tile[][] tiles){ - for(int x = 0; x < pixmap.getWidth(); x++){ - for(int y = 0; y < pixmap.getHeight(); y++){ - int color = pixmap.getPixel(x, pixmap.getHeight() - 1 - y); - LegacyBlock block = LegacyColorMapper.get(color); - Tile tile = tiles[x][y]; - - tile.setFloor(block.floor); - tile.setBlock(block.wall); - if(block.ore != null) tile.setOverlay(block.ore); - - //place core - if(color == Color.rgba8888(Color.green)){ - //actual core parts - tile.setBlock(Blocks.coreShard); - tile.setTeam(Team.sharded); - } - } - } - } -} diff --git a/core/src/mindustry/io/MapIO.java b/core/src/mindustry/io/MapIO.java index 88c011442b..85c5cc9cb7 100644 --- a/core/src/mindustry/io/MapIO.java +++ b/core/src/mindustry/io/MapIO.java @@ -10,6 +10,7 @@ import mindustry.core.*; import mindustry.game.*; import mindustry.maps.*; import mindustry.world.*; +import mindustry.world.LegacyColorMapper.*; import mindustry.world.blocks.storage.*; import java.io.*; @@ -91,7 +92,7 @@ public class MapIO{ public void setTeam(Team team){ super.setTeam(team); if(block instanceof CoreBlock){ - map.teams.add(team.ordinal()); + map.teams.add(team.id); } } }; @@ -145,11 +146,33 @@ public class MapIO{ public static int colorFor(Block floor, Block wall, Block ore, Team team){ if(wall.synthetic()){ - return team.intColor; + return team.color.rgba(); } return Color.rgba8888(wall.solid ? wall.color : ore == Blocks.air ? floor.color : ore.color); } + /** Reads a pixmap in the 3.5 pixmap format. */ + public static void readPixmap(Pixmap pixmap, Tile[][] tiles){ + for(int x = 0; x < pixmap.getWidth(); x++){ + for(int y = 0; y < pixmap.getHeight(); y++){ + int color = pixmap.getPixel(x, pixmap.getHeight() - 1 - y); + LegacyBlock block = LegacyColorMapper.get(color); + Tile tile = tiles[x][y]; + + tile.setFloor(block.floor); + tile.setBlock(block.wall); + if(block.ore != null) tile.setOverlay(block.ore); + + //place core + if(color == Color.rgba8888(Color.green)){ + //actual core parts + tile.setBlock(Blocks.coreShard); + tile.setTeam(Team.sharded); + } + } + } + } + interface TileProvider{ Tile get(int x, int y); } diff --git a/core/src/mindustry/io/SaveVersion.java b/core/src/mindustry/io/SaveVersion.java index ba9a991e05..06c75bc878 100644 --- a/core/src/mindustry/io/SaveVersion.java +++ b/core/src/mindustry/io/SaveVersion.java @@ -217,7 +217,7 @@ public abstract class SaveVersion extends SaveFileReader{ Array data = state.teams.getActive(); stream.writeInt(data.size); for(TeamData team : data){ - stream.writeInt(team.team.ordinal()); + stream.writeInt((int)team.team.id); stream.writeInt(team.brokenBlocks.size); for(BrokenBlock block : team.brokenBlocks){ stream.writeShort(block.x); @@ -258,8 +258,8 @@ public abstract class SaveVersion extends SaveFileReader{ public void readEntities(DataInput stream) throws IOException{ int teamc = stream.readInt(); for(int i = 0; i < teamc; i++){ - Team team = Team.all[stream.readInt()]; - TeamData data = state.teams.get(team); + Team team = Team.get(stream.readInt()); + TeamData data = team.data(); int blocks = stream.readInt(); for(int j = 0; j < blocks; j++){ data.brokenBlocks.addLast(new BrokenBlock(stream.readShort(), stream.readShort(), stream.readShort(), content.block(stream.readShort()).id, stream.readInt())); diff --git a/core/src/mindustry/io/TypeIO.java b/core/src/mindustry/io/TypeIO.java index 4e9c4b5024..5095ce396a 100644 --- a/core/src/mindustry/io/TypeIO.java +++ b/core/src/mindustry/io/TypeIO.java @@ -87,7 +87,7 @@ public class TypeIO{ @WriteClass(BaseUnit.class) public static void writeBaseUnit(ByteBuffer buffer, BaseUnit unit){ - buffer.put((byte)unit.getTeam().ordinal()); + buffer.put((byte) (int)unit.getTeam().id); buffer.putInt(unit.getID()); } @@ -95,7 +95,7 @@ public class TypeIO{ public static BaseUnit readBaseUnit(ByteBuffer buffer){ byte tid = buffer.get(); int id = buffer.getInt(); - return unitGroups[tid].getByID(id); + return unitGroup.getByID(id); } @WriteClass(Tile.class) @@ -194,12 +194,12 @@ public class TypeIO{ @WriteClass(Team.class) public static void writeTeam(ByteBuffer buffer, Team reason){ - buffer.put((byte)reason.ordinal()); + buffer.put((byte) (int)reason.id); } @ReadClass(Team.class) public static Team readTeam(ByteBuffer buffer){ - return Team.all[buffer.get()]; + return Team.get(buffer.get()); } @WriteClass(UnitCommand.class) diff --git a/core/src/mindustry/maps/generators/MapGenerator.java b/core/src/mindustry/maps/generators/MapGenerator.java index c0083c4738..69c11bdc7b 100644 --- a/core/src/mindustry/maps/generators/MapGenerator.java +++ b/core/src/mindustry/maps/generators/MapGenerator.java @@ -74,7 +74,7 @@ public class MapGenerator extends Generator{ for(int x = 0; x < width; x++){ for(int y = 0; y < height; y++){ - if(tiles[x][y].block() instanceof CoreBlock && tiles[x][y].getTeam() == defaultTeam){ + if(tiles[x][y].block() instanceof CoreBlock && tiles[x][y].getTeam() == state.rules.defaultTeam){ players.add(new Point2(x, y)); tiles[x][y].setBlock(Blocks.air); } diff --git a/core/src/mindustry/mod/ClassAccess.java b/core/src/mindustry/mod/ClassAccess.java index 62f089a107..06ff74766c 100644 --- a/core/src/mindustry/mod/ClassAccess.java +++ b/core/src/mindustry/mod/ClassAccess.java @@ -3,5 +3,5 @@ package mindustry.mod; import arc.struct.*; //obviously autogenerated, do not touch public class ClassAccess{ - public static final ObjectSet allowedClassNames = ObjectSet.with("arc.Core", "arc.func.Boolc", "arc.func.Boolf", "arc.func.Boolf2", "arc.func.Boolp", "arc.func.Cons", "arc.func.Cons2", "arc.func.Floatc", "arc.func.Floatc2", "arc.func.Floatc4", "arc.func.Floatf", "arc.func.Floatp", "arc.func.Func", "arc.func.Func2", "arc.func.Func3", "arc.func.Intc", "arc.func.Intc2", "arc.func.Intc4", "arc.func.Intf", "arc.func.Intp", "arc.func.Prov", "arc.graphics.Color", "arc.graphics.Pixmap", "arc.graphics.Texture", "arc.graphics.TextureData", "arc.graphics.g2d.Draw", "arc.graphics.g2d.Fill", "arc.graphics.g2d.Lines", "arc.graphics.g2d.TextureAtlas", "arc.graphics.g2d.TextureAtlas$AtlasRegion", "arc.graphics.g2d.TextureRegion", "arc.math.Angles", "arc.math.Mathf", "arc.scene.Action", "arc.scene.Element", "arc.scene.Group", "arc.scene.Scene", "arc.scene.actions.Actions", "arc.scene.actions.AddAction", "arc.scene.actions.AddListenerAction", "arc.scene.actions.AfterAction", "arc.scene.actions.AlphaAction", "arc.scene.actions.ColorAction", "arc.scene.actions.DelayAction", "arc.scene.actions.DelegateAction", "arc.scene.actions.FloatAction", "arc.scene.actions.IntAction", "arc.scene.actions.LayoutAction", "arc.scene.actions.MoveByAction", "arc.scene.actions.MoveToAction", "arc.scene.actions.OriginAction", "arc.scene.actions.ParallelAction", "arc.scene.actions.RelativeTemporalAction", "arc.scene.actions.RemoveAction", "arc.scene.actions.RemoveActorAction", "arc.scene.actions.RemoveListenerAction", "arc.scene.actions.RepeatAction", "arc.scene.actions.RotateByAction", "arc.scene.actions.RotateToAction", "arc.scene.actions.RunnableAction", "arc.scene.actions.ScaleByAction", "arc.scene.actions.ScaleToAction", "arc.scene.actions.SequenceAction", "arc.scene.actions.SizeByAction", "arc.scene.actions.SizeToAction", "arc.scene.actions.TemporalAction", "arc.scene.actions.TimeScaleAction", "arc.scene.actions.TouchableAction", "arc.scene.actions.TranslateByAction", "arc.scene.actions.VisibleAction", "arc.scene.event.ChangeListener", "arc.scene.event.ChangeListener$ChangeEvent", "arc.scene.event.ClickListener", "arc.scene.event.DragListener", "arc.scene.event.DragScrollListener", "arc.scene.event.ElementGestureListener", "arc.scene.event.EventListener", "arc.scene.event.FocusListener", "arc.scene.event.FocusListener$FocusEvent", "arc.scene.event.FocusListener$FocusEvent$Type", "arc.scene.event.HandCursorListener", "arc.scene.event.IbeamCursorListener", "arc.scene.event.InputEvent", "arc.scene.event.InputEvent$Type", "arc.scene.event.InputListener", "arc.scene.event.SceneEvent", "arc.scene.event.Touchable", "arc.scene.event.VisibilityEvent", "arc.scene.event.VisibilityListener", "arc.scene.style.BaseDrawable", "arc.scene.style.Drawable", "arc.scene.style.NinePatchDrawable", "arc.scene.style.ScaledNinePatchDrawable", "arc.scene.style.Style", "arc.scene.style.TextureRegionDrawable", "arc.scene.style.TiledDrawable", "arc.scene.style.TransformDrawable", "arc.scene.ui.Button", "arc.scene.ui.Button$ButtonStyle", "arc.scene.ui.ButtonGroup", "arc.scene.ui.CheckBox", "arc.scene.ui.CheckBox$CheckBoxStyle", "arc.scene.ui.ColorImage", "arc.scene.ui.Dialog", "arc.scene.ui.Dialog$DialogStyle", "arc.scene.ui.Image", "arc.scene.ui.ImageButton", "arc.scene.ui.ImageButton$ImageButtonStyle", "arc.scene.ui.KeybindDialog", "arc.scene.ui.KeybindDialog$KeybindDialogStyle", "arc.scene.ui.Label", "arc.scene.ui.Label$LabelStyle", "arc.scene.ui.ProgressBar", "arc.scene.ui.ProgressBar$ProgressBarStyle", "arc.scene.ui.ScrollPane", "arc.scene.ui.ScrollPane$ScrollPaneStyle", "arc.scene.ui.SettingsDialog", "arc.scene.ui.SettingsDialog$SettingsTable", "arc.scene.ui.SettingsDialog$SettingsTable$CheckSetting", "arc.scene.ui.SettingsDialog$SettingsTable$Setting", "arc.scene.ui.SettingsDialog$SettingsTable$SliderSetting", "arc.scene.ui.SettingsDialog$StringProcessor", "arc.scene.ui.Slider", "arc.scene.ui.Slider$SliderStyle", "arc.scene.ui.TextArea", "arc.scene.ui.TextArea$TextAreaListener", "arc.scene.ui.TextButton", "arc.scene.ui.TextButton$TextButtonStyle", "arc.scene.ui.TextField", "arc.scene.ui.TextField$DefaultOnscreenKeyboard", "arc.scene.ui.TextField$OnscreenKeyboard", "arc.scene.ui.TextField$TextFieldClickListener", "arc.scene.ui.TextField$TextFieldFilter", "arc.scene.ui.TextField$TextFieldListener", "arc.scene.ui.TextField$TextFieldStyle", "arc.scene.ui.TextField$TextFieldValidator", "arc.scene.ui.Tooltip", "arc.scene.ui.Tooltip$Tooltips", "arc.scene.ui.Touchpad", "arc.scene.ui.Touchpad$TouchpadStyle", "arc.scene.ui.TreeElement", "arc.scene.ui.TreeElement$Node", "arc.scene.ui.TreeElement$TreeStyle", "arc.scene.ui.layout.Cell", "arc.scene.ui.layout.Collapser", "arc.scene.ui.layout.HorizontalGroup", "arc.scene.ui.layout.Scl", "arc.scene.ui.layout.Stack", "arc.scene.ui.layout.Table", "arc.scene.ui.layout.Table$DrawRect", "arc.scene.ui.layout.VerticalGroup", "arc.scene.ui.layout.WidgetGroup", "arc.scene.utils.ArraySelection", "arc.scene.utils.Cullable", "arc.scene.utils.Disableable", "arc.scene.utils.DragAndDrop", "arc.scene.utils.DragAndDrop$Payload", "arc.scene.utils.DragAndDrop$Source", "arc.scene.utils.DragAndDrop$Target", "arc.scene.utils.Elements", "arc.scene.utils.Layout", "arc.scene.utils.Selection", "arc.struct.Array", "arc.struct.Array$ArrayIterable", "arc.struct.ArrayMap", "arc.struct.ArrayMap$Entries", "arc.struct.ArrayMap$Keys", "arc.struct.ArrayMap$Values", "arc.struct.AtomicQueue", "arc.struct.BinaryHeap", "arc.struct.BinaryHeap$Node", "arc.struct.Bits", "arc.struct.BooleanArray", "arc.struct.ByteArray", "arc.struct.CharArray", "arc.struct.ComparableTimSort", "arc.struct.DelayedRemovalArray", "arc.struct.EnumSet", "arc.struct.EnumSet$EnumSetIterator", "arc.struct.FloatArray", "arc.struct.GridBits", "arc.struct.GridMap", "arc.struct.IdentityMap", "arc.struct.IdentityMap$Entries", "arc.struct.IdentityMap$Entry", "arc.struct.IdentityMap$Keys", "arc.struct.IdentityMap$Values", "arc.struct.IntArray", "arc.struct.IntFloatMap", "arc.struct.IntFloatMap$Entries", "arc.struct.IntFloatMap$Entry", "arc.struct.IntFloatMap$Keys", "arc.struct.IntFloatMap$Values", "arc.struct.IntIntMap", "arc.struct.IntIntMap$Entries", "arc.struct.IntIntMap$Entry", "arc.struct.IntIntMap$Keys", "arc.struct.IntIntMap$Values", "arc.struct.IntMap", "arc.struct.IntMap$Entries", "arc.struct.IntMap$Entry", "arc.struct.IntMap$Keys", "arc.struct.IntMap$Values", "arc.struct.IntQueue", "arc.struct.IntSet", "arc.struct.IntSet$IntSetIterator", "arc.struct.LongArray", "arc.struct.LongMap", "arc.struct.LongMap$Entries", "arc.struct.LongMap$Entry", "arc.struct.LongMap$Keys", "arc.struct.LongMap$Values", "arc.struct.LongQueue", "arc.struct.ObjectFloatMap", "arc.struct.ObjectFloatMap$Entries", "arc.struct.ObjectFloatMap$Entry", "arc.struct.ObjectFloatMap$Keys", "arc.struct.ObjectFloatMap$Values", "arc.struct.ObjectIntMap", "arc.struct.ObjectIntMap$Entries", "arc.struct.ObjectIntMap$Entry", "arc.struct.ObjectIntMap$Keys", "arc.struct.ObjectIntMap$Values", "arc.struct.ObjectMap", "arc.struct.ObjectMap$Entries", "arc.struct.ObjectMap$Entry", "arc.struct.ObjectMap$Keys", "arc.struct.ObjectMap$Values", "arc.struct.ObjectSet", "arc.struct.ObjectSet$ObjectSetIterator", "arc.struct.OrderedMap", "arc.struct.OrderedMap$OrderedMapEntries", "arc.struct.OrderedMap$OrderedMapKeys", "arc.struct.OrderedMap$OrderedMapValues", "arc.struct.OrderedSet", "arc.struct.OrderedSet$OrderedSetIterator", "arc.struct.PooledLinkedList", "arc.struct.PooledLinkedList$Item", "arc.struct.Queue", "arc.struct.Queue$QueueIterable", "arc.struct.ShortArray", "arc.struct.SnapshotArray", "arc.struct.Sort", "arc.struct.SortedIntList", "arc.struct.SortedIntList$Iterator", "arc.struct.SortedIntList$Node", "arc.struct.StringMap", "arc.struct.TimSort", "arc.util.I18NBundle", "arc.util.Time", "java.io.PrintStream", "java.lang.Object", "java.lang.Runnable", "java.lang.String", "java.lang.System", "mindustry.Vars", "mindustry.ai.BlockIndexer", "mindustry.ai.Pathfinder", "mindustry.ai.Pathfinder$PathData", "mindustry.ai.Pathfinder$PathTarget", "mindustry.ai.Pathfinder$PathTileStruct", "mindustry.ai.WaveSpawner", "mindustry.content.Blocks", "mindustry.content.Bullets", "mindustry.content.Fx", "mindustry.content.Items", "mindustry.content.Liquids", "mindustry.content.Loadouts", "mindustry.content.Mechs", "mindustry.content.StatusEffects", "mindustry.content.TechTree", "mindustry.content.TechTree$TechNode", "mindustry.content.TypeIDs", "mindustry.content.UnitTypes", "mindustry.content.Zones", "mindustry.core.ContentLoader", "mindustry.core.Control", "mindustry.core.FileTree", "mindustry.core.GameState", "mindustry.core.GameState$State", "mindustry.core.Logic", "mindustry.core.Platform", "mindustry.core.Renderer", "mindustry.core.UI", "mindustry.core.Version", "mindustry.core.World", "mindustry.core.World$Raycaster", "mindustry.ctype.Content", "mindustry.ctype.Content$ModContentInfo", "mindustry.ctype.ContentList", "mindustry.ctype.ContentType", "mindustry.ctype.MappableContent", "mindustry.ctype.UnlockableContent", "mindustry.editor.DrawOperation", "mindustry.editor.DrawOperation$OpType", "mindustry.editor.DrawOperation$TileOpStruct", "mindustry.editor.EditorTile", "mindustry.editor.EditorTool", "mindustry.editor.MapEditor", "mindustry.editor.MapEditor$Context", "mindustry.editor.MapEditorDialog", "mindustry.editor.MapGenerateDialog", "mindustry.editor.MapInfoDialog", "mindustry.editor.MapLoadDialog", "mindustry.editor.MapRenderer", "mindustry.editor.MapResizeDialog", "mindustry.editor.MapSaveDialog", "mindustry.editor.MapView", "mindustry.editor.OperationStack", "mindustry.editor.WaveInfoDialog", "mindustry.entities.Damage", "mindustry.entities.Damage$PropCellStruct", "mindustry.entities.Effects", "mindustry.entities.Effects$Effect", "mindustry.entities.Effects$EffectContainer", "mindustry.entities.Effects$EffectProvider", "mindustry.entities.Effects$EffectRenderer", "mindustry.entities.Effects$ScreenshakeProvider", "mindustry.entities.Entities", "mindustry.entities.EntityCollisions", "mindustry.entities.EntityGroup", "mindustry.entities.Predict", "mindustry.entities.TargetPriority", "mindustry.entities.Units", "mindustry.entities.bullet.ArtilleryBulletType", "mindustry.entities.bullet.BasicBulletType", "mindustry.entities.bullet.BombBulletType", "mindustry.entities.bullet.BulletType", "mindustry.entities.bullet.FlakBulletType", "mindustry.entities.bullet.HealBulletType", "mindustry.entities.bullet.LiquidBulletType", "mindustry.entities.bullet.MassDriverBolt", "mindustry.entities.bullet.MissileBulletType", "mindustry.entities.effect.Decal", "mindustry.entities.effect.Fire", "mindustry.entities.effect.GroundEffectEntity", "mindustry.entities.effect.GroundEffectEntity$GroundEffect", "mindustry.entities.effect.ItemTransfer", "mindustry.entities.effect.Lightning", "mindustry.entities.effect.Puddle", "mindustry.entities.effect.RubbleDecal", "mindustry.entities.effect.ScorchDecal", "mindustry.entities.traits.AbsorbTrait", "mindustry.entities.traits.BelowLiquidTrait", "mindustry.entities.traits.BuilderMinerTrait", "mindustry.entities.traits.BuilderTrait", "mindustry.entities.traits.BuilderTrait$BuildDataStatic", "mindustry.entities.traits.BuilderTrait$BuildRequest", "mindustry.entities.traits.DamageTrait", "mindustry.entities.traits.DrawTrait", "mindustry.entities.traits.Entity", "mindustry.entities.traits.HealthTrait", "mindustry.entities.traits.KillerTrait", "mindustry.entities.traits.MinerTrait", "mindustry.entities.traits.MoveTrait", "mindustry.entities.traits.SaveTrait", "mindustry.entities.traits.Saveable", "mindustry.entities.traits.ScaleTrait", "mindustry.entities.traits.ShooterTrait", "mindustry.entities.traits.SolidTrait", "mindustry.entities.traits.SpawnerTrait", "mindustry.entities.traits.SyncTrait", "mindustry.entities.traits.TargetTrait", "mindustry.entities.traits.TeamTrait", "mindustry.entities.traits.TimeTrait", "mindustry.entities.traits.TypeTrait", "mindustry.entities.traits.VelocityTrait", "mindustry.entities.type.BaseEntity", "mindustry.entities.type.BaseUnit", "mindustry.entities.type.Bullet", "mindustry.entities.type.DestructibleEntity", "mindustry.entities.type.EffectEntity", "mindustry.entities.type.Player", "mindustry.entities.type.SolidEntity", "mindustry.entities.type.TileEntity", "mindustry.entities.type.TimedEntity", "mindustry.entities.type.Unit", "mindustry.entities.type.base.BaseDrone", "mindustry.entities.type.base.BuilderDrone", "mindustry.entities.type.base.FlyingUnit", "mindustry.entities.type.base.GroundUnit", "mindustry.entities.type.base.HoverUnit", "mindustry.entities.type.base.MinerDrone", "mindustry.entities.type.base.RepairDrone", "mindustry.entities.units.StateMachine", "mindustry.entities.units.Statuses", "mindustry.entities.units.Statuses$StatusEntry", "mindustry.entities.units.UnitCommand", "mindustry.entities.units.UnitDrops", "mindustry.entities.units.UnitState", "mindustry.game.DefaultWaves", "mindustry.game.Difficulty", "mindustry.game.EventType", "mindustry.game.EventType$BlockBuildBeginEvent", "mindustry.game.EventType$BlockBuildEndEvent", "mindustry.game.EventType$BlockDestroyEvent", "mindustry.game.EventType$BlockInfoEvent", "mindustry.game.EventType$BuildSelectEvent", "mindustry.game.EventType$ClientLoadEvent", "mindustry.game.EventType$CommandIssueEvent", "mindustry.game.EventType$ContentReloadEvent", "mindustry.game.EventType$CoreItemDeliverEvent", "mindustry.game.EventType$DepositEvent", "mindustry.game.EventType$DisposeEvent", "mindustry.game.EventType$GameOverEvent", "mindustry.game.EventType$LaunchEvent", "mindustry.game.EventType$LaunchItemEvent", "mindustry.game.EventType$LineConfirmEvent", "mindustry.game.EventType$LoseEvent", "mindustry.game.EventType$MapMakeEvent", "mindustry.game.EventType$MapPublishEvent", "mindustry.game.EventType$MechChangeEvent", "mindustry.game.EventType$PlayEvent", "mindustry.game.EventType$PlayerBanEvent", "mindustry.game.EventType$PlayerChatEvent", "mindustry.game.EventType$PlayerConnect", "mindustry.game.EventType$PlayerIpBanEvent", "mindustry.game.EventType$PlayerIpUnbanEvent", "mindustry.game.EventType$PlayerJoin", "mindustry.game.EventType$PlayerLeave", "mindustry.game.EventType$PlayerUnbanEvent", "mindustry.game.EventType$ResearchEvent", "mindustry.game.EventType$ResetEvent", "mindustry.game.EventType$ResizeEvent", "mindustry.game.EventType$ServerLoadEvent", "mindustry.game.EventType$StateChangeEvent", "mindustry.game.EventType$TapConfigEvent", "mindustry.game.EventType$TapEvent", "mindustry.game.EventType$TileChangeEvent", "mindustry.game.EventType$Trigger", "mindustry.game.EventType$TurretAmmoDeliverEvent", "mindustry.game.EventType$UnitCreateEvent", "mindustry.game.EventType$UnitDestroyEvent", "mindustry.game.EventType$UnlockEvent", "mindustry.game.EventType$WaveEvent", "mindustry.game.EventType$WinEvent", "mindustry.game.EventType$WithdrawEvent", "mindustry.game.EventType$WorldLoadEvent", "mindustry.game.EventType$ZoneConfigureCompleteEvent", "mindustry.game.EventType$ZoneRequireCompleteEvent", "mindustry.game.Gamemode", "mindustry.game.GlobalData", "mindustry.game.LoopControl", "mindustry.game.MusicControl", "mindustry.game.Objective", "mindustry.game.Objectives", "mindustry.game.Objectives$Launched", "mindustry.game.Objectives$Unlock", "mindustry.game.Objectives$Wave", "mindustry.game.Objectives$ZoneObjective", "mindustry.game.Objectives$ZoneWave", "mindustry.game.Rules", "mindustry.game.Saves", "mindustry.game.Saves$SaveSlot", "mindustry.game.Schematic", "mindustry.game.Schematic$Stile", "mindustry.game.Schematics", "mindustry.game.SoundLoop", "mindustry.game.SpawnGroup", "mindustry.game.Stats", "mindustry.game.Stats$Rank", "mindustry.game.Stats$RankResult", "mindustry.game.Team", "mindustry.game.Teams", "mindustry.game.Teams$BrokenBlock", "mindustry.game.Teams$TeamData", "mindustry.game.Tutorial", "mindustry.game.Tutorial$TutorialStage", "mindustry.gen.BufferItem", "mindustry.gen.Call", "mindustry.gen.Call", "mindustry.gen.Icon", "mindustry.gen.Icon", "mindustry.gen.MethodHash", "mindustry.gen.Musics", "mindustry.gen.Musics", "mindustry.gen.PathTile", "mindustry.gen.PropCell", "mindustry.gen.RemoteReadClient", "mindustry.gen.RemoteReadServer", "mindustry.gen.Serialization", "mindustry.gen.Sounds", "mindustry.gen.Sounds", "mindustry.gen.Tex", "mindustry.gen.Tex", "mindustry.gen.TileOp", "mindustry.graphics.BlockRenderer", "mindustry.graphics.Bloom", "mindustry.graphics.CacheLayer", "mindustry.graphics.Drawf", "mindustry.graphics.FloorRenderer", "mindustry.graphics.IndexedRenderer", "mindustry.graphics.Layer", "mindustry.graphics.LightRenderer", "mindustry.graphics.MenuRenderer", "mindustry.graphics.MinimapRenderer", "mindustry.graphics.MultiPacker", "mindustry.graphics.MultiPacker$PageType", "mindustry.graphics.OverlayRenderer", "mindustry.graphics.Pal", "mindustry.graphics.Pixelator", "mindustry.graphics.Shaders", "mindustry.input.Binding", "mindustry.input.DesktopInput", "mindustry.input.InputHandler", "mindustry.input.InputHandler$PlaceLine", "mindustry.input.MobileInput", "mindustry.input.PlaceMode", "mindustry.input.Placement", "mindustry.input.Placement$DistanceHeuristic", "mindustry.input.Placement$NormalizeDrawResult", "mindustry.input.Placement$NormalizeResult", "mindustry.input.Placement$TileHueristic", "mindustry.maps.Map", "mindustry.maps.Maps", "mindustry.maps.Maps$MapProvider", "mindustry.maps.Maps$ShuffleMode", "mindustry.maps.Maps$ShuffleMode", "mindustry.maps.filters.BlendFilter", "mindustry.maps.filters.ClearFilter", "mindustry.maps.filters.DistortFilter", "mindustry.maps.filters.FilterOption", "mindustry.maps.filters.FilterOption$BlockOption", "mindustry.maps.filters.FilterOption$SliderOption", "mindustry.maps.filters.GenerateFilter", "mindustry.maps.filters.GenerateFilter$GenerateInput", "mindustry.maps.filters.GenerateFilter$GenerateInput$TileProvider", "mindustry.maps.filters.MedianFilter", "mindustry.maps.filters.MirrorFilter", "mindustry.maps.filters.NoiseFilter", "mindustry.maps.filters.OreFilter", "mindustry.maps.filters.OreMedianFilter", "mindustry.maps.filters.RiverNoiseFilter", "mindustry.maps.filters.ScatterFilter", "mindustry.maps.filters.TerrainFilter", "mindustry.maps.generators.BasicGenerator", "mindustry.maps.generators.BasicGenerator$DistanceHeuristic", "mindustry.maps.generators.BasicGenerator$TileHueristic", "mindustry.maps.generators.Generator", "mindustry.maps.generators.MapGenerator", "mindustry.maps.generators.MapGenerator$Decoration", "mindustry.maps.generators.RandomGenerator", "mindustry.maps.zonegen.DesertWastesGenerator", "mindustry.maps.zonegen.OvergrowthGenerator", "mindustry.type.Category", "mindustry.type.ErrorContent", "mindustry.type.Item", "mindustry.type.ItemStack", "mindustry.type.ItemType", "mindustry.type.Liquid", "mindustry.type.LiquidStack", "mindustry.type.Mech", "mindustry.type.Publishable", "mindustry.type.StatusEffect", "mindustry.type.StatusEffect$TransitionHandler", "mindustry.type.TypeID", "mindustry.type.UnitType", "mindustry.type.Weapon", "mindustry.type.WeatherEvent", "mindustry.type.Zone", "mindustry.ui.Bar", "mindustry.ui.BorderImage", "mindustry.ui.Cicon", "mindustry.ui.ContentDisplay", "mindustry.ui.Fonts", "mindustry.ui.GridImage", "mindustry.ui.IconSize", "mindustry.ui.IntFormat", "mindustry.ui.ItemDisplay", "mindustry.ui.ItemImage", "mindustry.ui.ItemsDisplay", "mindustry.ui.Links", "mindustry.ui.Links$LinkEntry", "mindustry.ui.LiquidDisplay", "mindustry.ui.Minimap", "mindustry.ui.MobileButton", "mindustry.ui.MultiReqImage", "mindustry.ui.ReqImage", "mindustry.ui.Styles", "mindustry.ui.dialogs.AboutDialog", "mindustry.ui.dialogs.AdminsDialog", "mindustry.ui.dialogs.BansDialog", "mindustry.ui.dialogs.ColorPicker", "mindustry.ui.dialogs.ContentInfoDialog", "mindustry.ui.dialogs.ControlsDialog", "mindustry.ui.dialogs.CustomGameDialog", "mindustry.ui.dialogs.CustomRulesDialog", "mindustry.ui.dialogs.DatabaseDialog", "mindustry.ui.dialogs.DeployDialog", "mindustry.ui.dialogs.DeployDialog$View", "mindustry.ui.dialogs.DeployDialog$ZoneNode", "mindustry.ui.dialogs.DiscordDialog", "mindustry.ui.dialogs.FileChooser", "mindustry.ui.dialogs.FileChooser$FileHistory", "mindustry.ui.dialogs.FloatingDialog", "mindustry.ui.dialogs.GameOverDialog", "mindustry.ui.dialogs.HostDialog", "mindustry.ui.dialogs.JoinDialog", "mindustry.ui.dialogs.JoinDialog$Server", "mindustry.ui.dialogs.LanguageDialog", "mindustry.ui.dialogs.LoadDialog", "mindustry.ui.dialogs.LoadoutDialog", "mindustry.ui.dialogs.MapPlayDialog", "mindustry.ui.dialogs.MapsDialog", "mindustry.ui.dialogs.MinimapDialog", "mindustry.ui.dialogs.ModsDialog", "mindustry.ui.dialogs.PaletteDialog", "mindustry.ui.dialogs.PausedDialog", "mindustry.ui.dialogs.SaveDialog", "mindustry.ui.dialogs.SchematicsDialog", "mindustry.ui.dialogs.SchematicsDialog$SchematicImage", "mindustry.ui.dialogs.SchematicsDialog$SchematicInfoDialog", "mindustry.ui.dialogs.SettingsMenuDialog", "mindustry.ui.dialogs.TechTreeDialog", "mindustry.ui.dialogs.TechTreeDialog$LayoutNode", "mindustry.ui.dialogs.TechTreeDialog$TechTreeNode", "mindustry.ui.dialogs.TechTreeDialog$View", "mindustry.ui.dialogs.TraceDialog", "mindustry.ui.dialogs.ZoneInfoDialog", "mindustry.ui.fragments.BlockConfigFragment", "mindustry.ui.fragments.BlockInventoryFragment", "mindustry.ui.fragments.ChatFragment", "mindustry.ui.fragments.FadeInFragment", "mindustry.ui.fragments.Fragment", "mindustry.ui.fragments.HudFragment", "mindustry.ui.fragments.LoadingFragment", "mindustry.ui.fragments.MenuFragment", "mindustry.ui.fragments.OverlayFragment", "mindustry.ui.fragments.PlacementFragment", "mindustry.ui.fragments.PlayerListFragment", "mindustry.ui.fragments.ScriptConsoleFragment", "mindustry.ui.layout.BranchTreeLayout", "mindustry.ui.layout.BranchTreeLayout$TreeAlignment", "mindustry.ui.layout.BranchTreeLayout$TreeLocation", "mindustry.ui.layout.RadialTreeLayout", "mindustry.ui.layout.TreeLayout", "mindustry.ui.layout.TreeLayout$TreeNode", "mindustry.world.Block", "mindustry.world.BlockStorage", "mindustry.world.Build", "mindustry.world.CachedTile", "mindustry.world.DirectionalItemBuffer", "mindustry.world.DirectionalItemBuffer$BufferItemStruct", "mindustry.world.Edges", "mindustry.world.ItemBuffer", "mindustry.world.LegacyColorMapper", "mindustry.world.LegacyColorMapper$LegacyBlock", "mindustry.world.Pos", "mindustry.world.StaticTree", "mindustry.world.Tile", "mindustry.world.WorldContext", "mindustry.world.blocks.Attributes", "mindustry.world.blocks.Autotiler", "mindustry.world.blocks.Autotiler$AutotilerHolder", "mindustry.world.blocks.BlockPart", "mindustry.world.blocks.BuildBlock", "mindustry.world.blocks.BuildBlock$BuildEntity", "mindustry.world.blocks.DoubleOverlayFloor", "mindustry.world.blocks.Floor", "mindustry.world.blocks.ItemSelection", "mindustry.world.blocks.LiquidBlock", "mindustry.world.blocks.OreBlock", "mindustry.world.blocks.OverlayFloor", "mindustry.world.blocks.PowerBlock", "mindustry.world.blocks.RespawnBlock", "mindustry.world.blocks.Rock", "mindustry.world.blocks.StaticWall", "mindustry.world.blocks.TreeBlock", "mindustry.world.blocks.defense.DeflectorWall", "mindustry.world.blocks.defense.DeflectorWall$DeflectorEntity", "mindustry.world.blocks.defense.Door", "mindustry.world.blocks.defense.Door$DoorEntity", "mindustry.world.blocks.defense.ForceProjector", "mindustry.world.blocks.defense.ForceProjector$ForceEntity", "mindustry.world.blocks.defense.ForceProjector$ShieldEntity", "mindustry.world.blocks.defense.MendProjector", "mindustry.world.blocks.defense.MendProjector$MendEntity", "mindustry.world.blocks.defense.OverdriveProjector", "mindustry.world.blocks.defense.OverdriveProjector$OverdriveEntity", "mindustry.world.blocks.defense.ShockMine", "mindustry.world.blocks.defense.SurgeWall", "mindustry.world.blocks.defense.Wall", "mindustry.world.blocks.defense.turrets.ArtilleryTurret", "mindustry.world.blocks.defense.turrets.BurstTurret", "mindustry.world.blocks.defense.turrets.ChargeTurret", "mindustry.world.blocks.defense.turrets.ChargeTurret$LaserTurretEntity", "mindustry.world.blocks.defense.turrets.CooledTurret", "mindustry.world.blocks.defense.turrets.DoubleTurret", "mindustry.world.blocks.defense.turrets.ItemTurret", "mindustry.world.blocks.defense.turrets.ItemTurret$ItemEntry", "mindustry.world.blocks.defense.turrets.ItemTurret$ItemTurretEntity", "mindustry.world.blocks.defense.turrets.LaserTurret", "mindustry.world.blocks.defense.turrets.LaserTurret$LaserTurretEntity", "mindustry.world.blocks.defense.turrets.LiquidTurret", "mindustry.world.blocks.defense.turrets.PowerTurret", "mindustry.world.blocks.defense.turrets.Turret", "mindustry.world.blocks.defense.turrets.Turret$AmmoEntry", "mindustry.world.blocks.defense.turrets.Turret$TurretEntity", "mindustry.world.blocks.distribution.ArmoredConveyor", "mindustry.world.blocks.distribution.BufferedItemBridge", "mindustry.world.blocks.distribution.BufferedItemBridge$BufferedItemBridgeEntity", "mindustry.world.blocks.distribution.Conveyor", "mindustry.world.blocks.distribution.Conveyor$ConveyorEntity", "mindustry.world.blocks.distribution.Conveyor$ItemPos", "mindustry.world.blocks.distribution.ExtendingItemBridge", "mindustry.world.blocks.distribution.ItemBridge", "mindustry.world.blocks.distribution.ItemBridge$ItemBridgeEntity", "mindustry.world.blocks.distribution.Junction", "mindustry.world.blocks.distribution.Junction$JunctionEntity", "mindustry.world.blocks.distribution.MassDriver", "mindustry.world.blocks.distribution.MassDriver$DriverBulletData", "mindustry.world.blocks.distribution.MassDriver$DriverState", "mindustry.world.blocks.distribution.MassDriver$MassDriverEntity", "mindustry.world.blocks.distribution.OverflowGate", "mindustry.world.blocks.distribution.OverflowGate$OverflowGateEntity", "mindustry.world.blocks.distribution.Router", "mindustry.world.blocks.distribution.Router$RouterEntity", "mindustry.world.blocks.distribution.Sorter", "mindustry.world.blocks.distribution.Sorter$SorterEntity", "mindustry.world.blocks.liquid.ArmoredConduit", "mindustry.world.blocks.liquid.Conduit", "mindustry.world.blocks.liquid.Conduit$ConduitEntity", "mindustry.world.blocks.liquid.LiquidBridge", "mindustry.world.blocks.liquid.LiquidExtendingBridge", "mindustry.world.blocks.liquid.LiquidJunction", "mindustry.world.blocks.liquid.LiquidOverflowGate", "mindustry.world.blocks.liquid.LiquidRouter", "mindustry.world.blocks.liquid.LiquidTank", "mindustry.world.blocks.logic.LogicBlock", "mindustry.world.blocks.logic.MessageBlock", "mindustry.world.blocks.logic.MessageBlock$MessageBlockEntity", "mindustry.world.blocks.power.Battery", "mindustry.world.blocks.power.BurnerGenerator", "mindustry.world.blocks.power.ConditionalConsumePower", "mindustry.world.blocks.power.DecayGenerator", "mindustry.world.blocks.power.ImpactReactor", "mindustry.world.blocks.power.ImpactReactor$FusionReactorEntity", "mindustry.world.blocks.power.ItemLiquidGenerator", "mindustry.world.blocks.power.ItemLiquidGenerator$ItemLiquidGeneratorEntity", "mindustry.world.blocks.power.LightBlock", "mindustry.world.blocks.power.LightBlock$LightEntity", "mindustry.world.blocks.power.NuclearReactor", "mindustry.world.blocks.power.NuclearReactor$NuclearReactorEntity", "mindustry.world.blocks.power.PowerDiode", "mindustry.world.blocks.power.PowerDistributor", "mindustry.world.blocks.power.PowerGenerator", "mindustry.world.blocks.power.PowerGenerator$GeneratorEntity", "mindustry.world.blocks.power.PowerGraph", "mindustry.world.blocks.power.PowerNode", "mindustry.world.blocks.power.SingleTypeGenerator", "mindustry.world.blocks.power.SolarGenerator", "mindustry.world.blocks.power.ThermalGenerator", "mindustry.world.blocks.production.Cultivator", "mindustry.world.blocks.production.Cultivator$CultivatorEntity", "mindustry.world.blocks.production.Drill", "mindustry.world.blocks.production.Drill$DrillEntity", "mindustry.world.blocks.production.Fracker", "mindustry.world.blocks.production.Fracker$FrackerEntity", "mindustry.world.blocks.production.GenericCrafter", "mindustry.world.blocks.production.GenericCrafter$GenericCrafterEntity", "mindustry.world.blocks.production.GenericSmelter", "mindustry.world.blocks.production.Incinerator", "mindustry.world.blocks.production.Incinerator$IncineratorEntity", "mindustry.world.blocks.production.LiquidConverter", "mindustry.world.blocks.production.Pump", "mindustry.world.blocks.production.Separator", "mindustry.world.blocks.production.SolidPump", "mindustry.world.blocks.production.SolidPump$SolidPumpEntity", "mindustry.world.blocks.sandbox.ItemSource", "mindustry.world.blocks.sandbox.ItemSource$ItemSourceEntity", "mindustry.world.blocks.sandbox.ItemVoid", "mindustry.world.blocks.sandbox.LiquidSource", "mindustry.world.blocks.sandbox.LiquidSource$LiquidSourceEntity", "mindustry.world.blocks.sandbox.PowerSource", "mindustry.world.blocks.sandbox.PowerVoid", "mindustry.world.blocks.storage.CoreBlock", "mindustry.world.blocks.storage.CoreBlock$CoreEntity", "mindustry.world.blocks.storage.LaunchPad", "mindustry.world.blocks.storage.StorageBlock", "mindustry.world.blocks.storage.StorageBlock$StorageBlockEntity", "mindustry.world.blocks.storage.Unloader", "mindustry.world.blocks.storage.Unloader$UnloaderEntity", "mindustry.world.blocks.storage.Vault", "mindustry.world.blocks.units.CommandCenter", "mindustry.world.blocks.units.CommandCenter$CommandCenterEntity", "mindustry.world.blocks.units.MechPad", "mindustry.world.blocks.units.MechPad$MechFactoryEntity", "mindustry.world.blocks.units.RallyPoint", "mindustry.world.blocks.units.RepairPoint", "mindustry.world.blocks.units.RepairPoint$RepairPointEntity", "mindustry.world.blocks.units.UnitFactory", "mindustry.world.blocks.units.UnitFactory$UnitFactoryEntity", "mindustry.world.consumers.Consume", "mindustry.world.consumers.ConsumeItemFilter", "mindustry.world.consumers.ConsumeItems", "mindustry.world.consumers.ConsumeLiquid", "mindustry.world.consumers.ConsumeLiquidBase", "mindustry.world.consumers.ConsumeLiquidFilter", "mindustry.world.consumers.ConsumePower", "mindustry.world.consumers.ConsumeType", "mindustry.world.consumers.Consumers", "mindustry.world.meta.Attribute", "mindustry.world.meta.BlockBars", "mindustry.world.meta.BlockFlag", "mindustry.world.meta.BlockGroup", "mindustry.world.meta.BlockStat", "mindustry.world.meta.BlockStats", "mindustry.world.meta.BuildVisibility", "mindustry.world.meta.PowerType", "mindustry.world.meta.Producers", "mindustry.world.meta.StatCategory", "mindustry.world.meta.StatUnit", "mindustry.world.meta.StatValue", "mindustry.world.meta.values.AmmoListValue", "mindustry.world.meta.values.BooleanValue", "mindustry.world.meta.values.BoosterListValue", "mindustry.world.meta.values.ItemFilterValue", "mindustry.world.meta.values.ItemListValue", "mindustry.world.meta.values.LiquidFilterValue", "mindustry.world.meta.values.LiquidValue", "mindustry.world.meta.values.NumberValue", "mindustry.world.meta.values.StringValue", "mindustry.world.modules.BlockModule", "mindustry.world.modules.ConsumeModule", "mindustry.world.modules.ItemModule", "mindustry.world.modules.ItemModule$ItemCalculator", "mindustry.world.modules.ItemModule$ItemConsumer", "mindustry.world.modules.LiquidModule", "mindustry.world.modules.LiquidModule$LiquidCalculator", "mindustry.world.modules.LiquidModule$LiquidConsumer", "mindustry.world.modules.PowerModule", "mindustry.world.producers.Produce", "mindustry.world.producers.ProduceItem"); + public static final ObjectSet allowedClassNames = ObjectSet.with("arc.Core", "arc.func.Boolc", "arc.func.Boolf", "arc.func.Boolf2", "arc.func.Boolp", "arc.func.Cons", "arc.func.Cons2", "arc.func.Floatc", "arc.func.Floatc2", "arc.func.Floatc4", "arc.func.Floatf", "arc.func.Floatp", "arc.func.Func", "arc.func.Func2", "arc.func.Func3", "arc.func.Intc", "arc.func.Intc2", "arc.func.Intc4", "arc.func.Intf", "arc.func.Intp", "arc.func.Prov", "arc.graphics.Color", "arc.graphics.Pixmap", "arc.graphics.Texture", "arc.graphics.TextureData", "arc.graphics.g2d.Draw", "arc.graphics.g2d.Fill", "arc.graphics.g2d.Lines", "arc.graphics.g2d.TextureAtlas", "arc.graphics.g2d.TextureAtlas$AtlasRegion", "arc.graphics.g2d.TextureRegion", "arc.math.Angles", "arc.math.Mathf", "arc.scene.Action", "arc.scene.Element", "arc.scene.Group", "arc.scene.Scene", "arc.scene.actions.Actions", "arc.scene.actions.AddAction", "arc.scene.actions.AddListenerAction", "arc.scene.actions.AfterAction", "arc.scene.actions.AlphaAction", "arc.scene.actions.ColorAction", "arc.scene.actions.DelayAction", "arc.scene.actions.DelegateAction", "arc.scene.actions.FloatAction", "arc.scene.actions.IntAction", "arc.scene.actions.LayoutAction", "arc.scene.actions.MoveByAction", "arc.scene.actions.MoveToAction", "arc.scene.actions.OriginAction", "arc.scene.actions.ParallelAction", "arc.scene.actions.RelativeTemporalAction", "arc.scene.actions.RemoveAction", "arc.scene.actions.RemoveActorAction", "arc.scene.actions.RemoveListenerAction", "arc.scene.actions.RepeatAction", "arc.scene.actions.RotateByAction", "arc.scene.actions.RotateToAction", "arc.scene.actions.RunnableAction", "arc.scene.actions.ScaleByAction", "arc.scene.actions.ScaleToAction", "arc.scene.actions.SequenceAction", "arc.scene.actions.SizeByAction", "arc.scene.actions.SizeToAction", "arc.scene.actions.TemporalAction", "arc.scene.actions.TimeScaleAction", "arc.scene.actions.TouchableAction", "arc.scene.actions.TranslateByAction", "arc.scene.actions.VisibleAction", "arc.scene.event.ChangeListener", "arc.scene.event.ChangeListener$ChangeEvent", "arc.scene.event.ClickListener", "arc.scene.event.DragListener", "arc.scene.event.DragScrollListener", "arc.scene.event.ElementGestureListener", "arc.scene.event.EventListener", "arc.scene.event.FocusListener", "arc.scene.event.FocusListener$FocusEvent", "arc.scene.event.FocusListener$FocusEvent$Type", "arc.scene.event.HandCursorListener", "arc.scene.event.IbeamCursorListener", "arc.scene.event.InputEvent", "arc.scene.event.InputEvent$Type", "arc.scene.event.InputListener", "arc.scene.event.SceneEvent", "arc.scene.event.Touchable", "arc.scene.event.VisibilityEvent", "arc.scene.event.VisibilityListener", "arc.scene.style.BaseDrawable", "arc.scene.style.Drawable", "arc.scene.style.NinePatchDrawable", "arc.scene.style.ScaledNinePatchDrawable", "arc.scene.style.Style", "arc.scene.style.TextureRegionDrawable", "arc.scene.style.TiledDrawable", "arc.scene.style.TransformDrawable", "arc.scene.ui.Button", "arc.scene.ui.Button$ButtonStyle", "arc.scene.ui.ButtonGroup", "arc.scene.ui.CheckBox", "arc.scene.ui.CheckBox$CheckBoxStyle", "arc.scene.ui.ColorImage", "arc.scene.ui.Dialog", "arc.scene.ui.Dialog$DialogStyle", "arc.scene.ui.Image", "arc.scene.ui.ImageButton", "arc.scene.ui.ImageButton$ImageButtonStyle", "arc.scene.ui.KeybindDialog", "arc.scene.ui.KeybindDialog$KeybindDialogStyle", "arc.scene.ui.Label", "arc.scene.ui.Label$LabelStyle", "arc.scene.ui.ProgressBar", "arc.scene.ui.ProgressBar$ProgressBarStyle", "arc.scene.ui.ScrollPane", "arc.scene.ui.ScrollPane$ScrollPaneStyle", "arc.scene.ui.SettingsDialog", "arc.scene.ui.SettingsDialog$SettingsTable", "arc.scene.ui.SettingsDialog$SettingsTable$CheckSetting", "arc.scene.ui.SettingsDialog$SettingsTable$Setting", "arc.scene.ui.SettingsDialog$SettingsTable$SliderSetting", "arc.scene.ui.SettingsDialog$StringProcessor", "arc.scene.ui.Slider", "arc.scene.ui.Slider$SliderStyle", "arc.scene.ui.TextArea", "arc.scene.ui.TextArea$TextAreaListener", "arc.scene.ui.TextButton", "arc.scene.ui.TextButton$TextButtonStyle", "arc.scene.ui.TextField", "arc.scene.ui.TextField$DefaultOnscreenKeyboard", "arc.scene.ui.TextField$OnscreenKeyboard", "arc.scene.ui.TextField$TextFieldClickListener", "arc.scene.ui.TextField$TextFieldFilter", "arc.scene.ui.TextField$TextFieldListener", "arc.scene.ui.TextField$TextFieldStyle", "arc.scene.ui.TextField$TextFieldValidator", "arc.scene.ui.Tooltip", "arc.scene.ui.Tooltip$Tooltips", "arc.scene.ui.Touchpad", "arc.scene.ui.Touchpad$TouchpadStyle", "arc.scene.ui.TreeElement", "arc.scene.ui.TreeElement$Node", "arc.scene.ui.TreeElement$TreeStyle", "arc.scene.ui.layout.Cell", "arc.scene.ui.layout.Collapser", "arc.scene.ui.layout.HorizontalGroup", "arc.scene.ui.layout.Scl", "arc.scene.ui.layout.Stack", "arc.scene.ui.layout.Table", "arc.scene.ui.layout.Table$DrawRect", "arc.scene.ui.layout.VerticalGroup", "arc.scene.ui.layout.WidgetGroup", "arc.scene.utils.ArraySelection", "arc.scene.utils.Cullable", "arc.scene.utils.Disableable", "arc.scene.utils.DragAndDrop", "arc.scene.utils.DragAndDrop$Payload", "arc.scene.utils.DragAndDrop$Source", "arc.scene.utils.DragAndDrop$Target", "arc.scene.utils.Elements", "arc.scene.utils.Layout", "arc.scene.utils.Selection", "arc.struct.Array", "arc.struct.Array$ArrayIterable", "arc.struct.ArrayMap", "arc.struct.ArrayMap$Entries", "arc.struct.ArrayMap$Keys", "arc.struct.ArrayMap$Values", "arc.struct.AtomicQueue", "arc.struct.BinaryHeap", "arc.struct.BinaryHeap$Node", "arc.struct.Bits", "arc.struct.BooleanArray", "arc.struct.ByteArray", "arc.struct.CharArray", "arc.struct.ComparableTimSort", "arc.struct.DelayedRemovalArray", "arc.struct.EnumSet", "arc.struct.EnumSet$EnumSetIterator", "arc.struct.FloatArray", "arc.struct.GridBits", "arc.struct.GridMap", "arc.struct.IdentityMap", "arc.struct.IdentityMap$Entries", "arc.struct.IdentityMap$Entry", "arc.struct.IdentityMap$Keys", "arc.struct.IdentityMap$Values", "arc.struct.IntArray", "arc.struct.IntFloatMap", "arc.struct.IntFloatMap$Entries", "arc.struct.IntFloatMap$Entry", "arc.struct.IntFloatMap$Keys", "arc.struct.IntFloatMap$Values", "arc.struct.IntIntMap", "arc.struct.IntIntMap$Entries", "arc.struct.IntIntMap$Entry", "arc.struct.IntIntMap$Keys", "arc.struct.IntIntMap$Values", "arc.struct.IntMap", "arc.struct.IntMap$Entries", "arc.struct.IntMap$Entry", "arc.struct.IntMap$Keys", "arc.struct.IntMap$Values", "arc.struct.IntQueue", "arc.struct.IntSet", "arc.struct.IntSet$IntSetIterator", "arc.struct.LongArray", "arc.struct.LongMap", "arc.struct.LongMap$Entries", "arc.struct.LongMap$Entry", "arc.struct.LongMap$Keys", "arc.struct.LongMap$Values", "arc.struct.LongQueue", "arc.struct.ObjectFloatMap", "arc.struct.ObjectFloatMap$Entries", "arc.struct.ObjectFloatMap$Entry", "arc.struct.ObjectFloatMap$Keys", "arc.struct.ObjectFloatMap$Values", "arc.struct.ObjectIntMap", "arc.struct.ObjectIntMap$Entries", "arc.struct.ObjectIntMap$Entry", "arc.struct.ObjectIntMap$Keys", "arc.struct.ObjectIntMap$Values", "arc.struct.ObjectMap", "arc.struct.ObjectMap$Entries", "arc.struct.ObjectMap$Entry", "arc.struct.ObjectMap$Keys", "arc.struct.ObjectMap$Values", "arc.struct.ObjectSet", "arc.struct.ObjectSet$ObjectSetIterator", "arc.struct.OrderedMap", "arc.struct.OrderedMap$OrderedMapEntries", "arc.struct.OrderedMap$OrderedMapKeys", "arc.struct.OrderedMap$OrderedMapValues", "arc.struct.OrderedSet", "arc.struct.OrderedSet$OrderedSetIterator", "arc.struct.PooledLinkedList", "arc.struct.PooledLinkedList$Item", "arc.struct.Queue", "arc.struct.Queue$QueueIterable", "arc.struct.ShortArray", "arc.struct.SnapshotArray", "arc.struct.Sort", "arc.struct.SortedIntList", "arc.struct.SortedIntList$Iterator", "arc.struct.SortedIntList$Node", "arc.struct.StringMap", "arc.struct.TimSort", "arc.util.I18NBundle", "arc.util.Time", "java.io.PrintStream", "java.lang.Object", "java.lang.Runnable", "java.lang.String", "java.lang.System", "mindustry.Vars", "mindustry.ai.BlockIndexer", "mindustry.ai.Pathfinder", "mindustry.ai.Pathfinder$PathData", "mindustry.ai.Pathfinder$PathTarget", "mindustry.ai.Pathfinder$PathTileStruct", "mindustry.ai.WaveSpawner", "mindustry.content.Blocks", "mindustry.content.Bullets", "mindustry.content.Fx", "mindustry.content.Items", "mindustry.content.Liquids", "mindustry.content.Loadouts", "mindustry.content.Mechs", "mindustry.content.StatusEffects", "mindustry.content.TechTree", "mindustry.content.TechTree$TechNode", "mindustry.content.TypeIDs", "mindustry.content.UnitTypes", "mindustry.content.Zones", "mindustry.core.ContentLoader", "mindustry.core.Control", "mindustry.core.FileTree", "mindustry.core.GameState", "mindustry.core.GameState$State", "mindustry.core.Logic", "mindustry.core.NetServer$TeamAssigner", "mindustry.core.Platform", "mindustry.core.Renderer", "mindustry.core.UI", "mindustry.core.Version", "mindustry.core.World", "mindustry.core.World$Raycaster", "mindustry.ctype.Content", "mindustry.ctype.Content$ModContentInfo", "mindustry.ctype.ContentList", "mindustry.ctype.ContentType", "mindustry.ctype.MappableContent", "mindustry.ctype.UnlockableContent", "mindustry.editor.DrawOperation", "mindustry.editor.DrawOperation$OpType", "mindustry.editor.DrawOperation$TileOpStruct", "mindustry.editor.EditorTile", "mindustry.editor.EditorTool", "mindustry.editor.MapEditor", "mindustry.editor.MapEditor$Context", "mindustry.editor.MapEditorDialog", "mindustry.editor.MapGenerateDialog", "mindustry.editor.MapInfoDialog", "mindustry.editor.MapLoadDialog", "mindustry.editor.MapRenderer", "mindustry.editor.MapResizeDialog", "mindustry.editor.MapSaveDialog", "mindustry.editor.MapView", "mindustry.editor.OperationStack", "mindustry.editor.WaveInfoDialog", "mindustry.entities.Damage", "mindustry.entities.Damage$PropCellStruct", "mindustry.entities.Effects", "mindustry.entities.Effects$Effect", "mindustry.entities.Effects$EffectContainer", "mindustry.entities.Effects$EffectProvider", "mindustry.entities.Effects$EffectRenderer", "mindustry.entities.Effects$ScreenshakeProvider", "mindustry.entities.Entities", "mindustry.entities.EntityCollisions", "mindustry.entities.EntityGroup", "mindustry.entities.Predict", "mindustry.entities.TargetPriority", "mindustry.entities.Units", "mindustry.entities.bullet.ArtilleryBulletType", "mindustry.entities.bullet.BasicBulletType", "mindustry.entities.bullet.BombBulletType", "mindustry.entities.bullet.BulletType", "mindustry.entities.bullet.FlakBulletType", "mindustry.entities.bullet.HealBulletType", "mindustry.entities.bullet.LiquidBulletType", "mindustry.entities.bullet.MassDriverBolt", "mindustry.entities.bullet.MissileBulletType", "mindustry.entities.effect.Decal", "mindustry.entities.effect.Fire", "mindustry.entities.effect.GroundEffectEntity", "mindustry.entities.effect.GroundEffectEntity$GroundEffect", "mindustry.entities.effect.ItemTransfer", "mindustry.entities.effect.Lightning", "mindustry.entities.effect.Puddle", "mindustry.entities.effect.RubbleDecal", "mindustry.entities.effect.ScorchDecal", "mindustry.entities.traits.AbsorbTrait", "mindustry.entities.traits.BelowLiquidTrait", "mindustry.entities.traits.BuilderMinerTrait", "mindustry.entities.traits.BuilderTrait", "mindustry.entities.traits.BuilderTrait$BuildDataStatic", "mindustry.entities.traits.BuilderTrait$BuildRequest", "mindustry.entities.traits.DamageTrait", "mindustry.entities.traits.DrawTrait", "mindustry.entities.traits.Entity", "mindustry.entities.traits.HealthTrait", "mindustry.entities.traits.KillerTrait", "mindustry.entities.traits.MinerTrait", "mindustry.entities.traits.MoveTrait", "mindustry.entities.traits.SaveTrait", "mindustry.entities.traits.Saveable", "mindustry.entities.traits.ScaleTrait", "mindustry.entities.traits.ShooterTrait", "mindustry.entities.traits.SolidTrait", "mindustry.entities.traits.SpawnerTrait", "mindustry.entities.traits.SyncTrait", "mindustry.entities.traits.TargetTrait", "mindustry.entities.traits.TeamTrait", "mindustry.entities.traits.TimeTrait", "mindustry.entities.traits.TypeTrait", "mindustry.entities.traits.VelocityTrait", "mindustry.entities.type.BaseEntity", "mindustry.entities.type.BaseUnit", "mindustry.entities.type.Bullet", "mindustry.entities.type.DestructibleEntity", "mindustry.entities.type.EffectEntity", "mindustry.entities.type.Player", "mindustry.entities.type.SolidEntity", "mindustry.entities.type.TileEntity", "mindustry.entities.type.TimedEntity", "mindustry.entities.type.Unit", "mindustry.entities.type.base.BaseDrone", "mindustry.entities.type.base.BuilderDrone", "mindustry.entities.type.base.FlyingUnit", "mindustry.entities.type.base.GroundUnit", "mindustry.entities.type.base.HoverUnit", "mindustry.entities.type.base.MinerDrone", "mindustry.entities.type.base.RepairDrone", "mindustry.entities.units.StateMachine", "mindustry.entities.units.Statuses", "mindustry.entities.units.Statuses$StatusEntry", "mindustry.entities.units.UnitCommand", "mindustry.entities.units.UnitDrops", "mindustry.entities.units.UnitState", "mindustry.game.DefaultWaves", "mindustry.game.Difficulty", "mindustry.game.EventType", "mindustry.game.EventType$BlockBuildBeginEvent", "mindustry.game.EventType$BlockBuildEndEvent", "mindustry.game.EventType$BlockDestroyEvent", "mindustry.game.EventType$BlockInfoEvent", "mindustry.game.EventType$BuildSelectEvent", "mindustry.game.EventType$ClientLoadEvent", "mindustry.game.EventType$CommandIssueEvent", "mindustry.game.EventType$ContentReloadEvent", "mindustry.game.EventType$CoreItemDeliverEvent", "mindustry.game.EventType$DepositEvent", "mindustry.game.EventType$DisposeEvent", "mindustry.game.EventType$GameOverEvent", "mindustry.game.EventType$LaunchEvent", "mindustry.game.EventType$LaunchItemEvent", "mindustry.game.EventType$LineConfirmEvent", "mindustry.game.EventType$LoseEvent", "mindustry.game.EventType$MapMakeEvent", "mindustry.game.EventType$MapPublishEvent", "mindustry.game.EventType$MechChangeEvent", "mindustry.game.EventType$PlayEvent", "mindustry.game.EventType$PlayerBanEvent", "mindustry.game.EventType$PlayerChatEvent", "mindustry.game.EventType$PlayerConnect", "mindustry.game.EventType$PlayerIpBanEvent", "mindustry.game.EventType$PlayerIpUnbanEvent", "mindustry.game.EventType$PlayerJoin", "mindustry.game.EventType$PlayerLeave", "mindustry.game.EventType$PlayerUnbanEvent", "mindustry.game.EventType$ResearchEvent", "mindustry.game.EventType$ResetEvent", "mindustry.game.EventType$ResizeEvent", "mindustry.game.EventType$ServerLoadEvent", "mindustry.game.EventType$StateChangeEvent", "mindustry.game.EventType$TapConfigEvent", "mindustry.game.EventType$TapEvent", "mindustry.game.EventType$TileChangeEvent", "mindustry.game.EventType$Trigger", "mindustry.game.EventType$TurretAmmoDeliverEvent", "mindustry.game.EventType$UnitCreateEvent", "mindustry.game.EventType$UnitDestroyEvent", "mindustry.game.EventType$UnlockEvent", "mindustry.game.EventType$WaveEvent", "mindustry.game.EventType$WinEvent", "mindustry.game.EventType$WithdrawEvent", "mindustry.game.EventType$WorldLoadEvent", "mindustry.game.EventType$ZoneConfigureCompleteEvent", "mindustry.game.EventType$ZoneRequireCompleteEvent", "mindustry.game.Gamemode", "mindustry.game.GlobalData", "mindustry.game.LoopControl", "mindustry.game.MusicControl", "mindustry.game.Objective", "mindustry.game.Objectives", "mindustry.game.Objectives$Launched", "mindustry.game.Objectives$Unlock", "mindustry.game.Objectives$Wave", "mindustry.game.Objectives$ZoneObjective", "mindustry.game.Objectives$ZoneWave", "mindustry.game.Rules", "mindustry.game.Saves", "mindustry.game.Saves$SaveSlot", "mindustry.game.Schematic", "mindustry.game.Schematic$Stile", "mindustry.game.Schematics", "mindustry.game.SoundLoop", "mindustry.game.SpawnGroup", "mindustry.game.Stats", "mindustry.game.Stats$Rank", "mindustry.game.Stats$RankResult", "mindustry.game.Team", "mindustry.game.Teams", "mindustry.game.Teams$BrokenBlock", "mindustry.game.Teams$TeamData", "mindustry.game.Tutorial", "mindustry.game.Tutorial$TutorialStage", "mindustry.gen.BufferItem", "mindustry.gen.Call", "mindustry.gen.Call", "mindustry.gen.Icon", "mindustry.gen.Icon", "mindustry.gen.MethodHash", "mindustry.gen.Musics", "mindustry.gen.Musics", "mindustry.gen.PathTile", "mindustry.gen.PropCell", "mindustry.gen.RemoteReadClient", "mindustry.gen.RemoteReadServer", "mindustry.gen.Serialization", "mindustry.gen.Sounds", "mindustry.gen.Sounds", "mindustry.gen.Tex", "mindustry.gen.Tex", "mindustry.gen.TileOp", "mindustry.graphics.BlockRenderer", "mindustry.graphics.Bloom", "mindustry.graphics.CacheLayer", "mindustry.graphics.Drawf", "mindustry.graphics.FloorRenderer", "mindustry.graphics.IndexedRenderer", "mindustry.graphics.Layer", "mindustry.graphics.LightRenderer", "mindustry.graphics.MenuRenderer", "mindustry.graphics.MinimapRenderer", "mindustry.graphics.MultiPacker", "mindustry.graphics.MultiPacker$PageType", "mindustry.graphics.OverlayRenderer", "mindustry.graphics.Pal", "mindustry.graphics.Pixelator", "mindustry.graphics.Shaders", "mindustry.input.Binding", "mindustry.input.DesktopInput", "mindustry.input.InputHandler", "mindustry.input.InputHandler$PlaceLine", "mindustry.input.MobileInput", "mindustry.input.PlaceMode", "mindustry.input.Placement", "mindustry.input.Placement$DistanceHeuristic", "mindustry.input.Placement$NormalizeDrawResult", "mindustry.input.Placement$NormalizeResult", "mindustry.input.Placement$TileHueristic", "mindustry.maps.Map", "mindustry.maps.Maps", "mindustry.maps.Maps$MapProvider", "mindustry.maps.Maps$ShuffleMode", "mindustry.maps.Maps$ShuffleMode", "mindustry.maps.filters.BlendFilter", "mindustry.maps.filters.ClearFilter", "mindustry.maps.filters.DistortFilter", "mindustry.maps.filters.FilterOption", "mindustry.maps.filters.FilterOption$BlockOption", "mindustry.maps.filters.FilterOption$SliderOption", "mindustry.maps.filters.GenerateFilter", "mindustry.maps.filters.GenerateFilter$GenerateInput", "mindustry.maps.filters.GenerateFilter$GenerateInput$TileProvider", "mindustry.maps.filters.MedianFilter", "mindustry.maps.filters.MirrorFilter", "mindustry.maps.filters.NoiseFilter", "mindustry.maps.filters.OreFilter", "mindustry.maps.filters.OreMedianFilter", "mindustry.maps.filters.RiverNoiseFilter", "mindustry.maps.filters.ScatterFilter", "mindustry.maps.filters.TerrainFilter", "mindustry.maps.generators.BasicGenerator", "mindustry.maps.generators.BasicGenerator$DistanceHeuristic", "mindustry.maps.generators.BasicGenerator$TileHueristic", "mindustry.maps.generators.Generator", "mindustry.maps.generators.MapGenerator", "mindustry.maps.generators.MapGenerator$Decoration", "mindustry.maps.generators.RandomGenerator", "mindustry.maps.zonegen.DesertWastesGenerator", "mindustry.maps.zonegen.OvergrowthGenerator", "mindustry.type.Category", "mindustry.type.ErrorContent", "mindustry.type.Item", "mindustry.type.ItemStack", "mindustry.type.ItemType", "mindustry.type.Liquid", "mindustry.type.LiquidStack", "mindustry.type.Mech", "mindustry.type.Publishable", "mindustry.type.StatusEffect", "mindustry.type.StatusEffect$TransitionHandler", "mindustry.type.TypeID", "mindustry.type.UnitType", "mindustry.type.Weapon", "mindustry.type.WeatherEvent", "mindustry.type.Zone", "mindustry.ui.Bar", "mindustry.ui.BorderImage", "mindustry.ui.Cicon", "mindustry.ui.ContentDisplay", "mindustry.ui.Fonts", "mindustry.ui.GridImage", "mindustry.ui.IconSize", "mindustry.ui.IntFormat", "mindustry.ui.ItemDisplay", "mindustry.ui.ItemImage", "mindustry.ui.ItemsDisplay", "mindustry.ui.Links", "mindustry.ui.Links$LinkEntry", "mindustry.ui.LiquidDisplay", "mindustry.ui.Minimap", "mindustry.ui.MobileButton", "mindustry.ui.MultiReqImage", "mindustry.ui.ReqImage", "mindustry.ui.Styles", "mindustry.ui.dialogs.AboutDialog", "mindustry.ui.dialogs.AdminsDialog", "mindustry.ui.dialogs.BansDialog", "mindustry.ui.dialogs.ColorPicker", "mindustry.ui.dialogs.ContentInfoDialog", "mindustry.ui.dialogs.ControlsDialog", "mindustry.ui.dialogs.CustomGameDialog", "mindustry.ui.dialogs.CustomRulesDialog", "mindustry.ui.dialogs.DatabaseDialog", "mindustry.ui.dialogs.DeployDialog", "mindustry.ui.dialogs.DeployDialog$View", "mindustry.ui.dialogs.DeployDialog$ZoneNode", "mindustry.ui.dialogs.DiscordDialog", "mindustry.ui.dialogs.FileChooser", "mindustry.ui.dialogs.FileChooser$FileHistory", "mindustry.ui.dialogs.FloatingDialog", "mindustry.ui.dialogs.GameOverDialog", "mindustry.ui.dialogs.HostDialog", "mindustry.ui.dialogs.JoinDialog", "mindustry.ui.dialogs.JoinDialog$Server", "mindustry.ui.dialogs.LanguageDialog", "mindustry.ui.dialogs.LoadDialog", "mindustry.ui.dialogs.LoadoutDialog", "mindustry.ui.dialogs.MapPlayDialog", "mindustry.ui.dialogs.MapsDialog", "mindustry.ui.dialogs.MinimapDialog", "mindustry.ui.dialogs.ModsDialog", "mindustry.ui.dialogs.PaletteDialog", "mindustry.ui.dialogs.PausedDialog", "mindustry.ui.dialogs.SaveDialog", "mindustry.ui.dialogs.SchematicsDialog", "mindustry.ui.dialogs.SchematicsDialog$SchematicImage", "mindustry.ui.dialogs.SchematicsDialog$SchematicInfoDialog", "mindustry.ui.dialogs.SettingsMenuDialog", "mindustry.ui.dialogs.TechTreeDialog", "mindustry.ui.dialogs.TechTreeDialog$LayoutNode", "mindustry.ui.dialogs.TechTreeDialog$TechTreeNode", "mindustry.ui.dialogs.TechTreeDialog$View", "mindustry.ui.dialogs.TraceDialog", "mindustry.ui.dialogs.ZoneInfoDialog", "mindustry.ui.fragments.BlockConfigFragment", "mindustry.ui.fragments.BlockInventoryFragment", "mindustry.ui.fragments.ChatFragment", "mindustry.ui.fragments.FadeInFragment", "mindustry.ui.fragments.Fragment", "mindustry.ui.fragments.HudFragment", "mindustry.ui.fragments.LoadingFragment", "mindustry.ui.fragments.MenuFragment", "mindustry.ui.fragments.OverlayFragment", "mindustry.ui.fragments.PlacementFragment", "mindustry.ui.fragments.PlayerListFragment", "mindustry.ui.fragments.ScriptConsoleFragment", "mindustry.ui.layout.BranchTreeLayout", "mindustry.ui.layout.BranchTreeLayout$TreeAlignment", "mindustry.ui.layout.BranchTreeLayout$TreeLocation", "mindustry.ui.layout.RadialTreeLayout", "mindustry.ui.layout.TreeLayout", "mindustry.ui.layout.TreeLayout$TreeNode", "mindustry.world.Block", "mindustry.world.BlockStorage", "mindustry.world.Build", "mindustry.world.CachedTile", "mindustry.world.DirectionalItemBuffer", "mindustry.world.DirectionalItemBuffer$BufferItemStruct", "mindustry.world.Edges", "mindustry.world.ItemBuffer", "mindustry.world.LegacyColorMapper", "mindustry.world.LegacyColorMapper$LegacyBlock", "mindustry.world.Pos", "mindustry.world.StaticTree", "mindustry.world.Tile", "mindustry.world.WorldContext", "mindustry.world.blocks.Attributes", "mindustry.world.blocks.Autotiler", "mindustry.world.blocks.Autotiler$AutotilerHolder", "mindustry.world.blocks.BlockPart", "mindustry.world.blocks.BuildBlock", "mindustry.world.blocks.BuildBlock$BuildEntity", "mindustry.world.blocks.DoubleOverlayFloor", "mindustry.world.blocks.Floor", "mindustry.world.blocks.ItemSelection", "mindustry.world.blocks.LiquidBlock", "mindustry.world.blocks.OreBlock", "mindustry.world.blocks.OverlayFloor", "mindustry.world.blocks.PowerBlock", "mindustry.world.blocks.RespawnBlock", "mindustry.world.blocks.Rock", "mindustry.world.blocks.StaticWall", "mindustry.world.blocks.TreeBlock", "mindustry.world.blocks.defense.DeflectorWall", "mindustry.world.blocks.defense.DeflectorWall$DeflectorEntity", "mindustry.world.blocks.defense.Door", "mindustry.world.blocks.defense.Door$DoorEntity", "mindustry.world.blocks.defense.ForceProjector", "mindustry.world.blocks.defense.ForceProjector$ForceEntity", "mindustry.world.blocks.defense.ForceProjector$ShieldEntity", "mindustry.world.blocks.defense.MendProjector", "mindustry.world.blocks.defense.MendProjector$MendEntity", "mindustry.world.blocks.defense.OverdriveProjector", "mindustry.world.blocks.defense.OverdriveProjector$OverdriveEntity", "mindustry.world.blocks.defense.ShockMine", "mindustry.world.blocks.defense.SurgeWall", "mindustry.world.blocks.defense.Wall", "mindustry.world.blocks.defense.turrets.ArtilleryTurret", "mindustry.world.blocks.defense.turrets.BurstTurret", "mindustry.world.blocks.defense.turrets.ChargeTurret", "mindustry.world.blocks.defense.turrets.ChargeTurret$LaserTurretEntity", "mindustry.world.blocks.defense.turrets.CooledTurret", "mindustry.world.blocks.defense.turrets.DoubleTurret", "mindustry.world.blocks.defense.turrets.ItemTurret", "mindustry.world.blocks.defense.turrets.ItemTurret$ItemEntry", "mindustry.world.blocks.defense.turrets.ItemTurret$ItemTurretEntity", "mindustry.world.blocks.defense.turrets.LaserTurret", "mindustry.world.blocks.defense.turrets.LaserTurret$LaserTurretEntity", "mindustry.world.blocks.defense.turrets.LiquidTurret", "mindustry.world.blocks.defense.turrets.PowerTurret", "mindustry.world.blocks.defense.turrets.Turret", "mindustry.world.blocks.defense.turrets.Turret$AmmoEntry", "mindustry.world.blocks.defense.turrets.Turret$TurretEntity", "mindustry.world.blocks.distribution.ArmoredConveyor", "mindustry.world.blocks.distribution.BufferedItemBridge", "mindustry.world.blocks.distribution.BufferedItemBridge$BufferedItemBridgeEntity", "mindustry.world.blocks.distribution.Conveyor", "mindustry.world.blocks.distribution.Conveyor$ConveyorEntity", "mindustry.world.blocks.distribution.Conveyor$ItemPos", "mindustry.world.blocks.distribution.ExtendingItemBridge", "mindustry.world.blocks.distribution.ItemBridge", "mindustry.world.blocks.distribution.ItemBridge$ItemBridgeEntity", "mindustry.world.blocks.distribution.Junction", "mindustry.world.blocks.distribution.Junction$JunctionEntity", "mindustry.world.blocks.distribution.MassDriver", "mindustry.world.blocks.distribution.MassDriver$DriverBulletData", "mindustry.world.blocks.distribution.MassDriver$DriverState", "mindustry.world.blocks.distribution.MassDriver$MassDriverEntity", "mindustry.world.blocks.distribution.OverflowGate", "mindustry.world.blocks.distribution.OverflowGate$OverflowGateEntity", "mindustry.world.blocks.distribution.Router", "mindustry.world.blocks.distribution.Router$RouterEntity", "mindustry.world.blocks.distribution.Sorter", "mindustry.world.blocks.distribution.Sorter$SorterEntity", "mindustry.world.blocks.liquid.ArmoredConduit", "mindustry.world.blocks.liquid.Conduit", "mindustry.world.blocks.liquid.Conduit$ConduitEntity", "mindustry.world.blocks.liquid.LiquidBridge", "mindustry.world.blocks.liquid.LiquidExtendingBridge", "mindustry.world.blocks.liquid.LiquidJunction", "mindustry.world.blocks.liquid.LiquidOverflowGate", "mindustry.world.blocks.liquid.LiquidRouter", "mindustry.world.blocks.liquid.LiquidTank", "mindustry.world.blocks.logic.LogicBlock", "mindustry.world.blocks.logic.MessageBlock", "mindustry.world.blocks.logic.MessageBlock$MessageBlockEntity", "mindustry.world.blocks.power.Battery", "mindustry.world.blocks.power.BurnerGenerator", "mindustry.world.blocks.power.ConditionalConsumePower", "mindustry.world.blocks.power.DecayGenerator", "mindustry.world.blocks.power.ImpactReactor", "mindustry.world.blocks.power.ImpactReactor$FusionReactorEntity", "mindustry.world.blocks.power.ItemLiquidGenerator", "mindustry.world.blocks.power.ItemLiquidGenerator$ItemLiquidGeneratorEntity", "mindustry.world.blocks.power.LightBlock", "mindustry.world.blocks.power.LightBlock$LightEntity", "mindustry.world.blocks.power.NuclearReactor", "mindustry.world.blocks.power.NuclearReactor$NuclearReactorEntity", "mindustry.world.blocks.power.PowerDiode", "mindustry.world.blocks.power.PowerDistributor", "mindustry.world.blocks.power.PowerGenerator", "mindustry.world.blocks.power.PowerGenerator$GeneratorEntity", "mindustry.world.blocks.power.PowerGraph", "mindustry.world.blocks.power.PowerNode", "mindustry.world.blocks.power.SingleTypeGenerator", "mindustry.world.blocks.power.SolarGenerator", "mindustry.world.blocks.power.ThermalGenerator", "mindustry.world.blocks.production.Cultivator", "mindustry.world.blocks.production.Cultivator$CultivatorEntity", "mindustry.world.blocks.production.Drill", "mindustry.world.blocks.production.Drill$DrillEntity", "mindustry.world.blocks.production.Fracker", "mindustry.world.blocks.production.Fracker$FrackerEntity", "mindustry.world.blocks.production.GenericCrafter", "mindustry.world.blocks.production.GenericCrafter$GenericCrafterEntity", "mindustry.world.blocks.production.GenericSmelter", "mindustry.world.blocks.production.Incinerator", "mindustry.world.blocks.production.Incinerator$IncineratorEntity", "mindustry.world.blocks.production.LiquidConverter", "mindustry.world.blocks.production.Pump", "mindustry.world.blocks.production.Separator", "mindustry.world.blocks.production.SolidPump", "mindustry.world.blocks.production.SolidPump$SolidPumpEntity", "mindustry.world.blocks.sandbox.ItemSource", "mindustry.world.blocks.sandbox.ItemSource$ItemSourceEntity", "mindustry.world.blocks.sandbox.ItemVoid", "mindustry.world.blocks.sandbox.LiquidSource", "mindustry.world.blocks.sandbox.LiquidSource$LiquidSourceEntity", "mindustry.world.blocks.sandbox.PowerSource", "mindustry.world.blocks.sandbox.PowerVoid", "mindustry.world.blocks.storage.CoreBlock", "mindustry.world.blocks.storage.CoreBlock$CoreEntity", "mindustry.world.blocks.storage.LaunchPad", "mindustry.world.blocks.storage.StorageBlock", "mindustry.world.blocks.storage.StorageBlock$StorageBlockEntity", "mindustry.world.blocks.storage.Unloader", "mindustry.world.blocks.storage.Unloader$UnloaderEntity", "mindustry.world.blocks.storage.Vault", "mindustry.world.blocks.units.CommandCenter", "mindustry.world.blocks.units.CommandCenter$CommandCenterEntity", "mindustry.world.blocks.units.MechPad", "mindustry.world.blocks.units.MechPad$MechFactoryEntity", "mindustry.world.blocks.units.RallyPoint", "mindustry.world.blocks.units.RepairPoint", "mindustry.world.blocks.units.RepairPoint$RepairPointEntity", "mindustry.world.blocks.units.UnitFactory", "mindustry.world.blocks.units.UnitFactory$UnitFactoryEntity", "mindustry.world.consumers.Consume", "mindustry.world.consumers.ConsumeItemFilter", "mindustry.world.consumers.ConsumeItems", "mindustry.world.consumers.ConsumeLiquid", "mindustry.world.consumers.ConsumeLiquidBase", "mindustry.world.consumers.ConsumeLiquidFilter", "mindustry.world.consumers.ConsumePower", "mindustry.world.consumers.ConsumeType", "mindustry.world.consumers.Consumers", "mindustry.world.meta.Attribute", "mindustry.world.meta.BlockBars", "mindustry.world.meta.BlockFlag", "mindustry.world.meta.BlockGroup", "mindustry.world.meta.BlockStat", "mindustry.world.meta.BlockStats", "mindustry.world.meta.BuildVisibility", "mindustry.world.meta.PowerType", "mindustry.world.meta.Producers", "mindustry.world.meta.StatCategory", "mindustry.world.meta.StatUnit", "mindustry.world.meta.StatValue", "mindustry.world.meta.values.AmmoListValue", "mindustry.world.meta.values.BooleanValue", "mindustry.world.meta.values.BoosterListValue", "mindustry.world.meta.values.ItemFilterValue", "mindustry.world.meta.values.ItemListValue", "mindustry.world.meta.values.LiquidFilterValue", "mindustry.world.meta.values.LiquidValue", "mindustry.world.meta.values.NumberValue", "mindustry.world.meta.values.StringValue", "mindustry.world.modules.BlockModule", "mindustry.world.modules.ConsumeModule", "mindustry.world.modules.ItemModule", "mindustry.world.modules.ItemModule$ItemCalculator", "mindustry.world.modules.ItemModule$ItemConsumer", "mindustry.world.modules.LiquidModule", "mindustry.world.modules.LiquidModule$LiquidCalculator", "mindustry.world.modules.LiquidModule$LiquidConsumer", "mindustry.world.modules.PowerModule", "mindustry.world.producers.Produce", "mindustry.world.producers.ProduceItem"); } \ No newline at end of file diff --git a/core/src/mindustry/mod/Mods.java b/core/src/mindustry/mod/Mods.java index e4da45357b..e4907ed26c 100644 --- a/core/src/mindustry/mod/Mods.java +++ b/core/src/mindustry/mod/Mods.java @@ -2,7 +2,6 @@ package mindustry.mod; import arc.*; import arc.assets.*; -import arc.struct.*; import arc.files.*; import arc.func.*; import arc.graphics.*; @@ -10,6 +9,7 @@ import arc.graphics.Texture.*; import arc.graphics.g2d.*; import arc.graphics.g2d.TextureAtlas.*; import arc.scene.ui.*; +import arc.struct.*; import arc.util.*; import arc.util.ArcAnnotate.*; import arc.util.io.*; @@ -85,6 +85,7 @@ public class Mods implements Loadable{ try{ mods.add(loadMod(dest)); requiresReload = true; + sortMods(); }catch(IOException e){ dest.delete(); throw e; @@ -142,6 +143,17 @@ public class Mods implements Loadable{ @Override public void loadSync(){ + for(LoadedMod mod : mods){ + //try to load icon for each mod that can have one + if(mod.root.child("icon.png").exists()){ + try{ + mod.iconTexture = new Texture(mod.root.child("icon.png")); + }catch(Throwable t){ + Log.err("Failed to load icon for mod '" + mod.name + "'.", t); + } + } + } + if(packer == null) return; Time.mark(); @@ -408,6 +420,7 @@ public class Mods implements Loadable{ //TODO make it less epic Core.atlas = new TextureAtlas(Core.files.internal("sprites/sprites.atlas")); + mods.each(LoadedMod::dispose); mods.clear(); Core.bundle = I18NBundle.createBundle(Core.files.internal("bundles/bundle"), Core.bundle.getLocale()); load(); @@ -643,7 +656,7 @@ public class Mods implements Loadable{ } /** Represents a plugin that has been loaded from a jar file.*/ - public static class LoadedMod implements Publishable{ + public static class LoadedMod implements Publishable, Disposable{ /** The location of this mod's zip file/folder on the disk. */ public final Fi file; /** The root zip file; points to the contents of this mod. In the case of folders, this is the same as the mod's file. */ @@ -664,6 +677,8 @@ public class Mods implements Loadable{ public ObjectSet erroredContent = new ObjectSet<>(); /** Current state of this mod. */ public ModState state = ModState.enabled; + /** Icon texture. Should be disposed. */ + public @Nullable Texture iconTexture; public LoadedMod(Fi file, Fi root, Mod main, ModMeta meta){ this.root = root; @@ -701,6 +716,13 @@ public class Mods implements Loadable{ return Version.build >= Strings.parseInt(meta.minGameVersion, 0); } + @Override + public void dispose(){ + if(iconTexture != null){ + iconTexture.dispose(); + } + } + @Override public String getSteamID(){ return Core.settings.getString(name + "-steamid", null); diff --git a/core/src/mindustry/net/Administration.java b/core/src/mindustry/net/Administration.java index cd490eed04..dabf679d34 100644 --- a/core/src/mindustry/net/Administration.java +++ b/core/src/mindustry/net/Administration.java @@ -1,10 +1,11 @@ package mindustry.net; import arc.*; -import mindustry.annotations.Annotations.*; import arc.struct.*; -import mindustry.Vars; - +import arc.util.ArcAnnotate.*; +import mindustry.*; +import mindustry.annotations.Annotations.*; +import mindustry.entities.type.*; import static mindustry.Vars.headless; import static mindustry.game.EventType.*; @@ -14,6 +15,7 @@ public class Administration{ private ObjectMap playerInfo = new ObjectMap<>(); private Array bannedIPs = new Array<>(); private Array whitelist = new Array<>(); + private Array chatFilters = new Array<>(); public Administration(){ Core.settings.defaults( @@ -24,6 +26,23 @@ public class Administration{ load(); } + /** Adds a chat filter. This will transform the chat messages of every player. + * This functionality can be used to implement things like swear filters and special commands. + * Note that commands (starting with /) are not filtered.*/ + public void addChatFilter(ChatFilter filter){ + chatFilters.add(filter); + } + + /** Filters out a chat message. */ + public @Nullable String filterMessage(Player player, String message){ + String current = message; + for(ChatFilter f : chatFilters){ + current = f.filter(player, message); + if(current == null) return null; + } + return current; + } + public int getPlayerLimit(){ return Core.settings.getInt("playerlimit", 0); } @@ -334,6 +353,11 @@ public class Administration{ } } + public interface ChatFilter{ + /** @return the filtered message; a null string signals that the message should not be sent. */ + @Nullable String filter(Player player, String message); + } + public static class TraceInfo{ public String ip, uuid; public boolean modded, mobile; diff --git a/core/src/mindustry/ui/Bar.java b/core/src/mindustry/ui/Bar.java index c04a25167f..8c23ec0ad3 100644 --- a/core/src/mindustry/ui/Bar.java +++ b/core/src/mindustry/ui/Bar.java @@ -12,7 +12,7 @@ import arc.util.pooling.*; import mindustry.gen.*; public class Bar extends Element{ - private static Rectangle scissor = new Rectangle(); + private static Rect scissor = new Rect(); private Floatp fraction; private String name = ""; diff --git a/core/src/mindustry/ui/ItemsDisplay.java b/core/src/mindustry/ui/ItemsDisplay.java index 432417b305..d59a579c16 100644 --- a/core/src/mindustry/ui/ItemsDisplay.java +++ b/core/src/mindustry/ui/ItemsDisplay.java @@ -39,9 +39,9 @@ public class ItemsDisplay extends Table{ private String format(Item item){ builder.setLength(0); builder.append(ui.formatAmount(data.items().get(item, 0))); - if(!state.is(State.menu) && !state.teams.get(player.getTeam()).cores.isEmpty() && state.teams.get(player.getTeam()).cores.first().entity != null && state.teams.get(player.getTeam()).cores.first().entity.items.get(item) > 0){ + if(!state.is(State.menu) && player.getTeam().data().hasCore() && player.getTeam().core().items.get(item) > 0){ builder.append(" [unlaunched]+ "); - builder.append(ui.formatAmount(state.teams.get(player.getTeam()).cores.first().entity.items.get(item))); + builder.append(ui.formatAmount(state.teams.get(player.getTeam()).core().items.get(item))); } return builder.toString(); } diff --git a/core/src/mindustry/ui/dialogs/DeployDialog.java b/core/src/mindustry/ui/dialogs/DeployDialog.java index dda43d0e13..811caca161 100644 --- a/core/src/mindustry/ui/dialogs/DeployDialog.java +++ b/core/src/mindustry/ui/dialogs/DeployDialog.java @@ -33,7 +33,7 @@ public class DeployDialog extends FloatingDialog{ private final float nodeSize = Scl.scl(230f); private ObjectSet nodes = new ObjectSet<>(); private ZoneInfoDialog info = new ZoneInfoDialog(); - private Rectangle bounds = new Rectangle(); + private Rect bounds = new Rect(); private View view = new View(); public DeployDialog(){ diff --git a/core/src/mindustry/ui/dialogs/TechTreeDialog.java b/core/src/mindustry/ui/dialogs/TechTreeDialog.java index 6bbb249a66..0d28af70c5 100644 --- a/core/src/mindustry/ui/dialogs/TechTreeDialog.java +++ b/core/src/mindustry/ui/dialogs/TechTreeDialog.java @@ -31,7 +31,7 @@ public class TechTreeDialog extends FloatingDialog{ private final float nodeSize = Scl.scl(60f); private ObjectSet nodes = new ObjectSet<>(); private TechTreeNode root = new TechTreeNode(TechTree.root, null); - private Rectangle bounds = new Rectangle(); + private Rect bounds = new Rect(); private ItemsDisplay items; private View view; @@ -123,7 +123,7 @@ public class TechTreeDialog extends FloatingDialog{ miny = Math.min(n.y - n.height/2f, miny); maxy = Math.max(n.y + n.height/2f, maxy); } - bounds = new Rectangle(minx, miny, maxx - minx, maxy - miny); + bounds = new Rect(minx, miny, maxx - minx, maxy - miny); bounds.y += nodeSize*1.5f; } diff --git a/core/src/mindustry/ui/fragments/HudFragment.java b/core/src/mindustry/ui/fragments/HudFragment.java index 80e5dc0185..688923924c 100644 --- a/core/src/mindustry/ui/fragments/HudFragment.java +++ b/core/src/mindustry/ui/fragments/HudFragment.java @@ -168,7 +168,7 @@ public class HudFragment extends Fragment{ t.table(teams -> { teams.left(); int i = 0; - for(Team team : Team.all){ + for(Team team : Team.base()){ ImageButton button = teams.addImageButton(Tex.whiteui, Styles.clearTogglePartiali, 40f, () -> Call.setPlayerTeamEditor(player, team)) .size(50f).margin(6f).get(); button.getImageCell().grow(); @@ -287,7 +287,7 @@ public class HudFragment extends Fragment{ }); t.top().visible(() -> { - if(state.is(State.menu) || state.teams.get(player.getTeam()).cores.size == 0 || state.teams.get(player.getTeam()).cores.first().entity == null){ + if(state.is(State.menu) || !state.teams.get(player.getTeam()).hasCore()){ coreAttackTime[0] = 0f; return false; } @@ -557,7 +557,7 @@ public class HudFragment extends Fragment{ } private boolean canLaunch(){ - return inLaunchWave() && state.enemies() <= 0; + return inLaunchWave() && state.enemies <= 0; } private void toggleMenus(){ @@ -604,7 +604,7 @@ public class HudFragment extends Fragment{ if(inLaunchWave()){ builder.append("[#"); - Tmp.c1.set(Color.white).lerp(state.enemies() > 0 ? Color.white : Color.scarlet, Mathf.absin(Time.time(), 2f, 1f)).toString(builder); + Tmp.c1.set(Color.white).lerp(state.enemies > 0 ? Color.white : Color.scarlet, Mathf.absin(Time.time(), 2f, 1f)).toString(builder); builder.append("]"); if(!canLaunch()){ @@ -618,18 +618,18 @@ public class HudFragment extends Fragment{ builder.append("[]\n"); } - if(state.enemies() > 0){ - if(state.enemies() == 1){ - builder.append(enemyf.get(state.enemies())); + if(state.enemies > 0){ + if(state.enemies == 1){ + builder.append(enemyf.get(state.enemies)); }else{ - builder.append(enemiesf.get(state.enemies())); + builder.append(enemiesf.get(state.enemies)); } builder.append("\n"); } if(state.rules.waveTimer){ - builder.append((state.rules.waitForWaveToEnd && unitGroups[waveTeam.ordinal()].size() > 0) ? Core.bundle.get("wave.waveInProgress") : ( waitingf.get((int)(state.wavetime/60)))); - }else if(state.enemies() == 0){ + builder.append((state.rules.waitForWaveToEnd && state.enemies > 0 ? Core.bundle.get("wave.waveInProgress") : ( waitingf.get((int)(state.wavetime/60))))); + }else if(state.enemies == 0){ builder.append(Core.bundle.get("waiting")); } @@ -646,7 +646,7 @@ public class HudFragment extends Fragment{ } private boolean canSkipWave(){ - return state.rules.waves && ((net.server() || player.isAdmin) || !net.active()) && state.enemies() == 0 && !spawner.isSpawning() && !state.rules.tutorial; + return state.rules.waves && ((net.server() || player.isAdmin) || !net.active()) && state.enemies == 0 && !spawner.isSpawning() && !state.rules.tutorial; } private void addPlayButton(Table table){ diff --git a/core/src/mindustry/ui/fragments/PlayerListFragment.java b/core/src/mindustry/ui/fragments/PlayerListFragment.java index df0d9f7269..a9cca9fb85 100644 --- a/core/src/mindustry/ui/fragments/PlayerListFragment.java +++ b/core/src/mindustry/ui/fragments/PlayerListFragment.java @@ -8,6 +8,7 @@ import arc.scene.ui.*; import arc.scene.ui.layout.*; import arc.util.*; import mindustry.core.GameState.*; +import mindustry.entities.type.*; import mindustry.gen.*; import mindustry.graphics.*; import mindustry.net.*; @@ -65,7 +66,7 @@ public class PlayerListFragment extends Fragment{ float h = 74f; - playerGroup.all().sort((p1, p2) -> p1.getTeam().compareTo(p2.getTeam())); + playerGroup.all().sort(Structs.comparing(Unit::getTeam)); playerGroup.all().each(user -> { NetConnection connection = user.con; diff --git a/core/src/mindustry/ui/layout/BranchTreeLayout.java b/core/src/mindustry/ui/layout/BranchTreeLayout.java index b012d68e71..07c3fb5497 100644 --- a/core/src/mindustry/ui/layout/BranchTreeLayout.java +++ b/core/src/mindustry/ui/layout/BranchTreeLayout.java @@ -66,8 +66,8 @@ public class BranchTreeLayout implements TreeLayout{ } } - public Rectangle getBounds(){ - return new Rectangle(boundsLeft, boundsBottom, boundsRight - boundsLeft, boundsTop - boundsBottom); + public Rect getBounds(){ + return new Rect(boundsLeft, boundsBottom, boundsRight - boundsLeft, boundsTop - boundsBottom); } private void calcSizeOfLevels(TreeNode node, int level){ diff --git a/core/src/mindustry/world/Block.java b/core/src/mindustry/world/Block.java index 4b3999cb5e..b5eabb9a72 100644 --- a/core/src/mindustry/world/Block.java +++ b/core/src/mindustry/world/Block.java @@ -866,7 +866,7 @@ public class Block extends BlockStorage{ return ((size + 1) % 2) * tilesize / 2f; } - public Rectangle bounds(int x, int y, Rectangle rect){ + public Rect bounds(int x, int y, Rect rect){ return rect.setSize(size * tilesize).setCenter(x * tilesize + offset(), y * tilesize + offset()); } diff --git a/core/src/mindustry/world/Build.java b/core/src/mindustry/world/Build.java index dafd9fe38d..b8d41df4f0 100644 --- a/core/src/mindustry/world/Build.java +++ b/core/src/mindustry/world/Build.java @@ -38,7 +38,7 @@ public class Build{ Block previous = tile.block(); Block sub = BuildBlock.get(previous.size); - world.setBlock(tile, sub, team, rotation); + tile.set(sub, team, rotation); tile.ent().setDeconstruct(previous); tile.entity.health = tile.entity.maxHealth() * prevPercent; @@ -60,7 +60,7 @@ public class Build{ Block previous = tile.block(); Block sub = BuildBlock.get(result.size); - world.setBlock(tile, sub, team, rotation); + tile.set(sub, team, rotation); tile.ent().setConstruct(previous, result); Core.app.post(() -> Events.fire(new BlockBuildBeginEvent(tile, team, false))); @@ -72,7 +72,7 @@ public class Build{ return false; } - if(state.rules.bannedBlocks.contains(type) && !(state.rules.waves && team == waveTeam)){ + if(state.rules.bannedBlocks.contains(type) && !(state.rules.waves && team == state.rules.waveTeam)){ return false; } @@ -80,13 +80,8 @@ public class Build{ return false; } - //check for enemy cores - for(Team enemy : state.teams.enemiesOf(team)){ - for(Tile core : state.teams.get(enemy).cores){ - if(Mathf.dst(x * tilesize + type.offset(), y * tilesize + type.offset(), core.drawx(), core.drawy()) < state.rules.enemyCoreBuildRadius + type.size * tilesize / 2f){ - return false; - } - } + if(state.teams.eachEnemyCore(team, core -> Mathf.dst(x * tilesize + type.offset(), y * tilesize + type.offset(), core.x, core.y) < state.rules.enemyCoreBuildRadius + type.size * tilesize / 2f)){ + return false; } Tile tile = world.tile(x, y); diff --git a/core/src/mindustry/world/CachedTile.java b/core/src/mindustry/world/CachedTile.java index e46a57d3ba..281828dcd7 100644 --- a/core/src/mindustry/world/CachedTile.java +++ b/core/src/mindustry/world/CachedTile.java @@ -16,7 +16,7 @@ public class CachedTile extends Tile{ @Override public Team getTeam(){ - return Team.all[getTeamID()]; + return Team.get(getTeamID()); } @Override diff --git a/core/src/mindustry/world/Tile.java b/core/src/mindustry/world/Tile.java index 1ac2871bab..0572c74286 100644 --- a/core/src/mindustry/world/Tile.java +++ b/core/src/mindustry/world/Tile.java @@ -142,11 +142,11 @@ public class Tile implements Position, TargetTrait{ @Override public Team getTeam(){ - return Team.all[link().team]; + return Team.get(link().team); } public void setTeam(Team team){ - this.team = (byte)team.ordinal(); + this.team = (byte) team.id; } public byte getTeamID(){ @@ -156,7 +156,7 @@ public class Tile implements Position, TargetTrait{ public void setBlock(@NonNull Block type, Team team, int rotation){ preChanged(); this.block = type; - this.team = (byte)team.ordinal(); + this.team = (byte) team.id; this.rotation = (byte)Mathf.mod(rotation, 4); changed(); } @@ -186,6 +186,35 @@ public class Tile implements Position, TargetTrait{ setOverlay(overlay); } + public void remove(){ + link().getLinkedTiles(other -> other.setBlock(Blocks.air)); + } + + public void set(Block block, Team team){ + set(block, team, 0); + } + + public void set(Block block, Team team, int rotation){ + setBlock(block, team, rotation); + if(block.isMultiblock()){ + int offsetx = -(block.size - 1) / 2; + int offsety = -(block.size - 1) / 2; + + for(int dx = 0; dx < block.size; dx++){ + for(int dy = 0; dy < block.size; dy++){ + int worldx = dx + offsetx + x; + int worldy = dy + offsety + y; + if(!(worldx == x && worldy == y)){ + Tile toplace = world.tile(worldx, worldy); + if(toplace != null){ + toplace.setBlock(BlockPart.get(dx + offsetx, dy + offsety), team); + } + } + } + } + } + } + public byte rotation(){ return rotation; } @@ -240,7 +269,7 @@ public class Tile implements Position, TargetTrait{ } public boolean isEnemyCheat(){ - return getTeam() == waveTeam && state.rules.enemyCheat; + return getTeam() == state.rules.waveTeam && state.rules.enemyCheat; } public boolean isLinked(){ @@ -298,7 +327,7 @@ public class Tile implements Position, TargetTrait{ return tmpArray; } - public Rectangle getHitbox(Rectangle rect){ + public Rect getHitbox(Rect rect){ return rect.setSize(block().size * tilesize).setCenter(drawx(), drawy()); } @@ -344,7 +373,7 @@ public class Tile implements Position, TargetTrait{ } public boolean interactable(Team team){ - return getTeam() == Team.derelict || team == getTeam(); + return state.teams.canInteract(team, getTeam()); } public Item drop(){ diff --git a/core/src/mindustry/world/blocks/BuildBlock.java b/core/src/mindustry/world/blocks/BuildBlock.java index 69d9ba61e8..79061db553 100644 --- a/core/src/mindustry/world/blocks/BuildBlock.java +++ b/core/src/mindustry/world/blocks/BuildBlock.java @@ -57,7 +57,7 @@ public class BuildBlock extends Block{ public static void onDeconstructFinish(Tile tile, Block block, int builderID){ Team team = tile.getTeam(); Effects.effect(Fx.breakBlock, tile.drawx(), tile.drawy(), block.size); - world.removeBlock(tile); + tile.remove(); Events.fire(new BlockBuildEndEvent(tile, playerGroup.getByID(builderID), team, true)); if(shouldPlay()) Sounds.breaks.at(tile, calcPitch(false)); } @@ -66,7 +66,7 @@ public class BuildBlock extends Block{ public static void onConstructFinish(Tile tile, Block block, int builderID, byte rotation, Team team, boolean skipConfig){ if(tile == null) return; float healthf = tile.entity == null ? 1f : tile.entity.healthf(); - world.setBlock(tile, block, team, rotation); + tile.set(block, team, rotation); if(tile.entity != null){ tile.entity.health = block.health * healthf; } @@ -337,6 +337,7 @@ public class BuildBlock extends Block{ } public void setDeconstruct(Block previous){ + if(previous == null) return; this.previous = previous; this.progress = 1f; if(previous.buildCost >= 0.01f){ diff --git a/core/src/mindustry/world/blocks/StaticWall.java b/core/src/mindustry/world/blocks/StaticWall.java index d81e0521db..531fb010a2 100644 --- a/core/src/mindustry/world/blocks/StaticWall.java +++ b/core/src/mindustry/world/blocks/StaticWall.java @@ -43,9 +43,9 @@ public class StaticWall extends Rock{ boolean eq(int rx, int ry){ return rx < world.width() - 1 && ry < world.height() - 1 - && world.tile(rx + 1, ry).block() == this - && world.tile(rx, ry + 1).block() == this - && world.tile(rx, ry).block() == this - && world.tile(rx + 1, ry + 1).block() == this; + && world.tile(rx + 1, ry).block() == this + && world.tile(rx, ry + 1).block() == this + && world.tile(rx, ry).block() == this + && world.tile(rx + 1, ry + 1).block() == this; } } diff --git a/core/src/mindustry/world/blocks/defense/DeflectorWall.java b/core/src/mindustry/world/blocks/defense/DeflectorWall.java index cf8f54a8ce..ae535ca8a6 100644 --- a/core/src/mindustry/world/blocks/defense/DeflectorWall.java +++ b/core/src/mindustry/world/blocks/defense/DeflectorWall.java @@ -15,8 +15,8 @@ public class DeflectorWall extends Wall{ public static final float hitTime = 10f; protected float maxDamageDeflect = 10f; - protected Rectangle rect = new Rectangle(); - protected Rectangle rect2 = new Rectangle(); + protected Rect rect = new Rect(); + protected Rect rect2 = new Rect(); public DeflectorWall(String name){ super(name); diff --git a/core/src/mindustry/world/blocks/defense/Door.java b/core/src/mindustry/world/blocks/defense/Door.java index 27a0d26bff..df75416207 100644 --- a/core/src/mindustry/world/blocks/defense/Door.java +++ b/core/src/mindustry/world/blocks/defense/Door.java @@ -18,7 +18,7 @@ import java.io.*; import static mindustry.Vars.*; public class Door extends Wall{ - protected final static Rectangle rect = new Rectangle(); + protected final static Rect rect = new Rect(); public final int timerToggle = timers++; public Effect openfx = Fx.dooropen; diff --git a/core/src/mindustry/world/blocks/storage/CoreBlock.java b/core/src/mindustry/world/blocks/storage/CoreBlock.java index 7c766fd1d3..f9a5cf6c9b 100644 --- a/core/src/mindustry/world/blocks/storage/CoreBlock.java +++ b/core/src/mindustry/world/blocks/storage/CoreBlock.java @@ -84,12 +84,12 @@ public class CoreBlock extends StorageBlock{ public void onProximityUpdate(Tile tile){ CoreEntity entity = tile.ent(); - for(Tile other : state.teams.get(tile.getTeam()).cores){ - if(other != tile){ - entity.items = other.entity.items; + for(TileEntity other : state.teams.cores(tile.getTeam())){ + if(other.tile != tile){ + entity.items = other.items; } } - state.teams.get(tile.getTeam()).cores.add(tile); + state.teams.registerCore(entity); entity.storageCapacity = itemCapacity + entity.proximity().sum(e -> isContainer(e) ? e.block().itemCapacity : 0); entity.proximity().each(this::isContainer, t -> { @@ -97,9 +97,9 @@ public class CoreBlock extends StorageBlock{ t.ent().linkedCore = tile; }); - for(Tile other : state.teams.get(tile.getTeam()).cores){ - if(other == tile) continue; - entity.storageCapacity += other.block().itemCapacity + other.entity.proximity().sum(e -> isContainer(e) ? e.block().itemCapacity : 0); + for(TileEntity other : state.teams.cores(tile.getTeam())){ + if(other.tile == tile) continue; + entity.storageCapacity += other.block.itemCapacity + entity.proximity().sum(e -> isContainer(e) ? e.block().itemCapacity : 0); } if(!world.isGenerating()){ @@ -108,9 +108,8 @@ public class CoreBlock extends StorageBlock{ } } - for(Tile other : state.teams.get(tile.getTeam()).cores){ - CoreEntity oe = other.ent(); - oe.storageCapacity = entity.storageCapacity; + for(CoreEntity other : state.teams.cores(tile.getTeam())){ + other.storageCapacity = entity.storageCapacity; } } @@ -151,8 +150,9 @@ public class CoreBlock extends StorageBlock{ @Override public void removed(Tile tile){ + CoreEntity entity = tile.ent(); int total = tile.entity.proximity().count(e -> e.entity.items == tile.entity.items); - float fract = 1f / total / state.teams.get(tile.getTeam()).cores.size; + float fract = 1f / total / state.teams.cores(tile.getTeam()).size; tile.entity.proximity().each(e -> isContainer(e) && e.entity.items == tile.entity.items, t -> { StorageBlockEntity ent = (StorageBlockEntity)t.entity; @@ -163,22 +163,23 @@ public class CoreBlock extends StorageBlock{ } }); - state.teams.get(tile.getTeam()).cores.remove(tile); + state.teams.unregisterCore(entity); - int max = itemCapacity * state.teams.get(tile.getTeam()).cores.size; + int max = itemCapacity * state.teams.cores(tile.getTeam()).size; for(Item item : content.items()){ tile.entity.items.set(item, Math.min(tile.entity.items.get(item), max)); } - for(Tile other : state.teams.get(tile.getTeam()).cores){ - other.block().onProximityUpdate(other); + for(CoreEntity other : state.teams.cores(tile.getTeam())){ + other.block.onProximityUpdate(other.tile); } } @Override public void placed(Tile tile){ super.placed(tile); - state.teams.get(tile.getTeam()).cores.add(tile); + CoreEntity entity = tile.ent(); + state.teams.registerCore(entity); } @Override diff --git a/core/src/mindustry/world/blocks/units/CommandCenter.java b/core/src/mindustry/world/blocks/units/CommandCenter.java index 9e9312af75..be82783269 100644 --- a/core/src/mindustry/world/blocks/units/CommandCenter.java +++ b/core/src/mindustry/world/blocks/units/CommandCenter.java @@ -1,11 +1,11 @@ package mindustry.world.blocks.units; import arc.*; -import arc.struct.*; import arc.graphics.*; import arc.graphics.g2d.*; import arc.scene.ui.*; import arc.scene.ui.layout.*; +import arc.struct.*; import arc.util.*; import mindustry.content.*; import mindustry.entities.*; @@ -13,7 +13,6 @@ import mindustry.entities.Effects.*; import mindustry.entities.type.*; import mindustry.entities.units.*; import mindustry.game.EventType.*; -import mindustry.game.*; import mindustry.graphics.*; import mindustry.ui.*; import mindustry.world.*; @@ -21,7 +20,7 @@ import mindustry.world.meta.*; import java.io.*; -import static mindustry.Vars.*; +import static mindustry.Vars.indexer; public class CommandCenter extends Block{ protected TextureRegion[] commandRegions = new TextureRegion[UnitCommand.all.length]; @@ -58,9 +57,7 @@ public class CommandCenter extends Block{ ObjectSet set = indexer.getAllied(tile.getTeam(), BlockFlag.comandCenter); if(set.size == 1){ - for(BaseUnit unit : unitGroups[tile.getTeam().ordinal()].all()){ - unit.onCommand(UnitCommand.all[0]); - } + Units.each(tile.getTeam(), u -> u.onCommand(UnitCommand.all[0])); } } @@ -114,12 +111,7 @@ public class CommandCenter extends Block{ } } - Team team = (player == null ? tile.getTeam() : player.getTeam()); - - for(BaseUnit unit : unitGroups[team.ordinal()].all()){ - unit.onCommand(command); - } - + Units.each(tile.getTeam(), u -> u.onCommand(command)); Events.fire(new CommandIssueEvent(tile, command)); } diff --git a/core/src/mindustry/world/blocks/units/RepairPoint.java b/core/src/mindustry/world/blocks/units/RepairPoint.java index 183404148d..a17fffe1b1 100644 --- a/core/src/mindustry/world/blocks/units/RepairPoint.java +++ b/core/src/mindustry/world/blocks/units/RepairPoint.java @@ -6,7 +6,7 @@ import arc.graphics.Color; import arc.graphics.g2d.*; import arc.math.Angles; import arc.math.Mathf; -import arc.math.geom.Rectangle; +import arc.math.geom.Rect; import arc.util.Time; import mindustry.entities.Units; import mindustry.entities.type.TileEntity; @@ -19,7 +19,7 @@ import mindustry.world.meta.*; import static mindustry.Vars.tilesize; public class RepairPoint extends Block{ - private static Rectangle rect = new Rectangle(); + private static Rect rect = new Rect(); public int timerTarget = timers++; diff --git a/desktop/build.gradle b/desktop/build.gradle index efedf8c57b..d03320d394 100644 --- a/desktop/build.gradle +++ b/desktop/build.gradle @@ -33,7 +33,7 @@ task run(dependsOn: classes, type: JavaExec){ } if(args.contains("debug")){ - main = "io.anuke.mindustry.DebugLauncher" + main = "mindustry.debug.DebugLauncher" } } diff --git a/desktop/src/mindustry/desktop/steam/SStats.java b/desktop/src/mindustry/desktop/steam/SStats.java index ee1ab916bc..950bffc249 100644 --- a/desktop/src/mindustry/desktop/steam/SStats.java +++ b/desktop/src/mindustry/desktop/steam/SStats.java @@ -1,9 +1,9 @@ package mindustry.desktop.steam; import arc.*; -import com.codedisaster.steamworks.*; import arc.struct.*; import arc.util.*; +import com.codedisaster.steamworks.*; import mindustry.*; import mindustry.content.*; import mindustry.entities.type.*; @@ -11,7 +11,6 @@ import mindustry.entities.units.*; import mindustry.game.EventType.*; import mindustry.game.Stats.*; import mindustry.type.*; -import mindustry.world.*; import static mindustry.Vars.*; import static mindustry.desktop.steam.SAchievement.*; @@ -55,18 +54,18 @@ public class SStats implements SteamUserStatsCallback{ private void checkUpdate(){ if(campaign()){ - SStat.maxUnitActive.max(unitGroups[player.getTeam().ordinal()].size()); + SStat.maxUnitActive.max(unitGroup.count(t -> t.getTeam() == player.getTeam())); - if(unitGroups[player.getTeam().ordinal()].count(u -> u.getType() == UnitTypes.phantom) >= 10){ + if(unitGroup.count(u -> u.getType() == UnitTypes.phantom && u.getTeam() == player.getTeam()) >= 10){ active10Phantoms.complete(); } - if(unitGroups[player.getTeam().ordinal()].count(u -> u.getType() == UnitTypes.crawler) >= 50){ + if(unitGroup.count(u -> u.getType() == UnitTypes.crawler && u.getTeam() == player.getTeam()) >= 50){ active50Crawlers.complete(); } - for(Tile tile : state.teams.get(player.getTeam()).cores){ - if(!content.items().contains(i -> i.type == ItemType.material && tile.entity.items.get(i) < tile.block().itemCapacity)){ + for(TileEntity entity : player.getTeam().cores()){ + if(!content.items().contains(i -> i.type == ItemType.material && entity.items.get(i) < entity.block.itemCapacity)){ fillCoreAllCampaign.complete(); break; } diff --git a/gradle.properties b/gradle.properties index 29c1e50fad..19101944cf 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,3 +1,3 @@ org.gradle.daemon=true org.gradle.jvmargs=-Xms256m -Xmx1024m -archash=88c1a9afe2f5be4dd06e47ac8afe070247b3da29 +archash=60a9ebe264f92f2c3082596c77b9ab29474c4a7f diff --git a/server/src/mindustry/server/ServerControl.java b/server/src/mindustry/server/ServerControl.java index b821d5dcd5..3637ac972e 100644 --- a/server/src/mindustry/server/ServerControl.java +++ b/server/src/mindustry/server/ServerControl.java @@ -135,7 +135,7 @@ public class ServerControl implements ApplicationListener{ if(state.rules.waves){ info("&lcGame over! Reached wave &ly{0}&lc with &ly{1}&lc players online on map &ly{2}&lc.", state.wave, playerGroup.size(), Strings.capitalize(world.getMap().name())); }else{ - info("&lcGame over! Team &ly{0}&lc is victorious with &ly{1}&lc players online on map &ly{2}&lc.", event.winner.name(), playerGroup.size(), Strings.capitalize(world.getMap().name())); + info("&lcGame over! Team &ly{0}&lc is victorious with &ly{1}&lc players online on map &ly{2}&lc.", event.winner.name, playerGroup.size(), Strings.capitalize(world.getMap().name())); } //set next map to be played @@ -143,7 +143,7 @@ public class ServerControl implements ApplicationListener{ nextMapOverride = null; if(map != null){ Call.onInfoMessage((state.rules.pvp - ? "[YELLOW]The " + event.winner.name() + " team is victorious![]" : "[SCARLET]Game over![]") + ? "[YELLOW]The " + event.winner.name + " team is victorious![]" : "[SCARLET]Game over![]") + "\nNext selected map:[accent] " + map.name() + "[]" + (map.tags.containsKey("author") && !map.tags.get("author").trim().isEmpty() ? " by[accent] " + map.author() + "[]" : "") + "." + "\nNew game begins in " + roundExtraTime + "[] seconds."); @@ -292,7 +292,7 @@ public class ServerControl implements ApplicationListener{ info(" &lyPlaying on map &fi{0}&fb &lb/&ly Wave {1}", Strings.capitalize(world.getMap().name()), state.wave); if(state.rules.waves){ - info("&ly {0} enemies.", unitGroups[Team.crux.ordinal()].size()); + info("&ly {0} enemies.", state.enemies); }else{ info("&ly {0} seconds until next wave.", (int)(state.wavetime / 60)); } @@ -418,24 +418,26 @@ public class ServerControl implements ApplicationListener{ return; } - try{ - Team team = arg.length == 0 ? Team.sharded : Team.valueOf(arg[0]); + Team team = arg.length == 0 ? Team.sharded : Structs.find(Team.all(), t -> t.name.equals(arg[0])); - if(state.teams.get(team).cores.isEmpty()){ - err("That team has no cores."); - return; - } - - for(Item item : content.items()){ - if(item.type == ItemType.material){ - state.teams.get(team).cores.first().entity.items.set(item, state.teams.get(team).cores.first().block().itemCapacity); - } - } - - info("Core filled."); - }catch(IllegalArgumentException ignored){ - err("No such team exists."); + if(team == null){ + err("No team with that name found."); + return; } + + if(state.teams.cores(team).isEmpty()){ + err("That team has no cores."); + return; + } + + for(Item item : content.items()){ + if(item.type == ItemType.material){ + state.teams.cores(team).first().items.set(item, state.teams.cores(team).first().block.itemCapacity); + } + } + + info("Core filled."); + }); handler.register("name", "[name...]", "Change the server display name.", arg -> { diff --git a/tests/src/test/java/ApplicationTests.java b/tests/src/test/java/ApplicationTests.java index dfda5822c9..722bf246d0 100644 --- a/tests/src/test/java/ApplicationTests.java +++ b/tests/src/test/java/ApplicationTests.java @@ -106,8 +106,8 @@ public class ApplicationTests{ Time.update(); Time.update(); Time.setDeltaProvider(() -> 1f); - unitGroups[waveTeam.ordinal()].updateEvents(); - assertFalse(unitGroups[waveTeam.ordinal()].isEmpty(), "No enemies spawned."); + unitGroup.update(); + assertFalse(unitGroup.isEmpty(), "No enemies spawned."); } @Test @@ -128,7 +128,7 @@ public class ApplicationTests{ createMap(); int bx = 4; int by = 4; - world.setBlock(world.tile(bx, by), Blocks.coreShard, Team.sharded); + world.tile(bx, by).set(Blocks.coreShard, Team.sharded); assertEquals(world.tile(bx, by).getTeam(), Team.sharded); for(int x = bx - 1; x <= bx + 1; x++){ for(int y = by - 1; y <= by + 1; y++){ @@ -198,7 +198,7 @@ public class ApplicationTests{ @Test void save(){ world.loadMap(testMap); - assertTrue(state.teams.get(defaultTeam).cores.size > 0); + assertTrue(state.teams.playerCores().size > 0); SaveIO.save(saveDirectory.child("0.msav")); } @@ -213,7 +213,7 @@ public class ApplicationTests{ assertEquals(world.width(), map.width); assertEquals(world.height(), map.height); - assertTrue(state.teams.get(defaultTeam).cores.size > 0); + assertTrue(state.teams.playerCores().size > 0); } @Test @@ -379,12 +379,12 @@ public class ApplicationTests{ createMap(); Tile core = world.tile(5, 5); - world.setBlock(core, Blocks.coreShard, Team.sharded); + core.set(Blocks.coreShard, Team.sharded); for(Item item : content.items()){ core.entity.items.set(item, 3000); } - assertEquals(core, state.teams.get(Team.sharded).cores.first()); + assertEquals(core.entity, state.teams.get(Team.sharded).core()); } void depositTest(Block block, Item item){ diff --git a/tests/src/test/java/IOTests.java b/tests/src/test/java/IOTests.java index 240334f6dd..79f7a213cf 100644 --- a/tests/src/test/java/IOTests.java +++ b/tests/src/test/java/IOTests.java @@ -1,11 +1,11 @@ +import arc.util.*; import mindustry.game.*; -import mindustry.io.TypeIO; -import org.junit.jupiter.api.Test; +import mindustry.io.*; +import org.junit.jupiter.api.*; -import java.nio.ByteBuffer; +import java.nio.*; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.*; public class IOTests{ @@ -49,5 +49,23 @@ public class IOTests{ assertEquals(rules.attackMode, res.attackMode); } + @Test + void writeRules2(){ + Rules rules = new Rules(); + rules.attackMode = true; + rules.tags.put("blah", "bleh"); + rules.buildSpeedMultiplier = 99.1f; + String str = JsonIO.write(rules); + Rules res = JsonIO.read(Rules.class, str); + + assertEquals(rules.buildSpeedMultiplier, res.buildSpeedMultiplier); + assertEquals(rules.attackMode, res.attackMode); + assertEquals(rules.tags.get("blah"), res.tags.get("blah")); + + String str2 = JsonIO.write(new Rules(){{ + attackMode = true; + }}); + Log.info(str2); + } } diff --git a/tests/src/test/java/ZoneTests.java b/tests/src/test/java/ZoneTests.java index 2a044d5b75..a238a815ee 100644 --- a/tests/src/test/java/ZoneTests.java +++ b/tests/src/test/java/ZoneTests.java @@ -52,7 +52,7 @@ public class ZoneTests{ if(tile.drop() != null){ resources.add(tile.drop()); } - if(tile.block() instanceof CoreBlock && tile.getTeam() == defaultTeam){ + if(tile.block() instanceof CoreBlock && tile.getTeam() == state.rules.defaultTeam){ hasSpawnPoint = true; } } @@ -69,7 +69,7 @@ public class ZoneTests{ } assertTrue(hasSpawnPoint, "Zone \"" + zone.name + "\" has no spawn points."); - assertTrue(spawner.countSpawns() > 0 || (state.rules.attackMode && !state.teams.get(waveTeam).cores.isEmpty()), "Zone \"" + zone.name + "\" has no enemy spawn points: " + spawner.countSpawns()); + assertTrue(spawner.countSpawns() > 0 || (state.rules.attackMode && state.teams.get(state.rules.waveTeam).hasCore()), "Zone \"" + zone.name + "\" has no enemy spawn points: " + spawner.countSpawns()); for(Item item : resources){ assertTrue(zone.resources.contains(item), "Zone \"" + zone.name + "\" is missing item in resource list: \"" + item.name + "\""); diff --git a/tests/src/test/java/power/PowerTestFixture.java b/tests/src/test/java/power/PowerTestFixture.java index fd445a2c25..e5735052f5 100644 --- a/tests/src/test/java/power/PowerTestFixture.java +++ b/tests/src/test/java/power/PowerTestFixture.java @@ -27,6 +27,7 @@ public class PowerTestFixture{ @BeforeAll static void initializeDependencies(){ Core.graphics = new FakeGraphics(); + Vars.state = new GameState(); Vars.content = new ContentLoader(){ @Override public void handleMappableContent(MappableContent content){ diff --git a/tests/src/test/java/power/PowerTests.java b/tests/src/test/java/power/PowerTests.java index f017bf6e82..6815f2e880 100644 --- a/tests/src/test/java/power/PowerTests.java +++ b/tests/src/test/java/power/PowerTests.java @@ -3,6 +3,8 @@ package power; import arc.*; import arc.math.*; import arc.util.*; +import mindustry.*; +import mindustry.core.*; import mindustry.world.*; import mindustry.world.blocks.power.*; import mindustry.world.consumers.*; @@ -23,6 +25,7 @@ public class PowerTests extends PowerTestFixture{ @BeforeAll static void init(){ Core.graphics = new FakeGraphics(); + Vars.state = new GameState(); } @Nested diff --git a/tools/build.gradle b/tools/build.gradle index ea158a66a1..033040e96d 100644 --- a/tools/build.gradle +++ b/tools/build.gradle @@ -240,7 +240,7 @@ task swapColors(){ Color.argb8888ToColor(tmpc, c) if(tmpc.a < 0.1f) continue if(map.containsKey(c)){ - img.setRGB(x, y, (int) map.get(c)) + img.setRGB(x, y, (int)map.get(c)) } } }