Moved rotation to Building

This commit is contained in:
Anuken 2020-07-29 10:19:07 -04:00
parent 749b9f5b30
commit 8729410cd8
49 changed files with 154 additions and 202 deletions

View file

@ -121,7 +121,7 @@ public class Blocks implements ContentList{
cliff = new Cliff("cliff"){{
inEditor = false;
saveRotation = true;
saveData = true;
}};
//Registers build blocks

View file

@ -266,6 +266,7 @@ public class UnitTypes implements ContentList{
splashDamage = 40f;
killShooter = true;
hittable = false;
collidesAir = true;
}};
}});
}};

View file

@ -67,7 +67,7 @@ public class Logic implements ApplicationListener{
}
}
data.blocks.addFirst(new BlockPlan(tile.x, tile.y, tile.rotation(), block.id, tile.build.config()));
data.blocks.addFirst(new BlockPlan(tile.x, tile.y, (short)tile.build.rotation, block.id, tile.build.config()));
});
Events.on(BlockBuildEndEvent.class, event -> {

View file

@ -582,7 +582,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.rotation() == req.rotation)){
}else if(!req.breaking && tile.block() == req.block && (!req.block.rotate || (tile.build != null && tile.build.rotation == req.rotation))){
continue;
}else if(con.rejectedRequests.contains(r -> r.breaking == req.breaking && r.x == req.x && r.y == req.y)){ //check if request was recently rejected, and skip it if so
continue;

View file

@ -102,7 +102,7 @@ public class World{
}
@Nullable
public Tile Building(int x, int y){
public Tile tileBuilding(int x, int y){
Tile tile = tiles.get(x, y);
if(tile == null) return null;
if(tile.build != null) return tile.build.tile();
@ -418,7 +418,7 @@ public class World{
int idx = tile.y * tiles.width + tile.x;
if(tile.isDarkened()){
tile.rotation(dark[idx]);
tile.data = dark[idx];
}
if(dark[idx] == 4){
@ -432,7 +432,7 @@ public class World{
}
}
if(full) tile.rotation(5);
if(full) tile.data = 5;
}
}
}
@ -472,7 +472,7 @@ public class World{
Tile tile = world.tile(x, y);
if(tile != null && tile.block().solid && tile.block().fillsTile && !tile.block().synthetic()){
dark = Math.max(dark, tile.rotation());
dark = Math.max(dark, tile.data);
}
return dark;

View file

@ -50,7 +50,7 @@ public class DrawOperation{
}else if(type == OpType.block.ordinal()){
return tile.blockID();
}else if(type == OpType.rotation.ordinal()){
return tile.rotation();
return tile.build == null ? 0 : (byte)tile.build.rotation;
}else if(type == OpType.team.ordinal()){
return (byte)tile.getTeamID();
}else if(type == OpType.overlay.ordinal()){
@ -65,9 +65,9 @@ public class DrawOperation{
tile.setFloor((Floor)content.block(to));
}else if(type == OpType.block.ordinal()){
Block block = content.block(to);
tile.setBlock(block, tile.team(), tile.rotation());
tile.setBlock(block, tile.team(), tile.build == null ? 0 : tile.build.rotation);
}else if(type == OpType.rotation.ordinal()){
tile.rotation(to);
if(tile.build != null) tile.build.rotation = to;
}else if(type == OpType.team.ordinal()){
tile.setTeam(Team.get(to));
}else if(type == OpType.overlay.ordinal()){

View file

@ -71,18 +71,6 @@ public class EditorTile extends Tile{
super.setTeam(team);
}
@Override
public void rotation(int rotation){
if(state.isGame()){
super.rotation(rotation);
return;
}
if(rotation == rotation()) return;
op(OpType.rotation, rotation());
super.rotation(rotation);
}
@Override
public void setOverlay(Block overlay){
if(state.isGame()){
@ -109,9 +97,9 @@ public class EditorTile extends Tile{
}
@Override
protected void changeEntity(Team team, Prov<Building> entityprov){
protected void changeEntity(Team team, Prov<Building> entityprov, int rotation){
if(state.isGame()){
super.changeEntity(team, entityprov);
super.changeEntity(team, entityprov, rotation);
return;
}
@ -123,7 +111,7 @@ public class EditorTile extends Tile{
Block block = block();
if(block.hasEntity()){
build = entityprov.get().init(this, team, false);
build = entityprov.get().init(this, team, false, rotation);
build.cons(new ConsumeModule(build));
if(block.hasItems) build.items = new ItemModule();
if(block.hasLiquids) build.liquids(new LiquidModule());

View file

@ -6,6 +6,7 @@ import arc.graphics.*;
import arc.math.*;
import arc.struct.*;
import mindustry.content.*;
import mindustry.editor.DrawOperation.*;
import mindustry.game.*;
import mindustry.gen.*;
import mindustry.io.*;
@ -140,8 +141,9 @@ public class MapEditor{
if(drawBlock.synthetic()){
tile.setTeam(drawTeam);
}
if(drawBlock.rotate){
tile.rotation((byte)rotation);
if(drawBlock.rotate && tile.build != null && tile.build.rotation != rotation){
addTileOp(TileOp.get(tile.x, tile.y, (byte)OpType.rotation.ordinal(), (byte)rotation));
tile.build.rotation = (byte)rotation;
}
}
};

View file

@ -51,7 +51,7 @@ public class MapGenerateDialog extends BaseDialog{
private CachedTile ctile = new CachedTile(){
//nothing.
@Override
protected void changeEntity(Team team, Prov<Building> entityprov){
protected void changeEntity(Team team, Prov<Building> entityprov, int rotation){
}
};
@ -123,7 +123,7 @@ public class MapGenerateDialog extends BaseDialog{
Tile tile = editor.tile(x, y);
input.apply(x, y, tile.floor(), tile.block(), tile.overlay());
filter.apply(input);
writeTiles[x][y].set(input.floor, input.block, input.ore, tile.team(), tile.rotation());
writeTiles[x][y].set(input.floor, input.block, input.ore, tile.team());
}
}
@ -134,7 +134,6 @@ public class MapGenerateDialog extends BaseDialog{
Tile tile = editor.tile(x, y);
GenTile write = writeTiles[x][y];
tile.rotation(write.rotation);
tile.setFloor((Floor)content.block(write.floor));
tile.setBlock(content.block(write.block));
tile.setTeam(Team.get(write.team));
@ -365,7 +364,7 @@ public class MapGenerateDialog extends BaseDialog{
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.get(tile.team), tile.rotation);
buffer2[px][py].set(input.floor, input.block, input.ore, Team.get(tile.team));
});
pixmap.each((px, py) -> buffer1[px][py].set(buffer2[px][py]));
@ -402,15 +401,14 @@ public class MapGenerateDialog extends BaseDialog{
}
private class GenTile{
public byte team, rotation;
public byte team;
public short block, floor, ore;
public void set(Block floor, Block wall, Block ore, Team team, int rotation){
public void set(Block floor, Block wall, Block ore, Team team){
this.floor = floor.id;
this.block = wall.id;
this.ore = ore.id;
this.team = (byte)team.id;
this.rotation = (byte)rotation;
}
public void set(GenTile other){
@ -418,11 +416,10 @@ public class MapGenerateDialog extends BaseDialog{
this.block = other.block;
this.ore = other.ore;
this.team = other.team;
this.rotation = other.rotation;
}
public GenTile set(Tile other){
set(other.floor(), other.block(), other.overlay(), other.team(), other.rotation());
set(other.floor(), other.block(), other.overlay(), other.team());
return this;
}
@ -430,7 +427,6 @@ public class MapGenerateDialog extends BaseDialog{
ctile.setFloor((Floor)content.block(floor));
ctile.setBlock(content.block(block));
ctile.setOverlay(content.block(ore));
ctile.rotation(rotation);
ctile.setTeam(Team.get(team));
return ctile;
}

View file

@ -113,7 +113,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.rotdeg() - 90);
region.getWidth() * Draw.scl, region.getHeight() * Draw.scl, tile.build == null ? 0 : tile.build.rotdeg() - 90);
}else{
float width = region.getWidth() * Draw.scl, height = region.getHeight() * Draw.scl;

View file

@ -49,7 +49,7 @@ abstract class BuilderComp implements Unitc{
while(it.hasNext()){
BuildPlan req = it.next();
Tile tile = world.tile(req.x, req.y);
if(tile == null || (req.breaking && tile.block() == Blocks.air) || (!req.breaking && (tile.rotation() == req.rotation || !req.block.rotate) && tile.block() == req.block)){
if(tile == null || (req.breaking && tile.block() == Blocks.air) || (!req.breaking && ((tile.build != null && tile.build.rotation == req.rotation) || !req.block.rotate) && tile.block() == req.block)){
it.remove();
}
}

View file

@ -53,6 +53,7 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
transient Seq<Building> proximity = new Seq<>(8);
transient boolean updateFlow;
transient byte dump;
transient int rotation;
PowerModule power;
ItemModule items;
@ -68,10 +69,11 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
private transient boolean initialized;
/** Sets this tile entity data to this and adds it if necessary. */
public Building init(Tile tile, Team team, boolean shouldAdd){
public Building init(Tile tile, Team team, boolean shouldAdd, int rotation){
if(!initialized){
create(tile.block(), team);
}
this.rotation = rotation;
this.tile = tile;
set(tile.drawx(), tile.drawy());
@ -129,7 +131,7 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
public final void writeBase(Writes write){
write.f(health);
write.b(rotation());
write.b(rotation);
write.b(team.id);
if(items != null) items.write(write);
if(power != null) power.write(write);
@ -231,25 +233,25 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
/** Multiblock front. */
public @Nullable Building front(){
int trns = block.size/2 + 1;
return nearby(Geometry.d4(rotation()).x * trns, Geometry.d4(rotation()).y * trns);
return nearby(Geometry.d4(rotation).x * trns, Geometry.d4(rotation).y * trns);
}
/** Multiblock back. */
public @Nullable Building back(){
int trns = block.size/2 + 1;
return nearby(Geometry.d4(rotation() + 2).x * trns, Geometry.d4(rotation() + 2).y * trns);
return nearby(Geometry.d4(rotation + 2).x * trns, Geometry.d4(rotation + 2).y * trns);
}
/** Multiblock left. */
public @Nullable Building left(){
int trns = block.size/2 + 1;
return nearby(Geometry.d4(rotation() + 1).x * trns, Geometry.d4(rotation() + 1).y * trns);
return nearby(Geometry.d4(rotation + 1).x * trns, Geometry.d4(rotation + 1).y * trns);
}
/** Multiblock right. */
public @Nullable Building right(){
int trns = block.size/2 + 1;
return nearby(Geometry.d4(rotation() + 3).x * trns, Geometry.d4(rotation() + 3).y * trns);
return nearby(Geometry.d4(rotation + 3).x * trns, Geometry.d4(rotation + 3).y * trns);
}
public int pos(){
@ -257,15 +259,7 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
}
public float rotdeg(){
return tile.rotdeg();
}
public int rotation(){
return tile.rotation();
}
public void rotation(int rotation){
if(tile != null) tile.rotation(rotation);
return rotation * 90;
}
public Floor floor(){
@ -398,7 +392,7 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
*/
public boolean movePayload(@NonNull Payload todump){
int trns = block.size/2 + 1;
Tile next = tile.getNearby(Geometry.d4(rotation()).x * trns, Geometry.d4(rotation()).y * trns);
Tile next = tile.getNearby(Geometry.d4(rotation).x * trns, Geometry.d4(rotation).y * trns);
if(next != null && next.build != null && next.build.team() == team && next.build.acceptPayload(base(), todump)){
next.build.handlePayload(base(), todump);
@ -481,7 +475,7 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
}
public float moveLiquidForward(float leakResistance, Liquid liquid){
Tile next = tile.getNearby(rotation());
Tile next = tile.getNearby(rotation);
if(next == null) return 0;

View file

@ -89,7 +89,7 @@ abstract class PayloadComp implements Posc, Rotc, Hitboxc{
Building tile = payload.entity;
int tx = Vars.world.toTile(x - tile.block().offset), ty = Vars.world.toTile(y - tile.block().offset);
Tile on = Vars.world.tile(tx, ty);
if(on != null && Build.validPlace(tile.block(), tile.team(), tx, ty, tile.rotation())){
if(on != null && Build.validPlace(tile.block(), tile.team(), tx, ty, tile.rotation)){
int rot = (int)((rotation + 45f) / 90f) % 4;
payload.place(on, rot);

View file

@ -3,6 +3,7 @@ package mindustry.entities.units;
import arc.func.*;
import arc.math.geom.*;
import arc.util.ArcAnnotate.*;
import mindustry.gen.*;
import mindustry.world.*;
import static mindustry.Vars.*;
@ -134,6 +135,10 @@ public class BuildPlan{
return world.tile(x, y);
}
public @Nullable Building build(){
return world.build(x, y);
}
@Override
public String toString(){
return "BuildRequest{" +

View file

@ -379,7 +379,7 @@ public class Schematics implements Loadable{
&& (tile.block().isVisible() || (tile.block() instanceof CoreBlock))){
Object config = tile.config();
tiles.add(new Stile(tile.block(), tile.tileX() + offsetX, tile.tileY() + offsetY, config, (byte)tile.rotation()));
tiles.add(new Stile(tile.block(), tile.tileX() + offsetX, tile.tileY() + offsetY, config, (byte)tile.rotation));
counted.add(tile.pos());
}
}
@ -418,8 +418,7 @@ public class Schematics implements Loadable{
Tile tile = world.tile(st.x + ox, st.y + oy);
if(tile == null) return;
tile.setBlock(st.block, team, 0);
tile.rotation(st.rotation);
tile.setBlock(st.block, team, st.rotation);
Object config = st.config;
if(tile.build != null){
@ -438,8 +437,7 @@ public class Schematics implements Loadable{
Tile tile = world.tile(st.x + ox, st.y + oy);
if(tile == null) return;
tile.setBlock(st.block, team, 0);
tile.rotation(st.rotation);
tile.setBlock(st.block, team, st.rotation);
Object config = st.config;
if(tile.build != null){

View file

@ -206,7 +206,7 @@ public class FloorRenderer implements Disposable{
floor = tile.floor();
}
if(tile.block().cacheLayer == layer && layer == CacheLayer.walls && !(tile.isDarkened() && tile.rotation() >= 5)){
if(tile.block().cacheLayer == layer && layer == CacheLayer.walls && !(tile.isDarkened() && tile.data >= 5)){
tile.block().drawBase(tile);
}else if(floor.cacheLayer == layer && (world.isAccessible(tile.x, tile.y) || tile.block().cacheLayer != CacheLayer.walls || !tile.block().fillsTile)){
floor.drawBase(tile);

View file

@ -138,7 +138,7 @@ public class OverlayRenderer{
tile.drawSelect();
if(Core.input.keyDown(Binding.rotateplaced) && tile.block().rotate && tile.interactable(player.team())){
control.input.drawArrow(tile.block(), tile.tileX(), tile.tileY(), tile.rotation(), true);
control.input.drawArrow(tile.block(), tile.tileX(), tile.tileY(), tile.rotation, true);
Draw.color(Pal.accent, 0.3f + Mathf.absin(4f, 0.2f));
Fill.square(tile.x, tile.y, tile.block().size * tilesize/2f);
Draw.color();

View file

@ -167,11 +167,11 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
@Remote(targets = Loc.both, called = Loc.server, forward = true, unreliable = true)
public static void rotateBlock(Player player, Building tile, boolean direction){
if(net.server() && (!Units.canInteract(player, tile) ||
!netServer.admins.allowAction(player, ActionType.rotate, tile.tile(), action -> action.rotation = Mathf.mod(tile.rotation() + Mathf.sign(direction), 4)))){
!netServer.admins.allowAction(player, ActionType.rotate, tile.tile(), action -> action.rotation = Mathf.mod(tile.rotation + Mathf.sign(direction), 4)))){
throw new ValidateException(player, "Player cannot rotate a block.");
}
tile.rotation(Mathf.mod(tile.rotation() + Mathf.sign(direction), 4));
tile.rotation = Mathf.mod(tile.rotation + Mathf.sign(direction), 4);
tile.updateProximity();
tile.noSleep();
}
@ -532,7 +532,7 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
for(int x = dresult.x; x <= dresult.x2; x++){
for(int y = dresult.y; y <= dresult.y2; y++){
Tile tile = world.Building(x, y);
Tile tile = world.tileBuilding(x, y);
if(tile == null || !validBreak(tile.x, tile.y)) continue;
drawBreaking(tile.x, tile.y);
@ -648,7 +648,7 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
int wx = x1 + x * Mathf.sign(x2 - x1);
int wy = y1 + y * Mathf.sign(y2 - y1);
Tile tile = world.Building(wx, wy);
Tile tile = world.tileBuilding(wx, wy);
if(tile == null) continue;

View file

@ -168,8 +168,8 @@ public abstract class SaveVersion extends SaveFileReader{
Tile tile = world.rawTile(i % world.width(), i / world.width());
stream.writeShort(tile.blockID());
boolean saverot = tile.block().saveRotation;
byte packed = (byte)((tile.build != null ? 1 : 0) | (saverot ? 2 : 0));
boolean savedata = tile.block().saveData;
byte packed = (byte)((tile.build != null ? 1 : 0) | (savedata ? 2 : 0));
//make note of whether there was an entity/rotation here
stream.writeByte(packed);
@ -185,8 +185,8 @@ public abstract class SaveVersion extends SaveFileReader{
}else{
stream.writeBoolean(false);
}
}else if(saverot){
stream.writeByte(tile.rotation());
}else if(savedata){
stream.writeByte(tile.data);
}else{
//write consecutive non-entity blocks
int consecutives = 0;
@ -244,7 +244,7 @@ public abstract class SaveVersion extends SaveFileReader{
boolean isCenter = true;
byte packedCheck = stream.readByte();
boolean hadEntity = (packedCheck & 1) != 0;
boolean hadRotation = (packedCheck & 2) != 0;
boolean hadData = (packedCheck & 2) != 0;
if(hadEntity){
isCenter = stream.readBoolean();
@ -271,9 +271,9 @@ public abstract class SaveVersion extends SaveFileReader{
skipChunk(stream, true);
}
}
}else if(hadRotation){
}else if(hadData){
tile.setBlock(block);
tile.rotation(stream.readByte());
tile.data = stream.readByte();
}else{
int consecutives = stream.readUnsignedByte();

View file

@ -72,12 +72,12 @@ public abstract class LegacySaveVersion extends SaveVersion{
byte rotation = Pack.rightByte(packedrot);
tile.setTeam(Team.get(team));
tile.rotation(rotation);
tile.build.rotation = rotation;
if(tile.build.items != null) tile.build.items.read(Reads.get(stream));
if(tile.build.power != null) tile.build.power.read(Reads.get(stream));
if(tile.build.liquids != null) tile.build.liquids.read(Reads.get(stream));
if(tile.build.cons() != null) tile.build.cons().read(Reads.get(stream));
if(tile.build.cons != null) tile.build.cons.read(Reads.get(stream));
//read only from subclasses!
tile.build.read(Reads.get(in), version);

View file

@ -57,15 +57,15 @@ public abstract class BasicGenerator implements WorldGenerator{
}
}
tile.rotation(rotation);
tile.data = (byte)rotation;
}
for(Tile tile : tiles){
if(tile.rotation() != 0){
int rotation = tile.rotation();
if(tile.data != 0){
int rotation = tile.data;
tile.setBlock(Blocks.cliff);
tile.setOverlay(Blocks.air);
tile.rotation(rotation);
tile.data = (byte)rotation;
}
}
}
@ -86,7 +86,7 @@ public abstract class BasicGenerator implements WorldGenerator{
tile.setBlock(Blocks.cliff);
}
tile.rotation(rotation);
tile.data = (byte)rotation;
}
for(Tile tile : tiles){

View file

@ -199,15 +199,15 @@ public class Sector{
if(save != null){
int capacity = save.meta.secinfo.storageCapacity;
long seconds = state.rules.sector.getSecondsPassed();
long seconds = getSecondsPassed();
//add produced items
state.rules.sector.save.meta.secinfo.production.each((item, stat) -> {
save.meta.secinfo.production.each((item, stat) -> {
count.add(item, (int)(stat.mean * seconds));
});
//add received items
state.rules.sector.getReceivedItems().each(stack -> count.add(stack.item, stack.amount));
getReceivedItems().each(stack -> count.add(stack.item, stack.amount));
//validation
for(Item item : content.items()){

View file

@ -74,8 +74,8 @@ public class Block extends UnlockableContent{
public boolean solidifes;
/** whether this is rotateable */
public boolean rotate;
/** for static blocks only: if true, rotation is saved in world data. */
public boolean saveRotation;
/** for static blocks only: if true, tile data() is saved in world data. */
public boolean saveData;
/** whether you can break this with rightclick */
public boolean breakable;
/** whether to add this block to brokenblocks */

View file

@ -22,7 +22,7 @@ public class Build{
return;
}
Tile tile = world.Building(x, y);
Tile tile = world.tileBuilding(x, y);
//this should never happen, but it doesn't hurt to check for links
float prevPercent = 1f;
@ -30,7 +30,7 @@ public class Build{
prevPercent = tile.build.healthf();
}
int rotation = tile.rotation();
int rotation = tile.build != null ? tile.build.rotation : 0;
Block previous = tile.block();
Block sub = BuildBlock.get(previous.size);
@ -146,7 +146,7 @@ public class Build{
&& tile.floor().placeableOn
&& (!type.requiresWater || tile.floor().liquidDrop == Liquids.water)
&& (((type.canReplace(tile.block()) || (tile.block instanceof BuildBlock && tile.<BuildEntity>bc().cblock == type))
&& !(type == tile.block() && rotation == tile.rotation() && type.rotate)) || tile.block().alwaysReplace || tile.block() == Blocks.air)
&& !(type == tile.block() && (tile.build != null && rotation == tile.build.rotation) && type.rotate)) || tile.block().alwaysReplace || tile.block() == Blocks.air)
&& tile.block().isMultiblock() == type.isMultiblock() && type.canPlaceOn(tile, team);
}
}

View file

@ -21,7 +21,7 @@ public class CachedTile extends Tile{
}
@Override
protected void changeEntity(Team team, Prov<Building> entityprov){
protected void changeEntity(Team team, Prov<Building> entityprov, int rotation){
build = null;
Block block = block();

View file

@ -21,6 +21,8 @@ import static mindustry.Vars.*;
public class Tile implements Position, QuadTreeObject, Displayable{
static final ObjectSet<Building> tileSet = new ObjectSet<>();
/** Extra data for very specific blocks. */
public byte data;
/** Tile traversal cost. */
public short cost = 1;
/** Tile entity, usually null. */
@ -29,8 +31,6 @@ public class Tile implements Position, QuadTreeObject, Displayable{
protected @NonNull Block block;
protected @NonNull Floor floor;
protected @NonNull Floor overlay;
/** Rotation of blocks, or other data. Not guaranteed to be in any specific range. */
protected byte rotation;
protected boolean changing = false;
public Tile(int x, int y){
@ -47,7 +47,7 @@ public class Tile implements Position, QuadTreeObject, Displayable{
this.block = wall;
//update entity and create it if needed
changeEntity(Team.derelict, wall::newEntity);
changeEntity(Team.derelict, wall::newEntity, 0);
changed();
}
@ -183,9 +183,8 @@ public class Tile implements Position, QuadTreeObject, Displayable{
changing = true;
this.block = type;
this.rotation = rotation == 0 ? 0 : (byte)Mathf.mod(rotation, 4);
preChanged();
changeEntity(team, entityprov);
changeEntity(team, entityprov, (byte)Mathf.mod(rotation, 4));
if(build != null){
build.team(team);
@ -304,18 +303,6 @@ public class Tile implements Position, QuadTreeObject, Displayable{
setFloorNet(floor, Blocks.air);
}
public byte rotation(){
return rotation;
}
public int rotdeg(){
return rotation * 90;
}
public void rotation(int rotation){
this.rotation = (byte)rotation;
}
public short overlayID(){
return overlay.id;
}
@ -443,23 +430,6 @@ public class Tile implements Position, QuadTreeObject, Displayable{
return null;
}
// B A
public @Nullable Building front(){
return getNearbyEntity((rotation + 4) % 4);
}
public @Nullable Building right(){
return getNearbyEntity((rotation + 3) % 4);
}
public @Nullable Building back(){
return getNearbyEntity((rotation + 2) % 4);
}
public @Nullable Building left(){
return getNearbyEntity((rotation + 1) % 4);
}
public boolean interactable(Team team){
return state.teams.canInteract(team, team());
}
@ -469,7 +439,7 @@ public class Tile implements Position, QuadTreeObject, Displayable{
}
public int staticDarkness(){
return block.solid && block.fillsTile && !block.synthetic() ? rotation : 0;
return block.solid && block.fillsTile && !block.synthetic() ? data : 0;
}
public void updateOcclusion(){
@ -548,7 +518,7 @@ public class Tile implements Position, QuadTreeObject, Displayable{
}
}
protected void changeEntity(Team team, Prov<Building> entityprov){
protected void changeEntity(Team team, Prov<Building> entityprov, int rotation){
if(build != null){
int size = build.block.size;
build.remove();
@ -571,7 +541,7 @@ public class Tile implements Position, QuadTreeObject, Displayable{
}
if(block.hasEntity()){
build = entityprov.get().init(this, team, block.update);
build = entityprov.get().init(this, team, block.update, rotation);
}
}

View file

@ -147,7 +147,7 @@ public interface Autotiler{
default boolean blends(Tile tile, int rotation, int direction){
Building other = tile.getNearbyEntity(Mathf.mod(rotation - direction, 4));
return other != null && other.team() == tile.team() && blends(tile, rotation, other.tileX(), other.tileY(), other.rotation(), other.block());
return other != null && other.team() == tile.team() && blends(tile, rotation, other.tileX(), other.tileY(), other.rotation, other.block());
}
default boolean blendsArmored(Tile tile, int rotation, int otherx, int othery, int otherrot, Block otherblock){

View file

@ -154,7 +154,7 @@ public class BuildBlock extends Block{
if(control.input.buildWasAutoPaused && !control.input.isBuilding && player.isBuilder()){
control.input.isBuilding = true;
}
player.builder().addBuild(new BuildPlan(tile.x, tile.y, tile.rotation(), cblock), false);
player.builder().addBuild(new BuildPlan(tile.x, tile.y, rotation, cblock), false);
}
}
@ -170,7 +170,7 @@ public class BuildBlock extends Block{
@Override
public void draw(){
if(!(previous == null || cblock == null || previous == cblock) && Core.atlas.isFound(previous.icon(Cicon.full))){
Draw.rect(previous.icon(Cicon.full), x, y, previous.rotate ? tile.rotdeg() : 0);
Draw.rect(previous.icon(Cicon.full), x, y, previous.rotate ? rotdeg() : 0);
}
Draw.draw(Layer.blockBuilding, () -> {
@ -183,7 +183,7 @@ public class BuildBlock extends Block{
Shaders.blockbuild.region = region;
Shaders.blockbuild.progress = progress;
Draw.rect(region, x, y, target.rotate ? tile.rotdeg() : 0);
Draw.rect(region, x, y, target.rotate ? rotdeg() : 0);
Draw.flush();
}
}
@ -214,7 +214,7 @@ public class BuildBlock extends Block{
builderID = builder.id();
if(progress >= 1f || state.rules.infiniteResources){
constructed(tile, cblock, builderID, tile.rotation(), builder.team(), configured);
constructed(tile, cblock, builderID, (byte)rotation, builder.team(), configured);
return true;
}
return false;

View file

@ -65,9 +65,9 @@ public class MendProjector extends Block{
heat = Mathf.lerpDelta(heat, consValid() || cheating() ? 1f : 0f, 0.08f);
charge += heat * delta();
phaseHeat = Mathf.lerpDelta(phaseHeat, Mathf.num(cons().optionalValid()), 0.1f);
phaseHeat = Mathf.lerpDelta(phaseHeat, Mathf.num(cons.optionalValid()), 0.1f);
if(cons().optionalValid() && timer(timerUse, useTime) && efficiency() > 0){
if(cons.optionalValid() && timer(timerUse, useTime) && efficiency() > 0){
consume();
}

View file

@ -76,7 +76,7 @@ public class OverdriveProjector extends Block{
charge += heat * Time.delta;
if(hasBoost){
phaseHeat = Mathf.lerpDelta(phaseHeat, Mathf.num(cons().optionalValid()), 0.1f);
phaseHeat = Mathf.lerpDelta(phaseHeat, Mathf.num(cons.optionalValid()), 0.1f);
}
if(timer(timerUse, useTime) && efficiency() > 0){

View file

@ -18,7 +18,7 @@ public class ArmoredConveyor extends Conveyor{
public class ArmoredConveyorEntity extends ConveyorEntity{
@Override
public boolean acceptItem(Building source, Item item){
return super.acceptItem(source, item) && (source.block() instanceof Conveyor || Edges.getFacingEdge(source.tile(), tile).relativeTo(tile) == tile.rotation());
return super.acceptItem(source, item) && (source.block() instanceof Conveyor || Edges.getFacingEdge(source.tile(), tile).relativeTo(tile) == rotation);
}
}
}

View file

@ -88,7 +88,7 @@ public class Conveyor extends Block implements Autotiler{
cont.get(Geometry.d4(req.rotation - 2)) &&
req.tile() != null &&
req.tile().block() instanceof Conveyor &&
Mathf.mod(req.tile().rotation() - req.rotation, 2) == 1 ? Blocks.junction : this;
Mathf.mod(req.tile().build.rotation - req.rotation, 2) == 1 ? Blocks.junction : this;
}
public class ConveyorEntity extends Building{
@ -114,7 +114,6 @@ public class Conveyor extends Block implements Autotiler{
@Override
public void draw(){
byte rotation = tile.rotation();
int frame = clogHeat <= 0.5f ? (int)(((Time.time() * speed * 8f * timeScale())) % 4) : 0;
//draw extra conveyors facing this one for non-square tiling purposes
@ -155,16 +154,16 @@ public class Conveyor extends Block implements Autotiler{
public void onProximityUpdate(){
super.onProximityUpdate();
int[] bits = buildBlending(tile, rotation(), null, true);
int[] bits = buildBlending(tile, rotation, null, true);
blendbits = bits[0];
blendsclx = bits[1];
blendscly = bits[2];
blending = bits[4];
if(tile.front() != null && tile.front() != null){
next = tile.front();
if(front() != null && front() != null){
next = front();
nextc = next instanceof ConveyorEntity && next.team() == team ? (ConveyorEntity)next : null;
aligned = nextc != null && tile.rotation() == next.tile().rotation();
aligned = nextc != null && rotation == next.rotation;
}
}
@ -179,7 +178,7 @@ public class Conveyor extends Block implements Autotiler{
float mspeed = speed * tilesize / 2.4f;
float centerSpeed = 0.1f;
float centerDstScl = 3f;
float tx = Geometry.d4[tile.rotation()].x, ty = Geometry.d4[tile.rotation()].y;
float tx = Geometry.d4[rotation].x, ty = Geometry.d4[rotation].y;
float centerx = 0f, centery = 0f;
@ -263,7 +262,7 @@ public class Conveyor extends Block implements Autotiler{
@Override
public void getStackOffset(Item item, Vec2 trns){
trns.trns(tile.rotdeg() + 180f, tilesize / 2f);
trns.trns(rotdeg() + 180f, tilesize / 2f);
}
@Override
@ -290,15 +289,15 @@ public class Conveyor extends Block implements Autotiler{
public boolean acceptItem(Building source, Item item){
if(len >= capacity) return false;
Tile facing = Edges.getFacingEdge(source.tile(), tile);
int direction = Math.abs(facing.relativeTo(tile.x, tile.y) - tile.rotation());
return (((direction == 0) && minitem >= itemSpace) || ((direction % 2 == 1) && minitem > 0.7f)) && !(source.block().rotate && (source.rotation() + 2) % 4 == tile.rotation());
int direction = Math.abs(facing.relativeTo(tile.x, tile.y) - rotation);
return (((direction == 0) && minitem >= itemSpace) || ((direction % 2 == 1) && minitem > 0.7f)) && !(source.block().rotate && (source.rotation + 2) % 4 == rotation);
}
@Override
public void handleItem(Building source, Item item){
if(len >= capacity) return;
byte r = tile.rotation();
int r = rotation;
Tile facing = Edges.getFacingEdge(source.tile(), tile);
int ang = ((facing.relativeTo(tile.x, tile.y) - r));
float x = (ang == -1 || ang == 3) ? 1 : (ang == 1 || ang == -3) ? -1 : 0;

View file

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

View file

@ -66,15 +66,15 @@ public class PayloadConveyor extends Block{
public void onProximityUpdate(){
super.onProximityUpdate();
Building accept = nearby(Geometry.d4(rotation()).x * size, Geometry.d4(rotation()).y * size);
Building accept = nearby(Geometry.d4(rotation).x * size, Geometry.d4(rotation).y * size);
//next block must be aligned and of the same size
if(accept != null && (
//same size
(accept.block().size == size && tileX() + Geometry.d4(rotation()).x * size == accept.tileX() && tileY() + Geometry.d4(rotation()).y * size == accept.tileY()) ||
(accept.block().size == size && tileX() + Geometry.d4(rotation).x * size == accept.tileX() && tileY() + Geometry.d4(rotation).y * size == accept.tileY()) ||
//differing sizes
(accept.block().size > size &&
(rotation() % 2 == 0 ? //check orientation
(rotation % 2 == 0 ? //check orientation
Math.abs(accept.y - y) <= (accept.block().size * tilesize - size * tilesize)/2f : //check Y alignment
Math.abs(accept.x - x) <= (accept.block().size * tilesize - size * tilesize)/2f //check X alignment
)))){
@ -84,8 +84,8 @@ public class PayloadConveyor extends Block{
}
int ntrns = 1 + size/2;
Tile next = tile.getNearby(Geometry.d4(rotation()).x * ntrns, Geometry.d4(rotation()).y * ntrns);
blocked = (next != null && next.solid()) || (this.next != null && (this.next.rotation() + 2)%4 == rotation());
Tile next = tile.getNearby(Geometry.d4(rotation).x * ntrns, Geometry.d4(rotation).y * ntrns);
blocked = (next != null && next.solid()) || (this.next != null && (this.next.rotation + 2)%4 == rotation);
}
@Override
@ -161,7 +161,7 @@ public class PayloadConveyor extends Block{
Draw.rect(clipped, x + Tmp.v1.x, y + Tmp.v1.y, rot);
for(int i = 0; i < 4; i++){
if(blends(i) && i != rotation()){
if(blends(i) && i != rotation){
Draw.alpha(1f - Interp.pow5In.apply(fract()));
//prev from back
Tmp.v1.set(- s/2f + clipped.getWidth()/2f*Draw.scl, - s/2f + clipped.getHeight()/2f*Draw.scl).rotate(i * 90 + 180);
@ -242,7 +242,7 @@ public class PayloadConveyor extends Block{
}
boolean blends(int direction){
if(direction == rotation()){
if(direction == rotation){
return !blocked || next != null;
}else{
return PayloadAcceptor.blends(this, direction);

View file

@ -37,7 +37,7 @@ public class PayloadRouter extends PayloadConveyor{
public void moved(){
int rotations = 0;
do{
tile.rotation((tile.rotation() + 1) % 4);
rotation = (rotation + 1) % 4;
onProximityUpdate();
}while((blocked || next == null) && ++rotations < 4);
}

View file

@ -71,10 +71,10 @@ public class Router extends Block{
}
Building getTileTarget(Item item, Tile from, boolean set){
int counter = tile.rotation();
int counter = rotation;
for(int i = 0; i < proximity.size; i++){
Building other = proximity.get((i + counter) % proximity.size);
if(set) tile.rotation((byte)((tile.rotation() + 1) % proximity.size));
if(set) rotation = ((byte)((rotation + 1) % proximity.size));
if(other.tile() == from && from.block() == Blocks.overflowGate) continue;
if(other.acceptItem(this, item)){
return other;

View file

@ -117,12 +117,12 @@ public class Sorter extends Block{
}else if(!bc){
return null;
}else{
if(rotation() == 0){
if(rotation == 0){
to = a;
if(flip) rotation((byte)1);
if(flip) this.rotation = (byte)1;
}else{
to = b;
if(flip) rotation((byte)0);
if(flip) this.rotation = (byte)0;
}
}
}

View file

@ -104,25 +104,26 @@ public class StackConveyor extends Block implements Autotiler{
for(int i = 0; i < 4; i++){
if((blendprox & (1 << i)) == 0){
Draw.rect(edgeRegion, x, y, (rotation() - i) * 90);
Draw.rect(edgeRegion, x, y, (rotation - i) * 90);
}
}
Draw.z(Layer.blockOver);
if(link == -1) return;
Building from = world.build(link);
if(link == -1 || from == null) return;
//offset
Tile from = world.tile(link);
Tmp.v1.set(from);
Tmp.v2.set(tile);
Tmp.v1.interpolate(Tmp.v2, 1f - cooldown, Interp.linear);
//rotation
float a = (from.rotation()%4) * 90;
float b = (tile.rotation()%4) * 90;
if((from.rotation()%4) == 3 && (tile.rotation()%4) == 0) a = -1 * 90;
if((from.rotation()%4) == 0 && (tile.rotation()%4) == 3) a = 4 * 90;
float a = (from.rotation%4) * 90;
float b = (rotation%4) * 90;
if((from.rotation%4) == 3 && (rotation%4) == 0) a = -1 * 90;
if((from.rotation%4) == 0 && (rotation%4) == 3) a = 4 * 90;
//stack
Draw.rect(stackRegion, Tmp.v1.x, Tmp.v1.y, Mathf.lerp(a, b, Interp.smooth.apply(1f - Mathf.clamp(cooldown * 2, 0f, 1f))));
@ -141,14 +142,14 @@ public class StackConveyor extends Block implements Autotiler{
state = stateMove;
int[] bits = buildBlending(tile, tile.rotation(), null, true);
if(bits[0] == 0 && blends(tile, tile.rotation(), 0) && !blends(tile, tile.rotation(), 2)) state = stateLoad; // a 0 that faces into a conveyor with none behind it
if(bits[0] == 0 && !blends(tile, tile.rotation(), 0) && blends(tile, tile.rotation(), 2)) state = stateUnload; // a 0 that faces into none with a conveyor behind it
int[] bits = buildBlending(tile, rotation, null, true);
if(bits[0] == 0 && blends(tile, rotation, 0) && !blends(tile, rotation, 2)) state = stateLoad; // a 0 that faces into a conveyor with none behind it
if(bits[0] == 0 && !blends(tile, rotation, 0) && blends(tile, rotation, 2)) state = stateUnload; // a 0 that faces into none with a conveyor behind it
blendprox = 0;
for(int i = 0; i < 4; i++){
if(blends(tile, rotation(), i)){
if(blends(tile, rotation, i)){
blendprox |= (1 << i);
}
}
@ -253,7 +254,7 @@ public class StackConveyor extends Block implements Autotiler{
return !((state != stateLoad) // not a loading dock
|| (items.total() > 0 && !items.has(item)) // incompatible items
|| (items.total() >= getMaximumAccepted(item)) // filled to capacity
|| (tile.front() == source));
|| (front() == source));
}
@Override

View file

@ -18,7 +18,7 @@ public class Cliff extends Block{
@Override
public void drawBase(Tile tile){
int r = tile.rotation();
int r = tile.data;
for(int i = 0; i < 8; i++){
if((r & (1 << i)) != 0){
Draw.color(Tmp.c1.set(tile.floor().mapColor).mul(1.3f + (i >= 4 ? -0.4f : 0.3f)));

View file

@ -71,7 +71,7 @@ public class BlockLoader extends PayloadAcceptor{
//draw input
for(int i = 0; i < 4; i++){
if(blends(i) && i != rotation()){
if(blends(i) && i != rotation){
Draw.rect(inRegion, x, y, i * 90);
}
}

View file

@ -25,15 +25,16 @@ public class ArmoredConduit extends Conduit{
super.draw();
// draw the cap when a conduit would normally leak
Building next = tile.front();
Building next = front();
if(next != null && next.team() == team && next.block().hasLiquids) return;
Draw.rect(capRegion, x, y, tile.rotdeg());
Draw.rect(capRegion, x, y, rotdeg());
}
@Override
public boolean acceptLiquid(Building source, Liquid liquid, float amount){
return super.acceptLiquid(source, liquid, amount) && (source.block() instanceof Conduit) || Edges.getFacingEdge(source.tile(), tile).absoluteRelativeTo(tile.x, tile.y) == tile.rotation();
return super.acceptLiquid(source, liquid, amount) && (source.block() instanceof Conduit) ||
Edges.getFacingEdge(source.tile(), tile).absoluteRelativeTo(tile.x, tile.y) == rotation;
}
}
}

View file

@ -59,7 +59,7 @@ public class Conduit extends LiquidBlock implements Autotiler{
cont.get(Geometry.d4(req.rotation - 2)) &&
req.tile() != null &&
req.tile().block() instanceof Conduit &&
Mathf.mod(req.tile().rotation() - req.rotation, 2) == 1 ? Blocks.liquidJunction : this;
Mathf.mod(req.build().rotation - req.rotation, 2) == 1 ? Blocks.liquidJunction : this;
}
@Override
@ -79,7 +79,7 @@ public class Conduit extends LiquidBlock implements Autotiler{
@Override
public void draw(){
float rotation = rotdeg();
int r = rotation();
int r = this.rotation;
//draw extra conduits facing this one for tiling purposes
Draw.z(Layer.blockUnder);
@ -114,7 +114,7 @@ public class Conduit extends LiquidBlock implements Autotiler{
public void onProximityUpdate(){
super.onProximityUpdate();
int[] bits = buildBlending(tile, rotation(), null, true);
int[] bits = buildBlending(tile, rotation, null, true);
blendbits = bits[0];
xscl = bits[1];
yscl = bits[2];
@ -125,7 +125,7 @@ public class Conduit extends LiquidBlock implements Autotiler{
public boolean acceptLiquid(Building source, Liquid liquid, float amount){
noSleep();
return liquids.get(liquid) + amount < liquidCapacity && (liquids.current() == liquid || liquids.currentAmount() < 0.2f)
&& ((source.relativeTo(tile.x, tile.y) + 2) % 4 != tile.rotation());
&& ((source.relativeTo(tile.x, tile.y) + 2) % 4 != rotation);
}
@Override

View file

@ -46,17 +46,17 @@ public class PowerDiode extends Block{
@Override
public void draw(){
Draw.rect(region, x, y, 0);
Draw.rect(arrow, x, y, rotate ? tile.rotdeg() : 0);
Draw.rect(arrow, x, y, rotate ? rotdeg() : 0);
}
@Override
public void updateTile(){
super.updateTile();
if(tile.front() == null || tile.back() == null || !tile.back().block().hasPower || !tile.front().block().hasPower || tile.back().team() != tile.front().team()) return;
if(front() == null || back() == null || !back().block().hasPower || !front().block().hasPower || back().team() != front().team()) return;
PowerGraph backGraph = tile.back().power.graph;
PowerGraph frontGraph = tile.front().power.graph;
PowerGraph backGraph = back().power.graph;
PowerGraph frontGraph = front().power.graph;
if(backGraph == frontGraph) return;
// 0f - 1f of battery capacity in use

View file

@ -259,7 +259,7 @@ public class Drill extends Block{
float speed = 1f;
if(cons().optionalValid()){
if(cons.optionalValid()){
speed = liquidBoostIntensity;
}

View file

@ -34,12 +34,12 @@ public class PayloadAcceptor extends Block{
//if size is the same, block must either be facing this one, or not be rotating
((accept.block().size == size &&
((accept.tileX() + Geometry.d4(accept.rotation()).x * size == tile.tileX() && accept.tileY() + Geometry.d4(accept.rotation()).y * size == tile.tileY())
((accept.tileX() + Geometry.d4(accept.rotation).x * size == tile.tileX() && accept.tileY() + Geometry.d4(accept.rotation).y * size == tile.tileY())
|| !accept.block().rotate || (accept.block().rotate && !accept.block().outputFacing))) ||
//if the other block is smaller, check alignment
(accept.block().size < size &&
(accept.rotation() % 2 == 0 ? //check orientation; make sure it's aligned properly with this block.
(accept.rotation % 2 == 0 ? //check orientation; make sure it's aligned properly with this block.
Math.abs(accept.y - tile.y) <= (size * tilesize - accept.block().size * tilesize)/2f : //check Y alignment
Math.abs(accept.x - tile.x) <= (size * tilesize - accept.block().size * tilesize)/2f //check X alignment
)) && (!accept.block().rotate || accept.front() == tile || !accept.block().outputFacing) //make sure it's facing this block

View file

@ -86,7 +86,7 @@ public class Reconstructor extends UnitBlock{
@Override
public boolean acceptPayload(Building source, Payload payload){
return this.payload == null
&& relativeTo(source) != rotation()
&& relativeTo(source) != rotation
&& payload instanceof UnitPayload
&& hasUpgrade(((UnitPayload)payload).unit.type());
}
@ -102,7 +102,7 @@ public class Reconstructor extends UnitBlock{
//draw input
for(int i = 0; i < 4; i++){
if(blends(i) && i != rotation()){
if(blends(i) && i != rotation){
Draw.rect(inRegion, x, y, i * 90);
}
}

View file

@ -110,7 +110,6 @@ public class ApplicationTests{
Time.setDeltaProvider(() -> 1000f);
Time.update();
Time.update();
Time.setDeltaProvider(() -> 1f);
Groups.unit.update();
assertFalse(Groups.unit.isEmpty(), "No enemies spawned.");
}
@ -289,7 +288,6 @@ public class ApplicationTests{
state.set(State.playing);
world.tile(0, 0).setBlock(Blocks.conveyor);
world.tile(0, 0).rotation(0);
world.tile(0, 0).build.acceptStack(Items.copper, 1000, null);
}
@ -372,8 +370,7 @@ public class ApplicationTests{
Seq<Building> entities = Seq.with(world.tile(0, 0).build);
for(int i = 0; i < length; i++){
world.tile(i + 1, 0).setBlock(Blocks.conveyor);
world.tile(i + 1, 0).rotation(0);
world.tile(i + 1, 0).setBlock(Blocks.conveyor, Team.derelict, 0);
entities.add(world.tile(i + 1, 0).build);
}

View file

@ -89,7 +89,7 @@ public class ItemLiquidGeneratorTests extends PowerTestFixture{
assertTrue(entity.acceptLiquid(null, liquid, availableLiquidAmount), inputType + " | " + parameterDescription + ": Liquids which will be declined by the generator don't need to be tested - The code won't be called for those cases.");
entity.liquids.add(liquid, availableLiquidAmount);
entity.cons().update();
entity.cons.update();
// Perform an update on the generator once - This should use up any resource up to the maximum liquid usage
entity.updateTile();
@ -133,7 +133,7 @@ public class ItemLiquidGeneratorTests extends PowerTestFixture{
if(amount > 0){
entity.items.add(item, amount);
}
entity.cons().update();
entity.cons.update();
// Perform an update on the generator once - This should use up one or zero items - dependent on if the item is accepted and available or not.
try{
@ -164,7 +164,7 @@ public class ItemLiquidGeneratorTests extends PowerTestFixture{
// Burn a single coal and test for the duration
entity.items.add(Items.coal, 1);
entity.cons().update();
entity.cons.update();
entity.updateTile();
float expectedEfficiency = entity.productionEfficiency;

View file

@ -86,7 +86,7 @@ public class PowerTestFixture{
Reflect.set(Tile.class, tile, "floor", Blocks.sand);
// Simulate the "changed" method. Calling it through reflections would require half the game to be initialized.
tile.build = block.newEntity().init(tile, Team.sharded, false);
tile.build = block.newEntity().init(tile, Team.sharded, false, 0);
if(block.hasPower){
tile.build.power.graph = new PowerGraph(){
//assume there's always something consuming power