Skip to content

Commit

Permalink
Cache VRPoses and Only Make VRPoseHistory When Needed
Browse files Browse the repository at this point in the history
  • Loading branch information
hammy275 committed Jan 26, 2025
1 parent 128fb78 commit 43e0902
Show file tree
Hide file tree
Showing 11 changed files with 84 additions and 48 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*/
Expand Down
35 changes: 20 additions & 15 deletions common/src/main/java/org/vivecraft/client/ClientVRPlayers.java
Original file line number Diff line number Diff line change
Expand Up @@ -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()}
*/
Expand All @@ -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;
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand Down Expand Up @@ -137,6 +143,7 @@ public VRPoseHistory getHistoricalVRPoses() {
if (!isVRActive()) {
return null;
}
gatherPoseHistory = true;
return this.poseHistory;
}

Expand Down
35 changes: 20 additions & 15 deletions common/src/main/java/org/vivecraft/client_vr/VRData.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion common/src/main/java/org/vivecraft/client_vr/VRState.java
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
10 changes: 5 additions & 5 deletions common/src/main/java/org/vivecraft/server/ServerNetworking.java
Original file line number Diff line number Diff line change
Expand Up @@ -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 -> {
Expand Down Expand Up @@ -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
Expand All @@ -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());
}
Expand Down Expand Up @@ -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);
Expand Down
8 changes: 4 additions & 4 deletions common/src/main/java/org/vivecraft/server/ServerUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -337,21 +337,21 @@ 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());
}
}

if (ServerConfig.DEBUG_PARTICLES_HEAD.get()) {
debugParticleAxes(
vivePlayer.player.serverLevel(),
vivePlayer.getHMDPos(),
vivePlayer.vrPlayerState.hmd().orientation());
vivePlayer.vrPlayerState().hmd().orientation());
}
}
}
Expand Down
18 changes: 16 additions & 2 deletions common/src/main/java/org/vivecraft/server/ServerVivePlayer.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
}
}

0 comments on commit 43e0902

Please sign in to comment.