aha
This commit is contained in:
@ -0,0 +1,85 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!21 &2100000
|
||||
Material:
|
||||
serializedVersion: 8
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: LocalGhostMaterial
|
||||
m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0}
|
||||
m_Parent: {fileID: 0}
|
||||
m_ModifiedSerializedProperties: 0
|
||||
m_ValidKeywords:
|
||||
- _ALPHAPREMULTIPLY_ON
|
||||
m_InvalidKeywords: []
|
||||
m_LightmapFlags: 4
|
||||
m_EnableInstancingVariants: 0
|
||||
m_DoubleSidedGI: 0
|
||||
m_CustomRenderQueue: 3000
|
||||
stringTagMap:
|
||||
RenderType: Transparent
|
||||
disabledShaderPasses: []
|
||||
m_LockedProperties:
|
||||
m_SavedProperties:
|
||||
serializedVersion: 3
|
||||
m_TexEnvs:
|
||||
- _BumpMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _DetailAlbedoMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _DetailMask:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _DetailNormalMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _EmissionMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _MainTex:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _MetallicGlossMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _OcclusionMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _ParallaxMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
m_Ints: []
|
||||
m_Floats:
|
||||
- _BumpScale: 1
|
||||
- _Cutoff: 0.5
|
||||
- _DetailNormalMapScale: 1
|
||||
- _DstBlend: 10
|
||||
- _GlossMapScale: 1
|
||||
- _Glossiness: 0.92
|
||||
- _GlossyReflections: 1
|
||||
- _Metallic: 0
|
||||
- _Mode: 3
|
||||
- _OcclusionStrength: 1
|
||||
- _Parallax: 0.02
|
||||
- _SmoothnessTextureChannel: 0
|
||||
- _SpecularHighlights: 1
|
||||
- _SrcBlend: 1
|
||||
- _UVSec: 0
|
||||
- _ZWrite: 0
|
||||
m_Colors:
|
||||
- _Color: {r: 1, g: 0, b: 0.067070484, a: 0.15686275}
|
||||
- _EmissionColor: {r: 0, g: 0, b: 0, a: 1}
|
||||
m_BuildTextureStacks: []
|
@ -0,0 +1,15 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 411a48b4a197d4924bec3e3809bc9320
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 2100000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 129321
|
||||
packageName: Mirror
|
||||
packageVersion: 96.0.1
|
||||
assetPath: Assets/Mirror/Components/PredictedRigidbody/LocalGhostMaterial.mat
|
||||
uploadId: 736421
|
1021
Assets/Mirror/Components/PredictedRigidbody/PredictedRigidbody.cs
Normal file
1021
Assets/Mirror/Components/PredictedRigidbody/PredictedRigidbody.cs
Normal file
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,22 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d38927cdc6024b9682b5fe9778b9ef99
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences:
|
||||
- localGhostMaterial: {fileID: 2100000, guid: 411a48b4a197d4924bec3e3809bc9320,
|
||||
type: 2}
|
||||
- remoteGhostMaterial: {fileID: 2100000, guid: 04f0b2088c857414393bab3b80356776,
|
||||
type: 2}
|
||||
executionOrder: 0
|
||||
icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 129321
|
||||
packageName: Mirror
|
||||
packageVersion: 96.0.1
|
||||
assetPath: Assets/Mirror/Components/PredictedRigidbody/PredictedRigidbody.cs
|
||||
uploadId: 736421
|
@ -0,0 +1,15 @@
|
||||
// Prediction moves out the Rigidbody & Collider into a separate object.
|
||||
// this component simply points back to the owner component.
|
||||
// in case Raycasts hit it and need to know the owner, etc.
|
||||
using UnityEngine;
|
||||
|
||||
namespace Mirror
|
||||
{
|
||||
public class PredictedRigidbodyPhysicsGhost : MonoBehaviour
|
||||
{
|
||||
// this is performance critical, so store target's .Transform instead of
|
||||
// PredictedRigidbody, this way we don't need to call the .transform getter.
|
||||
[Tooltip("The predicted rigidbody owner.")]
|
||||
public Transform target;
|
||||
}
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 25593abc9bf0d44878a4ad6018204061
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 129321
|
||||
packageName: Mirror
|
||||
packageVersion: 96.0.1
|
||||
assetPath: Assets/Mirror/Components/PredictedRigidbody/PredictedRigidbodyPhysicsGhost.cs
|
||||
uploadId: 736421
|
@ -0,0 +1 @@
|
||||
// removed 2024-02-09
|
@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 62e7e9424c7e48d69b6a3517796142a1
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 129321
|
||||
packageName: Mirror
|
||||
packageVersion: 96.0.1
|
||||
assetPath: Assets/Mirror/Components/PredictedRigidbody/PredictedRigidbodyRemoteGhost.cs
|
||||
uploadId: 736421
|
@ -0,0 +1,54 @@
|
||||
// this struct exists only for OnDe/Serialize performance.
|
||||
// instead of WriteVector3+Quaternion+Vector3+Vector3,
|
||||
// we read & write the whole struct as blittable once.
|
||||
//
|
||||
// struct packing can cause odd results with blittable on different platforms,
|
||||
// so this is usually not recommended!
|
||||
//
|
||||
// in this case however, we need to squeeze everything we can out of prediction
|
||||
// to support low even devices / VR.
|
||||
using System.Runtime.InteropServices;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Mirror
|
||||
{
|
||||
// struct packing
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)] // explicitly force sequential
|
||||
public struct PredictedSyncData
|
||||
{
|
||||
public float deltaTime; // 4 bytes (word aligned)
|
||||
public Vector3 position; // 12 bytes (word aligned)
|
||||
public Quaternion rotation; // 16 bytes (word aligned)
|
||||
public Vector3 velocity; // 12 bytes (word aligned)
|
||||
public Vector3 angularVelocity; // 12 bytes (word aligned)
|
||||
// DO NOT SYNC SLEEPING! this cuts benchmark performance in half(!!!)
|
||||
// public byte sleeping; // 1 byte: bool isn't blittable
|
||||
|
||||
// constructor for convenience
|
||||
public PredictedSyncData(float deltaTime, Vector3 position, Quaternion rotation, Vector3 velocity, Vector3 angularVelocity)//, bool sleeping)
|
||||
{
|
||||
this.deltaTime = deltaTime;
|
||||
this.position = position;
|
||||
this.rotation = rotation;
|
||||
this.velocity = velocity;
|
||||
this.angularVelocity = angularVelocity;
|
||||
// DO NOT SYNC SLEEPING! this cuts benchmark performance in half(!!!)
|
||||
// this.sleeping = sleeping ? (byte)1 : (byte)0;
|
||||
}
|
||||
}
|
||||
|
||||
// NetworkReader/Writer extensions to write this struct
|
||||
public static class PredictedSyncDataReadWrite
|
||||
{
|
||||
public static void WritePredictedSyncData(this NetworkWriter writer, PredictedSyncData data)
|
||||
{
|
||||
writer.WriteBlittable(data);
|
||||
}
|
||||
|
||||
public static PredictedSyncData ReadPredictedSyncData(this NetworkReader reader)
|
||||
{
|
||||
return reader.ReadBlittable<PredictedSyncData>();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f595f112a39e4634b670d56991b23823
|
||||
timeCreated: 1710387026
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 129321
|
||||
packageName: Mirror
|
||||
packageVersion: 96.0.1
|
||||
assetPath: Assets/Mirror/Components/PredictedRigidbody/PredictedSyncData.cs
|
||||
uploadId: 736421
|
430
Assets/Mirror/Components/PredictedRigidbody/PredictionUtils.cs
Normal file
430
Assets/Mirror/Components/PredictedRigidbody/PredictionUtils.cs
Normal file
@ -0,0 +1,430 @@
|
||||
// standalone utility functions for PredictedRigidbody component.
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Mirror
|
||||
{
|
||||
public static class PredictionUtils
|
||||
{
|
||||
// rigidbody ///////////////////////////////////////////////////////////
|
||||
// move a Rigidbody + settings from one GameObject to another.
|
||||
public static void MoveRigidbody(GameObject source, GameObject destination, bool destroySource = true)
|
||||
{
|
||||
// create a new Rigidbody component on destination.
|
||||
// note that adding a Joint automatically adds a Rigidbody.
|
||||
// so first check if one was added yet.
|
||||
Rigidbody original = source.GetComponent<Rigidbody>();
|
||||
if (original == null) throw new Exception($"Prediction: attempted to move {source}'s Rigidbody to the predicted copy, but there was no component.");
|
||||
Rigidbody rigidbodyCopy;
|
||||
if (!destination.TryGetComponent(out rigidbodyCopy))
|
||||
rigidbodyCopy = destination.AddComponent<Rigidbody>();
|
||||
|
||||
// copy all properties
|
||||
rigidbodyCopy.mass = original.mass;
|
||||
#if UNITY_6000_0_OR_NEWER
|
||||
rigidbodyCopy.linearDamping = original.linearDamping;
|
||||
rigidbodyCopy.angularDamping = original.angularDamping;
|
||||
#else
|
||||
rigidbodyCopy.drag = original.drag;
|
||||
rigidbodyCopy.angularDrag = original.angularDrag;
|
||||
#endif
|
||||
rigidbodyCopy.useGravity = original.useGravity;
|
||||
rigidbodyCopy.isKinematic = original.isKinematic;
|
||||
rigidbodyCopy.interpolation = original.interpolation;
|
||||
rigidbodyCopy.collisionDetectionMode = original.collisionDetectionMode;
|
||||
// fix: need to set freezeRotation before constraints:
|
||||
// https://github.com/MirrorNetworking/Mirror/pull/3946
|
||||
rigidbodyCopy.freezeRotation = original.freezeRotation;
|
||||
rigidbodyCopy.constraints = original.constraints;
|
||||
rigidbodyCopy.sleepThreshold = original.sleepThreshold;
|
||||
|
||||
// moving (Configurable)Joints messes up their range of motion unless
|
||||
// we reset to initial position first (we do this in PredictedRigibody.cs).
|
||||
// so here we don't set the Rigidbody's physics position at all.
|
||||
// rigidbodyCopy.position = original.position;
|
||||
// rigidbodyCopy.rotation = original.rotation;
|
||||
|
||||
// projects may keep Rigidbodies as kinematic sometimes. in that case, setting velocity would log an error
|
||||
if (!original.isKinematic)
|
||||
{
|
||||
#if UNITY_6000_0_OR_NEWER
|
||||
rigidbodyCopy.linearVelocity = original.linearVelocity;
|
||||
#else
|
||||
rigidbodyCopy.velocity = original.velocity;
|
||||
#endif
|
||||
rigidbodyCopy.angularVelocity = original.angularVelocity;
|
||||
}
|
||||
|
||||
// destroy original
|
||||
if (destroySource) GameObject.Destroy(original);
|
||||
}
|
||||
|
||||
// helper function: if a collider is on a child, copy that child first.
|
||||
// this way child's relative position/rotation/scale are preserved.
|
||||
public static GameObject CopyRelativeTransform(GameObject source, Transform sourceChild, GameObject destination)
|
||||
{
|
||||
// is this on the source root? then we want to put it on the destination root.
|
||||
if (sourceChild == source.transform) return destination;
|
||||
|
||||
// is this on a child? then create the same child with the same transform on destination.
|
||||
// note this is technically only correct for the immediate child since
|
||||
// .localPosition is relative to parent, but this is good enough.
|
||||
GameObject child = new GameObject(sourceChild.name);
|
||||
child.transform.SetParent(destination.transform, true);
|
||||
child.transform.localPosition = sourceChild.localPosition;
|
||||
child.transform.localRotation = sourceChild.localRotation;
|
||||
child.transform.localScale = sourceChild.localScale;
|
||||
|
||||
// assign the same Layer for the physics copy.
|
||||
// games may use a custom physics collision matrix, layer matters.
|
||||
child.layer = sourceChild.gameObject.layer;
|
||||
|
||||
return child;
|
||||
}
|
||||
|
||||
// colliders ///////////////////////////////////////////////////////////
|
||||
// move all BoxColliders + settings from one GameObject to another.
|
||||
public static void MoveBoxColliders(GameObject source, GameObject destination, bool destroySource = true)
|
||||
{
|
||||
// colliders may be on children
|
||||
BoxCollider[] sourceColliders = source.GetComponentsInChildren<BoxCollider>();
|
||||
foreach (BoxCollider sourceCollider in sourceColliders)
|
||||
{
|
||||
// copy the relative transform:
|
||||
// if collider is on root, it returns destination root.
|
||||
// if collider is on a child, it creates and returns a child on destination.
|
||||
GameObject target = CopyRelativeTransform(source, sourceCollider.transform, destination);
|
||||
BoxCollider colliderCopy = target.AddComponent<BoxCollider>();
|
||||
colliderCopy.center = sourceCollider.center;
|
||||
colliderCopy.size = sourceCollider.size;
|
||||
colliderCopy.isTrigger = sourceCollider.isTrigger;
|
||||
colliderCopy.material = sourceCollider.material;
|
||||
if (destroySource) GameObject.Destroy(sourceCollider);
|
||||
}
|
||||
}
|
||||
|
||||
// move all SphereColliders + settings from one GameObject to another.
|
||||
public static void MoveSphereColliders(GameObject source, GameObject destination, bool destroySource = true)
|
||||
{
|
||||
// colliders may be on children
|
||||
SphereCollider[] sourceColliders = source.GetComponentsInChildren<SphereCollider>();
|
||||
foreach (SphereCollider sourceCollider in sourceColliders)
|
||||
{
|
||||
// copy the relative transform:
|
||||
// if collider is on root, it returns destination root.
|
||||
// if collider is on a child, it creates and returns a child on destination.
|
||||
GameObject target = CopyRelativeTransform(source, sourceCollider.transform, destination);
|
||||
SphereCollider colliderCopy = target.AddComponent<SphereCollider>();
|
||||
colliderCopy.center = sourceCollider.center;
|
||||
colliderCopy.radius = sourceCollider.radius;
|
||||
colliderCopy.isTrigger = sourceCollider.isTrigger;
|
||||
colliderCopy.material = sourceCollider.material;
|
||||
if (destroySource) GameObject.Destroy(sourceCollider);
|
||||
}
|
||||
}
|
||||
|
||||
// move all CapsuleColliders + settings from one GameObject to another.
|
||||
public static void MoveCapsuleColliders(GameObject source, GameObject destination, bool destroySource = true)
|
||||
{
|
||||
// colliders may be on children
|
||||
CapsuleCollider[] sourceColliders = source.GetComponentsInChildren<CapsuleCollider>();
|
||||
foreach (CapsuleCollider sourceCollider in sourceColliders)
|
||||
{
|
||||
// copy the relative transform:
|
||||
// if collider is on root, it returns destination root.
|
||||
// if collider is on a child, it creates and returns a child on destination.
|
||||
GameObject target = CopyRelativeTransform(source, sourceCollider.transform, destination);
|
||||
CapsuleCollider colliderCopy = target.AddComponent<CapsuleCollider>();
|
||||
colliderCopy.center = sourceCollider.center;
|
||||
colliderCopy.radius = sourceCollider.radius;
|
||||
colliderCopy.height = sourceCollider.height;
|
||||
colliderCopy.direction = sourceCollider.direction;
|
||||
colliderCopy.isTrigger = sourceCollider.isTrigger;
|
||||
colliderCopy.material = sourceCollider.material;
|
||||
if (destroySource) GameObject.Destroy(sourceCollider);
|
||||
}
|
||||
}
|
||||
|
||||
// move all MeshColliders + settings from one GameObject to another.
|
||||
public static void MoveMeshColliders(GameObject source, GameObject destination, bool destroySource = true)
|
||||
{
|
||||
// colliders may be on children
|
||||
MeshCollider[] sourceColliders = source.GetComponentsInChildren<MeshCollider>();
|
||||
foreach (MeshCollider sourceCollider in sourceColliders)
|
||||
{
|
||||
// when Models have Mesh->Read/Write disabled, it means that Unity
|
||||
// uploads the mesh directly to the GPU and erases it on the CPU.
|
||||
// on some platforms this makes moving a MeshCollider in builds impossible:
|
||||
//
|
||||
// "CollisionMeshData couldn't be created because the mesh has been marked as non-accessible."
|
||||
//
|
||||
// on other platforms, this works fine.
|
||||
// let's show an explicit log message so in case collisions don't
|
||||
// work at runtime, it's obvious why it happens and how to fix it.
|
||||
if (!sourceCollider.sharedMesh.isReadable)
|
||||
{
|
||||
Debug.Log($"[Prediction]: MeshCollider on {sourceCollider.name} isn't readable, which may indicate that the Mesh only exists on the GPU. If {sourceCollider.name} is missing collisions, then please select the model in the Project Area, and enable Mesh->Read/Write so it's also available on the CPU!");
|
||||
// don't early return. keep trying, it may work.
|
||||
}
|
||||
|
||||
// copy the relative transform:
|
||||
// if collider is on root, it returns destination root.
|
||||
// if collider is on a child, it creates and returns a child on destination.
|
||||
GameObject target = CopyRelativeTransform(source, sourceCollider.transform, destination);
|
||||
MeshCollider colliderCopy = target.AddComponent<MeshCollider>();
|
||||
colliderCopy.sharedMesh = sourceCollider.sharedMesh;
|
||||
colliderCopy.convex = sourceCollider.convex;
|
||||
colliderCopy.isTrigger = sourceCollider.isTrigger;
|
||||
colliderCopy.material = sourceCollider.material;
|
||||
if (destroySource) GameObject.Destroy(sourceCollider);
|
||||
}
|
||||
}
|
||||
|
||||
// move all Colliders + settings from one GameObject to another.
|
||||
public static void MoveAllColliders(GameObject source, GameObject destination, bool destroySource = true)
|
||||
{
|
||||
MoveBoxColliders(source, destination, destroySource);
|
||||
MoveSphereColliders(source, destination, destroySource);
|
||||
MoveCapsuleColliders(source, destination, destroySource);
|
||||
MoveMeshColliders(source, destination, destroySource);
|
||||
}
|
||||
|
||||
// joints //////////////////////////////////////////////////////////////
|
||||
// move all CharacterJoints + settings from one GameObject to another.
|
||||
public static void MoveCharacterJoints(GameObject source, GameObject destination, bool destroySource = true)
|
||||
{
|
||||
// colliders may be on children
|
||||
CharacterJoint[] sourceJoints = source.GetComponentsInChildren<CharacterJoint>();
|
||||
foreach (CharacterJoint sourceJoint in sourceJoints)
|
||||
{
|
||||
// copy the relative transform:
|
||||
// if joint is on root, it returns destination root.
|
||||
// if joint is on a child, it creates and returns a child on destination.
|
||||
GameObject target = CopyRelativeTransform(source, sourceJoint.transform, destination);
|
||||
CharacterJoint jointCopy = target.AddComponent<CharacterJoint>();
|
||||
// apply settings, in alphabetical order
|
||||
jointCopy.anchor = sourceJoint.anchor;
|
||||
jointCopy.autoConfigureConnectedAnchor = sourceJoint.autoConfigureConnectedAnchor;
|
||||
jointCopy.axis = sourceJoint.axis;
|
||||
jointCopy.breakForce = sourceJoint.breakForce;
|
||||
jointCopy.breakTorque = sourceJoint.breakTorque;
|
||||
jointCopy.connectedAnchor = sourceJoint.connectedAnchor;
|
||||
jointCopy.connectedBody = sourceJoint.connectedBody;
|
||||
jointCopy.connectedMassScale = sourceJoint.connectedMassScale;
|
||||
jointCopy.enableCollision = sourceJoint.enableCollision;
|
||||
jointCopy.enablePreprocessing = sourceJoint.enablePreprocessing;
|
||||
jointCopy.enableProjection = sourceJoint.enableProjection;
|
||||
jointCopy.highTwistLimit = sourceJoint.highTwistLimit;
|
||||
jointCopy.lowTwistLimit = sourceJoint.lowTwistLimit;
|
||||
jointCopy.massScale = sourceJoint.massScale;
|
||||
jointCopy.projectionAngle = sourceJoint.projectionAngle;
|
||||
jointCopy.projectionDistance = sourceJoint.projectionDistance;
|
||||
jointCopy.swing1Limit = sourceJoint.swing1Limit;
|
||||
jointCopy.swing2Limit = sourceJoint.swing2Limit;
|
||||
jointCopy.swingAxis = sourceJoint.swingAxis;
|
||||
jointCopy.swingLimitSpring = sourceJoint.swingLimitSpring;
|
||||
jointCopy.twistLimitSpring = sourceJoint.twistLimitSpring;
|
||||
#if UNITY_2020_3_OR_NEWER
|
||||
jointCopy.connectedArticulationBody = sourceJoint.connectedArticulationBody;
|
||||
#endif
|
||||
|
||||
if (destroySource) GameObject.Destroy(sourceJoint);
|
||||
}
|
||||
}
|
||||
|
||||
// move all ConfigurableJoints + settings from one GameObject to another.
|
||||
public static void MoveConfigurableJoints(GameObject source, GameObject destination, bool destroySource = true)
|
||||
{
|
||||
// colliders may be on children
|
||||
ConfigurableJoint[] sourceJoints = source.GetComponentsInChildren<ConfigurableJoint>();
|
||||
foreach (ConfigurableJoint sourceJoint in sourceJoints)
|
||||
{
|
||||
// copy the relative transform:
|
||||
// if joint is on root, it returns destination root.
|
||||
// if joint is on a child, it creates and returns a child on destination.
|
||||
GameObject target = CopyRelativeTransform(source, sourceJoint.transform, destination);
|
||||
ConfigurableJoint jointCopy = target.AddComponent<ConfigurableJoint>();
|
||||
// apply settings, in alphabetical order
|
||||
jointCopy.anchor = sourceJoint.anchor;
|
||||
jointCopy.angularXLimitSpring = sourceJoint.angularXLimitSpring;
|
||||
jointCopy.angularXDrive = sourceJoint.angularXDrive;
|
||||
jointCopy.angularXMotion = sourceJoint.angularXMotion;
|
||||
jointCopy.angularYLimit = sourceJoint.angularYLimit;
|
||||
jointCopy.angularYMotion = sourceJoint.angularYMotion;
|
||||
jointCopy.angularYZDrive = sourceJoint.angularYZDrive;
|
||||
jointCopy.angularYZLimitSpring = sourceJoint.angularYZLimitSpring;
|
||||
jointCopy.angularZLimit = sourceJoint.angularZLimit;
|
||||
jointCopy.angularZMotion = sourceJoint.angularZMotion;
|
||||
jointCopy.autoConfigureConnectedAnchor = sourceJoint.autoConfigureConnectedAnchor;
|
||||
jointCopy.axis = sourceJoint.axis;
|
||||
jointCopy.breakForce = sourceJoint.breakForce;
|
||||
jointCopy.breakTorque = sourceJoint.breakTorque;
|
||||
jointCopy.configuredInWorldSpace = sourceJoint.configuredInWorldSpace;
|
||||
jointCopy.connectedAnchor = sourceJoint.connectedAnchor;
|
||||
jointCopy.connectedBody = sourceJoint.connectedBody;
|
||||
jointCopy.connectedMassScale = sourceJoint.connectedMassScale;
|
||||
jointCopy.enableCollision = sourceJoint.enableCollision;
|
||||
jointCopy.enablePreprocessing = sourceJoint.enablePreprocessing;
|
||||
jointCopy.highAngularXLimit = sourceJoint.highAngularXLimit; // moving this only works if the object is at initial position/rotation/scale, see PredictedRigidbody.cs
|
||||
jointCopy.linearLimitSpring = sourceJoint.linearLimitSpring;
|
||||
jointCopy.linearLimit = sourceJoint.linearLimit;
|
||||
jointCopy.lowAngularXLimit = sourceJoint.lowAngularXLimit; // moving this only works if the object is at initial position/rotation/scale, see PredictedRigidbody.cs
|
||||
jointCopy.massScale = sourceJoint.massScale;
|
||||
jointCopy.projectionAngle = sourceJoint.projectionAngle;
|
||||
jointCopy.projectionDistance = sourceJoint.projectionDistance;
|
||||
jointCopy.projectionMode = sourceJoint.projectionMode;
|
||||
jointCopy.rotationDriveMode = sourceJoint.rotationDriveMode;
|
||||
jointCopy.secondaryAxis = sourceJoint.secondaryAxis;
|
||||
jointCopy.slerpDrive = sourceJoint.slerpDrive;
|
||||
jointCopy.swapBodies = sourceJoint.swapBodies;
|
||||
jointCopy.targetAngularVelocity = sourceJoint.targetAngularVelocity;
|
||||
jointCopy.targetPosition = sourceJoint.targetPosition;
|
||||
jointCopy.targetRotation = sourceJoint.targetRotation;
|
||||
jointCopy.targetVelocity = sourceJoint.targetVelocity;
|
||||
jointCopy.xDrive = sourceJoint.xDrive;
|
||||
jointCopy.xMotion = sourceJoint.xMotion;
|
||||
jointCopy.yDrive = sourceJoint.yDrive;
|
||||
jointCopy.yMotion = sourceJoint.yMotion;
|
||||
jointCopy.zDrive = sourceJoint.zDrive;
|
||||
jointCopy.zMotion = sourceJoint.zMotion;
|
||||
#if UNITY_2020_3_OR_NEWER
|
||||
jointCopy.connectedArticulationBody = sourceJoint.connectedArticulationBody;
|
||||
#endif
|
||||
|
||||
if (destroySource) GameObject.Destroy(sourceJoint);
|
||||
}
|
||||
}
|
||||
|
||||
// move all FixedJoints + settings from one GameObject to another.
|
||||
public static void MoveFixedJoints(GameObject source, GameObject destination, bool destroySource = true)
|
||||
{
|
||||
// colliders may be on children
|
||||
FixedJoint[] sourceJoints = source.GetComponentsInChildren<FixedJoint>();
|
||||
foreach (FixedJoint sourceJoint in sourceJoints)
|
||||
{
|
||||
// copy the relative transform:
|
||||
// if joint is on root, it returns destination root.
|
||||
// if joint is on a child, it creates and returns a child on destination.
|
||||
GameObject target = CopyRelativeTransform(source, sourceJoint.transform, destination);
|
||||
FixedJoint jointCopy = target.AddComponent<FixedJoint>();
|
||||
// apply settings, in alphabetical order
|
||||
jointCopy.anchor = sourceJoint.anchor;
|
||||
jointCopy.autoConfigureConnectedAnchor = sourceJoint.autoConfigureConnectedAnchor;
|
||||
jointCopy.axis = sourceJoint.axis;
|
||||
jointCopy.breakForce = sourceJoint.breakForce;
|
||||
jointCopy.breakTorque = sourceJoint.breakTorque;
|
||||
jointCopy.connectedAnchor = sourceJoint.connectedAnchor;
|
||||
jointCopy.connectedBody = sourceJoint.connectedBody;
|
||||
jointCopy.connectedMassScale = sourceJoint.connectedMassScale;
|
||||
jointCopy.enableCollision = sourceJoint.enableCollision;
|
||||
jointCopy.enablePreprocessing = sourceJoint.enablePreprocessing;
|
||||
jointCopy.massScale = sourceJoint.massScale;
|
||||
#if UNITY_2020_3_OR_NEWER
|
||||
jointCopy.connectedArticulationBody = sourceJoint.connectedArticulationBody;
|
||||
#endif
|
||||
|
||||
if (destroySource) GameObject.Destroy(sourceJoint);
|
||||
}
|
||||
}
|
||||
|
||||
// move all HingeJoints + settings from one GameObject to another.
|
||||
public static void MoveHingeJoints(GameObject source, GameObject destination, bool destroySource = true)
|
||||
{
|
||||
// colliders may be on children
|
||||
HingeJoint[] sourceJoints = source.GetComponentsInChildren<HingeJoint>();
|
||||
foreach (HingeJoint sourceJoint in sourceJoints)
|
||||
{
|
||||
// copy the relative transform:
|
||||
// if joint is on root, it returns destination root.
|
||||
// if joint is on a child, it creates and returns a child on destination.
|
||||
GameObject target = CopyRelativeTransform(source, sourceJoint.transform, destination);
|
||||
HingeJoint jointCopy = target.AddComponent<HingeJoint>();
|
||||
// apply settings, in alphabetical order
|
||||
jointCopy.anchor = sourceJoint.anchor;
|
||||
jointCopy.autoConfigureConnectedAnchor = sourceJoint.autoConfigureConnectedAnchor;
|
||||
jointCopy.axis = sourceJoint.axis;
|
||||
jointCopy.breakForce = sourceJoint.breakForce;
|
||||
jointCopy.breakTorque = sourceJoint.breakTorque;
|
||||
jointCopy.connectedAnchor = sourceJoint.connectedAnchor;
|
||||
jointCopy.connectedBody = sourceJoint.connectedBody;
|
||||
jointCopy.connectedMassScale = sourceJoint.connectedMassScale;
|
||||
jointCopy.enableCollision = sourceJoint.enableCollision;
|
||||
jointCopy.enablePreprocessing = sourceJoint.enablePreprocessing;
|
||||
jointCopy.limits = sourceJoint.limits;
|
||||
jointCopy.massScale = sourceJoint.massScale;
|
||||
jointCopy.motor = sourceJoint.motor;
|
||||
jointCopy.spring = sourceJoint.spring;
|
||||
jointCopy.useLimits = sourceJoint.useLimits;
|
||||
jointCopy.useMotor = sourceJoint.useMotor;
|
||||
jointCopy.useSpring = sourceJoint.useSpring;
|
||||
#if UNITY_2020_3_OR_NEWER
|
||||
jointCopy.connectedArticulationBody = sourceJoint.connectedArticulationBody;
|
||||
#endif
|
||||
#if UNITY_2022_3_OR_NEWER
|
||||
jointCopy.extendedLimits = sourceJoint.extendedLimits;
|
||||
jointCopy.useAcceleration = sourceJoint.useAcceleration;
|
||||
#endif
|
||||
|
||||
if (destroySource) GameObject.Destroy(sourceJoint);
|
||||
}
|
||||
}
|
||||
|
||||
// move all SpringJoints + settings from one GameObject to another.
|
||||
public static void MoveSpringJoints(GameObject source, GameObject destination, bool destroySource = true)
|
||||
{
|
||||
// colliders may be on children
|
||||
SpringJoint[] sourceJoints = source.GetComponentsInChildren<SpringJoint>();
|
||||
foreach (SpringJoint sourceJoint in sourceJoints)
|
||||
{
|
||||
// copy the relative transform:
|
||||
// if joint is on root, it returns destination root.
|
||||
// if joint is on a child, it creates and returns a child on destination.
|
||||
GameObject target = CopyRelativeTransform(source, sourceJoint.transform, destination);
|
||||
SpringJoint jointCopy = target.AddComponent<SpringJoint>();
|
||||
// apply settings, in alphabetical order
|
||||
jointCopy.anchor = sourceJoint.anchor;
|
||||
jointCopy.autoConfigureConnectedAnchor = sourceJoint.autoConfigureConnectedAnchor;
|
||||
jointCopy.axis = sourceJoint.axis;
|
||||
jointCopy.breakForce = sourceJoint.breakForce;
|
||||
jointCopy.breakTorque = sourceJoint.breakTorque;
|
||||
jointCopy.connectedAnchor = sourceJoint.connectedAnchor;
|
||||
jointCopy.connectedBody = sourceJoint.connectedBody;
|
||||
jointCopy.connectedMassScale = sourceJoint.connectedMassScale;
|
||||
jointCopy.damper = sourceJoint.damper;
|
||||
jointCopy.enableCollision = sourceJoint.enableCollision;
|
||||
jointCopy.enablePreprocessing = sourceJoint.enablePreprocessing;
|
||||
jointCopy.massScale = sourceJoint.massScale;
|
||||
jointCopy.maxDistance = sourceJoint.maxDistance;
|
||||
jointCopy.minDistance = sourceJoint.minDistance;
|
||||
jointCopy.spring = sourceJoint.spring;
|
||||
jointCopy.tolerance = sourceJoint.tolerance;
|
||||
#if UNITY_2020_3_OR_NEWER
|
||||
jointCopy.connectedArticulationBody = sourceJoint.connectedArticulationBody;
|
||||
#endif
|
||||
|
||||
if (destroySource) GameObject.Destroy(sourceJoint);
|
||||
}
|
||||
}
|
||||
|
||||
// move all Joints + settings from one GameObject to another.
|
||||
public static void MoveAllJoints(GameObject source, GameObject destination, bool destroySource = true)
|
||||
{
|
||||
MoveCharacterJoints(source, destination, destroySource);
|
||||
MoveConfigurableJoints(source, destination, destroySource);
|
||||
MoveFixedJoints(source, destination, destroySource);
|
||||
MoveHingeJoints(source, destination, destroySource);
|
||||
MoveSpringJoints(source, destination, destroySource);
|
||||
}
|
||||
|
||||
// all /////////////////////////////////////////////////////////////////
|
||||
// move all physics components from one GameObject to another.
|
||||
public static void MovePhysicsComponents(GameObject source, GameObject destination, bool destroySource = true)
|
||||
{
|
||||
// need to move joints first, otherwise we might see:
|
||||
// 'can't move Rigidbody because a Joint depends on it'
|
||||
MoveAllJoints(source, destination, destroySource);
|
||||
MoveAllColliders(source, destination, destroySource);
|
||||
MoveRigidbody(source, destination, destroySource);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 17cfe1beb3f94a69b94bf60afc37ef7a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 129321
|
||||
packageName: Mirror
|
||||
packageVersion: 96.0.1
|
||||
assetPath: Assets/Mirror/Components/PredictedRigidbody/PredictionUtils.cs
|
||||
uploadId: 736421
|
@ -0,0 +1,85 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!21 &2100000
|
||||
Material:
|
||||
serializedVersion: 8
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: RemoteGhostMaterial
|
||||
m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0}
|
||||
m_Parent: {fileID: 0}
|
||||
m_ModifiedSerializedProperties: 0
|
||||
m_ValidKeywords:
|
||||
- _ALPHAPREMULTIPLY_ON
|
||||
m_InvalidKeywords: []
|
||||
m_LightmapFlags: 4
|
||||
m_EnableInstancingVariants: 0
|
||||
m_DoubleSidedGI: 0
|
||||
m_CustomRenderQueue: 3000
|
||||
stringTagMap:
|
||||
RenderType: Transparent
|
||||
disabledShaderPasses: []
|
||||
m_LockedProperties:
|
||||
m_SavedProperties:
|
||||
serializedVersion: 3
|
||||
m_TexEnvs:
|
||||
- _BumpMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _DetailAlbedoMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _DetailMask:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _DetailNormalMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _EmissionMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _MainTex:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _MetallicGlossMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _OcclusionMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _ParallaxMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
m_Ints: []
|
||||
m_Floats:
|
||||
- _BumpScale: 1
|
||||
- _Cutoff: 0.5
|
||||
- _DetailNormalMapScale: 1
|
||||
- _DstBlend: 10
|
||||
- _GlossMapScale: 1
|
||||
- _Glossiness: 0.92
|
||||
- _GlossyReflections: 1
|
||||
- _Metallic: 0
|
||||
- _Mode: 3
|
||||
- _OcclusionStrength: 1
|
||||
- _Parallax: 0.02
|
||||
- _SmoothnessTextureChannel: 0
|
||||
- _SpecularHighlights: 1
|
||||
- _SrcBlend: 1
|
||||
- _UVSec: 0
|
||||
- _ZWrite: 0
|
||||
m_Colors:
|
||||
- _Color: {r: 0.09849727, g: 1, b: 0, a: 0.15686275}
|
||||
- _EmissionColor: {r: 0, g: 0, b: 0, a: 1}
|
||||
m_BuildTextureStacks: []
|
@ -0,0 +1,15 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 04f0b2088c857414393bab3b80356776
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 2100000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 129321
|
||||
packageName: Mirror
|
||||
packageVersion: 96.0.1
|
||||
assetPath: Assets/Mirror/Components/PredictedRigidbody/RemoteGhostMaterial.mat
|
||||
uploadId: 736421
|
@ -0,0 +1,60 @@
|
||||
// PredictedRigidbody stores a history of its rigidbody states.
|
||||
using System.Runtime.CompilerServices;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Mirror
|
||||
{
|
||||
// inline everything because this is performance critical!
|
||||
public struct RigidbodyState : PredictedState
|
||||
{
|
||||
public double timestamp { [MethodImpl(MethodImplOptions.AggressiveInlining)] get; [MethodImpl(MethodImplOptions.AggressiveInlining)] private set; }
|
||||
|
||||
// we want to store position delta (last + delta = current), and current.
|
||||
// this way we can apply deltas on top of corrected positions to get the corrected final position.
|
||||
public Vector3 positionDelta { [MethodImpl(MethodImplOptions.AggressiveInlining)] get; [MethodImpl(MethodImplOptions.AggressiveInlining)] set; } // delta to get from last to this position
|
||||
public Vector3 position { [MethodImpl(MethodImplOptions.AggressiveInlining)] get; [MethodImpl(MethodImplOptions.AggressiveInlining)] set; }
|
||||
|
||||
public Quaternion rotationDelta { [MethodImpl(MethodImplOptions.AggressiveInlining)] get; [MethodImpl(MethodImplOptions.AggressiveInlining)] set; } // delta to get from last to this rotation
|
||||
public Quaternion rotation { [MethodImpl(MethodImplOptions.AggressiveInlining)] get; [MethodImpl(MethodImplOptions.AggressiveInlining)] set; }
|
||||
|
||||
public Vector3 velocityDelta { [MethodImpl(MethodImplOptions.AggressiveInlining)] get; [MethodImpl(MethodImplOptions.AggressiveInlining)] set; } // delta to get from last to this velocity
|
||||
public Vector3 velocity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get; [MethodImpl(MethodImplOptions.AggressiveInlining)] set; }
|
||||
|
||||
public Vector3 angularVelocityDelta { [MethodImpl(MethodImplOptions.AggressiveInlining)] get; [MethodImpl(MethodImplOptions.AggressiveInlining)] set; } // delta to get from last to this velocity
|
||||
public Vector3 angularVelocity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get; [MethodImpl(MethodImplOptions.AggressiveInlining)] set; }
|
||||
|
||||
public RigidbodyState(
|
||||
double timestamp,
|
||||
Vector3 positionDelta,
|
||||
Vector3 position,
|
||||
Quaternion rotationDelta,
|
||||
Quaternion rotation,
|
||||
Vector3 velocityDelta,
|
||||
Vector3 velocity,
|
||||
Vector3 angularVelocityDelta,
|
||||
Vector3 angularVelocity)
|
||||
{
|
||||
this.timestamp = timestamp;
|
||||
this.positionDelta = positionDelta;
|
||||
this.position = position;
|
||||
this.rotationDelta = rotationDelta;
|
||||
this.rotation = rotation;
|
||||
this.velocityDelta = velocityDelta;
|
||||
this.velocity = velocity;
|
||||
this.angularVelocityDelta = angularVelocityDelta;
|
||||
this.angularVelocity = angularVelocity;
|
||||
}
|
||||
|
||||
public static RigidbodyState Interpolate(RigidbodyState a, RigidbodyState b, float t)
|
||||
{
|
||||
return new RigidbodyState
|
||||
{
|
||||
position = Vector3.Lerp(a.position, b.position, t),
|
||||
// Quaternions always need to be normalized in order to be a valid rotation after operations
|
||||
rotation = Quaternion.Slerp(a.rotation, b.rotation, t).normalized,
|
||||
velocity = Vector3.Lerp(a.velocity, b.velocity, t),
|
||||
angularVelocity = Vector3.Lerp(a.angularVelocity, b.angularVelocity, t)
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ed0e1c0c874c4c9db6be2d5885bb7bee
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 129321
|
||||
packageName: Mirror
|
||||
packageVersion: 96.0.1
|
||||
assetPath: Assets/Mirror/Components/PredictedRigidbody/RigidbodyState.cs
|
||||
uploadId: 736421
|
Reference in New Issue
Block a user