Added Unity project files
This commit is contained in:
@ -0,0 +1,293 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.IO;
|
||||
using UnityEngine;
|
||||
using VRC.SDKBase;
|
||||
|
||||
namespace VRC.SDK3.ClientSim
|
||||
{
|
||||
// Sends Events:
|
||||
// - ClientSimPlayerDeathStatusChangedEvent
|
||||
[AddComponentMenu("")]
|
||||
public class ClientSimCombatSystemHelper : ClientSimBehaviour, IVRC_Destructible
|
||||
{
|
||||
private static readonly string _visualDamagePrefabPath =
|
||||
Path.Combine("Assets", "VRChat Examples", "Prefabs", "VRCPlayerVisualDamage.prefab");
|
||||
|
||||
private VRCPlayerApi _player;
|
||||
private IClientSimEventDispatcher _eventDispatcher;
|
||||
private IClientSimProxyObjectProvider _proxyProvider;
|
||||
private ClientSimPlayerController _playerController;
|
||||
|
||||
// Make values public so users can see and modify these values at runtime.
|
||||
public bool respawnOnDeath;
|
||||
public bool resetHealthOnRespawn = true;
|
||||
public float respawnTime = 5f;
|
||||
public float maxPlayerHealth = 100;
|
||||
public float currentHealth = 100;
|
||||
public Transform respawnPoint;
|
||||
private GameObject _visualDamagePrefab;
|
||||
|
||||
private GameObject _visualDamageObj;
|
||||
private VRC_VisualDamage _visualDamage;
|
||||
|
||||
private bool _dead = false;
|
||||
|
||||
private static ClientSimCombatSystemHelper GetCombatHelper(VRCPlayerApi player)
|
||||
{
|
||||
return player.GetClientSimPlayer().GetCombatHelper();
|
||||
}
|
||||
|
||||
public static void CombatSetup(VRCPlayerApi player)
|
||||
{
|
||||
player.GetClientSimPlayer().InitializeCombat();
|
||||
}
|
||||
|
||||
public static void CombatSetMaxHitpoints(VRCPlayerApi player, float maxHealth)
|
||||
{
|
||||
ClientSimCombatSystemHelper combatHelper = GetCombatHelper(player);
|
||||
if (combatHelper == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
combatHelper.maxPlayerHealth = maxHealth;
|
||||
}
|
||||
|
||||
public static float CombatGetCurrentHitpoints(VRCPlayerApi player)
|
||||
{
|
||||
ClientSimCombatSystemHelper combatHelper = GetCombatHelper(player);
|
||||
if (combatHelper == null)
|
||||
{
|
||||
// If a player doesn't have combat setup, their hitpoints are -1.
|
||||
return -1;
|
||||
}
|
||||
return combatHelper.currentHealth;
|
||||
}
|
||||
|
||||
public static void CombatSetRespawn(VRCPlayerApi player, bool respawnOnDeath, float respawnTime, Transform spawnPoint)
|
||||
{
|
||||
ClientSimCombatSystemHelper combatHelper = GetCombatHelper(player);
|
||||
if (combatHelper == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
combatHelper.respawnOnDeath = respawnOnDeath;
|
||||
combatHelper.respawnTime = respawnTime;
|
||||
combatHelper.respawnPoint = spawnPoint;
|
||||
}
|
||||
|
||||
public static void CombatSetDamageGraphic(VRCPlayerApi player, GameObject visualDamage)
|
||||
{
|
||||
ClientSimCombatSystemHelper combatHelper = GetCombatHelper(player);
|
||||
if (combatHelper == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
combatHelper._visualDamagePrefab = visualDamage;
|
||||
}
|
||||
|
||||
public static IVRC_Destructible CombatGetDestructible(VRCPlayerApi player)
|
||||
{
|
||||
return GetCombatHelper(player);
|
||||
}
|
||||
|
||||
public static void CombatSetCurrentHitpoints(VRCPlayerApi player, float health)
|
||||
{
|
||||
ClientSimCombatSystemHelper combatHelper = GetCombatHelper(player);
|
||||
if (combatHelper == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (player.isLocal)
|
||||
{
|
||||
float delta = health - combatHelper.currentHealth;
|
||||
if (delta <= 0)
|
||||
{
|
||||
combatHelper.ApplyDamage(-delta);
|
||||
}
|
||||
else
|
||||
{
|
||||
combatHelper.ApplyHealing(delta);
|
||||
}
|
||||
}
|
||||
|
||||
combatHelper.currentHealth = health;
|
||||
}
|
||||
|
||||
public void Initialize(
|
||||
VRCPlayerApi player,
|
||||
IClientSimEventDispatcher eventDispatcher,
|
||||
IClientSimProxyObjectProvider proxyProvider,
|
||||
ClientSimPlayerController playerController)
|
||||
{
|
||||
_player = player;
|
||||
|
||||
// Values below will be null for remote players.
|
||||
_eventDispatcher = eventDispatcher;
|
||||
_playerController = playerController;
|
||||
_proxyProvider = proxyProvider;
|
||||
|
||||
// TODO add ragdoll to player avatar
|
||||
}
|
||||
|
||||
private void Start()
|
||||
{
|
||||
currentHealth = GetMaxHealth();
|
||||
CreateVisualDamage();
|
||||
}
|
||||
|
||||
private void CreateVisualDamage()
|
||||
{
|
||||
if (!_player.isLocal)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (_visualDamageObj != null)
|
||||
{
|
||||
Destroy(_visualDamageObj);
|
||||
}
|
||||
|
||||
GameObject damage = _visualDamagePrefab;
|
||||
#if UNITY_EDITOR
|
||||
// If damage prefab is null, try loading it from the sample prefabs
|
||||
if (damage == null)
|
||||
{
|
||||
damage = UnityEditor.AssetDatabase.LoadAssetAtPath<GameObject>(_visualDamagePrefabPath);
|
||||
}
|
||||
#endif
|
||||
if (damage != null)
|
||||
{
|
||||
_visualDamageObj = Instantiate(damage, _proxyProvider.CameraProxy().transform);
|
||||
_visualDamageObj.transform.localScale = new Vector3(40, 40, 40);
|
||||
_visualDamageObj.transform.localPosition = new Vector3(0, 0, 0.5f);
|
||||
|
||||
_visualDamage = _visualDamageObj.GetComponent<VRC_VisualDamage>();
|
||||
if (_visualDamage != null)
|
||||
{
|
||||
// VRChatBug: Visual Damage script is blacklisted in SDK3 and will be destroyed after spawning.
|
||||
DestroyImmediate(_visualDamage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public float GetMaxHealth()
|
||||
{
|
||||
return maxPlayerHealth;
|
||||
}
|
||||
|
||||
public float GetCurrentHealth()
|
||||
{
|
||||
return currentHealth;
|
||||
}
|
||||
|
||||
private void ApplyVisualDamage()
|
||||
{
|
||||
if (_visualDamage != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
_visualDamage.SetDamagePercent(1 - (currentHealth / maxPlayerHealth));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
this.LogWarning($"Error applying damage: {e}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void ApplyDamage(float damage)
|
||||
{
|
||||
if (!_player.isLocal)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (currentHealth <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
this.Log($"ApplyDamage: {damage} currentHealth: {currentHealth}");
|
||||
|
||||
currentHealth = Mathf.Clamp(currentHealth - damage, 0, maxPlayerHealth);
|
||||
ApplyVisualDamage();
|
||||
|
||||
if (currentHealth <= 0 && !_dead)
|
||||
{
|
||||
_dead = true;
|
||||
this.Log("Player Died");
|
||||
|
||||
_player.EnablePickups(false);
|
||||
_eventDispatcher?.SendEvent(new ClientSimPlayerDeathStatusChangedEvent
|
||||
{
|
||||
player = _player,
|
||||
isDead = true,
|
||||
});
|
||||
|
||||
StartCoroutine(PlayerDied());
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerator PlayerDied()
|
||||
{
|
||||
yield return new WaitForSeconds(respawnTime);
|
||||
|
||||
RevivePlayer();
|
||||
}
|
||||
|
||||
private void RevivePlayer()
|
||||
{
|
||||
if (!_player.isLocal)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_dead = false;
|
||||
this.Log("Player Revived");
|
||||
|
||||
_player.EnablePickups(true);
|
||||
|
||||
if (respawnPoint != null && respawnOnDeath)
|
||||
{
|
||||
_playerController.Teleport(respawnPoint, false);
|
||||
}
|
||||
|
||||
if (resetHealthOnRespawn)
|
||||
{
|
||||
ApplyHealing(maxPlayerHealth);
|
||||
}
|
||||
|
||||
_eventDispatcher?.SendEvent(new ClientSimPlayerDeathStatusChangedEvent
|
||||
{
|
||||
player = _player,
|
||||
isDead = false,
|
||||
});
|
||||
}
|
||||
|
||||
public void ApplyHealing(float healing)
|
||||
{
|
||||
if (!_player.isLocal)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
currentHealth = Mathf.Clamp(currentHealth + healing, 0, maxPlayerHealth);
|
||||
ApplyVisualDamage();
|
||||
|
||||
this.Log($"ApplyHealing: {healing} currentHealth: {currentHealth}");
|
||||
}
|
||||
|
||||
public object[] GetState()
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
|
||||
public void SetState(object[] state)
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e569e5d477213484e9111d560a39cafc
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,77 @@
|
||||
using UnityEngine;
|
||||
using VRC.SDK3.Components;
|
||||
|
||||
namespace VRC.SDK3.ClientSim
|
||||
{
|
||||
[AddComponentMenu("")]
|
||||
public class ClientSimObjectPoolHelper : ClientSimBehaviour, IClientSimSyncable
|
||||
{
|
||||
private int _ownerID = 1;
|
||||
private VRCObjectPool _objectPool;
|
||||
|
||||
private IClientSimSyncedObjectManager _syncedObjectManager;
|
||||
|
||||
|
||||
public static void OnSpawn(VRCObjectPool objectPool, int index)
|
||||
{
|
||||
ClientSimObjectPoolHelper poolHelper = objectPool.GetComponent<ClientSimObjectPoolHelper>();
|
||||
if (!poolHelper)
|
||||
{
|
||||
throw new ClientSimException("Object Pool has not been initialized yet before trying to spawn an object.");
|
||||
}
|
||||
poolHelper.OnObjectSpawned(index);
|
||||
}
|
||||
|
||||
public static void OnReturn(VRCObjectPool objectPool, int index)
|
||||
{
|
||||
ClientSimObjectPoolHelper poolHelper = objectPool.GetComponent<ClientSimObjectPoolHelper>();
|
||||
if (!poolHelper)
|
||||
{
|
||||
throw new ClientSimException("Object Pool has not been initialized yet before trying to return an object.");
|
||||
}
|
||||
poolHelper.OnObjectReturned(index);
|
||||
}
|
||||
|
||||
|
||||
public void Initialize(VRCObjectPool objectPool, IClientSimSyncedObjectManager syncedObjectManager)
|
||||
{
|
||||
_objectPool = objectPool;
|
||||
_syncedObjectManager = syncedObjectManager;
|
||||
syncedObjectManager.AddSyncedObject(this);
|
||||
}
|
||||
|
||||
private void Start()
|
||||
{
|
||||
// Catch Helper not initialized.
|
||||
if (_objectPool == null)
|
||||
{
|
||||
this.LogWarning($"Destroying uninitialized Helper. Object: {Tools.GetGameObjectPath(gameObject)}");
|
||||
DestroyImmediate(this);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
// Nullable needed for uninitialized case.
|
||||
_syncedObjectManager?.RemoveSyncedObject(this);
|
||||
}
|
||||
|
||||
private void OnObjectSpawned(int index) { }
|
||||
|
||||
private void OnObjectReturned(int index) { }
|
||||
|
||||
#region IClientSimSyncable
|
||||
|
||||
public int GetOwner()
|
||||
{
|
||||
return _ownerID;
|
||||
}
|
||||
|
||||
public void SetOwner(int ownerID)
|
||||
{
|
||||
_ownerID = ownerID;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: aae00de63d785d5468f307e29acf4ab7
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,68 @@
|
||||
using UnityEngine;
|
||||
using VRC.SDK3.Components;
|
||||
|
||||
namespace VRC.SDK3.ClientSim
|
||||
{
|
||||
[AddComponentMenu("")]
|
||||
public class ClientSimObjectSyncHelper : ClientSimPositionSyncedHelperBase
|
||||
{
|
||||
private VRCObjectSync _sync;
|
||||
|
||||
public static void TeleportTo(VRCObjectSync obj, Vector3 position, Quaternion rotation)
|
||||
{
|
||||
obj.GetComponent<ClientSimObjectSyncHelper>().TeleportTo(position, rotation);
|
||||
}
|
||||
|
||||
public static void RespawnObject(VRCObjectSync sync)
|
||||
{
|
||||
sync.GetComponent<ClientSimObjectSyncHelper>().Respawn();
|
||||
}
|
||||
|
||||
public static void SetIsKinematic(VRCObjectSync sync, bool value)
|
||||
{
|
||||
sync.GetComponent<ClientSimObjectSyncHelper>().SetIsKinematic(value);
|
||||
}
|
||||
|
||||
public static void SetUseGravity(VRCObjectSync sync, bool value)
|
||||
{
|
||||
sync.GetComponent<ClientSimObjectSyncHelper>().SetUseGravity(value);
|
||||
}
|
||||
|
||||
public static bool GetIsKinematic(VRCObjectSync sync)
|
||||
{
|
||||
return sync.GetComponent<ClientSimObjectSyncHelper>().GetIsKinematic();
|
||||
}
|
||||
|
||||
public static bool GetUseGravity(VRCObjectSync sync)
|
||||
{
|
||||
return sync.GetComponent<ClientSimObjectSyncHelper>().GetUseGravity();
|
||||
}
|
||||
|
||||
public static void FlagDiscontinuityHook(VRCObjectSync sync)
|
||||
{
|
||||
sync.GetComponent<ClientSimObjectSyncHelper>().FlagDiscontinuity();
|
||||
}
|
||||
|
||||
protected override void Awake()
|
||||
{
|
||||
base.Awake();
|
||||
SyncPosition = true;
|
||||
}
|
||||
|
||||
public void Initialize(VRCObjectSync sync, IClientSimSyncedObjectManager syncedObjectManager)
|
||||
{
|
||||
base.Initialize(syncedObjectManager);
|
||||
_sync = sync;
|
||||
}
|
||||
|
||||
private void Start()
|
||||
{
|
||||
// Catch Helper not initialized.
|
||||
if (_sync == null)
|
||||
{
|
||||
this.LogWarning($"Destroying uninitialized Helper. Object: {Tools.GetGameObjectPath(gameObject)}");
|
||||
DestroyImmediate(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 589d092631b45f945ace85beb794e76c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,172 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
using VRC.SDKBase;
|
||||
|
||||
namespace VRC.SDK3.ClientSim
|
||||
{
|
||||
[AddComponentMenu("")]
|
||||
public class ClientSimPickupHelper : ClientSimBehaviour, IClientSimPickupable
|
||||
{
|
||||
private Rigidbody _rigidbody;
|
||||
private VRC_Pickup _pickup;
|
||||
|
||||
private VRCPlayerApi _heldPlayer;
|
||||
private VRC_Pickup.PickupHand _heldHand;
|
||||
private Action<IClientSimPickupable> _forceDropHandler;
|
||||
|
||||
public static void InitializePickup(VRC_Pickup pickup)
|
||||
{
|
||||
ClientSimPickupHelper previousHelper = pickup.gameObject.GetComponent<ClientSimPickupHelper>();
|
||||
if (previousHelper != null)
|
||||
{
|
||||
DestroyImmediate(previousHelper);
|
||||
pickup.LogWarning($"Destroying old pickup helper on object: {Tools.GetGameObjectPath(pickup.gameObject)}");
|
||||
}
|
||||
|
||||
ClientSimPickupHelper helper = pickup.gameObject.AddComponent<ClientSimPickupHelper>();
|
||||
helper.SetPickup(pickup);
|
||||
}
|
||||
|
||||
public static void ForceDrop(VRC_Pickup pickup)
|
||||
{
|
||||
ClientSimPickupHelper helper = pickup.GetComponent<ClientSimPickupHelper>();
|
||||
if (helper)
|
||||
{
|
||||
helper._forceDropHandler?.Invoke(helper);
|
||||
}
|
||||
}
|
||||
|
||||
public static VRCPlayerApi GetCurrentPlayer(VRC_Pickup pickup)
|
||||
{
|
||||
ClientSimPickupHelper helper = pickup.GetComponent<ClientSimPickupHelper>();
|
||||
|
||||
if (!helper)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return helper.GetHoldingPlayer();
|
||||
}
|
||||
|
||||
public static VRC_Pickup.PickupHand GetPickupHand(VRC_Pickup pickup)
|
||||
{
|
||||
ClientSimPickupHelper helper = pickup.GetComponent<ClientSimPickupHelper>();
|
||||
if (helper)
|
||||
{
|
||||
return helper._heldHand;
|
||||
}
|
||||
return VRC_Pickup.PickupHand.None;
|
||||
}
|
||||
|
||||
public static void PickupDestroy(VRC_Pickup pickup)
|
||||
{
|
||||
ForceDrop(pickup);
|
||||
}
|
||||
|
||||
public static void PlayHapticForPickup(VRC_Pickup obj, float duration, float amplitude, float frequency)
|
||||
{
|
||||
VRCPlayerApi player = obj.currentPlayer;
|
||||
VRC_Pickup.PickupHand hand = obj.currentHand;
|
||||
if (Utilities.IsValid(player) && hand != VRC_Pickup.PickupHand.None)
|
||||
{
|
||||
player.PlayHapticEventInHand(obj.currentHand, duration, amplitude, frequency);
|
||||
}
|
||||
}
|
||||
|
||||
private void SetPickup(VRC_Pickup pickup)
|
||||
{
|
||||
_pickup = pickup;
|
||||
_rigidbody = GetComponent<Rigidbody>();
|
||||
}
|
||||
|
||||
|
||||
#region IClientSimInteractible
|
||||
|
||||
public float GetProximity()
|
||||
{
|
||||
return _pickup.proximity;
|
||||
}
|
||||
|
||||
public bool CanInteract()
|
||||
{
|
||||
return _pickup.pickupable;
|
||||
}
|
||||
|
||||
public string GetInteractText()
|
||||
{
|
||||
if (!string.IsNullOrEmpty(_pickup.InteractionText))
|
||||
{
|
||||
return _pickup.InteractionText;
|
||||
}
|
||||
|
||||
return AutoHold() ? "Equip" : "Hold to Grab";
|
||||
}
|
||||
|
||||
public Vector3 GetInteractTextPlacement()
|
||||
{
|
||||
// VRChatBug: Tooltips always ignore the tooltipPlacement transform and instead place the tooltip at the top
|
||||
// of the first collider on the object.
|
||||
return ClientSimTooltip.GetToolTipPosition(gameObject);
|
||||
}
|
||||
|
||||
public void Interact() { }
|
||||
|
||||
#endregion
|
||||
|
||||
#region IClientSimPickupable
|
||||
|
||||
public void Pickup(VRCPlayerApi player, VRC_Pickup.PickupHand heldHand, Action<IClientSimPickupable> forceDropHandler)
|
||||
{
|
||||
if (IsHeld())
|
||||
{
|
||||
return;
|
||||
}
|
||||
_heldPlayer = player;
|
||||
_heldHand = heldHand;
|
||||
_forceDropHandler = forceDropHandler;
|
||||
}
|
||||
|
||||
public void Drop(VRCPlayerApi player)
|
||||
{
|
||||
if (GetHoldingPlayer() != player)
|
||||
{
|
||||
return;
|
||||
}
|
||||
_heldPlayer = null;
|
||||
_heldHand = VRC_Pickup.PickupHand.None;
|
||||
_forceDropHandler = null;
|
||||
}
|
||||
|
||||
public bool IsHeld() => Utilities.IsValid(_heldPlayer);
|
||||
|
||||
public VRCPlayerApi GetHoldingPlayer() => IsHeld() ? _heldPlayer : null;
|
||||
|
||||
public bool AutoHold() => _pickup.AutoHold is VRC_Pickup.AutoHoldMode.Yes or VRC_Pickup.AutoHoldMode.Sometimes;
|
||||
|
||||
public GameObject GetGameObject() => gameObject;
|
||||
|
||||
public Transform GetTransform() => transform;
|
||||
|
||||
public Rigidbody GetRigidbody() => _rigidbody;
|
||||
|
||||
public VRC_Pickup GetPickup() => _pickup;
|
||||
|
||||
public VRC_Pickup.PickupOrientation GetOrientation() => _pickup.orientation;
|
||||
|
||||
public Transform GetGunLocation() => _pickup.ExactGun;
|
||||
|
||||
public Transform GetGripLocation() => _pickup.ExactGrip;
|
||||
|
||||
public float GetThrowVelocityBoostScale() => _pickup.ThrowVelocityBoostScale;
|
||||
|
||||
public bool AllowManipulation() => _pickup.allowManipulationWhenEquipped;
|
||||
|
||||
#endregion
|
||||
|
||||
// TODO display use text after picking up a pickup.
|
||||
public string PickupText()
|
||||
{
|
||||
return _pickup.UseText;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3202215373c7804408519f37ae740d55
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,7 @@
|
||||
namespace VRC.SDK3.ClientSim
|
||||
{
|
||||
public class IClientSimPlatformHelper
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9b649f5d029e44a281939561cd0adfd9
|
||||
timeCreated: 1698363870
|
||||
@ -0,0 +1,151 @@
|
||||
|
||||
using UnityEngine;
|
||||
|
||||
namespace VRC.SDK3.ClientSim
|
||||
{
|
||||
[AddComponentMenu("")]
|
||||
public abstract class ClientSimPositionSyncedHelperBase :
|
||||
ClientSimBehaviour,
|
||||
IClientSimSyncable,
|
||||
IClientSimPositionSyncable,
|
||||
IClientSimRespawnHandler
|
||||
{
|
||||
private int _ownerID = 1;
|
||||
private Vector3 _originalPosition;
|
||||
private Quaternion _originalRotation;
|
||||
|
||||
private Rigidbody _rigidbody;
|
||||
private bool _useGravity;
|
||||
private bool _isKinematic;
|
||||
|
||||
private IClientSimSyncedObjectManager _syncedObjectManager;
|
||||
|
||||
public bool SyncPosition { get; protected set; }
|
||||
|
||||
protected override void Awake()
|
||||
{
|
||||
base.Awake();
|
||||
|
||||
_originalPosition = transform.position;
|
||||
_originalRotation = transform.rotation;
|
||||
_rigidbody = GetComponent<Rigidbody>();
|
||||
|
||||
if (_rigidbody != null)
|
||||
{
|
||||
_isKinematic = _rigidbody.isKinematic;
|
||||
_useGravity = _rigidbody.useGravity;
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void Initialize(IClientSimSyncedObjectManager syncedObjectManager)
|
||||
{
|
||||
_syncedObjectManager = syncedObjectManager;
|
||||
_syncedObjectManager.AddSyncedObject(this);
|
||||
}
|
||||
|
||||
protected virtual void OnDestroy()
|
||||
{
|
||||
// Nullable needed for uninitialized case.
|
||||
_syncedObjectManager?.RemoveSyncedObject(this);
|
||||
}
|
||||
|
||||
public void TeleportTo(Vector3 position, Quaternion rotation)
|
||||
{
|
||||
this.Log($"Teleporting Object {Tools.GetGameObjectPath(gameObject)} to {position} and rotation {rotation.eulerAngles}");
|
||||
FlagDiscontinuity();
|
||||
transform.SetPositionAndRotation(position, rotation);
|
||||
}
|
||||
|
||||
public void FlagDiscontinuity()
|
||||
{
|
||||
// TODO As of right now, ClientSim doesn't handle any actual sync.
|
||||
}
|
||||
|
||||
#region IClientSimSyncable
|
||||
|
||||
public int GetOwner()
|
||||
{
|
||||
return _ownerID;
|
||||
}
|
||||
|
||||
public void SetOwner(int ownerID)
|
||||
{
|
||||
_ownerID = ownerID;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IClientSimRespawnable
|
||||
|
||||
public void Respawn()
|
||||
{
|
||||
this.Log($"Respawning Object {Tools.GetGameObjectPath(gameObject)}");
|
||||
TeleportTo(_originalPosition, _originalRotation);
|
||||
|
||||
if (_rigidbody != null)
|
||||
{
|
||||
_rigidbody.velocity = Vector3.zero;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IClientSimPositionSyncable
|
||||
|
||||
public void SetIsKinematic(bool value)
|
||||
{
|
||||
_isKinematic = value;
|
||||
if (_rigidbody)
|
||||
{
|
||||
_rigidbody.isKinematic = value;
|
||||
}
|
||||
}
|
||||
|
||||
public void SetUseGravity(bool value)
|
||||
{
|
||||
_useGravity = value;
|
||||
if (_rigidbody)
|
||||
{
|
||||
_rigidbody.useGravity = value;
|
||||
}
|
||||
}
|
||||
|
||||
public bool GetIsKinematic()
|
||||
{
|
||||
return _rigidbody && _rigidbody.isKinematic;
|
||||
}
|
||||
|
||||
public bool GetUseGravity()
|
||||
{
|
||||
return _rigidbody && _rigidbody.useGravity;
|
||||
}
|
||||
|
||||
public void UpdatePositionSync()
|
||||
{
|
||||
if (_rigidbody != null)
|
||||
{
|
||||
// TODO if user is not the owner, set useGravity to false, isKinematic to true.
|
||||
// This would better simulate ownership, but also make testing awkward.
|
||||
|
||||
if (_rigidbody.isKinematic != _isKinematic)
|
||||
{
|
||||
_rigidbody.isKinematic = _isKinematic;
|
||||
this.LogWarning($"Rigidbody.isKinematic was set outside of VRCObjectSync.SetKinematic method! {Tools.GetGameObjectPath(gameObject)}");
|
||||
}
|
||||
|
||||
if (_rigidbody.useGravity != _useGravity)
|
||||
{
|
||||
_rigidbody.useGravity = _useGravity;
|
||||
this.LogWarning($"Rigidbody.useGravity was set outside of VRCObjectSync.SetGravity method! {Tools.GetGameObjectPath(gameObject)}");
|
||||
}
|
||||
|
||||
// VRChatBug: Modifying a collider's "is Trigger" property is also restricted when VRCObjectSync is on
|
||||
// the same object, but this check will not be added.
|
||||
}
|
||||
}
|
||||
|
||||
public Transform GetTransform() => transform;
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a751849f43f6c724a8ce7ad9766b132c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,181 @@
|
||||
using UnityEngine;
|
||||
using VRC.SDKBase;
|
||||
|
||||
namespace VRC.SDK3.ClientSim
|
||||
{
|
||||
[AddComponentMenu("")]
|
||||
[DisallowMultipleComponent]
|
||||
public class ClientSimSpatialAudioHelper : ONSPAudioSource
|
||||
{
|
||||
private const float EPS = 1e-3f;
|
||||
|
||||
private VRC_SpatialAudioSource _spatialAudioSource;
|
||||
private AudioSource _audioSource;
|
||||
private bool _useAudioSourceCurve;
|
||||
private ONSPAudioSource _onsp;
|
||||
private bool _forceUpdate = true;
|
||||
private bool _updateONSPParams;
|
||||
|
||||
public static void InitializeAudio(VRC_SpatialAudioSource obj)
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
// VRC_SpatialAudioSource executes in editor, meaning it will try to initialize even outside of playmode.
|
||||
// This code is to prevent adding the ClientSim helper in these cases.
|
||||
if (!UnityEditor.EditorApplication.isPlayingOrWillChangePlaymode ||
|
||||
UnityEditor.SceneManagement.EditorSceneManager.IsPreviewSceneObject(obj))
|
||||
{
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
ClientSimSpatialAudioHelper spatialAudio = obj.GetComponent<ClientSimSpatialAudioHelper>();
|
||||
if (spatialAudio != null)
|
||||
{
|
||||
DestroyImmediate(spatialAudio);
|
||||
}
|
||||
|
||||
spatialAudio = obj.gameObject.AddComponent<ClientSimSpatialAudioHelper>();
|
||||
spatialAudio.PreventComponentFromSaving();
|
||||
spatialAudio.SetSpatializer(obj);
|
||||
}
|
||||
|
||||
private void SetSpatializer(VRC_SpatialAudioSource obj)
|
||||
{
|
||||
_spatialAudioSource = obj;
|
||||
_audioSource = GetComponent<AudioSource>();
|
||||
_onsp = this;
|
||||
_forceUpdate = true;
|
||||
|
||||
UpdateSettings();
|
||||
}
|
||||
|
||||
private void Start()
|
||||
{
|
||||
// Catch Helper not initialized.
|
||||
if (_spatialAudioSource == null)
|
||||
{
|
||||
this.LogWarning($"Destroying uninitialized Helper. Object: {Tools.GetGameObjectPath(gameObject)}");
|
||||
DestroyImmediate(this);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
// ONSP needs to reapply audio settings everytime the object is enabled.
|
||||
_forceUpdate = true;
|
||||
_updateONSPParams = true;
|
||||
}
|
||||
|
||||
// Late update to help with testing
|
||||
private void LateUpdate()
|
||||
{
|
||||
UpdateSettings();
|
||||
}
|
||||
|
||||
private void UpdateSettings()
|
||||
{
|
||||
if (_spatialAudioSource == null)
|
||||
{
|
||||
_spatialAudioSource = GetComponent<VRC_SpatialAudioSource>();
|
||||
if (_spatialAudioSource == null)
|
||||
{
|
||||
Destroy(this);
|
||||
}
|
||||
SetSpatializer(_spatialAudioSource);
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if we need to make changes.
|
||||
if (
|
||||
_onsp.EnableSpatialization != _spatialAudioSource.EnableSpatialization ||
|
||||
_onsp.Gain != _spatialAudioSource.Gain ||
|
||||
_onsp.Near != _spatialAudioSource.Near ||
|
||||
_onsp.Far != _spatialAudioSource.Far ||
|
||||
_useAudioSourceCurve != _spatialAudioSource.UseAudioSourceVolumeCurve
|
||||
) {
|
||||
_forceUpdate = true;
|
||||
_updateONSPParams = true;
|
||||
}
|
||||
|
||||
_onsp.EnableSpatialization = _spatialAudioSource.EnableSpatialization;
|
||||
_onsp.Gain = _spatialAudioSource.Gain;
|
||||
_useAudioSourceCurve = _spatialAudioSource.UseAudioSourceVolumeCurve;
|
||||
_onsp.Near = _spatialAudioSource.Near;
|
||||
_onsp.Far = _spatialAudioSource.Far;
|
||||
_onsp.VolumetricRadius = _spatialAudioSource.VolumetricRadius;
|
||||
|
||||
// In unity 2022 - updating ONSP params every frame can cause a logspam
|
||||
// This is a workaround to only update when needed
|
||||
if (_updateONSPParams)
|
||||
{
|
||||
_onsp.SetParameters(ref _audioSource);
|
||||
_updateONSPParams = false;
|
||||
}
|
||||
|
||||
if (!_onsp.EnableSpatialization)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_forceUpdate)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_forceUpdate = false;
|
||||
|
||||
if (!_spatialAudioSource.UseAudioSourceVolumeCurve)
|
||||
{
|
||||
float near = _onsp.VolumetricRadius + _onsp.Near;
|
||||
float far = _onsp.VolumetricRadius + Mathf.Max(near, _onsp.Far + EPS);
|
||||
|
||||
_audioSource.maxDistance = far;
|
||||
|
||||
CreateRolloffCurve(near, far);
|
||||
CreateSpatialCurve(near, far);
|
||||
}
|
||||
}
|
||||
|
||||
// Create volume rolloff curve where Volumetric + near is volume 1, then 2^-x fall off to far.
|
||||
private void CreateRolloffCurve(float near, float far)
|
||||
{
|
||||
_audioSource.rolloffMode = AudioRolloffMode.Custom;
|
||||
|
||||
AnimationCurve curve = new AnimationCurve();
|
||||
curve.AddKey(new Keyframe(near, 1));
|
||||
int max = 8;
|
||||
for (int loc = 1; loc < max; ++loc)
|
||||
{
|
||||
float time = near + Mathf.Pow(2, loc - max) * (far - near);
|
||||
float value = Mathf.Pow(2.2f, -loc);
|
||||
curve.AddKey(new Keyframe(time, value));
|
||||
}
|
||||
curve.AddKey(new Keyframe(far, 0));
|
||||
|
||||
for (int i = 0; i < curve.length; ++i)
|
||||
{
|
||||
curve.SmoothTangents(i, 0);
|
||||
}
|
||||
|
||||
_audioSource.SetCustomCurve(AudioSourceCurveType.CustomRolloff, curve);
|
||||
}
|
||||
|
||||
// Create spatial blend curve so that it goes from (Setting) to 3d from min to max
|
||||
private void CreateSpatialCurve(float near, float far)
|
||||
{
|
||||
AnimationCurve spatialCurve = new AnimationCurve();
|
||||
spatialCurve.AddKey(0, _audioSource.spatialBlend);
|
||||
spatialCurve.AddKey(_onsp.VolumetricRadius, _audioSource.spatialBlend);
|
||||
|
||||
Keyframe nearFrame = new Keyframe(near + EPS, 1);
|
||||
nearFrame.outTangent = 0;
|
||||
spatialCurve.AddKey(nearFrame);
|
||||
|
||||
Keyframe farFrame = new Keyframe(far, 1);
|
||||
farFrame.inTangent = 0;
|
||||
spatialCurve.AddKey(farFrame);
|
||||
|
||||
_audioSource.SetCustomCurve(AudioSourceCurveType.SpatialBlend, spatialCurve);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c1c30c850f67fff48a0e69a3e8fa4373
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,175 @@
|
||||
|
||||
using System.IO;
|
||||
using UnityEngine;
|
||||
using VRC.SDKBase;
|
||||
using VRC.Udon;
|
||||
using VRC.Udon.Common;
|
||||
|
||||
namespace VRC.SDK3.ClientSim
|
||||
{
|
||||
[AddComponentMenu("")]
|
||||
public class ClientSimStationHelper : ClientSimBehaviour, IClientSimStation
|
||||
{
|
||||
private VRCStation _station;
|
||||
private VRCPlayerApi _usingPlayer;
|
||||
|
||||
public Transform EnterLocation() => _station.stationEnterPlayerLocation;
|
||||
|
||||
public Transform ExitLocation() => _station.stationExitPlayerLocation;
|
||||
|
||||
public bool IsMobile() =>
|
||||
_station.PlayerMobility == VRCStation.Mobility.Mobile &&
|
||||
!_station.seated;
|
||||
|
||||
public bool IsSeated() => _station.seated;
|
||||
|
||||
public bool DisableStationExit() => _station.disableStationExit;
|
||||
|
||||
public bool CanUseStationFromStation() => _station.canUseStationFromStation;
|
||||
|
||||
public bool IsLockedInStation() => !IsMobile();
|
||||
|
||||
public VRCStation GetStation() => _station;
|
||||
|
||||
public GameObject GetStationGameObject() => gameObject;
|
||||
|
||||
public Transform GetStationTransform() => transform;
|
||||
|
||||
public bool IsOccupied() => _usingPlayer != null;
|
||||
|
||||
public VRCPlayerApi GetCurrentSittingPlayer() => _usingPlayer;
|
||||
|
||||
public static void InitializeStations(VRCStation station)
|
||||
{
|
||||
ClientSimStationHelper prevHelper = station.gameObject.GetComponent<ClientSimStationHelper>();
|
||||
if (prevHelper != null)
|
||||
{
|
||||
DestroyImmediate(prevHelper);
|
||||
station.LogWarning($"Destroying old station helper on object: {Tools.GetGameObjectPath(station.gameObject)}");
|
||||
}
|
||||
|
||||
station.gameObject.AddComponent<ClientSimStationHelper>();
|
||||
}
|
||||
|
||||
public static void UseAttachedStation(VRCPlayerApi player)
|
||||
{
|
||||
// UseAttachedStation is a method in the VRCPlayerApi class. This method will take the given player and try to put them in the station component on the GameObject running this Udon program. Since the GameObject is not provided in the parameters, it must be retrieved from the UdonManager by checking the current executing UdonBehaviour.
|
||||
UdonBehaviour currentUdon = UdonManager.Instance.currentlyExecuting;
|
||||
if (currentUdon == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
VRCStation station = currentUdon.GetComponent<VRCStation>();
|
||||
if (station == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
UseStation(station, player);
|
||||
}
|
||||
|
||||
public static void UseStation(VRCStation station, VRCPlayerApi player)
|
||||
{
|
||||
if (!player.isLocal)
|
||||
{
|
||||
station.LogWarning($"Trying to force a remote player to enter a station. Force enter a station can only be done for the local player. PlayerId: {player.playerId}, Station: {Tools.GetGameObjectPath(station.gameObject)}");
|
||||
return;
|
||||
}
|
||||
|
||||
ClientSimStationHelper helper = station.GetComponent<ClientSimStationHelper>();
|
||||
ClientSimPlayer clientPlayer = player.GetClientSimPlayer();
|
||||
if (helper != null && clientPlayer != null)
|
||||
{
|
||||
clientPlayer.GetStationHandler().EnterStation(helper);
|
||||
}
|
||||
}
|
||||
|
||||
public static void ExitStation(VRCStation station, VRCPlayerApi player)
|
||||
{
|
||||
if (!player.isLocal)
|
||||
{
|
||||
station.LogWarning($"Trying to force a remote player to exit a station. Force exit a station can only be done for the local player. PlayerId: {player.playerId}, Station: {Tools.GetGameObjectPath(station.gameObject)}");
|
||||
return;
|
||||
}
|
||||
|
||||
ClientSimStationHelper helper = station.GetComponent<ClientSimStationHelper>();
|
||||
ClientSimPlayer clientPlayer = player.GetClientSimPlayer();
|
||||
if (helper != null && clientPlayer != null)
|
||||
{
|
||||
clientPlayer.GetStationHandler().ExitStation(helper);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void Awake()
|
||||
{
|
||||
base.Awake();
|
||||
|
||||
_station = GetComponent<VRCStation>();
|
||||
|
||||
CheckForMissingComponents();
|
||||
|
||||
if (_station.stationEnterPlayerLocation == null)
|
||||
{
|
||||
_station.stationEnterPlayerLocation = transform;
|
||||
}
|
||||
if (_station.stationExitPlayerLocation == null)
|
||||
{
|
||||
_station.stationExitPlayerLocation = transform;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
if (_usingPlayer != null)
|
||||
{
|
||||
ExitStation(_station, _usingPlayer);
|
||||
}
|
||||
}
|
||||
|
||||
private void CheckForMissingComponents()
|
||||
{
|
||||
Collider stationCollider = GetComponent<Collider>();
|
||||
if (stationCollider == null)
|
||||
{
|
||||
gameObject.AddComponent<BoxCollider>().isTrigger = true;
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
UdonBehaviour udon = GetComponent<UdonBehaviour>();
|
||||
if (udon == null)
|
||||
{
|
||||
udon = gameObject.AddComponent<UdonBehaviour>();
|
||||
udon.interactText = "Sit";
|
||||
|
||||
// TODO properly load udon chair program asset.
|
||||
string sitProgramPath = Path.Combine("Assets", "VRChat Examples", "Prefabs", "VRCChair", "StationGraph.asset");
|
||||
AbstractUdonProgramSource program = UnityEditor.AssetDatabase.LoadAssetAtPath<AbstractUdonProgramSource>(sitProgramPath);
|
||||
if (program != null)
|
||||
{
|
||||
udon.AssignProgramAndVariables(program.SerializedProgramAsset, new UdonVariableTable());
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
public void EnterStation(VRCPlayerApi player)
|
||||
{
|
||||
if (_usingPlayer != null || !player.isLocal)
|
||||
{
|
||||
return;
|
||||
}
|
||||
_usingPlayer = player;
|
||||
}
|
||||
|
||||
public void ExitStation(VRCPlayerApi player)
|
||||
{
|
||||
if (_usingPlayer != player)
|
||||
{
|
||||
return;
|
||||
}
|
||||
_usingPlayer = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 989fabbff35c3d845b1b0363b1709ea7
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,163 @@
|
||||
using System.Reflection;
|
||||
using UnityEngine;
|
||||
using VRC.SDKBase;
|
||||
using VRC.Udon;
|
||||
|
||||
namespace VRC.SDK3.ClientSim
|
||||
{
|
||||
[AddComponentMenu("")]
|
||||
public class ClientSimUdonHelper :
|
||||
ClientSimPositionSyncedHelperBase,
|
||||
IClientSimInteractable,
|
||||
IClientSimPickupHandler,
|
||||
IClientSimStationHandler,
|
||||
IClientSimSyncableHandler
|
||||
{
|
||||
private IClientSimUdonManager _udonManager;
|
||||
private UdonBehaviour _udonBehaviour;
|
||||
|
||||
private static readonly FieldInfo _isReady =
|
||||
typeof(UdonBehaviour).GetField("_isReady", (BindingFlags.Instance | BindingFlags.NonPublic));
|
||||
|
||||
public void Initialize(
|
||||
UdonBehaviour udonBehaviour,
|
||||
IClientSimUdonManager udonManager,
|
||||
IClientSimSyncedObjectManager syncedObjectManager,
|
||||
bool isReady)
|
||||
{
|
||||
_udonBehaviour = udonBehaviour;
|
||||
#pragma warning disable 618
|
||||
SyncPosition = _udonBehaviour.SynchronizePosition;
|
||||
#pragma warning restore 618
|
||||
|
||||
SetIsReady(isReady);
|
||||
|
||||
_udonManager = udonManager;
|
||||
_udonManager.AddUdonBehaviour(_udonBehaviour);
|
||||
|
||||
// Ensure that SyncPosition is set before calling this.
|
||||
base.Initialize(syncedObjectManager);
|
||||
}
|
||||
|
||||
private void Start()
|
||||
{
|
||||
// Catch Helper not initialized.
|
||||
if (_udonBehaviour == null)
|
||||
{
|
||||
this.LogWarning($"Destroying uninitialized Helper. Object: {Tools.GetGameObjectPath(gameObject)}");
|
||||
DestroyImmediate(this);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnDestroy()
|
||||
{
|
||||
base.OnDestroy();
|
||||
|
||||
// Nullable needed for uninitialized case.
|
||||
_udonManager?.RemoveUdonBehaviour(_udonBehaviour);
|
||||
}
|
||||
|
||||
private void SetIsReady(bool isReady)
|
||||
{
|
||||
_isReady.SetValue(_udonBehaviour, isReady);
|
||||
}
|
||||
|
||||
public void OnReady()
|
||||
{
|
||||
SetIsReady(true);
|
||||
}
|
||||
|
||||
public UdonBehaviour GetUdonBehaviour()
|
||||
{
|
||||
return _udonBehaviour;
|
||||
}
|
||||
|
||||
#region IClientSimSyncableHandler
|
||||
|
||||
public void OnOwnershipTransferred(int ownerID)
|
||||
{
|
||||
_udonBehaviour.RunEvent("_onOwnershipTransferred", ("Player", VRCPlayerApi.GetPlayerById(ownerID)));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IClientSimInteractable
|
||||
|
||||
public float GetProximity()
|
||||
{
|
||||
return _udonBehaviour.proximity;
|
||||
}
|
||||
|
||||
public bool CanInteract()
|
||||
{
|
||||
return _udonBehaviour.IsInteractive;
|
||||
}
|
||||
|
||||
public string GetInteractText()
|
||||
{
|
||||
return _udonBehaviour.interactText;
|
||||
}
|
||||
|
||||
public Vector3 GetInteractTextPlacement()
|
||||
{
|
||||
// VRChatBug: Tooltips always ignore the tooltipPlacement transform and instead place the tooltip at the top
|
||||
// of the first collider on the object.
|
||||
|
||||
//check if this object has already been destroyed, we can't just do a null check because that still throws a destroyed object error in unity
|
||||
if (!Utilities.IsValid(this))
|
||||
{
|
||||
return Vector3.zero;
|
||||
}
|
||||
|
||||
|
||||
return ClientSimTooltip.GetToolTipPosition(gameObject);
|
||||
}
|
||||
|
||||
public void Interact()
|
||||
{
|
||||
_udonBehaviour.Interact();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IClientSimPickupable
|
||||
|
||||
public void OnPickup()
|
||||
{
|
||||
_udonBehaviour.OnPickup();
|
||||
}
|
||||
|
||||
public void OnDrop()
|
||||
{
|
||||
_udonBehaviour.OnDrop();
|
||||
}
|
||||
|
||||
public void OnPickupUseDown()
|
||||
{
|
||||
_udonBehaviour.OnPickupUseDown();
|
||||
}
|
||||
|
||||
public void OnPickupUseUp()
|
||||
{
|
||||
_udonBehaviour.OnPickupUseUp();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IClientSimStationHandler
|
||||
|
||||
public void OnStationEnter(VRCStation station)
|
||||
{
|
||||
VRC.SDK3.Components.VRCStation sdk3Station = station as VRC.SDK3.Components.VRCStation;
|
||||
_udonBehaviour.RunEvent(sdk3Station.OnLocalPlayerEnterStation, ("Player", Networking.LocalPlayer));
|
||||
}
|
||||
|
||||
public void OnStationExit(VRCStation station)
|
||||
{
|
||||
VRC.SDK3.Components.VRCStation sdk3Station = station as VRC.SDK3.Components.VRCStation;
|
||||
_udonBehaviour.RunEvent(sdk3Station.OnLocalPlayerExitStation, ("Player", Networking.LocalPlayer));
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 47cf12a423d907241aecd58f6c25b67f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 35b459bb3c0a402478e4dc51b61f4e08
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,13 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace VRC.SDK3.ClientSim
|
||||
{
|
||||
public interface IClientSimInteractable
|
||||
{
|
||||
float GetProximity();
|
||||
bool CanInteract();
|
||||
string GetInteractText();
|
||||
Vector3 GetInteractTextPlacement();
|
||||
void Interact();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 21636088934f3b046ae75a139062188f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,10 @@
|
||||
namespace VRC.SDK3.ClientSim
|
||||
{
|
||||
public interface IClientSimPickupHandler
|
||||
{
|
||||
void OnPickup();
|
||||
void OnDrop();
|
||||
void OnPickupUseDown();
|
||||
void OnPickupUseUp();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e92c80793952b604689f26d846684351
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,24 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
using VRC.SDKBase;
|
||||
|
||||
namespace VRC.SDK3.ClientSim
|
||||
{
|
||||
public interface IClientSimPickupable : IClientSimInteractable
|
||||
{
|
||||
bool IsHeld();
|
||||
VRCPlayerApi GetHoldingPlayer();
|
||||
bool AutoHold();
|
||||
GameObject GetGameObject();
|
||||
Transform GetTransform();
|
||||
Rigidbody GetRigidbody();
|
||||
VRC_Pickup GetPickup();
|
||||
VRC_Pickup.PickupOrientation GetOrientation();
|
||||
Transform GetGunLocation();
|
||||
Transform GetGripLocation();
|
||||
float GetThrowVelocityBoostScale();
|
||||
bool AllowManipulation();
|
||||
void Pickup(VRCPlayerApi player, VRC_Pickup.PickupHand heldHand, Action<IClientSimPickupable> forceDrop);
|
||||
void Drop(VRCPlayerApi player);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 055ff67a9eb2dd64eb2c06f4df3626e5
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,9 @@
|
||||
using VRC.SDK3.Platform;
|
||||
|
||||
namespace VRC.SDK3.ClientSim
|
||||
{
|
||||
public interface IClientSimPlatformManager
|
||||
{
|
||||
void OnScreenUpdate(ScreenUpdateData data);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0eab22d28a864961b5fdde0d9feae259
|
||||
timeCreated: 1698363855
|
||||
@ -0,0 +1,19 @@
|
||||
|
||||
using UnityEngine;
|
||||
|
||||
namespace VRC.SDK3.ClientSim
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents an object that syncs its position
|
||||
/// </summary>
|
||||
public interface IClientSimPositionSyncable : IClientSimSyncable, IClientSimRespawnHandler
|
||||
{
|
||||
bool SyncPosition { get; }
|
||||
void SetIsKinematic(bool value);
|
||||
void SetUseGravity(bool value);
|
||||
bool GetIsKinematic();
|
||||
bool GetUseGravity();
|
||||
void UpdatePositionSync();
|
||||
Transform GetTransform();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4b6da4177d7e4ca78b196bbf95952162
|
||||
timeCreated: 1640133052
|
||||
@ -0,0 +1,7 @@
|
||||
namespace VRC.SDK3.ClientSim
|
||||
{
|
||||
public interface IClientSimRespawnHandler
|
||||
{
|
||||
void Respawn();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c5fb7511272166a46844d934faa1c807
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,25 @@
|
||||
using UnityEngine;
|
||||
using VRC.SDKBase;
|
||||
|
||||
namespace VRC.SDK3.ClientSim
|
||||
{
|
||||
public interface IClientSimStation
|
||||
{
|
||||
Transform EnterLocation();
|
||||
Transform ExitLocation();
|
||||
bool IsMobile();
|
||||
bool IsSeated();
|
||||
bool DisableStationExit();
|
||||
bool CanUseStationFromStation();
|
||||
bool IsLockedInStation();
|
||||
VRCStation GetStation();
|
||||
GameObject GetStationGameObject();
|
||||
Transform GetStationTransform();
|
||||
|
||||
void EnterStation(VRCPlayerApi player);
|
||||
void ExitStation(VRCPlayerApi player);
|
||||
|
||||
bool IsOccupied();
|
||||
VRCPlayerApi GetCurrentSittingPlayer();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 74b90df615347ae4ea37ca4ad194ae63
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,10 @@
|
||||
using VRC.SDKBase;
|
||||
|
||||
namespace VRC.SDK3.ClientSim
|
||||
{
|
||||
public interface IClientSimStationHandler
|
||||
{
|
||||
void OnStationEnter(VRCStation station);
|
||||
void OnStationExit(VRCStation station);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c3297e7438270ea4cb73974aaad463b9
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,8 @@
|
||||
namespace VRC.SDK3.ClientSim
|
||||
{
|
||||
public interface IClientSimSyncable
|
||||
{
|
||||
int GetOwner();
|
||||
void SetOwner(int ownerID);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 58e4590a77a47fa429b2271e49050c99
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,7 @@
|
||||
namespace VRC.SDK3.ClientSim
|
||||
{
|
||||
public interface IClientSimSyncableHandler
|
||||
{
|
||||
void OnOwnershipTransferred(int ownerID);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d9cad5ab39e663849a092d187a23aa10
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user