Bogey power

- Trains now consume fuel from non-vault inventories to boost movement speed
This commit is contained in:
simibubi 2022-05-18 02:51:17 +02:00
parent f291dbc03a
commit 41facb7543
8 changed files with 137 additions and 51 deletions

View file

@ -1242,6 +1242,10 @@ public abstract class Contraption {
return storage.getItems();
}
public IItemHandlerModifiable getSharedFuelInventory() {
return storage.getFuelItems();
}
public IFluidHandler getSharedFluidTanks() {
return storage.getFluids();
}

View file

@ -26,16 +26,16 @@ public class MountedStorage {
private static final ItemStackHandler dummyHandler = new ItemStackHandler();
ItemStackHandler handler;
boolean noFuel;
boolean valid;
private BlockEntity te;
public static boolean canUseAsStorage(BlockEntity te) {
if (te == null)
return false;
if (te instanceof MechanicalCrafterTileEntity)
return false;
if (AllTileEntities.CREATIVE_CRATE.is(te))
return true;
if (te instanceof ShulkerBoxBlockEntity)
@ -55,6 +55,7 @@ public class MountedStorage {
public MountedStorage(BlockEntity te) {
this.te = te;
handler = dummyHandler;
noFuel = te instanceof ItemVaultTileEntity;
}
public void removeStorageFromWorld() {
@ -87,7 +88,7 @@ public class MountedStorage {
valid = true;
return;
}
// te uses ItemStackHandler
if (teHandler instanceof ItemStackHandler) {
handler = (ItemStackHandler) teHandler;
@ -124,7 +125,7 @@ public class MountedStorage {
te.load(tag);
return;
}
if (te instanceof ItemVaultTileEntity) {
((ItemVaultTileEntity) te).applyInventoryToBlock(handler);
return;
@ -147,14 +148,16 @@ public class MountedStorage {
public CompoundTag serialize() {
if (!valid)
return null;
CompoundTag tag = handler.serializeNBT();
if (noFuel)
NBTHelper.putMarker(tag, "NoFuel");
if (!(handler instanceof BottomlessItemHandler))
return tag;
if (handler instanceof BottomlessItemHandler) {
NBTHelper.putMarker(tag, "Bottomless");
tag.put("ProvidedStack", handler.getStackInSlot(0)
.serializeNBT());
}
NBTHelper.putMarker(tag, "Bottomless");
tag.put("ProvidedStack", handler.getStackInSlot(0)
.serializeNBT());
return tag;
}
@ -164,6 +167,7 @@ public class MountedStorage {
if (nbt == null)
return storage;
storage.valid = true;
storage.noFuel = nbt.contains("NoFuel");
if (nbt.contains("Bottomless")) {
ItemStack providedStack = ItemStack.of(nbt.getCompound("ProvidedStack"));
@ -178,5 +182,9 @@ public class MountedStorage {
public boolean isValid() {
return valid;
}
public boolean canUseForFuel() {
return !noFuel;
}
}

View file

@ -1,6 +1,8 @@
package com.simibubi.create.content.contraptions.components.structureMovement;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@ -29,6 +31,7 @@ import net.minecraftforge.items.IItemHandlerModifiable;
public class MountedStorageManager {
private ContraptionInvWrapper inventory;
private ContraptionInvWrapper fuelInventory;
private CombinedTankWrapper fluidInventory;
private Map<BlockPos, MountedStorage> storage;
private Map<BlockPos, MountedFluidStorage> fluidStorage;
@ -43,12 +46,16 @@ public class MountedStorageManager {
}
public void createHandlers() {
List<IItemHandlerModifiable> list = storage.values()
.stream()
Collection<MountedStorage> itemHandlers = storage.values();
inventory = wrap(itemHandlers.stream()
.map(MountedStorage::getItemHandler)
.collect(Collectors.toList());
inventory =
new ContraptionInvWrapper(Arrays.copyOf(list.toArray(), list.size(), IItemHandlerModifiable[].class));
.toList());
fuelInventory = wrap(itemHandlers.stream()
.filter(MountedStorage::canUseForFuel)
.map(MountedStorage::getItemHandler)
.toList());
List<IFluidHandler> fluidHandlers = fluidStorage.values()
.stream()
@ -58,6 +65,10 @@ public class MountedStorageManager {
Arrays.copyOf(fluidHandlers.toArray(), fluidHandlers.size(), IFluidHandler[].class));
}
private ContraptionInvWrapper wrap(List<IItemHandlerModifiable> list) {
return new ContraptionInvWrapper(Arrays.copyOf(list.toArray(), list.size(), IItemHandlerModifiable[].class));
}
public void addBlock(BlockPos localPos, BlockEntity te) {
if (te != null && MountedStorage.canUseAsStorage(te))
storage.put(localPos, new MountedStorage(te));
@ -88,17 +99,22 @@ public class MountedStorageManager {
mfs.assignTileEntity(tank);
});
IItemHandlerModifiable[] handlers = new IItemHandlerModifiable[storage.size()];
int index = 0;
for (MountedStorage mountedStorage : storage.values())
handlers[index++] = mountedStorage.getItemHandler();
List<IItemHandlerModifiable> handlers = new ArrayList<>();
List<IItemHandlerModifiable> fuelHandlers = new ArrayList<>();
for (MountedStorage mountedStorage : storage.values()) {
IItemHandlerModifiable itemHandler = mountedStorage.getItemHandler();
handlers.add(itemHandler);
if (mountedStorage.canUseForFuel())
fuelHandlers.add(itemHandler);
}
int index = 0;
IFluidHandler[] fluidHandlers = new IFluidHandler[fluidStorage.size()];
index = 0;
for (MountedFluidStorage mountedStorage : fluidStorage.values())
fluidHandlers[index++] = mountedStorage.getFluidHandler();
inventory = new ContraptionInvWrapper(handlers);
inventory = wrap(handlers);
fuelInventory = wrap(fuelHandlers);
fluidInventory = new CombinedTankWrapper(fluidHandlers);
}
@ -164,15 +180,20 @@ public class MountedStorageManager {
if (mountedFluidStorage != null)
mountedFluidStorage.updateFluid(containedFluid);
}
public void attachExternal(IItemHandlerModifiable externalStorage) {
inventory = new ContraptionInvWrapper(externalStorage, inventory);
fuelInventory = new ContraptionInvWrapper(externalStorage, fuelInventory);
}
public IItemHandlerModifiable getItems() {
return inventory;
}
public IItemHandlerModifiable getFuelItems() {
return fuelInventory;
}
public IFluidHandler getFluids() {
return fluidInventory;
}

View file

@ -496,6 +496,9 @@ public class CarriageContraptionEntity extends OrientedContraptionEntity {
targetSteer *= -1;
}
if (targetSpeed != 0)
carriage.train.burnFuel();
boolean slow = inverted ^ targetSpeed < 0;
boolean spaceDown = heldControls.contains(4);
GlobalStation currentStation = carriage.train.getCurrentStation();
@ -551,7 +554,7 @@ public class CarriageContraptionEntity extends OrientedContraptionEntity {
carriage.train.manualSteer =
targetSteer < 0 ? SteerDirection.RIGHT : targetSteer > 0 ? SteerDirection.LEFT : SteerDirection.NONE;
double topSpeed = AllConfigs.SERVER.trains.getTopSpeedMPT();
double topSpeed = carriage.train.maxSpeed();
carriage.train.targetSpeed = topSpeed * targetSpeed;
if (slow)
carriage.train.targetSpeed /= 8;

View file

@ -95,8 +95,7 @@ public class Navigation {
destination.reserveFor(train);
double acceleration = AllConfigs.SERVER.trains.getAccelerationMPTT();
double turnTopSpeed = AllConfigs.SERVER.trains.getTurningTopSpeedMPT();
double acceleration = train.acceleration();
double brakingDistance = (train.speed * train.speed) / (2 * acceleration);
double speedMod = destinationBehindTrain ? -1 : 1;
double preDepartureLookAhead = train.getCurrentStation() != null ? 4.5 : 0;
@ -240,7 +239,11 @@ public class Navigation {
return;
}
double topSpeed = AllConfigs.SERVER.trains.getTopSpeedMPT();
train.burnFuel();
double topSpeed = train.maxSpeed();
double turnTopSpeed = train.maxTurnSpeed();
if (targetDistance < 10) {
double target = topSpeed * ((targetDistance) / 10);
if (target < Math.abs(train.speed)) {
@ -505,7 +508,7 @@ public class Navigation {
return null;
MutableObject<GlobalStation> result = new MutableObject<>(null);
double acceleration = AllConfigs.SERVER.trains.getAccelerationMPTT();
double acceleration = train.acceleration();
double minDistance = .75f * (train.speed * train.speed) / (2 * acceleration);
double maxDistance = Math.max(32, 1.5f * (train.speed * train.speed) / (2 * acceleration));

View file

@ -56,9 +56,13 @@ import net.minecraft.resources.ResourceKey;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.util.Mth;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.Explosion.BlockInteraction;
import net.minecraft.world.level.Level;
import net.minecraft.world.phys.Vec3;
import net.minecraftforge.common.ForgeHooks;
import net.minecraftforge.items.IItemHandlerModifiable;
import net.minecraftforge.items.ItemHandlerHelper;
import net.minecraftforge.network.PacketDistributor;
public class Train {
@ -76,7 +80,7 @@ public class Train {
public TrainStatus status;
public boolean invalid;
public SteerDirection manualSteer;
public boolean manualTick;
@ -96,6 +100,8 @@ public class Train {
public int migrationCooldown;
public boolean derailed;
public int fuelTicks;
int tickOffset;
double[] stress;
@ -387,7 +393,7 @@ public class Train {
private void tickPassiveSlowdown() {
if (!manualTick && navigation.destination == null && speed != 0) {
double acceleration = AllConfigs.SERVER.trains.getAccelerationMPTT();
double acceleration = acceleration();
if (speed > 0) {
speed = Math.max(speed - acceleration, 0);
} else
@ -541,7 +547,7 @@ public class Train {
if (entity == null)
return false;
if (entity.getContraption() instanceof CarriageContraption cc)
if (entity.getContraption()instanceof CarriageContraption cc)
cc.returnStorageForDisassembly(carriage.storage);
entity.setPos(Vec3
.atLowerCornerOf(pos.relative(assemblyDirection, backwards ? offset + carriage.bogeySpacing : offset)));
@ -747,7 +753,7 @@ public class Train {
return;
if (manualTick)
leaveStation();
double acceleration = AllConfigs.SERVER.trains.getAccelerationMPTT();
double acceleration = acceleration();
if (speed < targetSpeed)
speed = Math.min(speed + acceleration * accelerationMod, targetSpeed);
else if (speed > targetSpeed)
@ -854,6 +860,50 @@ public class Train {
return Penalties.ANY_TRAIN;
}
public void burnFuel() {
if (fuelTicks > 0) {
fuelTicks--;
return;
}
boolean iterateFromBack = speed < 0;
int carriageCount = carriages.size();
for (int index = 0; index < carriageCount; index++) {
int i = iterateFromBack ? carriageCount - 1 - index : index;
Carriage carriage = carriages.get(i);
IItemHandlerModifiable fuelItems = carriage.storage.getFuelItems();
for (int slot = 0; slot < fuelItems.getSlots(); slot++) {
ItemStack stack = fuelItems.extractItem(slot, 1, true);
int burnTime = ForgeHooks.getBurnTime(stack, null);
if (burnTime <= 0)
continue;
stack = fuelItems.extractItem(slot, 1, false);
fuelTicks += burnTime * stack.getCount();
ItemStack containerItem = stack.getContainerItem();
if (!containerItem.isEmpty())
ItemHandlerHelper.insertItemStacked(fuelItems, containerItem, false);
}
}
}
public float maxSpeed() {
return (fuelTicks > 0 ? AllConfigs.SERVER.trains.poweredTrainTopSpeed.getF()
: AllConfigs.SERVER.trains.trainTopSpeed.getF()) / 20;
}
public float maxTurnSpeed() {
return (fuelTicks > 0 ? AllConfigs.SERVER.trains.poweredTrainTurningTopSpeed.getF()
: AllConfigs.SERVER.trains.trainTurningTopSpeed.getF()) / 20;
}
public float acceleration() {
return (fuelTicks > 0 ? AllConfigs.SERVER.trains.poweredTrainAcceleration.getF()
: AllConfigs.SERVER.trains.trainAcceleration.getF()) / 400;
}
public CompoundTag write(DimensionPalette dimensions) {
CompoundTag tag = new CompoundTag();
tag.putUUID("Id", id);
@ -864,6 +914,7 @@ public class Train {
tag.putIntArray("CarriageSpacing", carriageSpacing);
tag.putBoolean("DoubleEnded", doubleEnded);
tag.putDouble("Speed", speed);
tag.putInt("Fuel", fuelTicks);
tag.putDouble("TargetSpeed", targetSpeed);
tag.putString("IconType", icon.id.toString());
tag.putString("Name", Component.Serializer.toJson(name));
@ -917,6 +968,7 @@ public class Train {
train.heldForAssembly = tag.getBoolean("StillAssembling");
train.derailed = tag.getBoolean("Derailed");
train.updateSignalBlocks = tag.getBoolean("UpdateSignals");
train.fuelTicks = tag.getInt("Fuel");
NBTHelper.iterateCompoundList(tag.getList("SignalBlocks", Tag.TAG_COMPOUND), c -> train.occupiedSignalBlocks
.put(c.getUUID("Id"), c.contains("Boundary") ? c.getUUID("Boundary") : null));

View file

@ -15,8 +15,6 @@ import com.simibubi.create.content.logistics.trains.management.schedule.conditio
import com.simibubi.create.content.logistics.trains.management.schedule.destination.ChangeTitleInstruction;
import com.simibubi.create.content.logistics.trains.management.schedule.destination.DestinationInstruction;
import com.simibubi.create.content.logistics.trains.management.schedule.destination.ScheduleInstruction;
import com.simibubi.create.foundation.config.AllConfigs;
import com.simibubi.create.foundation.config.CTrains;
import com.simibubi.create.foundation.utility.NBTHelper;
import net.minecraft.nbt.CompoundTag;
@ -239,8 +237,7 @@ public class ScheduleRuntime {
} else {
GlobalStation destination = train.navigation.destination;
if (destination != null) {
CTrains conf = AllConfigs.SERVER.trains;
double speed = (conf.getTopSpeedMPT() + conf.getTurningTopSpeedMPT()) / 2;
double speed = (train.maxSpeed() + train.maxTurnSpeed()) / 2;
int timeRemaining = (int) (train.navigation.distanceToDestination / speed) * 2;
if (predictionTicks.size() > current && train.navigation.distanceStartedAt != 0) {

View file

@ -3,36 +3,34 @@ package com.simibubi.create.foundation.config;
public class CTrains extends ConfigBase {
public final ConfigBool trainsCauseDamage = b(true, "trainsCauseDamage", Comments.trainsCauseDamage);
public final ConfigFloat trainTopSpeed = f(36, 0, "trainTopSpeed", Comments.mps, Comments.trainTopSpeed);
public final ConfigFloat trainTurningTopSpeed =
f(18, 0, "trainTurningTopSpeed", Comments.mps, Comments.trainTurningTopSpeed);
public final ConfigFloat trainAcceleration = f(4, 0, "trainAcceleration", Comments.acc, Comments.trainAcceleration);
public final ConfigInt maxAssemblyLength = i(128, 5, "maxAssemblyLength", Comments.maxAssemblyLength);
public final ConfigInt maxBogeyCount = i(20, 1, "maxBogeyCount", Comments.maxBogeyCount);
public final ConfigGroup trainStats = group(1, "trainStats", "Standard Trains");
public final ConfigFloat trainTopSpeed = f(28, 0, "trainTopSpeed", Comments.mps, Comments.trainTopSpeed);
public final ConfigFloat trainTurningTopSpeed = f(14, 0, "trainTurningTopSpeed", Comments.mps, Comments.trainTurningTopSpeed);
public final ConfigFloat trainAcceleration = f(3, 0, "trainAcceleration", Comments.acc, Comments.trainAcceleration);
public final ConfigGroup poweredTrainStats = group(1, "poweredTrainStats", "Powered Trains");
public final ConfigFloat poweredTrainTopSpeed = f(40, 0, "poweredTrainTopSpeed", Comments.mps, Comments.poweredTrainTopSpeed);
public final ConfigFloat poweredTrainTurningTopSpeed = f(20, 0, "poweredTrainTurningTopSpeed", Comments.mps, Comments.poweredTrainTurningTopSpeed);
public final ConfigFloat poweredTrainAcceleration = f(3, 0, "poweredTrainAcceleration", Comments.acc, Comments.poweredTrainAcceleration);
@Override
public String getName() {
return "trains";
}
public double getTopSpeedMPT() {
return trainTopSpeed.getF() / 20;
}
public double getTurningTopSpeedMPT() {
return trainTurningTopSpeed.getF() / 20;
}
public double getAccelerationMPTT() {
return trainAcceleration.getF() / 400;
}
private static class Comments {
static String mps = "[in Blocks/Second]";
static String acc = "[in Blocks/Second²]";
static String trainTopSpeed = "The top speed of any assembled Train.";
static String trainTurningTopSpeed = "The top speed of Trains during a turn.";
static String trainAcceleration = "The acceleration of any assembled Train.";
static String poweredTrainTopSpeed = "The top speed of powered Trains.";
static String poweredTrainTurningTopSpeed = "The top speed of powered Trains during a turn.";
static String poweredTrainAcceleration = "The acceleration of powered Trains.";
static String trainsCauseDamage = "Whether moving Trains can hurt colliding mobs and players.";
static String maxAssemblyLength = "Maximum length of a Train Stations' assembly track.";
static String maxBogeyCount = "Maximum amount of bogeys assembled as a single Train.";