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(); return storage.getItems();
} }
public IItemHandlerModifiable getSharedFuelInventory() {
return storage.getFuelItems();
}
public IFluidHandler getSharedFluidTanks() { public IFluidHandler getSharedFluidTanks() {
return storage.getFluids(); return storage.getFluids();
} }

View file

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

View file

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

View file

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

View file

@ -95,8 +95,7 @@ public class Navigation {
destination.reserveFor(train); destination.reserveFor(train);
double acceleration = AllConfigs.SERVER.trains.getAccelerationMPTT(); double acceleration = train.acceleration();
double turnTopSpeed = AllConfigs.SERVER.trains.getTurningTopSpeedMPT();
double brakingDistance = (train.speed * train.speed) / (2 * acceleration); double brakingDistance = (train.speed * train.speed) / (2 * acceleration);
double speedMod = destinationBehindTrain ? -1 : 1; double speedMod = destinationBehindTrain ? -1 : 1;
double preDepartureLookAhead = train.getCurrentStation() != null ? 4.5 : 0; double preDepartureLookAhead = train.getCurrentStation() != null ? 4.5 : 0;
@ -240,7 +239,11 @@ public class Navigation {
return; return;
} }
double topSpeed = AllConfigs.SERVER.trains.getTopSpeedMPT(); train.burnFuel();
double topSpeed = train.maxSpeed();
double turnTopSpeed = train.maxTurnSpeed();
if (targetDistance < 10) { if (targetDistance < 10) {
double target = topSpeed * ((targetDistance) / 10); double target = topSpeed * ((targetDistance) / 10);
if (target < Math.abs(train.speed)) { if (target < Math.abs(train.speed)) {
@ -505,7 +508,7 @@ public class Navigation {
return null; return null;
MutableObject<GlobalStation> result = new MutableObject<>(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 minDistance = .75f * (train.speed * train.speed) / (2 * acceleration);
double maxDistance = Math.max(32, 1.5f * (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.resources.ResourceLocation;
import net.minecraft.util.Mth; import net.minecraft.util.Mth;
import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.Explosion.BlockInteraction; import net.minecraft.world.level.Explosion.BlockInteraction;
import net.minecraft.world.level.Level; import net.minecraft.world.level.Level;
import net.minecraft.world.phys.Vec3; 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; import net.minecraftforge.network.PacketDistributor;
public class Train { public class Train {
@ -76,7 +80,7 @@ public class Train {
public TrainStatus status; public TrainStatus status;
public boolean invalid; public boolean invalid;
public SteerDirection manualSteer; public SteerDirection manualSteer;
public boolean manualTick; public boolean manualTick;
@ -96,6 +100,8 @@ public class Train {
public int migrationCooldown; public int migrationCooldown;
public boolean derailed; public boolean derailed;
public int fuelTicks;
int tickOffset; int tickOffset;
double[] stress; double[] stress;
@ -387,7 +393,7 @@ public class Train {
private void tickPassiveSlowdown() { private void tickPassiveSlowdown() {
if (!manualTick && navigation.destination == null && speed != 0) { if (!manualTick && navigation.destination == null && speed != 0) {
double acceleration = AllConfigs.SERVER.trains.getAccelerationMPTT(); double acceleration = acceleration();
if (speed > 0) { if (speed > 0) {
speed = Math.max(speed - acceleration, 0); speed = Math.max(speed - acceleration, 0);
} else } else
@ -541,7 +547,7 @@ public class Train {
if (entity == null) if (entity == null)
return false; return false;
if (entity.getContraption() instanceof CarriageContraption cc) if (entity.getContraption()instanceof CarriageContraption cc)
cc.returnStorageForDisassembly(carriage.storage); cc.returnStorageForDisassembly(carriage.storage);
entity.setPos(Vec3 entity.setPos(Vec3
.atLowerCornerOf(pos.relative(assemblyDirection, backwards ? offset + carriage.bogeySpacing : offset))); .atLowerCornerOf(pos.relative(assemblyDirection, backwards ? offset + carriage.bogeySpacing : offset)));
@ -747,7 +753,7 @@ public class Train {
return; return;
if (manualTick) if (manualTick)
leaveStation(); leaveStation();
double acceleration = AllConfigs.SERVER.trains.getAccelerationMPTT(); double acceleration = acceleration();
if (speed < targetSpeed) if (speed < targetSpeed)
speed = Math.min(speed + acceleration * accelerationMod, targetSpeed); speed = Math.min(speed + acceleration * accelerationMod, targetSpeed);
else if (speed > targetSpeed) else if (speed > targetSpeed)
@ -854,6 +860,50 @@ public class Train {
return Penalties.ANY_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) { public CompoundTag write(DimensionPalette dimensions) {
CompoundTag tag = new CompoundTag(); CompoundTag tag = new CompoundTag();
tag.putUUID("Id", id); tag.putUUID("Id", id);
@ -864,6 +914,7 @@ public class Train {
tag.putIntArray("CarriageSpacing", carriageSpacing); tag.putIntArray("CarriageSpacing", carriageSpacing);
tag.putBoolean("DoubleEnded", doubleEnded); tag.putBoolean("DoubleEnded", doubleEnded);
tag.putDouble("Speed", speed); tag.putDouble("Speed", speed);
tag.putInt("Fuel", fuelTicks);
tag.putDouble("TargetSpeed", targetSpeed); tag.putDouble("TargetSpeed", targetSpeed);
tag.putString("IconType", icon.id.toString()); tag.putString("IconType", icon.id.toString());
tag.putString("Name", Component.Serializer.toJson(name)); tag.putString("Name", Component.Serializer.toJson(name));
@ -917,6 +968,7 @@ public class Train {
train.heldForAssembly = tag.getBoolean("StillAssembling"); train.heldForAssembly = tag.getBoolean("StillAssembling");
train.derailed = tag.getBoolean("Derailed"); train.derailed = tag.getBoolean("Derailed");
train.updateSignalBlocks = tag.getBoolean("UpdateSignals"); train.updateSignalBlocks = tag.getBoolean("UpdateSignals");
train.fuelTicks = tag.getInt("Fuel");
NBTHelper.iterateCompoundList(tag.getList("SignalBlocks", Tag.TAG_COMPOUND), c -> train.occupiedSignalBlocks NBTHelper.iterateCompoundList(tag.getList("SignalBlocks", Tag.TAG_COMPOUND), c -> train.occupiedSignalBlocks
.put(c.getUUID("Id"), c.contains("Boundary") ? c.getUUID("Boundary") : null)); .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.ChangeTitleInstruction;
import com.simibubi.create.content.logistics.trains.management.schedule.destination.DestinationInstruction; 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.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 com.simibubi.create.foundation.utility.NBTHelper;
import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.CompoundTag;
@ -239,8 +237,7 @@ public class ScheduleRuntime {
} else { } else {
GlobalStation destination = train.navigation.destination; GlobalStation destination = train.navigation.destination;
if (destination != null) { if (destination != null) {
CTrains conf = AllConfigs.SERVER.trains; double speed = (train.maxSpeed() + train.maxTurnSpeed()) / 2;
double speed = (conf.getTopSpeedMPT() + conf.getTurningTopSpeedMPT()) / 2;
int timeRemaining = (int) (train.navigation.distanceToDestination / speed) * 2; int timeRemaining = (int) (train.navigation.distanceToDestination / speed) * 2;
if (predictionTicks.size() > current && train.navigation.distanceStartedAt != 0) { 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 class CTrains extends ConfigBase {
public final ConfigBool trainsCauseDamage = b(true, "trainsCauseDamage", Comments.trainsCauseDamage); 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 maxAssemblyLength = i(128, 5, "maxAssemblyLength", Comments.maxAssemblyLength);
public final ConfigInt maxBogeyCount = i(20, 1, "maxBogeyCount", Comments.maxBogeyCount); 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 @Override
public String getName() { public String getName() {
return "trains"; 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 { private static class Comments {
static String mps = "[in Blocks/Second]"; static String mps = "[in Blocks/Second]";
static String acc = "[in Blocks/Second²]"; static String acc = "[in Blocks/Second²]";
static String trainTopSpeed = "The top speed of any assembled Train."; static String trainTopSpeed = "The top speed of any assembled Train.";
static String trainTurningTopSpeed = "The top speed of Trains during a turn."; static String trainTurningTopSpeed = "The top speed of Trains during a turn.";
static String trainAcceleration = "The acceleration of any assembled Train."; 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 trainsCauseDamage = "Whether moving Trains can hurt colliding mobs and players.";
static String maxAssemblyLength = "Maximum length of a Train Stations' assembly track."; static String maxAssemblyLength = "Maximum length of a Train Stations' assembly track.";
static String maxBogeyCount = "Maximum amount of bogeys assembled as a single Train."; static String maxBogeyCount = "Maximum amount of bogeys assembled as a single Train.";