Skip to content

Physics stage breaking when changing VS ship dimension and in Kontraption helm #49

Description

@blockninja124

BEFORE REPORTING MAKE SURE:

  • You are on the newest version of Kontraption and Valkyrien Skies.
  • You have tested it with only Kontraption, Valkyrien Skies, Mekanism and Kotlin for Forge installed. (Plus starlance and CH to trigger this issue)
  • The bug hasn't been reported already.

Describe the bug
When teleporting a VS ship between dimensions with a player in a Kontraption helm, the logs spam "is the physics stage broken?" and the world is partially broken (as it normally does when the physics stage breaks). There's no particular error in the logs as to why the physics stage broke however

To Reproduce
Use Starlance and Cosmic Horizons and get to above y=560 in the overworld (the trigger for the ship teleport)

Expected behavior
The physics stage not to break, especially since Starlance tries to dismount all seated entities before moving them. The Eureka helm does not cause this issue

Logs
Latest.log:
latest (16).log

Versions

  • VS2 version: 1.20.1 2.3.0-beta.5
  • Mekanism version: Idk, someone else discovered this. latest I assume?

Additional context
Here is the code I use to teleport a VS ship between dimensions. If you need more context, I can give you access to the github repo :D

/**
* This function took us like 3 days to make. You better appreciate it. <br>
* </br>
* It will teleport the given {@link ship}, using the {@link level}, to the
* dimension with id of {@link newDim} at {@link x}, {@link y}, {@link z}. <br>
* </br>
* But most importantly, it will also teleport any players or entities that are
* currently being dragged by the ship to the new dimension, and their correct
* position relative to the ship that was moved.
* 
* @param ship   The ship to move
* @param level  The ships current level
* @param newDim Normal dimension id string format (not VS format)
* @param x
* @param y
* @param z
*/
public static void DimensionTeleportShip(Ship ship, ServerLevel level, String newDim, double x, double y, double z) {

// ----- Prepare dimension destination ----- //

// Convert back into a stupid stupid VS dimension string
String VSnewDimension = VSCHUtils.dimToVSDim(newDim);

// Prepare ship teleport info for later
ShipTeleportData teleportData = new ShipTeleportDataImpl(new Vector3d(x, y, z), ship.getTransform().getShipToWorldRotation(), new Vector3d(), new Vector3d(), VSnewDimension, null);

// ----- AABB magic ----- //

// Get the AABB of the last tick and the AABB of the current tick
AABB prevWorldAABB = VectorConversionsMCKt.toMinecraft(VSCHUtils.transformToAABBd(ship.getPrevTickTransform(), ship.getShipAABB())).inflate(10);
AABB currentWorldAABB = VectorConversionsMCKt.toMinecraft(ship.getWorldAABB()).inflate(10);

// Combine the AABB's into one big one
AABB totalAABB = currentWorldAABB.minmax(prevWorldAABB);

Vec3 oldShipCenter = prevWorldAABB.deflate(10).getCenter();

// ---------- //

// ----- Get all entities BEFORE teleporting ship ----- //

// Save the distances from entities to the ship for afterwards
Map<String, Vec3> entityOffsets = new HashMap<String, Vec3>();

// Save entities that actually need to be teleported
List<Entity> importantEntities = new ArrayList<>();
List<Entity> playerEntities = new ArrayList<>();

// Find all entities nearby the ship
for (Entity entity : level.getEntities(null, totalAABB)) {

	//System.out.println("Entity: " + entity);

	// A couple checks to make sure they are able to be teleported with the ship
	if (VSCHUtils.CanEntityBeTaken(entity)) {

		// If the entity is riding another
		if (entity.getVehicle() != null) {
			// Dismount them
			entity.dismountTo(entity.getX(), entity.getY(), entity.getZ());
		}

		// Get the offset from the entities position to the ship
		Vec3 entityShipOffset = entity.getPosition(0).subtract(oldShipCenter);

		// Save the offset and the entity. Prob don't need two lists here but oh well
		entityOffsets.put(entity.getStringUUID(), entityShipOffset);
		if (entity instanceof ServerPlayer) {
			playerEntities.add(entity);
		} else {
			importantEntities.add(entity);
		}

	}

}

// ---------- //

// ----- Teleport ship ----- //

// Do we actually use this? Eh can't be bothered to check
// Yes we do. Don't remove this
ServerShipWorldCore shipWorld = VSGameUtilsKt.getShipObjectWorld(level);

// Teleport ship to new dimension at origin
ServerShip serverShip = (ServerShip) ship;
shipWorld.teleportShip(serverShip, teleportData);

// ---------- //

// ----- Teleport entities AFTER ship ----- //

// Get a level object from the VS dimension string of the dim we're going to
ServerLevel newLevel = VSCHUtils.VSDimToLevel(level.getServer(), VSnewDimension);
Vec3 newShipCenter = VectorConversionsMCKt.toMinecraft(ship.getWorldAABB()).getCenter();

// Teleport ALL players before teleporting ALL entities to prevent players getting entity pushed
for (Entity entity : playerEntities) {

	Vec3 shipOffset = entityOffsets.get(entity.getStringUUID());
	Vec3 newPosition = newShipCenter.add(shipOffset);

	/*System.out.println("New (player) info -----");
	System.out.println(entityOffsets);
	System.out.println(newShipCenter);
	System.out.println(newPosition);
	System.out.println("-----");*/

	// Players need a different teleport command to entities
	((ServerPlayer) entity).teleportTo(newLevel, newPosition.x, newPosition.y, newPosition.z, entity.getYRot(), entity.getXRot());
}

// Now teleport all non-player entities
for (Entity entity : importantEntities) {

	Vec3 shipOffset = entityOffsets.get(entity.getStringUUID());
	Vec3 newPosition = newShipCenter.add(shipOffset);

	/*System.out.println("New info -----");
	System.out.println(entityOffsets);
	System.out.println(newShipCenter);
	System.out.println(newPosition);
	System.out.println("-----");*/

	// Teleport entity (players are handled separately)
	entity.teleportTo(newLevel, newPosition.x, newPosition.y, newPosition.z, null, entity.getYRot(), entity.getXRot());

}

	}
	
/**
* Performs a check on an entity to see if it can/should be moved
* through dimensions with a VS ship. Checks if the entity 
* Has a
* {@link org.valkyrienskies.mod.common.util.IEntityDraggingInformationProvider
* IEntityDraggingInformationProvider}
* @param entity The entity to check
* @return True if the entity passed all checks, otherwise False
*/
public static boolean CanEntityBeTaken(Entity entity) {
// If the entity has dragging info (they should)
if (entity instanceof IEntityDraggingInformationProvider) {
	return true;
}
return false;
}

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions