Merge remote-tracking branch 'origin/continuous-sectors' into continuous-sectors
@ -27,7 +27,7 @@ allprojects {
|
||||
appName = 'Mindustry'
|
||||
gdxVersion = '1.9.8'
|
||||
roboVMVersion = '2.3.0'
|
||||
uCoreVersion = '39d511523f61b8464d7187a3bcd93ea17550712d'
|
||||
uCoreVersion = '99b7a3af00a1fa7e48a494515bf6b137774e114b'
|
||||
|
||||
getVersionString = {
|
||||
String buildVersion = getBuildVersion()
|
||||
|
Before Width: | Height: | Size: 326 B After Width: | Height: | Size: 629 B |
Before Width: | Height: | Size: 120 B After Width: | Height: | Size: 259 B |
Before Width: | Height: | Size: 119 B After Width: | Height: | Size: 252 B |
Before Width: | Height: | Size: 100 KiB After Width: | Height: | Size: 100 KiB |
Before Width: | Height: | Size: 85 KiB |
@ -10,11 +10,6 @@ Font: {
|
||||
markup: false,
|
||||
scale: 0.5
|
||||
},
|
||||
korean: {
|
||||
file: korean.fnt,
|
||||
markup: true,
|
||||
scale: 0.5
|
||||
},
|
||||
trad-chinese: {
|
||||
file: trad_chinese.fnt,
|
||||
markup: true,
|
||||
|
@ -13,6 +13,13 @@ public class Recipes implements ContentList{
|
||||
|
||||
@Override
|
||||
public void load(){
|
||||
//DEBUG
|
||||
new Recipe(distribution, DebugBlocks.itemSource).setMode(GameMode.sandbox).setHidden(true);
|
||||
new Recipe(distribution, DebugBlocks.itemVoid).setMode(GameMode.sandbox).setHidden(true);
|
||||
new Recipe(liquid, DebugBlocks.liquidSource).setMode(GameMode.sandbox).setHidden(true);
|
||||
new Recipe(power, DebugBlocks.powerVoid).setMode(GameMode.sandbox).setHidden(true);
|
||||
new Recipe(power, DebugBlocks.powerInfinite).setMode(GameMode.sandbox).setHidden(true);
|
||||
|
||||
//DEFENSE
|
||||
|
||||
//walls
|
||||
@ -181,13 +188,6 @@ public class Recipes implements ContentList{
|
||||
new Recipe(liquid, LiquidBlocks.mechanicalPump, new ItemStack(Items.copper, 30), new ItemStack(Items.lead, 20)).setDependencies(CraftingBlocks.smelter);
|
||||
new Recipe(liquid, LiquidBlocks.rotaryPump, new ItemStack(Items.copper, 140), new ItemStack(Items.lead, 100), new ItemStack(Items.silicon, 40), new ItemStack(Items.titanium, 70));
|
||||
new Recipe(liquid, LiquidBlocks.thermalPump, new ItemStack(Items.copper, 160), new ItemStack(Items.lead, 130), new ItemStack(Items.silicon, 60), new ItemStack(Items.titanium, 80), new ItemStack(Items.thorium, 70));
|
||||
|
||||
//DEBUG
|
||||
new Recipe(units, DebugBlocks.itemSource).setMode(GameMode.sandbox).setHidden(true);
|
||||
new Recipe(units, DebugBlocks.itemVoid).setMode(GameMode.sandbox).setHidden(true);
|
||||
new Recipe(units, DebugBlocks.liquidSource).setMode(GameMode.sandbox).setHidden(true);
|
||||
new Recipe(units, DebugBlocks.powerVoid).setMode(GameMode.sandbox).setHidden(true);
|
||||
new Recipe(units, DebugBlocks.powerInfinite).setMode(GameMode.sandbox).setHidden(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -10,6 +10,7 @@ import io.anuke.mindustry.gen.Call;
|
||||
import io.anuke.mindustry.game.ContentList;
|
||||
import io.anuke.mindustry.type.Item;
|
||||
import io.anuke.mindustry.type.Liquid;
|
||||
import io.anuke.mindustry.world.BarType;
|
||||
import io.anuke.mindustry.world.Block;
|
||||
import io.anuke.mindustry.world.Tile;
|
||||
import io.anuke.mindustry.world.blocks.PowerBlock;
|
||||
@ -39,6 +40,13 @@ public class DebugBlocks extends BlockList implements ContentList{
|
||||
powerVoid = new PowerBlock("powervoid"){
|
||||
{
|
||||
powerCapacity = Float.MAX_VALUE;
|
||||
shadow = "shadow-round-1";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBars(){
|
||||
super.setBars();
|
||||
bars.remove(BarType.power);
|
||||
}
|
||||
};
|
||||
|
||||
@ -47,6 +55,9 @@ public class DebugBlocks extends BlockList implements ContentList{
|
||||
powerCapacity = 10000f;
|
||||
powerSpeed = 100f;
|
||||
maxNodes = 100;
|
||||
outputsPower = true;
|
||||
consumesPower = false;
|
||||
shadow = "shadow-round-1";
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -134,7 +145,7 @@ public class DebugBlocks extends BlockList implements ContentList{
|
||||
}
|
||||
|
||||
@Override
|
||||
public TileEntity getEntity(){
|
||||
public TileEntity newEntity(){
|
||||
return new LiquidSourceEntity();
|
||||
}
|
||||
};
|
||||
|
@ -63,11 +63,11 @@ public class PowerBlocks extends BlockList implements ContentList{
|
||||
health = 600;
|
||||
}};
|
||||
|
||||
battery = new PowerDistributor("battery"){{
|
||||
battery = new Battery("battery"){{
|
||||
powerCapacity = 320f;
|
||||
}};
|
||||
|
||||
batteryLarge = new PowerDistributor("battery-large"){{
|
||||
batteryLarge = new Battery("battery-large"){{
|
||||
size = 3;
|
||||
powerCapacity = 2000f;
|
||||
}};
|
||||
|
@ -75,12 +75,12 @@ public class ProductionBlocks extends BlockList implements ContentList{
|
||||
|
||||
waterextractor = new SolidPump("water-extractor"){{
|
||||
result = Liquids.water;
|
||||
pumpAmount = 0.1f;
|
||||
pumpAmount = 0.065f;
|
||||
size = 2;
|
||||
liquidCapacity = 30f;
|
||||
rotateSpeed = 1.4f;
|
||||
|
||||
consumes.power(0.15f);
|
||||
consumes.power(0.13f);
|
||||
}};
|
||||
|
||||
oilextractor = new Fracker("oil-extractor"){{
|
||||
|
@ -62,7 +62,6 @@ public class UI extends SceneModule{
|
||||
public ContentInfoDialog content;
|
||||
public SectorsDialog sectors;
|
||||
public MissionDialog missions;
|
||||
public UnlockGraphDialog graph;
|
||||
|
||||
private Locale lastLocale;
|
||||
|
||||
@ -118,7 +117,7 @@ public class UI extends SceneModule{
|
||||
font.getData().setScale(Vars.fontScale);
|
||||
font.getData().down += Unit.dp.scl(4f);
|
||||
font.getData().lineHeight -= Unit.dp.scl(4.3f);
|
||||
}, skin.font(), skin.getFont("default-font-chat"), skin.getFont("korean"), skin.getFont("trad-chinese"), skin.getFont("simp-chinese"));
|
||||
}, skin.font(), skin.getFont("default-font-chat"), skin.getFont("trad-chinese"), skin.getFont("simp-chinese"));
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -173,12 +172,12 @@ public class UI extends SceneModule{
|
||||
Group group = Core.scene.getRoot();
|
||||
|
||||
backfrag.build(group);
|
||||
control.input(0).getFrag().build(Core.scene.getRoot());
|
||||
hudfrag.build(group);
|
||||
menufrag.build(group);
|
||||
chatfrag.container().build(group);
|
||||
listfrag.build(group);
|
||||
loadfrag.build(group);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -216,6 +216,10 @@ public class World extends Module{
|
||||
Events.fire(new WorldLoadEvent());
|
||||
}
|
||||
|
||||
public boolean isGenerating(){
|
||||
return generating;
|
||||
}
|
||||
|
||||
/**Loads up a sector map. This does not call play(), but calls reset().*/
|
||||
public void loadSector(Sector sector){
|
||||
currentSector = sector;
|
||||
@ -228,7 +232,7 @@ public class World extends Module{
|
||||
|
||||
beginMapLoad();
|
||||
|
||||
int width = sectorSize * sector.size, height = sectorSize * sector.size;
|
||||
int width = sectorSize * sector.width, height = sectorSize * sector.height;
|
||||
|
||||
Tile[][] tiles = createTiles(width, height);
|
||||
|
||||
|
@ -90,7 +90,7 @@ public class Damage{
|
||||
Tile tile = world.tile(cx, cy);
|
||||
if(tile != null && tile.entity != null && tile.target().getTeamID() != team.ordinal() && tile.entity.collide(hitter)){
|
||||
tile.entity.collision(hitter);
|
||||
Effects.effect(effect, tile.worldx(), tile.worldy());
|
||||
hitter.getBulletType().hit(hitter, tile.worldx(), tile.worldy());
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
@ -157,6 +157,10 @@ public class TileEntity extends BaseEntity implements TargetTrait, HealthTrait{
|
||||
}
|
||||
|
||||
public void removeFromProximity(){
|
||||
if(power != null){
|
||||
tile.block().powerGraphRemoved(tile);
|
||||
}
|
||||
|
||||
GridPoint2[] nearby = Edges.getEdges(tile.block().size);
|
||||
for(GridPoint2 point : nearby){
|
||||
Tile other = world.tile(tile.x + point.x, tile.y + point.y);
|
||||
@ -179,18 +183,17 @@ public class TileEntity extends BaseEntity implements TargetTrait, HealthTrait{
|
||||
for(GridPoint2 point : nearby){
|
||||
Tile other = world.tile(tile.x + point.x, tile.y + point.y);
|
||||
|
||||
if(other != null){
|
||||
other.block().onProximityUpdate(other);
|
||||
other = other.target();
|
||||
}
|
||||
if(other == null) continue;
|
||||
other = other.target();
|
||||
if(other.entity == null || other.getTeamID() != tile.getTeamID()) continue;
|
||||
|
||||
if(other != null && other.entity != null){
|
||||
tmpTiles.add(other);
|
||||
other.block().onProximityUpdate(other);
|
||||
|
||||
//add this tile to proximity of nearby tiles
|
||||
if(!other.entity.proximity.contains(tile, true)){
|
||||
other.entity.proximity.add(tile);
|
||||
}
|
||||
tmpTiles.add(other);
|
||||
|
||||
//add this tile to proximity of nearby tiles
|
||||
if(!other.entity.proximity.contains(tile, true)){
|
||||
other.entity.proximity.add(tile);
|
||||
}
|
||||
}
|
||||
|
||||
@ -199,6 +202,7 @@ public class TileEntity extends BaseEntity implements TargetTrait, HealthTrait{
|
||||
proximity.add(tile);
|
||||
}
|
||||
|
||||
if(tile.block().hasPower) tile.block().updatePowerGraph(tile);
|
||||
tile.block().onProximityUpdate(tile);
|
||||
}
|
||||
|
||||
|
@ -109,6 +109,10 @@ public class Bullet extends BulletEntity<BulletType> implements TeamTrait, SyncT
|
||||
remove();
|
||||
}
|
||||
|
||||
public BulletType getBulletType(){
|
||||
return type;
|
||||
}
|
||||
|
||||
public void resetOwner(Entity entity, Team team){
|
||||
this.owner = entity;
|
||||
this.team = team;
|
||||
|
@ -181,12 +181,7 @@ public interface BuilderTrait extends Entity{
|
||||
setMineTile(null);
|
||||
}
|
||||
|
||||
TileEntity core = unit.getClosestCore();
|
||||
|
||||
//if there is no core to build with, stop building!
|
||||
if(core == null){
|
||||
return;
|
||||
}
|
||||
|
||||
Tile tile = world.tile(current.x, current.y);
|
||||
|
||||
@ -205,6 +200,13 @@ public interface BuilderTrait extends Entity{
|
||||
}
|
||||
}
|
||||
|
||||
TileEntity core = unit.getClosestCore();
|
||||
|
||||
//if there is no core to build with, stop building!
|
||||
if(core == null){
|
||||
return;
|
||||
}
|
||||
|
||||
//otherwise, update it.
|
||||
BuildEntity entity = tile.entity();
|
||||
|
||||
|
@ -35,7 +35,8 @@ public class UnitDrops{
|
||||
|
||||
if(Mathf.chance(0.03)){
|
||||
int amount = Mathf.random(20, 40);
|
||||
Call.transferItemTo(item, amount, unit.x + Mathf.range(2f), unit.y + Mathf.range(2f), core.tile);
|
||||
amount = core.tile.block().acceptStack(item, amount, core.tile, null);
|
||||
if (amount > 0) Call.transferItemTo(item, amount, unit.x + Mathf.range(2f), unit.y + Mathf.range(2f), core.tile);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -48,7 +48,6 @@ public abstract class InputHandler extends InputAdapter{
|
||||
public InputHandler(Player player){
|
||||
this.player = player;
|
||||
this.section = "player_" + (player.playerIndex + 1);
|
||||
Timers.run(1f, () -> frag.build(Core.scene.getRoot()));
|
||||
}
|
||||
|
||||
//methods to override
|
||||
@ -122,6 +121,10 @@ public abstract class InputHandler extends InputAdapter{
|
||||
tile.block().tapped(tile, player);
|
||||
}
|
||||
|
||||
public OverlayFragment getFrag(){
|
||||
return frag;
|
||||
}
|
||||
|
||||
public void update(){
|
||||
|
||||
}
|
||||
|
@ -293,10 +293,7 @@ public class MobileInput extends InputHandler implements GestureListener{
|
||||
|
||||
@Override
|
||||
public void drawOutlined(){
|
||||
|
||||
//Draw.color(Palette.placing);
|
||||
//Lines.poly(player.x, player.y, 100, Player.placeDistance);
|
||||
//Draw.color();
|
||||
Lines.stroke(1f);
|
||||
|
||||
Shaders.mix.color.set(Palette.accent);
|
||||
Graphics.shader(Shaders.mix);
|
||||
@ -549,14 +546,14 @@ public class MobileInput extends InputHandler implements GestureListener{
|
||||
|
||||
float worldx = Graphics.world(x, y).x, worldy = Graphics.world(x, y).y;
|
||||
|
||||
checkTargets(worldx, worldy);
|
||||
|
||||
//get tile on cursor
|
||||
Tile cursor = tileAt(x, y);
|
||||
|
||||
//ignore off-screen taps
|
||||
if(cursor == null || ui.hasMouse(x, y)) return false;
|
||||
|
||||
checkTargets(worldx, worldy);
|
||||
|
||||
//remove if request present
|
||||
if(hasRequest(cursor)){
|
||||
removeRequest(getRequest(cursor));
|
||||
|
@ -22,7 +22,7 @@ public class Sector{
|
||||
/**Slot ID of this sector's save. -1 means no save has been created.*/
|
||||
public int saveID = -1;
|
||||
/**Sector size; if more than 1, the coordinates are the bottom left corner.*/
|
||||
public int size = 1;
|
||||
public int width = 1, height = 1;
|
||||
/**Num of missions in this sector that have been completed so far.*/
|
||||
public int completedMissions;
|
||||
/**Display texture. Needs to be disposed.*/
|
||||
|
@ -85,19 +85,14 @@ public class Sectors{
|
||||
Sector sector = get(x, y);
|
||||
sector.complete = true;
|
||||
|
||||
for(GridPoint2 point : Edges.getEdges(sector.size)){
|
||||
//TODO work for unique width + height?
|
||||
for(GridPoint2 point : Edges.getEdges(sector.width)){
|
||||
createSector(sector.x + point.x, sector.y + point.y);
|
||||
}
|
||||
}
|
||||
|
||||
/**Creates a sector at a location if it is not present, but does not unlock it.*/
|
||||
public void createSector(int x, int y){
|
||||
boolean isLarge = Mathf.randomSeed(3+Bits.packInt((short)round2(x), (short)round2(y))) < sectorLargeChance;
|
||||
|
||||
if(isLarge){
|
||||
x = round2(x);
|
||||
y = round2(y);
|
||||
}
|
||||
|
||||
if(grid.containsKey(x, y)) return;
|
||||
|
||||
@ -105,11 +100,11 @@ public class Sectors{
|
||||
sector.x = (short)x;
|
||||
sector.y = (short)y;
|
||||
sector.complete = false;
|
||||
sector.size = isLarge ? 2 : 1;
|
||||
sector.width = sector.height = 1;
|
||||
initSector(sector);
|
||||
|
||||
for(int cx = 0; cx < sector.size; cx++){
|
||||
for(int cy = 0; cy < sector.size; cy++){
|
||||
for(int cx = 0; cx < sector.width; cx++){
|
||||
for(int cy = 0; cy < sector.height; cy++){
|
||||
grid.put(x + cx, y + cy, sector);
|
||||
}
|
||||
}
|
||||
@ -128,8 +123,8 @@ public class Sectors{
|
||||
for(Sector sector : out){
|
||||
createTexture(sector);
|
||||
initSector(sector);
|
||||
for(int cx = 0; cx < sector.size; cx++){
|
||||
for(int cy = 0; cy < sector.size; cy++){
|
||||
for(int cx = 0; cx < sector.width; cx++){
|
||||
for(int cy = 0; cy < sector.height; cy++){
|
||||
grid.put(sector.x + cx, sector.y + cy, sector);
|
||||
}
|
||||
}
|
||||
@ -165,8 +160,7 @@ public class Sectors{
|
||||
|
||||
sector.spawns = sector.missions.first().getWaves(sector);
|
||||
|
||||
//add all ores for now since material differences aren't well handled yet
|
||||
sector.ores.addAll(Items.copper, Items.coal, Items.lead, Items.thorium, Items.titanium);
|
||||
sector.ores.addAll(Items.copper);
|
||||
|
||||
//set starter items
|
||||
if(sector.difficulty > 12){ //now with titanium
|
||||
@ -184,15 +178,10 @@ public class Sectors{
|
||||
}
|
||||
}
|
||||
|
||||
private int round2(int i){
|
||||
if(i < 0) i --;
|
||||
return i/2*2;
|
||||
}
|
||||
|
||||
private void createTexture(Sector sector){
|
||||
if(headless) return; //obviously not created or needed on server
|
||||
|
||||
Pixmap pixmap = new Pixmap(sectorImageSize * sector.size, sectorImageSize * sector.size, Format.RGBA8888);
|
||||
Pixmap pixmap = new Pixmap(sectorImageSize * sector.width, sectorImageSize * sector.height, Format.RGBA8888);
|
||||
|
||||
for(int x = 0; x < pixmap.getWidth(); x++){
|
||||
for(int y = 0; y < pixmap.getHeight(); y++){
|
||||
|
@ -70,7 +70,7 @@ public class FortressGenerator{
|
||||
gen.setBlock(enemyX, enemyY, StorageBlocks.core, team);
|
||||
|
||||
float difficultyScl = Mathf.clamp(gen.sector.difficulty / 20f + gen.random.range(1f/2f), 0f, 0.9999f);
|
||||
int coreDst = FortressGenerator.coreDst*gen.sector.size;
|
||||
int coreDst = FortressGenerator.coreDst*gen.sector.width;
|
||||
|
||||
Array<Block> turrets = find(b -> b instanceof ItemTurret);
|
||||
Array<Block> powerTurrets = find(b -> b instanceof PowerTurret);
|
||||
|
@ -1,119 +0,0 @@
|
||||
package io.anuke.mindustry.ui;
|
||||
|
||||
import com.badlogic.gdx.math.Vector2;
|
||||
import com.badlogic.gdx.utils.Array;
|
||||
import io.anuke.ucore.util.Mathf;
|
||||
import io.anuke.ucore.util.SafeArray;
|
||||
|
||||
public class GraphSimulation<T>{
|
||||
public Array<Vertex<T>> vertices = new SafeArray<>();
|
||||
public Array<Edge<T>> edges = new SafeArray<>();
|
||||
public int frameWidth;
|
||||
public int frameHeight;
|
||||
public boolean equi = false;
|
||||
public float criterion = 1000;
|
||||
public float coolingRate = 0.065f;
|
||||
|
||||
private static final float C = 1f;
|
||||
|
||||
private int iteration = 0;
|
||||
private float k;
|
||||
private float t;
|
||||
private boolean equilibriumReached = false;
|
||||
|
||||
private Vector2 deltaPos = new Vector2();
|
||||
|
||||
public int startSimulation() {
|
||||
|
||||
iteration = 0;
|
||||
equilibriumReached = false;
|
||||
|
||||
int area = Math.min(frameWidth * frameWidth, frameHeight * frameHeight);
|
||||
k = C * Mathf.sqrt(area / vertices.size);
|
||||
t = frameWidth / 10;
|
||||
|
||||
if (equi) {
|
||||
while (!equilibriumReached && iteration < 10000) {
|
||||
simulateStep();
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < criterion; i++) {
|
||||
simulateStep();
|
||||
}
|
||||
}
|
||||
return iteration;
|
||||
}
|
||||
|
||||
private void simulateStep() {
|
||||
for (Vertex<T> v : vertices) {
|
||||
v.disp.set(0, 0);
|
||||
for (Vertex<T> u : vertices) {
|
||||
if (v != u) {
|
||||
deltaPos.set(v.pos).sub(u.pos);
|
||||
float length = deltaPos.len();
|
||||
deltaPos.setLength(forceRepulsive(length, k));
|
||||
v.disp.add(deltaPos);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (Edge<T> e : edges) {
|
||||
deltaPos.set(e.v.pos).sub(e.u.pos);
|
||||
float length = deltaPos.len();
|
||||
deltaPos.setLength(forceAttractive(length, k));
|
||||
|
||||
e.v.disp.sub(deltaPos);
|
||||
e.u.disp.add(deltaPos);
|
||||
}
|
||||
|
||||
equilibriumReached = true;
|
||||
|
||||
for (Vertex<T> v : vertices) {
|
||||
|
||||
deltaPos.set(v.disp);
|
||||
float length = deltaPos.len();
|
||||
|
||||
if (length > criterion) {
|
||||
equilibriumReached = false;
|
||||
}
|
||||
|
||||
deltaPos.setLength(Math.min(length, t));
|
||||
|
||||
v.pos.add(deltaPos);
|
||||
v.pos.x = Mathf.clamp(v.pos.x, 0, frameWidth);
|
||||
v.pos.y = Mathf.clamp(v.pos.y, 0, frameHeight);
|
||||
}
|
||||
|
||||
t = Math.max(t * (1 - coolingRate), 1);
|
||||
iteration++;
|
||||
}
|
||||
|
||||
private float forceAttractive(float d, float k) {
|
||||
return d * d / k;
|
||||
}
|
||||
|
||||
private float forceRepulsive(float d, float k) {
|
||||
return k * k /d;
|
||||
}
|
||||
|
||||
public static class Vertex<T>{
|
||||
public Vector2 pos = new Vector2();
|
||||
public final T value;
|
||||
|
||||
private Vector2 disp = new Vector2();
|
||||
|
||||
public Vertex(T value){
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
|
||||
public static class Edge<T> {
|
||||
public final Vertex<T> v;
|
||||
public final Vertex<T> u;
|
||||
|
||||
public Edge(Vertex<T> v, Vertex<T> u) {
|
||||
this.v = v;
|
||||
this.u = u;
|
||||
}
|
||||
}
|
||||
}
|
@ -130,7 +130,7 @@ public class SectorsDialog extends FloatingDialog{
|
||||
float drawY = y + height/2f + sectorY * padSectorSize - offsetY * padSectorSize - panY % padSectorSize;
|
||||
|
||||
Sector sector = world.sectors().get(sectorX, sectorY);
|
||||
int size = (sector == null ? 1 : sector.size);
|
||||
int size = (sector == null ? 1 : sector.width);
|
||||
float padding = (size-1) * sectorPadding;
|
||||
|
||||
if(sector != null && (sector.x != sectorX || sector.y != sectorY)){
|
||||
|
@ -1,97 +0,0 @@
|
||||
package io.anuke.mindustry.ui.dialogs;
|
||||
|
||||
import com.badlogic.gdx.graphics.Color;
|
||||
import com.badlogic.gdx.utils.Array;
|
||||
import com.badlogic.gdx.utils.ObjectMap;
|
||||
import io.anuke.mindustry.Vars;
|
||||
import io.anuke.mindustry.game.UnlockableContent;
|
||||
import io.anuke.mindustry.type.Item;
|
||||
import io.anuke.mindustry.type.ItemStack;
|
||||
import io.anuke.mindustry.type.ItemType;
|
||||
import io.anuke.mindustry.type.Recipe;
|
||||
import io.anuke.mindustry.ui.GraphSimulation;
|
||||
import io.anuke.mindustry.ui.GraphSimulation.Edge;
|
||||
import io.anuke.mindustry.ui.GraphSimulation.Vertex;
|
||||
import io.anuke.ucore.graphics.Draw;
|
||||
import io.anuke.ucore.graphics.Lines;
|
||||
import io.anuke.ucore.util.Mathf;
|
||||
|
||||
public class UnlockGraphDialog extends FloatingDialog{
|
||||
int frameSize = 1000;
|
||||
ObjectMap<UnlockableContent, Vertex<UnlockableContent>> map = new ObjectMap<>();
|
||||
Array<Vertex<UnlockableContent>> vertices;
|
||||
Array<Edge<UnlockableContent>> edges;
|
||||
|
||||
public UnlockGraphDialog(){
|
||||
super("$text.unlocks");
|
||||
|
||||
rebuild();
|
||||
}
|
||||
|
||||
public void rebuild(){
|
||||
content().clear();
|
||||
|
||||
GraphSimulation<UnlockableContent> sim = new GraphSimulation<>();
|
||||
sim.frameWidth = frameSize;
|
||||
sim.frameHeight = frameSize;
|
||||
vertices = sim.vertices;
|
||||
edges = sim.edges;
|
||||
|
||||
for(Item item : Vars.content.items()){
|
||||
if(item.type != ItemType.material) continue;
|
||||
put(item);
|
||||
}
|
||||
|
||||
for(Recipe recipe : Vars.content.recipes()){
|
||||
if(recipe.requirements.length == 0) continue;
|
||||
put(recipe);
|
||||
|
||||
for(Item item : Vars.content.items()){
|
||||
for(ItemStack stack : recipe.requirements){
|
||||
if(stack.item == item){
|
||||
link(item, recipe);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sim.startSimulation();
|
||||
|
||||
content().addRect((x, y, w, h) -> {
|
||||
float cx = x + w/2f, cy = y + h/2f;
|
||||
float ox = cx - frameSize/2f, oy = cy - frameSize/2f;
|
||||
|
||||
Draw.color(Color.DARK_GRAY);
|
||||
Lines.stroke(4f);
|
||||
|
||||
for(Edge<UnlockableContent> e : edges){
|
||||
if(e.v.value instanceof Item){
|
||||
Draw.color(((Item) e.v.value).color);
|
||||
}
|
||||
Lines.line(e.u.pos.x + ox, e.u.pos.y + oy, e.v.pos.x + ox, e.v.pos.y + oy);
|
||||
}
|
||||
|
||||
Draw.color();
|
||||
|
||||
for(Vertex<UnlockableContent> v : vertices){
|
||||
Draw.rect(v.value.getContentIcon(), v.pos.x + ox, v.pos.y + oy, 16*2f, 16*2f);
|
||||
}
|
||||
}).grow();
|
||||
}
|
||||
|
||||
private Vertex<UnlockableContent> get(UnlockableContent c){
|
||||
return map.get(c);
|
||||
}
|
||||
|
||||
private void put(UnlockableContent c){
|
||||
Vertex<UnlockableContent> v = new Vertex<>(c);
|
||||
v.pos.set(frameSize/2f + Mathf.range(frameSize/2f), frameSize/2f + Mathf.range(frameSize/2f));
|
||||
map.put(c, v);
|
||||
vertices.add(v);
|
||||
}
|
||||
|
||||
private void link(UnlockableContent a, UnlockableContent b){
|
||||
edges.add(new Edge<>(get(a), get(b)));
|
||||
}
|
||||
}
|
@ -25,6 +25,8 @@ public abstract class BaseBlock extends MappableContent{
|
||||
|
||||
public boolean outputsLiquid = false;
|
||||
public boolean singleLiquid = true;
|
||||
public boolean consumesPower = true;
|
||||
public boolean outputsPower;
|
||||
|
||||
public int itemCapacity;
|
||||
public float liquidCapacity = 10f;
|
||||
@ -42,7 +44,7 @@ public abstract class BaseBlock extends MappableContent{
|
||||
* Returns the amount of items this block can accept.
|
||||
*/
|
||||
public int acceptStack(Item item, int amount, Tile tile, Unit source){
|
||||
if(acceptItem(item, tile, tile) && hasItems && source.getTeam() == tile.getTeam()){
|
||||
if(acceptItem(item, tile, tile) && hasItems && (source == null || source.getTeam() == tile.getTeam())){
|
||||
return Math.min(getMaximumAccepted(tile, item), amount);
|
||||
}else{
|
||||
return 0;
|
||||
|
@ -138,6 +138,41 @@ public class Block extends BaseBlock {
|
||||
return drops != null && drops.item == item;
|
||||
}
|
||||
|
||||
public void updatePowerGraph(Tile tile){
|
||||
TileEntity entity = tile.entity();
|
||||
|
||||
for(Tile other : getPowerConnections(tile, tempTiles)){
|
||||
if(other.entity.power != null){
|
||||
other.entity.power.graph.add(entity.power.graph);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void powerGraphRemoved(Tile tile){
|
||||
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.packedPosition());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Array<Tile> getPowerConnections(Tile tile, Array<Tile> out){
|
||||
out.clear();
|
||||
for(Tile other : tile.entity.proximity()){
|
||||
if(other.entity.power != null && !(consumesPower && other.block().consumesPower && !outputsPower && !other.block().outputsPower)){
|
||||
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;
|
||||
}
|
||||
|
||||
public boolean isLayer(Tile tile){
|
||||
return true;
|
||||
}
|
||||
@ -444,7 +479,7 @@ public class Block extends BaseBlock {
|
||||
return destructible || update;
|
||||
}
|
||||
|
||||
public TileEntity getEntity(){
|
||||
public TileEntity newEntity(){
|
||||
return new TileEntity();
|
||||
}
|
||||
|
||||
@ -478,7 +513,8 @@ public class Block extends BaseBlock {
|
||||
"entity.x", tile.entity.x,
|
||||
"entity.y", tile.entity.y,
|
||||
"entity.id", tile.entity.id,
|
||||
"entity.items.total", hasItems ? tile.entity.items.total() : null
|
||||
"entity.items.total", hasItems ? tile.entity.items.total() : null,
|
||||
"entity.graph", tile.entity.power != null && tile.entity.power.graph != null ? tile.entity.power.graph.getID() : null
|
||||
);
|
||||
}
|
||||
}
|
@ -416,12 +416,17 @@ public class Tile implements PosTrait, TargetTrait{
|
||||
Block block = block();
|
||||
|
||||
if(block.hasEntity()){
|
||||
entity = block.getEntity().init(this, block.update);
|
||||
entity = block.newEntity().init(this, block.update);
|
||||
entity.cons = new ConsumeModule();
|
||||
if(block.hasItems) entity.items = new InventoryModule();
|
||||
if(block.hasLiquids) entity.liquids = new LiquidModule();
|
||||
if(block.hasPower) entity.power = new PowerModule();
|
||||
entity.updateProximity();
|
||||
if(block.hasPower){
|
||||
entity.power = new PowerModule();
|
||||
entity.power.graph.add(this);
|
||||
}
|
||||
if(!world.isGenerating()){
|
||||
entity.updateProximity();
|
||||
}
|
||||
}else if(!(block instanceof BlockPart)){
|
||||
//since the entity won't update proximity for us, update proximity for all nearby tiles manually
|
||||
for(GridPoint2 p : Geometry.d4){
|
||||
|
@ -171,7 +171,7 @@ public class BuildBlock extends Block{
|
||||
}
|
||||
|
||||
@Override
|
||||
public TileEntity getEntity(){
|
||||
public TileEntity newEntity(){
|
||||
return new BuildEntity();
|
||||
}
|
||||
|
||||
|
@ -76,7 +76,7 @@ public class DeflectorWall extends Wall{
|
||||
}
|
||||
|
||||
@Override
|
||||
public TileEntity getEntity(){
|
||||
public TileEntity newEntity(){
|
||||
return new DeflectorEntity();
|
||||
}
|
||||
|
||||
|
@ -81,7 +81,7 @@ public class Door extends Wall{
|
||||
}
|
||||
|
||||
@Override
|
||||
public TileEntity getEntity(){
|
||||
public TileEntity newEntity(){
|
||||
return new DoorEntity();
|
||||
}
|
||||
|
||||
|
@ -169,7 +169,7 @@ public class ForceProjector extends Block {
|
||||
}
|
||||
|
||||
@Override
|
||||
public TileEntity getEntity(){
|
||||
public TileEntity newEntity(){
|
||||
return new ForceEntity();
|
||||
}
|
||||
|
||||
|
@ -122,7 +122,7 @@ public class MendProjector extends Block{
|
||||
}
|
||||
|
||||
@Override
|
||||
public TileEntity getEntity(){
|
||||
public TileEntity newEntity(){
|
||||
return new MendEntity();
|
||||
}
|
||||
|
||||
|
@ -52,7 +52,7 @@ public class MendingWall extends Wall{
|
||||
}
|
||||
|
||||
@Override
|
||||
public TileEntity getEntity(){
|
||||
public TileEntity newEntity(){
|
||||
return new DeflectorEntity();
|
||||
}
|
||||
}
|
||||
|
@ -123,7 +123,7 @@ public class OverdriveProjector extends Block{
|
||||
}
|
||||
|
||||
@Override
|
||||
public TileEntity getEntity(){
|
||||
public TileEntity newEntity(){
|
||||
return new OverdriveEntity();
|
||||
}
|
||||
|
||||
|
@ -38,7 +38,7 @@ public class ArtilleryTurret extends ItemTurret{
|
||||
|
||||
for(int i = 0; i < shots; i++){
|
||||
Bullet.create(ammo.bullet, tile.entity, tile.getTeam(), tile.drawx() + tr.x, tile.drawy() + tr.y,
|
||||
entity.rotation + Mathf.range(inaccuracy + type.inaccuracy), 1f + Mathf.range(velocityInaccuracy), (dst / maxTraveled));
|
||||
entity.rotation + Mathf.range(inaccuracy + type.inaccuracy), 1f + Mathf.range(velocityInaccuracy), (dst / maxTraveled));
|
||||
}
|
||||
|
||||
effects(tile);
|
||||
|
@ -60,7 +60,7 @@ public class ChargeTurret extends PowerTurret{
|
||||
}
|
||||
|
||||
@Override
|
||||
public TileEntity getEntity(){
|
||||
public TileEntity newEntity(){
|
||||
return new LaserTurretEntity();
|
||||
}
|
||||
|
||||
|
@ -89,7 +89,7 @@ public class LaserTurret extends PowerTurret{
|
||||
}
|
||||
|
||||
@Override
|
||||
public TileEntity getEntity(){
|
||||
public TileEntity newEntity(){
|
||||
return new LaserTurretEntity();
|
||||
}
|
||||
|
||||
|
@ -339,7 +339,7 @@ public abstract class Turret extends Block{
|
||||
}
|
||||
|
||||
@Override
|
||||
public TileEntity getEntity(){
|
||||
public TileEntity newEntity(){
|
||||
return new TurretEntity();
|
||||
}
|
||||
|
||||
|
@ -41,7 +41,7 @@ public class BufferedItemBridge extends ExtendingItemBridge{
|
||||
}
|
||||
|
||||
@Override
|
||||
public TileEntity getEntity(){
|
||||
public TileEntity newEntity(){
|
||||
return new BufferedItemBridgeEntity();
|
||||
}
|
||||
|
||||
|
@ -127,7 +127,7 @@ public class Conduit extends LiquidBlock{
|
||||
}
|
||||
|
||||
@Override
|
||||
public TileEntity getEntity(){
|
||||
public TileEntity newEntity(){
|
||||
return new ConduitEntity();
|
||||
}
|
||||
|
||||
|
@ -358,7 +358,7 @@ public class Conveyor extends Block{
|
||||
}
|
||||
|
||||
@Override
|
||||
public TileEntity getEntity(){
|
||||
public TileEntity newEntity(){
|
||||
return new ConveyorEntity();
|
||||
}
|
||||
|
||||
|
@ -287,7 +287,7 @@ public class ItemBridge extends Block{
|
||||
}
|
||||
|
||||
@Override
|
||||
public TileEntity getEntity(){
|
||||
public TileEntity newEntity(){
|
||||
return new ItemBridgeEntity();
|
||||
}
|
||||
|
||||
|
@ -92,7 +92,7 @@ public class Junction extends Block{
|
||||
}
|
||||
|
||||
@Override
|
||||
public TileEntity getEntity(){
|
||||
public TileEntity newEntity(){
|
||||
return new JunctionEntity();
|
||||
}
|
||||
|
||||
|
@ -234,7 +234,7 @@ public class MassDriver extends Block{
|
||||
}
|
||||
|
||||
@Override
|
||||
public TileEntity getEntity(){
|
||||
public TileEntity newEntity(){
|
||||
return new MassDriverEntity();
|
||||
}
|
||||
|
||||
|
@ -86,7 +86,7 @@ public class Router extends Block{
|
||||
}
|
||||
|
||||
@Override
|
||||
public TileEntity getEntity(){
|
||||
public TileEntity newEntity(){
|
||||
return new SplitterEntity();
|
||||
}
|
||||
|
||||
|
@ -114,7 +114,7 @@ public class Sorter extends Block implements SelectionTrait{
|
||||
}
|
||||
|
||||
@Override
|
||||
public TileEntity getEntity(){
|
||||
public TileEntity newEntity(){
|
||||
return new SorterEntity();
|
||||
}
|
||||
|
||||
|
@ -273,7 +273,7 @@ public class WarpGate extends PowerBlock{
|
||||
}
|
||||
|
||||
@Override
|
||||
public TileEntity getEntity(){
|
||||
public TileEntity newEntity(){
|
||||
return new TeleporterEntity();
|
||||
}
|
||||
|
||||
|
10
core/src/io/anuke/mindustry/world/blocks/power/Battery.java
Normal file
@ -0,0 +1,10 @@
|
||||
package io.anuke.mindustry.world.blocks.power;
|
||||
|
||||
public class Battery extends PowerDistributor{
|
||||
|
||||
public Battery(String name){
|
||||
super(name);
|
||||
outputsPower = true;
|
||||
consumesPower = true;
|
||||
}
|
||||
}
|
@ -50,7 +50,7 @@ public class FusionReactor extends PowerGenerator{
|
||||
entity.power.amount += powerAdded;
|
||||
entity.totalProgress += entity.warmup * Timers.delta();
|
||||
|
||||
distributePower(tile);
|
||||
tile.entity.power.graph.update();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -108,7 +108,7 @@ public class FusionReactor extends PowerGenerator{
|
||||
}
|
||||
|
||||
@Override
|
||||
public TileEntity getEntity(){
|
||||
public TileEntity newEntity(){
|
||||
return new FusionReactorEntity();
|
||||
}
|
||||
|
||||
|
@ -106,14 +106,13 @@ public abstract class ItemGenerator extends PowerGenerator{
|
||||
entity.generateTime = 1f;
|
||||
}
|
||||
|
||||
distributePower(tile);
|
||||
|
||||
tile.entity.power.graph.update();
|
||||
}
|
||||
|
||||
protected abstract float getItemEfficiency(Item item);
|
||||
|
||||
@Override
|
||||
public TileEntity getEntity(){
|
||||
public TileEntity newEntity(){
|
||||
return new ItemGeneratorEntity();
|
||||
}
|
||||
|
||||
|
@ -77,7 +77,7 @@ public abstract class ItemLiquidGenerator extends ItemGenerator{
|
||||
}
|
||||
}
|
||||
|
||||
distributePower(tile);
|
||||
tile.entity.power.graph.update();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -61,7 +61,7 @@ public abstract class LiquidGenerator extends PowerGenerator{
|
||||
}
|
||||
}
|
||||
|
||||
distributePower(tile);
|
||||
tile.entity.power.graph.update();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -70,7 +70,7 @@ public abstract class LiquidGenerator extends PowerGenerator{
|
||||
}
|
||||
|
||||
@Override
|
||||
public TileEntity getEntity(){
|
||||
public TileEntity newEntity(){
|
||||
return new ItemGeneratorEntity();
|
||||
}
|
||||
|
||||
|
@ -124,7 +124,7 @@ public class NuclearReactor extends PowerGenerator{
|
||||
if(entity.heat >= 0.999f){
|
||||
entity.kill();
|
||||
}else{
|
||||
distributePower(tile);
|
||||
tile.entity.power.graph.update();
|
||||
}
|
||||
}
|
||||
|
||||
@ -193,7 +193,7 @@ public class NuclearReactor extends PowerGenerator{
|
||||
}
|
||||
|
||||
@Override
|
||||
public TileEntity getEntity(){
|
||||
public TileEntity newEntity(){
|
||||
return new NuclearReactorEntity();
|
||||
}
|
||||
|
||||
|
@ -1,66 +1,18 @@
|
||||
package io.anuke.mindustry.world.blocks.power;
|
||||
|
||||
import com.badlogic.gdx.math.GridPoint2;
|
||||
import io.anuke.mindustry.entities.TileEntity;
|
||||
import io.anuke.mindustry.world.Edges;
|
||||
import io.anuke.mindustry.world.Tile;
|
||||
import io.anuke.mindustry.world.blocks.PowerBlock;
|
||||
import io.anuke.ucore.core.Timers;
|
||||
|
||||
public class PowerDistributor extends PowerBlock{
|
||||
|
||||
public PowerDistributor(String name){
|
||||
super(name);
|
||||
}
|
||||
|
||||
protected void distributePower(Tile tile){
|
||||
TileEntity entity = tile.entity;
|
||||
int sources = 0;
|
||||
|
||||
if(entity == null) return;
|
||||
|
||||
if(Float.isNaN(entity.power.amount)){
|
||||
entity.power.amount = 0f;
|
||||
}
|
||||
|
||||
for(GridPoint2 point : Edges.getEdges(size)){
|
||||
Tile target = tile.getNearby(point);
|
||||
if(target != null && target.block().hasPower &&
|
||||
shouldDistribute(tile, target)) sources++;
|
||||
}
|
||||
|
||||
if(sources == 0) return;
|
||||
|
||||
float result = entity.power.amount / sources;
|
||||
|
||||
for(GridPoint2 point : Edges.getEdges(size)){
|
||||
Tile target = tile.getNearby(point);
|
||||
if(target == null) continue;
|
||||
target = target.target();
|
||||
|
||||
if(target.block().hasPower && shouldDistribute(tile, target)){
|
||||
float diff = (tile.entity.power.amount / powerCapacity - target.entity.power.amount / target.block().powerCapacity) / 1.4f;
|
||||
|
||||
float transmit = Math.min(result * Timers.delta(), diff * powerCapacity);
|
||||
if(target.block().acceptPower(target, tile, transmit)){
|
||||
float transferred = target.block().addPower(target, transmit);
|
||||
entity.power.amount -= transferred;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean shouldDistribute(Tile tile, Tile other){
|
||||
other = other.target();
|
||||
//only generators can distribute to other generators
|
||||
return other.getTeamID() == tile.getTeamID() && (!(other.block() instanceof PowerGenerator) || tile.block() instanceof PowerGenerator)
|
||||
&& other.entity != null
|
||||
&& other.block().hasPower
|
||||
&& other.entity.power.amount / other.block().powerCapacity < tile.entity.power.amount / powerCapacity;
|
||||
consumesPower = false;
|
||||
outputsPower = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(Tile tile){
|
||||
distributePower(tile);
|
||||
tile.entity.power.graph.update();
|
||||
}
|
||||
}
|
||||
|
@ -18,7 +18,7 @@ public class PowerGenerator extends PowerDistributor{
|
||||
}
|
||||
|
||||
@Override
|
||||
public TileEntity getEntity(){
|
||||
public TileEntity newEntity(){
|
||||
return new GeneratorEntity();
|
||||
}
|
||||
|
||||
|
136
core/src/io/anuke/mindustry/world/blocks/power/PowerGraph.java
Normal file
@ -0,0 +1,136 @@
|
||||
package io.anuke.mindustry.world.blocks.power;
|
||||
|
||||
import com.badlogic.gdx.utils.Array;
|
||||
import com.badlogic.gdx.utils.ObjectSet;
|
||||
import com.badlogic.gdx.utils.Queue;
|
||||
import io.anuke.mindustry.world.Tile;
|
||||
|
||||
import static io.anuke.mindustry.Vars.threads;
|
||||
|
||||
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 ObjectSet<Tile> producers = new ObjectSet<>();
|
||||
private final ObjectSet<Tile> consumers = new ObjectSet<>();
|
||||
private final ObjectSet<Tile> all = new ObjectSet<>();
|
||||
|
||||
private long lastFrameUpdated;
|
||||
private final int graphID;
|
||||
private static int lastGraphID;
|
||||
|
||||
{
|
||||
graphID = lastGraphID++;
|
||||
}
|
||||
|
||||
public int getID(){
|
||||
return graphID;
|
||||
}
|
||||
|
||||
public synchronized void update(){
|
||||
if(threads.getFrameID() == lastFrameUpdated || consumers.size == 0 || producers.size == 0){
|
||||
return;
|
||||
}
|
||||
|
||||
lastFrameUpdated = threads.getFrameID();
|
||||
|
||||
float totalInput = 0f;
|
||||
|
||||
for(Tile producer : producers){
|
||||
totalInput += producer.entity.power.amount;
|
||||
}
|
||||
|
||||
for(Tile producer : producers){
|
||||
float accumulator = producer.entity.power.amount;
|
||||
|
||||
if(accumulator <= 0.0001f) continue;
|
||||
|
||||
float toEach = accumulator / consumers.size;
|
||||
float outputs = 0f;
|
||||
|
||||
for(Tile tile : consumers){
|
||||
outputs += Math.min(tile.block().powerCapacity - tile.entity.power.amount, toEach) / toEach;
|
||||
}
|
||||
|
||||
float finalEach = toEach / outputs;
|
||||
float buffer = 0f;
|
||||
|
||||
if(Float.isNaN(finalEach) || Float.isInfinite(finalEach)){
|
||||
continue;
|
||||
}
|
||||
|
||||
for(Tile tile : consumers){
|
||||
float used = Math.min(tile.block().powerCapacity - tile.entity.power.amount, finalEach) * accumulator / totalInput;
|
||||
buffer += used;
|
||||
tile.entity.power.amount += used;
|
||||
}
|
||||
|
||||
producer.entity.power.amount -= buffer;
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void add(PowerGraph graph){
|
||||
for(Tile tile : graph.all){
|
||||
add(tile);
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void add(Tile tile){
|
||||
tile.entity.power.graph = this;
|
||||
all.add(tile);
|
||||
|
||||
if(tile.block().outputsPower){
|
||||
producers.add(tile);
|
||||
}
|
||||
|
||||
if(tile.block().consumesPower){
|
||||
consumers.add(tile);
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void clear(){
|
||||
for(Tile other : all){
|
||||
other.entity.power.graph = null;
|
||||
}
|
||||
all.clear();
|
||||
producers.clear();
|
||||
consumers.clear();
|
||||
}
|
||||
|
||||
public synchronized void reflow(Tile tile){
|
||||
queue.clear();
|
||||
queue.addLast(tile);
|
||||
while(queue.size > 0){
|
||||
Tile child = queue.removeFirst();
|
||||
child.entity.power.graph = this;
|
||||
add(child);
|
||||
for(Tile next : child.block().getPowerConnections(child, outArray2)){
|
||||
if(next.entity.power != null && next.entity.power.graph == null){
|
||||
queue.addLast(next);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void remove(Tile tile){
|
||||
clear();
|
||||
|
||||
for(Tile other : tile.block().getPowerConnections(tile, outArray1)){
|
||||
if(other.entity.power == null || other.entity.power.graph != null) continue;
|
||||
PowerGraph graph = new PowerGraph();
|
||||
queue.clear();
|
||||
queue.addLast(other);
|
||||
while(queue.size > 0){
|
||||
Tile child = queue.removeFirst();
|
||||
child.entity.power.graph = graph;
|
||||
graph.add(child);
|
||||
for(Tile next : child.block().getPowerConnections(child, outArray2)){
|
||||
if(next != tile && next.entity.power != null && next.entity.power.graph == null){
|
||||
queue.addLast(next);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,7 +1,6 @@
|
||||
package io.anuke.mindustry.world.blocks.power;
|
||||
|
||||
import com.badlogic.gdx.math.Vector2;
|
||||
import com.badlogic.gdx.utils.IntArray;
|
||||
import io.anuke.annotations.Annotations.Loc;
|
||||
import io.anuke.annotations.Annotations.Remote;
|
||||
import io.anuke.mindustry.entities.Player;
|
||||
@ -23,10 +22,6 @@ import io.anuke.ucore.util.Angles;
|
||||
import io.anuke.ucore.util.Mathf;
|
||||
import io.anuke.ucore.util.Translator;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
import static io.anuke.mindustry.Vars.*;
|
||||
|
||||
public class PowerNode extends PowerBlock{
|
||||
@ -49,40 +44,52 @@ public class PowerNode extends PowerBlock{
|
||||
layer = Layer.power;
|
||||
powerCapacity = 5f;
|
||||
configurable = true;
|
||||
consumesPower = false;
|
||||
outputsPower = false;
|
||||
}
|
||||
|
||||
@Remote(targets = Loc.both, called = Loc.server, forward = true)
|
||||
public static void linkPowerDistributors(Player player, Tile tile, Tile other){
|
||||
if(!(tile.entity instanceof DistributorEntity)) return;
|
||||
public static void linkPowerNodes(Player player, Tile tile, Tile other){
|
||||
if(tile.entity.power == null) return;
|
||||
|
||||
DistributorEntity entity = tile.entity();
|
||||
TileEntity entity = tile.entity();
|
||||
|
||||
if(!entity.links.contains(other.packedPosition())){
|
||||
entity.links.add(other.packedPosition());
|
||||
if(!entity.power.links.contains(other.packedPosition())){
|
||||
entity.power.links.add(other.packedPosition());
|
||||
}
|
||||
|
||||
if(other.getTeamID() == tile.getTeamID() && other.block() instanceof PowerNode){
|
||||
DistributorEntity oe = other.entity();
|
||||
if(other.getTeamID() == tile.getTeamID()){
|
||||
|
||||
if(!oe.links.contains(tile.packedPosition())){
|
||||
oe.links.add(tile.packedPosition());
|
||||
if(!other.entity.power.links.contains(tile.packedPosition())){
|
||||
other.entity.power.links.add(tile.packedPosition());
|
||||
}
|
||||
}
|
||||
|
||||
entity.power.graph.add(other.entity.power.graph);
|
||||
}
|
||||
|
||||
@Remote(targets = Loc.both, called = Loc.server, forward = true)
|
||||
public static void unlinkPowerDistributors(Player player, Tile tile, Tile other){
|
||||
if(!(tile.entity instanceof DistributorEntity)) return;
|
||||
public static void unlinkPowerNodes(Player player, Tile tile, Tile other){
|
||||
if(tile.entity.power == null) return;
|
||||
|
||||
DistributorEntity entity = tile.entity();
|
||||
TileEntity entity = tile.entity();
|
||||
|
||||
entity.links.removeValue(other.packedPosition());
|
||||
entity.power.links.removeValue(other.packedPosition());
|
||||
|
||||
if(other.block() instanceof PowerNode){
|
||||
DistributorEntity oe = other.entity();
|
||||
|
||||
oe.links.removeValue(tile.packedPosition());
|
||||
other.entity.power.links.removeValue(tile.packedPosition());
|
||||
}
|
||||
|
||||
//clear all graph data first
|
||||
PowerGraph tg = entity.power.graph;
|
||||
tg.clear();
|
||||
//reflow from this point, covering all tiles on this side
|
||||
tg.reflow(tile);
|
||||
|
||||
//create new graph for other end
|
||||
PowerGraph og = new PowerGraph();
|
||||
//reflow from other end
|
||||
og.reflow(other);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -93,7 +100,7 @@ public class PowerNode extends PowerBlock{
|
||||
public void playerPlaced(Tile tile){
|
||||
Tile before = world.tile(lastPlaced);
|
||||
if(linkValid(tile, before) && before.block() instanceof PowerNode){
|
||||
Call.linkPowerDistributors(null, tile, before);
|
||||
Call.linkPowerNodes(null, tile, before);
|
||||
}
|
||||
|
||||
lastPlaced = tile.packedPosition();
|
||||
@ -109,21 +116,21 @@ public class PowerNode extends PowerBlock{
|
||||
|
||||
@Override
|
||||
public void update(Tile tile){
|
||||
distributeLaserPower(tile);
|
||||
tile.entity.power.graph.update();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onConfigureTileTapped(Tile tile, Tile other){
|
||||
DistributorEntity entity = tile.entity();
|
||||
TileEntity entity = tile.entity();
|
||||
other = other.target();
|
||||
|
||||
Tile result = other;
|
||||
|
||||
if(linkValid(tile, other)){
|
||||
if(linked(tile, other)){
|
||||
threads.run(() -> Call.unlinkPowerDistributors(null, tile, result));
|
||||
}else if(entity.links.size < maxNodes){
|
||||
threads.run(() -> Call.linkPowerDistributors(null, tile, result));
|
||||
threads.run(() -> Call.unlinkPowerNodes(null, tile, result));
|
||||
}else if(entity.power.links.size < maxNodes){
|
||||
threads.run(() -> Call.linkPowerNodes(null, tile, result));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@ -144,7 +151,7 @@ public class PowerNode extends PowerBlock{
|
||||
|
||||
@Override
|
||||
public void drawConfigure(Tile tile){
|
||||
DistributorEntity entity = tile.entity();
|
||||
TileEntity entity = tile.entity();
|
||||
|
||||
Draw.color(Palette.accent);
|
||||
|
||||
@ -170,7 +177,7 @@ public class PowerNode extends PowerBlock{
|
||||
Lines.square(link.drawx(), link.drawy(),
|
||||
link.block().size * tilesize / 2f + 1f + (linked ? 0f : Mathf.absin(Timers.time(), 4f, 1f)));
|
||||
|
||||
if((entity.links.size >= maxNodes || (link.block() instanceof PowerNode && ((DistributorEntity) link.entity).links.size >= ((PowerNode) link.block()).maxNodes)) && !linked){
|
||||
if((entity.power.links.size >= maxNodes || (link.block() instanceof PowerNode && link.entity.power.links.size >= ((PowerNode) link.block()).maxNodes)) && !linked){
|
||||
Draw.color();
|
||||
Draw.rect("cross-" + link.block().size, link.drawx(), link.drawy());
|
||||
}
|
||||
@ -195,89 +202,20 @@ public class PowerNode extends PowerBlock{
|
||||
public void drawLayer(Tile tile){
|
||||
if(!Settings.getBool("lasers")) return;
|
||||
|
||||
DistributorEntity entity = tile.entity();
|
||||
TileEntity entity = tile.entity();
|
||||
|
||||
entity.laserColor = Mathf.lerpDelta(entity.laserColor, Mathf.clamp(entity.powerRecieved / (powerSpeed)), 0.08f);
|
||||
Draw.color(Palette.powerLaserFrom, Palette.powerLaserTo, 0f * (1f - flashScl) + Mathf.sin(Timers.time(), 1.7f, flashScl));
|
||||
|
||||
Draw.color(Palette.powerLaserFrom, Palette.powerLaserTo, entity.laserColor * (1f - flashScl) + Mathf.sin(Timers.time(), 1.7f, flashScl));
|
||||
|
||||
for(int i = 0; i < entity.links.size; i++){
|
||||
Tile link = world.tile(entity.links.get(i));
|
||||
for(int i = 0; i < entity.power.links.size; i++){
|
||||
Tile link = world.tile(entity.power.links.get(i));
|
||||
if(linkValid(tile, link)) drawLaser(tile, link);
|
||||
}
|
||||
|
||||
Draw.color();
|
||||
}
|
||||
|
||||
@Override
|
||||
public float addPower(Tile tile, float amount){
|
||||
DistributorEntity entity = tile.entity();
|
||||
|
||||
if(entity.lastRecieved != threads.getFrameID()){
|
||||
entity.lastRecieved = threads.getFrameID();
|
||||
entity.powerRecieved = 0f;
|
||||
}
|
||||
|
||||
float canAccept = Math.min(powerCapacity * Timers.delta() - tile.entity.power.amount, amount);
|
||||
|
||||
tile.entity.power.amount += canAccept;
|
||||
entity.powerRecieved += canAccept;
|
||||
|
||||
return canAccept;
|
||||
}
|
||||
|
||||
protected boolean shouldDistribute(Tile tile, Tile other){
|
||||
return other != null && other.entity != null && other.block().hasPower && other.getTeamID() == tile.getTeamID() && other.entity.power.amount / other.block().powerCapacity <= tile.entity.power.amount / powerCapacity &&
|
||||
!(other.block() instanceof PowerGenerator); //do not distribute to power generators
|
||||
}
|
||||
|
||||
protected boolean shouldLeechPower(Tile tile, Tile other){
|
||||
return other.getTeamID() == tile.getTeamID() && !(other.block() instanceof PowerNode)
|
||||
&& other.block() instanceof PowerDistributor //only suck power from batteries and power generators
|
||||
&& other.entity.power.amount / other.block().powerCapacity > tile.entity.power.amount / powerCapacity;
|
||||
}
|
||||
|
||||
protected void distributeLaserPower(Tile tile){
|
||||
DistributorEntity entity = tile.entity();
|
||||
|
||||
if(Float.isNaN(entity.power.amount)){
|
||||
entity.power.amount = 0f;
|
||||
}
|
||||
|
||||
int targets = 0;
|
||||
|
||||
//validate everything first.
|
||||
for(int i = 0; i < entity.links.size; i++){
|
||||
Tile target = world.tile(entity.links.get(i));
|
||||
if(!linkValid(tile, target)){
|
||||
entity.links.removeIndex(i);
|
||||
i--;
|
||||
}else if(shouldDistribute(tile, target)){
|
||||
targets++;
|
||||
}
|
||||
}
|
||||
|
||||
float result = Math.min(entity.power.amount / targets, powerSpeed * Timers.delta());
|
||||
|
||||
for(int i = 0; i < entity.links.size; i++){
|
||||
Tile target = world.tile(entity.links.get(i));
|
||||
if(targets > 0 && shouldDistribute(tile, target)){
|
||||
|
||||
float transmit = Math.min(result, entity.power.amount);
|
||||
if(target.block().acceptPower(target, tile, transmit)){
|
||||
entity.power.amount -= target.block().addPower(target, transmit);
|
||||
}
|
||||
}else if(shouldLeechPower(tile, target)){
|
||||
float diff = (target.entity.power.amount / target.block().powerCapacity - tile.entity.power.amount / powerCapacity) / 1.4f;
|
||||
float transmit = Math.min(Math.min(target.block().powerCapacity * diff, target.entity.power.amount), powerCapacity - tile.entity.power.amount);
|
||||
entity.power.amount += transmit;
|
||||
target.entity.power.amount -= transmit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean linked(Tile tile, Tile other){
|
||||
return tile.<DistributorEntity>entity().links.contains(other.packedPosition());
|
||||
return tile.entity.power.links.contains(other.packedPosition());
|
||||
}
|
||||
|
||||
protected boolean linkValid(Tile tile, Tile link){
|
||||
@ -288,12 +226,12 @@ public class PowerNode extends PowerBlock{
|
||||
if(!(tile != link && link != null && link.block().hasPower) || tile.getTeamID() != link.getTeamID()) return false;
|
||||
|
||||
if(link.block() instanceof PowerNode){
|
||||
DistributorEntity oe = link.entity();
|
||||
TileEntity oe = link.entity();
|
||||
|
||||
return Vector2.dst(tile.drawx(), tile.drawy(), link.drawx(), link.drawy()) <= Math.max(laserRange * tilesize,
|
||||
((PowerNode) link.block()).laserRange * tilesize) - tilesize / 2f
|
||||
+ (link.block().size - 1) * tilesize / 2f + (tile.block().size - 1) * tilesize / 2f &&
|
||||
(!checkMaxNodes || (oe.links.size < ((PowerNode) link.block()).maxNodes || oe.links.contains(tile.packedPosition())));
|
||||
(!checkMaxNodes || (oe.power.links.size < ((PowerNode) link.block()).maxNodes || oe.power.links.contains(tile.packedPosition())));
|
||||
}else{
|
||||
return Vector2.dst(tile.drawx(), tile.drawy(), link.drawx(), link.drawy())
|
||||
<= laserRange * tilesize - tilesize / 2f + (link.block().size - 1) * tilesize;
|
||||
@ -314,32 +252,4 @@ public class PowerNode extends PowerBlock{
|
||||
x2 + t2.x, y2 + t2.y, thicknessScl);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TileEntity getEntity(){
|
||||
return new DistributorEntity();
|
||||
}
|
||||
|
||||
public static class DistributorEntity extends TileEntity{
|
||||
public float laserColor = 0f;
|
||||
public float powerRecieved = 0f;
|
||||
public long lastRecieved = 0;
|
||||
public IntArray links = new IntArray();
|
||||
|
||||
@Override
|
||||
public void write(DataOutputStream stream) throws IOException{
|
||||
stream.writeShort(links.size);
|
||||
for(int i = 0; i < links.size; i++){
|
||||
stream.writeInt(links.get(i));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(DataInputStream stream) throws IOException{
|
||||
short amount = stream.readShort();
|
||||
for(int i = 0; i < amount; i++){
|
||||
links.add(stream.readInt());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -28,7 +28,7 @@ public class SolarGenerator extends PowerGenerator{
|
||||
public void update(Tile tile){
|
||||
addPower(tile, generation * Timers.delta());
|
||||
|
||||
distributePower(tile);
|
||||
tile.entity.power.graph.update();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -95,7 +95,7 @@ public class Cultivator extends Drill{
|
||||
}
|
||||
|
||||
@Override
|
||||
public TileEntity getEntity(){
|
||||
public TileEntity newEntity(){
|
||||
return new CultivatorEntity();
|
||||
}
|
||||
|
||||
|
@ -228,7 +228,7 @@ public class Drill extends Block{
|
||||
}
|
||||
|
||||
@Override
|
||||
public TileEntity getEntity(){
|
||||
public TileEntity newEntity(){
|
||||
return new DrillEntity();
|
||||
}
|
||||
|
||||
|
@ -76,7 +76,7 @@ public class Fracker extends SolidPump{
|
||||
}
|
||||
|
||||
@Override
|
||||
public TileEntity getEntity(){
|
||||
public TileEntity newEntity(){
|
||||
return new FrackerEntity();
|
||||
}
|
||||
|
||||
|
@ -110,7 +110,7 @@ public class GenericCrafter extends Block{
|
||||
}
|
||||
|
||||
@Override
|
||||
public TileEntity getEntity(){
|
||||
public TileEntity newEntity(){
|
||||
return new GenericCrafterEntity();
|
||||
}
|
||||
|
||||
|
@ -94,7 +94,7 @@ public class Incinerator extends Block{
|
||||
}
|
||||
|
||||
@Override
|
||||
public TileEntity getEntity(){
|
||||
public TileEntity newEntity(){
|
||||
return new IncineratorEntity();
|
||||
}
|
||||
|
||||
|
@ -89,7 +89,7 @@ public class LiquidMixer extends LiquidBlock{
|
||||
}
|
||||
|
||||
@Override
|
||||
public TileEntity getEntity(){
|
||||
public TileEntity newEntity(){
|
||||
return new LiquidMixerEntity();
|
||||
}
|
||||
|
||||
|
@ -85,7 +85,7 @@ public class PowerCrafter extends Block{
|
||||
}
|
||||
|
||||
@Override
|
||||
public TileEntity getEntity(){
|
||||
public TileEntity newEntity(){
|
||||
return new GenericCrafterEntity();
|
||||
}
|
||||
}
|
||||
|
@ -203,7 +203,7 @@ public class PowerSmelter extends PowerBlock{
|
||||
}
|
||||
|
||||
@Override
|
||||
public TileEntity getEntity(){
|
||||
public TileEntity newEntity(){
|
||||
return new PowerSmelterEntity();
|
||||
}
|
||||
|
||||
|
@ -130,7 +130,7 @@ public class Separator extends Block{
|
||||
}
|
||||
|
||||
@Override
|
||||
public TileEntity getEntity(){
|
||||
public TileEntity newEntity(){
|
||||
return new GenericCrafterEntity();
|
||||
}
|
||||
}
|
||||
|
@ -194,7 +194,7 @@ public class Smelter extends Block{
|
||||
}
|
||||
|
||||
@Override
|
||||
public TileEntity getEntity(){
|
||||
public TileEntity newEntity(){
|
||||
return new SmelterEntity();
|
||||
}
|
||||
|
||||
|
@ -112,7 +112,7 @@ public class SolidPump extends Pump{
|
||||
}
|
||||
|
||||
@Override
|
||||
public TileEntity getEntity(){
|
||||
public TileEntity newEntity(){
|
||||
return new SolidPumpEntity();
|
||||
}
|
||||
|
||||
|
@ -155,7 +155,7 @@ public class CoreBlock extends StorageBlock{
|
||||
|
||||
@Override
|
||||
public int acceptStack(Item item, int amount, Tile tile, Unit source){
|
||||
if(acceptItem(item, tile, tile) && hasItems && source.getTeam() == tile.getTeam()){
|
||||
if(acceptItem(item, tile, tile) && hasItems && (source == null || source.getTeam() == tile.getTeam())){
|
||||
return Math.min(itemCapacity - tile.entity.items.get(item), amount);
|
||||
}else{
|
||||
return 0;
|
||||
@ -234,7 +234,7 @@ public class CoreBlock extends StorageBlock{
|
||||
}
|
||||
|
||||
@Override
|
||||
public TileEntity getEntity(){
|
||||
public TileEntity newEntity(){
|
||||
return new CoreEntity();
|
||||
}
|
||||
|
||||
|
@ -67,7 +67,7 @@ public class SortedUnloader extends Unloader implements SelectionTrait{
|
||||
}
|
||||
|
||||
@Override
|
||||
public TileEntity getEntity(){
|
||||
public TileEntity newEntity(){
|
||||
return new SortedUnloaderEntity();
|
||||
}
|
||||
|
||||
|
@ -107,7 +107,7 @@ public class CommandCenter extends Block{
|
||||
}
|
||||
|
||||
@Override
|
||||
public TileEntity getEntity(){
|
||||
public TileEntity newEntity(){
|
||||
return new CommandCenterEntity();
|
||||
}
|
||||
|
||||
|
@ -204,7 +204,7 @@ public class MechPad extends Block{
|
||||
}
|
||||
|
||||
@Override
|
||||
public TileEntity getEntity(){
|
||||
public TileEntity newEntity(){
|
||||
return new MechFactoryEntity();
|
||||
}
|
||||
|
||||
|
@ -299,7 +299,7 @@ public class Reconstructor extends Block{
|
||||
}
|
||||
|
||||
@Override
|
||||
public TileEntity getEntity(){
|
||||
public TileEntity newEntity(){
|
||||
return new ReconstructorEntity();
|
||||
}
|
||||
|
||||
|
@ -113,7 +113,7 @@ public class RepairPoint extends Block{
|
||||
}
|
||||
|
||||
@Override
|
||||
public TileEntity getEntity(){
|
||||
public TileEntity newEntity(){
|
||||
return new RepairPointEntity();
|
||||
}
|
||||
|
||||
|
@ -207,7 +207,7 @@ public class UnitFactory extends Block{
|
||||
}
|
||||
|
||||
@Override
|
||||
public TileEntity getEntity(){
|
||||
public TileEntity newEntity(){
|
||||
return new UnitFactoryEntity();
|
||||
}
|
||||
|
||||
|
7
core/src/io/anuke/mindustry/world/meta/PowerType.java
Normal file
@ -0,0 +1,7 @@
|
||||
package io.anuke.mindustry.world.meta;
|
||||
|
||||
public enum PowerType{
|
||||
consumer,
|
||||
producer,
|
||||
bridge
|
||||
}
|
@ -1,5 +1,8 @@
|
||||
package io.anuke.mindustry.world.modules;
|
||||
|
||||
import com.badlogic.gdx.utils.IntArray;
|
||||
import io.anuke.mindustry.world.blocks.power.PowerGraph;
|
||||
|
||||
import java.io.DataInput;
|
||||
import java.io.DataOutput;
|
||||
import java.io.IOException;
|
||||
@ -8,6 +11,8 @@ public class PowerModule extends BlockModule{
|
||||
public float amount;
|
||||
public float capacity = 10f;
|
||||
public float voltage = 0.0001f;
|
||||
public PowerGraph graph = new PowerGraph();
|
||||
public IntArray links = new IntArray();
|
||||
|
||||
public boolean acceptsPower(){
|
||||
return amount + 0.001f <= capacity;
|
||||
@ -19,7 +24,6 @@ public class PowerModule extends BlockModule{
|
||||
}
|
||||
|
||||
float canAccept = Math.min(capacity - amount, add);
|
||||
|
||||
amount += canAccept;
|
||||
|
||||
return canAccept;
|
||||
@ -28,6 +32,11 @@ public class PowerModule extends BlockModule{
|
||||
@Override
|
||||
public void write(DataOutput stream) throws IOException{
|
||||
stream.writeFloat(amount);
|
||||
|
||||
stream.writeShort(links.size);
|
||||
for(int i = 0; i < links.size; i++){
|
||||
stream.writeInt(links.get(i));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -36,5 +45,10 @@ public class PowerModule extends BlockModule{
|
||||
if(Float.isNaN(amount)){
|
||||
amount = 0f;
|
||||
}
|
||||
|
||||
short amount = stream.readShort();
|
||||
for(int i = 0; i < amount; i++){
|
||||
links.add(stream.readInt());
|
||||
}
|
||||
}
|
||||
}
|
||||
|