mirror of
https://github.com/Creators-of-Create/Create.git
synced 2025-01-25 20:38:11 +01:00
Deserialization magic
This commit is contained in:
parent
44d59fe793
commit
6d3c3e0d1f
14 changed files with 365 additions and 521 deletions
|
@ -9,7 +9,6 @@ import com.google.gson.Gson;
|
|||
import com.google.gson.GsonBuilder;
|
||||
import com.simibubi.create.api.behaviour.BlockSpoutingBehaviour;
|
||||
import com.simibubi.create.content.CreateItemGroup;
|
||||
import com.simibubi.create.content.contraptions.TorquePropagator;
|
||||
import com.simibubi.create.content.contraptions.components.flywheel.engine.FurnaceEngineModifiers;
|
||||
import com.simibubi.create.content.curiosities.weapons.BuiltinPotatoProjectileTypes;
|
||||
import com.simibubi.create.content.logistics.RedstoneLinkNetworkHandler;
|
||||
|
@ -71,7 +70,6 @@ public class Create {
|
|||
|
||||
public static final ServerSchematicLoader SCHEMATIC_RECEIVER = new ServerSchematicLoader();
|
||||
public static final RedstoneLinkNetworkHandler REDSTONE_LINK_NETWORK_HANDLER = new RedstoneLinkNetworkHandler();
|
||||
public static final TorquePropagator TORQUE_PROPAGATOR = new TorquePropagator();
|
||||
public static final ServerLagger LAGGER = new ServerLagger();
|
||||
public static final Random RANDOM = new Random();
|
||||
|
||||
|
|
|
@ -1,194 +0,0 @@
|
|||
package com.simibubi.create.content.contraptions;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
|
||||
import com.simibubi.create.content.contraptions.base.KineticTileEntity;
|
||||
import com.simibubi.create.content.contraptions.components.flywheel.FlywheelTileEntity;
|
||||
import com.simibubi.create.foundation.advancement.AllTriggers;
|
||||
|
||||
public class KineticNetwork {
|
||||
|
||||
public Long id;
|
||||
public boolean initialized;
|
||||
public boolean containsFlywheel;
|
||||
public Map<KineticTileEntity, Float> sources;
|
||||
public Map<KineticTileEntity, Float> members;
|
||||
|
||||
private float currentCapacity;
|
||||
private float currentStress;
|
||||
private float unloadedCapacity;
|
||||
private float unloadedStress;
|
||||
private int unloadedMembers;
|
||||
|
||||
public KineticNetwork() {
|
||||
sources = new HashMap<>();
|
||||
members = new HashMap<>();
|
||||
containsFlywheel = false;
|
||||
}
|
||||
|
||||
public void initFromTE(float maxStress, float currentStress, int members) {
|
||||
unloadedCapacity = maxStress;
|
||||
unloadedStress = currentStress;
|
||||
unloadedMembers = members;
|
||||
initialized = true;
|
||||
updateStress();
|
||||
updateCapacity();
|
||||
}
|
||||
|
||||
public void addSilently(KineticTileEntity te, float lastCapacity, float lastStress) {
|
||||
if (members.containsKey(te))
|
||||
return;
|
||||
if (te.isSource()) {
|
||||
unloadedCapacity -= lastCapacity * getStressMultiplierForSpeed(te.getGeneratedSpeed());
|
||||
float addedStressCapacity = te.calculateAddedStressCapacity();
|
||||
sources.put(te, addedStressCapacity);
|
||||
containsFlywheel |= te instanceof FlywheelTileEntity;
|
||||
}
|
||||
|
||||
unloadedStress -= lastStress * getStressMultiplierForSpeed(te.getTheoreticalSpeed());
|
||||
float stressApplied = te.calculateStressApplied();
|
||||
members.put(te, stressApplied);
|
||||
|
||||
unloadedMembers--;
|
||||
if (unloadedMembers < 0)
|
||||
unloadedMembers = 0;
|
||||
if (unloadedCapacity < 0)
|
||||
unloadedCapacity = 0;
|
||||
if (unloadedStress < 0)
|
||||
unloadedStress = 0;
|
||||
}
|
||||
|
||||
public void add(KineticTileEntity te) {
|
||||
if (members.containsKey(te))
|
||||
return;
|
||||
if (te.isSource())
|
||||
sources.put(te, te.calculateAddedStressCapacity());
|
||||
members.put(te, te.calculateStressApplied());
|
||||
updateFromNetwork(te);
|
||||
//te.networkDirty = true;
|
||||
}
|
||||
|
||||
public void updateCapacityFor(KineticTileEntity te, float capacity) {
|
||||
sources.put(te, capacity);
|
||||
updateCapacity();
|
||||
}
|
||||
|
||||
public void updateStressFor(KineticTileEntity te, float stress) {
|
||||
members.put(te, stress);
|
||||
updateStress();
|
||||
}
|
||||
|
||||
public void remove(KineticTileEntity te) {
|
||||
if (!members.containsKey(te))
|
||||
return;
|
||||
if (te.isSource())
|
||||
sources.remove(te);
|
||||
members.remove(te);
|
||||
te.updateFromNetwork(0, 0, 0);
|
||||
|
||||
if (members.isEmpty()) {
|
||||
TorquePropagator.networks.get(te.getLevel())
|
||||
.remove(this.id);
|
||||
return;
|
||||
}
|
||||
|
||||
// members.keySet()
|
||||
// .stream()
|
||||
// .findFirst()
|
||||
// .map(member -> member.networkDirty = true);
|
||||
}
|
||||
|
||||
public void sync() {
|
||||
for (KineticTileEntity te : members.keySet())
|
||||
updateFromNetwork(te);
|
||||
}
|
||||
|
||||
private void updateFromNetwork(KineticTileEntity te) {
|
||||
boolean wasOverStressed = te.isOverStressed();
|
||||
te.updateFromNetwork(currentCapacity, currentStress, getSize());
|
||||
if (!wasOverStressed && te.isOverStressed() && te.getTheoreticalSpeed() != 0) {
|
||||
AllTriggers.triggerForNearbyPlayers(AllTriggers.OVERSTRESSED, te.getLevel(), te.getBlockPos(), 4);
|
||||
if (containsFlywheel)
|
||||
AllTriggers.triggerForNearbyPlayers(AllTriggers.OVERSTRESS_FLYWHEEL, te.getLevel(), te.getBlockPos(), 4);
|
||||
}
|
||||
}
|
||||
|
||||
public void updateCapacity() {
|
||||
float newMaxStress = calculateCapacity();
|
||||
if (currentCapacity != newMaxStress) {
|
||||
currentCapacity = newMaxStress;
|
||||
sync();
|
||||
}
|
||||
}
|
||||
|
||||
public void updateStress() {
|
||||
float newStress = calculateStress();
|
||||
if (currentStress != newStress) {
|
||||
currentStress = newStress;
|
||||
sync();
|
||||
}
|
||||
}
|
||||
|
||||
public void updateNetwork() {
|
||||
float newStress = calculateStress();
|
||||
float newMaxStress = calculateCapacity();
|
||||
if (currentStress != newStress || currentCapacity != newMaxStress) {
|
||||
currentStress = newStress;
|
||||
currentCapacity = newMaxStress;
|
||||
sync();
|
||||
}
|
||||
}
|
||||
|
||||
public float calculateCapacity() {
|
||||
float presentCapacity = 0;
|
||||
containsFlywheel = false;
|
||||
for (Iterator<KineticTileEntity> iterator = sources.keySet()
|
||||
.iterator(); iterator.hasNext();) {
|
||||
KineticTileEntity te = iterator.next();
|
||||
if (te.getLevel()
|
||||
.getBlockEntity(te.getBlockPos()) != te) {
|
||||
iterator.remove();
|
||||
continue;
|
||||
}
|
||||
containsFlywheel |= te instanceof FlywheelTileEntity;
|
||||
presentCapacity += getActualCapacityOf(te);
|
||||
}
|
||||
float newMaxStress = presentCapacity + unloadedCapacity;
|
||||
return newMaxStress;
|
||||
}
|
||||
|
||||
public float calculateStress() {
|
||||
float presentStress = 0;
|
||||
for (Iterator<KineticTileEntity> iterator = members.keySet()
|
||||
.iterator(); iterator.hasNext();) {
|
||||
KineticTileEntity te = iterator.next();
|
||||
if (te.getLevel()
|
||||
.getBlockEntity(te.getBlockPos()) != te) {
|
||||
iterator.remove();
|
||||
continue;
|
||||
}
|
||||
presentStress += getActualStressOf(te);
|
||||
}
|
||||
float newStress = presentStress + unloadedStress;
|
||||
return newStress;
|
||||
}
|
||||
|
||||
public float getActualCapacityOf(KineticTileEntity te) {
|
||||
return sources.get(te) * getStressMultiplierForSpeed(te.getGeneratedSpeed());
|
||||
}
|
||||
|
||||
public float getActualStressOf(KineticTileEntity te) {
|
||||
return members.get(te) * getStressMultiplierForSpeed(te.getTheoreticalSpeed());
|
||||
}
|
||||
|
||||
private static float getStressMultiplierForSpeed(float speed) {
|
||||
return Math.abs(speed);
|
||||
}
|
||||
|
||||
public int getSize() {
|
||||
return unloadedMembers + members.size();
|
||||
}
|
||||
|
||||
}
|
|
@ -1,42 +0,0 @@
|
|||
package com.simibubi.create.content.contraptions;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import com.simibubi.create.Create;
|
||||
import com.simibubi.create.content.contraptions.base.KineticTileEntity;
|
||||
import com.simibubi.create.foundation.utility.WorldHelper;
|
||||
|
||||
import net.minecraft.world.level.LevelAccessor;
|
||||
|
||||
public class TorquePropagator {
|
||||
|
||||
static Map<LevelAccessor, Map<Long, KineticNetwork>> networks = new HashMap<>();
|
||||
|
||||
public void onLoadWorld(LevelAccessor world) {
|
||||
networks.put(world, new HashMap<>());
|
||||
Create.LOGGER.debug("Prepared Kinetic Network Space for " + WorldHelper.getDimensionID(world));
|
||||
}
|
||||
|
||||
public void onUnloadWorld(LevelAccessor world) {
|
||||
networks.remove(world);
|
||||
Create.LOGGER.debug("Removed Kinetic Network Space for " + WorldHelper.getDimensionID(world));
|
||||
}
|
||||
|
||||
public KineticNetwork getOrCreateNetworkFor(KineticTileEntity te) {
|
||||
Long id = te.network;
|
||||
KineticNetwork network;
|
||||
Map<Long, KineticNetwork> map = networks.get(te.getLevel());
|
||||
if (id == null)
|
||||
return null;
|
||||
|
||||
if (!map.containsKey(id)) {
|
||||
network = new KineticNetwork();
|
||||
network.id = te.network;
|
||||
map.put(id, network);
|
||||
}
|
||||
network = map.get(id);
|
||||
return network;
|
||||
}
|
||||
|
||||
}
|
|
@ -2,16 +2,8 @@ package com.simibubi.create.content.contraptions.base;
|
|||
|
||||
import java.util.List;
|
||||
|
||||
import com.simibubi.create.content.contraptions.KineticNetwork;
|
||||
import com.simibubi.create.content.contraptions.base.IRotate.SpeedLevel;
|
||||
import com.simibubi.create.content.contraptions.goggles.IHaveGoggleInformation;
|
||||
import com.simibubi.create.foundation.utility.Lang;
|
||||
|
||||
import net.minecraft.ChatFormatting;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.network.chat.TextComponent;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraft.world.level.block.entity.BlockEntityType;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
|
||||
|
@ -23,28 +15,6 @@ public abstract class GeneratingKineticTileEntity extends KineticTileEntity {
|
|||
super(typeIn, pos, state);
|
||||
}
|
||||
|
||||
protected void notifyStressCapacityChange(float capacity) {
|
||||
getOrCreateNetwork().updateCapacityFor(this, capacity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeSource() {
|
||||
if (hasSource() && isSource())
|
||||
reActivateSource = true;
|
||||
super.removeSource();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSource(BlockPos source) {
|
||||
super.setSource(source);
|
||||
BlockEntity tileEntity = level.getBlockEntity(source);
|
||||
if (!(tileEntity instanceof KineticTileEntity))
|
||||
return;
|
||||
KineticTileEntity sourceTe = (KineticTileEntity) tileEntity;
|
||||
if (reActivateSource && Math.abs(sourceTe.getSpeed()) >= Math.abs(getGeneratedSpeed()))
|
||||
reActivateSource = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tick() {
|
||||
super.tick();
|
||||
|
@ -58,107 +28,59 @@ public abstract class GeneratingKineticTileEntity extends KineticTileEntity {
|
|||
public boolean addToGoggleTooltip(List<Component> tooltip, boolean isPlayerSneaking) {
|
||||
boolean added = super.addToGoggleTooltip(tooltip, isPlayerSneaking);
|
||||
|
||||
float stressBase = calculateAddedStressCapacity();
|
||||
if (stressBase != 0 && IRotate.StressImpact.isEnabled()) {
|
||||
tooltip.add(componentSpacing.plainCopy().append(Lang.translate("gui.goggles.generator_stats")));
|
||||
tooltip.add(componentSpacing.plainCopy().append(Lang.translate("tooltip.capacityProvided").withStyle(ChatFormatting.GRAY)));
|
||||
|
||||
float speed = getTheoreticalSpeed();
|
||||
if (speed != getGeneratedSpeed() && speed != 0)
|
||||
stressBase *= getGeneratedSpeed() / speed;
|
||||
|
||||
speed = Math.abs(speed);
|
||||
float stressTotal = stressBase * speed;
|
||||
|
||||
tooltip.add(
|
||||
componentSpacing.plainCopy()
|
||||
.append(new TextComponent(" " + IHaveGoggleInformation.format(stressTotal))
|
||||
.append(Lang.translate("generic.unit.stress"))
|
||||
.withStyle(ChatFormatting.AQUA))
|
||||
.append(" ")
|
||||
.append(Lang.translate("gui.goggles.at_current_speed").withStyle(ChatFormatting.DARK_GRAY)));
|
||||
|
||||
added = true;
|
||||
}
|
||||
// float stressBase = calculateAddedStressCapacity();
|
||||
// if (stressBase != 0 && IRotate.StressImpact.isEnabled()) {
|
||||
// tooltip.add(componentSpacing.plainCopy().append(Lang.translate("gui.goggles.generator_stats")));
|
||||
// tooltip.add(componentSpacing.plainCopy().append(Lang.translate("tooltip.capacityProvided").withStyle(ChatFormatting.GRAY)));
|
||||
//
|
||||
// float speed = getTheoreticalSpeed();
|
||||
// if (speed != getGeneratedSpeed() && speed != 0)
|
||||
// stressBase *= getGeneratedSpeed() / speed;
|
||||
//
|
||||
// speed = Math.abs(speed);
|
||||
// float stressTotal = stressBase * speed;
|
||||
//
|
||||
// tooltip.add(
|
||||
// componentSpacing.plainCopy()
|
||||
// .append(new TextComponent(" " + IHaveGoggleInformation.format(stressTotal))
|
||||
// .append(Lang.translate("generic.unit.stress"))
|
||||
// .withStyle(ChatFormatting.AQUA))
|
||||
// .append(" ")
|
||||
// .append(Lang.translate("gui.goggles.at_current_speed").withStyle(ChatFormatting.DARK_GRAY)));
|
||||
//
|
||||
// added = true;
|
||||
// }
|
||||
|
||||
return added;
|
||||
}
|
||||
|
||||
public void updateGeneratedRotation() {
|
||||
float speed = getGeneratedSpeed();
|
||||
float prevSpeed = this.speed;
|
||||
|
||||
if (level.isClientSide)
|
||||
return;
|
||||
|
||||
if (prevSpeed != speed) {
|
||||
if (!hasSource()) {
|
||||
SpeedLevel levelBefore = SpeedLevel.of(this.speed);
|
||||
SpeedLevel levelafter = SpeedLevel.of(speed);
|
||||
if (levelBefore != levelafter)
|
||||
effects.queueRotationIndicators();
|
||||
}
|
||||
|
||||
applyNewSpeed(prevSpeed, speed);
|
||||
}
|
||||
|
||||
if (hasNetwork() && speed != 0) {
|
||||
KineticNetwork network = getOrCreateNetwork();
|
||||
notifyStressCapacityChange(calculateAddedStressCapacity());
|
||||
getOrCreateNetwork().updateStressFor(this, calculateStressApplied());
|
||||
network.updateStress();
|
||||
}
|
||||
|
||||
onSpeedChanged(prevSpeed);
|
||||
sendData();
|
||||
}
|
||||
|
||||
public void applyNewSpeed(float prevSpeed, float speed) {
|
||||
|
||||
// Speed changed to 0
|
||||
if (speed == 0) {
|
||||
if (hasSource()) {
|
||||
notifyStressCapacityChange(0);
|
||||
getOrCreateNetwork().updateStressFor(this, calculateStressApplied());
|
||||
return;
|
||||
}
|
||||
detachKinetics();
|
||||
setSpeed(0);
|
||||
setNetwork(null);
|
||||
return;
|
||||
}
|
||||
|
||||
// Now turning - create a new Network
|
||||
if (prevSpeed == 0) {
|
||||
setSpeed(speed);
|
||||
setNetwork(createNetworkId());
|
||||
attachKinetics();
|
||||
return;
|
||||
}
|
||||
|
||||
// Change speed when overpowered by other generator
|
||||
if (hasSource()) {
|
||||
|
||||
// Staying below Overpowered speed
|
||||
if (Math.abs(prevSpeed) >= Math.abs(speed)) {
|
||||
if (Math.signum(prevSpeed) != Math.signum(speed))
|
||||
level.destroyBlock(worldPosition, true);
|
||||
return;
|
||||
}
|
||||
|
||||
// Faster than attached network -> become the new source
|
||||
detachKinetics();
|
||||
setSpeed(speed);
|
||||
source = null;
|
||||
setNetwork(createNetworkId());
|
||||
attachKinetics();
|
||||
return;
|
||||
}
|
||||
|
||||
// Reapply source
|
||||
detachKinetics();
|
||||
setSpeed(speed);
|
||||
attachKinetics();
|
||||
// float speed = getGeneratedSpeed();
|
||||
// float prevSpeed = this.speed;
|
||||
//
|
||||
// if (level.isClientSide)
|
||||
// return;
|
||||
//
|
||||
// if (prevSpeed != speed) {
|
||||
// if (!hasSource()) {
|
||||
// SpeedLevel levelBefore = SpeedLevel.of(this.speed);
|
||||
// SpeedLevel levelafter = SpeedLevel.of(speed);
|
||||
// if (levelBefore != levelafter)
|
||||
// effects.queueRotationIndicators();
|
||||
// }
|
||||
//
|
||||
// applyNewSpeed(prevSpeed, speed);
|
||||
// }
|
||||
//
|
||||
// if (hasNetwork() && speed != 0) {
|
||||
// KineticNetwork network = getOrCreateNetwork();
|
||||
// notifyStressCapacityChange(calculateAddedStressCapacity());
|
||||
// getOrCreateNetwork().updateStressFor(this, calculateStressApplied());
|
||||
// network.updateStress();
|
||||
// }
|
||||
//
|
||||
// onSpeedChanged(prevSpeed);
|
||||
// sendData();
|
||||
}
|
||||
|
||||
public Long createNetworkId() {
|
||||
|
|
|
@ -10,8 +10,6 @@ import javax.annotation.Nullable;
|
|||
|
||||
import com.jozufozu.flywheel.api.FlywheelRendered;
|
||||
import com.jozufozu.flywheel.backend.instancing.InstancedRenderDispatcher;
|
||||
import com.simibubi.create.Create;
|
||||
import com.simibubi.create.content.contraptions.KineticNetwork;
|
||||
import com.simibubi.create.content.contraptions.base.IRotate.SpeedLevel;
|
||||
import com.simibubi.create.content.contraptions.base.IRotate.StressImpact;
|
||||
import com.simibubi.create.content.contraptions.goggles.IHaveGoggleInformation;
|
||||
|
@ -19,6 +17,7 @@ import com.simibubi.create.content.contraptions.goggles.IHaveHoveringInformation
|
|||
import com.simibubi.create.content.contraptions.relays.elementary.ICogWheel;
|
||||
import com.simibubi.create.content.contraptions.relays.gearbox.GearboxBlock;
|
||||
import com.simibubi.create.content.contraptions.solver.AllConnections;
|
||||
import com.simibubi.create.content.contraptions.solver.IKineticController;
|
||||
import com.simibubi.create.content.contraptions.solver.KineticConnections;
|
||||
import com.simibubi.create.content.contraptions.solver.KineticSolver;
|
||||
import com.simibubi.create.foundation.block.BlockStressValues;
|
||||
|
@ -51,7 +50,7 @@ import net.minecraftforge.api.distmarker.OnlyIn;
|
|||
import net.minecraftforge.fml.DistExecutor;
|
||||
|
||||
public class KineticTileEntity extends SmartTileEntity
|
||||
implements IHaveGoggleInformation, IHaveHoveringInformation, FlywheelRendered {
|
||||
implements IHaveGoggleInformation, IHaveHoveringInformation, FlywheelRendered, IKineticController {
|
||||
|
||||
public @Nullable Long network = null;
|
||||
public @Nullable BlockPos source = null;
|
||||
|
@ -69,35 +68,25 @@ public class KineticTileEntity extends SmartTileEntity
|
|||
protected float lastStressApplied;
|
||||
protected float lastCapacityProvided;
|
||||
|
||||
private KineticConnections connections = AllConnections.EMPTY;
|
||||
private final KineticConnections connections;
|
||||
|
||||
public KineticTileEntity(BlockEntityType<?> typeIn, BlockPos pos, BlockState state) {
|
||||
super(typeIn, pos, state);
|
||||
|
||||
effects = new KineticEffectHandler(this);
|
||||
|
||||
if (state.getBlock() instanceof IRotate rotate) {
|
||||
connections = rotate.getInitialConnections(state);
|
||||
} else {
|
||||
connections = AllConnections.EMPTY;
|
||||
}
|
||||
}
|
||||
|
||||
public KineticConnections getConnections() {
|
||||
return connections;
|
||||
}
|
||||
@Override public KineticConnections getConnections() { return connections; }
|
||||
|
||||
public float getGeneratedSpeed() {
|
||||
return 0;
|
||||
}
|
||||
@Override public float getStressImpact() { return getDefaultStressImpact(); }
|
||||
|
||||
public float getStressImpact() {
|
||||
return getDefaultStressImpact();
|
||||
}
|
||||
|
||||
public float getStressCapacity() {
|
||||
return getDefaultStressCapacity();
|
||||
}
|
||||
|
||||
public boolean isStressConstant() {
|
||||
return false;
|
||||
}
|
||||
@Override public float getStressCapacity() { return getDefaultStressCapacity(); }
|
||||
|
||||
public float getDefaultStressImpact() {
|
||||
return (float) BlockStressValues.getImpact(getStressConfigKey());
|
||||
|
@ -129,9 +118,9 @@ public class KineticTileEntity extends SmartTileEntity
|
|||
super.tick();
|
||||
effects.tick();
|
||||
|
||||
if (!level.isClientSide) {
|
||||
KineticSolver.getSolver(level).updateNode(this);
|
||||
}
|
||||
// if (!level.isClientSide) {
|
||||
// KineticSolver.getSolver(level).updateNode(this);
|
||||
// }
|
||||
|
||||
if (level.isClientSide) {
|
||||
cachedBoundingBox = null; // cache the bounding box for every frame between ticks
|
||||
|
@ -161,9 +150,7 @@ public class KineticTileEntity extends SmartTileEntity
|
|||
super.onChunkUnloaded();
|
||||
if (!level.isClientSide) {
|
||||
preKineticsUnloaded();
|
||||
KineticSolver solver = KineticSolver.getSolver(level);
|
||||
solver.updateNode(this);
|
||||
solver.unloadNode(this);
|
||||
KineticSolver.getSolver(level).unloadNode(this);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -312,7 +299,8 @@ public class KineticTileEntity extends SmartTileEntity
|
|||
}
|
||||
|
||||
public boolean isSource() {
|
||||
return getGeneratedSpeed() != 0;
|
||||
//return getGeneratedSpeed() != 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
public float getSpeed() {
|
||||
|
@ -378,10 +366,6 @@ public class KineticTileEntity extends SmartTileEntity
|
|||
// network.add(this);
|
||||
}
|
||||
|
||||
public KineticNetwork getOrCreateNetwork() {
|
||||
return Create.TORQUE_PROPAGATOR.getOrCreateNetworkFor(this);
|
||||
}
|
||||
|
||||
public boolean hasNetwork() {
|
||||
return network != null;
|
||||
}
|
||||
|
|
|
@ -7,15 +7,20 @@ import com.simibubi.create.content.contraptions.base.KineticTileEntity;
|
|||
import com.simibubi.create.content.contraptions.components.motor.CreativeMotorTileEntity;
|
||||
import com.simibubi.create.content.contraptions.relays.elementary.CogWheelBlock;
|
||||
import com.simibubi.create.content.contraptions.relays.elementary.ICogWheel;
|
||||
import com.simibubi.create.content.contraptions.solver.KineticControllerSerial;
|
||||
import com.simibubi.create.content.contraptions.solver.KineticNode;
|
||||
import com.simibubi.create.content.contraptions.solver.KineticSolver;
|
||||
import com.simibubi.create.foundation.config.AllConfigs;
|
||||
import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour;
|
||||
import com.simibubi.create.foundation.tileEntity.behaviour.ValueBoxTransform;
|
||||
import com.simibubi.create.foundation.tileEntity.behaviour.scrollvalue.ScrollValueBehaviour;
|
||||
import com.simibubi.create.foundation.utility.Lang;
|
||||
import com.simibubi.create.foundation.utility.Pair;
|
||||
import com.simibubi.create.foundation.utility.VecHelper;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.block.entity.BlockEntityType;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
|
@ -57,16 +62,15 @@ public class SpeedControllerTileEntity extends KineticTileEntity {
|
|||
return targetSpeed.getValue();
|
||||
}
|
||||
|
||||
private void updateTargetRotation() {
|
||||
if (hasNetwork())
|
||||
getOrCreateNetwork().remove(this);
|
||||
RotationPropagator.handleRemoved(level, worldPosition, this);
|
||||
removeSource();
|
||||
attachKinetics();
|
||||
@Override
|
||||
public void onUpdate(Level level, KineticSolver solver, KineticNode node) {
|
||||
solver.getNode(node.getPos().above())
|
||||
.filter(n -> node.getActiveStressOnlyConnections().anyMatch(m -> m == n))
|
||||
.ifPresent(n -> n.setController(node, KineticControllerSerial.SPEED_CONTROLLER_COG));
|
||||
}
|
||||
|
||||
public static float getConveyedSpeed(KineticTileEntity cogWheel, KineticTileEntity speedControllerIn,
|
||||
boolean targetingController) {
|
||||
boolean targetingController) {
|
||||
if (!(speedControllerIn instanceof SpeedControllerTileEntity))
|
||||
return 0;
|
||||
|
||||
|
|
|
@ -2,11 +2,7 @@ package com.simibubi.create.content.contraptions.relays.elementary;
|
|||
|
||||
import com.simibubi.create.content.contraptions.base.KineticTileEntity;
|
||||
|
||||
import com.simibubi.create.content.contraptions.relays.advanced.SpeedControllerTileEntity;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraft.world.level.block.entity.BlockEntityType;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.phys.AABB;
|
||||
|
@ -27,13 +23,4 @@ public class SimpleKineticTileEntity extends KineticTileEntity {
|
|||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getGeneratedSpeed() {
|
||||
BlockPos belowPos = getBlockPos().below();
|
||||
if (isStressOnlyConnected(belowPos)
|
||||
&& level.getBlockEntity(belowPos) instanceof SpeedControllerTileEntity controller
|
||||
&& controller.getSpeed() != 0)
|
||||
return controller.getTargetSpeed();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -57,7 +57,7 @@ public class StressGaugeTileEntity extends GaugeTileEntity {
|
|||
return;
|
||||
}
|
||||
|
||||
updateFromNetwork(capacity, stress, getOrCreateNetwork().getSize());
|
||||
updateFromNetwork(capacity, stress, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
package com.simibubi.create.content.contraptions.solver;
|
||||
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.world.level.Level;
|
||||
|
||||
public interface IKineticController {
|
||||
default void onUpdate(Level level, KineticSolver solver, KineticNode node) { }
|
||||
|
||||
default KineticConnections getConnections() {
|
||||
return AllConnections.EMPTY;
|
||||
}
|
||||
|
||||
default float getGeneratedSpeed() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
default float getStressImpact() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
default float getStressCapacity() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
default boolean isStressConstant() {
|
||||
return false;
|
||||
}
|
||||
|
||||
default CompoundTag save(CompoundTag tag) { return tag; }
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
package com.simibubi.create.content.contraptions.solver;
|
||||
|
||||
import com.simibubi.create.content.contraptions.relays.advanced.SpeedControllerTileEntity;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.world.level.Level;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
public enum KineticControllerSerial {
|
||||
|
||||
SPEED_CONTROLLER_COG {
|
||||
class Controller implements IKineticController {
|
||||
private final KineticConnections connections;
|
||||
private float targetSpeed;
|
||||
private float generatedSpeed;
|
||||
|
||||
public Controller(KineticConnections connections, float targetSpeed) {
|
||||
this.connections = connections;
|
||||
this.targetSpeed = targetSpeed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public KineticConnections getConnections() {
|
||||
return connections;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUpdate(Level level, KineticSolver solver, KineticNode node) {
|
||||
BlockPos below = node.getPos().below();
|
||||
if (level.getBlockEntity(below) instanceof SpeedControllerTileEntity se) {
|
||||
targetSpeed = se.getTargetSpeed();
|
||||
}
|
||||
|
||||
Optional<KineticNode> seNode = solver.getNode(below);
|
||||
if (seNode.isPresent() && seNode.get().getTheoreticalSpeed() != 0) {
|
||||
generatedSpeed = targetSpeed;
|
||||
} else {
|
||||
generatedSpeed = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getGeneratedSpeed() {
|
||||
return generatedSpeed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompoundTag save(CompoundTag tag) {
|
||||
tag.put("Connections", connections.save(new CompoundTag()));
|
||||
tag.putFloat("Target", targetSpeed);
|
||||
return tag;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public IKineticController init(KineticNode prev) {
|
||||
return new Controller(prev.getConnections(), 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IKineticController load(CompoundTag tag) {
|
||||
KineticConnections connections = KineticConnections.load(tag.getCompound("Connections"));
|
||||
float target = tag.getFloat("Target");
|
||||
return new Controller(connections, target);
|
||||
}
|
||||
};
|
||||
|
||||
public abstract IKineticController init(KineticNode prev);
|
||||
public abstract IKineticController load(CompoundTag tag);
|
||||
|
||||
}
|
|
@ -10,6 +10,7 @@ import java.util.HashSet;
|
|||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class KineticNetwork {
|
||||
|
@ -28,18 +29,18 @@ public class KineticNetwork {
|
|||
private final Set<KineticNode> potentialNewBranches = new HashSet<>();
|
||||
|
||||
private final ResetableLazy<Float> totalStressImpact = ResetableLazy.of(() ->
|
||||
(float) members.stream().mapToDouble(n -> n.getTotalStressImpact(rootTheoreticalSpeed)).sum());
|
||||
(float) members.stream().mapToDouble(KineticNode::getTotalStressImpact).sum());
|
||||
private final ResetableLazy<Float> totalStressCapacity = ResetableLazy.of(() ->
|
||||
(float) members.stream().mapToDouble(KineticNode::getStressCapacity).sum());
|
||||
|
||||
private boolean ticked;
|
||||
private final Set<KineticNode> stressConnectors = new HashSet<>();
|
||||
|
||||
public KineticNetwork(KineticNode root) {
|
||||
protected KineticNetwork(KineticNode root) {
|
||||
addMember(root);
|
||||
}
|
||||
|
||||
public void addMember(KineticNode node) {
|
||||
protected void addMember(KineticNode node) {
|
||||
members.add(node);
|
||||
potentialNewBranches.add(node);
|
||||
if (node.getConnections().hasStressOnlyConnections()) stressConnectors.add(node);
|
||||
|
@ -52,11 +53,11 @@ public class KineticNetwork {
|
|||
if (node.hasStressCapacity()) onMemberStressCapacityUpdated();
|
||||
}
|
||||
|
||||
public void onMemberLoaded(KineticNode node) {
|
||||
protected void onMemberLoaded(KineticNode node) {
|
||||
potentialNewBranches.add(node);
|
||||
}
|
||||
|
||||
public void onMemberGeneratedSpeedUpdated(KineticNode node) {
|
||||
protected void onMemberGeneratedSpeedUpdated(KineticNode node) {
|
||||
if (node.isGenerator()) {
|
||||
generators.add(node);
|
||||
} else {
|
||||
|
@ -66,15 +67,15 @@ public class KineticNetwork {
|
|||
onMemberStressCapacityUpdated();
|
||||
}
|
||||
|
||||
public void onMemberStressImpactUpdated() {
|
||||
protected void onMemberStressImpactUpdated() {
|
||||
totalStressImpact.reset();
|
||||
}
|
||||
|
||||
public void onMemberStressCapacityUpdated() {
|
||||
protected void onMemberStressCapacityUpdated() {
|
||||
totalStressCapacity.reset();
|
||||
}
|
||||
|
||||
public void removeMember(KineticNode node) {
|
||||
protected void removeMember(KineticNode node) {
|
||||
if (node.isGenerator() && generators.contains(node)) {
|
||||
generators.remove(node);
|
||||
rootSpeedDirty = true;
|
||||
|
@ -87,25 +88,25 @@ public class KineticNetwork {
|
|||
conflictingCycles.removeIf(p -> p.getFirst() == node || p.getSecond() == node);
|
||||
}
|
||||
|
||||
public void markConflictingCycle(KineticNode from, KineticNode to) {
|
||||
protected void markConflictingCycle(KineticNode from, KineticNode to) {
|
||||
if (!members.contains(from) || !members.contains(to)) throw new IllegalArgumentException();
|
||||
conflictingCycles.add(Pair.of(from, to));
|
||||
}
|
||||
|
||||
public boolean isStopped() { return generators.isEmpty() || overstressed; }
|
||||
protected boolean isStopped() { return generators.isEmpty() || overstressed; }
|
||||
|
||||
/**
|
||||
* Recalculates the speed at the root node of this network.
|
||||
* @return CONTRADICTION if the network has cycles with conflicting speed ratios or generators turning against
|
||||
* each other, and OK otherwise
|
||||
*/
|
||||
public SolveResult tryRecalculateSpeed() {
|
||||
protected SolveResult tryRecalculateSpeed() {
|
||||
SolveResult result = tryRecalculateTheoreticalSpeed();
|
||||
if (isStopped()) return SolveResult.OK;
|
||||
return result;
|
||||
}
|
||||
|
||||
private SolveResult tryRecalculateTheoreticalSpeed() {
|
||||
protected SolveResult tryRecalculateTheoreticalSpeed() {
|
||||
SolveResult result = conflictingCycles.isEmpty() ? SolveResult.OK : SolveResult.CONTRADICTION;
|
||||
if (!rootSpeedDirty) return result;
|
||||
|
||||
|
@ -152,7 +153,11 @@ public class KineticNetwork {
|
|||
return totalStressCapacity.get();
|
||||
}
|
||||
|
||||
private float getRootSpeed() {
|
||||
public float getRootTheoreticalSpeed() {
|
||||
return rootTheoreticalSpeed;
|
||||
}
|
||||
|
||||
public float getRootSpeed() {
|
||||
return isStopped() ? 0 : rootTheoreticalSpeed;
|
||||
}
|
||||
|
||||
|
@ -161,45 +166,52 @@ public class KineticNetwork {
|
|||
onMemberStressImpactUpdated();
|
||||
}
|
||||
|
||||
public void untick() {
|
||||
protected void untick() {
|
||||
ticked = false;
|
||||
}
|
||||
|
||||
public void tick(List<KineticNetwork> newNetworks) {
|
||||
protected void tick(List<KineticNetwork> newNetworks) {
|
||||
if (ticked) return;
|
||||
|
||||
Set<KineticNetwork> stressConnected = stressConnectors.stream()
|
||||
.flatMap(KineticNode::getActiveStressOnlyConnections)
|
||||
.map(KineticNode::getNetwork)
|
||||
.collect(Collectors.toSet());
|
||||
stressConnected.add(this);
|
||||
|
||||
float stressImpact = 0;
|
||||
float stressCapacity = 0;
|
||||
Set<KineticNode> popQueue = new HashSet<>();
|
||||
Consumer<KineticNode> pop = n -> { n.popBlock(); newNetworks.add(n.getNetwork()); };
|
||||
|
||||
for (KineticNetwork cur : stressConnected) {
|
||||
cur.ticked = true;
|
||||
cur.updateMemberSpeeds(newNetworks);
|
||||
cur.updateMemberSpeeds(popQueue::add);
|
||||
stressImpact += cur.getTotalStressImpact();
|
||||
stressCapacity += cur.getTotalStressCapacity();
|
||||
}
|
||||
|
||||
boolean nowOverstressed = stressImpact > stressCapacity;
|
||||
if (!nowOverstressed) {
|
||||
// we should only pop speeding nodes if the network isn't actually overstressed now
|
||||
popQueue.forEach(pop);
|
||||
}
|
||||
|
||||
for (KineticNetwork cur : stressConnected) {
|
||||
if (cur.generators.isEmpty()) {
|
||||
cur.overstressed = false;
|
||||
} else if (nowOverstressed) {
|
||||
if (nowOverstressed) {
|
||||
if (!cur.overstressed) {
|
||||
// just became overstressed
|
||||
cur.overstressed = true;
|
||||
cur.onRootSpeedChanged();
|
||||
cur.members.forEach(KineticNode::stop);
|
||||
}
|
||||
} else {
|
||||
if (cur.overstressed) {
|
||||
// just became non-overstressed
|
||||
cur.overstressed = false;
|
||||
cur.onRootSpeedChanged();
|
||||
cur.bulldozeContradictingMembers(newNetworks);
|
||||
cur.updateMemberSpeeds(newNetworks);
|
||||
cur.updateMemberSpeeds(pop);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -208,10 +220,10 @@ public class KineticNetwork {
|
|||
}
|
||||
|
||||
/**
|
||||
* Update the speed of every member, starting from the main generator and popping off speeding nodes along the way
|
||||
* @param newNetworks a List that any new networks created during this call will be added to
|
||||
* Update the speed of every member, starting from the main generator and checking for speeding nodes along the way
|
||||
* @param onSpeeding a function to call whenever a speeding node is found and should be popped
|
||||
*/
|
||||
private void updateMemberSpeeds(List<KineticNetwork> newNetworks) {
|
||||
private void updateMemberSpeeds(Consumer<KineticNode> onSpeeding) {
|
||||
SolveResult recalculateSpeedResult = tryRecalculateSpeed();
|
||||
// generators should not be turning against each other or have conflicting cycles by now
|
||||
assert(recalculateSpeedResult.isOk());
|
||||
|
@ -225,17 +237,17 @@ public class KineticNetwork {
|
|||
if (rootSpeedChanged) {
|
||||
// root speed changed, update all nodes starting from the main generator
|
||||
rootSpeedChanged = false;
|
||||
bfs(mainGenerator, newNetworks, false);
|
||||
bfs(mainGenerator, onSpeeding, false);
|
||||
} else if (!potentialNewBranches.isEmpty()) {
|
||||
// new nodes added, update only the new network branches
|
||||
potentialNewBranches.stream()
|
||||
.filter(n -> !potentialNewBranches.contains(n.getSource()))
|
||||
.forEach(n -> bfs(n, newNetworks, true));
|
||||
.forEach(n -> bfs(n, onSpeeding, true));
|
||||
}
|
||||
potentialNewBranches.clear();
|
||||
}
|
||||
|
||||
private void bfs(KineticNode root, List<KineticNetwork> newNetworks, boolean followSource) {
|
||||
private void bfs(KineticNode root, Consumer<KineticNode> onSpeeding, boolean followSource) {
|
||||
// update node speeds in a breadth-first order, checking for speeding nodes along the way
|
||||
Set<KineticNode> visited = new HashSet<>();
|
||||
List<KineticNode> frontier = new LinkedList<>();
|
||||
|
@ -246,15 +258,14 @@ public class KineticNetwork {
|
|||
if (!members.contains(cur) || visited.contains(cur)) continue;
|
||||
visited.add(cur);
|
||||
|
||||
if (cur.tryUpdateSpeed(getRootSpeed()).isOk()) {
|
||||
if (cur.tryUpdateSpeed().isOk()) {
|
||||
cur.getActiveConnections()
|
||||
.map(Pair::getFirst)
|
||||
.filter(n -> !followSource || n.getSource() == cur)
|
||||
.forEach(frontier::add);
|
||||
} else {
|
||||
// stop searching on this branch once a speeding node is found
|
||||
cur.popBlock();
|
||||
newNetworks.add(cur.getNetwork());
|
||||
onSpeeding.accept(cur);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ package com.simibubi.create.content.contraptions.solver;
|
|||
|
||||
import com.simibubi.create.content.contraptions.base.KineticTileEntity;
|
||||
import com.simibubi.create.foundation.config.AllConfigs;
|
||||
import com.simibubi.create.foundation.utility.NBTHelper;
|
||||
import com.simibubi.create.foundation.utility.Pair;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
|
@ -11,9 +12,11 @@ import net.minecraft.util.Mth;
|
|||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
|
@ -22,6 +25,10 @@ public class KineticNode {
|
|||
private final KineticSolver solver;
|
||||
private @Nullable KineticTileEntity entity;
|
||||
|
||||
private @Nullable IKineticController controller;
|
||||
private @Nullable KineticControllerSerial controllerType;
|
||||
private @Nullable Set<BlockPos> controlling;
|
||||
|
||||
private @Nullable KineticNode source;
|
||||
private KineticNetwork network;
|
||||
private float speedRatio = 1;
|
||||
|
@ -35,18 +42,22 @@ public class KineticNode {
|
|||
private float stressImpact;
|
||||
private final boolean constantStress;
|
||||
|
||||
protected KineticNode regen() {
|
||||
return new KineticNode(solver, pos, entity, getController().get(), controllerType);
|
||||
}
|
||||
|
||||
public KineticNode(KineticSolver solver, KineticTileEntity entity) {
|
||||
this.solver = solver;
|
||||
this(solver, entity.getBlockPos(), entity, entity, null);
|
||||
this.controller = null;
|
||||
}
|
||||
|
||||
private KineticNode(KineticSolver solver, BlockPos pos, @Nullable KineticTileEntity entity,
|
||||
IKineticController controller, @Nullable KineticControllerSerial controllerType) {
|
||||
this(solver, pos, controller.getConnections(), controller.getGeneratedSpeed(), controller.getStressCapacity(),
|
||||
controller.getStressImpact(), controller.isStressConstant());
|
||||
this.entity = entity;
|
||||
|
||||
this.pos = entity.getBlockPos();
|
||||
this.connections = entity.getConnections();
|
||||
this.generatedSpeed = entity.getGeneratedSpeed();
|
||||
this.stressImpact = entity.getStressImpact();
|
||||
this.stressCapacity = entity.getStressCapacity();
|
||||
this.constantStress = entity.isStressConstant();
|
||||
|
||||
this.network = new KineticNetwork(this);
|
||||
this.controller = controller;
|
||||
this.controllerType = controllerType;
|
||||
}
|
||||
|
||||
private KineticNode(KineticSolver solver, BlockPos pos, KineticConnections connections, float generatedSpeed,
|
||||
|
@ -65,17 +76,29 @@ public class KineticNode {
|
|||
|
||||
public CompoundTag save(CompoundTag tag) {
|
||||
tag.put("Pos", NbtUtils.writeBlockPos(pos));
|
||||
if (controller != null && controllerType != null) {
|
||||
NBTHelper.writeEnum(tag, "ControllerType", controllerType);
|
||||
tag.put("Controller", controller.save(new CompoundTag()));
|
||||
return tag;
|
||||
}
|
||||
|
||||
tag.put("Connections", connections.save(new CompoundTag()));
|
||||
tag.putFloat("Generated", generatedSpeed);
|
||||
tag.putFloat("Capacity", stressCapacity);
|
||||
tag.putFloat("Impact", stressImpact);
|
||||
if (constantStress)
|
||||
if (constantStress) {
|
||||
tag.putBoolean("ConstantStress", true);
|
||||
}
|
||||
return tag;
|
||||
}
|
||||
|
||||
public static KineticNode load(KineticSolver solver, CompoundTag tag) {
|
||||
BlockPos pos = NbtUtils.readBlockPos(tag.getCompound("Pos"));
|
||||
if (tag.contains("Controller") && tag.contains("ControllerType")) {
|
||||
KineticControllerSerial type = NBTHelper.readEnum(tag, "ControllerType", KineticControllerSerial.class);
|
||||
return new KineticNode(solver, pos, null, type.load(tag.getCompound("Controller")), type);
|
||||
}
|
||||
|
||||
KineticConnections connections = KineticConnections.load(tag.getCompound("Connections"));
|
||||
float generatedSpeed = tag.getFloat("Generated");
|
||||
float stressCapacity = tag.getFloat("Capacity");
|
||||
|
@ -88,16 +111,38 @@ public class KineticNode {
|
|||
return entity != null;
|
||||
}
|
||||
|
||||
public void onLoaded(KineticTileEntity entity) {
|
||||
protected void onLoaded(KineticTileEntity entity) {
|
||||
this.entity = entity;
|
||||
network.onMemberLoaded(this);
|
||||
if (speedCur != 0) entity.setSpeed(speedCur);
|
||||
if (speedCur != 0)
|
||||
entity.setSpeed(speedCur);
|
||||
}
|
||||
|
||||
public void onUnloaded() {
|
||||
protected void onUnloaded() {
|
||||
this.entity = null;
|
||||
}
|
||||
|
||||
public Optional<IKineticController> getController() {
|
||||
if (controller != null) return Optional.of(controller);
|
||||
if (entity != null) return Optional.of(entity);
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
public boolean setController(KineticNode source, KineticControllerSerial controller) {
|
||||
if (this.controller != null) return false;
|
||||
this.controller = controller.init(this);
|
||||
this.controllerType = controller;
|
||||
if (source.controlling == null)
|
||||
source.controlling = new HashSet<>();
|
||||
source.controlling.add(pos);
|
||||
return true;
|
||||
}
|
||||
|
||||
protected void removeController() {
|
||||
controller = null;
|
||||
controllerType = null;
|
||||
}
|
||||
|
||||
public KineticConnections getConnections() {
|
||||
return connections;
|
||||
}
|
||||
|
@ -127,12 +172,15 @@ public class KineticNode {
|
|||
return getActiveConnections().collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public Stream<KineticNetwork> getActiveStressOnlyConnections() {
|
||||
public Stream<KineticNode> getActiveStressOnlyConnections() {
|
||||
return connections.getDirections().stream()
|
||||
.map(d -> solver.getNode(pos.offset(d))
|
||||
.filter(n -> connections.checkStressOnlyConnection(n.connections, d)))
|
||||
.flatMap(Optional::stream)
|
||||
.map(KineticNode::getNetwork);
|
||||
.flatMap(Optional::stream);
|
||||
}
|
||||
|
||||
public float getGeneratedSpeed() {
|
||||
return generatedSpeed;
|
||||
}
|
||||
|
||||
public float getGeneratedSpeedAtRoot() {
|
||||
|
@ -143,36 +191,42 @@ public class KineticNode {
|
|||
return generatedSpeed != 0;
|
||||
}
|
||||
|
||||
public boolean onUpdated() {
|
||||
if (entity == null) return false;
|
||||
protected enum UpdateResult {
|
||||
UNCHANGED, CHANGED, NEEDS_REGEN, NEEDS_POP
|
||||
}
|
||||
protected UpdateResult onUpdated() {
|
||||
return getController().map(ctl -> {
|
||||
if (!getConnections().equals(ctl.getConnections()) || constantStress != ctl.isStressConstant())
|
||||
return UpdateResult.NEEDS_REGEN;
|
||||
|
||||
boolean changed = false;
|
||||
UpdateResult result = UpdateResult.UNCHANGED;
|
||||
|
||||
float generatedSpeedNew = entity.getGeneratedSpeed();
|
||||
if (this.generatedSpeed != generatedSpeedNew) {
|
||||
this.generatedSpeed = generatedSpeedNew;
|
||||
changed = true;
|
||||
network.onMemberGeneratedSpeedUpdated(this);
|
||||
if (network.tryRecalculateSpeed().isContradiction()) {
|
||||
popBlock();
|
||||
float generatedSpeedNew = ctl.getGeneratedSpeed();
|
||||
if (this.generatedSpeed != generatedSpeedNew) {
|
||||
this.generatedSpeed = generatedSpeedNew;
|
||||
network.onMemberGeneratedSpeedUpdated(this);
|
||||
if (network.tryRecalculateSpeed().isContradiction()) {
|
||||
return UpdateResult.NEEDS_POP;
|
||||
}
|
||||
result = UpdateResult.CHANGED;
|
||||
}
|
||||
}
|
||||
|
||||
float stressImpactNew = entity.getStressImpact();
|
||||
if (this.stressImpact != stressImpactNew) {
|
||||
this.stressImpact = stressImpactNew;
|
||||
changed = true;
|
||||
network.onMemberStressImpactUpdated();
|
||||
}
|
||||
float stressImpactNew = ctl.getStressImpact();
|
||||
if (this.stressImpact != stressImpactNew) {
|
||||
this.stressImpact = stressImpactNew;
|
||||
network.onMemberStressImpactUpdated();
|
||||
result = UpdateResult.CHANGED;
|
||||
}
|
||||
|
||||
float stressCapacityNew = entity.getStressCapacity();
|
||||
if (this.stressCapacity != stressCapacityNew) {
|
||||
this.stressCapacity = stressCapacityNew;
|
||||
changed = true;
|
||||
network.onMemberStressCapacityUpdated();
|
||||
}
|
||||
float stressCapacityNew = ctl.getStressCapacity();
|
||||
if (this.stressCapacity != stressCapacityNew) {
|
||||
this.stressCapacity = stressCapacityNew;
|
||||
network.onMemberStressCapacityUpdated();
|
||||
result = UpdateResult.CHANGED;
|
||||
}
|
||||
|
||||
return changed;
|
||||
return result;
|
||||
}).orElse(UpdateResult.UNCHANGED);
|
||||
}
|
||||
|
||||
public boolean hasStressCapacity() {
|
||||
|
@ -183,16 +237,20 @@ public class KineticNode {
|
|||
return stressImpact != 0;
|
||||
}
|
||||
|
||||
public float getTheoreticalSpeed(float speedAtRoot) {
|
||||
return speedAtRoot * speedRatio;
|
||||
public float getSpeed() {
|
||||
return network.getRootSpeed() * speedRatio;
|
||||
}
|
||||
|
||||
public float getTheoreticalSpeed() {
|
||||
return network.getRootTheoreticalSpeed() * speedRatio;
|
||||
}
|
||||
|
||||
public float getStressCapacity() {
|
||||
return constantStress ? stressCapacity : stressCapacity * Math.abs(generatedSpeed);
|
||||
}
|
||||
|
||||
public float getTotalStressImpact(float speedAtRoot) {
|
||||
return constantStress ? stressImpact : stressImpact * Math.abs(getTheoreticalSpeed(speedAtRoot));
|
||||
public float getTotalStressImpact() {
|
||||
return constantStress ? stressImpact : stressImpact * Math.abs(getTheoreticalSpeed());
|
||||
}
|
||||
|
||||
private SolveResult setNetwork(KineticNetwork network) {
|
||||
|
@ -202,7 +260,7 @@ public class KineticNode {
|
|||
return network.tryRecalculateSpeed();
|
||||
}
|
||||
|
||||
public @Nullable KineticNode getSource() {
|
||||
protected @Nullable KineticNode getSource() {
|
||||
return source;
|
||||
}
|
||||
|
||||
|
@ -212,7 +270,7 @@ public class KineticNode {
|
|||
return setNetwork(from.network);
|
||||
}
|
||||
|
||||
public void onAdded() {
|
||||
protected void onAdded() {
|
||||
getActiveConnections()
|
||||
.findAny()
|
||||
.ifPresent(e -> {
|
||||
|
@ -264,12 +322,18 @@ public class KineticNode {
|
|||
}
|
||||
}
|
||||
|
||||
public void onRemoved() {
|
||||
protected void onRemoved() {
|
||||
network.removeMember(this);
|
||||
getActiveConnections()
|
||||
.map(Pair::getFirst)
|
||||
.filter(n -> n.source == this)
|
||||
.forEach(KineticNode::rerootHere);
|
||||
if (controlling != null) {
|
||||
controlling.stream()
|
||||
.map(solver::getNode)
|
||||
.flatMap(Optional::stream)
|
||||
.forEach(KineticNode::removeController);
|
||||
}
|
||||
}
|
||||
|
||||
private void rerootHere() {
|
||||
|
@ -282,11 +346,10 @@ public class KineticNode {
|
|||
|
||||
/**
|
||||
* Updates the speed of this node based on its network's root speed and its own speed ratio.
|
||||
* @param speedAtRoot Current speed at the root of this node's network
|
||||
* @return CONTRADICTION if the node's new speed exceeds the maximum value, and OK otherwise
|
||||
* @return CONTRADICTION if the node's new speed exceeds the maximum value, and OK otherwise
|
||||
*/
|
||||
protected SolveResult tryUpdateSpeed(float speedAtRoot) {
|
||||
speedNext = getTheoreticalSpeed(speedAtRoot);
|
||||
protected SolveResult tryUpdateSpeed() {
|
||||
speedNext = getSpeed();
|
||||
if (Math.abs(speedNext) > AllConfigs.SERVER.kinetics.maxRotationSpeed.get())
|
||||
return SolveResult.CONTRADICTION;
|
||||
return SolveResult.OK;
|
||||
|
@ -296,7 +359,7 @@ public class KineticNode {
|
|||
speedNext = 0;
|
||||
}
|
||||
|
||||
public void flushChangedSpeed() {
|
||||
protected void flushChangedSpeed() {
|
||||
if (speedCur != speedNext) {
|
||||
speedCur = speedNext;
|
||||
if (entity != null) {
|
||||
|
@ -305,7 +368,7 @@ public class KineticNode {
|
|||
}
|
||||
}
|
||||
|
||||
public void popBlock() {
|
||||
protected void popBlock() {
|
||||
if (entity != null) {
|
||||
solver.removeAndPopNow(entity);
|
||||
} else {
|
||||
|
|
|
@ -109,20 +109,14 @@ public class KineticSolver extends SavedData {
|
|||
setDirty();
|
||||
}
|
||||
|
||||
public void updateNode(KineticTileEntity entity) {
|
||||
KineticNode node = nodes.get(entity.getBlockPos());
|
||||
if (node == null) return;
|
||||
|
||||
if (!node.getConnections().equals(entity.getConnections())) {
|
||||
// connections changed, so things could've been disconnected
|
||||
removeNode(entity);
|
||||
addNode(entity);
|
||||
} else {
|
||||
// connections are the same, so just update in case other properties changed
|
||||
if (node.onUpdated()) {
|
||||
setDirty();
|
||||
}
|
||||
}
|
||||
private void regenNode(KineticNode node) {
|
||||
BlockPos pos = node.getPos();
|
||||
nodes.remove(pos);
|
||||
node.onRemoved();
|
||||
KineticNode newNode = node.regen();
|
||||
nodes.put(pos, newNode);
|
||||
newNode.onAdded();
|
||||
setDirty();
|
||||
}
|
||||
|
||||
public void unloadNode(KineticTileEntity entity) {
|
||||
|
@ -130,7 +124,7 @@ public class KineticSolver extends SavedData {
|
|||
if (node != null) node.onUnloaded();
|
||||
}
|
||||
|
||||
protected Optional<KineticNode> getNode(BlockPos pos) {
|
||||
public Optional<KineticNode> getNode(BlockPos pos) {
|
||||
return Optional.ofNullable(nodes.get(pos));
|
||||
}
|
||||
|
||||
|
@ -164,9 +158,25 @@ public class KineticSolver extends SavedData {
|
|||
level.destroyBlock(pos, true);
|
||||
}
|
||||
|
||||
public void tick() {
|
||||
Set<KineticNetwork> networks = nodes.values().stream().map(KineticNode::getNetwork).collect(Collectors.toSet());
|
||||
networks.forEach(KineticNetwork::untick);
|
||||
public void tick(Level level) {
|
||||
Set<KineticNode> popQueue = new HashSet<>();
|
||||
Set<KineticNode> regenQueue = new HashSet<>();
|
||||
for (KineticNode node : nodes.values()) {
|
||||
node.getController().ifPresent(c -> c.onUpdate(level, this, node));
|
||||
switch (node.onUpdated()) {
|
||||
case NEEDS_POP -> popQueue.add(node);
|
||||
case NEEDS_REGEN -> regenQueue.add(node);
|
||||
case CHANGED -> setDirty();
|
||||
}
|
||||
}
|
||||
popQueue.forEach(KineticNode::popBlock);
|
||||
regenQueue.forEach(this::regenNode);
|
||||
|
||||
Set<KineticNetwork> networks = new HashSet<>();
|
||||
for (KineticNode node : nodes.values()) {
|
||||
networks.add(node.getNetwork());
|
||||
node.getNetwork().untick();
|
||||
}
|
||||
|
||||
List<KineticNetwork> frontier = new LinkedList<>();
|
||||
|
||||
|
|
|
@ -112,7 +112,7 @@ public class CommonEvents {
|
|||
CouplingPhysics.tick(world);
|
||||
LinkedControllerServerHandler.tick(world);
|
||||
|
||||
KineticSolver.getSolver(world).tick();
|
||||
KineticSolver.getSolver(world).tick(world);
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
|
@ -169,14 +169,12 @@ public class CommonEvents {
|
|||
public static void onLoadWorld(WorldEvent.Load event) {
|
||||
LevelAccessor world = event.getWorld();
|
||||
Create.REDSTONE_LINK_NETWORK_HANDLER.onLoadWorld(world);
|
||||
Create.TORQUE_PROPAGATOR.onLoadWorld(world);
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onUnloadWorld(WorldEvent.Unload event) {
|
||||
LevelAccessor world = event.getWorld();
|
||||
Create.REDSTONE_LINK_NETWORK_HANDLER.onUnloadWorld(world);
|
||||
Create.TORQUE_PROPAGATOR.onUnloadWorld(world);
|
||||
WorldAttached.invalidateWorld(world);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue