diff --git a/common/src/main/java/org/vivecraft/api/VivecraftAPI.java b/common/src/main/java/org/vivecraft/api/VivecraftAPI.java new file mode 100644 index 000000000..7a24f6140 --- /dev/null +++ b/common/src/main/java/org/vivecraft/api/VivecraftAPI.java @@ -0,0 +1,35 @@ +package org.vivecraft.api; + +import net.minecraft.world.entity.player.Player; +import org.vivecraft.api.data.VRData; +import org.vivecraft.common.api_impl.APIImpl; + +import javax.annotation.Nullable; + +public interface VivecraftAPI { + + /** + * @return The Vivecraft API instance for interacting with Vivecraft's API. + */ + static VivecraftAPI getInstance() { + return APIImpl.INSTANCE; + } + + /** + * Check whether a given player is currently in VR. + * + * @param player The player to check the VR status of. + * @return true if the player is in VR. + */ + boolean isVRPlayer(Player player); + + /** + * Returns the VR data for the given player. Will return null if the player isn't in VR, + * or if being called from the client, and the client has yet to receive any data for the player. + * + * @param player Player to get the VR data of. + * @return The VR data for a player, or null if the player isn't in VR or no data has been received for said player. + */ + @Nullable + VRData getVRData(Player player); +} diff --git a/common/src/main/java/org/vivecraft/api/client/Tracker.java b/common/src/main/java/org/vivecraft/api/client/Tracker.java new file mode 100644 index 000000000..525f25d0f --- /dev/null +++ b/common/src/main/java/org/vivecraft/api/client/Tracker.java @@ -0,0 +1,64 @@ +package org.vivecraft.api.client; + +import net.minecraft.client.player.LocalPlayer; +import net.minecraft.world.entity.player.Player; + +/** + * A tracker is an object that is run for the local player during the game tick or before rendering a frame only if + * they are in VR. Using trackers are one of the cleanest ways to interact with Vivecraft's data; it's how Vivecraft + * itself does. Trackers should generally use {@link VivecraftClientAPI#getPreTickWorldData()}, as this provides + * the most up-to-date data, and other methods such as {@link VivecraftClientAPI#getPostTickWorldData()} or + * {@link org.vivecraft.api.VivecraftAPI#getVRData(Player)} may not have data available when the tracker is run. + */ +public interface Tracker { + + /** + * Whether the tracker is active for the local player. + * + * @param player Player being checked if they are active for this tracker instances. + * @return true if the tracker is active for the specified player. + */ + boolean isActive(LocalPlayer player); + + /** + * Called for the client player if this tracker is active, which is when {@link #isActive(LocalPlayer)} returns true. + * + * @param player Player to run this tracker for, which is the local player. + */ + void doProcess(LocalPlayer player); + + /** + * The ticking type for this tracker. + * If this is PER_FRAME, the tracker is called once with the local player per frame before the frame is rendered. + * If this is PER_TICK, the tracker is called once with the local player per game tick during the tick. + * + * @return The ticking type this tracker should use. + */ + TrackerTickType tickType(); + + /** + * Called to reset data for the local player. This is called whenever {@link #isActive(LocalPlayer)} returns false. + * + * @param player The local player, which will have their data reset. + */ + default void reset(LocalPlayer player) { + + } + + /** + * Called for all players, whether the tracker is active or not for them. This runs before + * {@link #isActive(LocalPlayer)} or {@link #reset(LocalPlayer)}. + * + * @param player Player to do an idle tick for, which is the local player. + */ + default void idleTick(LocalPlayer player) { + + } + + /** + * The timing type used for ticking trackers. + */ + enum TrackerTickType { + PER_FRAME, PER_TICK + } +} diff --git a/common/src/main/java/org/vivecraft/api/client/VivecraftClientAPI.java b/common/src/main/java/org/vivecraft/api/client/VivecraftClientAPI.java new file mode 100644 index 000000000..5b05225ab --- /dev/null +++ b/common/src/main/java/org/vivecraft/api/client/VivecraftClientAPI.java @@ -0,0 +1,212 @@ +package org.vivecraft.api.client; + +import com.google.common.annotations.Beta; +import net.minecraft.world.InteractionHand; +import org.vivecraft.api.client.data.VRPoseHistory; +import org.vivecraft.api.data.VRData; +import org.vivecraft.client.api_impl.ClientAPIImpl; +import org.vivecraft.client_vr.render.RenderPass; + +import javax.annotation.Nullable; + +public interface VivecraftClientAPI { + + static VivecraftClientAPI getInstance() { + return ClientAPIImpl.INSTANCE; + } + + /** + * Adds the tracker to the list of all trackers to be run for the local player. See the documentation for + * {@link Tracker} for more information on what a tracker is. + * + * @param tracker Tracker to register. + */ + void addTracker(Tracker tracker); + + /** + * Gets data representing the devices as they exist in the room before the game tick. + * Note that this data is gathered BEFORE mod loaders' pre-tick events. + * + * @return Data representing the devices in the room pre-tick, or null if the local player isn't in VR. + */ + @Nullable + VRData getPreTickRoomData(); + + /** + * Gets data representing the devices as they exist in the room after the game tick. + * Note that this data is gathered AFTER mod loaders' post-tick events. + * + * @return Data representing the devices in the room post-tick, or null if the local player isn't in VR. + */ + @Nullable + VRData getPostTickRoomData(); + + /** + * Gets data representing the devices as they exist in Minecraft coordinates before the game tick. + * This is the same as {@link #getPreTickRoomData()} with translation to Minecraft's coordinates as of the last + * tick, and is the main data source used by Vivecraft. If you're unsure which {@link VRData} method to use, you + * likely want to use this one. + * Note that this data is gathered BEFORE mod loaders' pre-tick events. + * + * @return Data representing the devices in Minecraft space pre-tick, or null if the local player isn't in VR. + */ + @Nullable + VRData getPreTickWorldData(); + + /** + * Gets data representing the devices as they exist in Minecraft coordinates after the game tick. + * This is the data sent to the server, and also used to calculate the data in {@link #getWorldRenderData()}. + * Note that this data is gathered AFTER mod loaders' post-tick events. + * + * @return Data representing the devices in Minecraft space post-tick, or null if the local player isn't in VR. + */ + @Nullable + VRData getPostTickWorldData(); + + /** + * Gets data representing the devices as they exist in Minecraft coordinates after the game tick interpolated for + * rendering. + * This is the same data as {@link #getPostTickWorldData()}, however it is interpolated for rendering. + * + * @return Data representing the devices in Minecraft space post-tick interpolated for rendering, or null if the + * local player isn't in VR. + */ + @Nullable + VRData getWorldRenderData(); + + /** + * Causes a haptic pulse (vibration/rumble) for the specified controller. + * This function silently fails if called for players not in VR or players who are in seated mode. + * + * @param controllerNum The controller number to trigger a haptic pulse. 0 is the primary controller, while 1 is + * the secondary controller. + * @param duration The duration of the haptic pulse in seconds. Note that this number is passed to the + * underlying VR API used by Vivecraft, and may act with a shorter length than expected beyond + * very short pulses. + * @param frequency The frequency of the haptic pulse in Hz. 160 is a safe bet for this number, with Vivecraft's codebase + * using anywhere from 160F for actions such as a bite on a fishing line, to 1000F for things such + * as a chat notification. + * @param amplitude The amplitude of the haptic pulse. This should be kept between 0F and 1F. + * @param delay An amount of time to delay until creating the haptic pulse. The majority of the time, one should use 0F here. + */ + void triggerHapticPulse(int controllerNum, float duration, float frequency, float amplitude, float delay); + + /** + * Causes a haptic pulse (vibration/rumble) for the specified controller. + * This function silently fails if called for players not in VR or players who are in seated mode. + * + * @param controllerNum The controller number to trigger a haptic pulse. 0 is the primary controller, while 1 is + * the secondary controller. + * @param duration The duration of the haptic pulse in seconds. Note that this number is passed to the + * underlying VR API used by Vivecraft, and may act with a shorter length than expected beyond + * very short pulses. + */ + default void triggerHapticPulse(int controllerNum, float duration) { + triggerHapticPulse(controllerNum, duration, 160F, 1F, 0F); + } + + /** + * @return Whether the client player is currently in seated mode. + */ + boolean isSeated(); + + /** + * @return Whether the client player is using reversed hands. + */ + boolean usingReversedHands(); + + /** + * @return Whether VR support is initialized. + */ + boolean isVrInitialized(); + + /** + * @return Whether the client is actively in VR. + */ + boolean isVrActive(); + + /** + * @return The currently active world scale. + */ + float getWorldScale(); + + /** + * Returns the history of VR poses for the player for the HMD. Will return null if the player isn't + * in VR. + * + * @return The historical VR data for the player's HMD, or null if the player isn't in VR. + */ + @Nullable + VRPoseHistory getHistoricalVRHMDPoses(); + + /** + * Returns the history of VR poses for the player for a controller. Will return null if the player isn't + * in VR. + * + * @param controller The controller number to get, with 0 being the primary controller. + * @return The historical VR data for the player's controller, or null if the player isn't in VR. + */ + @Nullable + VRPoseHistory getHistoricalVRControllerPoses(int controller); + + /** + * Returns the history of VR poses for the player for a controller. Will return null if the player isn't + * in VR. + * + * @param hand The hand to get controller history for. + * @return The historical VR data for the player's controller, or null if the player isn't in VR. + */ + @Nullable + default VRPoseHistory getHistoricalVRControllerPoses(InteractionHand hand) { + return getHistoricalVRControllerPoses(hand.ordinal()); + } + + /** + * Returns the history of VR poses for the player for the primary controller. Will return null if the + * player isn't in VR. + * + * @return The historical VR data for the player's primary controller, or null if the player isn't in VR. + */ + @Nullable + default VRPoseHistory getHistoricalVRController0Poses() { + return getHistoricalVRControllerPoses(0); + } + + /** + * Returns the history of VR poses for the player for the secondary controller. Will return null if the + * player isn't in VR. + * + * @return The historical VR data for the player's secondary controller, or null if the player isn't in VR. + */ + @Nullable + default VRPoseHistory getHistoricalVRController1Poses() { + return getHistoricalVRControllerPoses(1); + } + + /** + * Opens or closes Vivecraft's keyboard. Will fail silently if the user isn't in VR or if the keyboard's new state + * is the same as the old. + * + * @param isNowOpen Whether the keyboard should now be open. If false, the keyboard will attempt to close. + * @return Whether the keyboard is currently showing after attempting to open/close it. + */ + boolean setKeyboardState(boolean isNowOpen); + + /** + * @return Whether the current render pass is a vanilla render pass. + */ + @Beta + boolean isVanillaRenderPass(); + + /** + * @return The current render pass Vivecraft is performing. + */ + @Beta + RenderPass getCurrentRenderPass(); + + /** + * @return Whether the current render pass is the first one it performed for this render cycle. + */ + @Beta + boolean isFirstRenderPass(); +} diff --git a/common/src/main/java/org/vivecraft/api/client/data/VRPoseHistory.java b/common/src/main/java/org/vivecraft/api/client/data/VRPoseHistory.java new file mode 100644 index 000000000..b0a50549c --- /dev/null +++ b/common/src/main/java/org/vivecraft/api/client/data/VRPoseHistory.java @@ -0,0 +1,95 @@ +package org.vivecraft.api.client.data; + +import net.minecraft.world.phys.Vec3; +import org.vivecraft.api.data.VRPose; + +import java.util.List; + +/** + * Represents historical VRData associated with a player. + */ +public interface VRPoseHistory { + + /** + * The maximum amount of ticks back data is held for. + * It is only guaranteed that historical data does not go beyond this number of ticks back. Functions do not + * guarantee that they will reference this many ticks, as, for example, this amount of ticks may not have gone + * by for the player this history represents. + * Passing a value larger than this number to any methods below in their maxTicksBack or ticksBack parameters + * will throw an {@link IllegalArgumentException}. + */ + int MAX_TICKS_BACK = 20; + + /** + * @return The amount of ticks worth of history being held. The number returned by this methodwill never be higher + * than {@link VRPoseHistory#MAX_TICKS_BACK}, however can be lower than it. + */ + int ticksOfHistory(); + + /** + * Gets a raw list of {@link VRPose} instances, with index 0 representing the least recent pose known. + * + * @return The aforementioned list of {@link VRPose} instances. + */ + List getAllHistoricalData() throws IllegalArgumentException; + + /** + * Gets the historical data ticksBack ticks back. This will throw an IllegalStateException if the data cannot + * be retrieved due to not having enough history. + * + * @param ticksBack Ticks back to retrieve data. + * @return A {@link VRPose} instance from index ticks ago. + * @throws IllegalStateException If ticksBack references a tick that there is not yet data for. + * @throws IllegalArgumentException Thrown when maxTicksBack is larger than {@value #MAX_TICKS_BACK} or less than 0. + */ + VRPose getHistoricalData(int ticksBack) throws IllegalArgumentException, IllegalStateException; + + /** + * Gets the net movement between the most recent data in this instance and the oldest position that can be + * retrieved, going no farther back than maxTicksBack. + * + * @param maxTicksBack The maximum amount of ticks back to compare the most recent data with. + * @return The aforementioned net movement. Note that this will return zero change on all axes if only zero ticks + * can be looked back. + * @throws IllegalArgumentException Thrown when maxTicksBack is larger than {@value #MAX_TICKS_BACK} or less than 0. + */ + Vec3 netMovement(int maxTicksBack) throws IllegalArgumentException; + + /** + * Gets the average velocity in blocks/tick between the most recent data in this instance and the oldest position + * that can be retrieved, going no farther back than maxTicksBack. + * + * @param maxTicksBack The maximum amount of ticks back to calculate velocity with. + * @return The aforementioned average velocity on each axis. Note that this will return zero velocity on all axes + * if only zero ticks can be looked back. + * @throws IllegalArgumentException Thrown when maxTicksBack is larger than {@value #MAX_TICKS_BACK} or less than 0. + */ + Vec3 averageVelocity(int maxTicksBack) throws IllegalArgumentException; + + /** + * Gets the average speed in blocks/tick between the most recent data in this instance and the oldest position + * that can be retrieved, going no farther back than maxTicksBack. + * + * @param maxTicksBack The maximum amount of ticks back to calculate speed with. + * @return The aforementioned average speed on each axis. Note that this will return zero speed if only zero ticks + * can be looked back. + * @throws IllegalArgumentException Thrown when maxTicksBack is larger than {@value #MAX_TICKS_BACK} or less than 0. + */ + default double averageSpeed(int maxTicksBack) throws IllegalArgumentException { + Vec3 averageVelocity = averageVelocity(maxTicksBack); + return Math.sqrt(averageVelocity.x() * averageVelocity.x() + + averageVelocity.y() * averageVelocity.y() + + averageVelocity.z() * averageVelocity.z()); + } + + /** + * Gets the average position between the most recent data in this instance and the oldest position that can be + * retrieved, going no farther back than maxTicksBack. + * + * @param maxTicksBack The maximum amount of ticks back to calculate velocity with. + * @return The aforementioned average position. Note that this will return the current position if only zero ticks + * can be looked back. + * @throws IllegalArgumentException Thrown when maxTicksBack is larger than {@value #MAX_TICKS_BACK} or less than 0. + */ + Vec3 averagePosition(int maxTicksBack) throws IllegalArgumentException; +} diff --git a/common/src/main/java/org/vivecraft/api/data/VRData.java b/common/src/main/java/org/vivecraft/api/data/VRData.java new file mode 100644 index 000000000..124eabb8e --- /dev/null +++ b/common/src/main/java/org/vivecraft/api/data/VRData.java @@ -0,0 +1,63 @@ +package org.vivecraft.api.data; + +import com.google.common.annotations.Beta; +import net.minecraft.world.InteractionHand; + +/** + * Represents all VR data associated with a given player, mainly the pose of the HMD and both controllers + * of the player. If the player is in seated mode, controller 1 carries the HMD's data, and controller 0 is + * based on the direction being looked at via the mouse pointer. + */ +public interface VRData { + + /** + * @return Pose data for the HMD. + */ + VRPose getHMD(); + + /** + * Gets the pose data for a given controller. + * + * @param controller The controller number to get, with 0 being the primary controller. + * @return The specified controller's pose data. + */ + VRPose getController(int controller); + + /** + * @return Whether the player is currently in seated mode. + */ + boolean isSeated(); + + /** + * @return Whether the player is using reversed hands. + */ + boolean usingReversedHands(); + + /** + * Gets the pose for a given controller. + * + * @param hand The interaction hand to get controller data for. + * @return The specified controller's pose data. + */ + default VRPose getController(InteractionHand hand) { + return getController(hand.ordinal()); + } + + /** + * Gets the pose for the primary controller. + * + * @return The main controller's pose data. + */ + default VRPose getController0() { + return getController(0); + } + + /** + * Gets the pose for the secondary controller. + * + * @return The main controller's pose data. + */ + default VRPose getController1() { + return getController(1); + } +} diff --git a/common/src/main/java/org/vivecraft/api/data/VRPose.java b/common/src/main/java/org/vivecraft/api/data/VRPose.java new file mode 100644 index 000000000..176827aaa --- /dev/null +++ b/common/src/main/java/org/vivecraft/api/data/VRPose.java @@ -0,0 +1,42 @@ +package org.vivecraft.api.data; + +import net.minecraft.world.phys.Vec3; +import org.joml.Quaternionf; +import org.joml.Quaternionfc; + +/** + * Represents the pose data, such as position and rotation, for a given trackable object, such as the HMD or + * a controller. + */ +public interface VRPose { + + /** + * @return The position of the device in Minecraft world coordinates. + */ + Vec3 getPos(); + + /** + * @return The rotation of the device. + */ + Vec3 getRot(); + + /** + * @return The pitch of the device in radians. + */ + double getPitch(); + + /** + * @return The yaw of the device in radians. + */ + double getYaw(); + + /** + * @return The roll of the device in radians. + */ + double getRoll(); + + /** + * @return The quaternion representing the rotation of the device. + */ + Quaternionfc getQuaternion(); +} diff --git a/common/src/main/java/org/vivecraft/api_beta/VivecraftAPI.java b/common/src/main/java/org/vivecraft/api_beta/VivecraftAPI.java deleted file mode 100644 index a95a3b0b8..000000000 --- a/common/src/main/java/org/vivecraft/api_beta/VivecraftAPI.java +++ /dev/null @@ -1,16 +0,0 @@ -package org.vivecraft.api_beta; - -import com.google.common.annotations.Beta; -import net.minecraft.world.entity.player.Player; -import org.vivecraft.common.APIImpl; - -@Beta -public interface VivecraftAPI { - - static VivecraftAPI getInstance() { - return APIImpl.INSTANCE; - } - - @Beta - boolean isVRPlayer(Player player); -} diff --git a/common/src/main/java/org/vivecraft/api_beta/client/VivecraftClientAPI.java b/common/src/main/java/org/vivecraft/api_beta/client/VivecraftClientAPI.java deleted file mode 100644 index ff629beb4..000000000 --- a/common/src/main/java/org/vivecraft/api_beta/client/VivecraftClientAPI.java +++ /dev/null @@ -1,18 +0,0 @@ -package org.vivecraft.api_beta.client; - -import com.google.common.annotations.Beta; -import org.vivecraft.client.ClientAPIImpl; - -public interface VivecraftClientAPI { - - static VivecraftClientAPI getInstance() { - return ClientAPIImpl.INSTANCE; - } - - boolean isVrInitialized(); - - boolean isVrActive(); - - @Beta - boolean isVanillaRenderPass(); -} diff --git a/common/src/main/java/org/vivecraft/client/ClientAPIImpl.java b/common/src/main/java/org/vivecraft/client/ClientAPIImpl.java deleted file mode 100644 index 27fdbd721..000000000 --- a/common/src/main/java/org/vivecraft/client/ClientAPIImpl.java +++ /dev/null @@ -1,27 +0,0 @@ -package org.vivecraft.client; - -import org.vivecraft.api_beta.client.VivecraftClientAPI; -import org.vivecraft.client_vr.VRState; -import org.vivecraft.client_xr.render_pass.RenderPassType; - -public final class ClientAPIImpl implements VivecraftClientAPI { - - public static final ClientAPIImpl INSTANCE = new ClientAPIImpl(); - - private ClientAPIImpl() {} - - @Override - public boolean isVrInitialized() { - return VRState.VR_INITIALIZED; - } - - @Override - public boolean isVrActive() { - return VRState.VR_RUNNING; - } - - @Override - public boolean isVanillaRenderPass() { - return RenderPassType.isVanilla(); - } -} diff --git a/common/src/main/java/org/vivecraft/client/VRPlayersClient.java b/common/src/main/java/org/vivecraft/client/VRPlayersClient.java index e4e3fc08b..222bc49d8 100644 --- a/common/src/main/java/org/vivecraft/client/VRPlayersClient.java +++ b/common/src/main/java/org/vivecraft/client/VRPlayersClient.java @@ -15,6 +15,8 @@ import org.vivecraft.common.utils.MathUtils; import org.vivecraft.client_vr.ClientDataHolderVR; import org.vivecraft.client_vr.VRData; +import org.vivecraft.common.api_impl.data.VRDataImpl; +import org.vivecraft.common.api_impl.data.VRPoseImpl; import org.vivecraft.common.network.VrPlayerState; import java.util.*; @@ -296,5 +298,25 @@ public float getBodyYawRad() { diff.lerp(this.headRot, 0.5F, diff); return (float) Math.atan2(-diff.x, diff.z); } + + public org.vivecraft.api.data.VRData asVRData(Vec3 playerPos) { + // Have to add the player's position here, as the RotInfo positions are player relative, rather + // than the in-world position. + return new VRDataImpl( + new VRPoseImpl(addVec3AndVector3f(this.headPos, playerPos), ofVector3fc(this.headRot), this.headQuat), + new VRPoseImpl(addVec3AndVector3f(this.rightArmPos, playerPos), ofVector3fc(this.rightArmRot), this.rightArmQuat), + new VRPoseImpl(addVec3AndVector3f(this.leftArmPos, playerPos), ofVector3fc(this.leftArmRot), this.leftArmQuat), + this.seated, + this.reverse + ); + } + + private Vec3 addVec3AndVector3f(Vector3fc a, Vec3 b) { + return new Vec3(a.x() + b.x(), a.y() + b.y(), a.z() + b.z()); + } + + private Vec3 ofVector3fc(Vector3fc vec) { + return new Vec3(vec.x(), vec.y(), vec.z()); + } } } diff --git a/common/src/main/java/org/vivecraft/client/api_impl/ClientAPIImpl.java b/common/src/main/java/org/vivecraft/client/api_impl/ClientAPIImpl.java new file mode 100644 index 000000000..96f1e4538 --- /dev/null +++ b/common/src/main/java/org/vivecraft/client/api_impl/ClientAPIImpl.java @@ -0,0 +1,180 @@ +package org.vivecraft.client.api_impl; + +import org.jetbrains.annotations.Nullable; +import org.vivecraft.api.client.Tracker; +import org.vivecraft.api.client.data.VRPoseHistory; +import org.vivecraft.api.client.VivecraftClientAPI; +import org.vivecraft.api.data.VRData; +import org.vivecraft.client.api_impl.data.VRPoseHistoryImpl; +import org.vivecraft.client_vr.ClientDataHolderVR; +import org.vivecraft.client_vr.VRState; +import org.vivecraft.client_vr.gameplay.screenhandlers.KeyboardHandler; +import org.vivecraft.client_vr.provider.ControllerType; +import org.vivecraft.client_vr.render.RenderPass; +import org.vivecraft.client_vr.settings.VRSettings; +import org.vivecraft.client_xr.render_pass.RenderPassType; + +public final class ClientAPIImpl implements VivecraftClientAPI { + + public static final ClientAPIImpl INSTANCE = new ClientAPIImpl(); + + private final VRPoseHistoryImpl hmdHistory = new VRPoseHistoryImpl(); + private VRPoseHistoryImpl c0History = new VRPoseHistoryImpl(); + private VRPoseHistoryImpl c1History = new VRPoseHistoryImpl(); + + private ClientAPIImpl() { + } + + public void clearHistories() { + this.hmdHistory.clear(); + this.c0History.clear(); + this.c1History.clear(); + } + + public void addPosesToHistory(VRData data) { + this.hmdHistory.addPose(data.getHMD()); + this.c0History.addPose(data.getController0()); + this.c1History.addPose(data.getController1()); + } + + @Nullable + @Override + public VRData getPreTickRoomData() { + if (!isVrActive()) { + return null; + } + return ClientDataHolderVR.getInstance().vrPlayer.vrdata_room_pre.asVRData(); + } + + @Nullable + @Override + public VRData getPostTickRoomData() { + if (!isVrActive()) { + return null; + } + return ClientDataHolderVR.getInstance().vrPlayer.vrdata_room_post.asVRData(); + } + + @Nullable + @Override + public VRData getPreTickWorldData() { + if (!isVrActive()) { + return null; + } + return ClientDataHolderVR.getInstance().vrPlayer.vrdata_world_pre.asVRData(); + } + + @Nullable + @Override + public VRData getPostTickWorldData() { + if (!isVrActive()) { + return null; + } + return ClientDataHolderVR.getInstance().vrPlayer.vrdata_world_post.asVRData(); + } + + @Nullable + @Override + public VRData getWorldRenderData() { + if (!isVrActive()) { + return null; + } + return ClientDataHolderVR.getInstance().vrPlayer.vrdata_world_render.asVRData(); + } + + @Override + public void triggerHapticPulse(int controllerNum, float duration, float frequency, float amplitude, float delay) { + if (controllerNum != 0 && controllerNum != 1) { + throw new IllegalArgumentException("Can only trigger a haptic pulse for controllers 0 and 1."); + } + if (amplitude < 0F || amplitude > 1F) { + throw new IllegalArgumentException("The amplitude of a haptic pulse must be between 0 and 1."); + } + if (isVrActive() && !isSeated()) { + ClientDataHolderVR.getInstance().vr.triggerHapticPulse( + ControllerType.values()[controllerNum], + duration, + frequency, + amplitude, + delay + ); + } + } + + @Override + public boolean isSeated() { + return ClientDataHolderVR.getInstance().vrSettings.seated; + } + + @Override + public boolean usingReversedHands() { + return ClientDataHolderVR.getInstance().vrSettings.reverseHands; + } + + @Override + public boolean isVrInitialized() { + return VRState.VR_INITIALIZED; + } + + @Override + public boolean isVrActive() { + return VRState.VR_RUNNING; + } + + @Override + public float getWorldScale() { + if (isVrActive()) { + return ClientDataHolderVR.getInstance().vrPlayer.worldScale; + } else { + return 1f; + } + } + + @Override + public void addTracker(Tracker tracker) { + ClientDataHolderVR.getInstance().addTracker(tracker); + } + + @Nullable + @Override + public VRPoseHistory getHistoricalVRHMDPoses() { + if (!isVrActive()) { + return null; + } + return this.hmdHistory; + } + + @Nullable + @Override + public VRPoseHistory getHistoricalVRControllerPoses(int controller) { + if (controller != 0 && controller != 1) { + throw new IllegalArgumentException("Historical VR controller data only available for controllers 0 and 1."); + } else if (!isVrActive()) { + return null; + } + return controller == 0 ? this.c0History : this.c1History; + } + + @Override + public boolean setKeyboardState(boolean isNowOpen) { + if (isVrActive()) { + return KeyboardHandler.setOverlayShowing(isNowOpen); + } + return false; + } + + @Override + public boolean isVanillaRenderPass() { + return RenderPassType.isVanilla(); + } + + @Override + public RenderPass getCurrentRenderPass() { + return ClientDataHolderVR.getInstance().currentPass; + } + + @Override + public boolean isFirstRenderPass() { + return ClientDataHolderVR.getInstance().isFirstPass; + } +} diff --git a/common/src/main/java/org/vivecraft/client/api_impl/data/VRPoseHistoryImpl.java b/common/src/main/java/org/vivecraft/client/api_impl/data/VRPoseHistoryImpl.java new file mode 100644 index 000000000..3058a06cd --- /dev/null +++ b/common/src/main/java/org/vivecraft/client/api_impl/data/VRPoseHistoryImpl.java @@ -0,0 +1,104 @@ +package org.vivecraft.client.api_impl.data; + +import net.minecraft.world.phys.Vec3; +import org.vivecraft.api.client.data.VRPoseHistory; +import org.vivecraft.api.data.VRPose; + +import java.util.*; + +public class VRPoseHistoryImpl implements VRPoseHistory { + + private final LinkedList dataQueue = new LinkedList<>(); + + public VRPoseHistoryImpl() { + } + + public void addPose(VRPose pose) { + this.dataQueue.addFirst(pose); + if (this.dataQueue.size() > VRPoseHistory.MAX_TICKS_BACK) { + this.dataQueue.removeLast(); + } + } + + public void clear() { + this.dataQueue.clear(); + } + + @Override + public int ticksOfHistory() { + return this.dataQueue.size(); + } + + @Override + public List getAllHistoricalData() { + return new ArrayList<>(this.dataQueue); + } + + @Override + public VRPose getHistoricalData(int ticksBack) throws IllegalArgumentException, IllegalStateException { + checkTicksBack(ticksBack); + if (this.dataQueue.size() <= ticksBack) { + throw new IllegalStateException("Cannot retrieve data from " + ticksBack + " ticks ago, when there is " + + "only data for up to " + (this.dataQueue.size() - 1) + " ticks ago."); + } + return this.dataQueue.get(ticksBack); + } + + @Override + public Vec3 netMovement(int maxTicksBack) throws IllegalArgumentException { + checkTicksBack(maxTicksBack); + Vec3 current = this.dataQueue.getLast().getPos(); + Vec3 old = getOldPose(maxTicksBack).getPos(); + return current.subtract(old); + } + + @Override + public Vec3 averageVelocity(int maxTicksBack) throws IllegalArgumentException { + checkTicksBack(maxTicksBack); + Vec3 current = this.dataQueue.getLast().getPos(); + Vec3 old = getOldPose(maxTicksBack).getPos(); + return current.subtract(old).scale(1d / getNumTicksBack(maxTicksBack)); + } + + @Override + public Vec3 averagePosition(int maxTicksBack) throws IllegalArgumentException { + checkTicksBack(maxTicksBack); + int iters = getNumTicksBack(maxTicksBack); + ListIterator iterator = this.dataQueue.listIterator(this.dataQueue.size() - 1); + Vec3 avg = this.dataQueue.getLast().getPos(); + int i = iters; + while (i > 0) { + avg = avg.add(iterator.previous().getPos()); + i--; + } + return avg.scale(1d / (iters + 1)); + } + + private void checkTicksBack(int ticksBack) { + if (ticksBack < 0 || ticksBack > VRPoseHistory.MAX_TICKS_BACK) { + throw new IllegalArgumentException("Value must be between 0 and " + VRPoseHistory.MAX_TICKS_BACK + "."); + } + } + + private VRPose getOldPose(int maxTicksBack) { + if (this.dataQueue.size() <= maxTicksBack) { + return this.dataQueue.getFirst(); + } else { + return this.dataQueue.get(this.dataQueue.size() - maxTicksBack - 1); + } + } + + /** + * Converts maxTicksBack to the actual maximum number of ticks we can go back. + * + * @param maxTicksBack The maximum number of ticks to attempt to go back. + * @return The actual number of ticks to go back by. + */ + private int getNumTicksBack(int maxTicksBack) { + if (this.dataQueue.size() <= maxTicksBack) { + return this.dataQueue.size() - 1; + } else { + return maxTicksBack; + } + } +} diff --git a/common/src/main/java/org/vivecraft/client_vr/ClientDataHolderVR.java b/common/src/main/java/org/vivecraft/client_vr/ClientDataHolderVR.java index 31b98a348..368895b6f 100644 --- a/common/src/main/java/org/vivecraft/client_vr/ClientDataHolderVR.java +++ b/common/src/main/java/org/vivecraft/client_vr/ClientDataHolderVR.java @@ -2,6 +2,7 @@ import net.minecraft.client.Minecraft; import net.minecraft.client.resources.model.ModelResourceLocation; +import org.vivecraft.api.client.Tracker; import org.vivecraft.client_vr.gameplay.VRPlayer; import org.vivecraft.client_vr.gameplay.trackers.*; import org.vivecraft.client_vr.menuworlds.MenuWorldRenderer; @@ -11,6 +12,9 @@ import org.vivecraft.client_vr.render.VRFirstPersonArmSwing; import org.vivecraft.client_vr.settings.VRSettings; +import java.util.ArrayList; +import java.util.List; + public class ClientDataHolderVR { public static final ModelResourceLocation THIRD_PERSON_CAMERA_MODEL = new ModelResourceLocation("vivecraft", "camcorder", ""); @@ -64,10 +68,42 @@ public class ClientDataHolderVR { public boolean showedUpdateNotification; public boolean showedStencilMessage; + // List of registered trackers + ArrayList trackers = new ArrayList<>(); + + private ClientDataHolderVR() { + addTracker(backpackTracker); + addTracker(bowTracker); + addTracker(swingTracker); + addTracker(autoFood); + addTracker(jumpTracker); + addTracker(sneakTracker); + addTracker(climbTracker); + addTracker(runTracker); + addTracker(rowTracker); + addTracker(teleportTracker); + addTracker(horseTracker); + addTracker(vehicleTracker); + addTracker(interactTracker); + addTracker(crawlTracker); + addTracker(cameraTracker); + } + public static ClientDataHolderVR getInstance() { if (INSTANCE == null) { INSTANCE = new ClientDataHolderVR(); } return INSTANCE; } + + public void addTracker(Tracker tracker) { + if (trackers.contains(tracker)) { + throw new IllegalArgumentException("Tracker is already added and should not be added again!"); + } + trackers.add(tracker); + } + + public List getTrackers() { + return this.trackers; + } } 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 f90b37a08..5beab16d1 100644 --- a/common/src/main/java/org/vivecraft/client_vr/VRData.java +++ b/common/src/main/java/org/vivecraft/client_vr/VRData.java @@ -9,6 +9,10 @@ import org.vivecraft.client_vr.settings.VRSettings; import java.lang.Math; +import org.joml.Quaternionf; +import org.vivecraft.api.data.VRPose; +import org.vivecraft.common.api_impl.data.VRDataImpl; +import org.vivecraft.common.api_impl.data.VRPoseImpl; public class VRData { // headset center @@ -272,6 +276,19 @@ public VRDevicePose getEye(RenderPass pass) { }; } + /** + * @return this data in a manner better-suited for the API + */ + public org.vivecraft.api.data.VRData asVRData() { + return new VRDataImpl( + this.hmd.asVRPose(), + this.c0.asVRPose(), + this.c1.asVRPose(), + ClientDataHolderVR.getInstance().vrSettings.seated, + ClientDataHolderVR.getInstance().vrSettings.reverseHands + ); + } + @Override public String toString() { return """ @@ -413,6 +430,16 @@ public Matrix4f getMatrix() { return new Matrix4f().rotationY(VRData.this.rotation_radians).mul(this.matrix); } + public VRPose asVRPose() { + Quaternionf quat = new Quaternionf(); + quat.setFromUnnormalized(getMatrix()); + return new VRPoseImpl( + getPosition(), + new Vec3(getDirection()), + quat + ); + } + @Override public String toString() { return "Device: pos:" + this.getPosition() + ", dir: " + this.getDirection(); 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 bdf1df0bb..9083c1c70 100644 --- a/common/src/main/java/org/vivecraft/client_vr/VRState.java +++ b/common/src/main/java/org/vivecraft/client_vr/VRState.java @@ -8,6 +8,7 @@ import org.vivecraft.client.gui.screens.GarbageCollectorScreen; import org.vivecraft.client.utils.TextUtils; import org.vivecraft.client_vr.gameplay.VRPlayer; +import org.vivecraft.client.api_impl.ClientAPIImpl; import org.vivecraft.client_vr.menuworlds.MenuWorldRenderer; import org.vivecraft.client_vr.provider.nullvr.NullVR; import org.vivecraft.client_vr.provider.openvr_lwjgl.MCOpenVR; @@ -69,22 +70,6 @@ public static void initializeVR() { RenderPassManager.setVanillaRenderPass(); dh.vrPlayer = new VRPlayer(); - dh.vrPlayer.registerTracker(dh.backpackTracker); - dh.vrPlayer.registerTracker(dh.bowTracker); - dh.vrPlayer.registerTracker(dh.climbTracker); - dh.vrPlayer.registerTracker(dh.autoFood); - dh.vrPlayer.registerTracker(dh.jumpTracker); - dh.vrPlayer.registerTracker(dh.rowTracker); - dh.vrPlayer.registerTracker(dh.runTracker); - dh.vrPlayer.registerTracker(dh.sneakTracker); - dh.vrPlayer.registerTracker(dh.swimTracker); - dh.vrPlayer.registerTracker(dh.swingTracker); - dh.vrPlayer.registerTracker(dh.interactTracker); - dh.vrPlayer.registerTracker(dh.teleportTracker); - dh.vrPlayer.registerTracker(dh.horseTracker); - dh.vrPlayer.registerTracker(dh.vehicleTracker); - dh.vrPlayer.registerTracker(dh.crawlTracker); - dh.vrPlayer.registerTracker(dh.cameraTracker); dh.menuWorldRenderer = new MenuWorldRenderer(); @@ -155,5 +140,6 @@ public static void destroyVR(boolean disableVRSetting) { if (Xplat.isModLoaded("distanthorizons") && disableVRSetting) { ShadersHelper.maybeReloadShaders(); } + ClientAPIImpl.INSTANCE.clearHistories(); } } 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 ed347aa28..03da981bb 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 @@ -23,11 +23,14 @@ import net.minecraft.world.phys.Vec3; import org.joml.Vector3f; import org.joml.Vector3fc; +import org.vivecraft.api.client.Tracker; import org.vivecraft.client.VivecraftVRMod; +import org.vivecraft.client.api_impl.ClientAPIImpl; +import org.vivecraft.client_vr.ClientDataHolderVR; +import org.vivecraft.common.VRServerPerms; import org.vivecraft.client.network.ClientNetworking; import org.vivecraft.common.utils.MathUtils; import org.vivecraft.client.utils.ScaleHelper; -import org.vivecraft.client_vr.ClientDataHolderVR; import org.vivecraft.client_vr.ItemTags; import org.vivecraft.client_vr.MethodHolder; import org.vivecraft.client_vr.VRData; @@ -36,13 +39,9 @@ import org.vivecraft.client_vr.gameplay.screenhandlers.GuiHandler; import org.vivecraft.client_vr.gameplay.screenhandlers.KeyboardHandler; import org.vivecraft.client_vr.gameplay.screenhandlers.RadialHandler; -import org.vivecraft.client_vr.gameplay.trackers.Tracker; import org.vivecraft.client_vr.gameplay.trackers.VehicleTracker; import org.vivecraft.client_vr.render.RenderPass; import org.vivecraft.client_vr.settings.VRSettings; -import org.vivecraft.common.VRServerPerms; - -import java.util.ArrayList; public class VRPlayer { private final Minecraft mc = Minecraft.getInstance(); @@ -61,8 +60,6 @@ public class VRPlayer { public VRData vrdata_world_post; // interpolate here between post and pre public VRData vrdata_world_render; - - private final ArrayList trackers = new ArrayList<>(); public float worldScale = this.dh.vrSettings.overrides.getSetting(VRSettings.VrOptions.WORLD_SCALE).getFloat(); private float rawWorldScale = this.dh.vrSettings.overrides.getSetting(VRSettings.VrOptions.WORLD_SCALE).getFloat(); private boolean teleportOverride = false; @@ -82,10 +79,6 @@ public class VRPlayer { private boolean initDone = false; public boolean onTick; - public void registerTracker(Tracker tracker) { - this.trackers.add(tracker); - } - public VRPlayer() { this.vrdata_room_pre = new VRData( Vec3.ZERO, @@ -226,6 +219,8 @@ public void preTick() { if (this.dh.vrSettings.seated && !MethodHolder.isInMenuRoom()) { this.dh.vrSettings.worldRotation = this.dh.vr.seatedRot; } + + ClientAPIImpl.INSTANCE.addPosesToHistory(this.vrdata_world_pre.asVRData()); } public void postTick() { @@ -288,11 +283,11 @@ public void preRender(float partialTick) { interpolatedWorldScale, interpolatedWorldRotation_Radians); - // handle special items - for (Tracker tracker : this.trackers) { - if (tracker.getEntryPoint() == Tracker.EntryPoint.SPECIAL_ITEMS) { + for (Tracker tracker : ClientDataHolderVR.getInstance().getTrackers()) + { + if (tracker.tickType() == Tracker.TrackerTickType.PER_FRAME) + { tracker.idleTick(this.mc.player); - if (tracker.isActive(this.mc.player)) { tracker.doProcess(this.mc.player); } else { @@ -381,11 +376,11 @@ public void tick(LocalPlayer player, Minecraft mc) { } this.doPlayerMoveInRoom(player); - - for (Tracker tracker : this.trackers) { - if (tracker.getEntryPoint() == Tracker.EntryPoint.LIVING_UPDATE) { + for (Tracker tracker : dh.getTrackers()) + { + if (tracker.tickType() == Tracker.TrackerTickType.PER_TICK) + { tracker.idleTick(mc.player); - if (tracker.isActive(mc.player)) { tracker.doProcess(mc.player); } else { diff --git a/common/src/main/java/org/vivecraft/client_vr/gameplay/trackers/BackpackTracker.java b/common/src/main/java/org/vivecraft/client_vr/gameplay/trackers/BackpackTracker.java index 03cbb5a4a..bde3cb448 100644 --- a/common/src/main/java/org/vivecraft/client_vr/gameplay/trackers/BackpackTracker.java +++ b/common/src/main/java/org/vivecraft/client_vr/gameplay/trackers/BackpackTracker.java @@ -1,5 +1,9 @@ package org.vivecraft.client_vr.gameplay.trackers; +import org.vivecraft.api.client.Tracker; +import org.vivecraft.client_vr.ClientDataHolderVR; +import org.vivecraft.client_vr.gameplay.VRPlayer; + import net.minecraft.client.Minecraft; import net.minecraft.client.player.LocalPlayer; import net.minecraft.core.BlockPos; @@ -8,15 +12,16 @@ import net.minecraft.world.phys.Vec3; import org.joml.Vector3f; import org.vivecraft.common.utils.MathUtils; -import org.vivecraft.client_vr.ClientDataHolderVR; -import org.vivecraft.client_vr.gameplay.VRPlayer; -public class BackpackTracker extends Tracker { +public class BackpackTracker implements Tracker { public boolean[] wasIn = new boolean[2]; public int previousSlot = 0; + protected Minecraft mc; + protected ClientDataHolderVR dh; public BackpackTracker(Minecraft mc, ClientDataHolderVR dh) { - super(mc, dh); + this.mc = mc; + this.dh = dh; } @Override @@ -92,4 +97,9 @@ public void doProcess(LocalPlayer player) { } } } + + @Override + public TrackerTickType tickType() { + return TrackerTickType.PER_TICK; + } } diff --git a/common/src/main/java/org/vivecraft/client_vr/gameplay/trackers/BowTracker.java b/common/src/main/java/org/vivecraft/client_vr/gameplay/trackers/BowTracker.java index 1b8fe9cb1..4877810d1 100644 --- a/common/src/main/java/org/vivecraft/client_vr/gameplay/trackers/BowTracker.java +++ b/common/src/main/java/org/vivecraft/client_vr/gameplay/trackers/BowTracker.java @@ -1,5 +1,12 @@ package org.vivecraft.client_vr.gameplay.trackers; +import org.vivecraft.api.client.Tracker; +import org.vivecraft.client_vr.ClientDataHolderVR; +import org.vivecraft.client_vr.extensions.PlayerExtension; +import org.vivecraft.client.network.ClientNetworking; +import org.vivecraft.client_vr.VRData; +import org.vivecraft.client_vr.settings.VRSettings; + import net.minecraft.Util; import net.minecraft.client.Minecraft; import net.minecraft.client.player.LocalPlayer; @@ -23,7 +30,7 @@ import org.vivecraft.client_vr.settings.VRSettings; import org.vivecraft.common.network.packet.c2s.DrawPayloadC2S; -public class BowTracker extends Tracker { +public class BowTracker implements Tracker { private static final long MAX_DRAW_MILLIS = 1100L; private static final double NOTCH_DOT_THRESHOLD = 20F; @@ -42,8 +49,12 @@ public class BowTracker extends Tracker { private int hapCounter = 0; private int lastHapStep = 0; + protected Minecraft mc; + protected ClientDataHolderVR dh; + public BowTracker(Minecraft mc, ClientDataHolderVR dh) { - super(mc, dh); + this.mc = mc; + this.dh = dh; } public Vector3fc getAimVector() { @@ -103,11 +114,6 @@ public void reset(LocalPlayer player) { this.canDraw = false; } - @Override - public EntryPoint getEntryPoint() { - return EntryPoint.SPECIAL_ITEMS; - } - @Override public void doProcess(LocalPlayer player) { VRData vrData = this.dh.vrPlayer.getVRDataWorld(); @@ -279,4 +285,9 @@ public void doProcess(LocalPlayer player) { } } } + + @Override + public TrackerTickType tickType() { + return TrackerTickType.PER_FRAME; + } } diff --git a/common/src/main/java/org/vivecraft/client_vr/gameplay/trackers/CameraTracker.java b/common/src/main/java/org/vivecraft/client_vr/gameplay/trackers/CameraTracker.java index f1d1d245a..fa5af16f0 100644 --- a/common/src/main/java/org/vivecraft/client_vr/gameplay/trackers/CameraTracker.java +++ b/common/src/main/java/org/vivecraft/client_vr/gameplay/trackers/CameraTracker.java @@ -1,19 +1,21 @@ package org.vivecraft.client_vr.gameplay.trackers; +import org.joml.Matrix4f; +import org.vivecraft.api.client.Tracker; +import org.vivecraft.client_vr.ClientDataHolderVR; +import org.vivecraft.client_vr.VRData; +import org.vivecraft.client_vr.render.RenderPass; + import net.minecraft.client.Minecraft; import net.minecraft.client.player.LocalPlayer; import net.minecraft.client.resources.model.ModelResourceLocation; import net.minecraft.world.phys.Vec3; -import org.joml.Matrix4f; import org.joml.Matrix4fc; import org.joml.Quaternionf; import org.joml.Vector3f; import org.vivecraft.common.utils.MathUtils; -import org.vivecraft.client_vr.ClientDataHolderVR; -import org.vivecraft.client_vr.VRData; -import org.vivecraft.client_vr.render.RenderPass; -public class CameraTracker extends Tracker { +public class CameraTracker implements Tracker { public static final ModelResourceLocation CAMERA_MODEL = new ModelResourceLocation("vivecraft", "camera", ""); public static final ModelResourceLocation CAMERA_DISPLAY_MODEL = new ModelResourceLocation("vivecraft", "camera_display", ""); @@ -26,9 +28,12 @@ public class CameraTracker extends Tracker { private Vec3 startPosition; private Quaternionf startRotation; private boolean quickMode; + protected Minecraft mc; + protected ClientDataHolderVR dh; public CameraTracker(Minecraft mc, ClientDataHolderVR dh) { - super(mc, dh); + this.mc = mc; + this.dh = dh; } @Override @@ -72,17 +77,16 @@ public void doProcess(LocalPlayer player) { } @Override + public TrackerTickType tickType() { + return TrackerTickType.PER_FRAME; + } + public void reset(LocalPlayer player) { this.visible = false; this.quickMode = false; this.stopMoving(); } - @Override - public EntryPoint getEntryPoint() { - return EntryPoint.SPECIAL_ITEMS; // smoother camera movement - } - public boolean isVisible() { return this.visible; } diff --git a/common/src/main/java/org/vivecraft/client_vr/gameplay/trackers/ClimbTracker.java b/common/src/main/java/org/vivecraft/client_vr/gameplay/trackers/ClimbTracker.java index d976e7960..8e9c2d03d 100644 --- a/common/src/main/java/org/vivecraft/client_vr/gameplay/trackers/ClimbTracker.java +++ b/common/src/main/java/org/vivecraft/client_vr/gameplay/trackers/ClimbTracker.java @@ -1,5 +1,22 @@ package org.vivecraft.client_vr.gameplay.trackers; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Random; +import java.util.Set; + +import net.minecraft.network.chat.contents.TranslatableContents; +import org.vivecraft.api.client.Tracker; +import org.vivecraft.client.VivecraftVRMod; +import org.vivecraft.client_vr.ClientDataHolderVR; +import org.vivecraft.client_vr.BlockTags; +import org.vivecraft.common.network.CommonNetworkHelper; +import org.vivecraft.client_vr.extensions.PlayerExtension; +import org.vivecraft.client.network.ClientNetworking; +import org.vivecraft.client_vr.gameplay.VRPlayer; +import org.vivecraft.client_vr.provider.ControllerType; + import net.minecraft.client.Minecraft; import net.minecraft.client.player.LocalPlayer; import net.minecraft.client.resources.model.ModelResourceLocation; @@ -29,9 +46,8 @@ import java.util.*; -public class ClimbTracker extends Tracker { +public class ClimbTracker implements Tracker { public static final ModelResourceLocation CLAWS_MODEL = new ModelResourceLocation("vivecraft", "climb_claws", "inventory"); - public Set blocklist = new HashSet<>(); public ClimbeyBlockmode serverBlockmode = ClimbeyBlockmode.DISABLED; public boolean forceActivate = false; @@ -59,9 +75,12 @@ public class ClimbTracker extends Tracker { private final AABB fullBB = new AABB(0.0D, 0.0D, 0.0D, 1.0D, 1.0D, 1.0D); private final Random rand = new Random(); private boolean unsetFlag; + protected Minecraft mc; + protected ClientDataHolderVR dh; public ClimbTracker(Minecraft mc, ClientDataHolderVR dh) { - super(mc, dh); + this.mc = mc; + this.dh = dh; } public boolean isGrabbingLadder() { @@ -637,6 +656,11 @@ private boolean isClimbableTrapdoor(Level level, BlockPos blockPos, BlockState b return false; } + @Override + public TrackerTickType tickType() { + return TrackerTickType.PER_TICK; + } + private boolean allowed(BlockState bs) { return switch(this.serverBlockmode) { case DISABLED -> true; diff --git a/common/src/main/java/org/vivecraft/client_vr/gameplay/trackers/CrawlTracker.java b/common/src/main/java/org/vivecraft/client_vr/gameplay/trackers/CrawlTracker.java index 6745bed9c..cff585456 100644 --- a/common/src/main/java/org/vivecraft/client_vr/gameplay/trackers/CrawlTracker.java +++ b/common/src/main/java/org/vivecraft/client_vr/gameplay/trackers/CrawlTracker.java @@ -1,20 +1,25 @@ package org.vivecraft.client_vr.gameplay.trackers; +import org.vivecraft.api.client.Tracker; +import org.vivecraft.client_vr.ClientDataHolderVR; +import org.vivecraft.client.network.ClientNetworking; + import net.minecraft.client.Minecraft; import net.minecraft.client.player.LocalPlayer; import net.minecraft.world.entity.Pose; -import org.vivecraft.client.network.ClientNetworking; import org.vivecraft.client.utils.ScaleHelper; -import org.vivecraft.client_vr.ClientDataHolderVR; import org.vivecraft.common.network.packet.c2s.CrawlPayloadC2S; -public class CrawlTracker extends Tracker { +public class CrawlTracker implements Tracker { private boolean wasCrawling; public boolean crawling; public boolean crawlsteresis; + protected Minecraft mc; + protected ClientDataHolderVR dh; public CrawlTracker(Minecraft mc, ClientDataHolderVR dh) { - super(mc, dh); + this.mc = mc; + this.dh = dh; } @Override @@ -50,6 +55,11 @@ public void doProcess(LocalPlayer player) { this.updateState(player); } + @Override + public TrackerTickType tickType() { + return TrackerTickType.PER_TICK; + } + private void updateState(LocalPlayer player) { if (this.crawling != this.wasCrawling) { if (this.crawling) { diff --git a/common/src/main/java/org/vivecraft/client_vr/gameplay/trackers/EatingTracker.java b/common/src/main/java/org/vivecraft/client_vr/gameplay/trackers/EatingTracker.java index 0a22544f2..e7af8a050 100644 --- a/common/src/main/java/org/vivecraft/client_vr/gameplay/trackers/EatingTracker.java +++ b/common/src/main/java/org/vivecraft/client_vr/gameplay/trackers/EatingTracker.java @@ -1,5 +1,8 @@ package org.vivecraft.client_vr.gameplay.trackers; +import org.vivecraft.api.client.Tracker; +import org.vivecraft.client_vr.ClientDataHolderVR; + import net.minecraft.Util; import net.minecraft.client.Minecraft; import net.minecraft.client.player.LocalPlayer; @@ -8,10 +11,9 @@ import net.minecraft.world.item.UseAnim; import org.joml.Vector3f; import org.vivecraft.common.utils.MathUtils; -import org.vivecraft.client_vr.ClientDataHolderVR; import org.vivecraft.client_vr.VRData; -public class EatingTracker extends Tracker { +public class EatingTracker implements Tracker { private static final float MOUTH_TO_EYE_DISTANCE = 0.0F; private static final float THRESHOLD = 0.25F; private static final long EAT_TIME = 2100L; @@ -19,8 +21,12 @@ public class EatingTracker extends Tracker { public boolean[] eating = new boolean[2]; private long eatStart; + protected Minecraft mc; + protected ClientDataHolderVR dh; + public EatingTracker(Minecraft mc, ClientDataHolderVR dh) { - super(mc, dh); + this.mc = mc; + this.dh = dh; } public boolean isEating() { @@ -92,7 +98,6 @@ public void doProcess(LocalPlayer player) { if (!this.eating[c]) { //Minecraft.getInstance().physicalGuiManager.preClickAction(); - if (this.mc.gameMode.useItem(player, c == 0 ? InteractionHand.MAIN_HAND : InteractionHand.OFF_HAND).consumesAction()) { this.mc.gameRenderer.itemInHandRenderer.itemUsed(c == 0 ? InteractionHand.MAIN_HAND : InteractionHand.OFF_HAND); this.eating[c] = true; @@ -116,4 +121,9 @@ public void doProcess(LocalPlayer player) { } } } + + @Override + public TrackerTickType tickType() { + return TrackerTickType.PER_TICK; + } } diff --git a/common/src/main/java/org/vivecraft/client_vr/gameplay/trackers/HorseTracker.java b/common/src/main/java/org/vivecraft/client_vr/gameplay/trackers/HorseTracker.java index f9e90621b..12f116ede 100644 --- a/common/src/main/java/org/vivecraft/client_vr/gameplay/trackers/HorseTracker.java +++ b/common/src/main/java/org/vivecraft/client_vr/gameplay/trackers/HorseTracker.java @@ -1,5 +1,10 @@ package org.vivecraft.client_vr.gameplay.trackers; +import org.vivecraft.api.client.Tracker; +import org.vivecraft.client_vr.ClientDataHolderVR; +import org.vivecraft.client_vr.gameplay.VRPlayer; +import org.vivecraft.client_vr.settings.VRSettings; + import net.minecraft.client.Minecraft; import net.minecraft.client.player.LocalPlayer; import net.minecraft.world.entity.animal.horse.AbstractHorse; @@ -7,11 +12,8 @@ import net.minecraft.world.phys.Vec3; import org.joml.Vector3f; import org.vivecraft.common.utils.MathUtils; -import org.vivecraft.client_vr.ClientDataHolderVR; -import org.vivecraft.client_vr.gameplay.VRPlayer; -import org.vivecraft.client_vr.settings.VRSettings; -public class HorseTracker extends Tracker { +public class HorseTracker implements Tracker { private static final double BOOST_TRIGGER = 1.4D; private static final double PULL_TRIGGER = 0.8D; private static final int MAX_SPEED_LEVEL = 3; @@ -25,8 +27,12 @@ public class HorseTracker extends Tracker { private Horse horse = null; private final ModelInfo info = new ModelInfo(); + protected Minecraft mc; + protected ClientDataHolderVR dh; + public HorseTracker(Minecraft mc, ClientDataHolderVR dh) { - super(mc, dh); + this.mc = mc; + this.dh = dh; } @Override @@ -51,8 +57,6 @@ public boolean isActive(LocalPlayer player) { @Override public void reset(LocalPlayer player) { - super.reset(player); - if (this.horse != null) { this.horse.setNoAi(false); } @@ -123,6 +127,11 @@ public void doProcess(LocalPlayer player) { this.horse.setDeltaMovement(movement.x, this.horse.getDeltaMovement().y, movement.z); } + @Override + public TrackerTickType tickType() { + return TrackerTickType.PER_TICK; + } + private boolean doBoost() { if (this.speedLevel >= MAX_SPEED_LEVEL) { return false; diff --git a/common/src/main/java/org/vivecraft/client_vr/gameplay/trackers/InteractTracker.java b/common/src/main/java/org/vivecraft/client_vr/gameplay/trackers/InteractTracker.java index f1d8282b9..57bdadf64 100644 --- a/common/src/main/java/org/vivecraft/client_vr/gameplay/trackers/InteractTracker.java +++ b/common/src/main/java/org/vivecraft/client_vr/gameplay/trackers/InteractTracker.java @@ -1,5 +1,19 @@ package org.vivecraft.client_vr.gameplay.trackers; +import java.util.HashSet; + +import org.vivecraft.api.client.Tracker; +import org.vivecraft.client.VivecraftVRMod; +import org.vivecraft.client_vr.ClientDataHolderVR; +import org.vivecraft.client.Xplat; +import org.vivecraft.client_vr.extensions.PlayerExtension; +import org.vivecraft.client_vr.VRData; +import org.vivecraft.client_vr.provider.ControllerType; +import org.vivecraft.client_vr.settings.VRHotkeys; +import org.vivecraft.client_vr.settings.VRSettings; +import org.vivecraft.client_vr.render.RenderPass; +import org.vivecraft.client_vr.render.VRFirstPersonArmSwing; + import net.minecraft.client.Minecraft; import net.minecraft.client.player.LocalPlayer; import net.minecraft.core.BlockPos; @@ -32,7 +46,7 @@ import java.util.HashSet; -public class InteractTracker extends Tracker { +public class InteractTracker implements Tracker { // indicates when a hand has a bucket and is in a liquid public boolean[] bukkit = new boolean[2]; @@ -59,8 +73,12 @@ public class InteractTracker extends Tracker { // a set of blocks that can be interacted with private HashSet> rightClickable = null; + protected Minecraft mc; + protected ClientDataHolderVR dh; + public InteractTracker(Minecraft mc, ClientDataHolderVR dh) { - super(mc, dh); + this.mc = mc; + this.dh = dh; } @Override @@ -263,6 +281,11 @@ private void addIfClassHasMethod(String name, Class oclass) { } } + @Override + public TrackerTickType tickType() { + return TrackerTickType.PER_TICK; + } + public boolean isInteractActive(int controller) { return this.active[controller]; } diff --git a/common/src/main/java/org/vivecraft/client_vr/gameplay/trackers/JumpTracker.java b/common/src/main/java/org/vivecraft/client_vr/gameplay/trackers/JumpTracker.java index f7e9ec921..fdd414838 100644 --- a/common/src/main/java/org/vivecraft/client_vr/gameplay/trackers/JumpTracker.java +++ b/common/src/main/java/org/vivecraft/client_vr/gameplay/trackers/JumpTracker.java @@ -1,8 +1,14 @@ package org.vivecraft.client_vr.gameplay.trackers; +import net.minecraft.network.chat.contents.TranslatableContents; +import org.vivecraft.api.client.Tracker; +import org.vivecraft.client.VivecraftVRMod; +import org.vivecraft.client_vr.ClientDataHolderVR; +import org.vivecraft.client.network.ClientNetworking; +import org.vivecraft.client_vr.settings.AutoCalibration; + import net.minecraft.client.Minecraft; import net.minecraft.client.player.LocalPlayer; -import net.minecraft.network.chat.contents.TranslatableContents; import net.minecraft.world.effect.MobEffects; import net.minecraft.world.entity.EquipmentSlot; import net.minecraft.world.entity.player.Player; @@ -10,13 +16,9 @@ import net.minecraft.world.item.Items; import net.minecraft.world.phys.Vec3; import org.joml.Vector3f; -import org.vivecraft.client.VivecraftVRMod; -import org.vivecraft.client.network.ClientNetworking; -import org.vivecraft.client_vr.ClientDataHolderVR; -import org.vivecraft.client_vr.settings.AutoCalibration; import org.vivecraft.client_vr.settings.VRSettings; -public class JumpTracker extends Tracker { +public class JumpTracker implements Tracker { // in room space public Vector3f[] latchStart = new Vector3f[]{new Vector3f(), new Vector3f()}; @@ -25,9 +27,12 @@ public class JumpTracker extends Tracker { public Vec3[] latchStartPlayer = new Vec3[]{Vec3.ZERO, Vec3.ZERO}; private boolean c0Latched = false; private boolean c1Latched = false; + protected Minecraft mc; + protected ClientDataHolderVR dh; public JumpTracker(Minecraft mc, ClientDataHolderVR dh) { - super(mc, dh); + this.mc = mc; + this.dh = dh; } /** @@ -221,4 +226,9 @@ public void doProcess(LocalPlayer player) { player.jumpFromGround(); } } + + @Override + public TrackerTickType tickType() { + return TrackerTickType.PER_TICK; + } } diff --git a/common/src/main/java/org/vivecraft/client_vr/gameplay/trackers/RowTracker.java b/common/src/main/java/org/vivecraft/client_vr/gameplay/trackers/RowTracker.java index 0df2d39a8..b86302f67 100644 --- a/common/src/main/java/org/vivecraft/client_vr/gameplay/trackers/RowTracker.java +++ b/common/src/main/java/org/vivecraft/client_vr/gameplay/trackers/RowTracker.java @@ -1,5 +1,8 @@ package org.vivecraft.client_vr.gameplay.trackers; +import org.vivecraft.api.client.Tracker; +import org.vivecraft.client_vr.ClientDataHolderVR; + import net.minecraft.client.Minecraft; import net.minecraft.client.player.LocalPlayer; import net.minecraft.core.BlockPos; @@ -9,9 +12,8 @@ import org.joml.Quaternionf; import org.joml.Vector3f; import org.vivecraft.common.utils.MathUtils; -import org.vivecraft.client_vr.ClientDataHolderVR; -public class RowTracker extends Tracker { +public class RowTracker implements Tracker { private static final double TRANSMISSION_EFFICIENCY = 0.9D; public double[] forces = new double[]{0.0D, 0.0D}; @@ -21,24 +23,29 @@ public class RowTracker extends Tracker { private final Vec3[] lastUWPs = new Vec3[2]; + protected Minecraft mc; + protected ClientDataHolderVR dh; + public RowTracker(Minecraft mc, ClientDataHolderVR dh) { - super(mc, dh); + this.mc = mc; + this.dh = dh; } - @Override - public boolean isActive(LocalPlayer player) { + public boolean isActive(LocalPlayer p) { if (this.dh.vrSettings.seated) { return false; } else if (!this.dh.vrSettings.realisticRowEnabled) { return false; - } else if (player == null || !player.isAlive()) { - return false; - } else if (this.mc.gameMode == null) { - return false; - } else if (this.mc.options.keyUp.isDown()) { // important - return false; - } else if (!(player.getVehicle() instanceof Boat)) { - return false; + } else if (p != null && p.isAlive()) { + if (this.mc.gameMode == null) { + return false; + } else if (this.mc.options.keyUp.isDown()) { + return false; + } else if (!(p.getVehicle() instanceof Boat)) { + return false; + } else { + return !this.dh.bowTracker.isNotched(); + } } else { return !this.dh.bowTracker.isNotched(); } @@ -83,6 +90,11 @@ public void doProcess(LocalPlayer player) { //TODO: Backwards paddlin' } + @Override + public TrackerTickType tickType() { + return TrackerTickType.PER_TICK; + } + public void doProcessFinaltransmithastofixthis(LocalPlayer player) { Boat boat = (Boat) player.getVehicle(); Quaternionf boatRot = new Quaternionf().rotationYXZ( diff --git a/common/src/main/java/org/vivecraft/client_vr/gameplay/trackers/RunTracker.java b/common/src/main/java/org/vivecraft/client_vr/gameplay/trackers/RunTracker.java index cae9ac70c..198bc5846 100644 --- a/common/src/main/java/org/vivecraft/client_vr/gameplay/trackers/RunTracker.java +++ b/common/src/main/java/org/vivecraft/client_vr/gameplay/trackers/RunTracker.java @@ -1,17 +1,22 @@ package org.vivecraft.client_vr.gameplay.trackers; +import org.vivecraft.api.client.Tracker; +import org.vivecraft.client_vr.ClientDataHolderVR; +import org.vivecraft.client_vr.settings.VRSettings; + import net.minecraft.client.Minecraft; import net.minecraft.client.player.LocalPlayer; import org.joml.Vector3f; -import org.vivecraft.client_vr.ClientDataHolderVR; -import org.vivecraft.client_vr.settings.VRSettings; -public class RunTracker extends Tracker { +public class RunTracker implements Tracker { private double direction = 0.0D; private float speed = 0.0F; + protected Minecraft mc; + protected ClientDataHolderVR dh; public RunTracker(Minecraft mc, ClientDataHolderVR dh) { - super(mc, dh); + this.mc = mc; + this.dh = dh; } @Override @@ -86,4 +91,9 @@ public void doProcess(LocalPlayer player) { this.speed = 1.3F; } } + + @Override + public TrackerTickType tickType() { + return TrackerTickType.PER_TICK; + } } diff --git a/common/src/main/java/org/vivecraft/client_vr/gameplay/trackers/SneakTracker.java b/common/src/main/java/org/vivecraft/client_vr/gameplay/trackers/SneakTracker.java index 0822299b7..b3372f943 100644 --- a/common/src/main/java/org/vivecraft/client_vr/gameplay/trackers/SneakTracker.java +++ b/common/src/main/java/org/vivecraft/client_vr/gameplay/trackers/SneakTracker.java @@ -1,16 +1,21 @@ package org.vivecraft.client_vr.gameplay.trackers; -import net.minecraft.client.Minecraft; -import net.minecraft.client.player.LocalPlayer; +import org.vivecraft.api.client.Tracker; import org.vivecraft.client_vr.ClientDataHolderVR; import org.vivecraft.client_vr.settings.AutoCalibration; -public class SneakTracker extends Tracker { +import net.minecraft.client.Minecraft; +import net.minecraft.client.player.LocalPlayer; + +public class SneakTracker implements Tracker { public boolean sneakOverride = false; public int sneakCounter = 0; + protected Minecraft mc; + protected ClientDataHolderVR dh; public SneakTracker(Minecraft mc, ClientDataHolderVR dh) { - super(mc, dh); + this.mc = mc; + this.dh = dh; } @Override @@ -44,4 +49,9 @@ public void doProcess(LocalPlayer player) { this.sneakOverride = AutoCalibration.getPlayerHeight() - this.dh.vr.hmdPivotHistory.latest().y() > this.dh.vrSettings.sneakThreshold; } + + @Override + public TrackerTickType tickType() { + return TrackerTickType.PER_TICK; + } } diff --git a/common/src/main/java/org/vivecraft/client_vr/gameplay/trackers/SwimTracker.java b/common/src/main/java/org/vivecraft/client_vr/gameplay/trackers/SwimTracker.java index 5581ccbe6..5f09e698f 100644 --- a/common/src/main/java/org/vivecraft/client_vr/gameplay/trackers/SwimTracker.java +++ b/common/src/main/java/org/vivecraft/client_vr/gameplay/trackers/SwimTracker.java @@ -1,22 +1,27 @@ package org.vivecraft.client_vr.gameplay.trackers; +import org.vivecraft.api.client.Tracker; +import org.vivecraft.client_vr.ClientDataHolderVR; + import net.minecraft.client.Minecraft; import net.minecraft.client.player.LocalPlayer; import net.minecraft.world.phys.Vec3; import org.joml.Vector3f; import org.vivecraft.common.utils.MathUtils; -import org.vivecraft.client_vr.ClientDataHolderVR; -public class SwimTracker extends Tracker { +public class SwimTracker implements Tracker { private static final float FRICTION = 0.9F; private static final float RISE_SPEED = 0.005F; private static final float SWIM_SPEED = 1.3F; private Vector3f motion = new Vector3f(); private double lastDist; + protected Minecraft mc; + protected ClientDataHolderVR dh; public SwimTracker(Minecraft mc, ClientDataHolderVR dh) { - super(mc, dh); + this.mc = mc; + this.dh = dh; } @Override @@ -73,4 +78,9 @@ public void doProcess(LocalPlayer player) { player.push(this.motion.x, this.motion.y, this.motion.z); this.motion = this.motion.mul(FRICTION); } + + @Override + public TrackerTickType tickType() { + return TrackerTickType.PER_TICK; + } } diff --git a/common/src/main/java/org/vivecraft/client_vr/gameplay/trackers/SwingTracker.java b/common/src/main/java/org/vivecraft/client_vr/gameplay/trackers/SwingTracker.java index 1a9d600e0..43b0ed348 100644 --- a/common/src/main/java/org/vivecraft/client_vr/gameplay/trackers/SwingTracker.java +++ b/common/src/main/java/org/vivecraft/client_vr/gameplay/trackers/SwingTracker.java @@ -1,5 +1,17 @@ package org.vivecraft.client_vr.gameplay.trackers; +import java.util.List; + +import net.minecraft.world.item.context.UseOnContext; +import net.minecraft.world.level.block.*; +import org.vivecraft.api.client.Tracker; +import org.vivecraft.client.VivecraftVRMod; +import org.vivecraft.client_vr.ClientDataHolderVR; +import org.vivecraft.client_vr.BlockTags; +import org.vivecraft.client_vr.ItemTags; +import org.vivecraft.client_vr.provider.ControllerType; +import org.vivecraft.client_vr.settings.VRSettings; + import net.minecraft.client.Minecraft; import net.minecraft.client.player.LocalPlayer; import net.minecraft.core.BlockPos; @@ -10,30 +22,20 @@ import net.minecraft.world.entity.EquipmentSlot; import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.*; -import net.minecraft.world.item.context.UseOnContext; import net.minecraft.world.level.ClipContext; -import net.minecraft.world.level.block.*; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.phys.AABB; import net.minecraft.world.phys.BlockHitResult; import net.minecraft.world.phys.HitResult; import net.minecraft.world.phys.Vec3; import org.joml.Vector3f; -import org.vivecraft.client.VivecraftVRMod; import org.vivecraft.client.Xplat; import org.vivecraft.common.utils.MathUtils; -import org.vivecraft.client_vr.BlockTags; -import org.vivecraft.client_vr.ClientDataHolderVR; -import org.vivecraft.client_vr.ItemTags; import org.vivecraft.client_vr.Vector3fHistory; -import org.vivecraft.client_vr.provider.ControllerType; -import org.vivecraft.client_vr.settings.VRSettings; import org.vivecraft.mod_compat_vr.bettercombat.BetterCombatHelper; import org.vivecraft.mod_compat_vr.epicfight.EpicFightHelper; -import java.util.List; - -public class SwingTracker extends Tracker { +public class SwingTracker implements Tracker { private final Vec3[] lastWeaponEndAir = new Vec3[]{Vec3.ZERO, Vec3.ZERO}; private final boolean[] lastWeaponSolid = new boolean[2]; public final Vec3[] miningPoint = new Vec3[2]; @@ -42,9 +44,12 @@ public class SwingTracker extends Tracker { public boolean[] canAct = new boolean[2]; public int disableSwing = 3; private float speedThresh = 3.0F; + protected Minecraft mc; + protected ClientDataHolderVR dh; public SwingTracker(Minecraft mc, ClientDataHolderVR dh) { - super(mc, dh); + this.mc = mc; + this.dh = dh; } @Override @@ -328,14 +333,19 @@ else if (blockstate.getBlock() instanceof NoteBlock || blockstate.is(BlockTags.V this.mc.getProfiler().pop(); } + @Override + public TrackerTickType tickType() { + return TrackerTickType.PER_TICK; + } + private boolean getIsHittingBlock() { return this.mc.gameMode.isDestroying(); } private void clearBlockHitDelay() { // TODO set destroyTicks to 1 to cancel multiple sound events per hit - //MCReflection.PlayerController_blockHitDelay.set(Minecraft.getInstance().gameMode, 0); - // Minecraft.getInstance().gameMode.blockBreakingCooldown = 1; + //MCReflection.PlayerController_blockHitDelay.set(this.mc.gameMode, 0); + // this.mc.gameMode.blockBreakingCooldown = 1; } /** diff --git a/common/src/main/java/org/vivecraft/client_vr/gameplay/trackers/TeleportTracker.java b/common/src/main/java/org/vivecraft/client_vr/gameplay/trackers/TeleportTracker.java index 8d61ddea5..f079ecff9 100644 --- a/common/src/main/java/org/vivecraft/client_vr/gameplay/trackers/TeleportTracker.java +++ b/common/src/main/java/org/vivecraft/client_vr/gameplay/trackers/TeleportTracker.java @@ -15,6 +15,7 @@ import net.minecraft.world.phys.HitResult; import net.minecraft.world.phys.Vec3; import org.joml.Vector3f; +import org.vivecraft.api.client.Tracker; import org.vivecraft.client.VivecraftVRMod; import org.vivecraft.client.network.ClientNetworking; import org.vivecraft.common.utils.MathUtils; @@ -27,7 +28,7 @@ import java.util.Random; -public class TeleportTracker extends Tracker { +public class TeleportTracker implements Tracker { private float teleportEnergy; private Vec3 movementTeleportDestination = Vec3.ZERO; private Direction movementTeleportDestinationSideHit; @@ -38,9 +39,12 @@ public class TeleportTracker extends Tracker { public int movementTeleportArcSteps = 0; public double lastTeleportArcDisplayOffset = 0.0D; public VRMovementStyle vrMovementStyle; + protected Minecraft mc; + protected ClientDataHolderVR dh; public TeleportTracker(Minecraft mc, ClientDataHolderVR dh) { - super(mc, dh); + this.mc = mc; + this.dh = dh; this.vrMovementStyle = new VRMovementStyle(); } @@ -493,4 +497,9 @@ public Vec3 getInterpolatedArcPosition(float progress) { this.movementTeleportArc[step].z + deltaZ * stepProgress); } } + + @Override + public TrackerTickType tickType() { + return TrackerTickType.PER_TICK; + } } diff --git a/common/src/main/java/org/vivecraft/client_vr/gameplay/trackers/TelescopeTracker.java b/common/src/main/java/org/vivecraft/client_vr/gameplay/trackers/TelescopeTracker.java index f21fc72f4..14a8073ba 100644 --- a/common/src/main/java/org/vivecraft/client_vr/gameplay/trackers/TelescopeTracker.java +++ b/common/src/main/java/org/vivecraft/client_vr/gameplay/trackers/TelescopeTracker.java @@ -8,20 +8,20 @@ import net.minecraft.world.item.Items; import org.joml.Vector3f; import org.vivecraft.common.utils.MathUtils; +import org.vivecraft.api.client.Tracker; import org.vivecraft.client_vr.ClientDataHolderVR; import org.vivecraft.client_vr.ItemTags; import org.vivecraft.client_vr.VRData; import org.vivecraft.client_vr.render.RenderPass; -public class TelescopeTracker extends Tracker { +public class TelescopeTracker implements Tracker { public static final ModelResourceLocation SCOPE_MODEL = new ModelResourceLocation("vivecraft", "spyglass_in_hand", "inventory"); private static final float LENS_DIST_MAX = 0.05F; private static final float LENS_DIST_MIN = 0.185F; private static final float LENS_DOT_MAX = 0.9F; private static final float LENS_DOT_MIN = 0.75F; - public TelescopeTracker(Minecraft mc, ClientDataHolderVR dh) { - super(mc, dh); + public TelescopeTracker() { } @Override @@ -33,6 +33,11 @@ public boolean isActive(LocalPlayer player) { public void doProcess(LocalPlayer player) { } + @Override + public TrackerTickType tickType() { + return TrackerTickType.PER_TICK; + } + /** * @param itemStack ItemStack to check * @return if the given {@code itemStack} is a telescope diff --git a/common/src/main/java/org/vivecraft/client_vr/gameplay/trackers/Tracker.java b/common/src/main/java/org/vivecraft/client_vr/gameplay/trackers/Tracker.java deleted file mode 100644 index 3c69a4e9e..000000000 --- a/common/src/main/java/org/vivecraft/client_vr/gameplay/trackers/Tracker.java +++ /dev/null @@ -1,34 +0,0 @@ -package org.vivecraft.client_vr.gameplay.trackers; - -import net.minecraft.client.Minecraft; -import net.minecraft.client.player.LocalPlayer; -import org.vivecraft.client_vr.ClientDataHolderVR; - -public abstract class Tracker { - public Minecraft mc; - public ClientDataHolderVR dh; - - public Tracker(Minecraft mc, ClientDataHolderVR dh) { - this.mc = mc; - this.dh = dh; - } - - public abstract boolean isActive(LocalPlayer player); - - public abstract void doProcess(LocalPlayer player); - - public void reset(LocalPlayer player) { - } - - public void idleTick(LocalPlayer player) { - } - - public EntryPoint getEntryPoint() { - return EntryPoint.LIVING_UPDATE; - } - - public enum EntryPoint { - LIVING_UPDATE, - SPECIAL_ITEMS - } -} diff --git a/common/src/main/java/org/vivecraft/client_vr/gameplay/trackers/VehicleTracker.java b/common/src/main/java/org/vivecraft/client_vr/gameplay/trackers/VehicleTracker.java index 3f8e63a82..0ac0ba27c 100644 --- a/common/src/main/java/org/vivecraft/client_vr/gameplay/trackers/VehicleTracker.java +++ b/common/src/main/java/org/vivecraft/client_vr/gameplay/trackers/VehicleTracker.java @@ -1,5 +1,11 @@ package org.vivecraft.client_vr.gameplay.trackers; +import org.vivecraft.api.client.Tracker; +import org.vivecraft.client_vr.ClientDataHolderVR; +import org.vivecraft.client_vr.ItemTags; +import org.vivecraft.client_vr.VRData; +import org.vivecraft.client_vr.settings.VRSettings; + import net.minecraft.client.Minecraft; import net.minecraft.client.player.LocalPlayer; import net.minecraft.world.entity.Entity; @@ -11,12 +17,8 @@ import net.minecraft.world.phys.Vec3; import org.joml.Vector3f; import org.vivecraft.common.utils.MathUtils; -import org.vivecraft.client_vr.ClientDataHolderVR; -import org.vivecraft.client_vr.ItemTags; -import org.vivecraft.client_vr.VRData; -import org.vivecraft.client_vr.settings.VRSettings; -public class VehicleTracker extends Tracker { +public class VehicleTracker implements Tracker { private float PreMount_World_Rotation; public Vec3 Premount_Pos_Room = Vec3.ZERO; public float vehicleInitialRotation = 0.0F; @@ -24,9 +26,12 @@ public class VehicleTracker extends Tracker { private double rotationTarget = 0.0D; private int minecartStupidityCounter; public int dismountCooldown = 0; + protected Minecraft mc; + protected ClientDataHolderVR dh; public VehicleTracker(Minecraft mc, ClientDataHolderVR dh) { - super(mc, dh); + this.mc = mc; + this.dh = dh; } @Override @@ -43,7 +48,6 @@ public boolean isActive(LocalPlayer player) { @Override public void reset(LocalPlayer player) { this.minecartStupidityCounter = 2; - super.reset(player); } public double getVehicleFloor(Entity vehicle, double original) { @@ -235,4 +239,9 @@ public boolean canRoomscaleDismount(LocalPlayer player) { player.isPassenger() && player.getVehicle().onGround() && this.dismountCooldown == 0; } + + @Override + public TrackerTickType tickType() { + return TrackerTickType.PER_TICK; + } } diff --git a/common/src/main/java/org/vivecraft/common/APIImpl.java b/common/src/main/java/org/vivecraft/common/api_impl/APIImpl.java similarity index 51% rename from common/src/main/java/org/vivecraft/common/APIImpl.java rename to common/src/main/java/org/vivecraft/common/api_impl/APIImpl.java index ac634ec67..08c8d2703 100644 --- a/common/src/main/java/org/vivecraft/common/APIImpl.java +++ b/common/src/main/java/org/vivecraft/common/api_impl/APIImpl.java @@ -1,8 +1,10 @@ -package org.vivecraft.common; +package org.vivecraft.common.api_impl; import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.entity.player.Player; -import org.vivecraft.api_beta.VivecraftAPI; +import org.jetbrains.annotations.Nullable; +import org.vivecraft.api.VivecraftAPI; +import org.vivecraft.api.data.VRData; import org.vivecraft.client.VRPlayersClient; import org.vivecraft.server.ServerVRPlayers; @@ -21,4 +23,17 @@ public boolean isVRPlayer(Player player) { return VRPlayersClient.getInstance().isVRPlayer(player); } + + @Nullable + @Override + public VRData getVRData(Player player) { + if (!isVRPlayer(player)) { + return null; + } + if (player instanceof ServerPlayer serverPlayer) { + return ServerVRPlayers.getVivePlayer(serverPlayer).asVRData(); + } + + return VRPlayersClient.getInstance().getRotationsForPlayer(player.getUUID()).asVRData(player.position()); + } } diff --git a/common/src/main/java/org/vivecraft/common/api_impl/data/VRDataImpl.java b/common/src/main/java/org/vivecraft/common/api_impl/data/VRDataImpl.java new file mode 100644 index 000000000..64b7c8f1c --- /dev/null +++ b/common/src/main/java/org/vivecraft/common/api_impl/data/VRDataImpl.java @@ -0,0 +1,49 @@ +package org.vivecraft.common.api_impl.data; + +import org.vivecraft.api.data.VRData; +import org.vivecraft.api.data.VRPose; + +public class VRDataImpl implements VRData { + + private final VRPose hmd; + private final VRPose c0; + private final VRPose c1; + private final boolean isSeated; + private final boolean usingReversedHands; + + public VRDataImpl(VRPose hmd, VRPose c0, VRPose c1, boolean isSeated, boolean usingReversedHands) { + this.hmd = hmd; + this.c0 = c0; + this.c1 = c1; + this.isSeated = isSeated; + this.usingReversedHands = usingReversedHands; + } + + @Override + public VRPose getHMD() { + return this.hmd; + } + + @Override + public VRPose getController(int controller) { + if (controller != 0 && controller != 1) { + throw new IllegalArgumentException("Controller number must be controller 0 or controller 1."); + } + return controller == 0 ? this.c0 : this.c1; + } + + @Override + public boolean isSeated() { + return this.isSeated; + } + + @Override + public boolean usingReversedHands() { + return this.usingReversedHands; + } + + @Override + public String toString() { + return "HMD: " + getHMD() + "\nController 0: " + getController0() + "\nController 1: " + getController1(); + } +} diff --git a/common/src/main/java/org/vivecraft/common/api_impl/data/VRPoseImpl.java b/common/src/main/java/org/vivecraft/common/api_impl/data/VRPoseImpl.java new file mode 100644 index 000000000..db371a765 --- /dev/null +++ b/common/src/main/java/org/vivecraft/common/api_impl/data/VRPoseImpl.java @@ -0,0 +1,55 @@ +package org.vivecraft.common.api_impl.data; + +import net.minecraft.world.phys.Vec3; +import org.joml.Quaternionf; +import org.joml.Quaternionfc; +import org.vivecraft.api.data.VRPose; + +public class VRPoseImpl implements VRPose { + + private final Vec3 pos; + private final Vec3 rot; + private final Quaternionfc quaternion; + + public VRPoseImpl(Vec3 pos, Vec3 rot, Quaternionfc quaternion) { + this.pos = pos; + this.rot = rot; + this.quaternion = quaternion; + } + + @Override + public Vec3 getPos() { + return this.pos; + } + + @Override + public Vec3 getRot() { + return this.rot; + } + + @Override + public double getPitch() { + return Math.asin(this.rot.y / this.rot.length()); + } + + @Override + public double getYaw() { + return Math.atan2(-this.rot.x, this.rot.z); + } + + @Override + public double getRoll() { + return -Math.atan2(2.0F * (quaternion.x() * quaternion.y() + quaternion.w() * quaternion.z()), + quaternion.w() * quaternion.w() - quaternion.x() * quaternion.x() + quaternion.y() * quaternion.y() - quaternion.z() * quaternion.z()); + } + + @Override + public Quaternionfc getQuaternion() { + return this.quaternion; + } + + @Override + public String toString() { + return "Position: " + getPos() + "\tRotation: " + getRot(); + } +} diff --git a/common/src/main/java/org/vivecraft/server/ServerVivePlayer.java b/common/src/main/java/org/vivecraft/server/ServerVivePlayer.java index 9971a312f..ba9e04bc9 100644 --- a/common/src/main/java/org/vivecraft/server/ServerVivePlayer.java +++ b/common/src/main/java/org/vivecraft/server/ServerVivePlayer.java @@ -3,9 +3,13 @@ import net.minecraft.server.level.ServerPlayer; import net.minecraft.util.Mth; import net.minecraft.world.phys.Vec3; +import org.joml.Quaternionfc; import org.joml.Vector3f; import org.joml.Vector3fc; import org.vivecraft.common.utils.MathUtils; +import org.vivecraft.api.data.VRData; +import org.vivecraft.common.api_impl.data.VRDataImpl; +import org.vivecraft.common.api_impl.data.VRPoseImpl; import org.vivecraft.common.network.CommonNetworkHelper; import org.vivecraft.common.network.Pose; import org.vivecraft.common.network.VrPlayerState; @@ -88,6 +92,16 @@ public Vec3 getHMDPos() { } } + /** + * @return rotation of the head as a quaternion + */ + public Quaternionfc getHMDQuaternion() { + if (this.vrPlayerState != null) { + return this.vrPlayerState.hmd().orientation(); + } + return null; // Should only return null if player isn't in VR. + } + /** * @param c controller to get the position for * @param realPosition if true disables the seated override @@ -130,6 +144,19 @@ public Vec3 getControllerPos(int c) { return getControllerPos(c, false); } + /** + * + * @param c controller to get the rotation for + * @return controller rotation as a quaternion + */ + public Quaternionfc getControllerQuaternion(int c) { + if (this.vrPlayerState != null) { + Pose controllerPose = c == 0 ? this.vrPlayerState.controller0() : this.vrPlayerState.controller1(); + return controllerPose.orientation(); + } + return null; // Should only return null if player isn't in VR. + } + /** * @return if the player has VR active */ @@ -150,4 +177,24 @@ public void setVR(boolean vr) { public boolean isSeated() { return this.vrPlayerState != null && this.vrPlayerState.seated(); } + + public boolean usingReversedHands() { + if (this.vrPlayerState == null) { + return false; + } + return this.vrPlayerState.reverseHands(); + } + + public VRData asVRData() { + if (this.vrPlayerState == null) { + return null; + } + return new VRDataImpl( + new VRPoseImpl(this.getHMDPos(), this.getHMDDir(), this.getHMDQuaternion()), + new VRPoseImpl(this.getControllerPos(0), this.getControllerDir(0), this.getControllerQuaternion(0)), + new VRPoseImpl(this.getControllerPos(1), this.getControllerDir(1), this.getControllerQuaternion(1)), + this.isSeated(), + this.usingReversedHands() + ); + } }