1
0
mirror of https://github.com/Anuken/Mindustry.git synced 2024-11-10 15:05:23 +03:00
This commit is contained in:
Anuken 2020-03-05 18:05:59 -05:00
parent 2dfbbdfd5b
commit 5a0d079a78
62 changed files with 1296 additions and 1352 deletions

View File

@ -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;

View File

@ -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{

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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

View File

@ -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());
}

View File

@ -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);
}

View File

@ -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());
}
}
}

View File

@ -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);

View File

@ -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;

View File

@ -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());

View File

@ -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<Tile> tmpTiles = new ObjectSet<>();
static final ObjectSet<Tilec> tmpTiles = new ObjectSet<>();
static int sleepingEntities = 0;
transient Tile tile;
transient Block block;
transient Array<Tile> proximity = new Array<>(8);
transient Array<Tilec> 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<Tilec> 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<Tilec> 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<Tilec> 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<Tilec> getPowerConnections(Tilec tile, Array<Tilec> 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<Tilec, Bar> 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<Tile> 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
}

View File

@ -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;

View File

@ -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;

View File

@ -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);
}

View File

@ -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);

View File

@ -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){

View File

@ -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++;
}
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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());
}

View File

@ -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<PlayerAction> setter){
public boolean allowAction(Playerc player, ActionType type, Tilec tile, Cons<PlayerAction> 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);

View File

@ -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();

View File

@ -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);
}

View File

@ -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<Tilec> entityType = null; //initialized later
protected TextureRegion[] cacheRegions = {};
protected Array<String> cacheRegionStrings = new Array<>();
protected Prov<Tilec> entityType = TileEntity::create;
protected ObjectMap<Class<?>, ConfigHandler> configurations = new ObjectMap<>();
protected ObjectMap<Class<?>, Cons2> configurations = new ObjectMap<>();
protected Array<Tile> tempTiles = new Array<>();
protected Array<Tilec> 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<Tile> getPowerConnections(Tile tile, Array<Tile> 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<Tile> cons){
configurations.put(void.class, (tile, value) -> cons.get(tile));
}
/** Listen for a config by class type. */
public <T> void config(Class<T> type, ConfigHandler<T> 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) ? "<ERROR>" : (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<Tilec, Bar> bar : bars.list()){
table.add(bar.get(tile.entity)).growX();
table.row();
}
}
public void drawRequest(BuildRequest req, Eachable<BuildRequest> 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<BuildRequest> 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<BuildRequest> 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<Tilec> cons){
configurations.put(void.class, (tile, value) -> cons.get((Tilec)tile));
}
Pixmap last = null;
/** Listen for a config by class type. */
public <T> void config(Class<T> type, Cons2<Tile, T> 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<T>{
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<? extends Tilec> cons = (Constructor<? extends Tilec>)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);
}
}
}

View File

@ -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<Tile> 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<Tile> 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<Tile> 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;
}
}

View File

@ -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.<BuildEntity>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.<BuildEntity>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);
}
}

View File

@ -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<Tile> 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)

View File

@ -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 + "]";
}
}

View File

@ -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;

View File

@ -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){

View File

@ -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.<ItemTurretEntity>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;

View File

@ -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;
}

View File

@ -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

View File

@ -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);

View File

@ -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;

View File

@ -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();

View File

@ -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);

View File

@ -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);
}

View File

@ -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;

View File

@ -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;
}
}

View File

@ -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;

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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<Tile> queue = new Queue<>();
private final static Array<Tile> outArray1 = new Array<>();
private final static Array<Tile> outArray2 = new Array<>();
private final static Queue<Tilec> queue = new Queue<>();
private final static Array<Tilec> outArray1 = new Array<>();
private final static Array<Tilec> outArray2 = new Array<>();
private final static IntSet closedSet = new IntSet();
private final ObjectSet<Tile> producers = new ObjectSet<>();
private final ObjectSet<Tile> consumers = new ObjectSet<>();
private final ObjectSet<Tile> batteries = new ObjectSet<>();
private final ObjectSet<Tile> all = new ObjectSet<>();
private final ObjectSet<Tilec> producers = new ObjectSet<>();
private final ObjectSet<Tilec> consumers = new ObjectSet<>();
private final ObjectSet<Tilec> batteries = new ObjectSet<>();
private final ObjectSet<Tilec> 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;
}
}

View File

@ -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.<PowerNode>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){

View File

@ -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

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}
}

View File

@ -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());
}

View File

@ -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;
}

View File

@ -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

View File

@ -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){

View File

@ -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))));

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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<Liquid> 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))));

View File

@ -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
}

View File

@ -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));
}
}

View File

@ -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);