Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
f255487
feat: make default label translatable
Goldenfield192 Aug 13, 2025
dbdcade
i18n: add translation entries
Goldenfield192 Aug 13, 2025
8ad4280
fix: remap unexist material
Goldenfield192 Aug 14, 2025
ee66d97
i18n: add default stock name entries
Goldenfield192 Aug 14, 2025
d8eb411
feat: make label translatable
Goldenfield192 Aug 14, 2025
f62ea88
feat: optimize multiblock creation
Goldenfield192 Aug 14, 2025
476469e
Merge pull request #1553 from Goldenfield192/model-fix
cam72cam Aug 24, 2025
29b7888
Merge pull request #1554 from Goldenfield192/i18n
cam72cam Aug 24, 2025
059e969
Merge pull request #1555 from Goldenfield192/multiblock_threaded
cam72cam Aug 24, 2025
e0cf0ce
[Feature] Optimize CubicCurve (#1548)
Goldenfield192 Aug 24, 2025
df22370
feat: add range property to animatrix definition for better mapping (…
Goldenfield192 Aug 24, 2025
08c49dc
docs: update AUTHORS (#1560)
Goldenfield192 Sep 1, 2025
166d011
fix: stock not removed (#1561)
Goldenfield192 Sep 1, 2025
5bc7b43
feat: change ExpireableMap definition (#1563)
Goldenfield192 Sep 1, 2025
c956cb1
[Fix] Translation issue & Paintbrush GUI (#1564)
Goldenfield192 Sep 1, 2025
a01aa40
[Feature] LightFlare changes (#1559)
Goldenfield192 Sep 1, 2025
483c786
snowLayers property for rolling stock (#1567)
FnordyCave Sep 3, 2025
5cdfe09
fix translation error (#1570)
Goldenfield192 Sep 3, 2025
27eadfd
i18n: update zh-cn file (#1573)
Goldenfield192 Sep 7, 2025
c674f50
Allow golden spike to modify slope height (#1566)
cam72cam Sep 7, 2025
b806d46
Add cargo load command (#1569)
cam72cam Sep 7, 2025
f7d91a2
[feat] Added semi-transparent parts (#1556)
poizzy Sep 7, 2025
62e65ac
feat: add excludeStandaloneWagons to optimize performance (#1576)
Goldenfield192 Sep 8, 2025
7ec7db0
revert #1555 (#1582)
Goldenfield192 Sep 27, 2025
4c2717c
fix structure (#1580)
Goldenfield192 Sep 27, 2025
1b163f8
fix: unexpected fallthrough (#1586)
Goldenfield192 Sep 27, 2025
9954514
[Fix & Feature] Golden spike changes (#1572)
Goldenfield192 Sep 27, 2025
db204a6
Customizable decimals on GUI readouts (#1512)
SebastianD334 Sep 27, 2025
9ba71b5
[Feature] Advanced track model definition (#1565)
Goldenfield192 Sep 27, 2025
97ba649
[Feature] Add ability to customize diesel fuel by definition (#1577)
Goldenfield192 Sep 27, 2025
7e4afec
feat: add `whitelistBlocks` to prevent destruction to certain blocks …
Goldenfield192 Sep 27, 2025
376a848
[Feature] SI Units (#1585)
Goldenfield192 Sep 27, 2025
7f46277
fix: NPE (#1587)
Goldenfield192 Sep 28, 2025
93797f7
Remove decimals from tooltips (#1590)
SebastianD334 Sep 29, 2025
5b6edb5
Fix SI units and add power_hp as alternative to horsepower (#1589)
SebastianD334 Sep 29, 2025
e0dd89f
fix: track with too many segments won't work (#1591)
Goldenfield192 Sep 29, 2025
aa0b711
Added bar, adjusted hp, added ps, adjusted defaults, organized unit l…
SebastianD334 Sep 30, 2025
89dd8a7
docs: update changelog
Goldenfield192 Oct 5, 2025
d351b77
[Refactor] VecYawPitch cleanup (#1595)
Goldenfield192 Oct 5, 2025
d413bf5
fix: slope without golden spike won't work (#1597)
Goldenfield192 Oct 6, 2025
d358c93
[I18n] Add missing entries for lang files & update ja_jp.lang(Transla…
Goldenfield192 Oct 6, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions AUTHORS
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,6 @@ Cyberslas (littlej54192)
Tovlyn
Florian Kostenzer (123FLO321)
Ben K. (Xyvoracle)
Zuo Fei (Goldenfield192)

See sounds/CREDITS for links to the audio sources and their licensing info
61 changes: 61 additions & 0 deletions DevelopmentNotes/immersiverailroading-1.11.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
## New Features

### **Configuration**
- **Goldenfield192**:
- Added `stockDropInCreativeMode` in `Config/Debug` to facilitate world building.
- Added `excludeStandaloneWagons` in `Config/Debug` to reduce chunk loading costs (works with `keepStockLoaded`).
- Added `TrainsIgnoreBlocks` in `Config/Damage` to prevent destruction to specific block types (use registry names shown in the F3 panel).
- Added `TrackRenderDistance` in `Config/Graphics` to customize the maximum track render distance for values above 256.
- Added `DisableLightTextureRender` in `Config/Graphics` to disable flare rendering (Dynamic light is preserved if OptiFine is installed).
- Added `powerUnit` and `forceUnit` in `Config/Graphics` to customize units used in GUI and item tooltips.

### **Track**
- **cam72cam**: Golden spikes can now modify the height of `slope` tracks instead of being fixed at 1 block upwards.
- **Goldenfield192**:
- Updated golden spike behavior for horizontal direction—now uses arc length for `turn` and shadow length for `straight` and `slope`.
- Introduced the transfer table as a new track type.
- Rewrote curve generation to prevent overlapping track segments.
- Added a new method for defining tracks (documented in [GitHub Gist](https://gist.github.com/Goldenfield192/70bc96cce31cd1a784868fbe302073b5)).

### **Stock**
- **poizzy & cam72cam**: Stock parts can now be made transparent by adding `ALPHA`.
- **FnordyCave**: Added `snow_layers` (integer property) under `properties` in stock definitions to define reserved snow layers on tracks after cleaning.
- **SebastianD334**:
- Added `power_w`, `power_kw`, `power_ps` (Metric horsepower), and `power_hp` (Imperial horsepower) as alternatives for locomotive power definitions (legacy `horsepower` is equivalent to `power_hp` and is **no longer recommended and may not be supported by newer versions**).
- Added `tractive_effort_kn` and `tractive_effort_n` as alternatives for locomotive tractive effort definitions.
- Added `max_pressure_bar`, `max_pressure_kpa`, and `max_pressure_psi` as alternatives for steam locomotive pressure definitions (legacy `max_psi` is equivalent to `max_pressure_psi` and is **no longer recommended and may not be supported by newer versions**).
- **Goldenfield192**:
- Added `range_min` and `range_max` to the animatrix definition block to align with `RANGE_[min]_[max]` in control definitions.
- Added `revertDirection` to light definitions to specify if the light's direction is reversed (e.g., a front-facing light at the stock's tail).
- Added support for defining light working directions using `FORWARD` or `REVERSE`.
- Added `fuel_override` under `properties` to customize diesel locomotive fuels (documented in [GitHub PR #1577](https://github.com/TeamOpenIndustry/ImmersiveRailroading/pull/1577)).

### **Translations**
- **Goldenfield192**:
- Stock labels can now be translated using the key `part.immersiverailroading:control.[name]` for [defaults](https://github.com/TeamOpenIndustry/ImmersiveRailroading/blob/master/src/main/java/cam72cam/immersiverailroading/library/ModelComponentType.java#L141) and `label.immersiverailroading:[stock_type].[stock_definition_name].[label]` or `label.immersiverailroading:[label]` for other `LABEL`s.
- Example: For a diesel locomotive defined as `test` with a control `WIDGET_1_LABEL_test`, IR will first search for `label.immersiverailroading:diesel.test.test`, then `label.immersiverailroading:test` if the first one not found.
- The first method is recommended for better compatibility.
- Added numerous new translation entries for GUI elements.

### **Commands**
- **cam72cam**: Removed `/immersiverailroading reload` and added `/immersiverailroading cargoFill [radius: Integer]` to fill all stocks in the specified radius with the item held in the player's main hand (clears all stocks if the hand is empty).
- Default radius is 2.

### **GUI**
- **SebastianD334 & Goldenfield192**: Added support for defining decimal digits in GUI definitions using `state.[name].X`.
- Example: `stat.speed.3` will display speed with 3 decimal digits.

## Fixes and Refactoring

- **DarkRaider**:
- Updated `clearArea` exception logic to avoid manual cleaning when placing tracks in snow.
- Adjusted grade crossing math to ensure symmetrical heights on both sides of the track.
- **Goldenfield192**:
- Fixed draggable widgets on unfinished stocks.
- Corrected particle emitter offsets, especially during high-speed movement.
- Resolved element overlapping in the track blueprint GUI.
- Fixed incorrect boiler machine model offsets.
- Addressed diesel throttle glitches when setting non-notched values via dragging or augmentation.
- Remapped non-existent materials in `firefly` and `iron_duke` to prevent unnecessary logs.
- Ensured stocks are removed when their pack is unloaded.
- Expanded paintbrush GUI button width to accommodate new translations.
8 changes: 8 additions & 0 deletions src/main/java/cam72cam/immersiverailroading/Config.java
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,11 @@ public static class ConfigDamage {
@Comment("Trains should break block")
public static boolean TrainsBreakBlocks = true;

@Comment("Which block is reserved if TrainsBreakBlocks is true")
public static String[] TrainsIgnoreBlocks = new String[]{
"littletiles:blocklittletiles"
};

@Comment("How hard are blocks to break by rolling stock?")
@Range(min = 0, max = 500)
public static int blockHardness = 50;
Expand Down Expand Up @@ -257,6 +262,9 @@ public static class ConfigDebug {
@Comment("Keep rolling stock loaded even when it is not moving")
public static boolean keepStockLoaded = true;

@Comment("Exclude unattached wagons from chunk loading when keepStockLoaded is true")
public static boolean excludeStandaloneWagons = false;

@Comment( "Print extra chunk loading info" )
public static boolean debugLog = false;

Expand Down
24 changes: 17 additions & 7 deletions src/main/java/cam72cam/immersiverailroading/ConfigGraphics.java
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
package cam72cam.immersiverailroading;

import cam72cam.immersiverailroading.library.PressureDisplayType;
import cam72cam.immersiverailroading.library.SpeedDisplayType;
import cam72cam.immersiverailroading.library.TemperatureDisplayType;
import cam72cam.immersiverailroading.library.unit.*;
import cam72cam.mod.config.ConfigFile.Comment;
import cam72cam.mod.config.ConfigFile.Name;
import cam72cam.mod.render.OptiFine;
Expand All @@ -22,15 +20,21 @@ public class ConfigGraphics {
@Comment( "Self explanatory" )
public static boolean trainsOnTheBrain = true;

@Comment( "What unit to use for speedometer. (kmh, mph or ms)" )
@Comment("What unit to display speed in (kmh, ms, mph)")
public static SpeedDisplayType speedUnit = SpeedDisplayType.kmh;

@Comment("What units to display pressure in (psi, bar)")
public static PressureDisplayType pressureUnit = PressureDisplayType.psi;
@Comment("What unit to display pressure in (psi, kpa, bar)")
public static PressureDisplayType pressureUnit = PressureDisplayType.bar;

@Comment("What units to display pressure in (psi, bar)")
@Comment("What unit to display temperature in (celcius, kelvin, farenheit)")
public static TemperatureDisplayType temperatureUnit = TemperatureDisplayType.celcius;

@Comment("What unit to display locomotive power in (w, kw, ps (metric horsepower), horsepower (imperial horsepower))")
public static PowerDisplayType powerUnit = PowerDisplayType.kw;

@Comment("What unit to display locomotive traction force in (kn, n, lbf)")
public static ForceDisplayType forceUnit = ForceDisplayType.kn;

@Comment( "How long to keep textures in memory after they have left the screen (higher numbers = smoother game play, lower numbers = less GPU memory used)")
@Range(min = 0, max = 100)
public static int textureCacheSeconds = 30;
Expand Down Expand Up @@ -68,7 +72,13 @@ public class ConfigGraphics {
@Comment("Try to fake interior lighting for locomotives/passenger cars that are being ridden")
public static boolean FakeInteriorLighting = true;

@Comment("Disable headlights' texture render")
public static boolean DisableLightTextureRender = false;

@Comment("The track's maximum visibility range")
@Range(min = 256, max = 4096)
public static double TrackRenderDistance = 256;

@Comment("Should semi-transparent parts render? Disable this if you are experiencing problems with semi-transparent parts when using a Shader")
public static boolean RenderSemiTransparentParts = true;
}
43 changes: 38 additions & 5 deletions src/main/java/cam72cam/immersiverailroading/IRCommand.java
Original file line number Diff line number Diff line change
@@ -1,12 +1,19 @@
package cam72cam.immersiverailroading;

import cam72cam.immersiverailroading.entity.EntityCoupleableRollingStock;
import cam72cam.immersiverailroading.entity.EntityRollingStock;
import cam72cam.immersiverailroading.entity.Freight;
import cam72cam.immersiverailroading.registry.DefinitionManager;
import cam72cam.mod.entity.Player;
import cam72cam.mod.entity.boundingbox.IBoundingBox;
import cam72cam.mod.item.ItemStack;
import cam72cam.mod.math.Vec3d;
import cam72cam.mod.math.Vec3i;
import cam72cam.mod.text.Command;
import cam72cam.mod.text.PlayerMessage;
import cam72cam.mod.world.World;

import java.awt.*;
import java.io.IOException;
import java.util.Comparator;
import java.util.List;
Expand All @@ -32,13 +39,39 @@ public int getRequiredPermissionLevel() {

@Override
public boolean execute(Consumer<PlayerMessage> sender, Optional<Player> player, String[] args) {
if (args.length != 1) {
if (args.length == 0) {
return false;
}
if (args[0].equals("reload")) {
ImmersiveRailroading.warn("Reloading Immersive Railroading definitions");
DefinitionManager.initDefinitions();
ImmersiveRailroading.info("Done reloading Immersive Railroading definitions");
if (args[0].equals("cargoFill")) {
if (player.isPresent()) {
int distance = 2;
if (args.length > 1) {
try {
distance = Integer.parseInt(args[1]);
} catch (NumberFormatException e) {
sender.accept(PlayerMessage.direct("Invalid number " + args[1]));
return true;
}
}
IBoundingBox bb = player.get().getBounds().grow(new Vec3d(distance, 4, distance));
List<Freight> carsNearby = player.get().getWorld().getEntities((Freight stock) -> bb.intersects(stock.getBounds()), Freight.class);
ItemStack stack = player.get().getHeldItem(Player.Hand.PRIMARY);

if (carsNearby.isEmpty()) {
sender.accept(PlayerMessage.direct("No rolling stock within range to fill"));
}

for (Freight freight : carsNearby) {
sender.accept(PlayerMessage.direct(String.format("Filling %s@%s with %s", freight.getDefinition().name(), new Vec3i(freight.getPosition()), stack.getDisplayName())));
for (int i = 0; i < freight.cargoItems.getSlotCount(); i++) {
if (stack.isEmpty() || freight.cargoItems.get(i).isEmpty()) {
freight.cargoItems.set(i, stack.copy());
}
}
}
} else {
sender.accept(PlayerMessage.direct("This command is not supported for non-players (yet)"));
}
return true;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ public String toString() {
@TagSync
@TagField("hasElectricalPower")
private boolean hasElectricalPower;
private boolean linkedToLocomotive;
private boolean hadElectricalPower = false;
private int gotElectricalPowerTick = -1;

Expand Down Expand Up @@ -186,17 +187,23 @@ public void onTick() {

if (this.getTickCount() % 5 == 0) {
hasElectricalPower = false;
this.mapTrain(this, false, stock ->
hasElectricalPower = hasElectricalPower ||
stock instanceof Locomotive && ((Locomotive) stock).providesElectricalPower()
linkedToLocomotive = false;
this.mapTrain(this, false, stock -> {
hasElectricalPower = hasElectricalPower ||
stock instanceof Locomotive && ((Locomotive) stock).providesElectricalPower();
linkedToLocomotive = linkedToLocomotive || stock instanceof Locomotive;
}
);
}

hadElectricalPower = hasElectricalPower();

if (this.getCurrentState() != null && !this.getCurrentState().atRest || ConfigDebug.keepStockLoaded) {
keepLoaded();
}
//Then exclude stocks not linked to any locomotive
if (!ConfigDebug.excludeStandaloneWagons || this.linkedToLocomotive) {
keepLoaded();
}
}

slackFrontPercent = 0;
slackRearPercent = 0;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,7 @@ public void onTick() {
for (Vec3i bp : state.trackToUpdate) {
TileRailBase te = getWorld().getBlockEntity(bp, TileRailBase.class);
if (te != null) {
te.cleanSnow();
te.cleanSnow(this.getDefinition().getSnowLayers());
te.stockOverhead(this);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ public String tryJoinWorld() {
if (DefinitionManager.getDefinition(defID) == null) {
String error = String.format("Missing definition %s, do you have all of the required resource packs?", defID);
ImmersiveRailroading.error(error);
this.kill();
return error;
}
return null;
Expand All @@ -108,8 +109,7 @@ public String getDefinitionID() {
@Override
public void onTick() {
if (getWorld().isServer && this.getTickCount() % 5 == 0) {
EntityRollingStockDefinition def = DefinitionManager.getDefinition(defID);
if (def == null) {
if (DefinitionManager.getDefinition(defID) == null) {
this.kill();
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -158,13 +158,6 @@ protected void initContainerFilter() {
@Override
public double getWeight() {
double fLoad = ConfigBalance.blockWeight * itemCount;
/*
for (int i = 0; i < cargoItems.getSlotCount(); i++) {
ItemStack item = Fuzzy.WOOD_PLANK.example();
item.setCount(64);
cargoItems.set(i, item);
}*/

fLoad = fLoad + super.getWeight();
return fLoad;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public double getAppliedTractiveEffort(Speed speed) {
}
}
// Same as diesel for now
double maxPower_W = this.getDefinition().getHorsePower(gauge) * 745.7d * passengers;
double maxPower_W = this.getDefinition().getWatt(gauge) * passengers;
double efficiency = 0.82; // Similar to a *lot* of imperial references
double speed_M_S = (Math.abs(speed.metric())/3.6);
double maxPowerAtSpeed = maxPower_W * efficiency / Math.max(0.001, speed_M_S);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,7 @@
import cam72cam.mod.fluid.FluidStack;
import cam72cam.mod.serialization.TagField;

import java.util.List;
import java.util.OptionalDouble;
import java.util.*;

public class LocomotiveDiesel extends Locomotive {

Expand Down Expand Up @@ -161,7 +160,7 @@ public void setReverser(float newReverser) {
@Override
public double getAppliedTractiveEffort(Speed speed) {
if (isRunning() && (getEngineTemperature() > 75 || !Config.isFuelRequired(gauge))) {
double maxPower_W = this.getDefinition().getHorsePower(gauge) * 745.7d;
double maxPower_W = this.getDefinition().getWatt(gauge);
double efficiency = 0.82; // Similar to a *lot* of imperial references
double speed_M_S = (Math.abs(speed.metric())/3.6);
double maxPowerAtSpeed = maxPower_W * efficiency / Math.max(0.001, speed_M_S);
Expand Down Expand Up @@ -221,9 +220,12 @@ public void onTick() {

if (this.getLiquidAmount() > 0 && isRunning()) {
float consumption = Math.abs(getThrottle()) + 0.05f;
float burnTime = BurnUtil.getBurnTime(this.getLiquid());
float burnTime = getDefinition().getOverriddenFuels().getOrDefault(this.getLiquid(), 0);
if (burnTime == 0) {
burnTime = 200; //Default to 200 for unregistered liquids
burnTime = BurnUtil.getBurnTime(this.getLiquid());
}
if (burnTime == 0) {
burnTime = 200;
}
burnTime *= getDefinition().getFuelEfficiency()/100f;
burnTime *= (Config.ConfigBalance.locoDieselFuelEfficiency / 100f);
Expand Down Expand Up @@ -253,10 +255,11 @@ public void onTick() {

setEngineTemperature(engineTemperature);
}

@Override
public List<Fluid> getFluidFilter() {
return BurnUtil.burnableFluids();
Set<Fluid> set = getDefinition().getOverriddenFuels().keySet();
return set.isEmpty() ? BurnUtil.burnableFluids() : new ArrayList<>(set);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ public double getAppliedTractiveEffort(Speed speed) {
// This is terrible, but allows wheel slip for both legacy and updated hp vs te
double traction_N = Math.max(
this.getDefinition().getStartingTractionNewtons(gauge),
this.getDefinition().getHorsePower(gauge) * 375 / Math.max(Math.abs(speed.imperial()), 1.0)
this.getDefinition().getWatt(gauge) * 0.5 / Math.max(Math.abs(speed.imperial()), 1.0)
);
if (Config.isFuelRequired(gauge)) {
traction_N = traction_N / this.getDefinition().getMaxPSI(gauge) * this.getBoilerPressure();
Expand Down Expand Up @@ -286,7 +286,7 @@ public void onTick() {
}

// Pressure relief valve
int maxPSI = this.getDefinition().getMaxPSI(gauge);
int maxPSI = (int) this.getDefinition().getMaxPSI(gauge);
pressureValve = boilerPressure > maxPSI;
if (boilerPressure > maxPSI) {
waterUsed += boilerPressure - maxPSI;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -286,7 +286,9 @@ public void calculateBlockCollisions(List<Vec3i> blocksAlreadyBroken) {
if (BlockUtil.isIRRail(config.world, bp)) {
trackToUpdate.add(bp);
} else {
if (Config.ConfigDamage.TrainsBreakBlocks && !BlockUtil.isIRRail(config.world, bp.up())) {
if (Config.ConfigDamage.TrainsBreakBlocks
&& !BlockUtil.isWhitelisted(config.world, bp)
&& !BlockUtil.isIRRail(config.world, bp.up())) {
if (bp.y >= position.y - (position.y % 1)) { // Prevent it from breaking blocks under the pitched train (bb expanded)
interferingBlocks.add(bp);
interferingResistance += config.world.getBlockHardness(bp);
Expand Down
Loading
Loading