Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/refactor ship mounting #660

Merged
merged 5 commits into from
Dec 24, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import org.valkyrienskies.core.apigame.world.ClientShipWorldCore;
import org.valkyrienskies.mod.client.IVSCamera;
import org.valkyrienskies.mod.common.IShipObjectWorldClientProvider;
import org.valkyrienskies.mod.common.entity.ShipMountedToData;
import org.valkyrienskies.mod.common.VSGameUtilsKt;
import org.valkyrienskies.mod.common.util.EntityDraggingInformation;
import org.valkyrienskies.mod.common.util.IEntityDraggingInformationProvider;
Expand Down Expand Up @@ -134,14 +135,13 @@ private void preRender(final float tickDelta, final long startTime, final boolea
// This is set when an entity is mounted to a ship, or an entity is being dragged by a ship
Vector3dc entityShouldBeHere = null;

// First, try getting [entityShouldBeHere] from [shipMountedTo]
final ClientShip shipMountedTo =
VSGameUtilsKt.getShipObjectEntityMountedTo(clientWorld, entity);
// First, try getting the ship the entity is mounted to, if one exists
final ShipMountedToData shipMountedToData = VSGameUtilsKt.getShipMountedToData(entity, tickDelta);

if (shipMountedTo != null) {
if (shipMountedToData != null) {
final ClientShip shipMountedTo = (ClientShip) shipMountedToData.getShipMountedTo();
// If the entity is mounted to a ship then update their position
final Vector3dc passengerPos =
VSGameUtilsKt.getPassengerPos(entity.getVehicle(), entity.getMyRidingOffset(), tickDelta);
final Vector3dc passengerPos = shipMountedToData.getMountPosInShip();
entityShouldBeHere = shipMountedTo.getRenderTransform().getShipToWorld()
.transformPosition(passengerPos, new Vector3d());
entity.setPos(entityShouldBeHere.x(), entityShouldBeHere.y(), entityShouldBeHere.z());
Expand Down Expand Up @@ -248,41 +248,43 @@ private void setupCameraWithMountedShip(final LevelRenderer instance, final Pose
prepareCullFrustum.call(instance, matrixStack, vec3, matrix4f);
return;
}
final ClientShip playerShipMountedTo =
VSGameUtilsKt.getShipObjectEntityMountedTo(clientLevel, player);
if (playerShipMountedTo == null) {

final ShipMountedToData shipMountedToData = VSGameUtilsKt.getShipMountedToData(player, partialTicks);
if (shipMountedToData == null) {
prepareCullFrustum.call(instance, matrixStack, vec3, matrix4f);
return;
}

final Entity playerVehicle = player.getVehicle();
if (playerVehicle == null) {
prepareCullFrustum.call(instance, matrixStack, vec3, matrix4f);
return;
}

// Update [matrixStack] to mount the camera to the ship
final Vector3dc inShipPos =
VSGameUtilsKt.getPassengerPos(playerVehicle, player.getMyRidingOffset(), partialTicks);

final Camera camera = this.mainCamera;
if (camera == null) {
prepareCullFrustum.call(instance, matrixStack, vec3, matrix4f);
return;
}

final ClientShip clientShip = (ClientShip) shipMountedToData.getShipMountedTo();

((IVSCamera) camera).setupWithShipMounted(
this.minecraft.level,
this.minecraft.getCameraEntity() == null ? this.minecraft.player : this.minecraft.getCameraEntity(),
!this.minecraft.options.getCameraType().isFirstPerson(),
this.minecraft.options.getCameraType().isMirrored(),
partialTicks,
playerShipMountedTo,
inShipPos
clientShip,
shipMountedToData.getMountPosInShip()
);

// Apply the ship render transform to [matrixStack]
final Quaternion invShipRenderRotation = VectorConversionsMCKt.toMinecraft(
playerShipMountedTo.getRenderTransform().getShipToWorldRotation().conjugate(new Quaterniond()));
clientShip.getRenderTransform().getShipToWorldRotation().conjugate(new Quaterniond())
);
matrixStack.mulPose(invShipRenderRotation);

// We also need to recompute [inverseViewRotationMatrix] after updating [matrixStack]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.Vec3;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.joml.Vector3d;
import org.joml.Vector3dc;
import org.joml.primitives.AABBd;
Expand All @@ -33,6 +32,7 @@
import org.valkyrienskies.core.api.ships.Ship;
import org.valkyrienskies.core.api.ships.properties.ShipTransform;
import org.valkyrienskies.core.impl.game.ships.ShipObjectClient;
import org.valkyrienskies.mod.common.entity.ShipMountedToData;
import org.valkyrienskies.mod.common.VSGameUtilsKt;
import org.valkyrienskies.mod.common.util.EntityDraggingInformation;
import org.valkyrienskies.mod.common.util.IEntityDraggingInformationProvider;
Expand Down Expand Up @@ -105,11 +105,11 @@ private void originalCheckInside(final AABBd aABB) {
*/
@Inject(method = "getEyePosition(F)Lnet/minecraft/world/phys/Vec3;", at = @At("HEAD"), cancellable = true)
private void preGetEyePosition(final float partialTicks, final CallbackInfoReturnable<Vec3> cir) {
final LoadedShip shipMountedTo =
VSGameUtilsKt.getShipObjectEntityMountedTo(level, Entity.class.cast(this));
if (shipMountedTo == null) {
final ShipMountedToData shipMountedToData = VSGameUtilsKt.getShipMountedToData(Entity.class.cast(this), partialTicks);
if (shipMountedToData == null) {
return;
}
final LoadedShip shipMountedTo = shipMountedToData.getShipMountedTo();

final ShipTransform shipTransform;
if (shipMountedTo instanceof ShipObjectClient) {
Expand All @@ -118,24 +118,20 @@ private void preGetEyePosition(final float partialTicks, final CallbackInfoRetur
shipTransform = shipMountedTo.getShipTransform();
}
final Vector3dc basePos = shipTransform.getShipToWorldMatrix()
.transformPosition(VSGameUtilsKt.getPassengerPos(this.vehicle, getMyRidingOffset(), partialTicks),
new Vector3d());
.transformPosition(shipMountedToData.getMountPosInShip(), new Vector3d());
final Vector3dc eyeRelativePos = shipTransform.getShipCoordinatesToWorldCoordinatesRotation().transform(
new Vector3d(0.0, getEyeHeight(), 0.0)
);
final Vec3 newEyePos = VectorConversionsMCKt.toMinecraft(basePos.add(eyeRelativePos, new Vector3d()));
cir.setReturnValue(newEyePos);
}

@Shadow
private Vec3 position;

/**
* @reason Needed for players to pick blocks correctly when mounted to a ship
*/
@Inject(method = "calculateViewVector", at = @At("HEAD"), cancellable = true)
private void preCalculateViewVector(final float xRot, final float yRot, final CallbackInfoReturnable<Vec3> cir) {
final LoadedShip shipMountedTo = VSGameUtilsKt.getShipObjectEntityMountedTo(level, Entity.class.cast(this));
final LoadedShip shipMountedTo = VSGameUtilsKt.getShipMountedTo(Entity.class.cast(this));
if (shipMountedTo == null) {
return;
}
Expand Down Expand Up @@ -180,9 +176,6 @@ private void preCalculateViewVector(final float xRot, final float yRot, final Ca
@Shadow
public abstract double getX();

@Shadow
private @Nullable Entity vehicle;

@Shadow
public abstract float getEyeHeight();

Expand All @@ -191,9 +184,6 @@ private void preCalculateViewVector(final float xRot, final float yRot, final Ca
@Shadow
public abstract EntityType<?> getType();

@Shadow
public abstract double getMyRidingOffset();

@Override
@NotNull
public EntityDraggingInformation getDraggingInformation() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ private void injectListenerVelocity(final Listener listener, final Vec3 position
((HasOpenALVelocity) listener).setVelocity(new Vector3d());

if (level != null && player != null) {
final ClientShip mounted = VSGameUtilsKt.getShipObjectEntityMountedTo(level, player);
final ClientShip mounted = (ClientShip) VSGameUtilsKt.getShipMountedTo(player);
if (mounted != null) {
((HasOpenALVelocity) listener).setVelocity(mounted.getVelocity());
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ private boolean needsFrustumUpdate(final boolean needsFrustumUpdate) {

// force frustum update if default behaviour says to OR if the player is mounted to a ship
return needsFrustumUpdate ||
(player != null && VSGameUtilsKt.getShipObjectEntityMountedTo(level, player) != null);
(player != null && VSGameUtilsKt.getShipMountedTo(player) != null);
}

/**
Expand Down
29 changes: 16 additions & 13 deletions common/src/main/kotlin/org/valkyrienskies/mod/common/VSGameUtils.kt
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ import org.valkyrienskies.core.apigame.world.properties.DimensionId
import org.valkyrienskies.core.game.ships.ShipObjectServer
import org.valkyrienskies.core.impl.hooks.VSEvents.TickEndEvent
import org.valkyrienskies.core.util.expand
import org.valkyrienskies.mod.common.entity.ShipMountedToData
import org.valkyrienskies.mod.common.entity.ShipMountedToDataProvider
import org.valkyrienskies.mod.common.util.DimensionIdProvider
import org.valkyrienskies.mod.common.util.MinecraftPlayer
import org.valkyrienskies.mod.common.util.set
Expand Down Expand Up @@ -242,11 +244,6 @@ fun Level?.getShipObjectManagingPos(posX: Double, posY: Double, posZ: Double) =
fun Level?.getShipObjectManagingPos(chunkPos: ChunkPos) =
getShipObjectManagingPos(chunkPos.x, chunkPos.z)

fun Level.getShipObjectEntityMountedTo(entity: Entity): LoadedShip? {
val vehicle = entity.vehicle ?: return null
return getShipObjectManagingPos(vehicle.position().toJOML())
}

// ClientLevel
fun ClientLevel?.getShipObjectManagingPos(chunkX: Int, chunkZ: Int) =
getShipObjectManagingPosImpl(this, chunkX, chunkZ) as ClientShip?
Expand All @@ -266,11 +263,6 @@ fun ClientLevel?.getShipObjectManagingPos(pos: Position) =
fun ClientLevel?.getShipObjectManagingPos(chunkPos: ChunkPos) =
getShipObjectManagingPos(chunkPos.x, chunkPos.z)

fun ClientLevel?.getShipObjectEntityMountedTo(entity: Entity): ClientShip? {
val vehicle = entity.vehicle ?: return null
return getShipObjectManagingPos(vehicle.position().toJOML())
}

// ServerWorld
fun ServerLevel?.getShipObjectManagingPos(chunkX: Int, chunkZ: Int) =
getShipObjectManagingPosImpl(this, chunkX, chunkZ) as ShipObjectServer?
Expand Down Expand Up @@ -417,7 +409,18 @@ fun Level.transformAabbToWorld(aabb: AABBdc, dest: AABBd): AABBd {
return dest.set(aabb)
}

fun Entity.getPassengerPos(myRidingOffset: Double, partialTicks: Float): Vector3dc {
return this.getPosition(partialTicks)
.add(0.0, this.passengersRidingOffset + myRidingOffset, 0.0).toJOML()
fun getShipMountedToData(passenger: Entity, partialTicks: Float? = null): ShipMountedToData? {
val vehicle = passenger.vehicle ?: return null
if (vehicle is ShipMountedToDataProvider) {
return vehicle.provideShipMountedToData(passenger)
}
val shipObjectEntityMountedTo = passenger.level.getShipObjectManagingPos(vehicle.position().toJOML()) ?: return null
val mountedPosInShip: Vector3dc = vehicle.getPosition(partialTicks ?: 0.0f)
.add(0.0, vehicle.passengersRidingOffset + passenger.myRidingOffset, 0.0).toJOML()

return ShipMountedToData(shipObjectEntityMountedTo, mountedPosInShip)
}

fun getShipMountedTo(entity: Entity): LoadedShip? {
return getShipMountedToData(entity)?.shipMountedTo
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package org.valkyrienskies.mod.common.entity

import org.joml.Vector3dc
import org.valkyrienskies.core.api.ships.LoadedShip

data class ShipMountedToData(
val shipMountedTo: LoadedShip,
val mountPosInShip: Vector3dc,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package org.valkyrienskies.mod.common.entity

import net.minecraft.world.entity.Entity

interface ShipMountedToDataProvider {
fun provideShipMountedToData(passenger: Entity): ShipMountedToData?
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import net.minecraft.server.level.ServerPlayer
import net.minecraft.world.entity.Entity
import org.joml.Vector3d
import org.joml.Vector3dc
import org.valkyrienskies.mod.common.getShipObjectEntityMountedTo
import org.valkyrienskies.mod.common.shipObjectWorld
import kotlin.math.asin
import kotlin.math.atan2
Expand All @@ -13,25 +12,23 @@ import kotlin.math.sin

object EntityDragger {
// How much we decay the addedMovement each tick after player hasn't collided with a ship for at least 10 ticks.
private const val addedMovementDecay = 0.9
private const val ADDED_MOVEMENT_DECAY = 0.9

/**
* Drag these entities with the ship they're standing on.
*/
fun dragEntitiesWithShips(entities: Iterable<Entity>) {
entities.forEach { entity ->
val shipMountedTo = entity.level.getShipObjectEntityMountedTo(entity)
// Don't drag entities that are already mounted to a ship
if (shipMountedTo != null) return@forEach

val entityDraggingInformation = (entity as IEntityDraggingInformationProvider).draggingInformation

var dragTheEntity = false
var addedMovement: Vector3dc? = null
var addedYRot = 0.0

val shipDraggingEntity = entityDraggingInformation.lastShipStoodOn
if (shipDraggingEntity != null) {

// Only drag entities that aren't mounted to vehicles
if (shipDraggingEntity != null && entity.vehicle == null) {
if (entityDraggingInformation.isEntityBeingDraggedByAShip()) {
// Compute how much we should drag the entity
val shipData = entity.level.shipObjectWorld.allShips.getById(shipDraggingEntity)
Expand Down Expand Up @@ -87,8 +84,8 @@ object EntityDragger {
} else {
dragTheEntity = true
addedMovement = entityDraggingInformation.addedMovementLastTick
.mul(addedMovementDecay, Vector3d())
addedYRot = entityDraggingInformation.addedYawRotLastTick * addedMovementDecay
.mul(ADDED_MOVEMENT_DECAY, Vector3d())
addedYRot = entityDraggingInformation.addedYawRotLastTick * ADDED_MOVEMENT_DECAY
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,11 @@ package org.valkyrienskies.mod.common.util

import net.minecraft.world.entity.player.Player
import org.joml.Vector3d
import org.joml.Vector3dc
import org.valkyrienskies.core.api.ships.properties.ShipId
import org.valkyrienskies.core.apigame.world.IPlayer
import org.valkyrienskies.core.apigame.world.PlayerState
import org.valkyrienskies.core.apigame.world.properties.DimensionId
import org.valkyrienskies.mod.common.dimensionId
import org.valkyrienskies.mod.common.getPassengerPos
import org.valkyrienskies.mod.common.getShipObjectEntityMountedTo
import org.valkyrienskies.mod.common.getShipMountedToData
import org.valkyrienskies.mod.common.vsCore
import java.lang.ref.WeakReference
import java.util.UUID
Expand Down Expand Up @@ -40,18 +37,13 @@ class MinecraftPlayer(playerObject: Player) : IPlayer {
}

override fun getPlayerState(): PlayerState {
var mountedShip: ShipId? = null
var mountedPos: Vector3dc? = null
player.level.getShipObjectEntityMountedTo(player)?.let {
mountedShip = it.id
mountedPos = player.vehicle!!.getPassengerPos(player.myRidingOffset, 0.0f)
}
val mountedShipAndPos = getShipMountedToData(player)
return PlayerState(
Vector3d(player.x, player.y, player.z),
Vector3d(Vector3d(player.x - player.xo, player.y - player.yo, player.z - player.zo)),
dimension,
mountedShip,
mountedPos,
mountedShipAndPos?.shipMountedTo?.id,
mountedShipAndPos?.mountPosInShip,
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ class ValkyrienSkiesModForge {
val vsCore = if (isClient) {
VSCoreFactory.instance.newVsCoreClient(ForgeHooksImpl)
} else {
org.valkyrienskies.core.apigame.VSCoreFactory.instance.newVsCoreServer(ForgeHooksImpl)
VSCoreFactory.instance.newVsCoreServer(ForgeHooksImpl)
}

VSForgeNetworking.registerPacketHandlers(vsCore.hooks)
Expand Down
Loading