From 43e0902232ce8bc8234cc17d5c3844bacb2952cc Mon Sep 17 00:00:00 2001 From: hammy275 Date: Sun, 26 Jan 2025 11:16:35 -0500 Subject: [PATCH] Cache VRPoses and Only Make VRPoseHistory When Needed --- .../org/vivecraft/api/client/VRClientAPI.java | 3 +- .../org/vivecraft/client/ClientVRPlayers.java | 35 +++++++++++-------- .../client/api_impl/VRClientAPIImpl.java | 11 ++++-- .../java/org/vivecraft/client_vr/VRData.java | 35 +++++++++++-------- .../java/org/vivecraft/client_vr/VRState.java | 2 +- .../client_vr/gameplay/VRPlayer.java | 6 +++- .../common/network/VrPlayerState.java | 2 +- .../ServerGamePacketListenerImplMixin.java | 2 +- .../vivecraft/server/ServerNetworking.java | 10 +++--- .../java/org/vivecraft/server/ServerUtil.java | 8 ++--- .../vivecraft/server/ServerVivePlayer.java | 18 ++++++++-- 11 files changed, 84 insertions(+), 48 deletions(-) diff --git a/common/src/main/java/org/vivecraft/api/client/VRClientAPI.java b/common/src/main/java/org/vivecraft/api/client/VRClientAPI.java index eaad02b66..9c5e2dc71 100644 --- a/common/src/main/java/org/vivecraft/api/client/VRClientAPI.java +++ b/common/src/main/java/org/vivecraft/api/client/VRClientAPI.java @@ -136,7 +136,8 @@ default void triggerHapticPulse(int controllerNum, float duration) { float getWorldScale(); /** - * Returns the history of VR poses for the player. Will return null if the player isn't in VR. + * Returns the history of VR poses for the player. Must be called at least once by some caller before the pose + * history is populated. * * @return The history of VR poses for the player, or null if the player isn't in VR. */ diff --git a/common/src/main/java/org/vivecraft/client/ClientVRPlayers.java b/common/src/main/java/org/vivecraft/client/ClientVRPlayers.java index fa128a91d..f7b5a3a06 100644 --- a/common/src/main/java/org/vivecraft/client/ClientVRPlayers.java +++ b/common/src/main/java/org/vivecraft/client/ClientVRPlayers.java @@ -546,6 +546,8 @@ public static class RotInfo { public Vector3fc leftElbowPos; public Quaternionfc leftElbowQuat; + private VRPose vrPose; + /** * IMPORTANT!!! when changing this, also change {@link VRData#getBodyYawRad()} */ @@ -570,21 +572,24 @@ public float getBodyYawRad() { } public VRPose asVRPose(Vec3 playerPos) { - return new VRPoseImpl( - makeBodyPartData(this.headPos, this.headRot, this.headQuat, playerPos), - makeBodyPartData(this.mainHandPos, this.mainHandRot, this.mainHandQuat, playerPos), - makeBodyPartData(this.offHandPos, this.offHandRot, this.offHandQuat, playerPos), - makeBodyPartData(this.rightFootPos, this.rightFootQuat, playerPos, this.fbtMode.bodyPartAvailable(VRBodyPart.RIGHT_FOOT)), - makeBodyPartData(this.leftFootPos, this.leftFootQuat, playerPos, this.fbtMode.bodyPartAvailable(VRBodyPart.LEFT_FOOT)), - makeBodyPartData(this.waistPos, this.waistQuat, playerPos, this.fbtMode.bodyPartAvailable(VRBodyPart.WAIST)), - makeBodyPartData(this.rightKneePos, this.rightKneeQuat, playerPos, this.fbtMode.bodyPartAvailable(VRBodyPart.RIGHT_KNEE)), - makeBodyPartData(this.leftKneePos, this.leftKneeQuat, playerPos, this.fbtMode.bodyPartAvailable(VRBodyPart.LEFT_KNEE)), - makeBodyPartData(this.rightElbowPos, this.rightElbowQuat, playerPos, this.fbtMode.bodyPartAvailable(VRBodyPart.RIGHT_ELBOW)), - makeBodyPartData(this.leftElbowPos, this.leftElbowQuat, playerPos, this.fbtMode.bodyPartAvailable(VRBodyPart.LEFT_ELBOW)), - this.seated, - this.leftHanded, - this.fbtMode - ); + if (vrPose == null) { + vrPose = new VRPoseImpl( + makeBodyPartData(this.headPos, this.headRot, this.headQuat, playerPos), + makeBodyPartData(this.mainHandPos, this.mainHandRot, this.mainHandQuat, playerPos), + makeBodyPartData(this.offHandPos, this.offHandRot, this.offHandQuat, playerPos), + makeBodyPartData(this.rightFootPos, this.rightFootQuat, playerPos, this.fbtMode.bodyPartAvailable(VRBodyPart.RIGHT_FOOT)), + makeBodyPartData(this.leftFootPos, this.leftFootQuat, playerPos, this.fbtMode.bodyPartAvailable(VRBodyPart.LEFT_FOOT)), + makeBodyPartData(this.waistPos, this.waistQuat, playerPos, this.fbtMode.bodyPartAvailable(VRBodyPart.WAIST)), + makeBodyPartData(this.rightKneePos, this.rightKneeQuat, playerPos, this.fbtMode.bodyPartAvailable(VRBodyPart.RIGHT_KNEE)), + makeBodyPartData(this.leftKneePos, this.leftKneeQuat, playerPos, this.fbtMode.bodyPartAvailable(VRBodyPart.LEFT_KNEE)), + makeBodyPartData(this.rightElbowPos, this.rightElbowQuat, playerPos, this.fbtMode.bodyPartAvailable(VRBodyPart.RIGHT_ELBOW)), + makeBodyPartData(this.leftElbowPos, this.leftElbowQuat, playerPos, this.fbtMode.bodyPartAvailable(VRBodyPart.LEFT_ELBOW)), + this.seated, + this.leftHanded, + this.fbtMode + ); + } + return vrPose; } } diff --git a/common/src/main/java/org/vivecraft/client/api_impl/VRClientAPIImpl.java b/common/src/main/java/org/vivecraft/client/api_impl/VRClientAPIImpl.java index 4e30112a4..8b7346add 100644 --- a/common/src/main/java/org/vivecraft/client/api_impl/VRClientAPIImpl.java +++ b/common/src/main/java/org/vivecraft/client/api_impl/VRClientAPIImpl.java @@ -17,18 +17,24 @@ public final class VRClientAPIImpl implements VRClientAPI { public static final VRClientAPIImpl INSTANCE = new VRClientAPIImpl(); private final VRPoseHistoryImpl poseHistory = new VRPoseHistoryImpl(); + private boolean gatherPoseHistory = false; private VRClientAPIImpl() { } - public void clearHistories() { + public void clearAndDisablePoseHistory() { this.poseHistory.clear(); + gatherPoseHistory = false; } - public void addPosesToHistory(VRPose pose) { + public void addPoseToHistory(VRPose pose) { this.poseHistory.addPose(pose); } + public boolean gatherPoseHistory() { + return this.gatherPoseHistory; + } + @Nullable @Override public VRPose getLatestRoomPose() { @@ -137,6 +143,7 @@ public VRPoseHistory getHistoricalVRPoses() { if (!isVRActive()) { return null; } + gatherPoseHistory = true; return this.poseHistory; } diff --git a/common/src/main/java/org/vivecraft/client_vr/VRData.java b/common/src/main/java/org/vivecraft/client_vr/VRData.java index 51eceb4f5..94157e8df 100644 --- a/common/src/main/java/org/vivecraft/client_vr/VRData.java +++ b/common/src/main/java/org/vivecraft/client_vr/VRData.java @@ -66,6 +66,8 @@ public class VRData { // pose positions get scaled by that public float worldScale; + private VRPose vrPose; + public VRData(Vec3 origin, float walkMul, float worldScale, float rotation) { ClientDataHolderVR dataHolder = ClientDataHolderVR.getInstance(); MCVR mcVR = dataHolder.vr; @@ -368,21 +370,24 @@ public VRDevicePose getEye(RenderPass pass) { * @return this data in a manner better-suited for the API */ public VRPose asVRPose() { - return new VRPoseImpl( - this.hmd.asVRBodyPart(), - this.c0.asVRBodyPart(), - this.c1.asVRBodyPart(), - getDataIfAvailable(this.foot_right, this.fbtMode.bodyPartAvailable(VRBodyPart.RIGHT_FOOT)), - getDataIfAvailable(this.foot_left, this.fbtMode.bodyPartAvailable(VRBodyPart.LEFT_FOOT)), - getDataIfAvailable(this.waist, this.fbtMode.bodyPartAvailable(VRBodyPart.WAIST)), - getDataIfAvailable(this.knee_right, this.fbtMode.bodyPartAvailable(VRBodyPart.RIGHT_KNEE)), - getDataIfAvailable(this.knee_left, this.fbtMode.bodyPartAvailable(VRBodyPart.LEFT_KNEE)), - getDataIfAvailable(this.elbow_right, this.fbtMode.bodyPartAvailable(VRBodyPart.RIGHT_ELBOW)), - getDataIfAvailable(this.elbow_left, this.fbtMode.bodyPartAvailable(VRBodyPart.LEFT_ELBOW)), - ClientDataHolderVR.getInstance().vrSettings.seated, - ClientDataHolderVR.getInstance().vrSettings.reverseHands, - this.fbtMode - ); + if (vrPose == null) { + vrPose = new VRPoseImpl( + this.hmd.asVRBodyPart(), + this.c0.asVRBodyPart(), + this.c1.asVRBodyPart(), + getDataIfAvailable(this.foot_right, this.fbtMode.bodyPartAvailable(VRBodyPart.RIGHT_FOOT)), + getDataIfAvailable(this.foot_left, this.fbtMode.bodyPartAvailable(VRBodyPart.LEFT_FOOT)), + getDataIfAvailable(this.waist, this.fbtMode.bodyPartAvailable(VRBodyPart.WAIST)), + getDataIfAvailable(this.knee_right, this.fbtMode.bodyPartAvailable(VRBodyPart.RIGHT_KNEE)), + getDataIfAvailable(this.knee_left, this.fbtMode.bodyPartAvailable(VRBodyPart.LEFT_KNEE)), + getDataIfAvailable(this.elbow_right, this.fbtMode.bodyPartAvailable(VRBodyPart.RIGHT_ELBOW)), + getDataIfAvailable(this.elbow_left, this.fbtMode.bodyPartAvailable(VRBodyPart.LEFT_ELBOW)), + ClientDataHolderVR.getInstance().vrSettings.seated, + ClientDataHolderVR.getInstance().vrSettings.reverseHands, + this.fbtMode + ); + } + return vrPose; } @Nullable diff --git a/common/src/main/java/org/vivecraft/client_vr/VRState.java b/common/src/main/java/org/vivecraft/client_vr/VRState.java index 1ced3e55b..f4d1be42b 100644 --- a/common/src/main/java/org/vivecraft/client_vr/VRState.java +++ b/common/src/main/java/org/vivecraft/client_vr/VRState.java @@ -153,6 +153,6 @@ public static void destroyVR(boolean disableVRSetting) { // this reloads any PostChain, at least in vanilla Minecraft.getInstance().levelRenderer.onResourceManagerReload(Minecraft.getInstance().getResourceManager()); } - VRClientAPIImpl.INSTANCE.clearHistories(); + VRClientAPIImpl.INSTANCE.clearAndDisablePoseHistory(); } } diff --git a/common/src/main/java/org/vivecraft/client_vr/gameplay/VRPlayer.java b/common/src/main/java/org/vivecraft/client_vr/gameplay/VRPlayer.java index 12941677f..81cbef30c 100644 --- a/common/src/main/java/org/vivecraft/client_vr/gameplay/VRPlayer.java +++ b/common/src/main/java/org/vivecraft/client_vr/gameplay/VRPlayer.java @@ -237,7 +237,11 @@ public void preTick() { this.dh.vrSettings.worldRotation = this.dh.vr.seatedRot; } - VRClientAPIImpl.INSTANCE.addPosesToHistory(this.vrdata_world_pre.asVRPose()); + // Gather VRPose history if some API consumer wants it and we're in a non-paused world. + if (VRClientAPIImpl.INSTANCE.gatherPoseHistory() && this.mc.level != null && + (this.mc.getSingleplayerServer() == null || !this.mc.getSingleplayerServer().isPaused())) { + VRClientAPIImpl.INSTANCE.addPoseToHistory(this.vrdata_world_pre.asVRPose()); + } } public void postTick() { diff --git a/common/src/main/java/org/vivecraft/common/network/VrPlayerState.java b/common/src/main/java/org/vivecraft/common/network/VrPlayerState.java index 41bfcfc5a..7ff53c9bb 100644 --- a/common/src/main/java/org/vivecraft/common/network/VrPlayerState.java +++ b/common/src/main/java/org/vivecraft/common/network/VrPlayerState.java @@ -244,7 +244,7 @@ public void serialize(FriendlyByteBuf buffer) { * * @return This object as a pose for use with the API. */ - public VRPoseImpl asPose(Vec3 playerPos) { + public VRPoseImpl asVRPose(Vec3 playerPos) { return new VRPoseImpl( this.hmd.asBodyPartData(playerPos), this.mainHand.asBodyPartData(playerPos), diff --git a/common/src/main/java/org/vivecraft/mixin/server/ServerGamePacketListenerImplMixin.java b/common/src/main/java/org/vivecraft/mixin/server/ServerGamePacketListenerImplMixin.java index 7712eba6c..b9731d48e 100644 --- a/common/src/main/java/org/vivecraft/mixin/server/ServerGamePacketListenerImplMixin.java +++ b/common/src/main/java/org/vivecraft/mixin/server/ServerGamePacketListenerImplMixin.java @@ -45,7 +45,7 @@ public ServerGamePacketListenerImplMixin( if (this.player.hasDisconnected()) { // if they did disconnect remove them ServerVRPlayers.getPlayersWithVivecraft(this.player.server).remove(this.player.getUUID()); - } else if (vivePlayer.isVR() && vivePlayer.vrPlayerState != null) { + } else if (vivePlayer.isVR() && vivePlayer.vrPlayerState() != null) { ServerNetworking.sendVrPlayerStateToClients(vivePlayer); if (ServerConfig.DEBUG_PARTICLES.get()) { ServerUtil.debugParticleAxes(vivePlayer); diff --git a/common/src/main/java/org/vivecraft/server/ServerNetworking.java b/common/src/main/java/org/vivecraft/server/ServerNetworking.java index df15bbfb0..5713f54b3 100644 --- a/common/src/main/java/org/vivecraft/server/ServerNetworking.java +++ b/common/src/main/java/org/vivecraft/server/ServerNetworking.java @@ -182,7 +182,7 @@ public static void handlePacket( } } case DRAW -> vivePlayer.draw = ((DrawPayloadC2S) c2sPayload).draw(); - case VR_PLAYER_STATE -> vivePlayer.vrPlayerState = ((VRPlayerStatePayloadC2S) c2sPayload).playerState(); + case VR_PLAYER_STATE -> vivePlayer.setVrPlayerState(((VRPlayerStatePayloadC2S) c2sPayload).playerState()); case WORLDSCALE -> vivePlayer.worldScale = ((WorldScalePayloadC2S) c2sPayload).worldScale(); case HEIGHT -> vivePlayer.heightScale = ((HeightPayloadC2S) c2sPayload).heightScale(); case TELEPORT -> { @@ -239,7 +239,7 @@ public static void handlePacket( LegacyHeadDataPayloadC2S headData = (LegacyHeadDataPayloadC2S) playerData .get(PayloadIdentifier.HEADDATA); - vivePlayer.vrPlayerState = new VrPlayerState( + vivePlayer.setVrPlayerState(new VrPlayerState( headData.seated(), // isSeated headData.hmdPose(), // head pose controller0Data.leftHanded(), // leftHanded 0 @@ -249,7 +249,7 @@ public static void handlePacket( FBTMode.ARMS_ONLY, null, null, null, null, null, - null, null); + null, null)); LEGACY_DATA_MAP.remove(player.getUUID()); } @@ -287,10 +287,10 @@ public static VivecraftPayloadS2C getClimbeyServerPayload() { public static void sendVrPlayerStateToClients(ServerVivePlayer vivePlayer) { // create the packets here, to try to avoid unnecessary memory copies when creating multiple packets Packet legacyPacket = Xplat.getS2CPacket( - new UberPacketPayloadS2C(vivePlayer.player.getUUID(), new VrPlayerState(vivePlayer.vrPlayerState, 0), + new UberPacketPayloadS2C(vivePlayer.player.getUUID(), new VrPlayerState(vivePlayer.vrPlayerState(), 0), vivePlayer.worldScale, vivePlayer.heightScale)); Packet newPacket = Xplat.getS2CPacket( - new UberPacketPayloadS2C(vivePlayer.player.getUUID(), vivePlayer.vrPlayerState, vivePlayer.worldScale, + new UberPacketPayloadS2C(vivePlayer.player.getUUID(), vivePlayer.vrPlayerState(), vivePlayer.worldScale, vivePlayer.heightScale)); sendPacketToTrackingPlayers(vivePlayer, (version) -> version < 1 ? legacyPacket : newPacket); diff --git a/common/src/main/java/org/vivecraft/server/ServerUtil.java b/common/src/main/java/org/vivecraft/server/ServerUtil.java index 3766dbd34..470d1f277 100644 --- a/common/src/main/java/org/vivecraft/server/ServerUtil.java +++ b/common/src/main/java/org/vivecraft/server/ServerUtil.java @@ -337,13 +337,13 @@ public static void registerCommands( * @param vivePlayer vive vivePlayer to spawn particles for */ public static void debugParticleAxes(ServerVivePlayer vivePlayer) { - if (vivePlayer.isVR() && vivePlayer.vrPlayerState != null) { + if (vivePlayer.isVR() && vivePlayer.vrPlayerState() != null) { for(VRBodyPart bodyPart : VRBodyPart.values()) { - if (bodyPart.availableInMode(vivePlayer.vrPlayerState.fbtMode()) && bodyPart != VRBodyPart.HMD) { + if (bodyPart.availableInMode(vivePlayer.vrPlayerState().fbtMode()) && bodyPart != VRBodyPart.HMD) { debugParticleAxes( vivePlayer.player.serverLevel(), vivePlayer.getBodyPartPos(bodyPart), - vivePlayer.vrPlayerState.getBodyPartPose(bodyPart).orientation()); + vivePlayer.vrPlayerState().getBodyPartPose(bodyPart).orientation()); } } @@ -351,7 +351,7 @@ public static void debugParticleAxes(ServerVivePlayer vivePlayer) { debugParticleAxes( vivePlayer.player.serverLevel(), vivePlayer.getHMDPos(), - vivePlayer.vrPlayerState.hmd().orientation()); + vivePlayer.vrPlayerState().hmd().orientation()); } } } diff --git a/common/src/main/java/org/vivecraft/server/ServerVivePlayer.java b/common/src/main/java/org/vivecraft/server/ServerVivePlayer.java index 1f170dc4c..9af64826f 100644 --- a/common/src/main/java/org/vivecraft/server/ServerVivePlayer.java +++ b/common/src/main/java/org/vivecraft/server/ServerVivePlayer.java @@ -16,7 +16,8 @@ public class ServerVivePlayer { // player movement state @Nullable - public VrPlayerState vrPlayerState; + private VrPlayerState vrPlayerState; + private VRPose vrPlayerStateAsPose; // how much the player is drawing the roomscale bow public float draw; public float worldScale = 1.0F; @@ -176,10 +177,23 @@ public boolean isLeftHanded() { return this.vrPlayerState.leftHanded(); } + @Nullable + public VrPlayerState vrPlayerState() { + return this.vrPlayerState; + } + + public void setVrPlayerState(VrPlayerState vrPlayerState) { + this.vrPlayerState = vrPlayerState; + this.vrPlayerStateAsPose = null; + } + public VRPose asVRPose() { if (this.vrPlayerState == null) { return null; } - return this.vrPlayerState.asPose(player.position()); + if (this.vrPlayerStateAsPose == null) { + this.vrPlayerStateAsPose = this.vrPlayerState.asVRPose(player.position()); + } + return this.vrPlayerStateAsPose; } }