Skip to content

[feat] Multi-floor capability#1598

Open
poizzy wants to merge 19 commits intoTeamOpenIndustry:masterfrom
poizzy:multi-floor-feature
Open

[feat] Multi-floor capability#1598
poizzy wants to merge 19 commits intoTeamOpenIndustry:masterfrom
poizzy:multi-floor-feature

Conversation

@poizzy
Copy link
Copy Markdown
Contributor

@poizzy poizzy commented Oct 6, 2025

2nd time the charme because I fucked up...

@poizzy poizzy marked this pull request as ready for review February 24, 2026 18:16
@cam72cam
Copy link
Copy Markdown
Member

Overall, this looks really good! I'm going to do some performance testing tomorrow, but don't see any major blockers on first review.

data = new float[components.size() * xRes * zRes];

VertexBuffer vb = def.model.vbo.buffer.get();
FaceAccessor visitor = def.model.getFaceAccessor();
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using the FaceAccessor / the changes here are about 8% slower in my testing. The code is much cleaner, so I'd be willing to live with it.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the context of everything else during a cold cache startup, it's only around 0.25% increase.

return intersects;
}

private boolean isAtCoupler(Vec3d offset, Vec3d movement, EntityCoupleableRollingStock.CouplerType type) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This does not seem to work based on my initial testing. I've got two pieces of stock on a curve and it does not detect isAtFront or isAtBack correctly.

Copy link
Copy Markdown
Member

@cam72cam cam72cam left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall, the multi-floor stuff feels really smooth!

I need the following fixed before merge:

  • Walking between cars does not work, see comment
  • All movement stops when colliding with a wall, this should try to smear instead
  • Gauge scaling of models is completely broken

@SebastianD334
Copy link
Copy Markdown
Contributor

I'm not sure this is still the case with the latest version, but on past versions the calculations for the length of the walkable area from the center were flipped back to front, so you'd get teleported to the next car when you'd reached the end of the opposite side of the car, to test this try making a FLOOR object that's heavily shifted towards one end and see when you get switched to the next car when approaching the far end.

Just something to look out for, I first noticed this with my IC 2020 AD at the time when the floors were still numbered to be stacked, but I believe the issue persists to this day.

@poizzy
Copy link
Copy Markdown
Contributor Author

poizzy commented Mar 10, 2026

All movement stops when colliding with a wall, this should try to smear instead

Honestly this is beyond my capability. Even with the help of AI I couldn't figure out an algorithm that can detect the edges of floor mesh, without having to change the way how the floors are defined. The only thing I could add is sliding along the collision mesh.

@cam72cam
Copy link
Copy Markdown
Member

@poizzy I've got an idea that I'd like to try. It's brute force, but it should work. I'll PR into your branch

@cam72cam
Copy link
Copy Markdown
Member

diff --git a/src/main/java/cam72cam/immersiverailroading/entity/EntityRidableRollingStock.java b/src/main/java/cam72cam/immersiverailroading/entity/EntityRidableRollingStock.java
index d10f567a..58a8c34f 100644
--- a/src/main/java/cam72cam/immersiverailroading/entity/EntityRidableRollingStock.java
+++ b/src/main/java/cam72cam/immersiverailroading/entity/EntityRidableRollingStock.java
@@ -138,9 +138,6 @@ public abstract class EntityRidableRollingStock extends EntityBuildableRollingSt
                }
                Vec3d targetXZ = VecUtil.rotatePitch(movement, -this.getRotationPitch());
 
-               Vec3d rayStart = targetXZ.rotateYaw(-90).add(0, 1, 0);
-               Vec3d rayDir = new Vec3d(0, -1, 0);
-
                Vec3d localTarget = targetXZ.rotateYaw(-90);
 
                IBoundingBox rayBox = IBoundingBox.from(
@@ -151,22 +148,32 @@ public abstract class EntityRidableRollingStock extends EntityBuildableRollingSt
                NavMesh navMesh = getDefinition().navMesh;
                navMesh.queryBVH(navMesh.root, rayBox, nearby, this.gauge.scale());
 
-               double closestY = Float.NEGATIVE_INFINITY;
-               boolean hit = false;
-
-               for(OBJFace tri : nearby) {
-                       Double t = MathUtil.intersectRayTriangle(rayStart, rayDir, tri);
-                       if (t != null && t >= 0) {
-                               Vec3d hitPoint = rayStart.add(rayDir.scale(t));
-                               if (!hit || hitPoint.y > closestY) {
-                                       closestY = hitPoint.y;
-                                       hit = true;
+               Double closestY = null;
+               Vec3d rayDir = new Vec3d(0, -1, 0);
+               outer:
+               for (int yawOffset = 0; yawOffset < 50; yawOffset+=5) {
+                       for (int yawDirection = 0; yawDirection < 2; yawDirection++) {
+                               int yawDelta = yawOffset * (yawDirection == 0 ? -1 : 1);
+                               Vec3d modXZ = movement.subtract(offset).rotateYaw(yawDelta).add(offset);
+                               Vec3d testingXZ = VecUtil.rotatePitch(modXZ, -this.getRotationPitch());
+                               Vec3d rayStart = testingXZ.rotateYaw(-90).add(0, 1, 0);
+                               for(OBJFace tri : nearby) {
+                                       Double t = MathUtil.intersectRayTriangle(rayStart, rayDir, tri);
+                                       if (t != null && t >= 0) {
+                                               Vec3d hitPoint = rayStart.add(rayDir.scale(t));
+                                               if (closestY == null || hitPoint.y > closestY) {
+                                                       closestY = hitPoint.y;
+                                               }
+                                       }
+                               }
+                               if (closestY != null) {
+                                       targetXZ = testingXZ;
+                                       break outer;
                                }
                        }
-
                }
 
-               if (hit) {
+               if (closestY != null) {
                        offset = VecUtil.rotatePitch(new Vec3d(targetXZ.x, closestY, targetXZ.z), this.getRotationPitch());
                }

I'm thinking something like this, but in practice the changes you made to EntityRidableRollingStock need to be mostly rewritten. I'll put in a PR in the next day or two.

@Goldenfield192
Copy link
Copy Markdown
Member

Ridiculous idea:
Can we generate a new "floor" mesh in code with COLLISIONs subtracted from FLOORs?(think bool modifier in blender), then we could change the problem to not letting players bypass holes on ground

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants