neongm

interpolated RAttachment

May 24th, 2023
756
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 9.42 KB | None | 0 0
  1.  
  2. using UdonSharp;
  3. using UnityEngine;
  4. using VRC.SDKBase;
  5. using VRC.Udon;
  6. using VRC.Udon.Common;
  7.  
  8. // attachment does most of the stuff, attachment point just stores attachments and clamps position
  9. // detach only when moved
  10.  
  11.  
  12. // late joiner sync DONE
  13. // collision prevention TODO
  14.  
  15.  
  16. public class RAttachment : UdonSharpBehaviour
  17. {
  18. // main config
  19.     [Header("Config")]
  20.     [Tooltip("String that will be compared against names of the entered triggers to identify attachment points")]
  21.     public string attachmentPointIndentifierString = "AttachmentPoint";
  22.     public int attachmentCompatibilityLayer = 0;
  23.     public float attachmentOffset = 0f;
  24.     public float interpolationTimeSec = 0.25f;
  25.  
  26.     [Header("Plugins")]
  27.     public UdonBehaviour[] callbackReceivers = null;
  28.     public bool forwardAttachmentPointToCallbackReceivers = false;
  29.    
  30.     [Header("Audio")]
  31.     public float soundVolume = 0.2f;
  32.     public AudioClip readyToAttachSound = null;
  33.     public AudioClip attachCancelSound = null;
  34.     public AudioClip attachSound = null;
  35.     public AudioClip detachSound = null;
  36.  
  37. // PRIVATE VARIABLES
  38.     private RAttachmentPoint _targetAttachmentPoint = null;
  39.     private Transform _initialParent = null;
  40.     private bool isHeld = false;
  41.     private bool isAttached = false;
  42.    
  43.  
  44. // DEBUG
  45.     public RDebug RDbg = null;
  46.  
  47. // SYNCED
  48.     [UdonSynced]
  49.     private Vector3 _positionOffset = Vector3.zero;
  50.     [UdonSynced]
  51.     private string _targetAttachmentPointSyncName;
  52.  
  53.  
  54.     [UdonSynced]
  55.     private Vector3 _syncPos;
  56.     [UdonSynced]
  57.     private Quaternion _syncRot;
  58.  
  59. // interpolation
  60.     private Vector3 _prevPos;
  61.     private Quaternion _prevRot;
  62.     [UdonSynced]
  63.     private bool _interpolate = false;
  64.     private float _timeSpentInterpolating = 0f;
  65.     private bool _syncIsDirty = false;
  66.  
  67. // INITIALIZATION
  68.     void Start()
  69.     {
  70.         _initialParent = transform.parent;
  71.         RDbg = GameObject.Find("Dibugir").GetComponent<RDebug>();
  72.     }
  73.  
  74.  
  75. // IMPLEMENTATION
  76.     private void OnAttachSyncReceived(){ // triggered when others are guaranteed to have_targetAttachmentPoint set;
  77.         Debug.Log($"{gameObject.name} OnAttachSyncReceived: attach to {_targetAttachmentPoint}");
  78.         _attachLocal();
  79.     }
  80.  
  81.     private void OnDetachSyncReceived(){
  82.         Debug.Log($"{gameObject.name} OnDetachSyncReceived: paren changed to {_targetAttachmentPoint}");
  83.         _detachLocal();
  84.     }
  85.  
  86.     private void _setLocalTransform(){ // zero local position and rotation
  87.         transform.localRotation = Quaternion.identity;
  88.         transform.localPosition = _positionOffset;
  89.         Debug.Log($"new local localPosition: {_positionOffset}");
  90.     }
  91.  
  92.     private void _attachLocal(){
  93.         Debug.Log($"{gameObject.name} _attachLocal to {_targetAttachmentPoint.gameObject}");
  94.         transform.parent = _targetAttachmentPoint.attachmentParentContainer;
  95.         if(Networking.LocalPlayer.IsOwner(gameObject)){
  96.             _positionOffset = _targetAttachmentPoint.ClampOffset(transform.localPosition);
  97.             _positionOffset.x+=attachmentOffset;
  98.             _interpolate = false;
  99.             Debug.Log($"_positionOffset is calculated to be {_positionOffset} for localPosition: {transform.localPosition}");
  100.         }
  101.         _setLocalTransform(); // move to the position
  102.         isAttached = true;
  103.         _playAttachAudio();
  104.         _sendCallback("OnRAttachmentAttachLocal");
  105.     }
  106.  
  107.     private void _detachLocal(){
  108.         //Debug.Log($"{gameObject.name} _detachLocal DETACHED FROM {_targetAttachmentPoint}");
  109.         transform.parent = _initialParent;
  110.         isAttached = false;
  111.         if(_targetAttachmentPoint == null) return;
  112.         _targetAttachmentPoint = null;
  113.         //transform.parent = _initialParent;
  114.         //isAttached = false;
  115.         _playDetachAudio();
  116.         _sendCallback("OnRAttachmentDetachLocal");
  117.     }
  118.  
  119.     private void _syncToOthers(){
  120.         _targetAttachmentPointSyncName = (_targetAttachmentPoint) ? _targetAttachmentPoint.gameObject.name : null;
  121.         Debug.Log($"{gameObject.name} _syncToOthers sent by {Networking.LocalPlayer.displayName}, sent: {_targetAttachmentPointSyncName}");
  122.         RequestSerialization();
  123.     }
  124.  
  125.     private void _handleSerialization(){
  126.         if(_targetAttachmentPoint == null && _targetAttachmentPointSyncName != ""){
  127.             _targetAttachmentPoint = GameObject.Find(_targetAttachmentPointSyncName).GetComponent<RAttachmentPoint>();
  128.             OnAttachSyncReceived();
  129.         }else if (_targetAttachmentPoint != null && _targetAttachmentPointSyncName == ""){
  130.             OnDetachSyncReceived();
  131.         }
  132.  
  133.         if(transform.parent == _initialParent){
  134.             _prevPos = transform.localPosition;
  135.             _prevRot = transform.localRotation;
  136.             if(_prevPos == _syncPos && _prevRot == _syncRot) return;
  137.  
  138.             if(!_interpolate){
  139.                 transform.localPosition = _syncPos;
  140.                 transform.localRotation = _syncRot;
  141.             }else{
  142.                 _timeSpentInterpolating = 0f;
  143.             }
  144.         }
  145.     }
  146. // COLLISION DETECTION:
  147.     private void OnTriggerEnter(Collider _collider){
  148.         if(_collider.name.IndexOf(attachmentPointIndentifierString) == -1) return;
  149.         if(!Networking.LocalPlayer.IsOwner(gameObject)) return;
  150.         if(!isAttached) _playReadyToAttachAudio();
  151.         _targetAttachmentPoint = _collider.gameObject.GetComponent<RAttachmentPoint>();
  152.     }
  153.  
  154.     private void OnTriggerExit(Collider _collider){
  155.         if(_collider.name.IndexOf(attachmentPointIndentifierString) == -1) return;
  156.         if(!Networking.LocalPlayer.IsOwner(gameObject)) return;
  157.         if(!isAttached) _playAttachCancelAudio();
  158.         _targetAttachmentPoint = null;
  159.     }
  160.  
  161.  
  162. // EVENTS OWNER SIDE
  163.     public override void OnPickup() // called only by owner // detach here
  164.     {  
  165.         isHeld = true;
  166.         Debug.Log($"{this}: OnPickup {gameObject.name}, _targetAttachmentPoint: {_targetAttachmentPoint}");
  167.         _detachLocal();
  168.         _interpolate = true;
  169.         _syncToOthers();
  170.     }
  171.  
  172.     public override void OnDrop() // called only by owner
  173.     {
  174.         isHeld = false;
  175.         if(_targetAttachmentPoint==null) {
  176.             SendCustomEventDelayedSeconds("syncPos", 0.2f);
  177.             return;
  178.         }
  179.         if(_targetAttachmentPoint.attachmentCompatibilityLayer != this.attachmentCompatibilityLayer) {
  180.             SendCustomEventDelayedSeconds("syncPos", 0.2f);
  181.             return;
  182.         }
  183.         if(Networking.LocalPlayer.IsOwner(gameObject)) Debug.LogWarning($"ON DROP SENT NOT BY OWNER HOW DID YOU DO THIS");
  184.         // attaching
  185.        
  186.         // set offset here, calculated only by owner then
  187.         _attachLocal();
  188.         _syncToOthers();
  189.     }
  190.  
  191.     public override void OnDeserialization(){
  192.         _handleSerialization();
  193.     }
  194.  
  195.     public override void OnPlayerJoined(VRCPlayerApi player){
  196.         if(Networking.LocalPlayer.IsOwner(gameObject)) syncPos();
  197.     }
  198.  
  199. // UPDATE LOOP
  200.     public void syncPos(){ // it can be called only by an owner
  201.         _syncPos = transform.localPosition;
  202.         _syncRot = transform.localRotation;
  203.         RequestSerialization();
  204.     }
  205.  
  206.     void FixedUpdate(){
  207.         if(isHeld){
  208.             syncPos();
  209.         }
  210.     }
  211.     void Update(){
  212.         _interpolationLoop();
  213.     }
  214.  
  215.  
  216.     void _interpolationLoop(){
  217.         if(!_interpolate || _timeSpentInterpolating >= interpolationTimeSec) return;
  218.  
  219.         // if(_syncIsDirty){
  220.         //     _timeSpentInterpolating = 0f;
  221.         //     _syncIsDirty = false;
  222.         // }
  223.  
  224.         float _step = _timeSpentInterpolating/interpolationTimeSec;
  225.         Vector3 _nextPos = Vector3.Lerp(_prevPos, _syncPos, _step);
  226.         Quaternion _nextRot = Quaternion.Lerp(_prevRot, _syncRot, _step);
  227.  
  228.         transform.localPosition = _nextPos;
  229.         transform.localRotation = _nextRot;
  230.  
  231.        
  232.         _timeSpentInterpolating += Time.deltaTime;
  233.         if(_timeSpentInterpolating >= interpolationTimeSec){
  234.             transform.localPosition = _syncPos;
  235.             transform.localRotation = _syncRot;
  236.             //_timeSpentInterpolating = 0f;
  237.         }
  238.  
  239.         //_timeSpentInterpolating = 0f;
  240.         //transform.localPosition = _syncPos;
  241.         //transform.localRotation = _syncRot;
  242.        
  243.     }
  244. // CALLBACK SENDER
  245.     private void _sendCallback(string _callback){
  246.         Debug.Log($"{this}: _sendCallback");
  247.         if(callbackReceivers == null) return;
  248.        
  249.         foreach(UdonBehaviour _receiver in callbackReceivers){
  250.             Debug.Log($"{this}: Sending {_callback} to {_receiver}");
  251.             if(_receiver!=null) _receiver.SendCustomEvent(_callback);
  252.         }
  253.     }
  254.  
  255. // API
  256.     public RAttachmentPoint getAttachmentPoint() => _targetAttachmentPoint;
  257.  
  258.  
  259.  
  260. // AUDIO
  261.     void _playAttachAudio(){
  262.         if(attachSound == null) return;
  263.         AudioSource.PlayClipAtPoint(attachSound, transform.position, soundVolume);
  264.     }
  265.     void _playDetachAudio(){
  266.         if(detachSound == null) return;
  267.         AudioSource.PlayClipAtPoint(detachSound, transform.position, soundVolume);
  268.     }
  269.     void _playReadyToAttachAudio(){
  270.         if(readyToAttachSound == null) return;
  271.         AudioSource.PlayClipAtPoint(readyToAttachSound, transform.position, soundVolume);
  272.     }
  273.     void _playAttachCancelAudio(){
  274.         if(attachCancelSound == null) return;
  275.         AudioSource.PlayClipAtPoint(attachCancelSound, transform.position, soundVolume);
  276.     }
  277. }
  278.  
  279.  
Advertisement
Add Comment
Please, Sign In to add comment