Initial commit

This commit is contained in:
2025-12-10 21:06:22 +01:00
commit cc9190b9ce
476 changed files with 320218 additions and 0 deletions

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: cd1874151eeacf146954ae92f6daf1a2
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: c5ba5e9533e05b14b98eb6ad18f7d604
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,32 @@
https://github.com/Superbstingray/UdonPlayerPlatformHook
v1.5 - 20/3/24 - Made in Unity 2019.4.31f1 / SDK3-2022.02.16.19.13 / UdonSharp_v0.20.3
(Prefab Functionality)
* Drag and Drop solution for making Players correctly follow moving colliders in the scene when standing on them. The prefab makes Players functionally behave as if they were parented to any collider they stand on.
* Behavior can be enabled or disabled based on layers.
(Usage)
* Drag into the root of your scene and set your moving Objects/Platforms to layer 11(Environment) or a custom layer and assign layers in the scripts layer mask.
* You only need to add one instance of the prefab to your scene, ideally not parented to any other Game Object.
(Functionality / Features)
* Makes the Player move seamlessly with colliders.
* Will correctly move and rotate the Player with colliders they stand on.
* Behavior is enabled/disabled based on GameObject layers.
* Correct physics/momentum when jumping off of moving colliders.
* Ability to stop moving the player when they are accessing their menu(s)
* Player will seamlessly teleport with colliders that get teleported / moved quickly.
(Additional)
Objects with Rigidbodies that have Interpolate or Extrapolate set that move on FixedUpdate can have issues with fast linear vertical movement causing the player to detach from the platform, this includes any object that uses VRC Object Sync as it silently overrides Rigidody Interpolation settings.
If your world utilizes VRCPlayerAPI.Immobilize the ReduceIKDrift setting may interfere with it.

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: db662579ba3593148b303296058d2e10
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: a80f329631af0714bbfe6836f43beeb7
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 324706932a8965e44b4dce80c3bf5701
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 11400000
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,249 @@
using UnityEngine;
using VRC.SDKBase;
using VRC.Udon.Common;
using UdonSharp;
using VRC.Udon.Wrapper.Modules;
namespace Superbstingray
{
[UdonBehaviourSyncMode(BehaviourSyncMode.NoVariableSync)]
public class UdonPlatformHook : UdonSharp.UdonSharpBehaviour
{
[Tooltip("Layers that the Player will move with.")]
public LayerMask hookLayerMask;
[Tooltip("Vertical distance between the Player and Platform before the Script Unhooks from Colliders. You may want to increase this value if your world has a higher than average jump impulse.")]
public float hookDistance = 0.75F;
[Tooltip("Will make the Player keep their Velocity + the Platforms Velocity when they detach from it.")]
public bool inheritVelocity = true;
[Tooltip("Will Immobilize(true) players when standing still on moving platforms to prevent Avatars from having IK drift / IK walk.")]
public bool reduceIKDrift = true;
[Tooltip("Try Detect if the Player has their Main Menu open and stop moving them. Will help with menu interactions.")]
public bool mainMenuPause = true;
[Tooltip("Try Detect if the Player has their Quick Menu open and stop moving them. Will help with menu interactions.")]
public bool quickMenuPause = false;
BoxCollider platformOverride;
Collider[] colliderArray;
Collider sceneCollider;
Quaternion headRotation;
RaycastHit hitInfo;
Transform PlayerOffset, playerTracker, hook;
Vector3 playerVelocity, hookLastPos, hookOffsetPos, lastFramePos;
VRCPlayerApi localPlayer;
bool menuOpen;
float InputMoveH, InputMoveV;
int unhookThreshold, localColliders, intUI;
[FieldChangeCallback(nameof(isHookedCallback))]
bool isHooked;
bool isHookedCallback
{ set
{ isHooked = value;
if (isHooked) // isHooked=true functions
{
hook.localPosition = Vector3.zero; hook.eulerAngles = Vector3.zero;
platformOverride.enabled = true;
PlayerOffset.SetPositionAndRotation(hook.position, hook.rotation);
// When hooking count the number of PlayerLocal colliders the player has
// as this will help us know when the Player enters a station.
localColliders = Mathf.Clamp(Physics.OverlapSphere((localPlayer.GetPosition()), 1024f, 1024).Length, 1, 100);
}
else // isHooked=false functions
{
if(inheritVelocity) { localPlayer.SetVelocity(playerVelocity); } // Sets the players velocity to their actual worldspace velocity when they Unhook.
OverridesOff();
hook.localPosition = Vector3.zero; hook.eulerAngles = Vector3.zero;
PlayerOffset.SetPositionAndRotation(hook.position, hook.rotation);
}
}
}
void Start()
{
InitializeVariables();
IgnoreSceneCollision();
}
void FixedUpdate()
{
FixedUpdateFunctions();
}
void LateUpdate()
{
LateUpdateFunctions();
}
void FixedUpdateFunctions()
{
if (!VRC.SDKBase.Utilities.IsValid(localPlayer)) { return; }
if (isHooked && inheritVelocity) // Average the last X frames of the players global velocity.
{
playerVelocity = Vector3.ClampMagnitude((playerVelocity * 3f + (localPlayer.GetPosition() - lastFramePos) / Time.deltaTime) / 4f, 100f);
lastFramePos = localPlayer.GetPosition();
}
if (!menuOpen)
{
// Override_Spherecast. Set position of override collider.
Physics.SphereCast(localPlayer.GetPosition() + new Vector3(0F, .3f, 0f), 0.25f, Vector3.down, out hitInfo, 10f, hookLayerMask.value);
platformOverride.center = hitInfo.point;
// FixedUpdate_Spherecast. Check for valid platforms.
// Add to the unhookThreshold if it misses a valid platform and unhook if unhookThreshold is greater than X.
if (!Physics.SphereCast(localPlayer.GetPosition() + new Vector3(0f, .3f, 0f), 0.25f, Vector3.down, out hitInfo, hookDistance + .3f, hookLayerMask.value))
{
unhookThreshold++;
if (unhookThreshold > 10 && isHooked)
{
hook.parent = transform;
SetProgramVariable(nameof(isHooked), false);
SendCustomEventDelayedSeconds(nameof(OverridesOff), 0.5f);
}
}
}
}
void LateUpdateFunctions()
{
if (!VRC.SDKBase.Utilities.IsValid(localPlayer)) { return; }
#if !UNITY_EDITOR
if (isHooked) // Count the number of InterntalUI colliders as a means to know if the menu is open or not.
{
intUI = Physics.OverlapSphereNonAlloc(localPlayer.GetPosition(), 10f, colliderArray, 524288);
menuOpen = (mainMenuPause && (intUI >= 7 && intUI <= 14)) || (quickMenuPause && (intUI >= 15 && intUI <= 19));
}
if (isHooked && !menuOpen) // Move the parented hook to the Players position
{
hookLastPos = hook.position;
hook.position = localPlayer.GetPosition();
hookOffsetPos = hook.position - hookLastPos;
}
if (isHooked && menuOpen) { localPlayer.SetVelocity(Vector3.zero); } // Override Player Velocity to make it easier to use their menu.
// Teleport the player to the new offset position only if the players PlayerLocal collider count
// didn't decrease otherwise assume the player entered a station.
if (isHooked && !menuOpen)
{
playerTracker.SetPositionAndRotation(localPlayer.GetTrackingData(VRCPlayerApi.TrackingDataType.Origin).position, localPlayer.GetTrackingData(VRCPlayerApi.TrackingDataType.Origin).rotation);
PlayerOffset.SetPositionAndRotation(hook.position, hook.rotation);
if (Physics.OverlapSphere(localPlayer.GetPosition(), 1024f, 1024).Length >= localColliders)
{
localPlayer.TeleportTo(playerTracker.position - hookOffsetPos, playerTracker.rotation, VRC_SceneDescriptor.SpawnOrientation.AlignRoomWithSpawnPoint, true);
}
}
#else
// "EditorOnly" duplicate funtion from above specifically for CyanEmu/ClientSim as Origin tracking does not behave the same in editor as in client.
if (isHooked)
{
playerTracker.SetPositionAndRotation(localPlayer.GetPosition(), localPlayer.GetRotation());
PlayerOffset.SetPositionAndRotation(hook.position, hook.rotation);
if (Physics.OverlapSphere(localPlayer.GetPosition(), 1024f, 1024).Length >= localColliders)
{
localPlayer.TeleportTo(playerTracker.position - hookOffsetPos, playerTracker.rotation, VRC_SceneDescriptor.SpawnOrientation.AlignPlayerWithSpawnPoint, true);
hookOffsetPos = Vector3.zero;
}
}
#endif
// Players in Desktop or 3 Point tracking will have their Inverse Kinematics drag behind and "IK Walk" while being moved when they aren't intentionally locomoting.
// This function is to prevent that from occuring by Immobilizing the player when they are hooked to a platform and aren't moving relative to the platform.
// This is scuffed and I should optimize it.
if(reduceIKDrift && isHooked)
{
headRotation = localPlayer.GetTrackingData(VRCPlayerApi.TrackingDataType.Head).rotation;
localPlayer.Immobilize(!(InputMoveH * 0.1f + InputMoveV != 0f)
&& Mathf.Abs(playerVelocity.x) + Mathf.Abs(playerVelocity.z) > .1f
&& Mathf.Abs(localPlayer.GetVelocity().x) + Mathf.Abs(localPlayer.GetVelocity().z) < .01f
&& Quaternion.Angle(new Quaternion(0f, headRotation.y, 0f, headRotation.w).normalized, localPlayer.GetRotation()) < 90f);
}
// LateUpdate_Spherecast. Check for valid platforms.
if (Physics.SphereCast(localPlayer.GetPosition() + new Vector3(0f, .3f, 0f), 0.25f, Vector3.down, out hitInfo, hookDistance + .3f, hookLayerMask.value))
{
unhookThreshold = 0;
if (unhookThreshold < 10 && (localPlayer.IsPlayerGrounded())) // Hook to the valid platform if the Player is grounded.
{
hook.parent = hitInfo.transform;
SetProgramVariable(nameof(isHooked), true);
}
}
}
// INPUT EVENTS: MoveVertical, MoveHorizontal, InputJump.
public override void InputMoveVertical(float Value, UdonInputEventArgs InputMoveVerticalArgs)
{
InputMoveV = InputMoveVerticalArgs.floatValue;
}
public override void InputMoveHorizontal(float Value, UdonInputEventArgs InputMoveHorizontalArgs)
{
InputMoveH = InputMoveHorizontalArgs.floatValue;
}
public override void InputJump(bool outputJumpBool, UdonInputEventArgs inputJumpArgs)
{
if (reduceIKDrift) { localPlayer.Immobilize(false); }
}
// Reset prefab state and call unhook on Respawn.
public override void OnPlayerRespawn(VRCPlayerApi onPlayerRespawnPlayer)
{
hook.parent = transform;
unhookThreshold = System.Int32.MaxValue;
localPlayer.SetVelocity(Vector3.zero);
SetProgramVariable(nameof(isHooked), false);
OverridesOff();
}
// The prefab uses an additional overriding collider to prevent the VRC player controller from being affected by moving world
// colliders which can affect locomotion and animations, and this is to prevent the override collider from interacting with other colliders in the scene.
public void IgnoreSceneCollision()
{
SendCustomEventDelayedSeconds(nameof(IgnoreSceneCollision), 60f);
colliderArray = Physics.OverlapSphere(Vector3.zero, System.Single.MaxValue);
for (int i = 0; i < colliderArray.Length; i++)
{
sceneCollider = colliderArray[i];
if (VRC.SDKBase.Utilities.IsValid(sceneCollider))
{
Physics.IgnoreCollision(sceneCollider, platformOverride);
}
}
}
void InitializeVariables() // Set Prefab Variables
{
localPlayer = Networking.LocalPlayer;
if (!VRC.SDKBase.Utilities.IsValid(localPlayer)) { return; }
lastFramePos = localPlayer.GetPosition();
playerTracker = transform.GetChild(0).GetChild(0);
PlayerOffset = transform.GetChild(0);
hook = transform.GetChild(1);
platformOverride = transform.GetComponent<BoxCollider>();
platformOverride.size = new Vector3(0.5f, 0.05f, 0.5f);
transform.position = Vector3.zero;
if (hookLayerMask.value == -1) // Override if using "Everything" as a layermask to Everything -PlayerLocal,-MirrorReflection to prevent interference with the prefabs functionality.
{
hookLayerMask.value = -263369;
}
}
// Disable Override Collider and set Immobilize state false.
void OverridesOff()
{
if (!localPlayer.IsPlayerGrounded()) { platformOverride.enabled = false; }
if (reduceIKDrift) { localPlayer.Immobilize(false); }
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: c6ba0c440cd811d45b8c1ad93549ed19
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 04a153bd56e937d4cae0c0779f232e6a
PrefabImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant: