diff --git a/core/src/mindustry/content/Blocks.java b/core/src/mindustry/content/Blocks.java index f2f2a85397..b27e8f7bac 100644 --- a/core/src/mindustry/content/Blocks.java +++ b/core/src/mindustry/content/Blocks.java @@ -106,16 +106,6 @@ 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++){ - int fx = dx - BlockPart.maxSize/2, fy = dy - BlockPart.maxSize/2; - if(fx != 0 || fy != 0){ - new BlockPart(fx, fy); - } - } - } - spawn = new OverlayFloor("spawn"){ { variants = 0; diff --git a/core/src/mindustry/core/World.java b/core/src/mindustry/core/World.java index 8c73372da5..801ee0ae26 100644 --- a/core/src/mindustry/core/World.java +++ b/core/src/mindustry/core/World.java @@ -19,7 +19,6 @@ import mindustry.maps.filters.*; import mindustry.maps.filters.GenerateFilter.*; import mindustry.type.*; import mindustry.world.*; -import mindustry.world.blocks.*; import static mindustry.Vars.*; @@ -84,19 +83,36 @@ public class World{ return height()*tilesize; } - public @Nullable - Tile tile(int pos){ - return tiles == null ? null : tile(Point2.x(pos), Point2.y(pos)); + @Nullable + public Tile tile(int pos){ + return tile(Point2.x(pos), Point2.y(pos)); } - public @Nullable Tile tile(int x, int y){ + @Nullable + public Tile tile(int x, int y){ return tiles.get(x, y); } - public @Nullable Tile ltile(int x, int y){ + @Nullable + public Tile tilec(int x, int y){ + Tile tile = tiles.get(x, y); + if(tile == null) return null; + if(tile.entity != null) return tile.entity.tile(); + return tile; + } + + @Nullable + public Tilec ent(int x, int y){ Tile tile = tile(x, y); if(tile == null) return null; - return tile.block().linked(tile); + return tile.entity; + } + + @Nullable + public Tilec ent(int pos){ + Tile tile = tile(pos); + if(tile == null) return null; + return tile.entity; } @NonNull @@ -104,12 +120,14 @@ public class World{ return tiles.getn(x, y); } - public @Nullable Tile tileWorld(float x, float y){ + @Nullable + public Tile tileWorld(float x, float y){ 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)); + @Nullable + public Tilec entWorld(float x, float y){ + return ent(Math.round(x / tilesize), Math.round(y / tilesize)); } public int toTile(float coord){ @@ -384,6 +402,8 @@ public class World{ */ public void prepareTiles(Tiles tiles){ + //TODO FIX + /* //find multiblocks IntArray multiblocks = new IntArray(); for(Tile tile : tiles){ @@ -418,7 +438,7 @@ public class World{ } } } - } + }*/ } public interface Raycaster{ diff --git a/core/src/mindustry/editor/MapEditor.java b/core/src/mindustry/editor/MapEditor.java index 64a60cbd58..245ee60a3e 100644 --- a/core/src/mindustry/editor/MapEditor.java +++ b/core/src/mindustry/editor/MapEditor.java @@ -13,7 +13,6 @@ import mindustry.gen.TileOp; import mindustry.io.MapIO; import mindustry.maps.Map; import mindustry.world.*; -import mindustry.world.blocks.BlockPart; import static mindustry.Vars.*; @@ -83,7 +82,7 @@ public class MapEditor{ //re-add them for(Tile tile : tiles){ if(tile.block().isMultiblock()){ - tile.set(tile.block(), tile.team()); + tile.setBlock(tile.block(), tile.team(), 0); } } @@ -173,7 +172,7 @@ public class MapEditor{ } } - tile(x, y).set(drawBlock, drawTeam); + tile(x, y).setBlock(drawBlock, drawTeam, 0); }else{ boolean isFloor = drawBlock.isFloor() && drawBlock != Blocks.air; diff --git a/core/src/mindustry/editor/MapRenderer.java b/core/src/mindustry/editor/MapRenderer.java index 07ef0c1c5c..fc1559f5de 100644 --- a/core/src/mindustry/editor/MapRenderer.java +++ b/core/src/mindustry/editor/MapRenderer.java @@ -15,7 +15,6 @@ import mindustry.game.Team; import mindustry.graphics.IndexedRenderer; import mindustry.world.Block; import mindustry.world.Tile; -import mindustry.world.blocks.BlockPart; import static mindustry.Vars.tilesize; diff --git a/core/src/mindustry/entities/Damage.java b/core/src/mindustry/entities/Damage.java index 931cbd762d..0939437258 100644 --- a/core/src/mindustry/entities/Damage.java +++ b/core/src/mindustry/entities/Damage.java @@ -83,11 +83,11 @@ public class Damage{ collidedBlocks.clear(); tr.trns(angle, length); Intc2 collider = (cx, cy) -> { - Tile tile = world.ltile(cx, cy); - if(tile != null && !collidedBlocks.contains(tile.pos()) && tile.entity != null && tile.getTeamID() != team.id && tile.entity.collide(hitter)){ - tile.entity.collision(hitter); + Tilec tile = world.ent(cx, cy); + if(tile != null && !collidedBlocks.contains(tile.pos()) && tile.entity != null && tile.team() != team && tile.collide(hitter)){ + tile.collision(hitter); collidedBlocks.add(tile.pos()); - hitter.type().hit(hitter, tile.worldx(), tile.worldy()); + hitter.type().hit(hitter, tile.x(), tile.y()); } }; @@ -227,15 +227,15 @@ public class Damage{ int scaledDamage = (int)(damage * (1f - (float)dst / radius)); bits.set(bitOffset + x, bitOffset + y); - Tile tile = world.ltile(startx + x, starty + y); + Tilec tile = world.ent(startx + x, starty + y); if(scaledDamage <= 0 || tile == null) continue; //apply damage to entity if needed - if(tile.entity != null && tile.team() != team){ - int health = (int)tile.entity.health(); - if(tile.entity.health() > 0){ - tile.entity.damage(scaledDamage); + if(tile.team() != team){ + int health = (int)tile.health(); + if(tile.health() > 0){ + tile.damage(scaledDamage); scaledDamage -= health; if(scaledDamage <= 0) continue; diff --git a/core/src/mindustry/entities/Lightning.java b/core/src/mindustry/entities/Lightning.java index df9cdd9b61..9422f1008d 100644 --- a/core/src/mindustry/entities/Lightning.java +++ b/core/src/mindustry/entities/Lightning.java @@ -46,7 +46,7 @@ public class Lightning{ Vec2 to = lines.get(lines.size - 1); world.raycastEach(world.toTile(from.getX()), world.toTile(from.getY()), world.toTile(to.getX()), world.toTile(to.getY()), (wx, wy) -> { - Tile tile = world.ltile(wx, wy); + Tile tile = world.tile(wx, wy); if(tile != null && tile.block().insulated){ bhit = true; //snap it instead of removing diff --git a/core/src/mindustry/entities/Units.java b/core/src/mindustry/entities/Units.java index e2bd6619e3..8f827b5e19 100644 --- a/core/src/mindustry/entities/Units.java +++ b/core/src/mindustry/entities/Units.java @@ -16,7 +16,7 @@ public class Units{ private static boolean boolResult; /** @return whether this player can interact with a specific tile. if either of these are null, returns true.*/ - public static boolean canInteract(Playerc player, Tile tile){ + public static boolean canInteract(Playerc player, Tilec tile){ return player == null || tile == null || tile.interactable(player.team()); } diff --git a/core/src/mindustry/entities/bullet/BulletType.java b/core/src/mindustry/entities/bullet/BulletType.java index 55bec8e773..0f97ff686c 100644 --- a/core/src/mindustry/entities/bullet/BulletType.java +++ b/core/src/mindustry/entities/bullet/BulletType.java @@ -12,7 +12,6 @@ import mindustry.game.*; import mindustry.gen.*; import mindustry.graphics.*; import mindustry.type.*; -import mindustry.world.*; public abstract class BulletType extends Content{ public float lifetime; @@ -97,11 +96,11 @@ public abstract class BulletType extends Content{ return speed * lifetime * (1f - drag); } - public boolean collides(Bulletc bullet, Tile tile){ + public boolean collides(Bulletc bullet, Tilec tile){ return true; } - public void hitTile(Bulletc b, Tile tile){ + public void hitTile(Bulletc b, Tilec tile){ hit(b); } diff --git a/core/src/mindustry/entities/bullet/HealBulletType.java b/core/src/mindustry/entities/bullet/HealBulletType.java index 64f65fc1a5..cbd33ac951 100644 --- a/core/src/mindustry/entities/bullet/HealBulletType.java +++ b/core/src/mindustry/entities/bullet/HealBulletType.java @@ -5,7 +5,6 @@ import arc.graphics.g2d.*; import mindustry.content.*; import mindustry.gen.*; import mindustry.graphics.*; -import mindustry.world.*; import mindustry.world.blocks.*; public class HealBulletType extends BulletType{ @@ -28,8 +27,8 @@ public class HealBulletType extends BulletType{ } @Override - public boolean collides(Bulletc b, Tile tile){ - return tile.team() != b.team() || tile.entity.healthf() < 1f; + public boolean collides(Bulletc b, Tilec tile){ + return tile.team() != b.team() || tile.healthf() < 1f; } @Override @@ -43,13 +42,12 @@ public class HealBulletType extends BulletType{ } @Override - public void hitTile(Bulletc b, Tile tile){ + public void hitTile(Bulletc b, Tilec tile){ super.hit(b); - tile = tile.link(); - if(tile.entity != null && tile.team() == b.team() && !(tile.block() instanceof BuildBlock)){ - Fx.healBlockFull.at(tile.drawx(), tile.drawy(), tile.block().size, Pal.heal); - tile.entity.heal(healPercent / 100f * tile.entity.maxHealth()); + if(tile.team() == b.team() && !(tile.block() instanceof BuildBlock)){ + Fx.healBlockFull.at(tile.x(), tile.y(), tile.block().size, Pal.heal); + tile.heal(healPercent / 100f * tile.maxHealth()); } } } diff --git a/core/src/mindustry/entities/def/BulletComp.java b/core/src/mindustry/entities/def/BulletComp.java index 3c2e4a346c..6a24ab61c2 100644 --- a/core/src/mindustry/entities/def/BulletComp.java +++ b/core/src/mindustry/entities/def/BulletComp.java @@ -6,7 +6,6 @@ import mindustry.annotations.Annotations.*; import mindustry.entities.bullet.*; import mindustry.gen.*; import mindustry.graphics.*; -import mindustry.world.*; import static mindustry.Vars.*; @@ -90,12 +89,12 @@ abstract class BulletComp implements Timedc, Damagec, Hitboxc, Teamc, Posc, Draw if(type.hitTiles){ world.raycastEach(world.toTile(lastX()), world.toTile(lastY()), tileX(), tileY(), (x, y) -> { - Tile tile = world.ltile(x, y); + Tilec tile = world.ent(x, y); if(tile == null) return false; - if(tile.entity != null && tile.entity.collide(this) && type.collides(this, tile) && !tile.entity.dead() && (type.collidesTeam || tile.team() != team())){ + if(tile.collide(this) && type.collides(this, tile) && !tile.dead() && (type.collidesTeam || tile.team() != team())){ if(tile.team() != team()){ - tile.entity.collision(this); + tile.collision(this); } type.hitTile(this, tile); diff --git a/core/src/mindustry/entities/def/FireComp.java b/core/src/mindustry/entities/def/FireComp.java index d417e6f4b1..6e431e05ee 100644 --- a/core/src/mindustry/entities/def/FireComp.java +++ b/core/src/mindustry/entities/def/FireComp.java @@ -49,7 +49,7 @@ abstract class FireComp implements Timedc, Posc, Firec{ return; } - Tilec entity = tile.link().entity; + Tilec entity = tile.entity; boolean damage = entity != null; float flammability = baseFlammability + puddleFlammability; diff --git a/core/src/mindustry/entities/def/MinerComp.java b/core/src/mindustry/entities/def/MinerComp.java index de0a8601b9..66918677ae 100644 --- a/core/src/mindustry/entities/def/MinerComp.java +++ b/core/src/mindustry/entities/def/MinerComp.java @@ -38,7 +38,7 @@ abstract class MinerComp implements Itemsc, Posc, Teamc, Rotc, DrawLayerGroundc{ Tilec core = closestCore(); if(core != null && mineTile != null && mineTile.drop() != null && !acceptsItem(mineTile.drop()) && dst(core) < mineTransferRange){ - int accepted = core.tile().block().acceptStack(item(), stack().amount, core.tile(), this); + int accepted = core.tile().block().acceptStack(core.tile(), item(), stack().amount, this); if(accepted > 0){ Call.transferItemTo(item(), accepted, mineTile.worldx() + Mathf.range(tilesize / 2f), @@ -60,7 +60,7 @@ abstract class MinerComp implements Itemsc, Posc, Teamc, Rotc, DrawLayerGroundc{ if(mineTimer >= 50f + item.hardness*10f){ mineTimer = 0; - if(dst(core) < mineTransferRange && core.tile().block().acceptStack(item, 1, core.tile(), this) == 1 && offloadImmediately()){ + if(dst(core) < mineTransferRange && core.tile().block().acceptStack(core.tile(), item, 1, this) == 1 && offloadImmediately()){ Call.transferItemTo(item, 1, mineTile.worldx() + Mathf.range(tilesize / 2f), mineTile.worldy() + Mathf.range(tilesize / 2f), core.tile()); diff --git a/core/src/mindustry/entities/def/TileComp.java b/core/src/mindustry/entities/def/TileComp.java index bceccf9f56..d8f347c7d9 100644 --- a/core/src/mindustry/entities/def/TileComp.java +++ b/core/src/mindustry/entities/def/TileComp.java @@ -1,7 +1,12 @@ package mindustry.entities.def; import arc.*; +import arc.Graphics.*; +import arc.Graphics.Cursor.*; +import arc.func.*; +import arc.graphics.g2d.*; import arc.math.geom.*; +import arc.scene.ui.layout.*; import arc.struct.*; import arc.util.ArcAnnotate.*; import arc.util.*; @@ -10,8 +15,12 @@ import mindustry.annotations.Annotations.*; import mindustry.game.EventType.*; import mindustry.game.*; import mindustry.gen.*; +import mindustry.graphics.*; +import mindustry.ui.*; import mindustry.world.*; +import mindustry.world.blocks.*; import mindustry.world.consumers.*; +import mindustry.world.meta.*; import mindustry.world.modules.*; import static mindustry.Vars.*; @@ -19,13 +28,14 @@ import static mindustry.Vars.*; @EntityDef(value = {Tilec.class}, isFinal = false, genio = false, serialize = false) @Component abstract class TileComp implements Posc, Teamc, Healthc, Tilec, Timerc{ + //region vars and initialization static final float timeToSleep = 60f * 1; - static final ObjectSet tmpTiles = new ObjectSet<>(); + static final ObjectSet tmpTiles = new ObjectSet<>(); static int sleepingEntities = 0; transient Tile tile; transient Block block; - transient Array proximity = new Array<>(8); + transient Array proximity = new Array<>(8); PowerModule power; ItemModule items; @@ -40,7 +50,6 @@ abstract class TileComp implements Posc, Teamc, Healthc, Tilec, Timerc{ private transient float sleepTime; /** Sets this tile entity data to this tile, and adds it if necessary. */ - @Override public Tilec init(Tile tile, boolean shouldAdd){ this.tile = tile; this.block = tile.block(); @@ -61,6 +70,9 @@ abstract class TileComp implements Posc, Teamc, Healthc, Tilec, Timerc{ return this; } + //endregion + //region io + public final void writeBase(Writes write){ write.f(health()); write.b(tile.rotation()); @@ -92,52 +104,66 @@ abstract class TileComp implements Posc, Teamc, Healthc, Tilec, Timerc{ } @CallSuper - @Override public void write(Writes write){ //overriden by subclasses! } @CallSuper - @Override public void read(Reads read, byte revision){ //overriden by subclasses! } - @Override + //endregion + //region utility methods + public void applyBoost(float intensity, float duration){ timeScale = Math.max(timeScale, intensity); timeScaleDuration = Math.max(timeScaleDuration, duration); } - @Override + public int pos(){ + return tile.pos(); + } + + public int rotation(){ + return tile.rotation(); + } + + public void rotation(int rotation){ + tile.rotation(rotation); + } + + public Floor floor(){ + return tile.floor(); + } + + public boolean interactable(Team team){ + return state.teams.canInteract(team, team()); + } + public float timeScale(){ return timeScale; } - @Override public boolean consValid(){ return cons.valid(); } - @Override public void consume(){ cons.trigger(); } /** Scaled delta. */ - @Override public float delta(){ return Time.delta() * timeScale; } /** Base efficiency. If this entity has non-buffered power, returns the power %, otherwise returns 1. */ - @Override public float efficiency(){ return power != null && (block.consumes.has(ConsumeType.power) && !block.consumes.getPower().buffered) ? power.status : 1f; } /** Call when nothing is happening to the entity. This increments the internal sleep timer. */ - @Override public void sleep(){ sleepTime += Time.delta(); if(!sleeping && sleepTime >= timeToSleep){ @@ -148,7 +174,6 @@ abstract class TileComp implements Posc, Teamc, Healthc, Tilec, Timerc{ } /** Call when this entity is updating. This wakes it up. */ - @Override public void noSleep(){ sleepTime = 0f; if(sleeping){ @@ -159,82 +184,718 @@ abstract class TileComp implements Posc, Teamc, Healthc, Tilec, Timerc{ } /** Returns the version of this TileEntity IO code.*/ - @Override public byte version(){ return 0; } - @Override - public boolean collide(Bulletc other){ + //endregion + //region handler methods + + + public boolean shouldConsume(Tilec tile){ return true; } - @Override - public void collision(Bulletc other){ - block.handleBulletHit(this, other); + public boolean productionValid(Tilec tile){ + return true; } - //TODO Implement damage! + public float getPowerProduction(Tilec tile){ + return 0f; + } - @Override - public void removeFromProximity(){ - block.onProximityRemoved(tile); + /** Returns the amount of items this block can accept. */ + public int acceptStack(Tilec tile, Item item, int amount, Teamc source){ + if(acceptItem(tile, tile, item) && hasItems && (source == null || source.team() == tile.team())){ + return Math.min(getMaximumAccepted(tile, item) - tile.items().get(item), amount); + }else{ + return 0; + } + } - Point2[] nearby = Edges.getEdges(block.size); - for(Point2 point : nearby){ - 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.block().onProximityUpdate(other); + public int getMaximumAccepted(Tilec tile, Item item){ + return itemCapacity; + } - if(other.entity != null){ - other.entity.proximity().remove(tile, true); + /** Remove a stack from this inventory, and return the amount removed. */ + public int removeStack(Tilec tile, Item item, int amount){ + if(tile.entity == null || tile.items() == null) return 0; + amount = Math.min(amount, tile.items().get(item)); + tile.noSleep(); + tile.items().remove(item, amount); + return amount; + } + + /** Handle a stack input. */ + public void handleStack(Tilec tile, Item item, int amount, Teamc source){ + tile.noSleep(); + tile.items().add(item, amount); + } + + public boolean outputsItems(){ + return hasItems; + } + + /** Returns offset for stack placement. */ + public void getStackOffset(Tilec tile, Item item, Vec2 trns){ + + } + + public void onProximityUpdate(Tilec tile){ + tile.noSleep(); + } + + public void handleItem(Tilec tile, Tilec source, Item item){ + tile.items().add(item, 1); + } + + public boolean acceptItem(Tilec tile, Tilec source, Item item){ + return consumes.itemFilters.get(item.id) && tile.items().get(item) < getMaximumAccepted(tile, item); + } + + public boolean acceptLiquid(Tilec tile, Tilec source, Liquid liquid, float amount){ + return hasLiquids && tile.liquids().get(liquid) + amount < liquidCapacity && consumes.liquidfilters.get(liquid.id); + } + + public void handleLiquid(Tilec tile, Tilec source, Liquid liquid, float amount){ + tile.liquids().add(liquid, amount); + } + + public void tryDumpLiquid(Tilec tile, Liquid liquid){ + Array proximity = tile.proximity(); + int dump = tile.rotation(); + + for(int i = 0; i < proximity.size; i++){ + incrementDump(tile, proximity.size); + Tilec other = proximity.get((i + dump) % proximity.size); + //TODO fix, this is incorrect + Tilec in = Edges.getFacingEdge(tile.tile(), other.tile()).entity; + + other = other.block().getLiquidDestination(other, in, liquid); + + if(other != null && other.team() == tile.team() && other.block().hasLiquids && canDumpLiquid(tile, other, liquid) && other.liquids() != null){ + float ofract = other.liquids().get(liquid) / other.block().liquidCapacity; + float fract = tile.liquids().get(liquid) / liquidCapacity; + + if(ofract < fract) tryMoveLiquid(tile, in, other, (fract - ofract) * liquidCapacity / 2f, liquid); + } + } + + } + + public boolean canDumpLiquid(Tilec tile, Tilec to, Liquid liquid){ + return true; + } + + public void tryMoveLiquid(Tilec tile, Tilec tileSource, Tilec next, float amount, Liquid liquid){ + float flow = Math.min(next.block().liquidCapacity - next.liquids().get(liquid) - 0.001f, amount); + + if(next.block().acceptLiquid(next, tileSource, liquid, flow)){ + next.block().handleLiquid(next, tileSource, liquid, flow); + tile.liquids().remove(liquid, flow); + } + } + + public float tryMoveLiquid(Tilec tile, Tilec next, boolean leak, Liquid liquid){ + return tryMoveLiquid(tile, next, leak ? 1.5f : 100, liquid); + } + + public float tryMoveLiquid(Tilec tile, Tilec next, float leakResistance, Liquid liquid){ + if(next == null) return 0; + + next = next.block().getLiquidDestination(next, tile, liquid); + + if(next.team() == tile.team() && next.block().hasLiquids && tile.liquids().get(liquid) > 0f){ + + if(next.block().acceptLiquid(next, tile, liquid, 0f)){ + float ofract = next.liquids().get(liquid) / next.block().liquidCapacity; + float fract = tile.liquids().get(liquid) / liquidCapacity * liquidPressure; + float flow = Math.min(Mathf.clamp((fract - ofract) * (1f)) * (liquidCapacity), tile.liquids().get(liquid)); + flow = Math.min(flow, next.block().liquidCapacity - next.liquids().get(liquid) - 0.001f); + + if(flow > 0f && ofract <= fract && next.block().acceptLiquid(next, tile, liquid, flow)){ + next.block().handleLiquid(next, tile, liquid, flow); + tile.liquids().remove(liquid, flow); + return flow; + }else if(ofract > 0.1f && fract > 0.1f){ + //TODO these are incorrect effect positions + float fx = (tile.x() + next.x()) / 2f, fy = (tile.y() + next.y()) / 2f; + + Liquid other = next.liquids().current(); + if((other.flammability > 0.3f && liquid.temperature > 0.7f) || (liquid.flammability > 0.3f && other.temperature > 0.7f)){ + tile.damage(1 * Time.delta()); + next.damage(1 * Time.delta()); + if(Mathf.chance(0.1 * Time.delta())){ + Fx.fire.at(fx, fy); + } + }else if((liquid.temperature > 0.7f && other.temperature < 0.55f) || (other.temperature > 0.7f && liquid.temperature < 0.55f)){ + tile.liquids().remove(liquid, Math.min(tile.liquids().get(liquid), 0.7f * Time.delta())); + if(Mathf.chance(0.2f * Time.delta())){ + Fx.steam.at(fx, fy); + } + } + } + } + }else if(leakResistance != 100f && !next.block().solid && !next.block().hasLiquids){ + float leakAmount = tile.liquids().get(liquid) / leakResistance; + Puddles.deposit(next.tile(), tile.tile(), liquid, leakAmount); + tile.liquids().remove(liquid, leakAmount); + } + return 0; + } + + public Tilec getLiquidDestination(Tilec tile, Tilec from, Liquid liquid){ + return tile; + } + + /** + * Tries to put this item into a nearby container, if there are no available + * containers, it gets added to the block's inventory. + */ + public void offloadNear(Tilec tile, Item item){ + Array proximity = tile.proximity(); + int dump = tile.rotation(); + + for(int i = 0; i < proximity.size; i++){ + incrementDump(tile, proximity.size); + Tilec other = proximity.get((i + dump) % proximity.size); + //TODO fix position + Tilec in = Edges.getFacingEdge(tile.tile(), other.tile()).entity; + if(other.team() == tile.team() && other.block().acceptItem(other, in, item) && canDump(tile, other, item)){ + other.block().handleItem(other, in, item); + return; + } + } + + handleItem(tile, tile, item); + } + + /** Try dumping any item near the tile. */ + public boolean tryDump(Tilec tile){ + return tryDump(tile, null); + } + + /** + * Try dumping a specific item near the tile. + * @param todump Item to dump. Can be null to dump anything. + */ + public boolean tryDump(Tilec entity, Item todump){ + if(entity == null || !hasItems || entity.items().total() == 0 || (todump != null && !entity.items().has(todump))) + return false; + + Array proximity = entity.proximity(); + int dump = entity.rotation(); + + if(proximity.size == 0) return false; + + for(int i = 0; i < proximity.size; i++){ + Tilec other = proximity.get((i + dump) % proximity.size); + //TODO fix position + Tilec in = Edges.getFacingEdge(entity.tile(), other.tile()).entity; + + if(todump == null){ + + for(int ii = 0; ii < content.items().size; ii++){ + Item item = content.item(ii); + + if(other.team() == entity.team() && entity.items().has(item) && other.block().acceptItem(other, in, item) && canDump(entity, other, item)){ + other.block().handleItem(other, in, item); + entity.items().remove(item, 1); + incrementDump(entity, proximity.size); + return true; + } + } + }else{ + if(other.team() == entity.team() && other.block().acceptItem(other, in, todump) && canDump(entity, other, todump)){ + other.block().handleItem(other, in, todump); + entity.items().remove(todump, 1); + incrementDump(entity, proximity.size); + return true; + } + } + + incrementDump(entity, proximity.size); + } + + return false; + } + + protected void incrementDump(Tilec tile, int prox){ + tile.rotation((byte)((tile.rotation() + 1) % prox)); + } + + /** Used for dumping items. */ + public boolean canDump(Tilec tile, Tilec to, Item item){ + return true; + } + + /** Try offloading an item to a nearby container in its facing direction. Returns true if success. */ + public boolean offloadDir(Tilec tile, Item item){ + Tilec other = tile.tile().front(); + if(other != null && other.team() == tile.team() && other.block().acceptItem(other, tile, item)){ + other.block().handleItem(other, tile, item); + return true; + } + return false; + } + + public boolean canBreak(Tile tile){ + return true; + } + + public void onProximityRemoved(Tilec tile){ + if(tile.power() != null){ + tile.block().powerGraphRemoved(tile); + } + } + + public void onProximityAdded(Tilec tile){ + if(tile.block().hasPower) tile.block().updatePowerGraph(tile); + } + + protected void updatePowerGraph(Tilec tile){ + + for(Tilec other : getPowerConnections(tile, tempTileEnts)){ + if(other.power() != null){ + other.power().graph.add(tile.power().graph); + } + } + } + + protected void powerGraphRemoved(Tilec tile){ + if(tile.entity == null || tile.power() == null){ + return; + } + + tile.power().graph.remove(tile); + for(int i = 0; i < tile.power().links.size; i++){ + Tile other = world.tile(tile.power().links.get(i)); + if(other != null && other.entity != null && other.entity.power() != null){ + other.entity.power().links.removeValue(tile.pos()); + } + } + } + + public Array getPowerConnections(Tilec tile, Array out){ + out.clear(); + if(tile == null || tile.entity == null || tile.power() == null) return out; + + for(Tilec other : tile.proximity()){ + if(other != null && other.entity != null && other.power() != null + && !(consumesPower && other.block().consumesPower && !outputsPower && !other.block().outputsPower) + && !tile.power().links.contains(other.pos())){ + out.add(other); + } + } + + for(int i = 0; i < tile.power().links.size; i++){ + Tile link = world.tile(tile.power().links.get(i)); + if(link != null && link.entity != null && link.entity.power() != null) out.add(link.entity); + } + return out; + } + + protected float getProgressIncrease(Tilec entity, float baseTime){ + return 1f / baseTime * entity.delta() * entity.efficiency(); + } + + /** @return whether this block should play its active sound.*/ + public boolean shouldActiveSound(Tilec tile){ + return false; + } + + /** @return whether this block should play its idle sound.*/ + public boolean shouldIdleSound(Tilec tile){ + return shouldConsume(tile); + } + + public void drawLayer(Tilec tile){ + } + + public void drawLayer2(Tilec tile){ + } + + public void drawCracks(Tilec tile){ + if(!tile.damaged() || size > maxCrackSize) return; + int id = tile.pos(); + TextureRegion region = cracks[size - 1][Mathf.clamp((int)((1f - tile.healthf()) * crackRegions), 0, crackRegions-1)]; + Draw.colorl(0.2f, 0.1f + (1f - tile.healthf())* 0.6f); + Draw.rect(region, tile.x(), tile.y(), (id%4)*90); + Draw.color(); + } + + /** Draw the block overlay that is shown when a cursor is over the block. */ + public void drawSelect(Tilec tile){ + } + + /** Drawn when you are placing a block. */ + public void drawPlace(int x, int y, int rotation, boolean valid){ + } + + public float drawPlaceText(String text, int x, int y, boolean valid){ + if(renderer.pixelator.enabled()) return 0; + + Color color = valid ? Pal.accent : Pal.remove; + BitmapFont font = Fonts.outline; + GlyphLayout layout = Pools.obtain(GlyphLayout.class, GlyphLayout::new); + boolean ints = font.usesIntegerPositions(); + font.setUseIntegerPositions(false); + font.getData().setScale(1f / 4f / Scl.scl(1f)); + layout.setText(font, text); + + float width = layout.width; + + font.setColor(color); + float dx = x * tilesize + offset(), dy = y * tilesize + offset() + size * tilesize / 2f + 3; + font.draw(text, dx, dy + layout.height + 1, Align.center); + dy -= 1f; + Lines.stroke(2f, Color.darkGray); + Lines.line(dx - layout.width / 2f - 2f, dy, dx + layout.width / 2f + 1.5f, dy); + Lines.stroke(1f, color); + Lines.line(dx - layout.width / 2f - 2f, dy, dx + layout.width / 2f + 1.5f, dy); + + font.setUseIntegerPositions(ints); + font.setColor(Color.white); + font.getData().setScale(1f); + Draw.reset(); + Pools.free(layout); + return width; + } + + public void draw(Tilec tile){ + Draw.rect(region, tile.x(), tile.y(), rotate ? tile.rotation() * 90 : 0); + } + + public void drawLight(Tilec tile){ + if(tile.entity != null && hasLiquids && drawLiquidLight && tile.liquids().current().lightColor.a > 0.001f){ + drawLiquidLight(tile, tile.liquids().current(), tile.liquids().smoothAmount()); + } + } + + public void drawLiquidLight(Tilec tile, Liquid liquid, float amount){ + if(amount > 0.01f){ + Color color = liquid.lightColor; + float fract = 1f; + float opacity = color.a * fract; + if(opacity > 0.001f){ + renderer.lights.add(tile.x(), tile.y(), size * 30f * fract, color, opacity); + } + } + } + + public void drawTeam(Tilec tile){ + Draw.color(tile.team().color); + Draw.rect("block-border", tile.x() - size * tilesize / 2f + 4, tile.y() - size * tilesize / 2f + 4); + Draw.color(); + } + + /** Called after the block is placed by this client. */ + @CallSuper + public void playerPlaced(Tilec tile){ + + } + + /** Called after the block is placed by anyone. */ + @CallSuper + public void placed(Tilec tile){ + if(net.client()) return; + + if((consumesPower && !outputsPower) || (!consumesPower && outputsPower)){ + int range = 10; + tempTiles.clear(); + Geometry.circle(tile.tileX(), tile.tileY(), range, (x, y) -> { + Tilec other = world.ent(x, y); + if(other != null && other.block() instanceof PowerNode && ((PowerNode)other.block()).linkValid(other, tile) && !PowerNode.insulated(other, tile) && !other.proximity().contains(tile) && + !(outputsPower && tile.proximity().contains(p -> p.entity != null && p.power() != null && p.power().graph == other.power().graph))){ + tempTiles.add(other.tile()); + } + }); + tempTiles.sort(Structs.comparingFloat(t -> t.dst2(tile))); + if(!tempTiles.isEmpty()){ + Tile toLink = tempTiles.first(); + if(!toLink.entity.power().links.contains(tile.pos())){ + toLink.configureAny(tile.pos()); } } } } - @Override + public void removed(Tilec tile){ + } + + /** Called every frame a unit is on this tile. */ + public void unitOn(Tilec tile, Unitc unit){ + } + + /** Called when a unit that spawned at this tile is removed. */ + public void unitRemoved(Tilec tile, Unitc unit){ + } + + /** Returns whether ot not this block can be place on the specified tile. */ + public boolean canPlaceOn(Tile tile){ + return true; + } + + /** Call when some content is produced. This unlocks the content if it is applicable. */ + public void useContent(Tilec tile, UnlockableContent content){ + //only unlocks content in zones + if(!headless && tile.team() == player.team() && state.isCampaign()){ + logic.handleContent(content); + } + } + + public float sumAttribute(Attribute attr, int x, int y){ + Tile tile = world.tile(x, y); + if(tile == null) return 0; + float sum = 0; + for(Tile other : tile.getLinkedTilesAs(this, tempTiles)){ + sum += other.floor().attributes.get(attr); + } + return sum; + } + + public float percentSolid(int x, int y){ + Tile tile = world.tile(x, y); + if(tile == null) return 0; + float sum = 0; + for(Tile other : tile.getLinkedTilesAs(this, tempTiles)){ + sum += !other.floor.isLiquid ? 1f : 0f; + } + return sum / size / size; + } + + /** Called when the block is tapped. This is equivalent to being configured with null. */ + public void tapped(Tilec tile, Playerc player){ + + } + + /** Called when the block is destroyed. */ + public void onDestroyed(Tilec tile){ + float x = tile.x(), y = tile.y(); + float explosiveness = baseExplosiveness; + float flammability = 0f; + float power = 0f; + + if(hasItems){ + for(Item item : content.items()){ + int amount = tile.items().get(item); + explosiveness += item.explosiveness * amount; + flammability += item.flammability * amount; + } + } + + if(hasLiquids){ + flammability += tile.liquids().sum((liquid, amount) -> liquid.explosiveness * amount / 2f); + explosiveness += tile.liquids().sum((liquid, amount) -> liquid.flammability * amount / 2f); + } + + if(consumes.hasPower() && consumes.getPower().buffered){ + power += tile.power().status * consumes.getPower().capacity; + } + + if(hasLiquids){ + + tile.liquids().each((liquid, amount) -> { + float splash = Mathf.clamp(amount / 4f, 0f, 10f); + + for(int i = 0; i < Mathf.clamp(amount / 5, 0, 30); i++){ + Time.run(i / 2f, () -> { + Tile other = world.tile(tile.tileX() + Mathf.range(size / 2), tile.tileY() + Mathf.range(size / 2)); + if(other != null){ + Puddles.deposit(other, liquid, splash); + } + }); + } + }); + } + + Damage.dynamicExplosion(x, y, flammability, explosiveness * 3.5f, power, tilesize * size / 2f, Pal.darkFlame); + if(!tile.floor().solid && !tile.floor().isLiquid){ + Effects.rubble(tile.x(), tile.y(), size); + } + } + + /** + * Returns the flammability of the tile. Used for fire calculations. + * Takes flammability of floor liquid into account. + */ + public float getFlammability(Tilec tile){ + if(!hasItems || tile.entity == null){ + if(tile.floor().isLiquid && !solid){ + return tile.floor().liquidDrop.flammability; + } + return 0; + }else{ + float result = tile.items().sum((item, amount) -> item.flammability * amount); + + if(hasLiquids){ + result += tile.liquids().sum((liquid, amount) -> liquid.flammability * amount / 3f); + } + + return result; + } + } + + public String getDisplayName(Tilec tile){ + return block.localizedName; + } + + public TextureRegion getDisplayIcon(Tilec tile){ + return block.icon(Cicon.medium); + } + + public void display(Tilec entity, Table table){ + + if(entity != null){ + table.table(bars -> { + bars.defaults().growX().height(18f).pad(4); + + displayBars(entity, bars); + }).growX(); + table.row(); + table.table(ctable -> { + displayConsumption(entity, ctable); + }).growX(); + + table.marginBottom(-5); + } + } + + public void displayConsumption(Tilec tile, Table table){ + table.left(); + for(Consume cons : consumes.all()){ + if(cons.isOptional() && cons.isBoost()) continue; + cons.build(tile, table); + } + } + + public void displayBars(Tilec tile, Table table){ + for(Func bar : bars.list()){ + table.add(bar.get(tile)).growX(); + table.row(); + } + } + + /** Called when this block is tapped to build a UI on the table. + * configurable must be true for this to be called.*/ + public void buildConfiguration(Tilec tile, Table table){ + } + + /** Update table alignment after configuring.*/ + public void updateTableAlign(Tilec tile, Table table){ + Vec2 pos = Core.input.mouseScreen(tile.x(), tile.y() - tile.block().size * tilesize / 2f - 1); + table.setPosition(pos.x, pos.y, Align.top); + } + + /** Returns whether or not a hand cursor should be shown over this block. */ + public Cursor getCursor(Tilec tile){ + return configurable ? SystemCursor.hand : SystemCursor.arrow; + } + + /** + * Called when another tile is tapped while this block is selected. + * Returns whether or not this block should be deselected. + */ + public boolean onConfigureTileTapped(Tilec tile, Tilec other){ + return tile != other; + } + + /** Returns whether this config menu should show when the specified player taps it. */ + public boolean shouldShowConfigure(Tilec tile, Playerc player){ + return true; + } + + /** Whether this configuration should be hidden now. Called every frame the config is open. */ + public boolean shouldHideConfigure(Tilec tile, Playerc player){ + return false; + } + + public void drawConfigure(Tilec tile){ + Draw.color(Pal.accent); + Lines.stroke(1f); + Lines.square(tile.x(), tile.y(), tile.block().size * tilesize / 2f + 1f); + Draw.reset(); + } + + public boolean isSolidFor(Tilec tile){ + return false; + } + + + public float handleDamage(Tilec tile, float amount){ + return amount; + } + + public void handleBulletHit(Tilec entity, Bulletc bullet){ + entity.damage(bullet.damage()); + } + + /** @return a custom minimap color for this tile, or 0 to use default colors. */ + public int minimapColor(Tile tile){ + return 0; + } + + public void update(Tilec tile){ + } + + public boolean collide(Bulletc other){ + return true; + } + + public void collision(Bulletc other){ + block.handleBulletHit(this, other); + } + + public void removeFromProximity(){ + block.onProximityRemoved(this); + + Point2[] nearby = Edges.getEdges(block.size); + for(Point2 point : nearby){ + Tilec other = world.ent(tile.x + point.x, tile.y + point.y); + //remove this tile from all nearby tile's proximities + if(other != null){ + other.block().onProximityUpdate(other); + other.proximity().remove(this, true); + } + } + } + public void updateProximity(){ tmpTiles.clear(); proximity.clear(); Point2[] nearby = Edges.getEdges(block.size); for(Point2 point : nearby){ - Tile other = world.ltile(tile.x + point.x, tile.y + point.y); + Tilec other = world.ent(tile.x + point.x, tile.y + point.y); - if(other == null) continue; - if(other.entity == null || !(other.interactable(tile.team()))) continue; + if(other == null || !(other.tile().interactable(tile.team()))) continue; //add this tile to proximity of nearby tiles - if(!other.entity.proximity().contains(tile, true)){ - other.entity.proximity().add(tile); + if(!other.proximity().contains(this, true)){ + other.proximity().add(this); } tmpTiles.add(other); } //using a set to prevent duplicates - for(Tile tile : tmpTiles){ + for(Tilec tile : tmpTiles){ proximity.add(tile); } - block.onProximityAdded(tile); - block.onProximityUpdate(tile); + block.onProximityAdded(this); + block.onProximityUpdate(this); - for(Tile other : tmpTiles){ + for(Tilec other : tmpTiles){ other.block().onProximityUpdate(other); } } - @Override - public Array proximity(){ - return proximity; - } + //endregion + //region overrides /** Tile configuration. Defaults to null. Used for block rebuilding. */ @Nullable - @Override public Object config(){ return null; } @@ -250,7 +911,7 @@ abstract class TileComp implements Posc, Teamc, Healthc, Tilec, Timerc{ public void killed(){ Events.fire(new BlockDestroyEvent(tile)); block.breakSound.at(tile); - block.onDestroyed(tile); + block.onDestroyed(this); tile.remove(); } @@ -262,14 +923,14 @@ abstract class TileComp implements Posc, Teamc, Healthc, Tilec, Timerc{ } if(sound != null){ - sound.update(x(), y(), block.shouldActiveSound(tile)); + sound.update(x(), y(), block.shouldActiveSound(this)); } - if(block.idleSound != Sounds.none && block.shouldIdleSound(tile)){ + if(block.idleSound != Sounds.none && block.shouldIdleSound(this)){ loops.play(block.idleSound, this, block.idleSoundVolume); } - block.update(tile); + block.update(this); if(liquids != null){ liquids.update(); @@ -283,4 +944,6 @@ abstract class TileComp implements Posc, Teamc, Healthc, Tilec, Timerc{ power.graph.update(); } } + + //endregion } diff --git a/core/src/mindustry/game/EventType.java b/core/src/mindustry/game/EventType.java index 7451cc4b88..bb51635a4e 100644 --- a/core/src/mindustry/game/EventType.java +++ b/core/src/mindustry/game/EventType.java @@ -146,12 +146,12 @@ public class EventType{ /** Called when the player withdraws items from a block. */ public static class WithdrawEvent{ - public final Tile tile; + public final Tilec tile; public final Playerc player; public final Item item; public final int amount; - public WithdrawEvent(Tile tile, Playerc player, Item item, int amount){ + public WithdrawEvent(Tilec tile, Playerc player, Item item, int amount){ this.tile = tile; this.player = player; this.item = item; @@ -161,12 +161,12 @@ public class EventType{ /** Called when a player deposits items to a block.*/ public static class DepositEvent{ - public final Tile tile; + public final Tilec tile; public final Playerc player; public final Item item; public final int amount; - public DepositEvent(Tile tile, Playerc player, Item item, int amount){ + public DepositEvent(Tilec tile, Playerc player, Item item, int amount){ this.tile = tile; this.player = player; this.item = item; @@ -176,10 +176,10 @@ public class EventType{ /** Called when the player taps a block. */ public static class TapEvent{ - public final Tile tile; + public final Tilec tile; public final Playerc player; - public TapEvent(Tile tile, Playerc player){ + public TapEvent(Tilec tile, Playerc player){ this.tile = tile; this.player = player; } @@ -187,11 +187,11 @@ public class EventType{ /** Called when the player sets a specific block. */ public static class TapConfigEvent{ - public final Tile tile; + public final Tilec tile; public final Playerc player; public final Object value; - public TapConfigEvent(Tile tile, Playerc player, Object value){ + public TapConfigEvent(Tilec tile, Playerc player, Object value){ this.tile = tile; this.player = player; this.value = value; diff --git a/core/src/mindustry/game/Schematics.java b/core/src/mindustry/game/Schematics.java index d833a50b38..f6c69e39e9 100644 --- a/core/src/mindustry/game/Schematics.java +++ b/core/src/mindustry/game/Schematics.java @@ -263,7 +263,7 @@ public class Schematics implements Loadable{ Tile tile = world.tile(st.x + ox, st.y + oy); if(tile == null) return; - tile.set(st.block, state.rules.defaultTeam); + tile.setBlock(st.block, state.rules.defaultTeam, 0); tile.rotation(st.rotation); Object config = st.config; diff --git a/core/src/mindustry/graphics/BlockRenderer.java b/core/src/mindustry/graphics/BlockRenderer.java index b4ea7e5bef..12e7685a6b 100644 --- a/core/src/mindustry/graphics/BlockRenderer.java +++ b/core/src/mindustry/graphics/BlockRenderer.java @@ -13,7 +13,6 @@ import mindustry.game.EventType.*; import mindustry.game.Teams.*; import mindustry.ui.*; import mindustry.world.*; -import mindustry.world.blocks.*; import static arc.Core.camera; import static mindustry.Vars.*; @@ -199,15 +198,14 @@ public class BlockRenderer implements Disposable{ for(int y = miny; y <= maxy; y++){ boolean expanded = (Math.abs(x - avgx) > rangex || Math.abs(y - avgy) > rangey); Tile tile = world.rawTile(x, y); - if(tile == null) continue; //how is this possible? Block block = tile.block(); - if(block != Blocks.air && block.cacheLayer == CacheLayer.normal){ + if(block != Blocks.air && tile.isCenter() && block.cacheLayer == CacheLayer.normal){ if(!expanded){ addRequest(tile, Layer.block); } - if(state.rules.lighting && tile.block().synthetic() && !(tile.block() instanceof BlockPart)){ + if(state.rules.lighting && tile.block().synthetic()){ addRequest(tile, Layer.lights); } diff --git a/core/src/mindustry/graphics/OverlayRenderer.java b/core/src/mindustry/graphics/OverlayRenderer.java index f40afc7c2e..e258727ab3 100644 --- a/core/src/mindustry/graphics/OverlayRenderer.java +++ b/core/src/mindustry/graphics/OverlayRenderer.java @@ -143,7 +143,7 @@ public class OverlayRenderer{ Draw.reset(); Tile tile = world.ltileWorld(v.x, v.y); - if(tile != null && tile.interactable(player.team()) && tile.block().acceptStack(player.unit().item(), player.unit().stack().amount, tile, player.unit()) > 0){ + if(tile != null && tile.interactable(player.team()) && tile.block().acceptStack(tile, player.unit().item(), player.unit().stack().amount, player.unit()) > 0){ Lines.stroke(3f, Pal.gray); Lines.square(tile.drawx(), tile.drawy(), tile.block().size * tilesize / 2f + 3 + Mathf.absin(Time.time(), 5f, 1f)); Lines.stroke(1f, Pal.place); diff --git a/core/src/mindustry/input/DesktopInput.java b/core/src/mindustry/input/DesktopInput.java index dab4efd267..bccbbbf417 100644 --- a/core/src/mindustry/input/DesktopInput.java +++ b/core/src/mindustry/input/DesktopInput.java @@ -229,9 +229,9 @@ public class DesktopInput extends InputHandler{ Tile cursor = tileAt(Core.input.mouseX(), Core.input.mouseY()); if(cursor != null){ - cursor = cursor.link(); - - cursorType = cursor.block().getCursor(cursor); + if(cursor.entity != null){ + cursorType = cursor.block().getCursor(cursor.entity); + } if(isPlacing() || !selectRequests.isEmpty()){ cursorType = SystemCursor.hand; @@ -249,8 +249,8 @@ public class DesktopInput extends InputHandler{ cursorType = ui.unloadCursor; } - if(cursor.interactable(player.team()) && !isPlacing() && Math.abs(Core.input.axisTap(Binding.rotate)) > 0 && Core.input.keyDown(Binding.rotateplaced) && cursor.block().rotate){ - Call.rotateBlock(player, cursor, Core.input.axisTap(Binding.rotate) > 0); + if(cursor.entity != null && cursor.interactable(player.team()) && !isPlacing() && Math.abs(Core.input.axisTap(Binding.rotate)) > 0 && Core.input.keyDown(Binding.rotateplaced) && cursor.block().rotate){ + Call.rotateBlock(player, cursor.entity, Core.input.axisTap(Binding.rotate) > 0); } } @@ -401,7 +401,7 @@ public class DesktopInput extends InputHandler{ deleting = true; }else if(selected != null){ //only begin shooting if there's no cursor event - if(!tileTapped(selected) && !tryTapPlayer(Core.input.mouseWorld().x, Core.input.mouseWorld().y) && (player.builder().requests().size == 0 || !player.builder().isBuilding()) && !droppingItem && + if(!tileTapped(selected.entity) && !tryTapPlayer(Core.input.mouseWorld().x, Core.input.mouseWorld().y) && (player.builder().requests().size == 0 || !player.builder().isBuilding()) && !droppingItem && !tryBeginMine(selected) && player.miner().mineTile() == null && !Core.scene.hasKeyboard()){ isShooting = true; } @@ -450,8 +450,8 @@ public class DesktopInput extends InputHandler{ removeSelection(selectX, selectY, cursorX, cursorY); } - if(selected != null){ - tryDropItems(selected.link(), Core.input.mouseWorld().x, Core.input.mouseWorld().y); + if(selected != null && selected.entity != null){ + tryDropItems(selected.entity, Core.input.mouseWorld().x, Core.input.mouseWorld().y); } if(sreq != null){ diff --git a/core/src/mindustry/input/InputHandler.java b/core/src/mindustry/input/InputHandler.java index 3867a51690..2b777c740c 100644 --- a/core/src/mindustry/input/InputHandler.java +++ b/core/src/mindustry/input/InputHandler.java @@ -110,22 +110,19 @@ public abstract class InputHandler implements InputProcessor, GestureListener{ } @Remote(targets = Loc.both, called = Loc.server, forward = true, unreliable = true) - public static void rotateBlock(Playerc player, Tile tile, boolean direction){ + public static void rotateBlock(Playerc player, Tilec tile, boolean direction){ if(net.server() && (!Units.canInteract(player, tile) || !netServer.admins.allowAction(player, ActionType.rotate, 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)); - - if(tile.entity != null){ - tile.entity.updateProximity(); - tile.entity.noSleep(); - } + tile.updateProximity(); + tile.noSleep(); } @Remote(targets = Loc.both, forward = true, called = Loc.server) - public static void transferInventory(Playerc player, Tile tile){ + public static void transferInventory(Playerc player, Tilec tile){ if(player == null) return; if(net.server() && (player.unit().stack().amount <= 0 || !Units.canInteract(player, tile) || !netServer.admins.allowAction(player, ActionType.depositItem, tile, action -> { @@ -139,7 +136,7 @@ public abstract class InputHandler implements InputProcessor, GestureListener{ Item item = player.unit().item(); int amount = player.unit().stack().amount; - int accepted = tile.block().acceptStack(item, amount, tile, player.unit()); + int accepted = tile.block().acceptStack(tile, item, amount, player.unit()); player.unit().stack().amount -= accepted; int sent = Mathf.clamp(accepted / 4, 1, 8); @@ -148,19 +145,19 @@ public abstract class InputHandler implements InputProcessor, GestureListener{ Core.app.post(() -> Events.fire(new DepositEvent(tile, player, item, accepted))); for(int i = 0; i < sent; i++){ - tile.block().getStackOffset(item, tile, stackTrns); + tile.block().getStackOffset(tile, item, stackTrns); createItemTransfer(item, player.x() + Angles.trnsx(player.unit().rotation() + 180f, backTrns), player.y() + Angles.trnsy(player.unit().rotation() + 180f, backTrns), - new Vec2(tile.drawx() + stackTrns.x, tile.drawy() + stackTrns.y), () -> { - if(tile.block() != block || tile.entity == null || tile.entity.items() == null) return; + new Vec2(tile.x() + stackTrns.x, tile.y() + stackTrns.y), () -> { + if(tile.block() != block || tile.entity == null || tile.items() == null) return; - tile.block().handleStack(item, accepted, tile, player.unit()); + tile.block().handleStack(tile, item, accepted, player.unit()); }); } } @Remote(targets = Loc.both, called = Loc.server, forward = true) - public static void onTileTapped(Playerc player, Tile tile){ + public static void onTileTapped(Playerc player, Tilec tile){ if(tile == null || player == null) return; if(net.server() && (!Units.canInteract(player, tile) || !netServer.admins.allowAction(player, ActionType.tapTile, tile, action -> {}))) throw new ValidateException(player, "Player cannot tap a tile."); @@ -169,7 +166,7 @@ public abstract class InputHandler implements InputProcessor, GestureListener{ } @Remote(targets = Loc.both, called = Loc.both, forward = true) - public static void onTileConfig(Playerc player, Tile tile, @Nullable Object value){ + public static void onTileConfig(Playerc player, Tilec tile, @Nullable Object value){ if(tile == null) return; if(net.server() && (!Units.canInteract(player, tile) || !netServer.admins.allowAction(player, ActionType.configure, tile, action -> action.config = value))) throw new ValidateException(player, "Player cannot configure a tile."); @@ -247,7 +244,7 @@ public abstract class InputHandler implements InputProcessor, GestureListener{ } public void drawBreaking(int x, int y){ - Tile tile = world.ltile(x, y); + Tile tile = world.tile(x, y); if(tile == null) return; Block block = tile.block(); @@ -388,7 +385,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.ltile(x, y); + Tile tile = world.tilec(x, y); if(tile == null || !validBreak(tile.x, tile.y)) continue; drawBreaking(tile.x, tile.y); @@ -497,13 +494,13 @@ 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.ltile(wx, wy); + Tile tile = world.tilec(wx, wy); if(tile == null) continue; if(!flush){ tryBreakBlock(wx, wy); - }else if(validBreak(tile.x, tile.y) && !selectRequests.contains(r -> r.tile() != null && r.tile().link() == tile)){ + }else if(validBreak(tile.x, tile.y) && !selectRequests.contains(r -> r.tile() != null && r.tile() == tile)){ selectRequests.add(new BuildRequest(tile.x, tile.y)); } } @@ -563,9 +560,8 @@ public abstract class InputHandler implements InputProcessor, GestureListener{ } /** Handles tile tap events that are not platform specific. */ - boolean tileTapped(Tile tile){ - tile = tile.link(); - + boolean tileTapped(@Nullable Tilec tile){ + if(tile == null) return false; boolean consumed = false, showedInventory = false; //check if tapped block is configurable @@ -599,7 +595,7 @@ public abstract class InputHandler implements InputProcessor, GestureListener{ if(tile.interactable(player.team()) && tile.block().consumesTap){ consumed = true; }else if(tile.interactable(player.team()) && tile.block().synthetic() && !consumed){ - if(tile.block().hasItems && tile.entity.items().total() > 0){ + if(tile.block().hasItems && tile.items().total() > 0){ frag.inv.showFor(tile); consumed = true; showedInventory = true; @@ -644,6 +640,10 @@ public abstract class InputHandler implements InputProcessor, GestureListener{ && tile.block() == Blocks.air && player.dst(tile.worldx(), tile.worldy()) <= miningRange; } + Tilec entAt(float x, float y){ + return world.ent(tileX(x), tileY(y)); + } + /** Returns the tile at the specified MOUSE coordinates. */ Tile tileAt(float x, float y){ return world.tile(tileX(x), tileY(y)); @@ -740,7 +740,7 @@ public abstract class InputHandler implements InputProcessor, GestureListener{ return droppingItem; } - public void tryDropItems(Tile tile, float x, float y){ + public void tryDropItems(Tilec tile, float x, float y){ if(!droppingItem || player.unit().stack().amount <= 0 || canTapPlayer(x, y) || state.isPaused() ){ droppingItem = false; return; @@ -750,7 +750,7 @@ public abstract class InputHandler implements InputProcessor, GestureListener{ ItemStack stack = player.unit().stack(); - if(tile.block().acceptStack(stack.item, stack.amount, tile, player.unit()) > 0 && tile.interactable(player.team()) && tile.block().hasItems && player.unit().stack().amount > 0 && tile.interactable(player.team())){ + if(tile.block().acceptStack(tile, stack.item, stack.amount, player.unit()) > 0 && tile.interactable(player.team()) && tile.block().hasItems && player.unit().stack().amount > 0 && tile.interactable(player.team())){ Call.transferInventory(player, tile); }else{ Call.dropItem(player.angleTo(x, y)); @@ -798,7 +798,9 @@ public abstract class InputHandler implements InputProcessor, GestureListener{ } public void breakBlock(int x, int y){ - Tile tile = world.ltile(x, y); + Tile tile = world.tile(x, y); + //TODO hacky + if(tile.entity != null) tile = tile.entity.tile(); player.builder().addBuild(new BuildRequest(tile.x, tile.y)); } @@ -849,7 +851,7 @@ public abstract class InputHandler implements InputProcessor, GestureListener{ //check with how many powernodes the *next* tile will overlap for(int j = 0; j < i; j++){ - if(!skip.contains(points.get(j)) && ((PowerNode)block).overlaps(world.ltile(point.x, point.y), world.ltile(points.get(j).x, points.get(j).y))){ + if(!skip.contains(points.get(j)) && ((PowerNode)block).overlaps(world.tile(point.x, point.y), world.tile(points.get(j).x, points.get(j).y))){ overlaps++; } } diff --git a/core/src/mindustry/input/MobileInput.java b/core/src/mindustry/input/MobileInput.java index 8532154b4e..d1a58d71d9 100644 --- a/core/src/mindustry/input/MobileInput.java +++ b/core/src/mindustry/input/MobileInput.java @@ -75,12 +75,11 @@ public class MobileInput extends InputHandler implements GestureListener{ player.miner().mineTile(null); target = unit; }else{ - Tile tile = world.ltileWorld(x, y); + Tilec tile = world.entWorld(x, y); - if(tile != null && tile.synthetic() && player.team().isEnemy(tile.team())){ - Tilec entity = tile.entity; + if(tile != null && player.team().isEnemy(tile.team())){ player.miner().mineTile(null); - target = entity; + target = tile; //TODO implement healing }//else if(tile != null && player.unit().canHeal && tile.entity != null && tile.team() == player.team() && tile.entity.damaged()){ /// player.miner().mineTile(null); @@ -505,9 +504,9 @@ public class MobileInput extends InputHandler implements GestureListener{ }else{ Tile tile = tileAt(screenX, screenY); - if(tile == null) return false; + if(tile == null || tile.entity == null) return false; - tryDropItems(tile.link(), Core.input.mouseWorld(screenX, screenY).x, Core.input.mouseWorld(screenX, screenY).y); + tryDropItems(tile.entity.tile(), Core.input.mouseWorld(screenX, screenY).x, Core.input.mouseWorld(screenX, screenY).y); } return false; } @@ -551,6 +550,7 @@ public class MobileInput extends InputHandler implements GestureListener{ //ignore off-screen taps if(cursor == null || Core.scene.hasMouse(x, y)) return false; + Tile linked = cursor.entity == null ? cursor : cursor.entity.tile(); checkTargets(worldx, worldy); @@ -560,11 +560,10 @@ 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 selectRequests.add(lastPlaced = new BuildRequest(cursor.x, cursor.y, rotation, block)); - }else if(mode == breaking && validBreak(cursor.link().x, cursor.link().y) && !hasRequest(cursor.link())){ + }else if(mode == breaking && validBreak(linked.x,linked.y) && !hasRequest(linked)){ //add to selection queue if it's a valid BREAK position - cursor = cursor.link(); - selectRequests.add(new BuildRequest(cursor.x, cursor.y)); - }else if(!canTapPlayer(worldx, worldy) && !tileTapped(cursor.link())){ + selectRequests.add(new BuildRequest(linked.x, linked.y)); + }else if(!canTapPlayer(worldx, worldy) && !tileTapped(linked)){ tryBeginMine(cursor); } diff --git a/core/src/mindustry/io/MapIO.java b/core/src/mindustry/io/MapIO.java index 1dd39e6d5e..20657b5186 100644 --- a/core/src/mindustry/io/MapIO.java +++ b/core/src/mindustry/io/MapIO.java @@ -169,7 +169,7 @@ public class MapIO{ if(block.isFloor()){ tile.setFloor(block.asFloor()); }else if(block.isMultiblock()){ - tile.set(block, Team.derelict); + tile.setBlock(block, Team.derelict, 0); }else{ tile.setBlock(block); } diff --git a/core/src/mindustry/io/TypeIO.java b/core/src/mindustry/io/TypeIO.java index 9d7914a126..7ca5e13cfb 100644 --- a/core/src/mindustry/io/TypeIO.java +++ b/core/src/mindustry/io/TypeIO.java @@ -94,6 +94,14 @@ public class TypeIO{ return (T)Groups.all.getByID(read.i()); } + public static void writeTilec(Writes write, Tilec tile){ + write.i(tile == null ? -1 : tile.pos()); + } + + public static Tilec readTilec(Reads read){ + return world.ent(read.i()); + } + public static void writeTile(Writes write, Tile tile){ write.i(tile == null ? Point2.pack(-1, -1) : tile.pos()); } diff --git a/core/src/mindustry/net/Administration.java b/core/src/mindustry/net/Administration.java index a068dc9472..396458b173 100644 --- a/core/src/mindustry/net/Administration.java +++ b/core/src/mindustry/net/Administration.java @@ -101,9 +101,9 @@ public class Administration{ } /** @return whether this action is allowed by the action filters. */ - public boolean allowAction(Playerc player, ActionType type, Tile tile, Cons setter){ + public boolean allowAction(Playerc player, ActionType type, Tilec tile, Cons setter){ PlayerAction act = Pools.obtain(PlayerAction.class, PlayerAction::new); - setter.get(act.set(player, type, tile)); + setter.get(act.set(player, type, tile.tile())); for(ActionFilter filter : actionFilters){ if(!filter.allow(act)){ Pools.free(act); diff --git a/core/src/mindustry/ui/fragments/BlockConfigFragment.java b/core/src/mindustry/ui/fragments/BlockConfigFragment.java index 8a6aaceda9..b2bc91dbee 100644 --- a/core/src/mindustry/ui/fragments/BlockConfigFragment.java +++ b/core/src/mindustry/ui/fragments/BlockConfigFragment.java @@ -8,14 +8,13 @@ import arc.scene.ui.layout.*; import arc.util.*; import mindustry.content.*; import mindustry.core.GameState.*; -import mindustry.world.*; +import mindustry.gen.*; import static mindustry.Vars.*; public class BlockConfigFragment extends Fragment{ private Table table = new Table(); - private Tile configTile; - private Block configBlock; + private Tilec configTile; @Override public void build(Group parent){ @@ -40,13 +39,12 @@ public class BlockConfigFragment extends Fragment{ return table.isVisible() && configTile != null; } - public Tile getSelectedTile(){ + public Tilec getSelectedTile(){ return configTile; } - public void showConfig(Tile tile){ + public void showConfig(Tilec tile){ configTile = tile; - configBlock = tile.block(); table.visible(true); table.clear(); diff --git a/core/src/mindustry/ui/fragments/BlockInventoryFragment.java b/core/src/mindustry/ui/fragments/BlockInventoryFragment.java index 4f53e2fd75..a4966ffee3 100644 --- a/core/src/mindustry/ui/fragments/BlockInventoryFragment.java +++ b/core/src/mindustry/ui/fragments/BlockInventoryFragment.java @@ -22,7 +22,6 @@ import mindustry.net.Administration.*; import mindustry.net.*; import mindustry.type.*; import mindustry.ui.*; -import mindustry.world.*; import static mindustry.Vars.*; @@ -30,19 +29,19 @@ public class BlockInventoryFragment extends Fragment{ private final static float holdWithdraw = 20f; private Table table = new Table(); - private Tile tile; + private Tilec tile; private float holdTime = 0f; private boolean holding; private Item lastItem; @Remote(called = Loc.server, targets = Loc.both, forward = true) - public static void requestItem(Playerc player, Tile tile, Item item, int amount){ + public static void requestItem(Playerc player, Tilec tile, Item item, int amount){ if(player == null || tile == null || !tile.interactable(player.team())) return; amount = Mathf.clamp(amount, 0, player.unit().itemCapacity()); int fa = amount; if(net.server() && (!Units.canInteract(player, tile) || - !netServer.admins.allowAction(player, ActionType.withdrawItem, tile, action -> { + !netServer.admins.allowAction(player, ActionType.withdrawItem, tile.tile(), action -> { action.item = item; action.itemAmount = fa; }))) throw new ValidateException(player, "Player cannot request items."); @@ -52,7 +51,7 @@ public class BlockInventoryFragment extends Fragment{ player.unit().addItem(item, removed); Events.fire(new WithdrawEvent(tile, player, item, amount)); for(int j = 0; j < Mathf.clamp(removed / 3, 1, 8); j++){ - Time.run(j * 3f, () -> Call.transferItemEffect(item, tile.drawx(), tile.drawy(), player.unit())); + Time.run(j * 3f, () -> Call.transferItemEffect(item, tile.x(), tile.y(), player.unit())); } } @@ -64,13 +63,13 @@ public class BlockInventoryFragment extends Fragment{ parent.addChild(table); } - public void showFor(Tile t){ + public void showFor(Tilec t){ if(this.tile == t){ hide(); return; } this.tile = t; - if(tile == null || tile.entity == null || !tile.block().isAccessible() || tile.entity.items().total() == 0) + if(tile == null || !tile.block().isAccessible() || tile.items().total() == 0) return; rebuild(true); } @@ -97,14 +96,14 @@ public class BlockInventoryFragment extends Fragment{ table.touchable(Touchable.enabled); table.update(() -> { - if(state.is(State.menu) || tile == null || tile.entity == null || !tile.block().isAccessible() || tile.entity.items().total() == 0){ + if(state.is(State.menu) || tile == null || tile.entity == null || !tile.block().isAccessible() || tile.items().total() == 0){ hide(); }else{ if(holding && lastItem != null){ holdTime += Time.delta(); if(holdTime >= holdWithdraw){ - int amount = Math.min(tile.entity.items().get(lastItem), player.unit().maxAccepted(lastItem)); + int amount = Math.min(tile.items().get(lastItem), player.unit().maxAccepted(lastItem)); Call.requestItem(player, tile, lastItem, amount); holding = false; holdTime = 0f; @@ -116,7 +115,7 @@ public class BlockInventoryFragment extends Fragment{ updateTablePosition(); if(tile.block().hasItems){ for(int i = 0; i < content.items().size; i++){ - boolean has = tile.entity.items().has(content.item(i)); + boolean has = tile.items().has(content.item(i)); if(has != container.contains(i)){ rebuild(false); } @@ -135,7 +134,7 @@ public class BlockInventoryFragment extends Fragment{ for(int i = 0; i < content.items().size; i++){ Item item = content.item(i); - if(!tile.entity.items().has(item)) continue; + if(!tile.items().has(item)) continue; container.add(i); @@ -148,14 +147,14 @@ public class BlockInventoryFragment extends Fragment{ if(tile == null || tile.entity == null){ return ""; } - return round(tile.entity.items().get(item)); + return round(tile.items().get(item)); }); image.addListener(l); image.addListener(new InputListener(){ @Override public boolean touchDown(InputEvent event, float x, float y, int pointer, KeyCode button){ - if(!canPick.get() || tile == null || tile.entity == null || tile.entity.items() == null || !tile.entity.items().has(item)) return false; + if(!canPick.get() || tile == null || tile.entity == null || tile.items() == null || !tile.items().has(item)) return false; int amount = Math.min(1, player.unit().maxAccepted(item)); if(amount > 0){ Call.requestItem(player, tile, item, amount); @@ -207,7 +206,7 @@ public class BlockInventoryFragment extends Fragment{ } private void updateTablePosition(){ - Vec2 v = Core.input.mouseScreen(tile.drawx() + tile.block().size * tilesize / 2f, tile.drawy() + tile.block().size * tilesize / 2f); + Vec2 v = Core.input.mouseScreen(tile.x() + tile.block().size * tilesize / 2f, tile.y() + tile.block().size * tilesize / 2f); table.pack(); table.setPosition(v.x, v.y, Align.topLeft); } diff --git a/core/src/mindustry/world/Block.java b/core/src/mindustry/world/Block.java index edabf16581..59ee21c423 100644 --- a/core/src/mindustry/world/Block.java +++ b/core/src/mindustry/world/Block.java @@ -1,8 +1,6 @@ package mindustry.world; import arc.*; -import arc.Graphics.*; -import arc.Graphics.Cursor.*; import arc.audio.*; import arc.func.*; import arc.graphics.*; @@ -11,11 +9,11 @@ import arc.graphics.g2d.TextureAtlas.*; import arc.math.*; import arc.math.geom.*; import arc.scene.ui.layout.*; +import arc.struct.Array; import arc.struct.EnumSet; import arc.struct.*; import arc.util.*; import arc.util.ArcAnnotate.*; -import arc.util.pooling.*; import mindustry.annotations.Annotations.*; import mindustry.ctype.*; import mindustry.entities.*; @@ -26,18 +24,34 @@ import mindustry.graphics.MultiPacker.*; import mindustry.type.*; import mindustry.ui.*; import mindustry.world.blocks.*; -import mindustry.world.blocks.power.*; import mindustry.world.consumers.*; import mindustry.world.meta.*; import mindustry.world.meta.values.*; +import java.lang.reflect.*; import java.util.*; -import static mindustry.Vars.*; +import static mindustry.Vars.tilesize; -public class Block extends BlockStorage{ +public class Block extends UnlockableContent{ public static final int crackRegions = 8, maxCrackSize = 5; + public boolean hasItems; + public boolean hasLiquids; + public boolean hasPower; + + public boolean outputsLiquid = false; + public boolean consumesPower = true; + public boolean outputsPower = false; + + public int itemCapacity = 10; + public float liquidCapacity = 10f; + public float liquidPressure = 1f; + + public final BlockStats stats = new BlockStats(); + public final BlockBars bars = new BlockBars(); + public final Consumers consumes = new Consumers(); + /** whether this block has a tile entity that updates */ public boolean update; /** whether this block has health and can be destroyed */ @@ -140,12 +154,13 @@ public class Block extends BlockStorage{ public boolean instantTransfer = false; public boolean alwaysUnlocked = false; + protected Prov entityType = null; //initialized later protected TextureRegion[] cacheRegions = {}; protected Array cacheRegionStrings = new Array<>(); - protected Prov entityType = TileEntity::create; - protected ObjectMap, ConfigHandler> configurations = new ObjectMap<>(); + protected ObjectMap, Cons2> configurations = new ObjectMap<>(); protected Array tempTiles = new Array<>(); + protected Array tempTileEnts = new Array<>(); protected TextureRegion[] generatedIcons; protected TextureRegion[] variantRegions, editorVariantRegions; protected TextureRegion region, editorIcon; @@ -162,302 +177,6 @@ public class Block extends BlockStorage{ this.solid = false; } - public boolean isAir(){ - return id == 0; - } - - public boolean canBreak(Tile tile){ - return true; - } - - public boolean isBuildable(){ - return buildVisibility != BuildVisibility.hidden && buildVisibility != BuildVisibility.debugOnly; - } - - public boolean isStatic(){ - return cacheLayer == CacheLayer.walls; - } - - public void onProximityRemoved(Tile tile){ - if(tile.entity.power() != null){ - tile.block().powerGraphRemoved(tile); - } - } - - public void onProximityAdded(Tile tile){ - if(tile.block().hasPower) tile.block().updatePowerGraph(tile); - } - - protected void updatePowerGraph(Tile tile){ - Tilec entity = tile.ent(); - - for(Tile other : getPowerConnections(tile, tempTiles)){ - if(other.entity.power() != null){ - other.entity.power().graph.add(entity.power().graph); - } - } - } - - protected void powerGraphRemoved(Tile tile){ - if(tile.entity == null || tile.entity.power() == null){ - return; - } - - tile.entity.power().graph.remove(tile); - for(int i = 0; i < tile.entity.power().links.size; i++){ - Tile other = world.tile(tile.entity.power().links.get(i)); - if(other != null && other.entity != null && other.entity.power() != null){ - other.entity.power().links.removeValue(tile.pos()); - } - } - } - - public Array getPowerConnections(Tile tile, Array out){ - out.clear(); - if(tile == null || tile.entity == null || tile.entity.power() == null) return out; - - for(Tile other : tile.entity.proximity()){ - if(other != null && other.entity != null && other.entity.power() != null - && !(consumesPower && other.block().consumesPower && !outputsPower && !other.block().outputsPower) - && !tile.entity.power().links.contains(other.pos())){ - out.add(other); - } - } - - for(int i = 0; i < tile.entity.power().links.size; i++){ - Tile link = world.tile(tile.entity.power().links.get(i)); - if(link != null && link.entity != null && link.entity.power() != null) out.add(link); - } - return out; - } - - protected float getProgressIncrease(Tilec entity, float baseTime){ - return 1f / baseTime * entity.delta() * entity.efficiency(); - } - - /** @return whether this block should play its active sound.*/ - public boolean shouldActiveSound(Tile tile){ - return false; - } - - /** @return whether this block should play its idle sound.*/ - public boolean shouldIdleSound(Tile tile){ - return shouldConsume(tile); - } - - public void drawLayer(Tile tile){ - } - - public void drawLayer2(Tile tile){ - } - - public void drawCracks(Tile tile){ - if(!tile.entity.damaged() || size > maxCrackSize) return; - int id = tile.pos(); - TextureRegion region = cracks[size - 1][Mathf.clamp((int)((1f - tile.entity.healthf()) * crackRegions), 0, crackRegions-1)]; - Draw.colorl(0.2f, 0.1f + (1f - tile.entity.healthf())* 0.6f); - Draw.rect(region, tile.drawx(), tile.drawy(), (id%4)*90); - Draw.color(); - } - - /** Draw the block overlay that is shown when a cursor is over the block. */ - public void drawSelect(Tile tile){ - } - - /** Drawn when you are placing a block. */ - public void drawPlace(int x, int y, int rotation, boolean valid){ - } - - public float drawPlaceText(String text, int x, int y, boolean valid){ - if(renderer.pixelator.enabled()) return 0; - - Color color = valid ? Pal.accent : Pal.remove; - BitmapFont font = Fonts.outline; - GlyphLayout layout = Pools.obtain(GlyphLayout.class, GlyphLayout::new); - boolean ints = font.usesIntegerPositions(); - font.setUseIntegerPositions(false); - font.getData().setScale(1f / 4f / Scl.scl(1f)); - layout.setText(font, text); - - float width = layout.width; - - font.setColor(color); - float dx = x * tilesize + offset(), dy = y * tilesize + offset() + size * tilesize / 2f + 3; - font.draw(text, dx, dy + layout.height + 1, Align.center); - dy -= 1f; - Lines.stroke(2f, Color.darkGray); - Lines.line(dx - layout.width / 2f - 2f, dy, dx + layout.width / 2f + 1.5f, dy); - Lines.stroke(1f, color); - Lines.line(dx - layout.width / 2f - 2f, dy, dx + layout.width / 2f + 1.5f, dy); - - font.setUseIntegerPositions(ints); - font.setColor(Color.white); - font.getData().setScale(1f); - Draw.reset(); - Pools.free(layout); - return width; - } - - public void draw(Tile tile){ - Draw.rect(region, tile.drawx(), tile.drawy(), rotate ? tile.rotation() * 90 : 0); - } - - public void drawLight(Tile tile){ - if(tile.entity != null && hasLiquids && drawLiquidLight && tile.entity.liquids().current().lightColor.a > 0.001f){ - drawLiquidLight(tile, tile.entity.liquids().current(), tile.entity.liquids().smoothAmount()); - } - } - - public void drawLiquidLight(Tile tile, Liquid liquid, float amount){ - if(amount > 0.01f){ - Color color = liquid.lightColor; - float fract = 1f; - float opacity = color.a * fract; - if(opacity > 0.001f){ - renderer.lights.add(tile.drawx(), tile.drawy(), size * 30f * fract, color, opacity); - } - } - } - - public void drawTeam(Tile tile){ - Draw.color(tile.team().color); - Draw.rect("block-border", tile.drawx() - size * tilesize / 2f + 4, tile.drawy() - size * tilesize / 2f + 4); - Draw.color(); - } - - /** Called after the block is placed by this client. */ - @CallSuper - public void playerPlaced(Tile tile){ - - } - - /** Called after the block is placed by anyone. */ - @CallSuper - public void placed(Tile tile){ - if(net.client()) return; - - if((consumesPower && !outputsPower) || (!consumesPower && outputsPower)){ - int range = 10; - tempTiles.clear(); - Geometry.circle(tile.x, tile.y, range, (x, y) -> { - Tile other = world.ltile(x, y); - if(other != null && other.block instanceof PowerNode && ((PowerNode)other.block).linkValid(other, tile) && !PowerNode.insulated(other, tile) && !other.entity.proximity().contains(tile) && - !(outputsPower && tile.entity.proximity().contains(p -> p.entity != null && p.entity.power() != null && p.entity.power().graph == other.entity.power().graph))){ - tempTiles.add(other); - } - }); - tempTiles.sort(Structs.comparingFloat(t -> t.dst2(tile))); - if(!tempTiles.isEmpty()){ - Tile toLink = tempTiles.first(); - if(!toLink.entity.power().links.contains(tile.pos())){ - toLink.configureAny(tile.pos()); - } - } - } - } - - public void removed(Tile tile){ - } - - /** Called every frame a unit is on this tile. */ - public void unitOn(Tile tile, Unitc unit){ - } - - /** Called when a unit that spawned at this tile is removed. */ - public void unitRemoved(Tile tile, Unitc unit){ - } - - /** Returns whether ot not this block can be place on the specified tile. */ - public boolean canPlaceOn(Tile tile){ - return true; - } - - /** Call when some content is produced. This unlocks the content if it is applicable. */ - public void useContent(Tile tile, UnlockableContent content){ - //only unlocks content in zones - if(!headless && tile.team() == player.team() && state.isCampaign()){ - logic.handleContent(content); - } - } - - public float sumAttribute(Attribute attr, int x, int y){ - Tile tile = world.tile(x, y); - if(tile == null) return 0; - float sum = 0; - for(Tile other : tile.getLinkedTilesAs(this, tempTiles)){ - sum += other.floor().attributes.get(attr); - } - return sum; - } - - public float percentSolid(int x, int y){ - Tile tile = world.tile(x, y); - if(tile == null) return 0; - float sum = 0; - for(Tile other : tile.getLinkedTilesAs(this, tempTiles)){ - sum += !other.floor.isLiquid ? 1f : 0f; - } - return sum / size / size; - } - - @Override - public void displayInfo(Table table){ - ContentDisplay.displayBlock(table, this); - } - - @Override - public ContentType getContentType(){ - return ContentType.block; - } - - /** Called after all blocks are created. */ - @Override - @CallSuper - public void init(){ - //initialize default health based on size - if(health == -1){ - health = size * size * 40; - } - - buildCost = 0f; - for(ItemStack stack : requirements){ - buildCost += stack.amount * stack.item.cost; - } - buildCost *= buildCostMultiplier; - - if(consumes.has(ConsumeType.power)) hasPower = true; - if(consumes.has(ConsumeType.item)) hasItems = true; - if(consumes.has(ConsumeType.liquid)) hasLiquids = true; - - setStats(); - setBars(); - - consumes.init(); - - if(!outputsPower && consumes.hasPower() && consumes.getPower().buffered){ - throw new IllegalArgumentException("Consumer using buffered power: " + name); - } - } - - @Override - public void load(){ - region = Core.atlas.find(name); - - cacheRegions = new TextureRegion[cacheRegionStrings.size]; - for(int i = 0; i < cacheRegions.length; i++){ - cacheRegions[i] = Core.atlas.find(cacheRegionStrings.get(i)); - } - - if(cracks == null || (cracks[0][0].getTexture() != null && cracks[0][0].getTexture().isDisposed())){ - cracks = new TextureRegion[maxCrackSize][crackRegions]; - for(int size = 1; size <= maxCrackSize; size++){ - for(int i = 0; i < crackRegions; i++){ - cracks[size - 1][i] = Core.atlas.find("cracks-" + size + "-" + i); - } - } - } - } - /** Adds a region by name to be loaded, with the final name "{name}-suffix". Returns an ID to looks this region up by in {@link #reg(int)}. */ protected int reg(String suffix){ cacheRegionStrings.add(name + suffix); @@ -469,78 +188,10 @@ public class Block extends BlockStorage{ return cacheRegions[id]; } - /** Called when the block is tapped. This is equivalent to being configured with null. */ - public void tapped(Tile tile, Playerc player){ - - } - - /** Called when arbitrary configuration is applied to a tile. */ - public void configured(Tile tile, @Nullable Playerc player, @Nullable Object value){ - //null is of type Void.class; anonymous classes use their superclass. - Class type = value == null ? void.class : value.getClass().isAnonymousClass() ? value.getClass().getSuperclass() : value.getClass(); - - if(configurations.containsKey(type)){ - configurations.get(type).configured(tile, value); - } - } - - /** Configure when a null value is passed.*/ - public void configClear(Cons cons){ - configurations.put(void.class, (tile, value) -> cons.get(tile)); - } - - /** Listen for a config by class type. */ - public void config(Class type, ConfigHandler config){ - configurations.put(type, config); - } - - /** Returns whether or not a hand cursor should be shown over this block. */ - public Cursor getCursor(Tile tile){ - return configurable ? SystemCursor.hand : SystemCursor.arrow; - } - - /** - * Called when this block is tapped to build a UI on the table. - * {@link #configurable} must return true for this to be called. - */ - public void buildConfiguration(Tile tile, Table table){ - } - - /** Update table alignment after configuring.*/ - public void updateTableAlign(Tile tile, Table table){ - Vec2 pos = Core.input.mouseScreen(tile.drawx(), tile.drawy() - tile.block().size * tilesize / 2f - 1); - table.setPosition(pos.x, pos.y, Align.top); - } - - /** - * Called when another tile is tapped while this block is selected. - * Returns whether or not this block should be deselected. - */ - public boolean onConfigureTileTapped(Tile tile, Tile other){ - return tile != other; - } - - /** Returns whether this config menu should show when the specified player taps it. */ - public boolean shouldShowConfigure(Tile tile, Playerc player){ - return true; - } - - /** Whether this configuration should be hidden now. Called every frame the config is open. */ - public boolean shouldHideConfigure(Tile tile, Playerc player){ - return false; - } - public boolean synthetic(){ return update || destructible; } - public void drawConfigure(Tile tile){ - Draw.color(Pal.accent); - Lines.stroke(1f); - Lines.square(tile.drawx(), tile.drawy(), tile.block().size * tilesize / 2f + 1f); - Draw.reset(); - } - public void setStats(){ stats.add(BlockStat.size, "{0}x{0}", size); stats.add(BlockStat.health, health, StatUnit.none); @@ -568,7 +219,7 @@ public class Block extends BlockStorage{ current = entity -> entity.liquids().current(); } bars.add("liquid", entity -> new Bar(() -> entity.liquids().get(current.get(entity)) <= 0.001f ? Core.bundle.get("bar.liquid") : current.get(entity).localizedName, - () -> current.get(entity).barColor(), () -> entity.liquids().get(current.get(entity)) / liquidCapacity)); + () -> current.get(entity).barColor(), () -> entity.liquids().get(current.get(entity)) / liquidCapacity)); } if(hasPower && consumes.hasPower()){ @@ -577,7 +228,7 @@ public class Block extends BlockStorage{ float capacity = cons.capacity; bars.add("power", entity -> new Bar(() -> buffered ? Core.bundle.format("bar.poweramount", Float.isNaN(entity.power().status * capacity) ? "" : (int)(entity.power().status * capacity)) : - Core.bundle.get("bar.power"), () -> Pal.powerBar, () -> Mathf.zero(cons.requestedPower(entity)) && entity.power().graph.getPowerProduced() + entity.power().graph.getBatteryStored() > 0f ? 1f : entity.power().status)); + Core.bundle.get("bar.power"), () -> Pal.powerBar, () -> Mathf.zero(cons.requestedPower(entity)) && entity.power().graph.getPowerProduced() + entity.power().graph.getBatteryStored() > 0f ? 1f : entity.power().status)); } if(hasItems && configurable){ @@ -585,14 +236,6 @@ public class Block extends BlockStorage{ } } - public Tile linked(Tile tile){ - return tile; - } - - public boolean isSolidFor(Tile tile){ - return false; - } - public boolean canReplace(Block other){ return (other != this || rotate) && this.group != BlockGroup.none && other.group == this.group; } @@ -602,129 +245,6 @@ public class Block extends BlockStorage{ return this; } - public float handleDamage(Tile tile, float amount){ - return amount; - } - - public void handleBulletHit(Tilec entity, Bulletc bullet){ - entity.damage(bullet.damage()); - } - - public void update(Tile tile){ - } - - public boolean isAccessible(){ - return (hasItems && itemCapacity > 0); - } - - /** Called when the block is destroyed. */ - public void onDestroyed(Tile tile){ - float x = tile.worldx(), y = tile.worldy(); - float explosiveness = baseExplosiveness; - float flammability = 0f; - float power = 0f; - - if(hasItems){ - for(Item item : content.items()){ - int amount = tile.entity.items().get(item); - explosiveness += item.explosiveness * amount; - flammability += item.flammability * amount; - } - } - - if(hasLiquids){ - flammability += tile.entity.liquids().sum((liquid, amount) -> liquid.explosiveness * amount / 2f); - explosiveness += tile.entity.liquids().sum((liquid, amount) -> liquid.flammability * amount / 2f); - } - - if(consumes.hasPower() && consumes.getPower().buffered){ - power += tile.entity.power().status * consumes.getPower().capacity; - } - - if(hasLiquids){ - - tile.entity.liquids().each((liquid, amount) -> { - float splash = Mathf.clamp(amount / 4f, 0f, 10f); - - for(int i = 0; i < Mathf.clamp(amount / 5, 0, 30); i++){ - Time.run(i / 2f, () -> { - Tile other = world.tile(tile.x + Mathf.range(size / 2), tile.y + Mathf.range(size / 2)); - if(other != null){ - Puddles.deposit(other, liquid, splash); - } - }); - } - }); - } - - Damage.dynamicExplosion(x, y, flammability, explosiveness * 3.5f, power, tilesize * size / 2f, Pal.darkFlame); - if(!tile.floor().solid && !tile.floor().isLiquid){ - Effects.rubble(tile.drawx(), tile.drawy(), size); - } - } - - /** - * Returns the flammability of the tile. Used for fire calculations. - * Takes flammability of floor liquid into account. - */ - public float getFlammability(Tile tile){ - if(!hasItems || tile.entity == null){ - if(tile.floor().isLiquid && !solid){ - return tile.floor().liquidDrop.flammability; - } - return 0; - }else{ - float result = tile.entity.items().sum((item, amount) -> item.flammability * amount); - - if(hasLiquids){ - result += tile.entity.liquids().sum((liquid, amount) -> liquid.flammability * amount / 3f); - } - - return result; - } - } - - public String getDisplayName(Tile tile){ - return localizedName; - } - - public TextureRegion getDisplayIcon(Tile tile){ - return icon(Cicon.medium); - } - - public void display(Tile tile, Table table){ - Tilec entity = tile.entity; - - if(entity != null){ - table.table(bars -> { - bars.defaults().growX().height(18f).pad(4); - - displayBars(tile, bars); - }).growX(); - table.row(); - table.table(ctable -> { - displayConsumption(tile, ctable); - }).growX(); - - table.marginBottom(-5); - } - } - - public void displayConsumption(Tile tile, Table table){ - table.left(); - for(Consume cons : consumes.all()){ - if(cons.isOptional() && cons.isBoost()) continue; - cons.build(tile, table); - } - } - - public void displayBars(Tile tile, Table table){ - for(Func bar : bars.list()){ - table.add(bar.get(tile.entity)).growX(); - table.row(); - } - } - public void drawRequest(BuildRequest req, Eachable list, boolean valid){ Draw.reset(); Draw.mixcol(!valid ? Pal.breakInvalid : Color.white, (!valid ? 0.4f : 0.24f) + Mathf.absin(Time.globalTime(), 6f, 0.28f)); @@ -736,9 +256,9 @@ public class Block extends BlockStorage{ public void drawRequestRegion(BuildRequest req, Eachable list){ TextureRegion reg = getRequestRegion(req, list); Draw.rect(reg, req.drawx(), req.drawy(), - reg.getWidth() * req.animScale * Draw.scl, - reg.getHeight() * req.animScale * Draw.scl, - !rotate ? 0 : req.rotation * 90); + reg.getWidth() * req.animScale * Draw.scl, + reg.getHeight() * req.animScale * Draw.scl, + !rotate ? 0 : req.rotation * 90); if(req.hasConfig){ drawRequestConfig(req, list); @@ -766,75 +286,32 @@ public class Block extends BlockStorage{ Draw.color(); } - /** @return a custom minimap color for this tile, or 0 to use default colors. */ - public int minimapColor(Tile tile){ - return 0; - } - public void drawRequestConfigTop(BuildRequest req, Eachable list){ } - @Override - public void createIcons(MultiPacker packer){ - super.createIcons(packer); + /** Called when arbitrary configuration is applied to a tile. */ + public void configured(Tilec tile, @Nullable Playerc player, @Nullable Object value){ + //null is of type Void.class; anonymous classes use their superclass. + Class type = value == null ? void.class : value.getClass().isAnonymousClass() ? value.getClass().getSuperclass() : value.getClass(); - packer.add(PageType.editor, name + "-icon-editor", Core.atlas.getPixmap((AtlasRegion)icon(Cicon.full))); - - if(!synthetic()){ - PixmapRegion image = Core.atlas.getPixmap((AtlasRegion)icon(Cicon.full)); - mapColor.set(image.getPixel(image.width/2, image.height/2)); + if(configurations.containsKey(type)){ + configurations.get(type).get(tile, value); } + } - getGeneratedIcons(); + /** Configure when a null value is passed.*/ + public void configClear(Cons cons){ + configurations.put(void.class, (tile, value) -> cons.get((Tilec)tile)); + } - Pixmap last = null; + /** Listen for a config by class type. */ + public void config(Class type, Cons2 config){ + configurations.put(type, config); + } - if(outlineIcon){ - final int radius = 4; - PixmapRegion region = Core.atlas.getPixmap(getGeneratedIcons()[getGeneratedIcons().length-1]); - Pixmap out = new Pixmap(region.width, region.height); - Color color = new Color(); - for(int x = 0; x < region.width; x++){ - for(int y = 0; y < region.height; y++){ - - region.getPixel(x, y, color); - out.draw(x, y, color); - if(color.a < 1f){ - boolean found = false; - outer: - for(int rx = -radius; rx <= radius; rx++){ - for(int ry = -radius; ry <= radius; ry++){ - if(Structs.inBounds(rx + x, ry + y, region.width, region.height) && Mathf.dst2(rx, ry) <= radius*radius && color.set(region.getPixel(rx + x, ry + y)).a > 0.01f){ - found = true; - break outer; - } - } - } - if(found){ - out.draw(x, y, outlineColor); - } - } - } - } - last = out; - - packer.add(PageType.main, name, out); - } - - if(generatedIcons.length > 1){ - Pixmap base = Core.atlas.getPixmap(generatedIcons[0]).crop(); - for(int i = 1; i < generatedIcons.length; i++){ - if(i == generatedIcons.length - 1 && last != null){ - base.drawPixmap(last); - }else{ - base.draw(Core.atlas.getPixmap(generatedIcons[i])); - } - } - packer.add(PageType.main, "block-" + name + "-full", base); - generatedIcons = null; - Arrays.fill(cicons, null); - } + public boolean isAccessible(){ + return (hasItems && itemCapacity > 0); } /** Never use outside of the editor! */ @@ -911,14 +388,16 @@ public class Block extends BlockStorage{ return (Floor)this; } - @Override - public boolean isHidden(){ - return !buildVisibility.visible(); + public boolean isAir(){ + return id == 0; } - @Override - public boolean alwaysUnlocked(){ - return alwaysUnlocked; + public boolean isBuildable(){ + return buildVisibility != BuildVisibility.hidden && buildVisibility != BuildVisibility.debugOnly; + } + + public boolean isStatic(){ + return cacheLayer == CacheLayer.walls; } protected void requirements(Category cat, ItemStack[] stacks, boolean unlocked){ @@ -939,8 +418,157 @@ public class Block extends BlockStorage{ Arrays.sort(requirements, Structs.comparingInt(i -> i.item.id)); } - public interface ConfigHandler{ - void configured(Tile tile, T value); + @Override + public void displayInfo(Table table){ + ContentDisplay.displayBlock(table, this); + } + + @Override + public ContentType getContentType(){ + return ContentType.block; + } + + /** Called after all blocks are created. */ + @Override + @CallSuper + public void init(){ + //initialize default health based on size + if(health == -1){ + health = size * size * 40; + } + + if(entityType == null){ + //assign default value for now + entityType = TileEntity::create; + + //attempt to find the first declared class and use it as the entity type + try{ + Class[] classes = getClass().getDeclaredClasses(); + //first class that is subclass of Tilec + Class type = Structs.find(classes, Tilec.class::isAssignableFrom); + if(type != null){ + Constructor cons = (Constructor)type.getConstructor(); + entityType = () -> { + try{ + return cons.newInstance(); + }catch(Exception e){ + throw new RuntimeException(e); + } + }; + } + }catch(Throwable ignored){ + } + } + + buildCost = 0f; + for(ItemStack stack : requirements){ + buildCost += stack.amount * stack.item.cost; + } + buildCost *= buildCostMultiplier; + + if(consumes.has(ConsumeType.power)) hasPower = true; + if(consumes.has(ConsumeType.item)) hasItems = true; + if(consumes.has(ConsumeType.liquid)) hasLiquids = true; + + setStats(); + setBars(); + + consumes.init(); + + if(!outputsPower && consumes.hasPower() && consumes.getPower().buffered){ + throw new IllegalArgumentException("Consumer using buffered power: " + name); + } + } + + @Override + public void load(){ + region = Core.atlas.find(name); + + cacheRegions = new TextureRegion[cacheRegionStrings.size]; + for(int i = 0; i < cacheRegions.length; i++){ + cacheRegions[i] = Core.atlas.find(cacheRegionStrings.get(i)); + } + + if(cracks == null || (cracks[0][0].getTexture() != null && cracks[0][0].getTexture().isDisposed())){ + cracks = new TextureRegion[maxCrackSize][crackRegions]; + for(int size = 1; size <= maxCrackSize; size++){ + for(int i = 0; i < crackRegions; i++){ + cracks[size - 1][i] = Core.atlas.find("cracks-" + size + "-" + i); + } + } + } + } + + @Override + public boolean isHidden(){ + return !buildVisibility.visible(); + } + + @Override + public boolean alwaysUnlocked(){ + return alwaysUnlocked; + } + + @Override + public void createIcons(MultiPacker packer){ + super.createIcons(packer); + + packer.add(PageType.editor, name + "-icon-editor", Core.atlas.getPixmap((AtlasRegion)icon(Cicon.full))); + + if(!synthetic()){ + PixmapRegion image = Core.atlas.getPixmap((AtlasRegion)icon(Cicon.full)); + mapColor.set(image.getPixel(image.width/2, image.height/2)); + } + + getGeneratedIcons(); + + Pixmap last = null; + + if(outlineIcon){ + final int radius = 4; + PixmapRegion region = Core.atlas.getPixmap(getGeneratedIcons()[getGeneratedIcons().length-1]); + Pixmap out = new Pixmap(region.width, region.height); + Color color = new Color(); + for(int x = 0; x < region.width; x++){ + for(int y = 0; y < region.height; y++){ + + region.getPixel(x, y, color); + out.draw(x, y, color); + if(color.a < 1f){ + boolean found = false; + outer: + for(int rx = -radius; rx <= radius; rx++){ + for(int ry = -radius; ry <= radius; ry++){ + if(Structs.inBounds(rx + x, ry + y, region.width, region.height) && Mathf.dst2(rx, ry) <= radius*radius && color.set(region.getPixel(rx + x, ry + y)).a > 0.01f){ + found = true; + break outer; + } + } + } + if(found){ + out.draw(x, y, outlineColor); + } + } + } + } + last = out; + + packer.add(PageType.main, name, out); + } + + if(generatedIcons.length > 1){ + Pixmap base = Core.atlas.getPixmap(generatedIcons[0]).crop(); + for(int i = 1; i < generatedIcons.length; i++){ + if(i == generatedIcons.length - 1 && last != null){ + base.drawPixmap(last); + }else{ + base.draw(Core.atlas.getPixmap(generatedIcons[i])); + } + } + packer.add(PageType.main, "block-" + name + "-full", base); + generatedIcons = null; + Arrays.fill(cicons, null); + } } } diff --git a/core/src/mindustry/world/BlockStorage.java b/core/src/mindustry/world/BlockStorage.java deleted file mode 100644 index 0315fa4d8f..0000000000 --- a/core/src/mindustry/world/BlockStorage.java +++ /dev/null @@ -1,280 +0,0 @@ -package mindustry.world; - -import arc.math.*; -import arc.math.geom.*; -import arc.struct.*; -import arc.util.*; -import mindustry.*; -import mindustry.content.*; -import mindustry.ctype.*; -import mindustry.entities.*; -import mindustry.gen.*; -import mindustry.type.*; -import mindustry.world.consumers.*; -import mindustry.world.meta.*; - -public abstract class BlockStorage extends UnlockableContent{ - public boolean hasItems; - public boolean hasLiquids; - public boolean hasPower; - - public boolean outputsLiquid = false; - public boolean consumesPower = true; - public boolean outputsPower = false; - - public int itemCapacity = 10; - public float liquidCapacity = 10f; - public float liquidPressure = 1f; - - public final BlockStats stats = new BlockStats(); - public final BlockBars bars = new BlockBars(); - public final Consumers consumes = new Consumers(); - - public BlockStorage(String name){ - super(name); - } - - public boolean shouldConsume(Tile tile){ - return true; - } - - public boolean productionValid(Tile tile){ - return true; - } - - public float getPowerProduction(Tile tile){ - return 0f; - } - - /** Returns the amount of items this block can accept. */ - public int acceptStack(Item item, int amount, Tile tile, Teamc source){ - if(acceptItem(item, tile, tile) && hasItems && (source == null || source.team() == tile.team())){ - return Math.min(getMaximumAccepted(tile, item) - tile.entity.items().get(item), amount); - }else{ - return 0; - } - } - - public int getMaximumAccepted(Tile tile, Item item){ - return itemCapacity; - } - - /** Remove a stack from this inventory, and return the amount removed. */ - public int removeStack(Tile tile, Item item, int amount){ - if(tile.entity == null || tile.entity.items() == null) return 0; - amount = Math.min(amount, tile.entity.items().get(item)); - tile.entity.noSleep(); - tile.entity.items().remove(item, amount); - return amount; - } - - /** Handle a stack input. */ - public void handleStack(Item item, int amount, Tile tile, Teamc source){ - tile.entity.noSleep(); - tile.entity.items().add(item, amount); - } - - public boolean outputsItems(){ - return hasItems; - } - - /** Returns offset for stack placement. */ - public void getStackOffset(Item item, Tile tile, Vec2 trns){ - - } - - public void onProximityUpdate(Tile tile){ - if(tile.entity != null) tile.entity.noSleep(); - } - - public void handleItem(Item item, Tile tile, Tile source){ - tile.entity.items().add(item, 1); - } - - public boolean acceptItem(Item item, Tile tile, Tile source){ - return consumes.itemFilters.get(item.id) && tile.entity.items().get(item) < getMaximumAccepted(tile, item); - } - - public boolean acceptLiquid(Tile tile, Tile source, Liquid liquid, float amount){ - return hasLiquids && tile.entity.liquids().get(liquid) + amount < liquidCapacity && consumes.liquidfilters.get(liquid.id); - } - - public void handleLiquid(Tile tile, Tile source, Liquid liquid, float amount){ - tile.entity.liquids().add(liquid, amount); - } - - public void tryDumpLiquid(Tile tile, Liquid liquid){ - Array proximity = tile.entity.proximity(); - int dump = tile.rotation(); - - for(int i = 0; i < proximity.size; i++){ - incrementDump(tile, proximity.size); - Tile other = proximity.get((i + dump) % proximity.size); - Tile in = Edges.getFacingEdge(tile, other); - - other = other.block().getLiquidDestination(other, in, liquid); - - if(other != null && other.team() == tile.team() && other.block().hasLiquids && canDumpLiquid(tile, other, liquid) && other.entity.liquids() != null){ - float ofract = other.entity.liquids().get(liquid) / other.block().liquidCapacity; - float fract = tile.entity.liquids().get(liquid) / liquidCapacity; - - if(ofract < fract) tryMoveLiquid(tile, in, other, (fract - ofract) * liquidCapacity / 2f, liquid); - } - } - - } - - public boolean canDumpLiquid(Tile tile, Tile to, Liquid liquid){ - return true; - } - - public void tryMoveLiquid(Tile tile, Tile tileSource, Tile next, float amount, Liquid liquid){ - float flow = Math.min(next.block().liquidCapacity - next.entity.liquids().get(liquid) - 0.001f, amount); - - if(next.block().acceptLiquid(next, tileSource, liquid, flow)){ - next.block().handleLiquid(next, tileSource, liquid, flow); - tile.entity.liquids().remove(liquid, flow); - } - } - - public float tryMoveLiquid(Tile tile, Tile next, boolean leak, Liquid liquid){ - return tryMoveLiquid(tile, next, leak ? 1.5f : 100, liquid); - } - - public float tryMoveLiquid(Tile tile, Tile next, float leakResistance, Liquid liquid){ - if(next == null) return 0; - - next = next.link(); - next = next.block().getLiquidDestination(next, tile, liquid); - - if(next.team() == tile.team() && next.block().hasLiquids && tile.entity.liquids().get(liquid) > 0f){ - - if(next.block().acceptLiquid(next, tile, liquid, 0f)){ - float ofract = next.entity.liquids().get(liquid) / next.block().liquidCapacity; - float fract = tile.entity.liquids().get(liquid) / liquidCapacity * liquidPressure; - float flow = Math.min(Mathf.clamp((fract - ofract) * (1f)) * (liquidCapacity), tile.entity.liquids().get(liquid)); - flow = Math.min(flow, next.block().liquidCapacity - next.entity.liquids().get(liquid) - 0.001f); - - if(flow > 0f && ofract <= fract && next.block().acceptLiquid(next, tile, liquid, flow)){ - next.block().handleLiquid(next, tile, liquid, flow); - tile.entity.liquids().remove(liquid, flow); - return flow; - }else if(ofract > 0.1f && fract > 0.1f){ - Liquid other = next.entity.liquids().current(); - if((other.flammability > 0.3f && liquid.temperature > 0.7f) || (liquid.flammability > 0.3f && other.temperature > 0.7f)){ - tile.entity.damage(1 * Time.delta()); - next.entity.damage(1 * Time.delta()); - if(Mathf.chance(0.1 * Time.delta())){ - Fx.fire.at((tile.worldx() + next.worldx()) / 2f, (tile.worldy() + next.worldy()) / 2f); - } - }else if((liquid.temperature > 0.7f && other.temperature < 0.55f) || (other.temperature > 0.7f && liquid.temperature < 0.55f)){ - tile.entity.liquids().remove(liquid, Math.min(tile.entity.liquids().get(liquid), 0.7f * Time.delta())); - if(Mathf.chance(0.2f * Time.delta())){ - Fx.steam.at((tile.worldx() + next.worldx()) / 2f, (tile.worldy() + next.worldy()) / 2f); - } - } - } - } - }else if(leakResistance != 100f && !next.block().solid && !next.block().hasLiquids){ - float leakAmount = tile.entity.liquids().get(liquid) / leakResistance; - Puddles.deposit(next, tile, liquid, leakAmount); - tile.entity.liquids().remove(liquid, leakAmount); - } - return 0; - } - - public Tile getLiquidDestination(Tile tile, Tile from, Liquid liquid){ - return tile; - } - - /** - * Tries to put this item into a nearby container, if there are no available - * containers, it gets added to the block's inventory. - */ - public void offloadNear(Tile tile, Item item){ - Array proximity = tile.entity.proximity(); - int dump = tile.rotation(); - - for(int i = 0; i < proximity.size; i++){ - incrementDump(tile, proximity.size); - Tile other = proximity.get((i + dump) % proximity.size); - Tile in = Edges.getFacingEdge(tile, other); - if(other.team() == tile.team() && other.block().acceptItem(item, other, in) && canDump(tile, other, item)){ - other.block().handleItem(item, other, in); - return; - } - } - - handleItem(item, tile, tile); - } - - /** Try dumping any item near the tile. */ - public boolean tryDump(Tile tile){ - return tryDump(tile, null); - } - - /** - * Try dumping a specific item near the tile. - * @param todump Item to dump. Can be null to dump anything. - */ - public boolean tryDump(Tile tile, Item todump){ - Tilec entity = tile.entity; - if(entity == null || !hasItems || tile.entity.items().total() == 0 || (todump != null && !entity.items().has(todump))) - return false; - - Array proximity = entity.proximity(); - int dump = tile.rotation(); - - if(proximity.size == 0) return false; - - for(int i = 0; i < proximity.size; i++){ - Tile other = proximity.get((i + dump) % proximity.size); - Tile in = Edges.getFacingEdge(tile, other); - - if(todump == null){ - - for(int ii = 0; ii < Vars.content.items().size; ii++){ - Item item = Vars.content.item(ii); - - if(other.team() == tile.team() && entity.items().has(item) && other.block().acceptItem(item, other, in) && canDump(tile, other, item)){ - other.block().handleItem(item, other, in); - tile.entity.items().remove(item, 1); - incrementDump(tile, proximity.size); - return true; - } - } - }else{ - - if(other.team() == tile.team() && other.block().acceptItem(todump, other, in) && canDump(tile, other, todump)){ - other.block().handleItem(todump, other, in); - tile.entity.items().remove(todump, 1); - incrementDump(tile, proximity.size); - return true; - } - } - - incrementDump(tile, proximity.size); - } - - return false; - } - - protected void incrementDump(Tile tile, int prox){ - tile.rotation((byte)((tile.rotation() + 1) % prox)); - } - - /** Used for dumping items. */ - public boolean canDump(Tile tile, Tile to, Item item){ - return true; - } - - /** 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.front(); - if(other != null && other.team() == tile.team() && other.block().acceptItem(item, other, tile)){ - other.block().handleItem(item, other, tile); - return true; - } - return false; - } -} diff --git a/core/src/mindustry/world/Build.java b/core/src/mindustry/world/Build.java index ee21b91101..78fbc59ce6 100644 --- a/core/src/mindustry/world/Build.java +++ b/core/src/mindustry/world/Build.java @@ -15,19 +15,16 @@ import static mindustry.Vars.*; public class Build{ - /** Returns block type that was broken, or null if unsuccesful. */ @Remote(called = Loc.server) public static void beginBreak(Team team, int x, int y){ if(!validBreak(team, x, y)){ return; } - Tile tile = world.ltile(x, y); + Tile tile = world.tilec(x, y); + //this should never happen, but it doesn't hurt to check for links float prevPercent = 1f; - //just in case - if(tile == null) return; - if(tile.entity != null){ prevPercent = tile.entity.healthf(); } @@ -36,7 +33,7 @@ public class Build{ Block previous = tile.block(); Block sub = BuildBlock.get(previous.size); - tile.set(sub, team, rotation); + tile.setBlock(sub, team, rotation); tile.ent().setDeconstruct(previous); tile.entity.health(tile.entity.maxHealth() * prevPercent); @@ -58,7 +55,7 @@ public class Build{ Block previous = tile.block(); Block sub = BuildBlock.get(result.size); - tile.set(sub, team, rotation); + tile.setBlock(sub, team, rotation); tile.ent().setConstruct(previous, result); Core.app.post(() -> Events.fire(new BlockBuildBeginEvent(tile, team, false))); @@ -152,7 +149,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.ltile(x, y); + Tile tile = world.tile(x, y); return tile != null && tile.block().canBreak(tile) && tile.breakable() && tile.interactable(team); } } diff --git a/core/src/mindustry/world/Tile.java b/core/src/mindustry/world/Tile.java index 8e86cf0f4b..f26ef4dfed 100644 --- a/core/src/mindustry/world/Tile.java +++ b/core/src/mindustry/world/Tile.java @@ -19,15 +19,13 @@ public class Tile implements Position{ /** Tile traversal cost. */ public byte cost = 1; /** Tile entity, usually null. */ - public Tilec entity; + public @Nullable Tilec entity; public short x, y; protected @NonNull Block block; protected @NonNull Floor floor; protected @NonNull Floor overlay; /** Rotation, 0-3. Also used to store offload location, in which case it can be any number.*/ protected byte rotation; - /** Team ordinal. */ - protected byte team; public Tile(int x, int y){ this.x = (short)x; @@ -144,23 +142,63 @@ public class Tile implements Position{ } public Team team(){ - return Team.get(link().team); + return entity == null ? Team.derelict : entity.team(); } public void setTeam(Team team){ - this.team = (byte) team.id; + if(entity != null){ + entity.team(team); + } + } + + public boolean isCenter(){ + return entity == null || entity.tile() == this; } public byte getTeamID(){ - return team; + return team().id; } public void setBlock(@NonNull Block type, Team team, int rotation){ preChanged(); this.block = type; - this.team = (byte) team.id; - this.rotation = (byte)Mathf.mod(rotation, 4); + this.rotation = rotation == 0 ? 0 : (byte)Mathf.mod(rotation, 4); changed(); + + if(entity != null){ + entity.team(team); + } + + //set up multiblock + if(block.isMultiblock()){ + int offsetx = -(block.size - 1) / 2; + int offsety = -(block.size - 1) / 2; + + //two passes: first one clears, second one sets + for(int pass = 0; pass < 2; pass++){ + for(int dx = 0; dx < block.size; dx++){ + for(int dy = 0; dy < block.size; dy++){ + int worldx = dx + offsetx + x; + int worldy = dy + offsety + y; + if(!(worldx == x && worldy == y)){ + Tile other = world.tile(worldx, worldy); + + if(other != null){ + if(pass == 0){ + //first pass: delete existing blocks - this should automatically trigger removal if overlap exists + other.setBlock(Blocks.air); + }else{ + //second pass: assign changed data + //assign entity and type to blocks, so they act as proxies for this one + other.entity = entity; + other.block = block; + } + } + } + } + } + } + } } public void setBlock(@NonNull Block type, Team team){ @@ -168,11 +206,7 @@ public class Tile implements Position{ } public void setBlock(@NonNull Block type){ - if(type == null) throw new IllegalArgumentException("Block cannot be null."); - preChanged(); - this.block = type; - this.rotation = 0; - changed(); + setBlock(type, Team.derelict, 0); } /** This resets the overlay! */ @@ -181,7 +215,9 @@ public class Tile implements Position{ this.overlay = (Floor)Blocks.air; recache(); - block.onProximityUpdate(this); + if(entity != null){ + block.onProximityUpdate(entity); + } } /** Sets the floor, preserving overlay.*/ @@ -205,32 +241,8 @@ public class Tile implements Position{ } public void remove(){ - link().getLinkedTiles(other -> other.setBlock(Blocks.air)); - } - - public void set(Block block, Team team){ - set(block, team, 0); - } - - public void set(Block block, Team team, int rotation){ - setBlock(block, team, rotation); - if(block.isMultiblock()){ - int offsetx = -(block.size - 1) / 2; - int offsety = -(block.size - 1) / 2; - - for(int dx = 0; dx < block.size; dx++){ - for(int dy = 0; dy < block.size; dy++){ - int worldx = dx + offsetx + x; - int worldy = dy + offsety + y; - if(!(worldx == x && worldy == y)){ - Tile toplace = world.tile(worldx, worldy); - if(toplace != null){ - toplace.setBlock(BlockPart.get(dx + offsetx, dy + offsety), team); - } - } - } - } - } + //this automatically removes multiblock references to this block + setBlock(Blocks.air); } /** remove()-s this tile, except it's synced across the network */ @@ -274,11 +286,13 @@ public class Tile implements Position{ } public void setOverlayID(short ore){ - this.overlay = (Floor)content.block(ore); + setOverlay(content.block(ore)); } public void setOverlay(Block block){ this.overlay = (Floor)block; + + recache(); } public void clearOverlay(){ @@ -286,7 +300,7 @@ public class Tile implements Position{ } public boolean passable(){ - return isLinked() || !((floor.solid && (block == Blocks.air || block.solidifes)) || (block.solid && (!block.destructible && !block.update))); + return !((floor.solid && (block == Blocks.air || block.solidifes)) || (block.solid && (!block.destructible && !block.update))); } /** Whether this block was placed by a player/unit. */ @@ -295,27 +309,19 @@ public class Tile implements Position{ } public boolean solid(){ - return block.solid || block.isSolidFor(this) || (isLinked() && link() != this && link().solid()); + return block.solid || (entity != null && block.isSolidFor(entity)); } public boolean breakable(){ - return !isLinked() ? (block.destructible || block.breakable || block.update) : link().breakable(); - } - - public Tile link(){ - return block.linked(this); + return block.destructible || block.breakable || block.update; } public boolean isEnemyCheat(){ return team() == state.rules.waveTeam && state.rules.enemyCheat; } - public boolean isLinked(){ - return block instanceof BlockPart; - } - /** - * Returns the list of all tiles linked to this multiblock, or an empty array if it's not a multiblock. + * Returns the list of all tiles linked to this multiblock, or just itself if it's not a multiblock. * This array contains all linked tiles, including this tile itself. */ public void getLinkedTiles(Cons cons){ @@ -385,29 +391,29 @@ public class Tile implements Position{ return null; } - public Tile getNearbyLink(int rotation){ - if(rotation == 0) return world.ltile(x + 1, y); - if(rotation == 1) return world.ltile(x, y + 1); - if(rotation == 2) return world.ltile(x - 1, y); - if(rotation == 3) return world.ltile(x, y - 1); + public Tilec getNearbyEntity(int rotation){ + if(rotation == 0) return world.ent(x + 1, y); + if(rotation == 1) return world.ent(x, y + 1); + if(rotation == 2) return world.ent(x - 1, y); + if(rotation == 3) return world.ent(x, y - 1); return null; } // ▲ ▲ ▼ ▼ ◀ ▶ ◀ ▶ B A - public @Nullable Tile front(){ - return getNearbyLink((rotation + 4) % 4); + public @Nullable Tilec front(){ + return getNearbyEntity((rotation + 4) % 4); } - public @Nullable Tile right(){ - return getNearbyLink((rotation + 3) % 4); + public @Nullable Tilec right(){ + return getNearbyEntity((rotation + 3) % 4); } - public @Nullable Tile back(){ - return getNearbyLink((rotation + 2) % 4); + public @Nullable Tilec back(){ + return getNearbyEntity((rotation + 2) % 4); } - public @Nullable Tile left(){ - return getNearbyLink((rotation + 1) % 4); + public @Nullable Tilec left(){ + return getNearbyEntity((rotation + 1) % 4); } public boolean interactable(Team team){ @@ -443,8 +449,8 @@ public class Tile implements Position{ //+26 - if(link().synthetic() && link().solid()){ - cost += Mathf.clamp(link().block.health / 10f, 0, 20); + if(block.synthetic() && solid()){ + cost += Mathf.clamp(block.health / 10f, 0, 20); } //+46 @@ -467,15 +473,34 @@ public class Tile implements Position{ } protected void preChanged(){ - block.removed(this); if(entity != null){ + //only call removed() for the center block - this only gets called once. + block.removed(entity); entity.removeFromProximity(); + + //remove this tile's dangling entities + if(entity.block().isMultiblock()){ + int size = entity.block().size; + int offsetx = -(size - 1) / 2; + int offsety = -(size - 1) / 2; + for(int dx = 0; dx < size; dx++){ + for(int dy = 0; dy < size; dy++){ + Tile other = world.tile(entity.tileX() + dx + offsetx, entity.tileY() + dy + offsety); + if(other != null){ + //reset entity and block *manually* - thus, preChanged() will not be called anywhere else, for multiblocks + other.entity = null; + other.block = Blocks.air; + } + } + } + } } + + //recache when static blocks get changed if(block.isStatic()){ recache(); } - team = 0; } protected void changed(){ @@ -493,18 +518,18 @@ public class Tile implements Position{ if(block.hasLiquids) entity.liquids(new LiquidModule()); if(block.hasPower){ entity.power(new PowerModule()); - entity.power().graph.add(this); + entity.power().graph.add(entity); } if(!world.isGenerating()){ entity.updateProximity(); } - }else if(!(block instanceof BlockPart) && !world.isGenerating()){ + }else if(!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.ltile(x + p.x, y + p.y); + Tile tile = world.tile(x + p.x, y + p.y); if(tile != null){ - tile.block().onProximityUpdate(tile); + tile.block().onProximityUpdate(entity); } } } @@ -549,7 +574,7 @@ public class Tile implements Position{ @Remote(called = Loc.server) public static void setTile(Tile tile, Block block, Team team, int rotation){ - tile.set(block, team, rotation); + tile.setBlock(block, team, rotation); } @Remote(called = Loc.server, unreliable = true) diff --git a/core/src/mindustry/world/blocks/BlockPart.java b/core/src/mindustry/world/blocks/BlockPart.java deleted file mode 100644 index ef2b3d1c38..0000000000 --- a/core/src/mindustry/world/blocks/BlockPart.java +++ /dev/null @@ -1,83 +0,0 @@ -package mindustry.world.blocks; - -import mindustry.type.Item; -import mindustry.type.Liquid; -import mindustry.world.Block; -import mindustry.world.Tile; - -/** - * Used for multiblocks. Each block that is not the center of the multiblock is a part. - * Think of these as delegates to the actual block; all events are passed to the target block. - * They are made to share all properties from the linked tile/block. - */ -public class BlockPart extends Block{ - public final static int maxSize = 9; - private final static BlockPart[][] parts = new BlockPart[maxSize][maxSize]; - - private final int dx, dy; - - public BlockPart(int dx, int dy){ - super("part_" + dx + "_" + dy); - this.dx = dx; - this.dy = dy; - solid = false; - hasPower = hasItems = hasLiquids = true; - parts[dx + maxSize/2][dy + maxSize/2] = this; - } - - 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]; - } - - @Override - public boolean acceptItem(Item item, Tile tile, Tile source){ - return tile.link().block().acceptItem(item, tile.link(), source); - } - - @Override - public void handleItem(Item item, Tile tile, Tile source){ - tile.link().block().handleItem(item, tile.link(), source); - } - - @Override - public void handleLiquid(Tile tile, Tile source, Liquid liquid, float amount){ - Block block = tile.link().block(); - block.handleLiquid(tile.link(), source, liquid, amount); - } - - @Override - public boolean acceptLiquid(Tile tile, Tile source, Liquid liquid, float amount){ - Block block = tile.link().block(); - return block.hasLiquids && block.acceptLiquid(tile.link(), source, liquid, amount); - } - - @Override - public Tile linked(Tile tile){ - Tile out = tile.getNearby(-dx, -dy); - return out == null ? tile : out; - } - - @Override - public void drawTeam(Tile tile){} - - @Override - public void draw(Tile tile){} - - @Override - public boolean synthetic(){ - return true; - } - - @Override - public boolean isHidden(){ - return true; - } - - @Override - public String toString(){ - return "BlockPart[" + dx + ", " + dy + "]"; - } - - -} diff --git a/core/src/mindustry/world/blocks/BuildBlock.java b/core/src/mindustry/world/blocks/BuildBlock.java index 68cbdf567a..ef7bc567aa 100644 --- a/core/src/mindustry/world/blocks/BuildBlock.java +++ b/core/src/mindustry/world/blocks/BuildBlock.java @@ -63,7 +63,7 @@ public class BuildBlock extends Block{ public static void onConstructFinish(Tile tile, Block block, int builderID, byte rotation, Team team, boolean skipConfig){ if(tile == null) return; float healthf = tile.entity == null ? 1f : tile.entity.healthf(); - tile.set(block, team, rotation); + tile.setBlock(block, team, (int)rotation); if(tile.entity != null){ tile.entity.health(block.health * healthf); } @@ -265,8 +265,8 @@ public class BuildBlock extends Block{ if(clampedAmount > 0 && accumulated > 0){ //if it's positive, add it to the core if(core != null){ - int accepting = core.tile().block().acceptStack(requirements[i].item, accumulated, core.tile(), builder); - core.tile().block().handleStack(requirements[i].item, accepting, core.tile(), builder); + int accepting = core.tile().block().acceptStack(core.tile(), requirements[i].item, accumulated, builder); + core.tile().block().handleStack(core.tile(), requirements[i].item, accepting, builder); accumulator[i] -= accepting; }else{ accumulator[i] -= accumulated; diff --git a/core/src/mindustry/world/blocks/RespawnBlock.java b/core/src/mindustry/world/blocks/RespawnBlock.java index 0379e44608..1ee3297219 100644 --- a/core/src/mindustry/world/blocks/RespawnBlock.java +++ b/core/src/mindustry/world/blocks/RespawnBlock.java @@ -10,6 +10,7 @@ import mindustry.world.*; import static mindustry.Vars.net; +//TODO remove ? public class RespawnBlock{ public static void drawRespawn(Tile tile, float heat, float progress, float time, Playerc player, UnitType to){ diff --git a/core/src/mindustry/world/blocks/defense/turrets/ItemTurret.java b/core/src/mindustry/world/blocks/defense/turrets/ItemTurret.java index 4293c2fd1a..88bf40fa0a 100644 --- a/core/src/mindustry/world/blocks/defense/turrets/ItemTurret.java +++ b/core/src/mindustry/world/blocks/defense/turrets/ItemTurret.java @@ -18,8 +18,6 @@ import mindustry.world.consumers.*; import mindustry.world.meta.*; import mindustry.world.meta.values.*; -import java.io.*; - import static mindustry.Vars.*; public class ItemTurret extends CooledTurret{ @@ -45,7 +43,7 @@ public class ItemTurret extends CooledTurret{ stats.add(BlockStat.ammo, new AmmoListValue<>(ammo)); consumes.add(new ConsumeItemFilter(i -> ammo.containsKey(i)){ @Override - public void build(Tile tile, Table table){ + public void build(Tilec tile, Table table){ MultiReqImage image = new MultiReqImage(); content.items().each(i -> filter.get(i) && (!state.isCampaign() || data.isUnlocked(i)), item -> image.add(new ReqImage(new ItemImage(item.icon(Cicon.medium)), () -> tile.entity != null && !((ItemTurretEntity)tile.entity).ammo.isEmpty() && ((ItemEntry)tile.ent().ammo.peek()).item == item))); @@ -72,7 +70,7 @@ public class ItemTurret extends CooledTurret{ //add first ammo item to cheaty blocks so they can shoot properly if(tile.isEnemyCheat() && ammo.size > 0){ - handleItem(ammo.entries().next().key, tile, tile); + handleItem(tile, tile, ammo.entries().next().key); } } @@ -87,7 +85,7 @@ public class ItemTurret extends CooledTurret{ } @Override - public int acceptStack(Item item, int amount, Tile tile, Teamc source){ + public int acceptStack(Tile tile, Item item, int amount, Teamc source){ TurretEntity entity = tile.ent(); BulletType type = ammo.get(item); @@ -98,9 +96,9 @@ public class ItemTurret extends CooledTurret{ } @Override - public void handleStack(Item item, int amount, Tile tile, Teamc source){ + public void handleStack(Tile tile, Item item, int amount, Teamc source){ for(int i = 0; i < amount; i++){ - handleItem(item, tile, null); + handleItem(tile, null, item); } } @@ -111,7 +109,7 @@ public class ItemTurret extends CooledTurret{ } @Override - public void handleItem(Item item, Tile tile, Tile source){ + public void handleItem(Tile tile, Tile source, Item item){ TurretEntity entity = tile.ent(); if(entity == null) return; @@ -144,7 +142,7 @@ public class ItemTurret extends CooledTurret{ } @Override - public boolean acceptItem(Item item, Tile tile, Tile source){ + public boolean acceptItem(Tile tile, Tile source, Item item){ TurretEntity entity = tile.ent(); return ammo != null && ammo.get(item) != null && entity.totalAmmo + ammo.get(item).ammoMultiplier <= maxAmmo; diff --git a/core/src/mindustry/world/blocks/defense/turrets/LiquidTurret.java b/core/src/mindustry/world/blocks/defense/turrets/LiquidTurret.java index ec0920387c..52e31321a3 100644 --- a/core/src/mindustry/world/blocks/defense/turrets/LiquidTurret.java +++ b/core/src/mindustry/world/blocks/defense/turrets/LiquidTurret.java @@ -123,7 +123,7 @@ public class LiquidTurret extends Turret{ } @Override - public boolean acceptItem(Item item, Tile tile, Tile source){ + public boolean acceptItem(Tile tile, Tile source, Item item){ return false; } diff --git a/core/src/mindustry/world/blocks/distribution/ArmoredConveyor.java b/core/src/mindustry/world/blocks/distribution/ArmoredConveyor.java index fb6eb261f9..b819f7dcc0 100644 --- a/core/src/mindustry/world/blocks/distribution/ArmoredConveyor.java +++ b/core/src/mindustry/world/blocks/distribution/ArmoredConveyor.java @@ -10,8 +10,8 @@ public class ArmoredConveyor extends Conveyor{ } @Override - public boolean acceptItem(Item item, Tile tile, Tile source){ - return super.acceptItem(item, tile, source) && (source.block() instanceof Conveyor || Edges.getFacingEdge(source, tile).relativeTo(tile) == tile.rotation()); + public boolean acceptItem(Tile tile, Tile source, Item item){ + return super.acceptItem(tile, source, item) && (source.block() instanceof Conveyor || Edges.getFacingEdge(source, tile).relativeTo(tile) == tile.rotation()); } @Override diff --git a/core/src/mindustry/world/blocks/distribution/BufferedItemBridge.java b/core/src/mindustry/world/blocks/distribution/BufferedItemBridge.java index 6171141034..5cc63008a3 100644 --- a/core/src/mindustry/world/blocks/distribution/BufferedItemBridge.java +++ b/core/src/mindustry/world/blocks/distribution/BufferedItemBridge.java @@ -5,8 +5,6 @@ import arc.util.io.*; import mindustry.type.*; import mindustry.world.*; -import java.io.*; - public class BufferedItemBridge extends ExtendingItemBridge{ public final int timerAccept = timers++; @@ -29,9 +27,9 @@ public class BufferedItemBridge extends ExtendingItemBridge{ } Item item = entity.buffer.poll(); - if(entity.timer(timerAccept, 4) && item != null && other.block().acceptItem(item, other, tile)){ + if(entity.timer(timerAccept, 4) && item != null && other.block().acceptItem(other, tile, item)){ entity.cycleSpeed = Mathf.lerpDelta(entity.cycleSpeed, 4f, 0.05f); - other.block().handleItem(item, other, tile); + other.block().handleItem(other, tile, item); entity.buffer.remove(); }else{ entity.cycleSpeed = Mathf.lerpDelta(entity.cycleSpeed, 0f, 0.008f); diff --git a/core/src/mindustry/world/blocks/distribution/Conveyor.java b/core/src/mindustry/world/blocks/distribution/Conveyor.java index 0d5e980351..3de051d7cc 100644 --- a/core/src/mindustry/world/blocks/distribution/Conveyor.java +++ b/core/src/mindustry/world/blocks/distribution/Conveyor.java @@ -19,8 +19,6 @@ import mindustry.world.*; import mindustry.world.blocks.*; import mindustry.world.meta.*; -import java.io.*; - import static mindustry.Vars.*; public class Conveyor extends Block implements Autotiler{ @@ -251,18 +249,18 @@ public class Conveyor extends Block implements Autotiler{ } @Override - public void getStackOffset(Item item, Tile tile, Vec2 trns){ + public void getStackOffset(Tile tile, Item item, Vec2 trns){ trns.trns(tile.rotation() * 90 + 180f, tilesize / 2f); } @Override - public int acceptStack(Item item, int amount, Tile tile, Teamc source){ + public int acceptStack(Tile tile, Item item, int amount, Teamc source){ ConveyorEntity entity = tile.ent(); return Math.min((int)(entity.minitem / itemSpace), amount); } @Override - public void handleStack(Item item, int amount, Tile tile, Teamc source){ + public void handleStack(Tile tile, Item item, int amount, Teamc source){ ConveyorEntity e = tile.ent(); amount = Math.min(amount, itemCapacity - e.len); @@ -278,7 +276,7 @@ public class Conveyor extends Block implements Autotiler{ } @Override - public boolean acceptItem(Item item, Tile tile, Tile source){ + public boolean acceptItem(Tile tile, Tile source, Item item){ ConveyorEntity e = tile.ent(); if(e.len >= capacity) return false; int direction = source == null ? 0 : Math.abs(source.relativeTo(tile.x, tile.y) - tile.rotation()); @@ -286,7 +284,7 @@ public class Conveyor extends Block implements Autotiler{ } @Override - public void handleItem(Item item, Tile tile, Tile source){ + public void handleItem(Tile tile, Tile source, Item item){ ConveyorEntity e = tile.ent(); if(e.len >= capacity) return; diff --git a/core/src/mindustry/world/blocks/distribution/ItemBridge.java b/core/src/mindustry/world/blocks/distribution/ItemBridge.java index f244fee5de..54f0b9c3eb 100644 --- a/core/src/mindustry/world/blocks/distribution/ItemBridge.java +++ b/core/src/mindustry/world/blocks/distribution/ItemBridge.java @@ -200,8 +200,8 @@ public class ItemBridge extends Block{ if(entity.uptime >= 0.5f && entity.timer(timerTransport, transportTime)){ Item item = entity.items().take(); - if(item != null && other.block().acceptItem(item, other, tile)){ - other.block().handleItem(item, other, tile); + if(item != null && other.block().acceptItem(other, tile, item)){ + other.block().handleItem(other, tile, item); entity.cycleSpeed = Mathf.lerpDelta(entity.cycleSpeed, 4f, 0.05f); }else{ entity.cycleSpeed = Mathf.lerpDelta(entity.cycleSpeed, 1f, 0.01f); @@ -252,7 +252,7 @@ public class ItemBridge extends Block{ } @Override - public boolean acceptItem(Item item, Tile tile, Tile source){ + public boolean acceptItem(Tile tile, Tile source, Item item){ if(tile.team() != source.team()) return false; ItemBridgeEntity entity = tile.ent(); diff --git a/core/src/mindustry/world/blocks/distribution/Junction.java b/core/src/mindustry/world/blocks/distribution/Junction.java index cb26a2e936..76f76ca1ea 100644 --- a/core/src/mindustry/world/blocks/distribution/Junction.java +++ b/core/src/mindustry/world/blocks/distribution/Junction.java @@ -10,8 +10,6 @@ import mindustry.world.DirectionalItemBuffer; import mindustry.world.Tile; import mindustry.world.meta.BlockGroup; -import java.io.IOException; - import static mindustry.Vars.content; public class Junction extends Block{ @@ -28,7 +26,7 @@ public class Junction extends Block{ } @Override - public int acceptStack(Item item, int amount, Tile tile, Teamc source){ + public int acceptStack(Tile tile, Item item, int amount, Teamc source){ return 0; } @@ -55,11 +53,11 @@ public class Junction extends Block{ if(dest != null) dest = dest.link(); //skip blocks that don't want the item, keep waiting until they do - if(dest == null || !dest.block().acceptItem(item, dest, tile) || dest.team() != tile.team()){ + if(dest == null || !dest.block().acceptItem(dest, tile, item) || dest.team() != tile.team()){ continue; } - dest.block().handleItem(item, dest, tile); + dest.block().handleItem(dest, tile, item); System.arraycopy(buffer.buffers[i], 1, buffer.buffers[i], 0, buffer.indexes[i] - 1); buffer.indexes[i] --; } @@ -68,14 +66,14 @@ public class Junction extends Block{ } @Override - public void handleItem(Item item, Tile tile, Tile source){ + public void handleItem(Tile tile, Tile source, Item item){ JunctionEntity entity = tile.ent(); int relative = source.relativeTo(tile.x, tile.y); entity.buffer.accept(relative, item); } @Override - public boolean acceptItem(Item item, Tile tile, Tile source){ + public boolean acceptItem(Tile tile, Tile source, Item item){ JunctionEntity entity = tile.ent(); int relative = source.relativeTo(tile.x, tile.y); diff --git a/core/src/mindustry/world/blocks/distribution/MassDriver.java b/core/src/mindustry/world/blocks/distribution/MassDriver.java index 595accecf9..b074717070 100644 --- a/core/src/mindustry/world/blocks/distribution/MassDriver.java +++ b/core/src/mindustry/world/blocks/distribution/MassDriver.java @@ -221,7 +221,7 @@ public class MassDriver extends Block{ } @Override - public boolean acceptItem(Item item, Tile tile, Tile source){ + public boolean acceptItem(Tile tile, Tile source, Item item){ //mass drivers that ouput only cannot accept items return tile.entity.items().total() < itemCapacity && linkValid(tile); } diff --git a/core/src/mindustry/world/blocks/distribution/OverflowGate.java b/core/src/mindustry/world/blocks/distribution/OverflowGate.java index 80562f81f3..be3bea308c 100644 --- a/core/src/mindustry/world/blocks/distribution/OverflowGate.java +++ b/core/src/mindustry/world/blocks/distribution/OverflowGate.java @@ -30,7 +30,7 @@ public class OverflowGate extends Block{ } @Override - public int acceptStack(Item item, int amount, Tile tile, Teamc source){ + public int acceptStack(Tile tile, Item item, int amount, Teamc source){ return 0; } @@ -63,7 +63,7 @@ public class OverflowGate extends Block{ if(target != null && (entity.time >= 1f)){ getTileTarget(tile, entity.lastItem, entity.lastInput, true); - target.block().handleItem(entity.lastItem, target, Edges.getFacingEdge(tile, target)); + target.block().handleItem(target, Edges.getFacingEdge(tile, target), entity.lastItem); entity.items().remove(entity.lastItem, 1); entity.lastItem = null; } @@ -71,14 +71,14 @@ public class OverflowGate extends Block{ } @Override - public boolean acceptItem(Item item, Tile tile, Tile source){ + public boolean acceptItem(Tile tile, Tile source, Item item){ OverflowGateEntity entity = tile.ent(); return tile.team() == source.team() && entity.lastItem == null && entity.items().total() == 0; } @Override - public void handleItem(Item item, Tile tile, Tile source){ + public void handleItem(Tile tile, Tile source, Item item){ OverflowGateEntity entity = tile.ent(); entity.items().add(item, 1); entity.lastItem = item; @@ -94,13 +94,13 @@ public class OverflowGate extends Block{ Tile to = tile.getNearby((from + 2) % 4); if(to == null) return null; Tile edge = Edges.getFacingEdge(tile, to); - boolean canForward = to.block().acceptItem(item, to, edge) && to.team() == tile.team() && !(to.block() instanceof OverflowGate); + boolean canForward = to.block().acceptItem(to, edge, item) && to.team() == tile.team() && !(to.block() instanceof OverflowGate); if(!canForward || invert){ Tile a = tile.getNearby(Mathf.mod(from - 1, 4)); Tile b = tile.getNearby(Mathf.mod(from + 1, 4)); - boolean ac = a != null && a.block().acceptItem(item, a, edge) && !(a.block() instanceof OverflowGate) && a.team() == tile.team(); - boolean bc = b != null && b.block().acceptItem(item, b, edge) && !(b.block() instanceof OverflowGate) && b.team() == tile.team(); + boolean ac = a != null && a.block().acceptItem(a, edge, item) && !(a.block() instanceof OverflowGate) && a.team() == tile.team(); + boolean bc = b != null && b.block().acceptItem(b, edge, item) && !(b.block() instanceof OverflowGate) && b.team() == tile.team(); if(!ac && !bc){ return invert && canForward ? to : null; diff --git a/core/src/mindustry/world/blocks/distribution/Router.java b/core/src/mindustry/world/blocks/distribution/Router.java index 6058d80de7..ec655a5edd 100644 --- a/core/src/mindustry/world/blocks/distribution/Router.java +++ b/core/src/mindustry/world/blocks/distribution/Router.java @@ -36,7 +36,7 @@ public class Router extends Block{ if(target != null && (entity.time >= 1f || !(target.block() instanceof Router))){ getTileTarget(tile, entity.lastItem, entity.lastInput, true); - target.block().handleItem(entity.lastItem, target, Edges.getFacingEdge(tile, target)); + target.block().handleItem(target, Edges.getFacingEdge(tile, target), entity.lastItem); entity.items().remove(entity.lastItem, 1); entity.lastItem = null; } @@ -44,14 +44,14 @@ public class Router extends Block{ } @Override - public boolean acceptItem(Item item, Tile tile, Tile source){ + public boolean acceptItem(Tile tile, Tile source, Item item){ RouterEntity entity = tile.ent(); return tile.team() == source.team() && entity.lastItem == null && entity.items().total() == 0; } @Override - public void handleItem(Item item, Tile tile, Tile source){ + public void handleItem(Tile tile, Tile source, Item item){ RouterEntity entity = tile.ent(); entity.items().add(item, 1); entity.lastItem = item; @@ -66,7 +66,7 @@ public class Router extends Block{ Tile other = proximity.get((i + counter) % proximity.size); if(set) tile.rotation((byte)((tile.rotation() + 1) % proximity.size)); if(other == from && from.block() == Blocks.overflowGate) continue; - if(other.block().acceptItem(item, other, Edges.getFacingEdge(tile, other))){ + if(other.block().acceptItem(other, Edges.getFacingEdge(tile, other), item)){ return other; } } diff --git a/core/src/mindustry/world/blocks/distribution/Sorter.java b/core/src/mindustry/world/blocks/distribution/Sorter.java index c2fa20efd7..6179ca9464 100644 --- a/core/src/mindustry/world/blocks/distribution/Sorter.java +++ b/core/src/mindustry/world/blocks/distribution/Sorter.java @@ -77,17 +77,17 @@ public class Sorter extends Block{ } @Override - public boolean acceptItem(Item item, Tile tile, Tile source){ + public boolean acceptItem(Tile tile, Tile source, Item item){ Tile to = getTileTarget(item, tile, source, false); - return to != null && to.block().acceptItem(item, to, tile) && to.team() == tile.team(); + return to != null && to.block().acceptItem(to, tile, item) && to.team() == tile.team(); } @Override - public void handleItem(Item item, Tile tile, Tile source){ + public void handleItem(Tile tile, Tile source, Item item){ Tile to = getTileTarget(item, tile, source, true); - to.block().handleItem(item, to, tile); + to.block().handleItem(to, tile, item); } boolean isSame(Tile tile, Tile other){ @@ -112,9 +112,9 @@ public class Sorter extends Block{ Tile a = dest.getNearby(Mathf.mod(dir - 1, 4)); Tile b = dest.getNearby(Mathf.mod(dir + 1, 4)); boolean ac = a != null && !(a.block().instantTransfer && source.block().instantTransfer) && - a.block().acceptItem(item, a, dest); + a.block().acceptItem(a, dest, item); boolean bc = b != null && !(b.block().instantTransfer && source.block().instantTransfer) && - b.block().acceptItem(item, b, dest); + b.block().acceptItem(b, dest, item); if(ac && !bc){ to = a; diff --git a/core/src/mindustry/world/blocks/liquid/LiquidBridge.java b/core/src/mindustry/world/blocks/liquid/LiquidBridge.java index 2f43129858..32828c44c7 100644 --- a/core/src/mindustry/world/blocks/liquid/LiquidBridge.java +++ b/core/src/mindustry/world/blocks/liquid/LiquidBridge.java @@ -54,7 +54,7 @@ public class LiquidBridge extends ItemBridge{ } @Override - public boolean acceptItem(Item item, Tile tile, Tile source){ + public boolean acceptItem(Tile tile, Tile source, Item item){ return false; } } diff --git a/core/src/mindustry/world/blocks/liquid/LiquidExtendingBridge.java b/core/src/mindustry/world/blocks/liquid/LiquidExtendingBridge.java index f3baf6283a..8b34b2e942 100644 --- a/core/src/mindustry/world/blocks/liquid/LiquidExtendingBridge.java +++ b/core/src/mindustry/world/blocks/liquid/LiquidExtendingBridge.java @@ -49,7 +49,7 @@ public class LiquidExtendingBridge extends ExtendingItemBridge{ } @Override - public boolean acceptItem(Item item, Tile tile, Tile source){ + public boolean acceptItem(Tile tile, Tile source, Item item){ return false; } } diff --git a/core/src/mindustry/world/blocks/power/PowerGraph.java b/core/src/mindustry/world/blocks/power/PowerGraph.java index c3ea54ad9e..eeaf66425c 100644 --- a/core/src/mindustry/world/blocks/power/PowerGraph.java +++ b/core/src/mindustry/world/blocks/power/PowerGraph.java @@ -1,22 +1,22 @@ package mindustry.world.blocks.power; import arc.*; -import arc.struct.*; import arc.math.*; +import arc.struct.*; import arc.util.*; -import mindustry.world.*; +import mindustry.gen.*; import mindustry.world.consumers.*; public class PowerGraph{ - private final static Queue queue = new Queue<>(); - private final static Array outArray1 = new Array<>(); - private final static Array outArray2 = new Array<>(); + private final static Queue queue = new Queue<>(); + private final static Array outArray1 = new Array<>(); + private final static Array outArray2 = new Array<>(); private final static IntSet closedSet = new IntSet(); - private final ObjectSet producers = new ObjectSet<>(); - private final ObjectSet consumers = new ObjectSet<>(); - private final ObjectSet batteries = new ObjectSet<>(); - private final ObjectSet all = new ObjectSet<>(); + private final ObjectSet producers = new ObjectSet<>(); + private final ObjectSet consumers = new ObjectSet<>(); + private final ObjectSet batteries = new ObjectSet<>(); + private final ObjectSet all = new ObjectSet<>(); private final WindowedMean powerBalance = new WindowedMean(60); private float lastPowerProduced, lastPowerNeeded, lastUsageFraction; @@ -62,21 +62,21 @@ public class PowerGraph{ public float getPowerProduced(){ float powerProduced = 0f; - for(Tile producer : producers){ + for(Tilec producer : producers){ if(producer.entity == null) continue; - powerProduced += producer.block().getPowerProduction(producer) * producer.entity.delta(); + powerProduced += producer.block().getPowerProduction(producer) * producer.delta(); } return powerProduced; } public float getPowerNeeded(){ float powerNeeded = 0f; - for(Tile consumer : consumers){ + for(Tilec consumer : consumers){ Consumers consumes = consumer.block().consumes; if(consumes.hasPower()){ ConsumePower consumePower = consumes.getPower(); if(otherConsumersAreValid(consumer, consumePower)){ - powerNeeded += consumePower.requestedPower(consumer.entity) * consumer.entity.delta(); + powerNeeded += consumePower.requestedPower(consumer) * consumer.delta(); } } } @@ -85,10 +85,10 @@ public class PowerGraph{ public float getBatteryStored(){ float totalAccumulator = 0f; - for(Tile battery : batteries){ + for(Tilec battery : batteries){ Consumers consumes = battery.block().consumes; if(consumes.hasPower()){ - totalAccumulator += battery.entity.power().status * consumes.getPower().capacity; + totalAccumulator += battery.power().status * consumes.getPower().capacity; } } return totalAccumulator; @@ -96,10 +96,10 @@ public class PowerGraph{ public float getBatteryCapacity(){ float totalCapacity = 0f; - for(Tile battery : batteries){ + for(Tilec battery : batteries){ if(battery.block().consumes.hasPower()){ ConsumePower power = battery.block().consumes.getPower(); - totalCapacity += (1f - battery.entity.power().status) * power.capacity; + totalCapacity += (1f - battery.power().status) * power.capacity; } } return totalCapacity; @@ -107,7 +107,7 @@ public class PowerGraph{ public float getTotalBatteryCapacity(){ float totalCapacity = 0f; - for(Tile battery : batteries){ + for(Tilec battery : batteries){ if(battery.block().consumes.hasPower()){ totalCapacity += battery.block().consumes.getPower().capacity; } @@ -121,10 +121,10 @@ public class PowerGraph{ float used = Math.min(stored, needed); float consumedPowerPercentage = Math.min(1.0f, needed / stored); - for(Tile battery : batteries){ + for(Tilec battery : batteries){ Consumers consumes = battery.block().consumes; if(consumes.hasPower()){ - battery.entity.power().status *= (1f-consumedPowerPercentage); + battery.power().status *= (1f-consumedPowerPercentage); } } return used; @@ -136,12 +136,12 @@ public class PowerGraph{ float chargedPercent = Math.min(excess/capacity, 1f); if(Mathf.equal(capacity, 0f)) return 0f; - for(Tile battery : batteries){ + for(Tilec battery : batteries){ Consumers consumes = battery.block().consumes; if(consumes.hasPower()){ ConsumePower consumePower = consumes.getPower(); if(consumePower.capacity > 0f){ - battery.entity.power().status += (1f-battery.entity.power().status) * chargedPercent; + battery.power().status += (1f-battery.power().status) * chargedPercent; } } } @@ -151,25 +151,25 @@ public class PowerGraph{ public void distributePower(float needed, float produced){ //distribute even if not needed. this is because some might be requiring power but not using it; it updates consumers float coverage = Mathf.zero(needed) && Mathf.zero(produced) ? 0f : Mathf.zero(needed) ? 1f : Math.min(1, produced / needed); - for(Tile consumer : consumers){ + for(Tilec consumer : consumers){ Consumers consumes = consumer.block().consumes; if(consumes.hasPower()){ ConsumePower consumePower = consumes.getPower(); if(consumePower.buffered){ if(!Mathf.zero(consumePower.capacity)){ // Add an equal percentage of power to all buffers, based on the global power coverage in this graph - float maximumRate = consumePower.requestedPower(consumer.entity) * coverage * consumer.entity.delta(); - consumer.entity.power().status = Mathf.clamp(consumer.entity.power().status + maximumRate / consumePower.capacity); + float maximumRate = consumePower.requestedPower(consumer) * coverage * consumer.delta(); + consumer.power().status = Mathf.clamp(consumer.power().status + maximumRate / consumePower.capacity); } }else{ //valid consumers get power as usual if(otherConsumersAreValid(consumer, consumePower)){ - consumer.entity.power().status = coverage; + consumer.power().status = coverage; }else{ //invalid consumers get an estimate, if they were to activate - consumer.entity.power().status = Math.min(1, produced / (needed + consumePower.usage * consumer.entity.delta())); + consumer.power().status = Math.min(1, produced / (needed + consumePower.usage * consumer.delta())); //just in case - if(Float.isNaN(consumer.entity.power().status)){ - consumer.entity.power().status = 0f; + if(Float.isNaN(consumer.power().status)){ + consumer.power().status = 0f; } } } @@ -180,10 +180,10 @@ public class PowerGraph{ public void update(){ if(Core.graphics.getFrameId() == lastFrameUpdated){ return; - }else if(!consumers.isEmpty() && consumers.first().isEnemyCheat()){ + }else if(!consumers.isEmpty() && consumers.first().tile().isEnemyCheat()){ //when cheating, just set status to 1 - for(Tile tile : consumers){ - tile.entity.power().status = 1f; + for(Tilec tile : consumers){ + tile.power().status = 1f; } lastPowerNeeded = lastPowerProduced = lastUsageFraction = 1f; @@ -224,14 +224,14 @@ public class PowerGraph{ } public void add(PowerGraph graph){ - for(Tile tile : graph.all){ + for(Tilec tile : graph.all){ add(tile); } } - public void add(Tile tile){ - if(tile.entity == null || tile.entity.power() == null) return; - tile.entity.power().graph = this; + public void add(Tilec tile){ + if(tile.entity == null || tile.power() == null) return; + tile.power().graph = this; all.add(tile); if(tile.block().outputsPower && tile.block().consumesPower && !tile.block().consumes.getPower().buffered){ @@ -246,14 +246,14 @@ public class PowerGraph{ } } - public void reflow(Tile tile){ + public void reflow(Tilec tile){ queue.clear(); queue.addLast(tile); closedSet.clear(); while(queue.size > 0){ - Tile child = queue.removeFirst(); + Tilec child = queue.removeFirst(); add(child); - for(Tile next : child.block().getPowerConnections(child, outArray2)){ + for(Tilec next : child.block().getPowerConnections(child, outArray2)){ if(!closedSet.contains(next.pos())){ queue.addLast(next); closedSet.add(next.pos()); @@ -262,22 +262,22 @@ public class PowerGraph{ } } - private void removeSingle(Tile tile){ + private void removeSingle(Tilec tile){ all.remove(tile); producers.remove(tile); consumers.remove(tile); batteries.remove(tile); } - public void remove(Tile tile){ + public void remove(Tilec tile){ removeSingle(tile); //begin by clearing the closed set closedSet.clear(); //go through all the connections of this tile - for(Tile other : tile.block().getPowerConnections(tile, outArray1)){ + for(Tilec other : tile.block().getPowerConnections(tile, outArray1)){ //a graph has already been assigned to this tile from a previous call, skip it - if(other.entity.power().graph != this) continue; + if(other.power().graph != this) continue; //create graph for this branch PowerGraph graph = new PowerGraph(); @@ -287,16 +287,16 @@ public class PowerGraph{ queue.addLast(other); while(queue.size > 0){ //get child from queue - Tile child = queue.removeFirst(); + Tilec child = queue.removeFirst(); //remove it from this graph removeSingle(child); //add it to the new branch graph graph.add(child); //go through connections - for(Tile next : child.block().getPowerConnections(child, outArray2)){ + for(Tilec next : child.block().getPowerConnections(child, outArray2)){ //make sure it hasn't looped back, and that the new graph being assigned hasn't already been assigned //also skip closed tiles - if(next != tile && next.entity.power().graph != graph && !closedSet.contains(next.pos())){ + if(next != tile && next.power().graph != graph && !closedSet.contains(next.pos())){ queue.addLast(next); closedSet.add(next.pos()); } @@ -307,9 +307,9 @@ public class PowerGraph{ } } - private boolean otherConsumersAreValid(Tile tile, Consume consumePower){ + private boolean otherConsumersAreValid(Tilec tile, Consume consumePower){ for(Consume cons : tile.block().consumes.all()){ - if(cons != consumePower && !cons.isOptional() && !cons.valid(tile.ent())){ + if(cons != consumePower && !cons.isOptional() && !cons.valid(tile)){ return false; } } diff --git a/core/src/mindustry/world/blocks/power/PowerNode.java b/core/src/mindustry/world/blocks/power/PowerNode.java index 5869854b9d..5a1a1b5d29 100644 --- a/core/src/mindustry/world/blocks/power/PowerNode.java +++ b/core/src/mindustry/world/blocks/power/PowerNode.java @@ -313,12 +313,12 @@ public class PowerNode extends PowerBlock{ return tile.entity.power().links.contains(other.pos()); } - public boolean linkValid(Tile tile, Tile link){ + public boolean linkValid(Tilec tile, Tilec link){ return linkValid(tile, link, true); } - public boolean linkValid(Tile tile, Tile link, boolean checkMaxNodes){ - if(tile == link || link == null || link.entity == null || tile.entity == null || !link.block().hasPower || tile.team() != link.team()) return false; + public boolean linkValid(Tilec tile, Tilec link, boolean checkMaxNodes){ + if(tile == link || link == null || !link.block().hasPower || tile.team() != link.team()) return false; if(overlaps(tile, link, laserRange * tilesize) || (link.block() instanceof PowerNode && overlaps(link, tile, link.cblock().laserRange * tilesize))){ if(checkMaxNodes && link.block() instanceof PowerNode){ @@ -369,8 +369,8 @@ public class PowerNode extends PowerBlock{ Draw.color(); } - public static boolean insulated(Tile tile, Tile other){ - return insulated(tile.x, tile.y, other.x, other.y); + public static boolean insulated(Tilec tile, Tilec other){ + return insulated(tile.tileX(), tile.tileY(), other.tileX(), other.tileY()); } public static boolean insulated(int x, int y, int x2, int y2){ diff --git a/core/src/mindustry/world/blocks/production/GenericCrafter.java b/core/src/mindustry/world/blocks/production/GenericCrafter.java index 657e100ec5..7b0c83b331 100644 --- a/core/src/mindustry/world/blocks/production/GenericCrafter.java +++ b/core/src/mindustry/world/blocks/production/GenericCrafter.java @@ -59,8 +59,8 @@ public class GenericCrafter extends Block{ } @Override - public boolean shouldIdleSound(Tile tile){ - return tile.entity.cons().valid(); + public boolean shouldIdleSound(Tilec tile){ + return tile.cons().valid(); } @Override diff --git a/core/src/mindustry/world/blocks/production/Incinerator.java b/core/src/mindustry/world/blocks/production/Incinerator.java index 5064d61702..d1b223b98c 100644 --- a/core/src/mindustry/world/blocks/production/Incinerator.java +++ b/core/src/mindustry/world/blocks/production/Incinerator.java @@ -59,14 +59,14 @@ public class Incinerator extends Block{ } @Override - public void handleItem(Item item, Tile tile, Tile source){ + public void handleItem(Tile tile, Tile source, Item item){ if(Mathf.chance(0.3)){ effect.at(tile.drawx(), tile.drawy()); } } @Override - public boolean acceptItem(Item item, Tile tile, Tile source){ + public boolean acceptItem(Tile tile, Tile source, Item item){ IncineratorEntity entity = tile.ent(); return entity.heat > 0.5f; } diff --git a/core/src/mindustry/world/blocks/sandbox/ItemSource.java b/core/src/mindustry/world/blocks/sandbox/ItemSource.java index c94374da77..083207ed33 100644 --- a/core/src/mindustry/world/blocks/sandbox/ItemSource.java +++ b/core/src/mindustry/world/blocks/sandbox/ItemSource.java @@ -82,7 +82,7 @@ public class ItemSource extends Block{ } @Override - public boolean acceptItem(Item item, Tile tile, Tile source){ + public boolean acceptItem(Tile tile, Tile source, Item item){ return false; } diff --git a/core/src/mindustry/world/blocks/sandbox/ItemVoid.java b/core/src/mindustry/world/blocks/sandbox/ItemVoid.java index 1271cbac6f..9e6ced5041 100644 --- a/core/src/mindustry/world/blocks/sandbox/ItemVoid.java +++ b/core/src/mindustry/world/blocks/sandbox/ItemVoid.java @@ -12,11 +12,11 @@ public class ItemVoid extends Block{ } @Override - public void handleItem(Item item, Tile tile, Tile source){ + public void handleItem(Tile tile, Tile source, Item item){ } @Override - public boolean acceptItem(Item item, Tile tile, Tile source){ + public boolean acceptItem(Tile tile, Tile source, Item item){ return true; } } diff --git a/core/src/mindustry/world/blocks/storage/CoreBlock.java b/core/src/mindustry/world/blocks/storage/CoreBlock.java index c769e592d6..7dec61ac8b 100644 --- a/core/src/mindustry/world/blocks/storage/CoreBlock.java +++ b/core/src/mindustry/world/blocks/storage/CoreBlock.java @@ -68,7 +68,7 @@ public class CoreBlock extends StorageBlock{ } @Override - public boolean acceptItem(Item item, Tile tile, Tile source){ + public boolean acceptItem(Tile tile, Tile source, Item item){ return tile.entity.items().get(item) < getMaximumAccepted(tile, item); } @@ -191,9 +191,9 @@ public class CoreBlock extends StorageBlock{ } @Override - public void handleItem(Item item, Tile tile, Tile source){ + public void handleItem(Tile tile, Tile source, Item item){ if(net.server() || !net.active()){ - super.handleItem(item, tile, source); + super.handleItem(tile, source, item); if(state.rules.tutorial){ Events.fire(new CoreItemDeliverEvent()); } diff --git a/core/src/mindustry/world/blocks/storage/LaunchPad.java b/core/src/mindustry/world/blocks/storage/LaunchPad.java index d33e5f0041..3c011cda8b 100644 --- a/core/src/mindustry/world/blocks/storage/LaunchPad.java +++ b/core/src/mindustry/world/blocks/storage/LaunchPad.java @@ -38,7 +38,7 @@ public class LaunchPad extends StorageBlock{ } @Override - public boolean acceptItem(Item item, Tile tile, Tile source){ + public boolean acceptItem(Tile tile, Tile source, Item item){ return item.type == ItemType.material && tile.entity.items().total() < itemCapacity; } diff --git a/core/src/mindustry/world/blocks/storage/StorageBlock.java b/core/src/mindustry/world/blocks/storage/StorageBlock.java index 297bee427e..fec2b942c0 100644 --- a/core/src/mindustry/world/blocks/storage/StorageBlock.java +++ b/core/src/mindustry/world/blocks/storage/StorageBlock.java @@ -15,9 +15,9 @@ public abstract class StorageBlock extends Block{ } @Override - public boolean acceptItem(Item item, Tile tile, Tile source){ + public boolean acceptItem(Tile tile, Tile source, Item item){ StorageBlockEntity entity = tile.ent(); - return entity.linkedCore != null ? entity.linkedCore.block().acceptItem(item, entity.linkedCore, source) : tile.entity.items().get(item) < getMaximumAccepted(tile, item); + return entity.linkedCore != null ? entity.linkedCore.block().acceptItem(entity.linkedCore, source, item) : tile.entity.items().get(item) < getMaximumAccepted(tile, item); } @Override diff --git a/core/src/mindustry/world/consumers/Consume.java b/core/src/mindustry/world/consumers/Consume.java index 76827379d6..cfcd77f708 100644 --- a/core/src/mindustry/world/consumers/Consume.java +++ b/core/src/mindustry/world/consumers/Consume.java @@ -3,7 +3,6 @@ package mindustry.world.consumers; import arc.struct.*; import arc.scene.ui.layout.Table; import mindustry.gen.*; -import mindustry.world.Tile; import mindustry.world.meta.BlockStats; /** An abstract class that defines a type of resource that a block can consume. */ @@ -59,7 +58,7 @@ public abstract class Consume{ public abstract ConsumeType type(); - public abstract void build(Tile tile, Table table); + public abstract void build(Tilec tile, Table table); /** Called when a consumption is triggered manually. */ public void trigger(Tilec entity){ diff --git a/core/src/mindustry/world/consumers/ConsumeItemFilter.java b/core/src/mindustry/world/consumers/ConsumeItemFilter.java index 9a3a011882..987b201151 100644 --- a/core/src/mindustry/world/consumers/ConsumeItemFilter.java +++ b/core/src/mindustry/world/consumers/ConsumeItemFilter.java @@ -8,7 +8,6 @@ import mindustry.gen.*; import mindustry.type.*; import mindustry.ui.*; import mindustry.ui.Cicon; -import mindustry.world.*; import mindustry.world.meta.*; import mindustry.world.meta.values.*; @@ -33,7 +32,7 @@ public class ConsumeItemFilter extends Consume{ } @Override - public void build(Tile tile, Table table){ + public void build(Tilec tile, Table table){ MultiReqImage image = new MultiReqImage(); content.items().each(i -> filter.get(i) && (!state.isCampaign() || data.isUnlocked(i)), item -> image.add(new ReqImage(new ItemImage(item.icon(Cicon.medium), 1), () -> tile.entity != null && tile.entity.items() != null && tile.entity.items().has(item)))); diff --git a/core/src/mindustry/world/consumers/ConsumeItems.java b/core/src/mindustry/world/consumers/ConsumeItems.java index aa604ff969..66d77718de 100644 --- a/core/src/mindustry/world/consumers/ConsumeItems.java +++ b/core/src/mindustry/world/consumers/ConsumeItems.java @@ -7,7 +7,6 @@ import mindustry.gen.*; import mindustry.type.*; import mindustry.ui.*; import mindustry.ui.Cicon; -import mindustry.world.*; import mindustry.world.meta.*; import mindustry.world.meta.values.*; @@ -36,7 +35,7 @@ public class ConsumeItems extends Consume{ } @Override - public void build(Tile tile, Table table){ + public void build(Tilec tile, Table table){ for(ItemStack stack : items){ table.add(new ReqImage(new ItemImage(stack.item.icon(Cicon.medium), stack.amount), () -> tile.entity != null && tile.entity.items() != null && tile.entity.items().has(stack.item, stack.amount))).size(8 * 4).padRight(5); } diff --git a/core/src/mindustry/world/consumers/ConsumeLiquid.java b/core/src/mindustry/world/consumers/ConsumeLiquid.java index a4de0a3b52..984dd5ba66 100644 --- a/core/src/mindustry/world/consumers/ConsumeLiquid.java +++ b/core/src/mindustry/world/consumers/ConsumeLiquid.java @@ -7,7 +7,6 @@ import mindustry.gen.*; import mindustry.type.*; import mindustry.ui.*; import mindustry.ui.Cicon; -import mindustry.world.*; import mindustry.world.meta.*; public class ConsumeLiquid extends ConsumeLiquidBase{ @@ -28,7 +27,7 @@ public class ConsumeLiquid extends ConsumeLiquidBase{ } @Override - public void build(Tile tile, Table table){ + public void build(Tilec tile, Table table){ table.add(new ReqImage(liquid.icon(Cicon.medium), () -> valid(tile.entity))).size(8 * 4); } diff --git a/core/src/mindustry/world/consumers/ConsumeLiquidFilter.java b/core/src/mindustry/world/consumers/ConsumeLiquidFilter.java index 2fb844a827..df9656803d 100644 --- a/core/src/mindustry/world/consumers/ConsumeLiquidFilter.java +++ b/core/src/mindustry/world/consumers/ConsumeLiquidFilter.java @@ -8,7 +8,6 @@ import mindustry.type.Liquid; import mindustry.ui.Cicon; import mindustry.ui.MultiReqImage; import mindustry.ui.ReqImage; -import mindustry.world.Tile; import mindustry.world.meta.BlockStat; import mindustry.world.meta.BlockStats; import mindustry.world.meta.values.LiquidFilterValue; @@ -29,7 +28,7 @@ public class ConsumeLiquidFilter extends ConsumeLiquidBase{ } @Override - public void build(Tile tile, Table table){ + public void build(Tilec tile, Table table){ Array list = content.liquids().select(l -> !l.isHidden() && filter.get(l)); MultiReqImage image = new MultiReqImage(); list.each(liquid -> image.add(new ReqImage(liquid.icon(Cicon.medium), () -> tile.entity != null && tile.entity.liquids() != null && tile.entity.liquids().get(liquid) >= use(tile.entity)))); diff --git a/core/src/mindustry/world/consumers/ConsumePower.java b/core/src/mindustry/world/consumers/ConsumePower.java index 630add2ca7..2aa7b924b8 100644 --- a/core/src/mindustry/world/consumers/ConsumePower.java +++ b/core/src/mindustry/world/consumers/ConsumePower.java @@ -3,7 +3,6 @@ package mindustry.world.consumers; import arc.math.Mathf; import arc.scene.ui.layout.Table; import mindustry.gen.*; -import mindustry.world.Tile; import mindustry.world.meta.*; /** Consumer class for blocks which consume power while being connected to a power graph. */ @@ -31,7 +30,7 @@ public class ConsumePower extends Consume{ } @Override - public void build(Tile tile, Table table){ + public void build(Tilec tile, Table table){ //No tooltip for power, for now } diff --git a/tests/src/test/java/ApplicationTests.java b/tests/src/test/java/ApplicationTests.java index 5834390682..cb82a24de5 100644 --- a/tests/src/test/java/ApplicationTests.java +++ b/tests/src/test/java/ApplicationTests.java @@ -16,7 +16,6 @@ import mindustry.maps.*; import mindustry.net.Net; import mindustry.type.*; import mindustry.world.*; -import mindustry.world.blocks.*; import org.junit.jupiter.api.*; import static mindustry.Vars.*; @@ -121,7 +120,7 @@ public class ApplicationTests{ createMap(); int bx = 4; int by = 4; - world.tile(bx, by).set(Blocks.coreShard, Team.sharded); + world.tile(bx, by).setBlock(Blocks.coreShard, Team.sharded, 0); assertEquals(world.tile(bx, by).team(), Team.sharded); for(int x = bx - 1; x <= bx + 1; x++){ for(int y = by - 1; y <= by + 1; y++){ @@ -216,7 +215,7 @@ public class ApplicationTests{ world.tile(0, 0).setBlock(Blocks.conveyor); world.tile(0, 0).rotation(0); - Blocks.conveyor.acceptStack(Items.copper, 1000, world.tile(0, 0), null); + Blocks.conveyor.acceptStack(world.tile(0, 0), Items.copper, 1000, null); } @Test @@ -239,12 +238,12 @@ public class ApplicationTests{ world.tile(length + 1, 0).setBlock(new Block("___"){ @Override - public void handleItem(Item item, Tile tile, Tile source){ + public void handleItem(Tile tile, Tile source, Item item){ items[0] ++; } @Override - public boolean acceptItem(Item item, Tile tile, Tile source){ + public boolean acceptItem(Tile tile, Tile source, Item item){ return true; } }); @@ -425,7 +424,7 @@ public class ApplicationTests{ createMap(); Tile core = world.tile(5, 5); - core.set(Blocks.coreShard, Team.sharded); + core.setBlock(Blocks.coreShard, Team.sharded, 0); for(Item item : content.items()){ core.entity.items().set(item, 3000); } @@ -440,16 +439,16 @@ public class ApplicationTests{ assertNotNull(tile.entity, "Tile should have an entity, but does not: " + tile); - int deposited = tile.block().acceptStack(item, capacity - 1, tile, unit); + int deposited = tile.block().acceptStack(tile, item, capacity - 1, unit); assertEquals(capacity - 1, deposited); - tile.block().handleStack(item, capacity - 1, tile, unit); + tile.block().handleStack(tile, item, capacity - 1, unit); assertEquals(tile.entity.items().get(item), capacity - 1); - int overflow = tile.block().acceptStack(item, 10, tile, unit); + int overflow = tile.block().acceptStack(tile, item, 10, unit); assertEquals(1, overflow); - tile.block().handleStack(item, 1, tile, unit); + tile.block().handleStack(tile, item, 1, unit); assertEquals(capacity, tile.entity.items().get(item)); } } diff --git a/tests/src/test/java/power/ItemLiquidGeneratorTests.java b/tests/src/test/java/power/ItemLiquidGeneratorTests.java index fe01e49dca..901e78e533 100644 --- a/tests/src/test/java/power/ItemLiquidGeneratorTests.java +++ b/tests/src/test/java/power/ItemLiquidGeneratorTests.java @@ -127,7 +127,7 @@ public class ItemLiquidGeneratorTests extends PowerTestFixture{ final float expectedRemainingItemAmount = Math.max(0, amount - 1); createGenerator(inputType); - assertTrue(generator.acceptItem(item, tile, null), inputType + " | " + parameterDescription + ": Items which will be declined by the generator don't need to be tested - The code won't be called for those cases."); + assertTrue(generator.acceptItem(tile, null, item), inputType + " | " + parameterDescription + ": Items which will be declined by the generator don't need to be tested - The code won't be called for those cases."); if(amount > 0){ entity.items().add(item, amount);