a bit less broken but still broken

This commit is contained in:
Anuken
2019-05-05 19:05:46 -04:00
parent 35b158dba7
commit bf073a84c8
57 changed files with 274 additions and 445 deletions

View File

@@ -171,12 +171,10 @@ public class BlockIndexer{
for(int tx = rx * structQuadrantSize; tx < (rx + 1) * structQuadrantSize && tx < world.width(); tx++){
for(int ty = ry * structQuadrantSize; ty < (ry + 1) * structQuadrantSize && ty < world.height(); ty++){
Tile other = world.tile(tx, ty);
Tile other = world.ltile(tx, ty);
if(other == null) continue;
other = other.target();
if(other.entity == null || other.getTeam() != team || !pred.test(other) || !other.block().targetable)
continue;
@@ -293,7 +291,7 @@ public class BlockIndexer{
outer:
for(int x = quadrantX * structQuadrantSize; x < world.width() && x < (quadrantX + 1) * structQuadrantSize; x++){
for(int y = quadrantY * structQuadrantSize; y < world.height() && y < (quadrantY + 1) * structQuadrantSize; y++){
Tile result = world.tile(x, y).target();
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(index);

View File

@@ -83,7 +83,7 @@ public class Pathfinder{
}
private boolean passable(Tile tile, Team team){
return (!tile.solid()) || (tile.breakable() && (tile.target().getTeam() != team));
return (!tile.solid()) || (tile.breakable() && (tile.getTeam() != team));
}
/**

View File

@@ -112,16 +112,19 @@ public class Blocks implements ContentList{
//create special blockpart variants
for(int dx = 0; dx < BlockPart.maxSize; dx++){
for(int dy = 0; dy < BlockPart.maxSize; dy++){
new BlockPart(dx - BlockPart.maxSize/2, dy - BlockPart.maxSize/2);
int fx = dx - BlockPart.maxSize/2, fy = dy - BlockPart.maxSize/2;
if(fx != 0 || fy != 0){
new BlockPart(fx, fy);
}
}
}
spawn = new Block("spawn");
//Registers build blocks from size 1-6
//Registers build blocks
//no reference is needed here since they can be looked up by name later
for(int i = 1; i <= 6; i++){
new BuildBlock("build" + i);
for(int i = 1; i <= BuildBlock.maxSize; i++){
new BuildBlock(i);
}
deepwater = new Floor("deepwater"){{
@@ -561,7 +564,7 @@ public class Blocks implements ContentList{
drawer = tile -> {
LiquidModule mod = tile.entity.liquids;
int rotation = rotate ? tile.getRotation() * 90 : 0;
int rotation = rotate ? tile.rotation() * 90 : 0;
Draw.rect(reg(bottomRegion), tile.drawx(), tile.drawy(), rotation);

View File

@@ -398,9 +398,9 @@ public class Bullets implements ContentList{
@Override
public void hitTile(Bullet b, Tile tile){
super.hit(b);
tile = tile.target();
tile = tile.link();
if(tile != null && tile.getTeam() == b.getTeam() && !(tile.block() instanceof BuildBlock)){
if(tile.getTeam() == b.getTeam() && !(tile.block() instanceof BuildBlock)){
Effects.effect(Fx.healBlockFull, Pal.heal, tile.drawx(), tile.drawy(), tile.block().size);
tile.entity.healBy(healPercent / 100f * tile.entity.maxHealth());
}

View File

@@ -120,7 +120,7 @@ public class Control implements ApplicationListener{
Effects.shake(5, 6, Core.camera.position.x, Core.camera.position.y);
//the restart dialog can show info for any number of scenarios
Call.onGameOver(event.winner);
if(state.rules.zone != -1){
if(state.rules.zone != null){
//remove zone save on game over
if(saves.getZoneSlot() != null){
saves.getZoneSlot().delete();

View File

@@ -289,7 +289,7 @@ public class NetServer implements ApplicationListener{
//auto-skip done requests
if(req.breaking && tile.block() == Blocks.air){
continue;
}else if(!req.breaking && tile.block() == req.block && (!req.block.rotate || tile.getRotation() == req.rotation)){
}else if(!req.breaking && tile.block() == req.block && (!req.block.rotate || tile.rotation() == req.rotation)){
continue;
}
player.getPlaceQueue().addLast(req);

View File

@@ -20,6 +20,7 @@ import io.anuke.mindustry.maps.*;
import io.anuke.mindustry.maps.generators.Generator;
import io.anuke.mindustry.type.*;
import io.anuke.mindustry.world.*;
import io.anuke.mindustry.world.blocks.BlockPart;
import static io.anuke.mindustry.Vars.*;
@@ -111,6 +112,10 @@ public class World implements ApplicationListener{
return tile(Math.round(x / tilesize), Math.round(y / tilesize));
}
public @Nullable Tile ltileWorld(float x, float y){
return ltile(Math.round(x / tilesize), Math.round(y / tilesize));
}
public int toTile(float coord){
return Math.round(coord / tilesize);
}
@@ -194,14 +199,14 @@ public class World implements ApplicationListener{
}
public Zone getZone(){
return content.getByID(ContentType.zone, state.rules.zone);
return state.rules.zone;
}
public void playZone(Zone zone){
ui.loadAnd(() -> {
logic.reset();
state.rules = zone.rules.get();
state.rules.zone = zone.id;
state.rules.zone = zone;
loadGenerator(zone.generator);
for(Tile core : state.teams.get(defaultTeam).cores){
for(ItemStack stack : zone.getStartingItems()){
@@ -295,16 +300,7 @@ public class World implements ApplicationListener{
}
public void removeBlock(Tile tile){
if(!tile.block().isMultiblock() && !tile.isLinked()){
tile.setBlock(Blocks.air);
}else{
Tile target = tile.target();
Array<Tile> removals = target.getLinkedTiles(tempTiles);
for(Tile toremove : removals){
//note that setting a new block automatically unlinks it
if(toremove != null) toremove.setBlock(Blocks.air);
}
}
tile.link().getLinkedTiles(other -> other.setBlock(Blocks.air));
}
public void setBlock(Tile tile, Block block, Team team){
@@ -324,8 +320,7 @@ public class World implements ApplicationListener{
if(!(worldx == tile.x && worldy == tile.y)){
Tile toplace = world.tile(worldx, worldy);
if(toplace != null){
toplace.setLinked((byte)(dx + offsetx), (byte)(dy + offsety));
toplace.setTeam(team);
toplace.setBlock(BlockPart.get(dx + offsetx, dy + offsety), team);
}
}
}
@@ -333,15 +328,6 @@ public class World implements ApplicationListener{
}
}
public int transform(int packed, int oldWidth, int oldHeight, int newWidth, int shiftX, int shiftY){
int x = packed % oldWidth;
int y = packed / oldWidth;
if(!Structs.inBounds(x, y, oldWidth, oldHeight)) return -1;
x += shiftX;
y += shiftY;
return y * newWidth + x;
}
/**
* Raycast, but with world coordinates.
*/
@@ -462,7 +448,7 @@ public class World implements ApplicationListener{
for(int y = 0; y < tiles[0].length; y++){
Tile tile = tiles[x][y];
if(tile.block().solid && !tile.block().synthetic()){
tiles[x][y].setRotation(dark[x][y]);
tiles[x][y].rotation(dark[x][y]);
}
}
}
@@ -509,8 +495,7 @@ public class World implements ApplicationListener{
if(!(worldx == x && worldy == y)){
Tile toplace = world.tile(worldx, worldy);
if(toplace != null){
toplace.setLinked((byte)(dx + offsetx), (byte)(dy + offsety));
toplace.setTeam(team);
toplace.setBlock(BlockPart.get(dx + offsetx, dy + offsety), team);
}
}
}

View File

@@ -46,7 +46,7 @@ public class DrawOperation{
editor.updateLinks(block, tile.x, tile.y);
}
}else if(type == OpType.rotation.ordinal()){
tile.setRotation(to);
tile.rotation(to);
}else if(type == OpType.team.ordinal()){
tile.setTeam(Team.all[to]);
}else if(type == OpType.ore.ordinal()){

View File

@@ -67,10 +67,10 @@ public class EditorTile extends Tile{
}
@Override
public void setRotation(byte rotation){
byte previous = getRotation();
public void rotation(byte rotation){
byte previous = rotation();
if(previous == rotation) return;
super.setRotation(rotation);
super.rotation(rotation);
op(TileOp.get(x, y, (byte)OpType.rotation.ordinal(), previous, rotation));
}

View File

@@ -116,7 +116,7 @@ public enum EditorTool{
}
if(draw.rotate){
write.setRotation((byte)editor.rotation);
write.rotation((byte)editor.rotation);
}
};

View File

@@ -246,7 +246,7 @@ public class MapEditor{
tile.setTeam(drawTeam);
}
if(drawBlock.rotate){
tile.setRotation((byte)rotation);
tile.rotation((byte)rotation);
}
}
}

View File

@@ -224,7 +224,7 @@ public class MapGenerateDialog extends FloatingDialog{
Tile tile = editor.tile(x, y);
input.begin(editor, x, y, tile.floor(), tile.block(), tile.overlay());
filter.apply(input);
writeTiles[x][y].set(input.floor, input.block, input.ore, tile.getTeam(), tile.getRotation());
writeTiles[x][y].set(input.floor, input.block, input.ore, tile.getTeam(), tile.rotation());
}
}
@@ -235,7 +235,7 @@ public class MapGenerateDialog extends FloatingDialog{
Tile tile = editor.tile(x, y);
DummyTile write = writeTiles[x][y];
tile.setRotation(write.rotation);
tile.rotation(write.rotation);
tile.setFloor((Floor)content.block(write.floor));
tile.setBlock(content.block(write.block));
tile.setTeam(Team.all[write.team]);
@@ -341,7 +341,7 @@ public class MapGenerateDialog extends FloatingDialog{
}
void set(Tile other){
set(other.floor(), other.block(), other.overlay(), other.getTeam(), other.getRotation());
set(other.floor(), other.block(), other.overlay(), other.getTeam(), other.rotation());
}
}

View File

@@ -116,7 +116,7 @@ public class MapRenderer implements Disposable{
if(wall.rotate){
mesh.draw(idxWall, region,
wx * tilesize + wall.offset(), wy * tilesize + wall.offset(),
region.getWidth() * Draw.scl, region.getHeight() * Draw.scl, tile.getRotation() * 90 - 90);
region.getWidth() * Draw.scl, region.getHeight() * Draw.scl, tile.rotation() * 90 - 90);
}else{
mesh.draw(idxWall, region,
wx * tilesize + wall.offset() + (tilesize - region.getWidth() * Draw.scl) / 2f,

View File

@@ -85,9 +85,8 @@ public class Damage{
public static void collideLine(Bullet hitter, Team team, Effect effect, float x, float y, float angle, float length){
tr.trns(angle, length);
world.raycastEachWorld(x, y, x + tr.x, y + tr.y, (cx, cy) -> {
Tile tile = world.tile(cx, cy);
if(tile != null) tile = tile.target();
if(tile != null && tile.entity != null && tile.target().getTeamID() != team.ordinal() && tile.entity.collide(hitter)){
Tile tile = world.ltile(cx, cy);
if(tile != null && tile.entity != null && tile.getTeamID() != team.ordinal() && tile.entity.collide(hitter)){
tile.entity.collision(hitter);
hitter.getBulletType().hit(hitter, tile.worldx(), tile.worldy());
}
@@ -216,12 +215,10 @@ public class Damage{
int scaledDamage = (int)(damage * (1f - (float)dst / radius));
bits.set(bitOffset + x, bitOffset + y);
Tile tile = world.tile(startx + x, starty + y);
Tile tile = world.ltile(startx + x, starty + y);
if(scaledDamage <= 0 || tile == null) continue;
tile = tile.target();
//apply damage to entity if needed
if(tile.entity != null && tile.getTeam() != team){
int health = (int)tile.entity.health;

View File

@@ -225,9 +225,8 @@ public class Bullet extends SolidEntity implements DamageTrait, ScaleTrait, Pool
if(type.hitTiles && collidesTiles() && !supressCollision && initialized){
world.raycastEach(world.toTile(lastPosition().x), world.toTile(lastPosition().y), world.toTile(x), world.toTile(y), (x, y) -> {
Tile tile = world.tile(x, y);
Tile tile = world.ltile(x, y);
if(tile == null) return false;
tile = tile.target();
if(tile.entity != null && tile.entity.collide(this) && type.collides(this, tile) && !tile.entity.isDead() && (type.collidesTeam || tile.getTeam() != team)){
if(tile.getTeam() != team){

View File

@@ -98,7 +98,7 @@ public class Fire extends TimedEntity implements SaveTrait, SyncTrait, Poolable{
return;
}
TileEntity entity = tile.target().entity;
TileEntity entity = tile.link().entity;
boolean damage = entity != null;
float flammability = baseFlammability + puddleFlammability;

View File

@@ -201,7 +201,7 @@ public class Puddle extends SolidEntity implements SaveTrait, Poolable, DrawTrai
}
});
if(liquid.temperature > 0.7f && (tile.target().entity != null) && Mathf.chance(0.3 * Time.delta())){
if(liquid.temperature > 0.7f && (tile.link().entity != null) && Mathf.chance(0.3 * Time.delta())){
Fire.create(tile);
}

View File

@@ -164,7 +164,7 @@ public interface BuilderTrait extends Entity, TeamTrait{
for(BuildRequest request : removal){
if(!((request.breaking && world.tile(request.x, request.y).block() == Blocks.air) ||
(!request.breaking && (world.tile(request.x, request.y).getRotation() == request.rotation || !request.block.rotate)
(!request.breaking && (world.tile(request.x, request.y).rotation() == request.rotation || !request.block.rotate)
&& world.tile(request.x, request.y).block() == request.block))){
getPlaceQueue().addLast(request);
}

View File

@@ -432,7 +432,7 @@ public class Player extends Unit implements BuilderTrait, ShooterTrait{
if(getCurrentRequest() == request && request.progress > 0.001f) continue;
if(request.breaking){
Block block = world.tile(request.x, request.y).target().block();
Block block = world.ltile(request.x, request.y).block();
//draw removal request
Lines.stroke(2f, Pal.removeBack);

View File

@@ -116,7 +116,7 @@ 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.getRotation())); //team + rotation
stream.writeByte(Pack.byteByte(tile.getTeamID(), tile.rotation())); //team + rotation
if(items != null) items.write(stream);
if(power != null) power.write(stream);
if(liquids != null) liquids.write(stream);
@@ -131,7 +131,7 @@ public class TileEntity extends BaseEntity implements TargetTrait, HealthTrait{
byte rotation = Pack.rightByte(tr);
tile.setTeam(Team.all[team]);
tile.setRotation(rotation);
tile.rotation(rotation);
if(items != null) items.read(stream);
if(power != null) power.read(stream);
@@ -180,14 +180,14 @@ public class TileEntity extends BaseEntity implements TargetTrait, HealthTrait{
Point2[] nearby = Edges.getEdges(block.size);
for(Point2 point : nearby){
Tile other = world.tile(tile.x + point.x, tile.y + point.y);
Tile other = world.ltile(tile.x + point.x, tile.y + point.y);
//remove this tile from all nearby tile's proximities
if(other != null){
other = other.target();
other.block().onProximityUpdate(other);
}
if(other != null && other.entity != null){
other.entity.proximity.removeValue(tile, true);
if(other.entity != null){
other.entity.proximity.removeValue(tile, true);
}
}
}
}
@@ -198,10 +198,9 @@ public class TileEntity extends BaseEntity implements TargetTrait, HealthTrait{
Point2[] nearby = Edges.getEdges(block.size);
for(Point2 point : nearby){
Tile other = world.tile(tile.x + point.x, tile.y + point.y);
Tile other = world.ltile(tile.x + point.x, tile.y + point.y);
if(other == null) continue;
other = other.target();
if(other.entity == null || !(other.interactable(tile.getTeam()))) continue;
other.block().onProximityUpdate(other);

View File

@@ -58,7 +58,7 @@ public class Drone extends FlyingUnit implements BuilderTrait{
if(isBreaking){
getPlaceQueue().addLast(new BuildRequest(entity.tile.x, entity.tile.y));
}else{
getPlaceQueue().addLast(new BuildRequest(entity.tile.x, entity.tile.y, entity.tile.getRotation(), entity.cblock));
getPlaceQueue().addLast(new BuildRequest(entity.tile.x, entity.tile.y, entity.tile.rotation(), entity.cblock));
}
}

View File

@@ -12,14 +12,14 @@ import io.anuke.mindustry.io.SaveIO;
import io.anuke.mindustry.io.SaveIO.SaveException;
import io.anuke.mindustry.io.SaveMeta;
import io.anuke.mindustry.maps.Map;
import io.anuke.mindustry.type.ContentType;
import io.anuke.mindustry.type.Zone;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import static io.anuke.mindustry.Vars.*;
import static io.anuke.mindustry.Vars.saveExtension;
import static io.anuke.mindustry.Vars.state;
public class Saves{
private int nextSlot;
@@ -224,7 +224,7 @@ public class Saves{
}
public Zone getZone(){
return meta == null || meta.rules == null ? null : content.getByID(ContentType.zone, meta.rules.zone);
return meta == null || meta.rules == null ? null : meta.rules.zone;
}
public int getBuild(){

View File

@@ -78,7 +78,7 @@ public class BlockRenderer implements Disposable{
for(int y = 0; y < world.height(); y++){
Tile tile = world.rawTile(x, y);
int edgeBlend = 2;
float rot = tile.getRotation();
float rot = tile.rotation();
boolean fillable = (tile.block().solid && tile.block().fillsTile && !tile.block().synthetic());
int edgeDst = Math.min(x, Math.min(y, Math.min(Math.abs(x - (world.width() - 1)), Math.abs(y - (world.height() - 1)))));
if(edgeDst <= edgeBlend){

View File

@@ -129,7 +129,7 @@ public class MinimapRenderer implements Disposable{
}
private int colorFor(Tile tile){
tile = tile.target();
tile = tile.link();
return MapIO.colorFor(tile.floor(), tile.block(), tile.overlay(), tile.getTeam());
}

View File

@@ -97,11 +97,10 @@ public class OverlayRenderer{
//draw selected block bars and info
if(input.block == null && !Core.scene.hasMouse()){
Vector2 vec = Core.input.mouseWorld(input.getMouseX(), input.getMouseY());
Tile tile = world.tileWorld(vec.x, vec.y);
Tile tile = world.ltileWorld(vec.x, vec.y);
if(tile != null && tile.block() != Blocks.air && tile.target().getTeam() == player.getTeam()){
Tile target = tile.target();
target.block().drawSelect(target);
if(tile != null && tile.block() != Blocks.air && tile.getTeam() == player.getTeam()){
tile.block().drawSelect(tile);
}
}
@@ -113,8 +112,7 @@ public class OverlayRenderer{
Lines.circle(v.x, v.y, 6 + Mathf.absin(Time.time(), 5f, 1f));
Draw.reset();
Tile tile = world.tileWorld(v.x, v.y);
if(tile != null) tile = tile.target();
Tile tile = world.ltileWorld(v.x, v.y);
if(tile != null && tile.interactable(player.getTeam()) && tile.block().acceptStack(player.item().item, player.item().amount, tile, player) > 0){
Draw.color(Pal.place);
Lines.square(tile.drawx(), tile.drawy(), tile.block().size * tilesize / 2f + 1 + Mathf.absin(Time.time(), 5f, 1f));

View File

@@ -96,9 +96,8 @@ public class DesktopInput extends InputHandler{
for(int x = dresult.x; x <= dresult.x2; x++){
for(int y = dresult.y; y <= dresult.y2; y++){
Tile tile = world.tile(x, y);
Tile tile = world.ltile(x, y);
if(tile == null || !validBreak(tile.x, tile.y)) continue;
tile = tile.target();
Draw.color(Pal.removeBack);
Lines.square(tile.drawx(), tile.drawy() - 1, tile.block().size * tilesize / 2f - 1);
@@ -175,7 +174,7 @@ public class DesktopInput extends InputHandler{
Tile cursor = tileAt(Core.input.mouseX(), Core.input.mouseY());
if(cursor != null){
cursor = cursor.target();
cursor = cursor.link();
cursorType = cursor.block().getCursor(cursor);
@@ -257,7 +256,7 @@ public class DesktopInput extends InputHandler{
}
if(selected != null){
tryDropItems(selected.target(), Core.input.mouseWorld().x, Core.input.mouseWorld().y);
tryDropItems(selected.link(), Core.input.mouseWorld().x, Core.input.mouseWorld().y);
}
mode = none;

View File

@@ -154,7 +154,7 @@ public abstract class InputHandler implements InputProcessor{
/** Handles tile tap events that are not platform specific. */
boolean tileTapped(Tile tile){
tile = tile.target();
tile = tile.link();
boolean consumed = false, showedInventory = false;
@@ -331,7 +331,7 @@ public abstract class InputHandler implements InputProcessor{
}
public void breakBlock(int x, int y){
Tile tile = world.tile(x, y).target();
Tile tile = world.ltile(x, y);
player.addBuildRequest(new BuildRequest(tile.x, tile.y));
}

View File

@@ -87,8 +87,7 @@ public class MobileInput extends InputHandler implements GestureListener{
player.setMineTile(null);
player.target = unit;
}else{
Tile tile = world.tileWorld(x, y);
if(tile != null) tile = tile.target();
Tile tile = world.ltileWorld(x, y);
if(tile != null && tile.synthetic() && state.teams.areEnemies(player.getTeam(), tile.getTeam())){
TileEntity entity = tile.entity;
@@ -408,9 +407,8 @@ public class MobileInput extends InputHandler implements GestureListener{
for(int x = dresult.x; x <= dresult.x2; x++){
for(int y = dresult.y; y <= dresult.y2; y++){
Tile other = world.tile(x, y);
Tile other = world.ltile(x, y);
if(other == null || !validBreak(other.x, other.y)) continue;
other = other.target();
Draw.color(Pal.removeBack);
Lines.square(other.drawx(), other.drawy() - 1, other.block().size * tilesize / 2f - 1);
@@ -506,12 +504,10 @@ public class MobileInput extends InputHandler implements GestureListener{
int wx = lineStartX + x * Mathf.sign(tileX - lineStartX);
int wy = lineStartY + y * Mathf.sign(tileY - lineStartY);
Tile tar = world.tile(wx, wy);
Tile tar = world.ltile(wx, wy);
if(tar == null) continue;
tar = tar.target();
if(!hasRequest(world.tile(tar.x, tar.y)) && validBreak(tar.x, tar.y)){
PlaceRequest request = new PlaceRequest(tar.x, tar.y);
request.scale = 1f;
@@ -527,7 +523,7 @@ public class MobileInput extends InputHandler implements GestureListener{
if(tile == null) return false;
tryDropItems(tile.target(), Core.input.mouseWorld(screenX, screenY).x, Core.input.mouseWorld(screenX, screenY).y);
tryDropItems(tile.link(), Core.input.mouseWorld(screenX, screenY).x, Core.input.mouseWorld(screenX, screenY).y);
}
return false;
}
@@ -577,11 +573,11 @@ public class MobileInput extends InputHandler implements GestureListener{
}else if(mode == placing && isPlacing() && validPlace(cursor.x, cursor.y, block, rotation) && !checkOverlapPlacement(cursor.x, cursor.y, block)){
//add to selection queue if it's a valid place position
selection.add(lastPlaced = new PlaceRequest(cursor.x, cursor.y, block, rotation));
}else if(mode == breaking && validBreak(cursor.target().x, cursor.target().y) && !hasRequest(cursor.target())){
}else if(mode == breaking && validBreak(cursor.link().x, cursor.link().y) && !hasRequest(cursor.link())){
//add to selection queue if it's a valid BREAK position
cursor = cursor.target();
cursor = cursor.link();
selection.add(new PlaceRequest(cursor.x, cursor.y));
}else if(!canTapPlayer(worldx, worldy) && !tileTapped(cursor.target())){
}else if(!canTapPlayer(worldx, worldy) && !tileTapped(cursor.link())){
tryBeginMine(cursor);
}

View File

@@ -1,26 +1,21 @@
package io.anuke.mindustry.io;
import io.anuke.arc.collection.IntIntMap;
import io.anuke.arc.collection.ObjectMap;
import io.anuke.arc.collection.ObjectMap.Entry;
import io.anuke.arc.files.FileHandle;
import io.anuke.arc.graphics.Color;
import io.anuke.arc.graphics.Pixmap;
import io.anuke.arc.graphics.Pixmap.Format;
import io.anuke.arc.math.Mathf;
import io.anuke.arc.util.*;
import io.anuke.mindustry.content.Blocks;
import io.anuke.mindustry.game.*;
import io.anuke.mindustry.maps.Map;
import io.anuke.mindustry.type.ContentType;
import io.anuke.mindustry.type.Item;
import io.anuke.mindustry.world.*;
import io.anuke.mindustry.world.LegacyColorMapper.LegacyBlock;
import io.anuke.mindustry.world.blocks.BlockPart;
import io.anuke.mindustry.world.blocks.Floor;
import java.io.*;
import java.util.Arrays;
import java.util.zip.DeflaterOutputStream;
import java.util.zip.InflaterInputStream;
@@ -30,24 +25,7 @@ import static io.anuke.mindustry.Vars.content;
/** Reads and writes map files. */
public class MapIO{
public static final int version = 1;
private static final int[] pngHeader = {0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A};
private static ObjectMap<String, Block> missingBlocks;
private static void initBlocks(){
if(missingBlocks != null) return;
//only for legacy maps
missingBlocks = ObjectMap.of(
"stained-stone", Blocks.shale,
"stained-stone-red", Blocks.shale,
"stained-stone-yellow", Blocks.shale,
"stained-rocks", Blocks.shaleRocks,
"stained-boulder", Blocks.shaleBoulder,
"stained-rocks-red", Blocks.shaleRocks,
"stained-rocks-yellow", Blocks.shaleRocks
);
}
public static boolean isImage(FileHandle file){
try(InputStream stream = file.read(32)){
@@ -169,7 +147,7 @@ public class MapIO{
if(tile.block() instanceof BlockPart){
stream.writeByte(tile.getLinkByte());
}else if(tile.entity != null){
stream.writeByte(Pack.byteByte(tile.getTeamID(), tile.getRotation())); //team + rotation
stream.writeByte(Pack.byteByte(tile.getTeamID(), tile.rotation())); //team + rotation
stream.writeShort(/*(short)tile.entity.health*/tile.block().health); //health
if(tile.block() == Blocks.liquidSource || tile.block() == Blocks.unloader || tile.block() == Blocks.sorter){
stream.writeByte(-1); //write an meaningless byte here, just a fallback thing
@@ -294,9 +272,7 @@ public class MapIO{
Tile tile = tiles.get(x, y);
tile.setBlock(block);
if(block == Blocks.part){
tile.setLinkByte(stream.readByte());
}else if(tile.entity != null){
if(tile.entity != null){
byte tr = stream.readByte();
short health = stream.readShort();
@@ -305,7 +281,7 @@ public class MapIO{
tile.setTeam(Team.all[team]);
tile.entity.health = /*health*/tile.block().health;
tile.setRotation(rotation);
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
@@ -353,9 +329,8 @@ public class MapIO{
//multiblock parts
if(Structs.inBounds(worldx, worldy, pixmap.getWidth(), pixmap.getHeight())){
Tile write = tiles[worldx][worldy];
write.setBlock(Blocks.part);
write.setBlock(BlockPart.get(dx - 1, dy - 1));
write.setTeam(Team.blue);
write.setLinkByte(Pack.byteByte((byte)(dx - 1 + 8), (byte)(dy - 1 + 8)));
}
}
}
@@ -368,112 +343,6 @@ public class MapIO{
}
}
/** Reads a pixmap in the old 4.0 .mmap format. */
private static void readLegacyMmapTiles(FileHandle file, Tile[][] tiles) throws IOException{
readLegacyMmapTiles(file, (x, y) -> tiles[x][y]);
}
/** Reads a mmap in the old 4.0 .mmap format. */
private static void readLegacyMmapTiles(FileHandle file, TileProvider tiles) throws IOException{
try(DataInputStream stream = new DataInputStream(file.read(bufferSize))){
stream.readInt(); //version
byte tagAmount = stream.readByte();
for(int i = 0; i < tagAmount; i++){
stream.readUTF(); //key
stream.readUTF(); //val
}
initBlocks();
//block id -> real id map
IntIntMap map = new IntIntMap();
IntIntMap oreMap = new IntIntMap();
short blocks = stream.readShort();
for(int i = 0; i < blocks; i++){
short id = stream.readShort();
String name = stream.readUTF();
Block block = content.getByName(ContentType.block, name);
if(block == null){
//substitute for replacement in missingBlocks if possible
if(missingBlocks.containsKey(name)){
block = missingBlocks.get(name);
}else if(name.startsWith("ore-")){ //an ore floor combination
String[] split = name.split("-");
String itemName = split[1], floorName = Strings.join("-", Arrays.copyOfRange(split, 2, split.length));
Item item = content.getByName(ContentType.item, itemName);
Block oreBlock = item == null ? null : content.getByName(ContentType.block, "ore-" + item.name);
Block floor = missingBlocks.get(floorName, content.getByName(ContentType.block, floorName));
if(oreBlock != null && floor != null){
oreMap.put(id, oreBlock.id);
block = floor;
}else{
block = Blocks.air;
}
}else{
block = Blocks.air;
}
}
map.put(id, block.id);
}
short width = stream.readShort(), height = stream.readShort();
for(int y = 0; y < height; y++){
for(int x = 0; x < width; x++){
Tile tile = tiles.get(x, y);
byte floorb = stream.readByte();
byte blockb = stream.readByte();
byte link = stream.readByte();
byte rotTeamb = stream.readByte();
stream.readByte();//unused stuff
tile.setFloor((Floor)content.block(map.get(floorb, 0)));
tile.setBlock(content.block(map.get(blockb, 0)));
tile.setRotation(Pack.leftByte(rotTeamb));
if(tile.block().synthetic()){
tile.setTeam(Team.all[Mathf.clamp(Pack.rightByte(rotTeamb), 0, Team.all.length)]);
}
if(tile.block() == Blocks.part){
tile.setLinkByte(link);
}
if(oreMap.containsKey(floorb)){
tile.setOverlay(content.block(oreMap.get(floorb, 0)));
}
}
}
}
}
private static Map readLegacyMap(FileHandle file, boolean custom) throws IOException{
try(DataInputStream stream = new DataInputStream(file.read(bufferSize))){
ObjectMap<String, String> tags = new ObjectMap<>();
int version = stream.readInt();
if(version != 0) throw new IOException("Attempted to read non-legacy map in legacy method!");
byte tagAmount = stream.readByte();
for(int i = 0; i < tagAmount; i++){
String name = stream.readUTF();
String value = stream.readUTF();
tags.put(name, value);
}
short blocks = stream.readShort();
for(int i = 0; i < blocks; i++){
stream.readShort();
stream.readUTF();
}
short width = stream.readShort(), height = stream.readShort();
//note that build 64 is the default build of all maps <65; while this can be inaccurate it's better than nothing
return new Map(file, width, height, tags, custom, 0, 64);
}
}
//endregion
interface TileProvider{

View File

@@ -2,12 +2,13 @@ package io.anuke.mindustry.io;
import io.anuke.arc.collection.*;
import io.anuke.arc.collection.ObjectMap.Entry;
import io.anuke.arc.util.io.CounterInputStream;
import io.anuke.arc.util.io.ReusableByteOutStream;
import io.anuke.mindustry.entities.Entities;
import io.anuke.mindustry.entities.EntityGroup;
import io.anuke.mindustry.entities.traits.*;
import io.anuke.mindustry.game.*;
import io.anuke.mindustry.gen.Serialization;
import io.anuke.mindustry.game.Content;
import io.anuke.mindustry.game.MappableContent;
import io.anuke.mindustry.type.ContentType;
import io.anuke.mindustry.world.Block;
import io.anuke.mindustry.world.Tile;
@@ -19,25 +20,25 @@ import static io.anuke.mindustry.Vars.world;
/**
* Format:
*
* Everything is compressed. Use a DeflaterStream to begin reading.
*
* 1. version of format / int
* 2. meta tags
* - length / short
* - continues with (string, string) pairs indicating key, value
* (begin deflating)
* 2. regions
*/
public abstract class SaveFileVersion{
public final int version;
private final ReusableByteOutStream byteOutput = new ReusableByteOutStream();
private final DataOutputStream dataBytes = new DataOutputStream(byteOutput);
private final ObjectMap<String, String> fallback = ObjectMap.of(
"alpha-dart-mech-pad", "dart-mech-pad"
);
private final Region[] regions;
private final ObjectMap<String, String> fallback = ObjectMap.of("alpha-dart-mech-pad", "dart-mech-pad");
public SaveFileVersion(int version){
public SaveFileVersion(int version, Region... regions){
this.version = version;
this.regions = regions;
}
public void writeChunk(DataOutput output, IORunner<DataOutput> runner) throws IOException{
writeChunk(output, false, runner);
}
/** Write a chunk of input to the stream. An integer of some length is written first, followed by the data. */
@@ -59,6 +60,10 @@ public abstract class SaveFileVersion{
output.write(byteOutput.getBytes(), 0, length);
}
public int readChunk(DataInput input, IORunner<DataInput> runner) throws IOException{
return readChunk(input, false, runner);
}
/** Reads a chunk of some length. Use the runner for reading to catch more descriptive errors. */
public int readChunk(DataInput input, boolean isByte, IORunner<DataInput> runner) throws IOException{
int length = isByte ? input.readUnsignedByte() : input.readInt();
@@ -76,18 +81,7 @@ public abstract class SaveFileVersion{
}
}
public SaveMeta getData(DataInputStream stream) throws IOException{
long time = stream.readLong();
long playtime = stream.readLong();
int build = stream.readInt();
Rules rules = Serialization.readRulesStreamJson(stream);
String map = stream.readUTF();
int wave = stream.readInt();
return new SaveMeta(version, time, playtime, build, map, wave, rules);
}
public void writeMeta(DataOutputStream stream, ObjectMap<String, String> map) throws IOException{
public void writeMeta(DataOutput stream, ObjectMap<String, String> map) throws IOException{
stream.writeShort(map.size);
for(Entry<String, String> entry : map.entries()){
stream.writeUTF(entry.key);
@@ -95,7 +89,7 @@ public abstract class SaveFileVersion{
}
}
public StringMap readMeta(DataInputStream stream) throws IOException{
public StringMap readMeta(DataInput stream) throws IOException{
StringMap map = new StringMap();
short size = stream.readShort();
for(int i = 0; i < size; i++){
@@ -104,7 +98,7 @@ public abstract class SaveFileVersion{
return map;
}
public void writeMap(DataOutputStream stream) throws IOException{
public void writeMap(DataOutput stream) throws IOException{
//write world size
stream.writeShort(world.width());
stream.writeShort(world.height());
@@ -185,7 +179,7 @@ public abstract class SaveFileVersion{
//read blocks
for(int i = 0; i < width * height; i++){
int x = i % width, y = i / width;
Block block = content.block(stream.readByte());
Block block = content.block(stream.readShort());
Tile tile = tiles[x][y];
tile.setBlock(block);
@@ -208,6 +202,7 @@ public abstract class SaveFileVersion{
}
public void writeEntities(DataOutputStream stream) throws IOException{
//write entity chunk
int groups = 0;
for(EntityGroup<?> group : Entities.getAllGroups()){
@@ -222,8 +217,11 @@ public abstract class SaveFileVersion{
if(!group.isEmpty() && group.all().get(0) instanceof SaveTrait){
stream.writeInt(group.size());
for(Entity entity : group.all()){
stream.writeByte(((SaveTrait)entity).getTypeID());
((SaveTrait)entity).writeSave(stream);
//each entity is a separate chunk.
writeChunk(stream, true, out -> {
stream.writeByte(((SaveTrait)entity).getTypeID());
((SaveTrait)entity).writeSave(out);
});
}
}
}
@@ -284,11 +282,45 @@ public abstract class SaveFileVersion{
}
}
public abstract void read(DataInputStream stream) throws IOException;
public final void read(DataInputStream stream, CounterInputStream counter) throws IOException{
for(Region region : regions){
counter.resetCount();
try{
int length = readChunk(stream, region.reader);
if(length != counter.count() + 4){
throw new IOException("Error reading region \"" + region.name + "\": read length mismatch. Expected: " + length + "; Actual: " + (counter.count() + 4));
}
}catch(Throwable e){
throw new IOException("Error reading region \"" + region.name + "\".", e);
}
}
}
public abstract void write(DataOutputStream stream) throws IOException;
public final void write(DataOutputStream stream) throws IOException{
for(Region region : regions){
try{
writeChunk(stream, region.writer);
}catch(Throwable e){
throw new IOException("Error writing region \"" + region.name + "\".", e);
}
}
}
public interface IORunner<T>{
/** A region of a save file that holds a specific category of information.
* Uses: simplify code reuse, provide better error messages, skip unnecessary data.*/
protected final class Region{
final IORunner<DataOutput> writer;
final IORunner<DataInput> reader;
final String name;
public Region(IORunner<DataOutput> writer, IORunner<DataInput> reader, String name){
this.writer = writer;
this.reader = reader;
this.name = name;
}
}
protected interface IORunner<T>{
void accept(T stream) throws IOException;
}
}

View File

@@ -2,6 +2,7 @@ package io.anuke.mindustry.io;
import io.anuke.arc.collection.*;
import io.anuke.arc.files.FileHandle;
import io.anuke.arc.util.io.CounterInputStream;
import io.anuke.mindustry.Vars;
import io.anuke.mindustry.io.versions.Save1;
@@ -12,6 +13,8 @@ import java.util.zip.InflaterInputStream;
import static io.anuke.mindustry.Vars.*;
public class SaveIO{
/** Format header. This is the string 'MSAV' in ASCII. */
public static final byte[] header = {77, 83, 65, 86};
public static final IntMap<SaveFileVersion> versions = new IntMap<>();
public static final Array<SaveFileVersion> versionArray = Array.with(new Save1());
@@ -130,15 +133,16 @@ public class SaveIO{
}
public static void load(InputStream is) throws SaveException{
try(DataInputStream stream = new DataInputStream(is)){
try(CounterInputStream counter = new CounterInputStream(is); DataInputStream stream = new DataInputStream(counter)){
logic.reset();
int version = stream.readInt();
SaveFileVersion ver = versions.get(version);
ver.read(stream);
ver.read(stream, counter);
}catch(Exception e){
content.setTemporaryMapper(null);
throw new SaveException(e);
}finally{
content.setTemporaryMapper(null);
}
}

View File

@@ -108,12 +108,12 @@ public class TypeIO{
@WriteClass(Block.class)
public static void writeBlock(ByteBuffer buffer, Block block){
buffer.put(block.id);
buffer.putShort(block.id);
}
@ReadClass(Block.class)
public static Block readBlock(ByteBuffer buffer){
return content.block(buffer.get());
return content.block(buffer.getShort());
}
@WriteClass(BuildRequest[].class)
@@ -123,7 +123,7 @@ public class TypeIO{
buffer.put(request.breaking ? (byte)1 : 0);
buffer.putInt(Pos.get(request.x, request.y));
if(!request.breaking){
buffer.put(request.block.id);
buffer.putShort(request.block.id);
buffer.put((byte)request.rotation);
}
}
@@ -141,7 +141,7 @@ public class TypeIO{
if(type == 1){ //remove
currentRequest = new BuildRequest(Pos.x(position), Pos.y(position));
}else{ //place
byte block = buffer.get();
short block = buffer.getShort();
byte rotation = buffer.get();
currentRequest = new BuildRequest(Pos.x(position), Pos.y(position), rotation, content.block(block));
}
@@ -204,7 +204,7 @@ public class TypeIO{
@WriteClass(Mech.class)
public static void writeMech(ByteBuffer buffer, Mech mech){
buffer.put(mech.id);
buffer.put((byte)mech.id);
}
@ReadClass(Mech.class)
@@ -214,33 +214,33 @@ public class TypeIO{
@WriteClass(Liquid.class)
public static void writeLiquid(ByteBuffer buffer, Liquid liquid){
buffer.put(liquid == null ? -1 : liquid.id);
buffer.putShort(liquid == null ? -1 : liquid.id);
}
@ReadClass(Liquid.class)
public static Liquid readLiquid(ByteBuffer buffer){
byte id = buffer.get();
return id == -1 ? null : content.liquid(buffer.get());
short id = buffer.getShort();
return id == -1 ? null : content.liquid(buffer.getShort());
}
@WriteClass(BulletType.class)
public static void writeBulletType(ByteBuffer buffer, BulletType type){
buffer.put(type.id);
buffer.putShort(type.id);
}
@ReadClass(BulletType.class)
public static BulletType readBulletType(ByteBuffer buffer){
return content.getByID(ContentType.bullet, buffer.get());
return content.getByID(ContentType.bullet, buffer.getShort());
}
@WriteClass(Item.class)
public static void writeItem(ByteBuffer buffer, Item item){
buffer.put(item == null ? -1 : item.id);
buffer.putShort(item == null ? -1 : item.id);
}
@ReadClass(Item.class)
public static Item readItem(ByteBuffer buffer){
byte id = buffer.get();
short id = buffer.getShort();
return id == -1 ? null : content.item(id);
}

View File

@@ -200,7 +200,7 @@ public abstract class BasicGenerator extends RandomGenerator{
Tile child = tiles[newx][newy];
if(!closed.get(child.x, child.y)){
closed.set(child.x, child.y);
child.setRotation(child.relativeTo(next.x, next.y));
child.rotation(child.relativeTo(next.x, next.y));
costs.put(child.pos(), th.cost(child) + baseCost);
queue.add(child);
}
@@ -215,7 +215,7 @@ public abstract class BasicGenerator extends RandomGenerator{
Tile current = end;
while(current != start){
out.add(current);
Point2 p = Geometry.d4(current.getRotation());
Point2 p = Geometry.d4(current.rotation());
current = tiles[current.x + p.x][current.y + p.y];
}

View File

@@ -71,7 +71,7 @@ public class Loadout extends Content{
int ry = Pos.y(entry.key);
Tile tile = world.tile(x + rx, y + ry);
world.setBlock(tile, entry.value.block, defaultTeam);
tile.setRotation((byte)entry.value.rotation);
tile.rotation((byte)entry.value.rotation);
if(entry.value.ore != null){
for(Tile t : tile.getLinkedTiles(outArray)){
t.setOverlay(entry.value.ore);

View File

@@ -59,11 +59,11 @@ public class BlockInventoryFragment extends Fragment{
}
public void showFor(Tile t){
if(this.tile == t.target()){
if(this.tile == t){
hide();
return;
}
this.tile = t.target();
this.tile = t;
if(tile == null || tile.entity == null || !tile.block().isAccessible() || tile.entity.items.total() == 0)
return;
rebuild(true);

View File

@@ -78,7 +78,7 @@ public class PlacementFragment extends Fragment{
Tile tile = world.tileWorld(Core.input.mouseWorld().x, Core.input.mouseWorld().y);
if(tile != null){
tile = tile.target();
tile = tile.link();
Block tryRecipe = tile.block();
if(tryRecipe.isVisible() && unlocked(tryRecipe)){
input.block = tryRecipe;
@@ -313,7 +313,7 @@ public class PlacementFragment extends Fragment{
if(!Core.scene.hasMouse() && topTable.hit(v.x, v.y, false) == null){
Tile tile = world.tileWorld(Core.input.mouseWorld().x, Core.input.mouseWorld().y);
if(tile != null){
hoverTile = tile.target();
hoverTile = tile.link();
}else{
hoverTile = null;
}

View File

@@ -240,7 +240,7 @@ public class Block extends BlockStorage{
}
public void draw(Tile tile){
Draw.rect(region, tile.drawx(), tile.drawy(), rotate ? tile.getRotation() * 90 : 0);
Draw.rect(region, tile.drawx(), tile.drawy(), rotate ? tile.rotation() * 90 : 0);
}
public void drawTeam(Tile tile){

View File

@@ -105,7 +105,7 @@ public abstract class BlockStorage extends UnlockableContent{
public void tryDumpLiquid(Tile tile, Liquid liquid){
Array<Tile> proximity = tile.entity.proximity();
int dump = tile.getDump();
int dump = tile.rotation();
for(int i = 0; i < proximity.size; i++){
incrementDump(tile, proximity.size);
@@ -138,7 +138,7 @@ public abstract class BlockStorage extends UnlockableContent{
public float tryMoveLiquid(Tile tile, Tile next, boolean leak, Liquid liquid){
if(next == null) return 0;
next = next.target();
next = next.link();
if(next.getTeam() == tile.getTeam() && next.block().hasLiquids && tile.entity.liquids.get(liquid) > 0f){
@@ -182,7 +182,7 @@ public abstract class BlockStorage extends UnlockableContent{
*/
public void offloadNear(Tile tile, Item item){
Array<Tile> proximity = tile.entity.proximity();
int dump = tile.getDump();
int dump = tile.rotation();
for(int i = 0; i < proximity.size; i++){
incrementDump(tile, proximity.size);
@@ -212,7 +212,7 @@ public abstract class BlockStorage extends UnlockableContent{
return false;
Array<Tile> proximity = entity.proximity();
int dump = tile.getDump();
int dump = tile.rotation();
if(proximity.size == 0) return false;
@@ -249,7 +249,7 @@ public abstract class BlockStorage extends UnlockableContent{
}
protected void incrementDump(Tile tile, int prox){
tile.setDump((byte)((tile.getDump() + 1) % prox));
tile.rotation((byte)((tile.rotation() + 1) % prox));
}
/** Used for dumping items. */
@@ -259,8 +259,8 @@ public abstract class BlockStorage extends UnlockableContent{
/** Try offloading an item to a nearby container in its facing direction. Returns true if success. */
public boolean offloadDir(Tile tile, Item item){
Tile other = tile.getNearby(tile.getRotation());
if(other != null && other.target().getTeamID() == tile.getTeamID() && other.block().acceptItem(item, other, tile)){
Tile other = tile.getNearby(tile.rotation());
if(other != null && other.getTeam() == tile.getTeam() && other.block().acceptItem(item, other, tile)){
other.block().handleItem(item, other, tile);
return true;
}

View File

@@ -10,7 +10,7 @@ import io.anuke.mindustry.content.Blocks;
import io.anuke.mindustry.entities.Units;
import io.anuke.mindustry.game.EventType.BlockBuildBeginEvent;
import io.anuke.mindustry.game.Team;
import io.anuke.mindustry.type.ContentType;
import io.anuke.mindustry.world.blocks.BuildBlock;
import io.anuke.mindustry.world.blocks.BuildBlock.BuildEntity;
import static io.anuke.mindustry.Vars.*;
@@ -25,7 +25,7 @@ public class Build{
return;
}
Tile tile = world.tile(x, y);
Tile tile = world.ltile(x, y);
float prevPercent = 1f;
//just in case
@@ -35,38 +35,15 @@ public class Build{
prevPercent = tile.entity.healthf();
}
tile = tile.target();
int rotation = tile.rotation();
Block previous = tile.block();
Block sub = BuildBlock.get(previous.size);
Block sub = content.getByName(ContentType.block, "build" + previous.size);
tile.setBlock(sub);
world.setBlock(tile, sub, team, rotation);
tile.<BuildEntity>entity().setDeconstruct(previous);
tile.setTeam(team);
tile.entity.health = tile.entity.maxHealth() * prevPercent;
if(previous.isMultiblock()){
int offsetx = -(previous.size - 1) / 2;
int offsety = -(previous.size - 1) / 2;
for(int dx = 0; dx < previous.size; dx++){
for(int dy = 0; dy < previous.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.setLinked((byte)(dx + offsetx), (byte)(dy + offsety));
toplace.setTeam(team);
}
}
}
}
}
Tile ftile = tile;
Core.app.post(() -> Events.fire(new BlockBuildBeginEvent(ftile, team, true)));
Core.app.post(() -> Events.fire(new BlockBuildBeginEvent(tile, team, true)));
}
/** Places a BuildBlock at this location. */
@@ -82,31 +59,10 @@ public class Build{
if(tile == null) return;
Block previous = tile.block();
Block sub = BuildBlock.get(result.size);
Block sub = content.getByName(ContentType.block, "build" + result.size);
tile.setBlock(sub, rotation);
world.setBlock(tile, sub, team, rotation);
tile.<BuildEntity>entity().setConstruct(previous, result);
tile.setTeam(team);
if(result.isMultiblock()){
int offsetx = -(result.size - 1) / 2;
int offsety = -(result.size - 1) / 2;
for(int dx = 0; dx < result.size; dx++){
for(int dy = 0; dy < result.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.setLinked((byte)(dx + offsetx), (byte)(dy + offsety));
toplace.setTeam(team);
}
}
}
}
}
Core.app.post(() -> Events.fire(new BlockBuildBeginEvent(tile, team, false)));
}
@@ -166,7 +122,7 @@ public class Build{
&& (!tile.floor().isDeep() || type.floating)
&& tile.floor().placeableOn
&& ((type.canReplace(tile.block())
&& !(type == tile.block() && rotation == tile.getRotation() && type.rotate)) || tile.block().alwaysReplace || tile.block() == Blocks.air)
&& !(type == tile.block() && rotation == tile.rotation() && type.rotate)) || tile.block().alwaysReplace || tile.block() == Blocks.air)
&& tile.block().isMultiblock() == type.isMultiblock() && type.canPlaceOn(tile);
}
}
@@ -195,9 +151,7 @@ public class Build{
/** Returns whether the tile at this position is breakable by this team */
public static boolean validBreak(Team team, int x, int y){
Tile tile = world.tile(x, y);
if(tile != null) tile = tile.target();
Tile tile = world.ltile(x, y);
return tile != null && tile.block().canBreak(tile) && tile.breakable() && tile.interactable(team);
}
}

View File

@@ -1,6 +1,7 @@
package io.anuke.mindustry.world;
import io.anuke.arc.collection.Array;
import io.anuke.arc.function.Consumer;
import io.anuke.arc.math.Mathf;
import io.anuke.arc.math.geom.*;
import io.anuke.mindustry.content.Blocks;
@@ -120,7 +121,7 @@ public class Tile implements Position, TargetTrait{
@Override
public Team getTeam(){
return Team.all[target().team];
return Team.all[link().team];
}
public void setTeam(Team team){
@@ -169,20 +170,12 @@ public class Tile implements Position, TargetTrait{
this.overlay = 0;
}
public byte getRotation(){
public byte rotation(){
return rotation;
}
public void setRotation(byte rotation){
this.rotation = rotation;
}
public byte getDump(){
return rotation;
}
public void setDump(byte dump){
this.rotation = dump;
public void rotation(int rotation){
this.rotation = (byte)rotation;
}
public short overlayID(){
@@ -210,31 +203,24 @@ public class Tile implements Position, TargetTrait{
}
public boolean passable(){
Block block = block();
Block floor = floor();
return isLinked() || !((floor.solid && (block == Blocks.air || block.solidifes)) || (block.solid && (!block.destructible && !block.update)));
}
/** Whether this block was placed by a player/unit. */
public boolean synthetic(){
Block block = block();
return block.update || block.destructible;
}
public boolean solid(){
Block block = block();
Block floor = floor();
return block.solid || (floor.solid && (block == Blocks.air || block.solidifes)) || block.isSolidFor(this)
|| (isLinked() && getLinked().block().isSolidFor(getLinked()));
return block.solid || block.isSolidFor(this) || (isLinked() && link().solid());
}
public boolean breakable(){
Block block = block();
if(!isLinked()){
return (block.destructible || block.breakable || block.update);
}else{
return getLinked() != this && getLinked().getLinked() == null && getLinked().breakable();
}
return !isLinked() ? (block.destructible || block.breakable || block.update) : link().breakable();
}
public Tile link(){
return block.linked(this);
}
public boolean isEnemyCheat(){
@@ -249,21 +235,28 @@ public class Tile implements Position, TargetTrait{
* Returns the list of all tiles linked to this multiblock, or an empty array if it's not a multiblock.
* This array contains all linked tiles, including this tile itself.
*/
public Array<Tile> getLinkedTiles(Array<Tile> tmpArray){
Block block = block();
tmpArray.clear();
public void getLinkedTiles(Consumer<Tile> cons){
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++){
Tile other = world.tile(x + dx + offsetx, y + dy + offsety);
if(other != null) tmpArray.add(other);
if(other != null) cons.accept(other);
}
}
}else{
tmpArray.add(this);
cons.accept(this);
}
}
/**
* Returns the list of all tiles linked to this multiblock, or an empty array if it's not a multiblock.
* This array contains all linked tiles, including this tile itself.
*/
public Array<Tile> getLinkedTiles(Array<Tile> tmpArray){
tmpArray.clear();
getLinkedTiles(tmpArray::add);
return tmpArray;
}
@@ -355,8 +348,8 @@ public class Tile implements Position, TargetTrait{
//+26
if(target().synthetic()){
cost += Mathf.clamp(target().block().health / 10f, 0, 20);
if(link().synthetic()){
cost += Mathf.clamp(link().block.health / 10f, 0, 20);
}
//+46
@@ -410,9 +403,8 @@ public class Tile implements Position, TargetTrait{
}else if(!(block instanceof BlockPart) && !world.isGenerating()){
//since the entity won't update proximity for us, update proximity for all nearby tiles manually
for(Point2 p : Geometry.d4){
Tile tile = world.tile(x + p.x, y + p.y);
Tile tile = world.ltile(x + p.x, y + p.y);
if(tile != null){
tile = tile.target();
tile.block().onProximityUpdate(tile);
}
}
@@ -455,9 +447,6 @@ public class Tile implements Position, TargetTrait{
@Override
public String toString(){
Block block = block();
Block floor = floor();
return floor.name + ":" + block.name + ":" + content.block(overlay) + "[" + x + "," + y + "] " + "entity=" + (entity == null ? "null" : (entity.getClass())) +
(isLinked() ? " link=[" + linkX(rotation) + ", " + linkY(rotation) + "]" : "");
}

View File

@@ -24,6 +24,7 @@ public class BlockPart extends Block{
}
public static BlockPart get(int dx, int dy){
if(dx == -maxSize/2 && dy == -maxSize/2) throw new IllegalArgumentException("Why are you getting a [0,0] blockpart? Stop it.");
return parts[dx + maxSize/2][dy + maxSize/2];
}

View File

@@ -28,15 +28,25 @@ import java.io.*;
import static io.anuke.mindustry.Vars.*;
public class BuildBlock extends Block{
public static final int maxSize = 9;
private static final BuildBlock[] buildBlocks = new BuildBlock[maxSize];
public BuildBlock(String name){
super(name);
public BuildBlock(int size){
super("build" + size);
this.size = size;
update = true;
size = Integer.parseInt(name.charAt(name.length() - 1) + "");
health = 20;
layer = Layer.placement;
consumesTap = true;
solidifes = true;
buildBlocks[size - 1] = this;
}
/** Returns a BuildBlock by size. */
public static BuildBlock get(int size){
if(size > maxSize) throw new IllegalArgumentException("No. Don't place BuildBlocks of size greater than " + maxSize);
return buildBlocks[size - 1];
}
@Remote(called = Loc.server)
@@ -102,7 +112,7 @@ public class BuildBlock extends Block{
//if the target is constructible, begin constructing
if(entity.cblock != null){
player.clearBuilding();
player.addBuildRequest(new BuildRequest(tile.x, tile.y, tile.getRotation(), entity.cblock));
player.addBuildRequest(new BuildRequest(tile.x, tile.y, tile.rotation(), entity.cblock));
}
}
@@ -127,7 +137,7 @@ public class BuildBlock extends Block{
if(entity.previous == null) return;
if(Core.atlas.isFound(entity.previous.icon(Icon.full))){
Draw.rect(entity.previous.icon(Icon.full), tile.drawx(), tile.drawy(), entity.previous.rotate ? tile.getRotation() * 90 : 0);
Draw.rect(entity.previous.icon(Icon.full), tile.drawx(), tile.drawy(), entity.previous.rotate ? tile.rotation() * 90 : 0);
}
}
@@ -146,7 +156,7 @@ public class BuildBlock extends Block{
Shaders.blockbuild.region = region;
Shaders.blockbuild.progress = entity.progress;
Draw.rect(region, tile.drawx(), tile.drawy(), target.rotate ? tile.getRotation() * 90 : 0);
Draw.rect(region, tile.drawx(), tile.drawy(), target.rotate ? tile.rotation() * 90 : 0);
Draw.flush();
}
}
@@ -198,7 +208,7 @@ public class BuildBlock extends Block{
}
if(progress >= 1f || state.rules.infiniteResources){
Call.onConstructFinish(tile, cblock, builderID, tile.getRotation(), builder.getTeam());
Call.onConstructFinish(tile, cblock, builderID, tile.rotation(), builder.getTeam());
}
}

View File

@@ -38,7 +38,7 @@ public class LiquidBlock extends Block{
public void draw(Tile tile){
LiquidModule mod = tile.entity.liquids;
int rotation = rotate ? tile.getRotation() * 90 : 0;
int rotation = rotate ? tile.rotation() * 90 : 0;
Draw.rect(bottomRegion, tile.drawx(), tile.drawy(), rotation);

View File

@@ -85,10 +85,9 @@ public class MendProjector extends Block{
for(int y = -tileRange + tile.y; y <= tileRange + tile.y; y++){
if(Mathf.dst(x, y, tile.x, tile.y) > tileRange) continue;
Tile other = world.tile(x, y);
Tile other = world.ltile(x, y);
if(other == null) continue;
other = other.target();
if(other.getTeamID() == tile.getTeamID() && !healed.contains(other.pos()) && other.entity != null && other.entity.health < other.entity.maxHealth()){
other.entity.healBy(other.entity.maxHealth() * (healPercent + entity.phaseHeat * phaseBoost) / 100f * entity.power.satisfaction);

View File

@@ -92,10 +92,9 @@ public class OverdriveProjector extends Block{
for(int y = -tileRange + tile.y; y <= tileRange + tile.y; y++){
if(Mathf.dst(x, y, tile.x, tile.y) > tileRange) continue;
Tile other = world.tile(x, y);
Tile other = world.ltile(x, y);
if(other == null) continue;
other = other.target();
if(other.getTeamID() == tile.getTeamID() && !healed.contains(other.pos()) && other.entity != null){
other.entity.timeScaleDuration = Math.max(other.entity.timeScaleDuration, reload + 1f);

View File

@@ -60,17 +60,17 @@ public class Conduit extends LiquidBlock{
}
private boolean blends(Tile tile, int direction){
Tile other = tile.getNearby(Mathf.mod(tile.getRotation() - direction, 4));
if(other != null) other = other.target();
Tile other = tile.getNearby(Mathf.mod(tile.rotation() - direction, 4));
if(other != null) other = other.link();
return other != null && other.block().hasLiquids && other.block().outputsLiquid && ((tile.getNearby(tile.getRotation()) == other) || (!other.block().rotate || other.getNearby(other.getRotation()) == tile));
return other != null && other.block().hasLiquids && other.block().outputsLiquid && ((tile.getNearby(tile.rotation()) == other) || (!other.block().rotate || other.getNearby(other.rotation()) == tile));
}
@Override
public void draw(Tile tile){
ConduitEntity entity = tile.entity();
LiquidModule mod = tile.entity.liquids;
int rotation = tile.getRotation() * 90;
int rotation = tile.rotation() * 90;
Draw.colorl(0.34f);
Draw.rect(botRegions[entity.blendbits], tile.drawx(), tile.drawy(), rotation);
@@ -89,7 +89,7 @@ public class Conduit extends LiquidBlock{
entity.smoothLiquid = Mathf.lerpDelta(entity.smoothLiquid, entity.liquids.total() / liquidCapacity, 0.05f);
if(tile.entity.liquids.total() > 0.001f && tile.entity.timer.get(timerFlow, 1)){
tryMoveLiquid(tile, tile.getNearby(tile.getRotation()), true, tile.entity.liquids.current());
tryMoveLiquid(tile, tile.getNearby(tile.rotation()), true, tile.entity.liquids.current());
entity.noSleep();
}else{
entity.sleep();
@@ -104,7 +104,7 @@ public class Conduit extends LiquidBlock{
@Override
public boolean acceptLiquid(Tile tile, Tile source, Liquid liquid, float amount){
tile.entity.noSleep();
return tile.entity.liquids.get(liquid) + amount < liquidCapacity && (tile.entity.liquids.current() == liquid || tile.entity.liquids.get(tile.entity.liquids.current()) < 0.2f) && ((2 + source.relativeTo(tile.x, tile.y)) % 4 != tile.getRotation());
return tile.entity.liquids.get(liquid) + amount < liquidCapacity && (tile.entity.liquids.current() == liquid || tile.entity.liquids.get(tile.entity.liquids.current()) < 0.2f) && ((2 + source.relativeTo(tile.x, tile.y)) % 4 != tile.rotation());
}
@Override

View File

@@ -69,7 +69,7 @@ public class Conveyor extends Block{
@Override
public void draw(Tile tile){
ConveyorEntity entity = tile.entity();
byte rotation = tile.getRotation();
byte rotation = tile.rotation();
int frame = entity.clogHeat <= 0.5f ? (int)(((Time.time() * speed * 8f * entity.timeScale)) % 4) : 0;
Draw.rect(regions[Mathf.clamp(entity.blendbits, 0, regions.length - 1)][Mathf.clamp(frame, 0, regions[0].length - 1)], tile.drawx(), tile.drawy(),
@@ -125,11 +125,11 @@ public class Conveyor extends Block{
}
private boolean blends(Tile tile, int direction){
Tile other = tile.getNearby(Mathf.mod(tile.getRotation() - direction, 4));
if(other != null) other = other.target();
Tile other = tile.getNearby(Mathf.mod(tile.rotation() - direction, 4));
if(other != null) other = other.link();
return other != null && other.block().outputsItems()
&& ((tile.getNearby(tile.getRotation()) == other) || (!other.block().rotate || other.getNearby(other.getRotation()) == tile));
&& ((tile.getNearby(tile.rotation()) == other) || (!other.block().rotate || other.getNearby(other.rotation()) == tile));
}
@Override
@@ -141,7 +141,7 @@ public class Conveyor extends Block{
public void drawLayer(Tile tile){
ConveyorEntity entity = tile.entity();
byte rotation = tile.getRotation();
byte rotation = tile.rotation();
try{
@@ -176,7 +176,7 @@ public class Conveyor extends Block{
float speed = this.speed * tilesize / 2.4f;
float centerSpeed = 0.1f;
float centerDstScl = 3f;
float tx = Geometry.d4[tile.getRotation()].x, ty = Geometry.d4[tile.getRotation()].y;
float tx = Geometry.d4[tile.rotation()].x, ty = Geometry.d4[tile.rotation()].y;
float centerx = 0f, centery = 0f;
@@ -197,7 +197,7 @@ public class Conveyor extends Block{
public void update(Tile tile){
ConveyorEntity entity = tile.entity();
entity.minitem = 1f;
Tile next = tile.getNearby(tile.getRotation());
Tile next = tile.getNearby(tile.rotation());
float nextMax = next != null && next.block() instanceof Conveyor ? 1f - Math.max(itemSpace - next.<ConveyorEntity>entity().minitem, 0) : 1f;
int minremove = Integer.MAX_VALUE;
@@ -231,7 +231,7 @@ public class Conveyor extends Block{
ItemPos ni = pos2.set(othere.convey.get(othere.lastInserted), ItemPos.updateShorts);
if(next.getRotation() == tile.getRotation()){
if(next.rotation() == tile.rotation()){
ni.x = pos.x;
}
othere.convey.set(othere.lastInserted, ni.pack());
@@ -290,7 +290,7 @@ public class Conveyor extends Block{
@Override
public void getStackOffset(Item item, Tile tile, Vector2 trns){
trns.trns(tile.getRotation() * 90 + 180f, tilesize / 2f);
trns.trns(tile.rotation() * 90 + 180f, tilesize / 2f);
}
@Override
@@ -314,15 +314,15 @@ public class Conveyor extends Block{
@Override
public boolean acceptItem(Item item, Tile tile, Tile source){
int direction = source == null ? 0 : Math.abs(source.relativeTo(tile.x, tile.y) - tile.getRotation());
int direction = source == null ? 0 : Math.abs(source.relativeTo(tile.x, tile.y) - tile.rotation());
float minitem = tile.<ConveyorEntity>entity().minitem;
return (((direction == 0) && minitem > itemSpace) ||
((direction % 2 == 1) && minitem > 0.52f)) && (source == null || !(source.block().rotate && (source.getRotation() + 2) % 4 == tile.getRotation()));
((direction % 2 == 1) && minitem > 0.52f)) && (source == null || !(source.block().rotate && (source.rotation() + 2) % 4 == tile.rotation()));
}
@Override
public void handleItem(Item item, Tile tile, Tile source){
byte rotation = tile.getRotation();
byte rotation = tile.rotation();
int ch = Math.abs(source.relativeTo(tile.x, tile.y) - rotation);
int ang = ((source.relativeTo(tile.x, tile.y) - rotation));

View File

@@ -252,7 +252,7 @@ public class ItemBridge extends Block{
@Override
public boolean acceptItem(Item item, Tile tile, Tile source){
if(tile.getTeam() != source.target().getTeam()) return false;
if(tile.getTeam() != source.getTeam()) return false;
ItemBridgeEntity entity = tile.entity();
Tile other = world.tile(entity.link);

View File

@@ -74,7 +74,7 @@ public class Junction extends Block{
if(entity == null || relative == -1 || entity.buffers[relative].full())
return false;
Tile to = tile.getNearby(relative);
return to != null && to.target().entity != null;
return to != null && to.link().entity != null;
}
@Override

View File

@@ -59,7 +59,7 @@ public class LiquidBridge extends ItemBridge{
@Override
public boolean acceptLiquid(Tile tile, Tile source, Liquid liquid, float amount){
if(tile.getTeam() != source.target().getTeam()) return false;
if(tile.getTeam() != source.getTeam()) return false;
ItemBridgeEntity entity = tile.entity();
Tile other = world.tile(entity.link);

View File

@@ -41,7 +41,7 @@ public class LiquidJunction extends LiquidBlock{
public void handleLiquid(Tile tile, Tile source, Liquid liquid, float amount){
int dir = source.relativeTo(tile.x, tile.y);
dir = (dir + 4) % 4;
Tile to = tile.getNearby(dir).target();
Tile to = tile.getNearby(dir).link();
if(to.block().hasLiquids && to.block().acceptLiquid(to, tile, liquid, amount)){
to.block().handleLiquid(to, tile, liquid, amount);
@@ -54,7 +54,7 @@ public class LiquidJunction extends LiquidBlock{
dir = (dir + 4) % 4;
Tile to = dest.getNearby(dir);
if(to == null) return false;
to = to.target();
to = to.link();
return to != null && to.entity != null && to.block().hasLiquids && to.block().acceptLiquid(to, dest, liquid, amount);
}
}

View File

@@ -58,12 +58,12 @@ public class OverflowGate extends Router{
}else if(bc && !ac){
to = b;
}else{
if(tile.getDump() == 0){
if(tile.rotation() == 0){
to = a;
if(flip) tile.setDump((byte)1);
if(flip) tile.rotation((byte)1);
}else{
to = b;
if(flip) tile.setDump((byte)0);
if(flip) tile.rotation((byte)0);
}
}
}

View File

@@ -58,11 +58,11 @@ public class Router extends Block{
Tile getTileTarget(Tile tile, Item item, Tile from, boolean set){
Array<Tile> proximity = tile.entity.proximity();
int counter = tile.getDump();
int counter = tile.rotation();
for(int i = 0; i < proximity.size; i++){
Tile other = proximity.get((i + counter) % proximity.size);
if(tile == from) continue;
if(set) tile.setDump((byte)((tile.getDump() + 1) % proximity.size));
if(set) tile.rotation((byte)((tile.rotation() + 1) % proximity.size));
if(other.block().acceptItem(item, other, Edges.getFacingEdge(tile, other))){
return other;
}

View File

@@ -99,14 +99,14 @@ public class Sorter extends Block{
}else if(!bc){
return null;
}else{
if(dest.getDump() == 0){
if(dest.rotation() == 0){
to = a;
if(flip)
dest.setDump((byte)1);
dest.rotation((byte)1);
}else{
to = b;
if(flip)
dest.setDump((byte)0);
dest.rotation((byte)0);
}
}
}

View File

@@ -101,7 +101,7 @@ public class PowerNode extends PowerBlock{
Tile before = world.tile(lastPlaced);
if(linkValid(tile, before) && before.block() instanceof PowerNode){
for(Tile near : before.entity.proximity()){
if(near.target() == tile){
if(near == tile){
lastPlaced = tile.pos();
return;
}
@@ -127,7 +127,7 @@ public class PowerNode extends PowerBlock{
@Override
public boolean onConfigureTileTapped(Tile tile, Tile other){
TileEntity entity = tile.entity();
other = other.target();
other = other.link();
Tile result = other;
@@ -167,8 +167,7 @@ public class PowerNode extends PowerBlock{
for(int x = (int)(tile.x - laserRange - 1); x <= tile.x + laserRange + 1; x++){
for(int y = (int)(tile.y - laserRange - 1); y <= tile.y + laserRange + 1; y++){
Tile link = world.tile(x, y);
if(link != null) link = link.target();
Tile link = world.ltile(x, y);
if(link != tile && linkValid(tile, link, false)){
boolean linked = linked(tile, link);

View File

@@ -35,8 +35,7 @@ public class Unloader extends Block{
@Override
public boolean canDump(Tile tile, Tile to, Item item){
Block block = to.target().block();
return !(block instanceof StorageBlock);
return !(to.block() instanceof StorageBlock);
}
@Override