This commit is contained in:
2025-09-27 11:33:50 +02:00
parent eee1a38150
commit e9d34a2d3b
3 changed files with 98 additions and 141 deletions

View File

@@ -4,6 +4,7 @@ import com.gregtechceu.gtceu.api.GTValues;
import com.gregtechceu.gtceu.api.blockentity.MetaMachineBlockEntity;
import com.gregtechceu.gtceu.api.capability.ITurbineMachine;
import com.gregtechceu.gtceu.api.capability.compat.FeCompat;
import com.gregtechceu.gtceu.api.item.tool.GTToolType;
import com.gregtechceu.gtceu.api.machine.IMachineBlockEntity;
import com.gregtechceu.gtceu.api.machine.MachineDefinition;
import com.gregtechceu.gtceu.api.machine.MetaMachine;
@@ -33,27 +34,31 @@ import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.common.util.LazyOptional;
import com.imbgt.kineticbridge.machine.KineticOutputHatchPartMachine;
import com.simibubi.create.content.kinetics.KineticNetwork;
import com.simibubi.create.content.kinetics.base.GeneratingKineticBlockEntity;
import com.simibubi.create.content.kinetics.base.IRotate;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
import java.util.Set;
import com.imbgt.kineticbridge.KineticBridge;
/**
* Block entity that bridges a GTCEu meta machine with Create's kinetic network.
*/
public class KineticOutputHatchBlockEntity extends GeneratingKineticBlockEntity
implements IMachineBlockEntity, IManaged {
implements IMachineBlockEntity, IManaged {
private static final ManagedFieldHolder MANAGED_FIELD_HOLDER = new ManagedFieldHolder(
KineticOutputHatchBlockEntity.class);
private static final float CREATE_MAX_RPM = KineticOutputHatchPartMachine.TARGET_RPM;
private static final float TURBINE_REFERENCE_RPM = 7000.0f;
private static final float MIN_GENERATED_RPM = 1.0f;
// FE generated per stress unit per RPM tick, aligned with Create: New Age defaults
private static final double SU_TO_FE_ENERGY = 15.0d / 512.0d;
// FE generated per stress unit per RPM tick, aligned with Create: New Age
// defaults
private static final double SU_TO_FE = 15.0d / 512.0d;
private static final float EPSILON = 1.0e-4f;
private static final float TARGET_RPM = KineticOutputHatchPartMachine.TARGET_RPM;
private final MultiManagedStorage managedStorage = new MultiManagedStorage();
private final FieldManagedStorage syncStorage = new FieldManagedStorage(this);
@@ -61,9 +66,8 @@ public class KineticOutputHatchBlockEntity extends GeneratingKineticBlockEntity
private MachineRenderState renderState;
private final long offset = GTValues.RNG.nextInt(20);
private float advertisedCapacity = 0.0f;
private float generatedSpeed = 0.0f;
private long lastTickPower = 0L;
private float lastGeneratedSpeed = 0.0f;
private boolean metaUnloaded = false;
public KineticOutputHatchBlockEntity(BlockEntityType<?> type, BlockPos pos, BlockState blockState) {
@@ -77,20 +81,19 @@ public class KineticOutputHatchBlockEntity extends GeneratingKineticBlockEntity
@Override
public void tick() {
super.tick();
if (level == null) {
if (level == null || level.isClientSide())
return;
MetaMachine mm = getMetaMachine();
if (!(mm instanceof KineticOutputHatchPartMachine hatch)) {
this.generatedSpeed = 0;
finalizeKinetics();
return;
}
if (level.isClientSide()) {
metaMachine.clientTick();
return;
}
var machine = getMetaMachine();
if (!(machine instanceof KineticOutputHatchPartMachine hatch)) {
updateKinetics(0.0f, 0.0f, 0L);
metaMachine.serverTick();
return;
var ec = getEc();
if (ec != null) {
ec.setEnergyStored(0);
}
ITurbineMachine turbine = null;
@@ -100,104 +103,74 @@ public class KineticOutputHatchBlockEntity extends GeneratingKineticBlockEntity
break;
}
}
int rotorSpeed = turbine != null ? Math.max(0, turbine.getRotorSpeed()) : hatch.getRotorSpeed();
int maxRotorSpeed = turbine != null ? Math.max(1, turbine.getMaxRotorHolderSpeed()) : hatch.getMaxRotorSpeed();
float rpmScale = 0.0f;
if (rotorSpeed > 0) {
rpmScale = Math.min(1.0f, Math.max(0.0f, rotorSpeed / TURBINE_REFERENCE_RPM));
}
hatch.updateRotorTelemetry(rotorSpeed, maxRotorSpeed);
NotifiableEnergyContainer container = hatch.getEnergyContainer();
long voltage = container.getOutputVoltage();
long amperage = container.getOutputAmperage();
long theoreticalPower = Math.max(0L, voltage * amperage);
if (theoreticalPower <= 0 || rpmScale <= 0.0f) {
updateKinetics(0.0f, 0.0f, 0L);
metaMachine.serverTick();
if (turbine == null) {
this.generatedSpeed = 0;
finalizeKinetics();
return;
}
int rotorSpeed = turbine.getRotorSpeed();
int maxRotorSpeed = turbine.getMaxRotorHolderSpeed();
float previousCapacity = advertisedCapacity;
float previousSpeed = generatedSpeed;
float nextSpeed = ((float) rotorSpeed / (float) maxRotorSpeed) * TARGET_RPM;
this.generatedSpeed = (float) Math.ceil(nextSpeed);
float nextSpeed = CREATE_MAX_RPM * rpmScale;
if (nextSpeed > 0.0f && nextSpeed < MIN_GENERATED_RPM) {
nextSpeed = MIN_GENERATED_RPM;
finalizeKinetics();
}
private NotifiableEnergyContainer getEc() {
MetaMachine mm = getMetaMachine();
if (!(mm instanceof KineticOutputHatchPartMachine hatch)) {
return null;
}
return hatch.getEnergyContainer();
}
private void finalizeKinetics() {
if (Math.abs(this.lastGeneratedSpeed - this.generatedSpeed) >= 1) {
updateGeneratedRotation();
this.lastGeneratedSpeed = this.generatedSpeed;
}
}
@Override
public void updateGeneratedRotation() {
if (level == null || level.isClientSide)
return;
float speed = getGeneratedSpeed();
float prev = this.lastGeneratedSpeed; // add a private field or reuse your cached prev if you keep one
if (prev != speed) {
if (!hasSource()) {
var before = IRotate.SpeedLevel.of(prev);
var after = IRotate.SpeedLevel.of(speed);
if (before != after)
effects.queueRotationIndicators();
}
// this attaches/creates the network and propagates RPM
applyNewSpeed(prev, speed);
}
double speedFraction = Math.min(1.0d, nextSpeed / CREATE_MAX_RPM);
int euToFeRatio = Math.max(1, FeCompat.ratio(false));
double theoreticalEuAtSpeed = theoreticalPower * speedFraction;
double theoreticalFeAtSpeed = theoreticalEuAtSpeed * euToFeRatio;
double absSpeed = Math.max(MIN_GENERATED_RPM, Math.abs(nextSpeed));
double theoreticalStressCapacity = absSpeed > 0.0d ?
theoreticalFeAtSpeed / (absSpeed * SU_TO_FE_ENERGY) : 0.0d;
double theoreticalStress = theoreticalStressCapacity * absSpeed;
double networkStress = Math.max(0.0d, this.stress);
double networkCapacity = Math.max(0.0d, this.capacity);
double requestedStress = theoreticalStress;
if (networkCapacity > 0.0d) {
double shareRatio = theoreticalStress / networkCapacity;
requestedStress = Math.min(theoreticalStress, networkStress * shareRatio);
} else if (networkStress <= 0.0d) {
requestedStress = 0.0d;
}
double requestedFe = requestedStress * SU_TO_FE_ENERGY;
double requestedEu = requestedFe / euToFeRatio;
double targetEu = Math.min(theoreticalEuAtSpeed, requestedEu);
long stored = container.getEnergyStored();
long maxAvailable = Math.min(stored, theoreticalPower);
if (maxAvailable > 0) {
targetEu = Math.min(targetEu, maxAvailable);
}
long energyBudget = 0L;
if (targetEu > 0.0d) {
energyBudget = Math.max(1L, (long) Math.ceil(targetEu));
if (maxAvailable > 0) {
energyBudget = Math.min(energyBudget, maxAvailable);
if (speed != 0 && hasNetwork()) {
KineticNetwork net = getOrCreateNetwork();
if (net != null) {
// your advertisedCapacity is TOTAL SU at current speed
net.updateCapacityFor(this, calculateAddedStressCapacity());
// keep Creates bookkeeping in sync
notifyStressCapacityChange(calculateAddedStressCapacity());
// generators apply 0 stress
net.updateStressFor(this, 0f);
net.updateStress();
}
}
long drained = energyBudget > 0 ? container.removeEnergy(energyBudget) : 0L;
onSpeedChanged(prev);
sendData();
double advertised = theoreticalStressCapacity;
if (energyBudget > drained && requestedStress > 0.0d) {
double drainedFe = FeCompat.toFeLong(drained, euToFeRatio);
double actualCapacity = drainedFe / (absSpeed * absSpeed * SU_TO_FE_ENERGY);
advertised = Math.min(theoreticalStressCapacity, actualCapacity);
}
float nextCapacity = (float) Math.max(0.0d, advertised);
updateKinetics(nextSpeed, nextCapacity, drained);
boolean speedChanged = Math.abs(previousSpeed - generatedSpeed) > EPSILON;
boolean capacityChanged = Math.abs(previousCapacity - advertisedCapacity) > EPSILON;
if (speedChanged) {
updateGeneratedRotation();
} else if (capacityChanged && hasNetwork()) {
notifyStressCapacityChange(advertisedCapacity);
getOrCreateNetwork().updateStressFor(this, calculateStressApplied());
getOrCreateNetwork().updateStress();
sendData();
}
metaMachine.serverTick();
}
private void updateKinetics(float speed, float capacityPerSpeed, long drainedPower) {
this.generatedSpeed = speed;
this.advertisedCapacity = capacityPerSpeed;
this.lastTickPower = drainedPower;
// remember last speed locally
this.lastGeneratedSpeed = speed;
}
@Override
@@ -207,7 +180,16 @@ public class KineticOutputHatchBlockEntity extends GeneratingKineticBlockEntity
@Override
public float calculateAddedStressCapacity() {
return advertisedCapacity;
var ec = getEc();
if (ec == null) {
return 0;
}
long euMax = Math.max(0L, ec.getOutputVoltage() * ec.getOutputAmperage());
double feMax = FeCompat.toFeLong(euMax, FeCompat.ratio(false));
double suMAx = feMax * SU_TO_FE;
return (float) suMAx;
}
@Override
@@ -222,16 +204,12 @@ public class KineticOutputHatchBlockEntity extends GeneratingKineticBlockEntity
}
super.read(tag, clientPacket);
this.generatedSpeed = tag.getFloat("GeneratedSpeed");
this.advertisedCapacity = tag.getFloat("StressCapacity");
this.lastTickPower = tag.getLong("LastPower");
}
@Override
protected void write(CompoundTag tag, boolean clientPacket) {
super.write(tag, clientPacket);
tag.putFloat("GeneratedSpeed", generatedSpeed);
tag.putFloat("StressCapacity", advertisedCapacity);
tag.putLong("LastPower", lastTickPower);
}
@Override
@@ -245,12 +223,10 @@ public class KineticOutputHatchBlockEntity extends GeneratingKineticBlockEntity
Component.literal(FormattingUtil.formatNumbers(maxPower))
.withStyle(ChatFormatting.AQUA)));
tooltip.add(Component.translatable("tooltip.kineticbridge.max_stress",
Component.literal(FormattingUtil.formatNumbers(Math.max(0.0f, advertisedCapacity)))
Component.literal(FormattingUtil.formatNumbers(Math.max(0.0f, calculateAddedStressCapacity())))
.withStyle(ChatFormatting.AQUA),
Component.literal(String.format("%.0f", (double) CREATE_MAX_RPM))
Component.literal(String.format("%.0f", (double) speed))
.withStyle(ChatFormatting.AQUA)));
tooltip.add(Component.translatable("tooltip.kineticbridge.last_tick_power",
Component.literal(FormattingUtil.formatNumbers(lastTickPower)).withStyle(ChatFormatting.AQUA)));
return true;
}
return added;
@@ -294,6 +270,8 @@ public class KineticOutputHatchBlockEntity extends GeneratingKineticBlockEntity
@Override
public void onLoad() {
super.onLoad();
if (!level.isClientSide)
updateGeneratedRotation();
metaMachine.onLoad();
}
@@ -318,15 +296,15 @@ public class KineticOutputHatchBlockEntity extends GeneratingKineticBlockEntity
@Override
public boolean shouldRenderGrid(Player player, BlockPos pos, BlockState state, ItemStack held,
Set<com.gregtechceu.gtceu.api.item.tool.GTToolType> toolTypes) {
Set<GTToolType> toolTypes) {
return metaMachine.shouldRenderGrid(player, pos, state, held, toolTypes);
}
@Override
public @Nullable com.lowdragmc.lowdraglib.gui.texture.ResourceTexture sideTips(Player player, BlockPos pos,
BlockState state,
Set<com.gregtechceu.gtceu.api.item.tool.GTToolType> toolTypes,
Direction side) {
BlockState state,
Set<GTToolType> toolTypes,
Direction side) {
return metaMachine.sideTips(player, pos, state, toolTypes, side);
}

View File

@@ -37,7 +37,6 @@ public final class KineticBridgeDatagen {
KineticBridge.REGISTRATE.addDataGenerator(ProviderType.LANG, provider -> {
provider.add("tooltip.kineticbridge.max_power", "Max Output: %s EU/t");
provider.add("tooltip.kineticbridge.max_stress", "Active Capacity: %s SU @ %s RPM");
provider.add("tooltip.kineticbridge.last_tick_power", "Last Tick Draw: %s EU");
provider.add("kineticbridge.tooltip.rpm", "Outputs Create rotation at %s RPM");
provider.add("kineticbridge.tooltip.capacity", "Provides up to %s SU (~%s EU/t)");
});

View File

@@ -25,27 +25,7 @@ public class KineticOutputHatchPartMachine extends EnergyHatchPartMachine {
return energyContainer.getOutputVoltage() * energyContainer.getOutputAmperage();
}
public float getTargetRpm() {
return TARGET_RPM;
}
public NotifiableEnergyContainer getEnergyContainer() {
return energyContainer;
}
private int reportedRotorSpeed;
private int maxRotorSpeed = 1;
public void updateRotorTelemetry(int rotorSpeed, int maxSpeed) {
this.reportedRotorSpeed = Math.max(0, rotorSpeed);
this.maxRotorSpeed = Math.max(1, maxSpeed);
}
public int getRotorSpeed() {
return reportedRotorSpeed;
}
public int getMaxRotorSpeed() {
return Math.max(1, maxRotorSpeed);
}
}