mirror of
https://github.com/Anuken/Mindustry.git
synced 2026-10-03 20:00:26 +03:00
Compare commits
13
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b70ea8afd6 | ||
|
|
fe6e3b03ba | ||
|
|
0849ed8cfc | ||
|
|
715c099dcc | ||
|
|
f9da9a3fe1 | ||
|
|
d4449289a8 | ||
|
|
adaf3112ed | ||
|
|
6524fc07a7 | ||
|
|
54e2c15ae4 | ||
|
|
5c224a49b6 | ||
|
|
fad7afb97e | ||
|
|
d5c78639f3 | ||
|
|
b91d26c509 |
@@ -5,21 +5,6 @@ import java.lang.annotation.*;
|
||||
public class Annotations{
|
||||
//region entity interfaces
|
||||
|
||||
@Repeatable(BuildingListDefs.class)
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@Target({ElementType.TYPE})
|
||||
public @interface BuildingListDef{
|
||||
String qualifiedType() default "";
|
||||
Class<?> type() default void.class;
|
||||
String method();
|
||||
}
|
||||
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@Target({ElementType.TYPE})
|
||||
public @interface BuildingListDefs{
|
||||
BuildingListDef[] value();
|
||||
}
|
||||
|
||||
/** Indicates that a method overrides other methods. */
|
||||
@Target({ElementType.METHOD})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
|
||||
@@ -1,112 +0,0 @@
|
||||
package mindustry.annotations.entity;
|
||||
|
||||
import mindustry.annotations.Annotations.*;
|
||||
import mindustry.annotations.*;
|
||||
|
||||
import javax.annotation.processing.*;
|
||||
import javax.lang.model.type.*;
|
||||
import javax.tools.*;
|
||||
import java.io.*;
|
||||
|
||||
@SupportedAnnotationTypes("mindustry.annotations.Annotations.BuildingListDefs")
|
||||
public class BuildingListProcess extends BaseProcessor{
|
||||
static final String template = """
|
||||
package mindustry.gen;
|
||||
|
||||
import ELEMENT_TYPE;
|
||||
|
||||
public class CLASS_NAME{
|
||||
public ELEMENT_TYPE[] values = new ELEMENT_TYPE[50];
|
||||
public int size, index;
|
||||
|
||||
public void update(){
|
||||
for(index = 0; index < size; index++){
|
||||
values[index].UPDATE_METHOD_NAME();
|
||||
}
|
||||
}
|
||||
|
||||
public void add(ELEMENT_TYPE building){
|
||||
ELEMENT_TYPE[] items = values;
|
||||
if(size == items.length){
|
||||
int newLength = (int)(size * 1.75f);
|
||||
ELEMENT_TYPE[] newItems = new ELEMENT_TYPE[newLength];
|
||||
System.arraycopy(items, 0, newItems, 0, size);
|
||||
values = items = newItems;
|
||||
}
|
||||
items[building.buildingArrayIndex = size++] = building;
|
||||
}
|
||||
|
||||
public void remove(ELEMENT_TYPE type){
|
||||
int position = type.buildingArrayIndex;
|
||||
|
||||
if(position != -1 && position < size){
|
||||
|
||||
//rarely the entity index is wrong; fallback to slow implementation
|
||||
if(values[position] != type){
|
||||
type.buildingArrayIndex = -1;
|
||||
for(int i = 0; i < size; i++){
|
||||
if(values[position] == type){
|
||||
type.buildingArrayIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
//not found in the array (attempt to remove a building that does not exist?)
|
||||
if(type.buildingArrayIndex == -1) return;
|
||||
}
|
||||
|
||||
//swap head with current
|
||||
if(size > 1){
|
||||
var head = values[size - 1];
|
||||
head.buildingArrayIndex = position;
|
||||
values[position] = head;
|
||||
}
|
||||
|
||||
size--;
|
||||
values[size] = null;
|
||||
|
||||
//fix iteration index when removing
|
||||
if(index >= position){
|
||||
index--;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
""";
|
||||
|
||||
@Override
|
||||
public void process(RoundEnvironment env) throws Exception{
|
||||
var types = types(BuildingListDefs.class);
|
||||
for(var type : types){
|
||||
for(var listDef : type.annotation(BuildingListDefs.class).value()){
|
||||
String fullName;
|
||||
|
||||
if(!listDef.qualifiedType().isEmpty()){
|
||||
fullName = listDef.qualifiedType();
|
||||
}else{
|
||||
try{
|
||||
fullName = listDef.type().getCanonicalName();
|
||||
}catch(MirroredTypeException e){
|
||||
fullName = e.getTypeMirror().toString();
|
||||
}
|
||||
}
|
||||
|
||||
String simpleName = simpleName(fullName);
|
||||
|
||||
var listMethod = listDef.method();
|
||||
|
||||
String listClassName = (simpleName.endsWith("Build") ? simpleName.replace("Build","") : simpleName) + "List";
|
||||
String resultClass = template
|
||||
.replaceAll("ELEMENT_TYPE", fullName)
|
||||
.replaceAll("CLASS_NAME", listClassName)
|
||||
.replaceAll("UPDATE_METHOD_NAME", listMethod)
|
||||
;
|
||||
|
||||
JavaFileObject object = filer.createSourceFile(packageName + "." + listClassName);
|
||||
Writer stream = object.openWriter();
|
||||
stream.write(resultClass);
|
||||
stream.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6401,10 +6401,9 @@ public class Blocks{
|
||||
repairSpeed = 0.45f;
|
||||
repairRadius = 60f;
|
||||
beamWidth = 0.73f;
|
||||
powerUse = 1f;
|
||||
pulseRadius = 5f;
|
||||
ambientSoundVolume = 0.9f;
|
||||
|
||||
consumePower(1f);
|
||||
}};
|
||||
|
||||
repairTurret = new RepairTurret("repair-turret"){{
|
||||
@@ -6413,14 +6412,13 @@ public class Blocks{
|
||||
length = 6f;
|
||||
repairSpeed = 3f;
|
||||
repairRadius = 145f;
|
||||
powerUse = 5f;
|
||||
beamWidth = 1.1f;
|
||||
pulseRadius = 6.1f;
|
||||
coolantUse = 0.16f;
|
||||
coolantMultiplier = 1.6f;
|
||||
acceptCoolant = true;
|
||||
ambientSoundVolume = 1.25f;
|
||||
|
||||
consumePower(5f);
|
||||
}};
|
||||
|
||||
//endregion
|
||||
|
||||
@@ -1,238 +0,0 @@
|
||||
package mindustry.core;
|
||||
|
||||
import arc.math.*;
|
||||
import arc.struct.*;
|
||||
import arc.util.*;
|
||||
import mindustry.*;
|
||||
import mindustry.annotations.Annotations.*;
|
||||
import mindustry.gen.*;
|
||||
import mindustry.world.blocks.*;
|
||||
import mindustry.world.blocks.distribution.BufferedItemBridge.*;
|
||||
import mindustry.world.blocks.distribution.Conveyor.*;
|
||||
import mindustry.world.blocks.distribution.DirectionLiquidBridge.*;
|
||||
import mindustry.world.blocks.distribution.Duct.*;
|
||||
import mindustry.world.blocks.distribution.DuctBridge.*;
|
||||
import mindustry.world.blocks.distribution.DuctRouter.*;
|
||||
import mindustry.world.blocks.distribution.ItemBridge.*;
|
||||
import mindustry.world.blocks.distribution.Junction.*;
|
||||
import mindustry.world.blocks.distribution.Router.*;
|
||||
import mindustry.world.blocks.distribution.StackConveyor.*;
|
||||
import mindustry.world.blocks.liquid.Conduit.*;
|
||||
import mindustry.world.blocks.liquid.LiquidBridge.*;
|
||||
import mindustry.world.blocks.liquid.LiquidRouter.*;
|
||||
import mindustry.world.blocks.power.*;
|
||||
import mindustry.world.blocks.storage.Unloader.*;
|
||||
|
||||
import java.util.concurrent.*;
|
||||
|
||||
import static mindustry.Vars.*;
|
||||
|
||||
@BuildingListDef(qualifiedType = "mindustry.gen.Building", method = "updateTile")
|
||||
|
||||
@BuildingListDef(type = PowerGraph.class, method = "update")
|
||||
@BuildingListDef(type = ConveyorBuild.class, method = "updateConveyor")
|
||||
@BuildingListDef(type = DuctBuild.class, method = "updateDuct")
|
||||
@BuildingListDef(type = DuctBridgeBuild.class, method = "updateTile")
|
||||
@BuildingListDef(type = JunctionBuild.class, method = "updateJunction")
|
||||
@BuildingListDef(type = RouterBuild.class, method = "updateTile")
|
||||
@BuildingListDef(type = DuctRouterBuild.class, method = "updateTile")
|
||||
@BuildingListDef(type = ItemBridgeBuild.class, method = "update") //TODO: has consume power, meaning updateConsumption needs to be called too (bad)
|
||||
@BuildingListDef(type = BufferedItemBridgeBuild.class, method = "updateTile")
|
||||
@BuildingListDef(type = StackConveyorBuild.class, method = "updateStackConveyor")
|
||||
@BuildingListDef(type = UnloaderBuild.class, method = "updateUnloader")
|
||||
|
||||
@BuildingListDef(type = ConduitBuild.class, method = "updateConduit")
|
||||
@BuildingListDef(type = LiquidRouterBuild.class, method = "updateLiquidRouter")
|
||||
@BuildingListDef(type = LiquidBridgeBuild.class, method = "update") //TODO: has consume power, meaning updateConsumption needs to be called too (bad)
|
||||
@BuildingListDef(type = DirectionLiquidBridgeBuild.class, method = "updateTile")
|
||||
|
||||
/*
|
||||
TODO: make enable/disable just remove them from the list of things that need to update
|
||||
- subpoint: remove all contents of update() as they would no longer be needed
|
||||
|
||||
TODO: remove the 'devirtualized' methods and see if it affects performance at all (check weaker devices too)
|
||||
|
||||
TODO:
|
||||
- refactor checkAllowUpdate in World to not access Groups.build
|
||||
- refactor fog scanning Groups.build (2 different places) and move that into a new thread
|
||||
- finally, remove it from the group list def (footgun avoidance)
|
||||
*
|
||||
*/
|
||||
public class Buildings{
|
||||
public final BuildingList buildings = new BuildingList();
|
||||
|
||||
public final ConveyorList conveyors = new ConveyorList();
|
||||
public final DuctList ducts = new DuctList();
|
||||
public final DuctBridgeList ductBridges = new DuctBridgeList();
|
||||
public final JunctionList junctions = new JunctionList();
|
||||
public final RouterList routers = new RouterList();
|
||||
public final DuctRouterList ductRouters = new DuctRouterList();
|
||||
public final BufferedItemBridgeList bufferedItemBridges = new BufferedItemBridgeList();
|
||||
public final ItemBridgeList itemBridges = new ItemBridgeList();
|
||||
public final StackConveyorList stackConveyors = new StackConveyorList();
|
||||
public final UnloaderList unloaders = new UnloaderList();
|
||||
|
||||
public final ConduitList conduits = new ConduitList();
|
||||
public final LiquidRouterList liquidRouters = new LiquidRouterList();
|
||||
public final LiquidBridgeList liquidBridges = new LiquidBridgeList();
|
||||
public final DirectionLiquidBridgeList directionLiquidBridges = new DirectionLiquidBridgeList();
|
||||
|
||||
public final PowerGraphList powerGraphs = new PowerGraphList();
|
||||
|
||||
private final Seq<Building> timeScaleBuilds = new Seq<>(false, 20, Building.class);
|
||||
private final Seq<Building> timeScaleQueue = new Seq<>(false, 20, Building.class);
|
||||
private final Seq<Building> ambientSoundBuilds = new Seq<>(false, 20, Building.class);
|
||||
private final Seq<Building> ambientSoundQueue = new Seq<>(false, 20, Building.class);
|
||||
private final Seq<LiquidUpdater> liquidUpdateBuilds = new Seq<>(false, 20, LiquidUpdater.class);
|
||||
|
||||
private final Seq<Future<?>> consFutures = new Seq<>();
|
||||
|
||||
public void update(){
|
||||
|
||||
timeScaleBuilds.addAll(timeScaleQueue);
|
||||
timeScaleQueue.clear();
|
||||
|
||||
ambientSoundBuilds.addAll(ambientSoundQueue);
|
||||
ambientSoundQueue.clear();
|
||||
|
||||
Future<?> updateSound = null;
|
||||
|
||||
if(!headless){
|
||||
updateSound = mainExecutor.submit(() -> {
|
||||
Building[] items = ambientSoundBuilds.items;
|
||||
int len = ambientSoundBuilds.size;
|
||||
for(int i = 0; i < len; i++){
|
||||
var build = items[i];
|
||||
|
||||
if(!build.isValid()){
|
||||
ambientSoundBuilds.remove(i);
|
||||
i --;
|
||||
len --;
|
||||
continue;
|
||||
}
|
||||
|
||||
if(build.shouldAmbientSound()){
|
||||
control.sound.loop(build.block.ambientSound, build, build.block.ambientSoundVolume * build.ambientVolume());
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
float delta = Time.delta;
|
||||
var updateTimeScale = Vars.mainExecutor.submit(() -> {
|
||||
Building[] items = timeScaleBuilds.items;
|
||||
int len = timeScaleBuilds.size;
|
||||
for(int i = 0; i < len; i++){
|
||||
var build = items[i];
|
||||
if((build.timeScaleDuration -= delta) <= 0f){
|
||||
build.timeScale = 1f;
|
||||
build.hadTimeScale = false;
|
||||
timeScaleBuilds.remove(i);
|
||||
len --;
|
||||
i --;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
var updatePower = mainExecutor.submit(() -> {
|
||||
PerfCounter.powerUpdate.begin();
|
||||
powerGraphs.update();
|
||||
PerfCounter.powerUpdate.end();
|
||||
});
|
||||
|
||||
var updateItems = Vars.mainExecutor.submit(() -> {
|
||||
PerfCounter.itemsUpdate.begin();
|
||||
conveyors.update();
|
||||
ducts.update();
|
||||
ductBridges.update();
|
||||
junctions.update();
|
||||
routers.update();
|
||||
ductRouters.update();
|
||||
bufferedItemBridges.update();
|
||||
itemBridges.update();
|
||||
stackConveyors.update();
|
||||
unloaders.update();
|
||||
PerfCounter.itemsUpdate.end();
|
||||
});
|
||||
|
||||
var updateLiquids = Vars.mainExecutor.submit(() -> {
|
||||
PerfCounter.liquidsUpdate.begin();
|
||||
conduits.update();
|
||||
liquidRouters.update();
|
||||
liquidBridges.update();
|
||||
directionLiquidBridges.update();
|
||||
|
||||
{
|
||||
LiquidUpdater[] items = liquidUpdateBuilds.items;
|
||||
int len = liquidUpdateBuilds.size;
|
||||
for(int i = 0; i < len; i++){
|
||||
var build = items[i];
|
||||
if(!build.isAdded()){
|
||||
liquidUpdateBuilds.remove(i);
|
||||
len --;
|
||||
i --;
|
||||
}else{
|
||||
build.processLiquids();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PerfCounter.liquidsUpdate.end();
|
||||
});
|
||||
|
||||
Threads.await(updateItems);
|
||||
Threads.await(updateLiquids);
|
||||
Threads.await(updateTimeScale);
|
||||
Threads.await(updatePower);
|
||||
|
||||
{
|
||||
PerfCounter.consumeUpdate.begin();
|
||||
|
||||
consFutures.clear();
|
||||
int chunks = Mathf.clamp(buildings.size / 400, 1, OS.cores);
|
||||
int chunkSize = Math.max(buildings.size / chunks, 1);
|
||||
|
||||
Building[] items = buildings.values;
|
||||
for(int i = 0; i < buildings.size; i += chunkSize){
|
||||
int from = i;
|
||||
int to = Math.min(buildings.size, i + chunkSize);
|
||||
|
||||
consFutures.add(mainExecutor.submit(() -> {
|
||||
for(int index = from; index < to; index++){
|
||||
items[index].updateConsumption();
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
Threads.awaitAll(consFutures);
|
||||
PerfCounter.consumeUpdate.end();
|
||||
}
|
||||
|
||||
if(updateSound != null){
|
||||
Threads.await(updateSound);
|
||||
}
|
||||
|
||||
PerfCounter.otherBuildingsUpdate.begin();
|
||||
buildings.update();
|
||||
PerfCounter.otherBuildingsUpdate.end();
|
||||
}
|
||||
|
||||
public void addLiquidUpdater(LiquidUpdater build){
|
||||
liquidUpdateBuilds.add(build);
|
||||
}
|
||||
|
||||
public void addAmbientSound(Building build){
|
||||
if(headless) return;
|
||||
|
||||
ambientSoundQueue.add(build);
|
||||
}
|
||||
|
||||
public void addTimeScaled(Building build){
|
||||
build.hadTimeScale = true;
|
||||
timeScaleQueue.add(build);
|
||||
}
|
||||
|
||||
public void clear(){
|
||||
//TODO: call clear on all the above
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,7 @@ import mindustry.gen.*;
|
||||
import mindustry.maps.*;
|
||||
import mindustry.mod.*;
|
||||
import mindustry.type.*;
|
||||
import mindustry.world.*;
|
||||
import mindustry.world.blocks.*;
|
||||
|
||||
import static mindustry.Vars.*;
|
||||
@@ -41,12 +42,12 @@ public class GameState{
|
||||
public MapLocales mapLocales = new MapLocales();
|
||||
/** Global attributes of the environment, calculated by weather. */
|
||||
public Attributes envAttrs = new Attributes();
|
||||
/** Cached team data. */
|
||||
/** Team data. Gets reset every new game. */
|
||||
public Teams teams = new Teams();
|
||||
/** Handles edits of game content and additional image/audio assets. */
|
||||
/** Runs liquids in a new thread. */
|
||||
public LiquidManager liquids = new LiquidManager();
|
||||
/** Handles JSON edits of game content. */
|
||||
public DataManager data = new DataManager();
|
||||
/** All buildings in the map. */
|
||||
public Buildings buildings = new Buildings();
|
||||
/** Number of enemies in the game; only used clientside in servers. */
|
||||
public int enemies;
|
||||
/** Map being playtested (not edited!) */
|
||||
|
||||
@@ -302,7 +302,7 @@ public class Logic implements ApplicationListener{
|
||||
Events.fire(new ResetEvent());
|
||||
world.tiles = new Tiles(0, 0);
|
||||
|
||||
state.buildings.clear();
|
||||
state.liquids.stop();
|
||||
state.data.unload();
|
||||
State prev = state.getState();
|
||||
//recreate gamestate - sets state to menu
|
||||
@@ -560,16 +560,13 @@ public class Logic implements ApplicationListener{
|
||||
runWave();
|
||||
}
|
||||
|
||||
state.liquids.checkUpdate();
|
||||
|
||||
//apply weather attributes
|
||||
state.envAttrs.clear();
|
||||
state.envAttrs.add(state.rules.attributes);
|
||||
Groups.weather.each(w -> state.envAttrs.add(w.weather.attrs, w.opacity));
|
||||
|
||||
//TODO: possible side effects of buildings before after all bullets do?
|
||||
PerfCounter.buildingUpdate.begin();
|
||||
state.buildings.update();
|
||||
PerfCounter.buildingUpdate.end();
|
||||
|
||||
PerfCounter.entityUpdate.begin();
|
||||
Groups.update();
|
||||
PerfCounter.entityUpdate.end();
|
||||
|
||||
@@ -8,12 +8,6 @@ public enum PerfCounter{
|
||||
frame,
|
||||
update,
|
||||
entityUpdate,
|
||||
buildingUpdate,
|
||||
itemsUpdate,
|
||||
powerUpdate,
|
||||
liquidsUpdate,
|
||||
consumeUpdate,
|
||||
otherBuildingsUpdate,
|
||||
ui,
|
||||
render;
|
||||
|
||||
|
||||
@@ -467,7 +467,7 @@ public class World{
|
||||
for(var build : team.buildings){
|
||||
//reset map-area-based disabled blocks that were not in the previous map area
|
||||
if(!build.enabled && build.block.autoResetEnabled && !Rect.contains(x, y, w, h, build.tile.x, build.tile.y)){
|
||||
build.setEnabled(true);
|
||||
build.enabled = true;
|
||||
}
|
||||
|
||||
//if the map area contracts, disable the block
|
||||
|
||||
@@ -94,7 +94,7 @@ public class DrawOperation{
|
||||
Block block = content.block(to);
|
||||
tile.setBlock(block, tile.team(), tile.build == null ? 0 : tile.build.rotation);
|
||||
if(tile.build != null){
|
||||
tile.build.setEnabled(true);
|
||||
tile.build.enabled = true;
|
||||
}
|
||||
}
|
||||
case opRotation -> {
|
||||
|
||||
@@ -208,10 +208,12 @@ public class MapEditorDialog extends Dialog implements Disposable{
|
||||
float oldDelta = Time.delta;
|
||||
Time.delta = deltaScl;
|
||||
|
||||
Seq<Building> builds = new Seq<>();
|
||||
Time.clear();
|
||||
|
||||
world.tiles.eachTile(t -> {
|
||||
if(t.build != null && t.isCenter()){
|
||||
if(t.build != null && t.isCenter() && t.block().update && t.build.allowUpdate()){
|
||||
builds.add(t.build);
|
||||
t.build.updateProximity();
|
||||
}
|
||||
});
|
||||
@@ -228,7 +230,10 @@ public class MapEditorDialog extends Dialog implements Disposable{
|
||||
}
|
||||
}
|
||||
Time.update();
|
||||
state.buildings.update();
|
||||
for(var build : builds){
|
||||
build.update();
|
||||
}
|
||||
Groups.powerGraph.update();
|
||||
Groups.bullet.update(); //needed for mass drivers...
|
||||
}
|
||||
|
||||
@@ -345,6 +350,7 @@ public class MapEditorDialog extends Dialog implements Disposable{
|
||||
}
|
||||
}
|
||||
|
||||
Groups.build.clear();
|
||||
Groups.weather.clear();
|
||||
logic.play();
|
||||
|
||||
|
||||
@@ -8,11 +8,12 @@ class GroupDefs<G>{
|
||||
@GroupDef(value = Playerc.class, mapping = true) G player;
|
||||
@GroupDef(value = Bulletc.class, spatial = true, collide = true) G bullet;
|
||||
@GroupDef(value = Unitc.class, spatial = true, mapping = true) G unit;
|
||||
@GroupDef(value = Buildingc.class) G build;
|
||||
@GroupDef(value = Buildingc.class, update = true) G build;
|
||||
@GroupDef(value = Syncc.class, mapping = true) G sync;
|
||||
@GroupDef(value = Drawc.class) G draw;
|
||||
@GroupDef(value = Firec.class) G fire;
|
||||
@GroupDef(value = Puddlec.class) G puddle;
|
||||
@GroupDef(value = WeatherStatec.class) G weather;
|
||||
@GroupDef(value = WorldLabelc.class, mapping = true) G label;
|
||||
@GroupDef(value = PowerGraphUpdaterc.class) G powerGraph;
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ import java.util.*;
|
||||
|
||||
import static mindustry.Vars.*;
|
||||
|
||||
@EntityDef(value = {Buildingc.class}, excludeGroups = {"all", "build"}, isFinal = false, genio = false, serialize = false)
|
||||
@EntityDef(value = {Buildingc.class}, excludeGroups = {"all"}, isFinal = false, genio = false, serialize = false)
|
||||
@Component(base = true, genInterface = false)
|
||||
abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc, QuadTreeObject, Displayable, Sized, Senseable, Controllable, Settable{
|
||||
//region vars and initialization
|
||||
@@ -58,9 +58,6 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
|
||||
static final BuildDamageEvent bulletDamageEvent = new BuildDamageEvent();
|
||||
static int sleepingEntities = 0;
|
||||
|
||||
transient int buildingArrayIndex = -1;
|
||||
|
||||
@Import boolean added;
|
||||
@Import float x, y, health, maxHealth;
|
||||
@Import Team team;
|
||||
@Import boolean dead;
|
||||
@@ -97,10 +94,8 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
|
||||
transient float lastHealTime = -120f * 10f;
|
||||
transient Color suppressColor = Pal.sapBullet;
|
||||
|
||||
transient volatile boolean hadTimeScale = false;
|
||||
transient float timeScale = 1f, timeScaleDuration;
|
||||
|
||||
private transient float lastDamageTime = -recentDamageTime;
|
||||
private transient float timeScale = 1f, timeScaleDuration;
|
||||
private transient float dumpAccum;
|
||||
|
||||
private transient boolean sleeping;
|
||||
@@ -131,6 +126,7 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
|
||||
if(shouldAdd){
|
||||
add();
|
||||
}
|
||||
if(this instanceof LiquidUpdater lu) state.liquids.add(lu);
|
||||
|
||||
checkAllowUpdate();
|
||||
created();
|
||||
@@ -159,46 +155,11 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
|
||||
return self();
|
||||
}
|
||||
|
||||
@Replace
|
||||
@Override
|
||||
public void add(){
|
||||
//there is no need for a 'is added' guard since it is injected regardless of whether the method is replaced
|
||||
|
||||
addToList();
|
||||
if(power != null){
|
||||
power.graph.addUpdate();
|
||||
power.graph.checkAdd();
|
||||
}
|
||||
|
||||
//note: removal is automatic and thus not necessary in remove()
|
||||
if(block.ambientSound != Sounds.none){
|
||||
state.buildings.addAmbientSound(self());
|
||||
}
|
||||
|
||||
if(this instanceof LiquidUpdater l){
|
||||
state.buildings.addLiquidUpdater(l);
|
||||
}
|
||||
|
||||
added = true;
|
||||
}
|
||||
|
||||
@Replace
|
||||
@Override
|
||||
public void remove(){
|
||||
removeFromList();
|
||||
added = false;
|
||||
}
|
||||
|
||||
public void removeFromList(){
|
||||
state.buildings.buildings.remove(self());
|
||||
}
|
||||
|
||||
public void addToList(){
|
||||
state.buildings.buildings.add(self());
|
||||
}
|
||||
|
||||
//used in clear()
|
||||
public void markRemoved(){
|
||||
added = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -499,16 +460,12 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
|
||||
|
||||
/** Sets the time scale of the building to the given intensity, unless it's above that value */
|
||||
public void applyBoost(float intensity, float duration){
|
||||
if(!block.canOverdrive || duration <= 0f) return;
|
||||
|
||||
if(!block.canOverdrive) return;
|
||||
//do not refresh time scale when getting a lower intensity
|
||||
if(intensity >= this.timeScale - 0.001f){
|
||||
timeScaleDuration = Math.max(timeScaleDuration, duration);
|
||||
}
|
||||
timeScale = Math.max(timeScale, intensity);
|
||||
if(!hadTimeScale){
|
||||
state.buildings.addTimeScaled(self());
|
||||
}
|
||||
}
|
||||
|
||||
/** Sets the time scale of the building to the given intensity, unless it's below that value */
|
||||
@@ -518,9 +475,6 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
|
||||
timeScaleDuration = Math.max(timeScaleDuration, duration);
|
||||
}
|
||||
timeScale = Math.min(timeScale, intensity);
|
||||
if(!hadTimeScale){
|
||||
state.buildings.addTimeScaled(self());
|
||||
}
|
||||
}
|
||||
|
||||
public void applyHealSuppression(float amount){
|
||||
@@ -931,12 +885,19 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
|
||||
|
||||
if(liquids.get(liquid) <= 0.0001f) return;
|
||||
|
||||
if(!net.client() && state.isCampaign() && team == state.rules.defaultTeam) liquid.unlock();
|
||||
//TODO add this back
|
||||
//if(!net.client() && state.isCampaign() && team == state.rules.defaultTeam) liquid.unlock();
|
||||
|
||||
for(int i = 0; i < proximity.size; i++){
|
||||
incrementDump(proximity.size);
|
||||
int psize = proximity.size;
|
||||
Building[] prox = proximity.items;
|
||||
|
||||
Building other = proximity.get((i + dump) % proximity.size);
|
||||
if(psize == 0) return;
|
||||
|
||||
for(int i = 0; i < psize; i++){
|
||||
incrementDump(psize);
|
||||
|
||||
Building other = prox[((i + dump) % psize)];
|
||||
if(other == null) continue;
|
||||
if(outputDir != -1 && (outputDir + rotation) % 4 != relativeTo(other)) continue;
|
||||
|
||||
other = other.getLiquidDestination(self(), liquid);
|
||||
@@ -963,22 +924,23 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
|
||||
}
|
||||
}
|
||||
|
||||
public float moveLiquidForward(boolean leaks, Liquid liquid){
|
||||
Tile next = tile.nearby(rotation);
|
||||
public float moveLiquidForward(@Nullable Building next, boolean leaks, Liquid liquid, float delta){
|
||||
if(next != null){
|
||||
return moveLiquid(next, liquid, delta);
|
||||
}else if(leaks){
|
||||
Tile nextTile = tile.nearby(rotation);
|
||||
|
||||
if(next == null) return 0;
|
||||
|
||||
if(next.build != null){
|
||||
return moveLiquid(next.build, liquid);
|
||||
}else if(leaks && !next.block().solid && !next.block().hasLiquids){
|
||||
float leakAmount = liquids.get(liquid) / 1.5f;
|
||||
Puddles.deposit(next, tile, liquid, leakAmount, true, true);
|
||||
liquids.remove(liquid, leakAmount);
|
||||
if(!nextTile.block().solid && !nextTile.block().hasLiquids){
|
||||
float leakAmount = liquids.get(liquid) / 1.5f;
|
||||
liquids.remove(liquid, leakAmount);
|
||||
//TODO: laggy
|
||||
Core.app.post(() -> Puddles.deposit(nextTile, tile, liquid, leakAmount, true, true));
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public float moveLiquid(Building next, Liquid liquid){
|
||||
public float moveLiquid(Building next, Liquid liquid, float delta){
|
||||
if(next == null) return 0;
|
||||
|
||||
next = next.getLiquidDestination(self(), liquid);
|
||||
@@ -1003,15 +965,20 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
|
||||
if(other.blockReactive && liquid.blockReactive){
|
||||
//TODO liquid reaction handler for extensibility
|
||||
if((other.flammability > 0.3f && liquid.temperature > 0.7f) || (liquid.flammability > 0.3f && other.temperature > 0.7f)){
|
||||
damageContinuous(1);
|
||||
next.damageContinuous(1);
|
||||
if(Mathf.chanceDelta(0.1)){
|
||||
Fx.fire.at(fx, fy);
|
||||
}
|
||||
var fnext = next;
|
||||
Core.app.post(() -> {
|
||||
damageContinuous(1);
|
||||
fnext.damageContinuous(1);
|
||||
if(Mathf.chanceDelta(0.1)){
|
||||
Fx.fire.at(fx, fy);
|
||||
}
|
||||
});
|
||||
}else if((liquid.temperature > 0.7f && other.temperature < 0.55f) || (other.temperature > 0.7f && liquid.temperature < 0.55f)){
|
||||
liquids.remove(liquid, Math.min(liquids.get(liquid), 0.7f * Time.delta));
|
||||
liquids.remove(liquid, Math.min(liquids.get(liquid), 0.7f * delta));
|
||||
if(Mathf.chanceDelta(0.2f)){
|
||||
Fx.steam.at(fx, fy);
|
||||
Core.app.post(() -> {
|
||||
Fx.steam.at(fx, fy);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2059,7 +2026,7 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
|
||||
@Replace
|
||||
@Override
|
||||
public boolean isValid(){
|
||||
return tile.build == self() && !dead();
|
||||
return tile.build == self() && !dead;
|
||||
}
|
||||
|
||||
@MethodPriority(100)
|
||||
@@ -2283,30 +2250,30 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
|
||||
|
||||
public void checkAllowUpdate(){
|
||||
if(!allowUpdate()){
|
||||
setEnabled(false);
|
||||
enabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
public void setEnabled(boolean enable){
|
||||
if(this.enabled == enable) return;
|
||||
|
||||
if(block.update && block.noUpdateDisabled){
|
||||
if(enable){
|
||||
add();
|
||||
}else{
|
||||
remove();
|
||||
}
|
||||
}
|
||||
this.enabled = enable;
|
||||
}
|
||||
|
||||
@Final
|
||||
@Replace
|
||||
@Override
|
||||
public void update(){
|
||||
|
||||
//TODO refactor to separate loop?
|
||||
if((timeScaleDuration -= Time.delta) <= 0f){
|
||||
timeScale = 1f;
|
||||
}
|
||||
|
||||
//TODO separate multithreaded system for sound? AudioSource, etc
|
||||
if(!headless && block.ambientSound != Sounds.none && shouldAmbientSound()){
|
||||
control.sound.loop(block.ambientSound, self(), block.ambientSoundVolume * ambientVolume());
|
||||
}
|
||||
|
||||
updateConsumption();
|
||||
|
||||
updateTile();
|
||||
if(enabled || !block.noUpdateDisabled){
|
||||
updateTile();
|
||||
}
|
||||
}
|
||||
|
||||
/** When a block is newly revealed outside of camera view range, it is updated on the minimap. */
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
package mindustry.entities.comp;
|
||||
|
||||
import mindustry.annotations.Annotations.*;
|
||||
import mindustry.gen.*;
|
||||
import mindustry.world.blocks.power.*;
|
||||
|
||||
@EntityDef(value = PowerGraphUpdaterc.class, serialize = false, genio = false)
|
||||
@Component
|
||||
abstract class PowerGraphUpdaterComp implements Entityc{
|
||||
public transient PowerGraph graph;
|
||||
|
||||
@Override
|
||||
public void update(){
|
||||
graph.update();
|
||||
}
|
||||
}
|
||||
@@ -332,7 +332,7 @@ public abstract class SaveVersion extends SaveFileReader{
|
||||
//set block only if this is the center; otherwise, it's handled elsewhere
|
||||
if(isCenter){
|
||||
tile.setBlock(block);
|
||||
if(tile.build != null) tile.build.setEnabled(true);
|
||||
if(tile.build != null) tile.build.enabled = true;
|
||||
}
|
||||
|
||||
//must be assigned after setBlock, because that can reset data
|
||||
|
||||
@@ -56,7 +56,7 @@ public abstract class LegacySaveVersion extends LegacyRegionSaveVersion{
|
||||
//do not override occupied cells
|
||||
if(!occupied){
|
||||
tile.setBlock(block);
|
||||
if(tile.build != null) tile.build.setEnabled(true);
|
||||
if(tile.build != null) tile.build.enabled = true;
|
||||
}
|
||||
|
||||
if(block.hasBuilding()){
|
||||
|
||||
@@ -101,7 +101,7 @@ public class ShortChunkSaveVersion extends SaveVersion{
|
||||
//set block only if this is the center; otherwise, it's handled elsewhere
|
||||
if(isCenter){
|
||||
tile.setBlock(block);
|
||||
if(tile.build != null) tile.build.setEnabled(true);
|
||||
if(tile.build != null) tile.build.enabled = true;
|
||||
}
|
||||
|
||||
//must be assigned after setBlock, because that can reset data
|
||||
|
||||
@@ -227,7 +227,7 @@ public class ClassMap{
|
||||
classes.put("DirectionBridge", mindustry.world.blocks.distribution.DirectionBridge.class);
|
||||
classes.put("DirectionBridgeBuild", mindustry.world.blocks.distribution.DirectionBridge.DirectionBridgeBuild.class);
|
||||
classes.put("DirectionLiquidBridge", mindustry.world.blocks.distribution.DirectionLiquidBridge.class);
|
||||
classes.put("DirectionLiquidBridgeBuild", mindustry.world.blocks.distribution.DirectionLiquidBridge.DirectionLiquidBridgeBuild.class);
|
||||
classes.put("DuctBridgeBuild", mindustry.world.blocks.distribution.DirectionLiquidBridge.DuctBridgeBuild.class);
|
||||
classes.put("DirectionalUnloader", mindustry.world.blocks.distribution.DirectionalUnloader.class);
|
||||
classes.put("DirectionalUnloaderBuild", mindustry.world.blocks.distribution.DirectionalUnloader.DirectionalUnloaderBuild.class);
|
||||
classes.put("Duct", mindustry.world.blocks.distribution.Duct.class);
|
||||
|
||||
@@ -566,9 +566,8 @@ public class GameService{
|
||||
}
|
||||
}
|
||||
|
||||
for(int i = 0; i < state.buildings.powerGraphs.size; i++){
|
||||
|
||||
var graph = state.buildings.powerGraphs.values[i];
|
||||
for(var up : Groups.powerGraph){
|
||||
var graph = up.graph();
|
||||
if(graph.all.size > 1 && graph.all.first().team == player.team() && graph.hasPowerBalanceSamples()){
|
||||
float balance = graph.getPowerBalance() * 60f;
|
||||
|
||||
|
||||
@@ -95,7 +95,7 @@ public class Build{
|
||||
if(tile.team() == Team.derelict && team != Team.derelict && tile.block == result && tile.build != null && tile.block.allowDerelictRepair && state.rules.derelictRepair){
|
||||
tile.build.rotation = rotation;
|
||||
tile.build.changeTeam(team);
|
||||
tile.build.setEnabled(true);
|
||||
tile.build.enabled = true;
|
||||
if(tile.build.power != null){
|
||||
tile.build.power.links.clear();
|
||||
tile.build.powerGraphRemoved();
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
package mindustry.world;
|
||||
|
||||
import arc.struct.*;
|
||||
import arc.util.*;
|
||||
import mindustry.world.blocks.*;
|
||||
|
||||
import java.util.concurrent.*;
|
||||
|
||||
//TODO: consumers read AND write from the liquids array... on the main thread. as do various other blocks. see remove() usage
|
||||
//TODO: payload loaders/unloaders don't use this system
|
||||
public class LiquidManager{
|
||||
private static final int targetFps = 60;
|
||||
private static final long targetNanos = 1000 * Time.nanosPerMilli / targetFps;
|
||||
|
||||
private UpdaterThread thread;
|
||||
private int curTick;
|
||||
|
||||
public void checkUpdate(){
|
||||
//ensures volatile read
|
||||
if(thread != null){
|
||||
curTick = thread.tick;
|
||||
}
|
||||
}
|
||||
|
||||
public void add(LiquidUpdater building){
|
||||
if(!building.shouldLiquidUpdate()) return;
|
||||
|
||||
if(thread == null){
|
||||
thread = new UpdaterThread();
|
||||
thread.start();
|
||||
}
|
||||
|
||||
thread.addQueue.add(building);
|
||||
}
|
||||
|
||||
public void stop(){
|
||||
if(thread != null){
|
||||
thread.running = false;
|
||||
thread.interrupt();
|
||||
thread = null;
|
||||
}
|
||||
}
|
||||
|
||||
static class UpdaterThread extends Thread{
|
||||
Seq<LiquidUpdater> updaters = new Seq<>(false, 20, LiquidUpdater.class);
|
||||
ConcurrentLinkedQueue<LiquidUpdater> addQueue = new ConcurrentLinkedQueue<>();
|
||||
volatile boolean running = true;
|
||||
volatile int tick;
|
||||
|
||||
long lastNanos = Time.nanos();
|
||||
|
||||
@Override
|
||||
public void run(){
|
||||
try{
|
||||
while(running){
|
||||
long nanos = Time.nanos();
|
||||
long deltaNanos = Time.timeSinceNanos(lastNanos);
|
||||
float deltaTicks = (float)deltaNanos / Time.nanosPerMilli / 1000f * 60f;
|
||||
lastNanos = nanos;
|
||||
|
||||
LiquidUpdater toAdd;
|
||||
while((toAdd = addQueue.poll()) != null){
|
||||
updaters.add(toAdd);
|
||||
}
|
||||
|
||||
LiquidUpdater[] items = updaters.items;
|
||||
int size = updaters.size;
|
||||
for(int i = 0; i < size; i++){
|
||||
var item = items[i];
|
||||
if(!item.isValid()){
|
||||
//note: this is an un-ordered seq, so this is just a O(1) swap
|
||||
updaters.remove(i);
|
||||
i --;
|
||||
size --;
|
||||
}else{
|
||||
item.updateLiquids(deltaTicks);
|
||||
}
|
||||
}
|
||||
|
||||
//update 'global tick' as a volatile memory barrier
|
||||
tick ++;
|
||||
|
||||
long elapsed = Time.timeSinceNanos(nanos);
|
||||
if(elapsed < targetNanos){
|
||||
long remaining = targetNanos - elapsed;
|
||||
Thread.sleep(remaining / Time.nanosPerMilli, (int)(remaining % Time.nanosPerMilli));
|
||||
}
|
||||
}
|
||||
|
||||
}catch(InterruptedException e){
|
||||
//stop the thread
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,13 @@
|
||||
package mindustry.world.blocks;
|
||||
|
||||
import mindustry.game.*;
|
||||
import mindustry.gen.*;
|
||||
|
||||
public interface LiquidUpdater extends Healthc{
|
||||
void processLiquids();
|
||||
default boolean shouldLiquidUpdate(){
|
||||
return true;
|
||||
}
|
||||
|
||||
void updateLiquids(float delta);
|
||||
Team team();
|
||||
}
|
||||
|
||||
@@ -63,7 +63,7 @@ public class ContinuousTurret extends Turret{
|
||||
|
||||
@Override
|
||||
public boolean shouldConsume(){
|
||||
return isShooting();
|
||||
return isShooting;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -123,7 +123,7 @@ public class ContinuousTurret extends Turret{
|
||||
entry.bullet.damage = entry.bullet.type.damage * Math.min(efficiency, 1f) * timeScale * entry.bullet.damageMultiplier();
|
||||
}
|
||||
|
||||
if(isShooting() && hasAmmo()){
|
||||
if(isShooting && hasAmmo()){
|
||||
entry.bullet.time = entry.bullet.lifetime * entry.bullet.type.optimalLifeFract * Math.min(shootWarmup, efficiency);
|
||||
entry.bullet.keepAlive = true;
|
||||
}
|
||||
|
||||
@@ -52,7 +52,8 @@ public class LaserTurret extends PowerTurret{
|
||||
@Override
|
||||
public boolean shouldConsume(){
|
||||
//still consumes power when bullet is around
|
||||
return bullets.any() || isActive() || isShooting();
|
||||
if(bullets.any() || isActive()) return true;
|
||||
return isShooting;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -289,7 +289,7 @@ public class Turret extends ReloadTurret{
|
||||
public @Nullable Posc target;
|
||||
public Vec2 targetPos = new Vec2();
|
||||
public BlockUnitc unit = (BlockUnitc)UnitTypes.block.create(team);
|
||||
public boolean wasShooting;
|
||||
public boolean wasShooting, isShooting;
|
||||
public int queuedBullets = 0;
|
||||
|
||||
public float heatReq;
|
||||
@@ -362,7 +362,7 @@ public class Turret extends ReloadTurret{
|
||||
|
||||
@Override
|
||||
public boolean shouldConsume(){
|
||||
return isShooting() || reloadCounter < reload;
|
||||
return isShooting || reloadCounter < reload;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -410,7 +410,7 @@ public class Turret extends ReloadTurret{
|
||||
case rotation -> rotation;
|
||||
case shootX -> World.conv(targetPos.x);
|
||||
case shootY -> World.conv(targetPos.y);
|
||||
case shooting -> isShooting() ? 1 : 0;
|
||||
case shooting -> isShooting ? 1 : 0;
|
||||
case progress -> progress();
|
||||
default -> super.sense(sensor);
|
||||
};
|
||||
@@ -427,7 +427,7 @@ public class Turret extends ReloadTurret{
|
||||
}
|
||||
|
||||
public boolean isShooting(){
|
||||
return alwaysShooting || (unit.controller() instanceof Player ? unit.isShooting() : logicControlled() ? logicShooting : target != null);
|
||||
return isShooting;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -438,6 +438,10 @@ public class Turret extends ReloadTurret{
|
||||
return (Unit)unit;
|
||||
}
|
||||
|
||||
public boolean controlled(){
|
||||
return unit.isPlayer();
|
||||
}
|
||||
|
||||
public boolean logicControlled(){
|
||||
return logicControlTime > 0;
|
||||
}
|
||||
@@ -485,6 +489,7 @@ public class Turret extends ReloadTurret{
|
||||
@Override
|
||||
public void updateTile(){
|
||||
if(!validateTarget()) target = null;
|
||||
isShooting = alwaysShooting || (unit.controller() instanceof Player ? unit.isShooting() : logicControlled() ? logicShooting : target != null);
|
||||
|
||||
if(unit.isPlayer()){ //there's no reason to update this when a player isn't controlling it
|
||||
unit.ammo(getAmmoFraction());
|
||||
@@ -494,8 +499,8 @@ public class Turret extends ReloadTurret{
|
||||
soundLoop.update(x, y, shouldActiveSound(), activeSoundVolume());
|
||||
}
|
||||
|
||||
float warmupTarget = (isShooting() && canConsume()) || charging() ? 1f : 0f;
|
||||
if(warmupTarget > 0 && !isControlled()){
|
||||
float warmupTarget = (isShooting && canConsume()) || charging() ? 1f : 0f;
|
||||
if(warmupTarget > 0 && !controlled()){
|
||||
warmupHold = 1f;
|
||||
}
|
||||
if(warmupHold > 0f){
|
||||
@@ -568,7 +573,7 @@ public class Turret extends ReloadTurret{
|
||||
if(validateTarget()){
|
||||
boolean canShoot;
|
||||
|
||||
if(isControlled()){ //player behavior
|
||||
if(controlled()){ //player behavior
|
||||
targetPos.set(unit.aimX(), unit.aimY());
|
||||
canShoot = unit.isShooting();
|
||||
}else if(logicControlled()){ //logic behavior
|
||||
@@ -580,7 +585,7 @@ public class Turret extends ReloadTurret{
|
||||
canShoot = within(target, range() + (target instanceof Sized hb ? hb.hitSize()/1.9f : 0f));
|
||||
}
|
||||
|
||||
if(!isControlled()){
|
||||
if(!controlled()){
|
||||
unit.aimX(targetPos.x);
|
||||
unit.aimY(targetPos.y);
|
||||
}
|
||||
@@ -624,7 +629,7 @@ public class Turret extends ReloadTurret{
|
||||
}
|
||||
|
||||
protected boolean validateTarget(){
|
||||
return !Units.invalidateTarget(target, canHeal() ? Team.derelict : team, x, y) || unit.isPlayer() || logicControlled();
|
||||
return !Units.invalidateTarget(target, canHeal() ? Team.derelict : team, x, y) || controlled() || logicControlled();
|
||||
}
|
||||
|
||||
protected boolean canHeal(){
|
||||
|
||||
@@ -6,8 +6,6 @@ import mindustry.type.*;
|
||||
import mindustry.world.*;
|
||||
import mindustry.world.meta.*;
|
||||
|
||||
import static mindustry.Vars.*;
|
||||
|
||||
public class BufferedItemBridge extends ItemBridge{
|
||||
public final int timerAccept = timers++;
|
||||
|
||||
@@ -21,7 +19,7 @@ public class BufferedItemBridge extends ItemBridge{
|
||||
hasItems = true;
|
||||
canOverdrive = true;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void setStats(){
|
||||
super.setStats();
|
||||
@@ -30,6 +28,7 @@ public class BufferedItemBridge extends ItemBridge{
|
||||
stats.add(Stat.itemsMoved, displayedSpeed, StatUnit.itemsSecond);
|
||||
}
|
||||
|
||||
|
||||
public class BufferedItemBridgeBuild extends ItemBridgeBuild{
|
||||
ItemBuffer buffer = new ItemBuffer(bufferCapacity);
|
||||
|
||||
@@ -47,21 +46,12 @@ public class BufferedItemBridge extends ItemBridge{
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addToList(){
|
||||
state.buildings.bufferedItemBridges.add(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeFromList(){
|
||||
state.buildings.bufferedItemBridges.remove(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doDump(){
|
||||
dump();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void write(Writes write){
|
||||
super.write(write);
|
||||
|
||||
@@ -142,7 +142,7 @@ public class Conveyor extends Block implements Autotiler{
|
||||
|
||||
@Override
|
||||
public void draw(){
|
||||
int frame = enabled && clogHeat <= 0.5f ? (int)(((Time.time * speed * 8f * timeScale)) % 4) : 0;
|
||||
int frame = enabled && clogHeat <= 0.5f ? (int)(((Time.time * speed * 8f * timeScale * efficiency)) % 4) : 0;
|
||||
|
||||
//draw extra conveyors facing this one for non-square tiling purposes
|
||||
Draw.z(Layer.blockUnder);
|
||||
@@ -250,8 +250,8 @@ public class Conveyor extends Block implements Autotiler{
|
||||
}
|
||||
}
|
||||
|
||||
public final void updateConveyor(){
|
||||
efficiency = enabled ? 1f : 0f;
|
||||
@Override
|
||||
public void updateTile(){
|
||||
minitem = 1f;
|
||||
mid = 0;
|
||||
|
||||
@@ -263,7 +263,7 @@ public class Conveyor extends Block implements Autotiler{
|
||||
}
|
||||
|
||||
float nextMax = aligned ? 1f - Math.max(itemSpace - nextc.minitem, 0) : 1f;
|
||||
float moved = speed * delta();
|
||||
float moved = speed * edelta();
|
||||
|
||||
for(int i = len - 1; i >= 0; i--){
|
||||
float nextpos = (i == len - 1 ? 100f : ys[i + 1]) - itemSpace;
|
||||
@@ -297,16 +297,6 @@ public class Conveyor extends Block implements Autotiler{
|
||||
noSleep();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addToList(){
|
||||
state.buildings.conveyors.add(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeFromList(){
|
||||
state.buildings.conveyors.remove(this);
|
||||
}
|
||||
|
||||
public boolean pass(Item item){
|
||||
if(item != null && next != null && next.team == team && next.acceptItem(this, item)){
|
||||
next.handleItem(this, item);
|
||||
|
||||
@@ -6,11 +6,10 @@ import mindustry.annotations.Annotations.*;
|
||||
import mindustry.gen.*;
|
||||
import mindustry.graphics.*;
|
||||
import mindustry.type.*;
|
||||
import mindustry.world.blocks.*;
|
||||
import mindustry.world.blocks.liquid.*;
|
||||
import mindustry.world.meta.*;
|
||||
|
||||
import static mindustry.Vars.*;
|
||||
|
||||
public class DirectionLiquidBridge extends DirectionBridge{
|
||||
public final int timerFlow = timers++;
|
||||
|
||||
@@ -35,17 +34,8 @@ public class DirectionLiquidBridge extends DirectionBridge{
|
||||
return new TextureRegion[]{bottomRegion, region, dirRegion};
|
||||
}
|
||||
|
||||
public class DirectionLiquidBridgeBuild extends DirectionBridgeBuild{
|
||||
|
||||
@Override
|
||||
public void addToList(){
|
||||
state.buildings.directionLiquidBridges.add(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeFromList(){
|
||||
state.buildings.directionLiquidBridges.remove(this);
|
||||
}
|
||||
public class DuctBridgeBuild extends DirectionBridgeBuild implements LiquidUpdater{
|
||||
Building next;
|
||||
|
||||
@Override
|
||||
public void drawCached(){
|
||||
@@ -68,20 +58,20 @@ public class DirectionLiquidBridge extends DirectionBridge{
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onProximityUpdate(){
|
||||
super.onProximityUpdate();
|
||||
|
||||
next = front();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateTile(){
|
||||
var link = lastLink = findLink();
|
||||
if(link != null){
|
||||
moveLiquid(link, liquids.current());
|
||||
link.occupied[rotation % 4] = this;
|
||||
}
|
||||
|
||||
if(link == null){
|
||||
if(liquids.currentAmount() > 0.0001f && timer(timerFlow, 1)){
|
||||
moveLiquidForward(false, liquids.current());
|
||||
}
|
||||
}
|
||||
|
||||
for(int i = 0; i < 4; i++){
|
||||
if(occupied[i] == null || occupied[i].rotation != i || !occupied[i].isValid() || occupied[i].lastLink != this){
|
||||
occupied[i] = null;
|
||||
@@ -89,11 +79,22 @@ public class DirectionLiquidBridge extends DirectionBridge{
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateLiquids(float delta){
|
||||
var link = lastLink;
|
||||
if(link != null){
|
||||
moveLiquid(link, liquids.current(), delta);
|
||||
}else{
|
||||
if(liquids.currentAmount() > 0.0001f && timer(timerFlow, 1)){
|
||||
moveLiquidForward(next, false, liquids.current(), Time.delta);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean acceptLiquid(Building source, Liquid liquid){
|
||||
var link = findLink();
|
||||
//only accept if there's an output point, or it comes from a link
|
||||
if(link == null && !(source instanceof DirectionBridgeBuild b && b.findLink() == this)) return false;
|
||||
if(lastLink == null && !(source instanceof DirectionBridgeBuild b && b.findLink() == this)) return false;
|
||||
|
||||
int rel = this.relativeToEdge(source.tile);
|
||||
|
||||
|
||||
@@ -135,16 +135,6 @@ public class Duct extends Block implements Autotiler{
|
||||
public @Nullable Building next;
|
||||
public @Nullable DuctBuild nextc;
|
||||
|
||||
@Override
|
||||
public void addToList(){
|
||||
state.buildings.ducts.add(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeFromList(){
|
||||
state.buildings.ducts.remove(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(){
|
||||
draw(false);
|
||||
@@ -199,7 +189,8 @@ public class Duct extends Block implements Autotiler{
|
||||
}
|
||||
}
|
||||
|
||||
public final void updateDuct(){
|
||||
@Override
|
||||
public void updateTile(){
|
||||
progress += edelta() / speed * 2f;
|
||||
|
||||
if(current != null && next != null){
|
||||
|
||||
@@ -2,10 +2,9 @@ package mindustry.world.blocks.distribution;
|
||||
|
||||
import mindustry.gen.*;
|
||||
import mindustry.type.*;
|
||||
import mindustry.world.*;
|
||||
import mindustry.world.meta.*;
|
||||
|
||||
import static mindustry.Vars.*;
|
||||
|
||||
public class DuctBridge extends DirectionBridge{
|
||||
public float speed = 5f;
|
||||
|
||||
@@ -27,16 +26,6 @@ public class DuctBridge extends DirectionBridge{
|
||||
public class DuctBridgeBuild extends DirectionBridgeBuild{
|
||||
public float progress = 0f;
|
||||
|
||||
@Override
|
||||
public void addToList(){
|
||||
state.buildings.ductBridges.add(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeFromList(){
|
||||
state.buildings.ductBridges.remove(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateTile(){
|
||||
var link = lastLink = findLink();
|
||||
|
||||
@@ -97,16 +97,6 @@ public class DuctRouter extends Block{
|
||||
drawItemSelection(sortItem);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addToList(){
|
||||
state.buildings.ductRouters.add(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeFromList(){
|
||||
state.buildings.ductRouters.remove(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateTile(){
|
||||
progress += edelta() / speed * 2f;
|
||||
|
||||
@@ -199,8 +199,9 @@ public class ItemBridge extends Block{
|
||||
public IntSeq incoming = new IntSeq(false, 4);
|
||||
public float warmup;
|
||||
public float time = -8f, timeSpeed;
|
||||
public boolean wasMoved, moved;
|
||||
public boolean wasMoved, moved, hadValidLink;
|
||||
public float transportCounter;
|
||||
public Building lastValidLink;
|
||||
|
||||
@Override
|
||||
public void pickedUp(){
|
||||
@@ -315,16 +316,6 @@ public class ItemBridge extends Block{
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addToList(){
|
||||
state.buildings.itemBridges.add(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeFromList(){
|
||||
state.buildings.itemBridges.remove(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateTile(){
|
||||
if(timer(timerCheckMoved, 30f)){
|
||||
@@ -340,10 +331,14 @@ public class ItemBridge extends Block{
|
||||
checkIncoming();
|
||||
|
||||
Tile other = world.tile(link);
|
||||
if(!linkValid(tile, other)){
|
||||
hadValidLink = linkValid(tile, other);
|
||||
|
||||
if(!hadValidLink){
|
||||
lastValidLink = null;
|
||||
doDump();
|
||||
warmup = 0f;
|
||||
}else{
|
||||
lastValidLink = other.build;
|
||||
var inc = ((ItemBridgeBuild)other.build).incoming;
|
||||
int pos = tile.pos();
|
||||
if(!inc.contains(pos)){
|
||||
@@ -501,7 +496,7 @@ public class ItemBridge extends Block{
|
||||
|
||||
@Override
|
||||
public boolean shouldConsume(){
|
||||
return linkValid(tile, world.tile(link)) && enabled;
|
||||
return hadValidLink && enabled;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -51,16 +51,8 @@ public class Junction extends Block{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addToList(){
|
||||
state.buildings.junctions.add(this);
|
||||
}
|
||||
public void updateTile(){
|
||||
|
||||
@Override
|
||||
public void removeFromList(){
|
||||
state.buildings.junctions.remove(this);
|
||||
}
|
||||
|
||||
public final void updateJunction(){
|
||||
for(int i = 0; i < 4; i++){
|
||||
if(buffer.indexes[i] > 0){
|
||||
if(buffer.indexes[i] > capacity) buffer.indexes[i] = capacity;
|
||||
|
||||
@@ -9,8 +9,6 @@ import mindustry.world.*;
|
||||
import mindustry.world.blocks.*;
|
||||
import mindustry.world.meta.*;
|
||||
|
||||
import static mindustry.Vars.*;
|
||||
|
||||
public class Router extends Block{
|
||||
public float speed = 8f;
|
||||
|
||||
@@ -53,16 +51,6 @@ public class Router extends Block{
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addToList(){
|
||||
state.buildings.routers.add(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeFromList(){
|
||||
state.buildings.routers.remove(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateTile(){
|
||||
if(lastItem == null && items.any()){
|
||||
|
||||
@@ -7,7 +7,6 @@ import arc.math.geom.*;
|
||||
import arc.struct.*;
|
||||
import arc.util.*;
|
||||
import arc.util.io.*;
|
||||
import mindustry.*;
|
||||
import mindustry.annotations.Annotations.*;
|
||||
import mindustry.content.*;
|
||||
import mindustry.entities.*;
|
||||
@@ -266,18 +265,7 @@ public class StackConveyor extends Block implements Autotiler{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addToList(){
|
||||
Vars.state.buildings.stackConveyors.add(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeFromList(){
|
||||
Vars.state.buildings.stackConveyors.remove(this);
|
||||
}
|
||||
|
||||
public final void updateStackConveyor(){
|
||||
updateConsumption();
|
||||
|
||||
public void updateTile(){
|
||||
//the item still needs to be "reeled" in when disabled
|
||||
float eff = enabled ? (efficiency + baseEfficiency) : 1f;
|
||||
|
||||
|
||||
@@ -55,6 +55,9 @@ public class Conduit extends LiquidBlock implements Autotiler{
|
||||
priority = TargetPriority.transport;
|
||||
drawCached = true;
|
||||
buildingCacheLayer = BuildingCacheLayer.under;
|
||||
|
||||
update = false;
|
||||
destructible = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -153,10 +156,11 @@ public class Conduit extends LiquidBlock implements Autotiler{
|
||||
return new TextureRegion[]{Core.atlas.find("conduit-bottom"), topRegions[0]};
|
||||
}
|
||||
|
||||
public class ConduitBuild extends LiquidBuild implements ChainedBuilding{
|
||||
public class ConduitBuild extends LiquidBuild implements ChainedBuilding, LiquidUpdater{
|
||||
public float smoothLiquid;
|
||||
public int blendbits, xscl = 1, yscl = 1, blending;
|
||||
public boolean capped, backCapped = false;
|
||||
Building next;
|
||||
|
||||
@Override
|
||||
public void drawCached(){
|
||||
@@ -236,38 +240,24 @@ public class Conduit extends LiquidBlock implements Autotiler{
|
||||
Building next = front(), prev = back();
|
||||
capped = next == null || next.team != team || !next.block.hasLiquids;
|
||||
backCapped = blendbits == 0 && (prev == null || prev.team != team || !prev.block.hasLiquids);
|
||||
this.next = next;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean acceptLiquid(Building source, Liquid liquid){
|
||||
noSleep();
|
||||
return (liquids.current() == liquid || liquids.currentAmount() < 0.2f)
|
||||
&& (tile == null || source == this || (source.relativeTo(tile.x, tile.y) + 2) % 4 != rotation);
|
||||
}
|
||||
|
||||
public final void updateConduit(){
|
||||
if(!noUpdateDisabled) return;
|
||||
|
||||
smoothLiquid = Mathf.lerpDelta(smoothLiquid, liquids.currentAmount() / liquidCapacity, 0.05f);
|
||||
@Override
|
||||
public void updateLiquids(float delta){
|
||||
smoothLiquid = Mathf.lerp(smoothLiquid, liquids.currentAmount() / liquidCapacity, 0.05f * delta);
|
||||
|
||||
if(liquids.currentAmount() > 0.0001f && timer(timerFlow, 1)){
|
||||
moveLiquidForward(leaks, liquids.current());
|
||||
noSleep();
|
||||
}else{
|
||||
sleep();
|
||||
moveLiquidForward(next, leaks, liquids.current(), delta);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addToList(){
|
||||
state.buildings.conduits.add(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeFromList(){
|
||||
state.buildings.conduits.remove(this);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Building next(){
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
package mindustry.world.blocks.liquid;
|
||||
|
||||
import arc.util.*;
|
||||
import mindustry.gen.*;
|
||||
import mindustry.world.blocks.*;
|
||||
import mindustry.world.blocks.distribution.*;
|
||||
import mindustry.world.meta.*;
|
||||
|
||||
import static mindustry.Vars.*;
|
||||
|
||||
public class LiquidBridge extends ItemBridge{
|
||||
|
||||
public LiquidBridge(String name){
|
||||
@@ -18,28 +18,27 @@ public class LiquidBridge extends ItemBridge{
|
||||
envEnabled = Env.any;
|
||||
}
|
||||
|
||||
public class LiquidBridgeBuild extends ItemBridgeBuild{
|
||||
|
||||
@Override
|
||||
public void addToList(){
|
||||
state.buildings.liquidBridges.add(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeFromList(){
|
||||
state.buildings.liquidBridges.remove(this);
|
||||
}
|
||||
public class LiquidBridgeBuild extends ItemBridgeBuild implements LiquidUpdater{
|
||||
|
||||
@Override
|
||||
public void updateTransport(Building other){
|
||||
if(warmup >= 0.25f){
|
||||
moved |= moveLiquid(other, liquids.current()) > 0.05f;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doDump(){
|
||||
dumpLiquid(liquids.current(), 1f);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateLiquids(float delta){
|
||||
var link = lastValidLink;
|
||||
|
||||
if(link == null){
|
||||
dumpLiquid(liquids.current(), 1f);
|
||||
}else if(warmup >= 0.25f){
|
||||
moved |= moveLiquid(link, liquids.current(), Time.delta) > 0.05f;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,8 +3,7 @@ package mindustry.world.blocks.liquid;
|
||||
import arc.graphics.g2d.*;
|
||||
import mindustry.gen.*;
|
||||
import mindustry.type.*;
|
||||
|
||||
import static mindustry.Vars.*;
|
||||
import mindustry.world.blocks.*;
|
||||
|
||||
public class LiquidRouter extends LiquidBlock{
|
||||
public float liquidPadding = 0f;
|
||||
@@ -15,6 +14,9 @@ public class LiquidRouter extends LiquidBlock{
|
||||
noUpdateDisabled = true;
|
||||
canOverdrive = false;
|
||||
floating = true;
|
||||
|
||||
update = false;
|
||||
destructible = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -22,22 +24,13 @@ public class LiquidRouter extends LiquidBlock{
|
||||
return new TextureRegion[]{bottomRegion, region};
|
||||
}
|
||||
|
||||
public class LiquidRouterBuild extends LiquidBuild{
|
||||
public class LiquidRouterBuild extends LiquidBuild implements LiquidUpdater{
|
||||
|
||||
public final void updateLiquidRouter(){
|
||||
@Override
|
||||
public void updateLiquids(float delta){
|
||||
dumpLiquid(liquids.current());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addToList(){
|
||||
state.buildings.liquidRouters.add(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeFromList(){
|
||||
state.buildings.liquidRouters.remove(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(){
|
||||
Draw.rect(bottomRegion, x, y);
|
||||
|
||||
@@ -96,7 +96,7 @@ public class LogicBlock extends Block{
|
||||
if(oldSize > entity.links.size){ //check whether any were removed
|
||||
//re-enable the target when unlinking
|
||||
if(lbuild.block.autoResetEnabled && lbuild.lastDisabler == entity){
|
||||
lbuild.setEnabled(true);
|
||||
lbuild.enabled = true;
|
||||
}
|
||||
}else{
|
||||
entity.links.add(new LogicLink(x, y, entity.findLinkName(lbuild.block), true));
|
||||
@@ -456,7 +456,7 @@ public class LogicBlock extends Block{
|
||||
|
||||
for(var link : executor.links){
|
||||
if(!link.enabled && link.lastDisabler == this){
|
||||
link.setEnabled(true);
|
||||
link.enabled = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ public class SwitchBlock extends Block{
|
||||
group = BlockGroup.logic;
|
||||
envEnabled = Env.any;
|
||||
|
||||
config(Boolean.class, (SwitchBuild entity, Boolean b) -> entity.setEnabled(b));
|
||||
config(Boolean.class, (SwitchBuild entity, Boolean b) -> entity.enabled = b);
|
||||
}
|
||||
|
||||
public boolean accessible(){
|
||||
|
||||
@@ -135,6 +135,8 @@ public class PayloadConveyor extends Block{
|
||||
|
||||
@Override
|
||||
public void updateTile(){
|
||||
if(!enabled) return;
|
||||
|
||||
if(item != null){
|
||||
item.update(null, this);
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import mindustry.entities.*;
|
||||
import mindustry.game.EventType.*;
|
||||
import mindustry.graphics.*;
|
||||
import mindustry.type.*;
|
||||
import mindustry.world.blocks.*;
|
||||
import mindustry.world.consumers.*;
|
||||
import mindustry.world.meta.*;
|
||||
|
||||
@@ -93,7 +94,7 @@ public class ConsumeGenerator extends PowerGenerator{
|
||||
}
|
||||
}
|
||||
|
||||
public class ConsumeGeneratorBuild extends GeneratorBuild{
|
||||
public class ConsumeGeneratorBuild extends GeneratorBuild implements LiquidUpdater{
|
||||
public float warmup, totalTime, efficiencyMultiplier = 1f, itemDurationMultiplier = 1;
|
||||
|
||||
@Override
|
||||
@@ -133,19 +134,29 @@ public class ConsumeGenerator extends PowerGenerator{
|
||||
generateTime = 1f;
|
||||
}
|
||||
|
||||
//generation time always goes down, but only at the end so consumeTriggerValid doesn't assume fake items
|
||||
generateTime -= delta() / (itemDuration * itemDurationMultiplier);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldLiquidUpdate(){
|
||||
return outputLiquid != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateLiquids(float delta){
|
||||
if(outputLiquid != null){
|
||||
float added = Math.min(productionEfficiency * delta() * outputLiquid.amount, liquidCapacity - liquids.get(outputLiquid.liquid));
|
||||
float added = Math.min(productionEfficiency * delta * timeScale * outputLiquid.amount, liquidCapacity - liquids.get(outputLiquid.liquid));
|
||||
liquids.add(outputLiquid.liquid, added);
|
||||
dumpLiquid(outputLiquid.liquid);
|
||||
|
||||
if(explodeOnFull && liquids.get(outputLiquid.liquid) >= liquidCapacity - 0.01f){
|
||||
kill();
|
||||
Events.fire(new GeneratorPressureExplodeEvent(this));
|
||||
Core.app.post(() -> {
|
||||
kill();
|
||||
Events.fire(new GeneratorPressureExplodeEvent(this));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
//generation time always goes down, but only at the end so consumeTriggerValid doesn't assume fake items
|
||||
generateTime -= delta() / (itemDuration * itemDurationMultiplier);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -3,7 +3,6 @@ package mindustry.world.blocks.power;
|
||||
import arc.math.*;
|
||||
import arc.struct.*;
|
||||
import arc.util.*;
|
||||
import mindustry.*;
|
||||
import mindustry.gen.*;
|
||||
|
||||
public class PowerGraph{
|
||||
@@ -18,11 +17,7 @@ public class PowerGraph{
|
||||
public final Seq<Building> batteries = new Seq<>(false, 16, Building.class);
|
||||
public final Seq<Building> all = new Seq<>(false, 16, Building.class);
|
||||
|
||||
public int buildingArrayIndex = -1;
|
||||
|
||||
private boolean added;
|
||||
private final boolean shouldUpdate;
|
||||
|
||||
private final @Nullable PowerGraphUpdater entity;
|
||||
private final WindowedMean powerBalance = new WindowedMean(60);
|
||||
private float lastPowerProduced, lastPowerNeeded, lastPowerStored;
|
||||
private float lastScaledPowerIn, lastScaledPowerOut, lastCapacity;
|
||||
@@ -33,12 +28,14 @@ public class PowerGraph{
|
||||
private static int lastGraphID;
|
||||
|
||||
public PowerGraph(){
|
||||
this(true);
|
||||
entity = PowerGraphUpdater.create();
|
||||
entity.graph = this;
|
||||
graphID = lastGraphID++;
|
||||
}
|
||||
|
||||
public PowerGraph(boolean shouldUpdate){
|
||||
public PowerGraph(boolean noEntity){
|
||||
entity = null;
|
||||
graphID = lastGraphID++;
|
||||
this.shouldUpdate = shouldUpdate;
|
||||
}
|
||||
|
||||
public int getID(){
|
||||
@@ -219,8 +216,8 @@ public class PowerGraph{
|
||||
public void update(){
|
||||
if(!consumers.isEmpty() && consumers.first().cheating()){
|
||||
//when cheating, just set status to 1
|
||||
for(int i = 0; i < consumers.size; i++){
|
||||
consumers.items[i].power.status = 1f;
|
||||
for(Building tile : consumers){
|
||||
tile.power.status = 1f;
|
||||
}
|
||||
|
||||
lastPowerNeeded = lastPowerProduced = 1f;
|
||||
@@ -269,12 +266,12 @@ public class PowerGraph{
|
||||
}
|
||||
|
||||
//other entity should be removed as the graph was merged
|
||||
graph.removeUpdate();
|
||||
if(graph.entity != null) graph.entity.remove();
|
||||
|
||||
for(Building tile : graph.all){
|
||||
add(tile);
|
||||
}
|
||||
addUpdate();
|
||||
checkAdd();
|
||||
}
|
||||
|
||||
public void add(Building build){
|
||||
@@ -283,7 +280,7 @@ public class PowerGraph{
|
||||
if(build.power.graph != this || !build.power.init){
|
||||
//any old graph that is added here MUST be invalid, remove it
|
||||
if(build.power.graph != null && build.power.graph != this){
|
||||
build.power.graph.removeUpdate();
|
||||
if(build.power.graph.entity != null) build.power.graph.entity.remove();
|
||||
}
|
||||
|
||||
build.power.graph = this;
|
||||
@@ -303,18 +300,8 @@ public class PowerGraph{
|
||||
}
|
||||
}
|
||||
|
||||
public void addUpdate(){
|
||||
if(added || !shouldUpdate) return;
|
||||
|
||||
added = true;
|
||||
Vars.state.buildings.powerGraphs.add(this);
|
||||
}
|
||||
|
||||
public void removeUpdate(){
|
||||
if(!added) return;
|
||||
|
||||
added = false;
|
||||
Vars.state.buildings.powerGraphs.remove(this);
|
||||
public void checkAdd(){
|
||||
if(entity != null) entity.add();
|
||||
}
|
||||
|
||||
public void clear(){
|
||||
@@ -322,8 +309,8 @@ public class PowerGraph{
|
||||
producers.clear();
|
||||
consumers.clear();
|
||||
batteries.clear();
|
||||
|
||||
removeUpdate();
|
||||
//nothing left
|
||||
if(entity != null) entity.remove();
|
||||
}
|
||||
|
||||
public void reflow(Building tile){
|
||||
@@ -333,7 +320,7 @@ public class PowerGraph{
|
||||
while(queue.size > 0){
|
||||
Building child = queue.removeFirst();
|
||||
add(child);
|
||||
addUpdate();
|
||||
checkAdd();
|
||||
for(Building next : child.getPowerConnections(outArray2)){
|
||||
if(closedSet.add(next.pos())){
|
||||
queue.addLast(next);
|
||||
@@ -361,7 +348,7 @@ public class PowerGraph{
|
||||
|
||||
//create graph for this branch
|
||||
PowerGraph graph = new PowerGraph();
|
||||
graph.addUpdate();
|
||||
graph.checkAdd();
|
||||
graph.add(other);
|
||||
//add to queue for BFS
|
||||
queue.clear();
|
||||
@@ -386,7 +373,7 @@ public class PowerGraph{
|
||||
}
|
||||
|
||||
//implied empty graph here
|
||||
removeUpdate();
|
||||
if(entity != null) entity.remove();
|
||||
}
|
||||
|
||||
public int getId(){
|
||||
|
||||
@@ -10,6 +10,7 @@ import mindustry.game.*;
|
||||
import mindustry.graphics.*;
|
||||
import mindustry.type.*;
|
||||
import mindustry.world.*;
|
||||
import mindustry.world.blocks.*;
|
||||
import mindustry.world.meta.*;
|
||||
|
||||
public class ThermalGenerator extends PowerGenerator{
|
||||
@@ -71,7 +72,7 @@ public class ThermalGenerator extends PowerGenerator{
|
||||
return tile.getLinkedTilesAs(this, tempTiles).sumf(other -> other.floor().attributes.get(attribute)) > minEfficiency;
|
||||
}
|
||||
|
||||
public class ThermalGeneratorBuild extends GeneratorBuild{
|
||||
public class ThermalGeneratorBuild extends GeneratorBuild implements LiquidUpdater{
|
||||
public float sum;
|
||||
|
||||
@Override
|
||||
@@ -81,9 +82,17 @@ public class ThermalGenerator extends PowerGenerator{
|
||||
if(productionEfficiency > 0.1f && Mathf.chanceDelta(effectChance)){
|
||||
generateEffect.at(x + Mathf.range(3f), y + Mathf.range(3f));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldLiquidUpdate(){
|
||||
return outputLiquid != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateLiquids(float delta){
|
||||
if(outputLiquid != null){
|
||||
float added = Math.min(productionEfficiency * delta() * outputLiquid.amount, liquidCapacity - liquids.get(outputLiquid.liquid));
|
||||
float added = Math.min(productionEfficiency * delta * timeScale * outputLiquid.amount, liquidCapacity - liquids.get(outputLiquid.liquid));
|
||||
liquids.add(outputLiquid.liquid, added);
|
||||
dumpLiquid(outputLiquid.liquid);
|
||||
}
|
||||
|
||||
@@ -41,5 +41,10 @@ public class Fracker extends SolidPump{
|
||||
lastPump = 0f;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateLiquids(float delta){
|
||||
dumpLiquid(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -325,7 +325,7 @@ public class GenericCrafter extends Block{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void processLiquids(){
|
||||
public void updateLiquids(float delta){
|
||||
if(outputLiquids != null){
|
||||
for(int i = 0; i < outputLiquids.length; i++){
|
||||
int dir = liquidOutputDirections.length > i ? liquidOutputDirections[i] : -1;
|
||||
|
||||
@@ -114,6 +114,8 @@ public class Pump extends LiquidBlock{
|
||||
public float amount = 0f;
|
||||
public @Nullable Liquid liquidDrop = null;
|
||||
|
||||
float lastPumped;
|
||||
|
||||
@Override
|
||||
public void draw(){
|
||||
drawer.draw(this);
|
||||
@@ -160,16 +162,13 @@ public class Pump extends LiquidBlock{
|
||||
@Override
|
||||
public void updateTile(){
|
||||
if(efficiency > 0 && liquidDrop != null){
|
||||
float maxPump = Math.min(liquidCapacity - liquids.get(liquidDrop), amount * pumpAmount * edelta());
|
||||
liquids.add(liquidDrop, maxPump);
|
||||
|
||||
//does nothing for most pumps, as those do not require items.
|
||||
if((consTimer += delta()) >= consumeTime){
|
||||
consume();
|
||||
consTimer %= 1f;
|
||||
}
|
||||
|
||||
warmup = Mathf.approachDelta(warmup, maxPump > 0.001f ? 1f : 0f, warmupSpeed);
|
||||
warmup = Mathf.approachDelta(warmup, lastPumped > 0.001f ? 1f : 0f, warmupSpeed);
|
||||
}else{
|
||||
warmup = Mathf.approachDelta(warmup, 0f, warmupSpeed);
|
||||
}
|
||||
@@ -178,9 +177,14 @@ public class Pump extends LiquidBlock{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void processLiquids(){
|
||||
if(liquidDrop != null){
|
||||
dumpLiquid(liquidDrop);
|
||||
public void updateLiquids(float delta){
|
||||
var ld = liquidDrop;
|
||||
if(ld != null){
|
||||
float maxPump = Math.min(liquidCapacity - liquids.get(liquidDrop), amount * pumpAmount * efficiency * timeScale * delta);
|
||||
liquids.add(liquidDrop, maxPump);
|
||||
lastPumped = maxPump;
|
||||
|
||||
dumpLiquid(ld);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -121,12 +121,7 @@ public class SolidPump extends Pump{
|
||||
@Override
|
||||
public void updateTile(){
|
||||
liquidDrop = result;
|
||||
float fraction = Math.max(validTiles + boost + (attribute == null ? 0 : attribute.env()), 0);
|
||||
|
||||
if(efficiency > 0 && typeLiquid() < liquidCapacity - 0.001f){
|
||||
float maxPump = Math.min(liquidCapacity - typeLiquid(), pumpAmount * delta() * fraction * efficiency);
|
||||
liquids.add(result, maxPump);
|
||||
lastPump = maxPump / Time.delta;
|
||||
warmup = Mathf.lerpDelta(warmup, 1f, 0.02f);
|
||||
if(Mathf.chance(delta() * updateEffectChance))
|
||||
updateEffect.at(x + Mathf.range(size * 2f), y + Mathf.range(size * 2f));
|
||||
@@ -139,7 +134,12 @@ public class SolidPump extends Pump{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void processLiquids(){
|
||||
public void updateLiquids(float delta){
|
||||
float fraction = Math.max(validTiles + boost + (attribute == null ? 0 : attribute.env()), 0);
|
||||
float maxPump = Math.min(liquidCapacity - typeLiquid(), pumpAmount * delta * timeScale * fraction * efficiency);
|
||||
liquids.add(result, maxPump);
|
||||
lastPump = maxPump / Time.delta;
|
||||
|
||||
dumpLiquid(result);
|
||||
}
|
||||
|
||||
|
||||
@@ -21,7 +21,8 @@ public class LiquidSource extends Block{
|
||||
|
||||
public LiquidSource(String name){
|
||||
super(name);
|
||||
update = true;
|
||||
update = false;
|
||||
destructible = true;
|
||||
solid = true;
|
||||
hasLiquids = true;
|
||||
liquidCapacity = 10000f;
|
||||
@@ -55,11 +56,11 @@ public class LiquidSource extends Block{
|
||||
return new TextureRegion[]{bottomRegion, region};
|
||||
}
|
||||
|
||||
public class LiquidSourceBuild extends Building{
|
||||
public class LiquidSourceBuild extends Building implements LiquidUpdater{
|
||||
public @Nullable Liquid source = null;
|
||||
|
||||
@Override
|
||||
public void updateTile(){
|
||||
public void updateLiquids(float delta){
|
||||
if(source == null){
|
||||
liquids.clear();
|
||||
}else{
|
||||
|
||||
@@ -20,7 +20,9 @@ public class PowerSource extends PowerNode{
|
||||
@Override
|
||||
public void onProximityUpdate(){
|
||||
super.onProximityUpdate();
|
||||
checkAllowUpdate();
|
||||
if(!allowUpdate()){
|
||||
enabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -8,7 +8,6 @@ import arc.util.*;
|
||||
import arc.util.io.*;
|
||||
import arc.util.pooling.*;
|
||||
import arc.util.pooling.Pool.*;
|
||||
import mindustry.*;
|
||||
import mindustry.annotations.Annotations.*;
|
||||
import mindustry.entities.units.*;
|
||||
import mindustry.gen.*;
|
||||
@@ -160,17 +159,8 @@ public class Unloader extends Block{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addToList(){
|
||||
state.buildings.unloaders.add(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeFromList(){
|
||||
state.buildings.unloaders.remove(this);
|
||||
}
|
||||
|
||||
public final void updateUnloader(){
|
||||
if(!enabled || ((unloadTimer += delta()) < speed) || (possibleBlocks.size < 2)) return;
|
||||
public void updateTile(){
|
||||
if(((unloadTimer += delta()) < speed) || (possibleBlocks.size < 2)) return;
|
||||
Item item = null;
|
||||
boolean any = false;
|
||||
|
||||
|
||||
@@ -31,6 +31,7 @@ public class RepairTurret extends Block{
|
||||
|
||||
public float repairRadius = 50f;
|
||||
public float repairSpeed = 0.3f;
|
||||
public float powerUse;
|
||||
public float length = 5f;
|
||||
public float beamWidth = 1f;
|
||||
public float pulseRadius = 6f;
|
||||
@@ -85,6 +86,7 @@ public class RepairTurret extends Block{
|
||||
consume(new ConsumeCoolant(coolantUse)).optional(true, true);
|
||||
}
|
||||
|
||||
consumePowerCond(powerUse, (RepairPointBuild entity) -> entity.target != null);
|
||||
updateClipRadius(repairRadius + tilesize);
|
||||
super.init();
|
||||
}
|
||||
|
||||
@@ -34,9 +34,7 @@ public class ConsumeItemExplode extends ConsumeItemFilter{
|
||||
|
||||
if(item != null){
|
||||
if(Vars.state.rules.reactorExplosions && Mathf.chance(build.delta() * baseChance * Mathf.clamp(item.explosiveness - threshold))){
|
||||
//this can be called in a different thread, so post() it. this is bad for performance, but exploding is just a funny gimmick mechanic anyway, and should not happen in most real games
|
||||
Core.app.post(() -> build.damage(damage));
|
||||
|
||||
build.damage(damage);
|
||||
explodeEffect.at(build.x + Mathf.range(build.block.size * tilesize / 2f), build.y + Mathf.range(build.block.size * tilesize / 2f));
|
||||
Events.fire(Trigger.blastGenerator);
|
||||
}
|
||||
|
||||
@@ -19,9 +19,7 @@ public class ConsumePayloadDynamic extends Consume{
|
||||
@Override
|
||||
public float efficiency(Building build){
|
||||
float mult = multiplier.get(build);
|
||||
var stacks = payloads.get(build);
|
||||
for(int i = 0; i < stacks.size; i ++){
|
||||
var stack = stacks.get(i);
|
||||
for(PayloadStack stack : payloads.get(build)){
|
||||
if(!build.getPayloads().contains(stack.item, Math.round(stack.amount * mult))){
|
||||
return 0f;
|
||||
}
|
||||
@@ -32,9 +30,7 @@ public class ConsumePayloadDynamic extends Consume{
|
||||
@Override
|
||||
public void trigger(Building build){
|
||||
float mult = multiplier.get(build);
|
||||
var stacks = payloads.get(build);
|
||||
for(int i = 0; i < stacks.size; i ++){
|
||||
var stack = stacks.get(i);
|
||||
for(PayloadStack stack : payloads.get(build)){
|
||||
build.getPayloads().remove(stack.item, Math.round(stack.amount * mult));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,14 +5,13 @@ import arc.struct.*;
|
||||
import mindustry.gen.*;
|
||||
import mindustry.type.*;
|
||||
import mindustry.ui.*;
|
||||
import mindustry.world.blocks.payloads.*;
|
||||
import mindustry.world.meta.*;
|
||||
|
||||
public class ConsumePayloads extends Consume{
|
||||
public PayloadStack[] payloads;
|
||||
public Seq<PayloadStack> payloads;
|
||||
|
||||
public ConsumePayloads(Seq<PayloadStack> payloads){
|
||||
this.payloads = payloads.toArray(Payload.class);
|
||||
this.payloads = payloads;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
Reference in New Issue
Block a user