diff --git a/Assets/GyroDroid-minimal-README.txt b/Assets/GyroDroid-minimal-README.txt deleted file mode 100644 index fde9ad2..0000000 --- a/Assets/GyroDroid-minimal-README.txt +++ /dev/null @@ -1 +0,0 @@ -The GyroDroid-minimal.unitypackage is for easier migration to your own projects. \ No newline at end of file diff --git a/Assets/GyroDroid-minimal-README.txt.meta b/Assets/GyroDroid-minimal-README.txt.meta deleted file mode 100644 index 6ecab91..0000000 --- a/Assets/GyroDroid-minimal-README.txt.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: b841190198a672c419fa25948845da38 diff --git a/Assets/GyroDroid-minimal.unitypackage b/Assets/GyroDroid-minimal.unitypackage deleted file mode 100644 index 0455d94..0000000 Binary files a/Assets/GyroDroid-minimal.unitypackage and /dev/null differ diff --git a/Assets/Photon Unity Networking.meta b/Assets/Photon Unity Networking.meta new file mode 100644 index 0000000..008e0f9 --- /dev/null +++ b/Assets/Photon Unity Networking.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: f7a92ef6f3eab4510a93886fdc13a07b +folderAsset: yes +timeCreated: 1501014811 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Photon Unity Networking/Demos.meta b/Assets/Photon Unity Networking/Demos.meta new file mode 100644 index 0000000..4cabefd --- /dev/null +++ b/Assets/Photon Unity Networking/Demos.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: e5da3d051ba024c2caf4e70129ede2dc +folderAsset: yes +timeCreated: 1501014811 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Photon Unity Networking/Demos/Demo2DJumpAndRunWithPhysics.meta b/Assets/Photon Unity Networking/Demos/Demo2DJumpAndRunWithPhysics.meta new file mode 100644 index 0000000..7795ac0 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/Demo2DJumpAndRunWithPhysics.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: a6773cdf6069d40b0923089148c459a6 +folderAsset: yes +timeCreated: 1501014811 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Photon Unity Networking/Demos/Demo2DJumpAndRunWithPhysics/Animations.meta b/Assets/Photon Unity Networking/Demos/Demo2DJumpAndRunWithPhysics/Animations.meta new file mode 100644 index 0000000..f89d119 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/Demo2DJumpAndRunWithPhysics/Animations.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 05e9f795641744285b9ba41b35af271c +folderAsset: yes +timeCreated: 1501014811 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Photon Unity Networking/Demos/Demo2DJumpAndRunWithPhysics/Animations/Fall.anim b/Assets/Photon Unity Networking/Demos/Demo2DJumpAndRunWithPhysics/Animations/Fall.anim new file mode 100644 index 0000000..bdda3b3 Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/Demo2DJumpAndRunWithPhysics/Animations/Fall.anim differ diff --git a/Assets/Photon Unity Networking/Demos/Demo2DJumpAndRunWithPhysics/Animations/Fall.anim.meta b/Assets/Photon Unity Networking/Demos/Demo2DJumpAndRunWithPhysics/Animations/Fall.anim.meta new file mode 100644 index 0000000..ea97721 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/Demo2DJumpAndRunWithPhysics/Animations/Fall.anim.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: 01b0b8b192837f34fbdd054d719dd80d +NativeFormatImporter: + userData: diff --git a/Assets/Photon Unity Networking/Demos/Demo2DJumpAndRunWithPhysics/Animations/Idle.anim b/Assets/Photon Unity Networking/Demos/Demo2DJumpAndRunWithPhysics/Animations/Idle.anim new file mode 100644 index 0000000..856f58f Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/Demo2DJumpAndRunWithPhysics/Animations/Idle.anim differ diff --git a/Assets/Photon Unity Networking/Demos/Demo2DJumpAndRunWithPhysics/Animations/Idle.anim.meta b/Assets/Photon Unity Networking/Demos/Demo2DJumpAndRunWithPhysics/Animations/Idle.anim.meta new file mode 100644 index 0000000..16ae5c9 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/Demo2DJumpAndRunWithPhysics/Animations/Idle.anim.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: 1a787ecb1de72484aad2d2aec3b4eebc +NativeFormatImporter: + userData: diff --git a/Assets/Photon Unity Networking/Demos/Demo2DJumpAndRunWithPhysics/Animations/Jump.anim b/Assets/Photon Unity Networking/Demos/Demo2DJumpAndRunWithPhysics/Animations/Jump.anim new file mode 100644 index 0000000..9dfa664 Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/Demo2DJumpAndRunWithPhysics/Animations/Jump.anim differ diff --git a/Assets/Photon Unity Networking/Demos/Demo2DJumpAndRunWithPhysics/Animations/Jump.anim.meta b/Assets/Photon Unity Networking/Demos/Demo2DJumpAndRunWithPhysics/Animations/Jump.anim.meta new file mode 100644 index 0000000..9d0a1dc --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/Demo2DJumpAndRunWithPhysics/Animations/Jump.anim.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: 3e9fe32f4019e6f44bce9b2737cff4fc +NativeFormatImporter: + userData: diff --git a/Assets/Photon Unity Networking/Demos/Demo2DJumpAndRunWithPhysics/Animations/Land.anim b/Assets/Photon Unity Networking/Demos/Demo2DJumpAndRunWithPhysics/Animations/Land.anim new file mode 100644 index 0000000..eac617d Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/Demo2DJumpAndRunWithPhysics/Animations/Land.anim differ diff --git a/Assets/Photon Unity Networking/Demos/Demo2DJumpAndRunWithPhysics/Animations/Land.anim.meta b/Assets/Photon Unity Networking/Demos/Demo2DJumpAndRunWithPhysics/Animations/Land.anim.meta new file mode 100644 index 0000000..5739763 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/Demo2DJumpAndRunWithPhysics/Animations/Land.anim.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: 298f4afe40ba3d74fae87ae1dfbe812e +NativeFormatImporter: + userData: diff --git a/Assets/Photon Unity Networking/Demos/Demo2DJumpAndRunWithPhysics/Animations/LandToIdle.anim b/Assets/Photon Unity Networking/Demos/Demo2DJumpAndRunWithPhysics/Animations/LandToIdle.anim new file mode 100644 index 0000000..d46c2bb Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/Demo2DJumpAndRunWithPhysics/Animations/LandToIdle.anim differ diff --git a/Assets/Photon Unity Networking/Demos/Demo2DJumpAndRunWithPhysics/Animations/LandToIdle.anim.meta b/Assets/Photon Unity Networking/Demos/Demo2DJumpAndRunWithPhysics/Animations/LandToIdle.anim.meta new file mode 100644 index 0000000..c45d87d --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/Demo2DJumpAndRunWithPhysics/Animations/LandToIdle.anim.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: 337069aec9b26ee46a5fff4869b0b951 +NativeFormatImporter: + userData: diff --git a/Assets/Photon Unity Networking/Demos/Demo2DJumpAndRunWithPhysics/Animations/RobotKyle2D.controller b/Assets/Photon Unity Networking/Demos/Demo2DJumpAndRunWithPhysics/Animations/RobotKyle2D.controller new file mode 100644 index 0000000..d986bbe Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/Demo2DJumpAndRunWithPhysics/Animations/RobotKyle2D.controller differ diff --git a/Assets/Photon Unity Networking/Demos/Demo2DJumpAndRunWithPhysics/Animations/RobotKyle2D.controller.meta b/Assets/Photon Unity Networking/Demos/Demo2DJumpAndRunWithPhysics/Animations/RobotKyle2D.controller.meta new file mode 100644 index 0000000..ab60f32 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/Demo2DJumpAndRunWithPhysics/Animations/RobotKyle2D.controller.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: c4166aae2783a884dbf46290328260bd +NativeFormatImporter: + userData: diff --git a/Assets/Photon Unity Networking/Demos/Demo2DJumpAndRunWithPhysics/Animations/Run.anim b/Assets/Photon Unity Networking/Demos/Demo2DJumpAndRunWithPhysics/Animations/Run.anim new file mode 100644 index 0000000..b6c9fd6 Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/Demo2DJumpAndRunWithPhysics/Animations/Run.anim differ diff --git a/Assets/Photon Unity Networking/Demos/Demo2DJumpAndRunWithPhysics/Animations/Run.anim.meta b/Assets/Photon Unity Networking/Demos/Demo2DJumpAndRunWithPhysics/Animations/Run.anim.meta new file mode 100644 index 0000000..fa5a518 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/Demo2DJumpAndRunWithPhysics/Animations/Run.anim.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: 34cffcb838cf9d64383508932cb3c8c0 +NativeFormatImporter: + userData: diff --git a/Assets/Photon Unity Networking/Demos/Demo2DJumpAndRunWithPhysics/Demo2DJumpAndRunWithPhysics-Scene.unity b/Assets/Photon Unity Networking/Demos/Demo2DJumpAndRunWithPhysics/Demo2DJumpAndRunWithPhysics-Scene.unity new file mode 100644 index 0000000..8c79bec Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/Demo2DJumpAndRunWithPhysics/Demo2DJumpAndRunWithPhysics-Scene.unity differ diff --git a/Assets/Photon Unity Networking/Demos/Demo2DJumpAndRunWithPhysics/Demo2DJumpAndRunWithPhysics-Scene.unity.meta b/Assets/Photon Unity Networking/Demos/Demo2DJumpAndRunWithPhysics/Demo2DJumpAndRunWithPhysics-Scene.unity.meta new file mode 100644 index 0000000..e14cd09 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/Demo2DJumpAndRunWithPhysics/Demo2DJumpAndRunWithPhysics-Scene.unity.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: 2cd8533503c3ea649b6c543c6126c811 +DefaultImporter: + userData: diff --git a/Assets/Photon Unity Networking/Demos/Demo2DJumpAndRunWithPhysics/Resources.meta b/Assets/Photon Unity Networking/Demos/Demo2DJumpAndRunWithPhysics/Resources.meta new file mode 100644 index 0000000..3930c01 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/Demo2DJumpAndRunWithPhysics/Resources.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 2e651d310d480470cb775de4bc4ece44 +folderAsset: yes +timeCreated: 1501014811 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Photon Unity Networking/Demos/Demo2DJumpAndRunWithPhysics/Resources/Physics Box.prefab b/Assets/Photon Unity Networking/Demos/Demo2DJumpAndRunWithPhysics/Resources/Physics Box.prefab new file mode 100644 index 0000000..5a63709 Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/Demo2DJumpAndRunWithPhysics/Resources/Physics Box.prefab differ diff --git a/Assets/Photon Unity Networking/Demos/Demo2DJumpAndRunWithPhysics/Resources/Physics Box.prefab.meta b/Assets/Photon Unity Networking/Demos/Demo2DJumpAndRunWithPhysics/Resources/Physics Box.prefab.meta new file mode 100644 index 0000000..a221e8c --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/Demo2DJumpAndRunWithPhysics/Resources/Physics Box.prefab.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: 71f9695057c753246adc29fcbd25f30a +NativeFormatImporter: + userData: diff --git a/Assets/Photon Unity Networking/Demos/Demo2DJumpAndRunWithPhysics/Resources/Robot Kyle 2D.prefab b/Assets/Photon Unity Networking/Demos/Demo2DJumpAndRunWithPhysics/Resources/Robot Kyle 2D.prefab new file mode 100644 index 0000000..40bc824 Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/Demo2DJumpAndRunWithPhysics/Resources/Robot Kyle 2D.prefab differ diff --git a/Assets/Photon Unity Networking/Demos/Demo2DJumpAndRunWithPhysics/Resources/Robot Kyle 2D.prefab.meta b/Assets/Photon Unity Networking/Demos/Demo2DJumpAndRunWithPhysics/Resources/Robot Kyle 2D.prefab.meta new file mode 100644 index 0000000..13ce84d --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/Demo2DJumpAndRunWithPhysics/Resources/Robot Kyle 2D.prefab.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: ae31d748c0bbc05448a13e58f8861963 +NativeFormatImporter: + userData: diff --git a/Assets/Photon Unity Networking/Demos/Demo2DJumpAndRunWithPhysics/Scripts.meta b/Assets/Photon Unity Networking/Demos/Demo2DJumpAndRunWithPhysics/Scripts.meta new file mode 100644 index 0000000..0123b75 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/Demo2DJumpAndRunWithPhysics/Scripts.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 857b444ac6fc348129371f37c898439c +folderAsset: yes +timeCreated: 1501014811 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Photon Unity Networking/Demos/Demo2DJumpAndRunWithPhysics/Scripts/Demo2DJumpAndRun.cs b/Assets/Photon Unity Networking/Demos/Demo2DJumpAndRunWithPhysics/Scripts/Demo2DJumpAndRun.cs new file mode 100644 index 0000000..af23fb5 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/Demo2DJumpAndRunWithPhysics/Scripts/Demo2DJumpAndRun.cs @@ -0,0 +1,21 @@ +using UnityEngine; +using System.Collections; + +public class Demo2DJumpAndRun : MonoBehaviour +{ + void OnJoinedRoom() + { + if( PhotonNetwork.isMasterClient == false ) + { + return; + } + + PhotonNetwork.InstantiateSceneObject( "Physics Box", new Vector3( -4.5f, 5.5f, 0 ), Quaternion.identity, 0, null ); + PhotonNetwork.InstantiateSceneObject( "Physics Box", new Vector3( -4.5f, 4.5f, 0 ), Quaternion.identity, 0, null ); + PhotonNetwork.InstantiateSceneObject( "Physics Box", new Vector3( -4.5f, 3.5f, 0 ), Quaternion.identity, 0, null ); + + PhotonNetwork.InstantiateSceneObject( "Physics Box", new Vector3( 4.5f, 5.5f, 0 ), Quaternion.identity, 0, null ); + PhotonNetwork.InstantiateSceneObject( "Physics Box", new Vector3( 4.5f, 4.5f, 0 ), Quaternion.identity, 0, null ); + PhotonNetwork.InstantiateSceneObject( "Physics Box", new Vector3( 4.5f, 3.5f, 0 ), Quaternion.identity, 0, null ); + } +} diff --git a/Assets/Photon Unity Networking/Demos/Demo2DJumpAndRunWithPhysics/Scripts/Demo2DJumpAndRun.cs.meta b/Assets/Photon Unity Networking/Demos/Demo2DJumpAndRunWithPhysics/Scripts/Demo2DJumpAndRun.cs.meta new file mode 100644 index 0000000..d23a067 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/Demo2DJumpAndRunWithPhysics/Scripts/Demo2DJumpAndRun.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 712cc66bfe310e0488fe518dca4440a7 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Photon Unity Networking/Demos/Demo2DJumpAndRunWithPhysics/Scripts/JumpAndRunMovement.cs b/Assets/Photon Unity Networking/Demos/Demo2DJumpAndRunWithPhysics/Scripts/JumpAndRunMovement.cs new file mode 100644 index 0000000..0a1d309 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/Demo2DJumpAndRunWithPhysics/Scripts/JumpAndRunMovement.cs @@ -0,0 +1,104 @@ +using UnityEngine; +using System.Collections; + +public class JumpAndRunMovement : MonoBehaviour +{ + public float Speed; + public float JumpForce; + + Animator m_Animator; + Rigidbody2D m_Body; + PhotonView m_PhotonView; + + bool m_IsGrounded; + + void Awake() + { + m_Animator = GetComponent(); + m_Body = GetComponent(); + m_PhotonView = GetComponent(); + } + + void Update() + { + UpdateIsGrounded(); + UpdateIsRunning(); + UpdateFacingDirection(); + } + + void FixedUpdate() + { + if( m_PhotonView.isMine == false ) + { + return; + } + + UpdateMovement(); + UpdateJumping(); + } + + void UpdateFacingDirection() + { + if( m_Body.velocity.x > 0.2f ) + { + transform.localScale = new Vector3( 1, 1, 1 ); + } + else if( m_Body.velocity.x < -0.2f ) + { + transform.localScale = new Vector3( -1, 1, 1 ); + } + } + + void UpdateJumping() + { + if (Input.GetButton("Jump") && m_IsGrounded) + { + m_Animator.SetTrigger("IsJumping"); + m_Body.AddForce(Vector2.up * JumpForce); + m_PhotonView.RPC("DoJump", PhotonTargets.Others); + } + } + + [PunRPC] + void DoJump() + { + m_Animator.SetTrigger( "IsJumping" ); + } + + void UpdateMovement() + { + Vector2 movementVelocity = m_Body.velocity; + + if( Input.GetAxisRaw( "Horizontal" ) > 0.5f ) + { + movementVelocity.x = Speed; + + } + else if( Input.GetAxisRaw( "Horizontal" ) < -0.5f ) + { + movementVelocity.x = -Speed; + } + else + { + movementVelocity.x = 0; + } + + m_Body.velocity = movementVelocity; + } + + void UpdateIsRunning() + { + m_Animator.SetBool( "IsRunning", Mathf.Abs( m_Body.velocity.x ) > 0.1f ); + } + + void UpdateIsGrounded() + { + Vector2 position = new Vector2( transform.position.x, transform.position.y ); + + //RaycastHit2D hit = Physics2D.Raycast( position, -Vector2.up, 0.1f, 1 << LayerMask.NameToLayer( "Ground" ) ); + RaycastHit2D hit = Physics2D.Raycast(position, -Vector2.up, 0.1f); + + m_IsGrounded = hit.collider != null; + m_Animator.SetBool( "IsGrounded", m_IsGrounded ); + } +} diff --git a/Assets/Photon Unity Networking/Demos/Demo2DJumpAndRunWithPhysics/Scripts/JumpAndRunMovement.cs.meta b/Assets/Photon Unity Networking/Demos/Demo2DJumpAndRunWithPhysics/Scripts/JumpAndRunMovement.cs.meta new file mode 100644 index 0000000..941f277 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/Demo2DJumpAndRunWithPhysics/Scripts/JumpAndRunMovement.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: a48660ddd165ff24d9eb599515ce2853 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Photon Unity Networking/Demos/Demo2DJumpAndRunWithPhysics/Sprites.meta b/Assets/Photon Unity Networking/Demos/Demo2DJumpAndRunWithPhysics/Sprites.meta new file mode 100644 index 0000000..0c59b7f --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/Demo2DJumpAndRunWithPhysics/Sprites.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 2d0346fdb41d04584a9f5aef6a80e6e8 +folderAsset: yes +timeCreated: 1501014811 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Photon Unity Networking/Demos/Demo2DJumpAndRunWithPhysics/Sprites/Background.png b/Assets/Photon Unity Networking/Demos/Demo2DJumpAndRunWithPhysics/Sprites/Background.png new file mode 100644 index 0000000..3c21ceb Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/Demo2DJumpAndRunWithPhysics/Sprites/Background.png differ diff --git a/Assets/Photon Unity Networking/Demos/Demo2DJumpAndRunWithPhysics/Sprites/Background.png.meta b/Assets/Photon Unity Networking/Demos/Demo2DJumpAndRunWithPhysics/Sprites/Background.png.meta new file mode 100644 index 0000000..4b29e43 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/Demo2DJumpAndRunWithPhysics/Sprites/Background.png.meta @@ -0,0 +1,45 @@ +fileFormatVersion: 2 +guid: 1bdfbf15f6abec34e9bb38e2d81fcc84 +TextureImporter: + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + linearTexture: 0 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -3 + maxTextureSize: 1024 + textureSettings: + filterMode: -1 + aniso: 1 + mipBias: -1 + wrapMode: 1 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spritePixelsToUnits: 128 + alphaIsTransparency: 1 + textureType: 8 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/Assets/Photon Unity Networking/Demos/Demo2DJumpAndRunWithPhysics/Sprites/Box.png b/Assets/Photon Unity Networking/Demos/Demo2DJumpAndRunWithPhysics/Sprites/Box.png new file mode 100644 index 0000000..886bd67 Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/Demo2DJumpAndRunWithPhysics/Sprites/Box.png differ diff --git a/Assets/Photon Unity Networking/Demos/Demo2DJumpAndRunWithPhysics/Sprites/Box.png.meta b/Assets/Photon Unity Networking/Demos/Demo2DJumpAndRunWithPhysics/Sprites/Box.png.meta new file mode 100644 index 0000000..f855ffc --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/Demo2DJumpAndRunWithPhysics/Sprites/Box.png.meta @@ -0,0 +1,45 @@ +fileFormatVersion: 2 +guid: db4b1de3894093748ba777a98ddacd8b +TextureImporter: + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + linearTexture: 0 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -3 + maxTextureSize: 1024 + textureSettings: + filterMode: -1 + aniso: 1 + mipBias: -1 + wrapMode: 1 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spritePixelsToUnits: 128 + alphaIsTransparency: 1 + textureType: 8 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/Assets/Photon Unity Networking/Demos/Demo2DJumpAndRunWithPhysics/Sprites/CharacterFrictionless.physicsMaterial2D b/Assets/Photon Unity Networking/Demos/Demo2DJumpAndRunWithPhysics/Sprites/CharacterFrictionless.physicsMaterial2D new file mode 100644 index 0000000..891c16b Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/Demo2DJumpAndRunWithPhysics/Sprites/CharacterFrictionless.physicsMaterial2D differ diff --git a/Assets/Photon Unity Networking/Demos/Demo2DJumpAndRunWithPhysics/Sprites/CharacterFrictionless.physicsMaterial2D.meta b/Assets/Photon Unity Networking/Demos/Demo2DJumpAndRunWithPhysics/Sprites/CharacterFrictionless.physicsMaterial2D.meta new file mode 100644 index 0000000..e6952fe --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/Demo2DJumpAndRunWithPhysics/Sprites/CharacterFrictionless.physicsMaterial2D.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: 5655d3beb0cbd324682a07c9f6ab7a6b +NativeFormatImporter: + userData: diff --git a/Assets/Photon Unity Networking/Demos/Demo2DJumpAndRunWithPhysics/Sprites/CharacterSheet.psd b/Assets/Photon Unity Networking/Demos/Demo2DJumpAndRunWithPhysics/Sprites/CharacterSheet.psd new file mode 100644 index 0000000..30ae7af Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/Demo2DJumpAndRunWithPhysics/Sprites/CharacterSheet.psd differ diff --git a/Assets/Photon Unity Networking/Demos/Demo2DJumpAndRunWithPhysics/Sprites/CharacterSheet.psd.meta b/Assets/Photon Unity Networking/Demos/Demo2DJumpAndRunWithPhysics/Sprites/CharacterSheet.psd.meta new file mode 100644 index 0000000..4f50ddb --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/Demo2DJumpAndRunWithPhysics/Sprites/CharacterSheet.psd.meta @@ -0,0 +1,1107 @@ +fileFormatVersion: 2 +guid: 6eedfc74195a44648b72bcf755811a88 +TextureImporter: + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + linearTexture: 0 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -3 + maxTextureSize: 1024 + textureSettings: + filterMode: -1 + aniso: 1 + mipBias: -1 + wrapMode: 1 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 2 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spritePixelsToUnits: 65 + alphaIsTransparency: 1 + textureType: 8 + buildTargetSettings: [] + spriteSheet: + sprites: + - name: idle_0 + rect: + serializedVersion: 2 + x: 13 + y: 916 + width: 20 + height: 99 + alignment: 7 + pivot: {x: .5, y: 0} + - name: idle_1 + rect: + serializedVersion: 2 + x: 44 + y: 916 + width: 21 + height: 99 + alignment: 7 + pivot: {x: .5, y: 0} + - name: idle_2 + rect: + serializedVersion: 2 + x: 76 + y: 916 + width: 21 + height: 99 + alignment: 7 + pivot: {x: .5, y: 0} + - name: idle_3 + rect: + serializedVersion: 2 + x: 111 + y: 916 + width: 20 + height: 99 + alignment: 7 + pivot: {x: .5, y: 0} + - name: idle_4 + rect: + serializedVersion: 2 + x: 143 + y: 916 + width: 21 + height: 99 + alignment: 7 + pivot: {x: .5, y: 0} + - name: idle_5 + rect: + serializedVersion: 2 + x: 177 + y: 916 + width: 20 + height: 99 + alignment: 7 + pivot: {x: .5, y: 0} + - name: idle_6 + rect: + serializedVersion: 2 + x: 212 + y: 916 + width: 21 + height: 99 + alignment: 7 + pivot: {x: .5, y: 0} + - name: idle_7 + rect: + serializedVersion: 2 + x: 245 + y: 916 + width: 21 + height: 99 + alignment: 7 + pivot: {x: .5, y: 0} + - name: idle_8 + rect: + serializedVersion: 2 + x: 282 + y: 916 + width: 20 + height: 99 + alignment: 7 + pivot: {x: .5, y: 0} + - name: idle_9 + rect: + serializedVersion: 2 + x: 319 + y: 916 + width: 21 + height: 99 + alignment: 7 + pivot: {x: .5, y: 0} + - name: idle_10 + rect: + serializedVersion: 2 + x: 355 + y: 916 + width: 21 + height: 99 + alignment: 7 + pivot: {x: .5, y: 0} + - name: idle_11 + rect: + serializedVersion: 2 + x: 387 + y: 916 + width: 21 + height: 99 + alignment: 7 + pivot: {x: .5, y: 0} + - name: idle_12 + rect: + serializedVersion: 2 + x: 417 + y: 916 + width: 20 + height: 99 + alignment: 7 + pivot: {x: .5, y: 0} + - name: idle_13 + rect: + serializedVersion: 2 + x: 446 + y: 916 + width: 20 + height: 99 + alignment: 7 + pivot: {x: .5, y: 0} + - name: idle_14 + rect: + serializedVersion: 2 + x: 473 + y: 916 + width: 20 + height: 99 + alignment: 7 + pivot: {x: .5, y: 0} + - name: run_15 + rect: + serializedVersion: 2 + x: 835 + y: 905 + width: 74 + height: 88 + alignment: 7 + pivot: {x: .5, y: 0} + - name: run_16 + rect: + serializedVersion: 2 + x: 924 + y: 903 + width: 74 + height: 88 + alignment: 7 + pivot: {x: .5, y: 0} + - name: run_0 + rect: + serializedVersion: 2 + x: 2 + y: 809 + width: 71 + height: 89 + alignment: 7 + pivot: {x: .5, y: 0} + - name: run_1 + rect: + serializedVersion: 2 + x: 76 + y: 809 + width: 66 + height: 89 + alignment: 7 + pivot: {x: .5, y: 0} + - name: run_2 + rect: + serializedVersion: 2 + x: 144 + y: 807 + width: 63 + height: 88 + alignment: 7 + pivot: {x: .5, y: 0} + - name: run_3 + rect: + serializedVersion: 2 + x: 217 + y: 807 + width: 59 + height: 88 + alignment: 7 + pivot: {x: .5, y: 0} + - name: run_4 + rect: + serializedVersion: 2 + x: 281 + y: 808 + width: 54 + height: 87 + alignment: 7 + pivot: {x: .5, y: 0} + - name: run_5 + rect: + serializedVersion: 2 + x: 338 + y: 808 + width: 48 + height: 87 + alignment: 7 + pivot: {x: .5, y: 0} + - name: run_6 + rect: + serializedVersion: 2 + x: 393 + y: 808 + width: 45 + height: 88 + alignment: 7 + pivot: {x: .5, y: 0} + - name: run_7 + rect: + serializedVersion: 2 + x: 447 + y: 805 + width: 48 + height: 90 + alignment: 7 + pivot: {x: .5, y: 0} + - name: run_8 + rect: + serializedVersion: 2 + x: 499 + y: 803 + width: 54 + height: 91 + alignment: 7 + pivot: {x: .5, y: 0} + - name: run_9 + rect: + serializedVersion: 2 + x: 561 + y: 801 + width: 57 + height: 91 + alignment: 7 + pivot: {x: .5, y: 0} + - name: run_10 + rect: + serializedVersion: 2 + x: 624 + y: 806 + width: 61 + height: 91 + alignment: 7 + pivot: {x: .5, y: 0} + - name: run_11 + rect: + serializedVersion: 2 + x: 692 + y: 805 + width: 64 + height: 90 + alignment: 7 + pivot: {x: .5, y: 0} + - name: run_12 + rect: + serializedVersion: 2 + x: 772 + y: 804 + width: 67 + height: 86 + alignment: 7 + pivot: {x: .5, y: 0} + - name: run_14 + rect: + serializedVersion: 2 + x: 856 + y: 804 + width: 71 + height: 86 + alignment: 7 + pivot: {x: .5, y: 0} + - name: run_17 + rect: + serializedVersion: 2 + x: 1 + y: 701 + width: 72 + height: 89 + alignment: 7 + pivot: {x: .5, y: 0} + - name: run_18 + rect: + serializedVersion: 2 + x: 79 + y: 701 + width: 67 + height: 89 + alignment: 7 + pivot: {x: .5, y: 0} + - name: run_19 + rect: + serializedVersion: 2 + x: 153 + y: 700 + width: 64 + height: 88 + alignment: 7 + pivot: {x: .5, y: 0} + - name: run_20 + rect: + serializedVersion: 2 + x: 217 + y: 699 + width: 60 + height: 88 + alignment: 7 + pivot: {x: .5, y: 0} + - name: run_21 + rect: + serializedVersion: 2 + x: 282 + y: 699 + width: 55 + height: 87 + alignment: 7 + pivot: {x: .5, y: 0} + - name: run_22 + rect: + serializedVersion: 2 + x: 344 + y: 698 + width: 50 + height: 86 + alignment: 7 + pivot: {x: .5, y: 0} + - name: run_23 + rect: + serializedVersion: 2 + x: 405 + y: 699 + width: 45 + height: 87 + alignment: 7 + pivot: {x: .5, y: 0} + - name: run_24 + rect: + serializedVersion: 2 + x: 458 + y: 699 + width: 49 + height: 87 + alignment: 7 + pivot: {x: .5, y: 0} + - name: run_25 + rect: + serializedVersion: 2 + x: 513 + y: 698 + width: 54 + height: 89 + alignment: 7 + pivot: {x: .5, y: 0} + - name: run_26 + rect: + serializedVersion: 2 + x: 579 + y: 696 + width: 59 + height: 91 + alignment: 7 + pivot: {x: .5, y: 0} + - name: run_27 + rect: + serializedVersion: 2 + x: 642 + y: 695 + width: 63 + height: 91 + alignment: 7 + pivot: {x: .5, y: 0} + - name: run_28 + rect: + serializedVersion: 2 + x: 709 + y: 695 + width: 66 + height: 89 + alignment: 7 + pivot: {x: .5, y: 0} + - name: run_29 + rect: + serializedVersion: 2 + x: 780 + y: 697 + width: 68 + height: 87 + alignment: 7 + pivot: {x: .5, y: 0} + - name: run_30 + rect: + serializedVersion: 2 + x: 852 + y: 700 + width: 70 + height: 87 + alignment: 7 + pivot: {x: .5, y: 0} + - name: run_31 + rect: + serializedVersion: 2 + x: 932 + y: 697 + width: 72 + height: 88 + alignment: 7 + pivot: {x: .5, y: 0} + - name: jump_0 + rect: + serializedVersion: 2 + x: 2 + y: 578 + width: 38 + height: 86 + alignment: 7 + pivot: {x: .5, y: 0} + - name: jump_1 + rect: + serializedVersion: 2 + x: 50 + y: 578 + width: 38 + height: 86 + alignment: 7 + pivot: {x: .5, y: 0} + - name: jump_2 + rect: + serializedVersion: 2 + x: 101 + y: 576 + width: 40 + height: 91 + alignment: 7 + pivot: {x: .5, y: 0} + - name: jump_3 + rect: + serializedVersion: 2 + x: 152 + y: 573 + width: 46 + height: 91 + alignment: 7 + pivot: {x: .5, y: 0} + - name: jump_4 + rect: + serializedVersion: 2 + x: 205 + y: 574 + width: 50 + height: 89 + alignment: 7 + pivot: {x: .5, y: 0} + - name: jump_5 + rect: + serializedVersion: 2 + x: 271 + y: 576 + width: 52 + height: 90 + alignment: 7 + pivot: {x: .5, y: 0} + - name: jump_6 + rect: + serializedVersion: 2 + x: 330 + y: 578 + width: 52 + height: 90 + alignment: 7 + pivot: {x: .5, y: 0} + - name: jump_7 + rect: + serializedVersion: 2 + x: 395 + y: 579 + width: 53 + height: 91 + alignment: 7 + pivot: {x: .5, y: 0} + - name: jump_8 + rect: + serializedVersion: 2 + x: 452 + y: 579 + width: 54 + height: 92 + alignment: 7 + pivot: {x: .5, y: 0} + - name: jump_9 + rect: + serializedVersion: 2 + x: 506 + y: 579 + width: 51 + height: 94 + alignment: 7 + pivot: {x: .5, y: 0} + - name: jump_10 + rect: + serializedVersion: 2 + x: 561 + y: 580 + width: 50 + height: 99 + alignment: 7 + pivot: {x: .5, y: 0} + - name: jump_11 + rect: + serializedVersion: 2 + x: 612 + y: 579 + width: 50 + height: 104 + alignment: 7 + pivot: {x: .5, y: 0} + - name: jump_12 + rect: + serializedVersion: 2 + x: 665 + y: 575 + width: 49 + height: 108 + alignment: 7 + pivot: {x: .5, y: 0} + - name: jump_13 + rect: + serializedVersion: 2 + x: 716 + y: 576 + width: 48 + height: 109 + alignment: 7 + pivot: {x: .5, y: 0} + - name: jump_14 + rect: + serializedVersion: 2 + x: 769 + y: 579 + width: 46 + height: 109 + alignment: 7 + pivot: {x: .5, y: 0} + - name: jump_15 + rect: + serializedVersion: 2 + x: 818 + y: 576 + width: 47 + height: 111 + alignment: 7 + pivot: {x: .5, y: 0} + - name: jump_16 + rect: + serializedVersion: 2 + x: 866 + y: 578 + width: 48 + height: 109 + alignment: 7 + pivot: {x: .5, y: 0} + - name: jump_17 + rect: + serializedVersion: 2 + x: 918 + y: 577 + width: 50 + height: 105 + alignment: 7 + pivot: {x: .5, y: 0} + - name: jump_18 + rect: + serializedVersion: 2 + x: 969 + y: 578 + width: 53 + height: 99 + alignment: 7 + pivot: {x: .5, y: 0} + - name: jump_19 + rect: + serializedVersion: 2 + x: 3 + y: 458 + width: 56 + height: 94 + alignment: 7 + pivot: {x: .5, y: 0} + - name: jump_20 + rect: + serializedVersion: 2 + x: 61 + y: 462 + width: 58 + height: 90 + alignment: 7 + pivot: {x: .5, y: 0} + - name: jump_21 + rect: + serializedVersion: 2 + x: 124 + y: 466 + width: 58 + height: 86 + alignment: 7 + pivot: {x: .5, y: 0} + - name: jump_22 + rect: + serializedVersion: 2 + x: 186 + y: 470 + width: 55 + height: 82 + alignment: 7 + pivot: {x: .5, y: 0} + - name: jump_23 + rect: + serializedVersion: 2 + x: 245 + y: 473 + width: 52 + height: 79 + alignment: 7 + pivot: {x: .5, y: 0} + - name: jump_24 + rect: + serializedVersion: 2 + x: 300 + y: 470 + width: 52 + height: 78 + alignment: 7 + pivot: {x: .5, y: 0} + - name: jump_25 + rect: + serializedVersion: 2 + x: 355 + y: 473 + width: 52 + height: 79 + alignment: 7 + pivot: {x: .5, y: 0} + - name: jump_26 + rect: + serializedVersion: 2 + x: 411 + y: 473 + width: 50 + height: 79 + alignment: 7 + pivot: {x: .5, y: 0} + - name: jump_27 + rect: + serializedVersion: 2 + x: 462 + y: 473 + width: 47 + height: 80 + alignment: 7 + pivot: {x: .5, y: 0} + - name: jump_28 + rect: + serializedVersion: 2 + x: 509 + y: 473 + width: 44 + height: 82 + alignment: 7 + pivot: {x: .5, y: 0} + - name: jump_29 + rect: + serializedVersion: 2 + x: 562 + y: 469 + width: 40 + height: 84 + alignment: 7 + pivot: {x: .5, y: 0} + - name: jump_30 + rect: + serializedVersion: 2 + x: 609 + y: 471 + width: 39 + height: 86 + alignment: 7 + pivot: {x: .5, y: 0} + - name: jump_31 + rect: + serializedVersion: 2 + x: 654 + y: 471 + width: 39 + height: 88 + alignment: 7 + pivot: {x: .5, y: 0} + - name: jump_32 + rect: + serializedVersion: 2 + x: 696 + y: 470 + width: 37 + height: 90 + alignment: 7 + pivot: {x: .5, y: 0} + - name: jump_33 + rect: + serializedVersion: 2 + x: 740 + y: 468 + width: 36 + height: 92 + alignment: 7 + pivot: {x: .5, y: 0} + - name: jump_34 + rect: + serializedVersion: 2 + x: 779 + y: 464 + width: 40 + height: 95 + alignment: 7 + pivot: {x: .5, y: 0} + - name: jump_35 + rect: + serializedVersion: 2 + x: 820 + y: 467 + width: 45 + height: 97 + alignment: 7 + pivot: {x: .5, y: 0} + - name: jump_36 + rect: + serializedVersion: 2 + x: 866 + y: 464 + width: 48 + height: 98 + alignment: 7 + pivot: {x: .5, y: 0} + - name: jump_37 + rect: + serializedVersion: 2 + x: 914 + y: 463 + width: 52 + height: 99 + alignment: 7 + pivot: {x: .5, y: 0} + - name: jump_38 + rect: + serializedVersion: 2 + x: 969 + y: 465 + width: 53 + height: 98 + alignment: 7 + pivot: {x: .5, y: 0} + - name: land_0 + rect: + serializedVersion: 2 + x: 7 + y: 318 + width: 53 + height: 100 + alignment: 7 + pivot: {x: .5, y: 0} + - name: land_1 + rect: + serializedVersion: 2 + x: 73 + y: 318 + width: 51 + height: 100 + alignment: 7 + pivot: {x: .5, y: 0} + - name: land_2 + rect: + serializedVersion: 2 + x: 145 + y: 318 + width: 52 + height: 96 + alignment: 7 + pivot: {x: .5, y: 0} + - name: land_3 + rect: + serializedVersion: 2 + x: 219 + y: 324 + width: 48 + height: 94 + alignment: 7 + pivot: {x: .5, y: 0} + - name: land_4 + rect: + serializedVersion: 2 + x: 283 + y: 324 + width: 46 + height: 91 + alignment: 7 + pivot: {x: .5, y: 0} + - name: land_5 + rect: + serializedVersion: 2 + x: 345 + y: 324 + width: 42 + height: 88 + alignment: 7 + pivot: {x: .5, y: 0} + - name: land_6 + rect: + serializedVersion: 2 + x: 403 + y: 324 + width: 37 + height: 88 + alignment: 7 + pivot: {x: .5, y: 0} + - name: land_7 + rect: + serializedVersion: 2 + x: 459 + y: 323 + width: 32 + height: 87 + alignment: 7 + pivot: {x: .5, y: 0} + - name: land_8 + rect: + serializedVersion: 2 + x: 513 + y: 325 + width: 30 + height: 86 + alignment: 7 + pivot: {x: .5, y: 0} + - name: land_9 + rect: + serializedVersion: 2 + x: 566 + y: 323 + width: 31 + height: 86 + alignment: 7 + pivot: {x: .5, y: 0} + - name: land_10 + rect: + serializedVersion: 2 + x: 615 + y: 324 + width: 33 + height: 86 + alignment: 7 + pivot: {x: .5, y: 0} + - name: land_11 + rect: + serializedVersion: 2 + x: 670 + y: 323 + width: 35 + height: 85 + alignment: 7 + pivot: {x: .5, y: 0} + - name: land_12 + rect: + serializedVersion: 2 + x: 726 + y: 324 + width: 37 + height: 84 + alignment: 7 + pivot: {x: .5, y: 0} + - name: land_13 + rect: + serializedVersion: 2 + x: 780 + y: 323 + width: 38 + height: 84 + alignment: 7 + pivot: {x: .5, y: 0} + - name: land_14 + rect: + serializedVersion: 2 + x: 838 + y: 324 + width: 38 + height: 84 + alignment: 7 + pivot: {x: .5, y: 0} + - name: land_15 + rect: + serializedVersion: 2 + x: 898 + y: 324 + width: 37 + height: 86 + alignment: 7 + pivot: {x: .5, y: 0} + - name: land_16 + rect: + serializedVersion: 2 + x: 956 + y: 324 + width: 37 + height: 86 + alignment: 7 + pivot: {x: .5, y: 0} + - name: land_17 + rect: + serializedVersion: 2 + x: 23 + y: 168 + width: 37 + height: 86 + alignment: 7 + pivot: {x: .5, y: 0} + - name: land_18 + rect: + serializedVersion: 2 + x: 80 + y: 168 + width: 37 + height: 87 + alignment: 7 + pivot: {x: .5, y: 0} + - name: land_19 + rect: + serializedVersion: 2 + x: 144 + y: 168 + width: 38 + height: 87 + alignment: 7 + pivot: {x: .5, y: 0} + - name: land_20 + rect: + serializedVersion: 2 + x: 203 + y: 168 + width: 37 + height: 87 + alignment: 7 + pivot: {x: .5, y: 0} + - name: land_21 + rect: + serializedVersion: 2 + x: 262 + y: 169 + width: 41 + height: 88 + alignment: 7 + pivot: {x: .5, y: 0} + - name: land_22 + rect: + serializedVersion: 2 + x: 317 + y: 168 + width: 45 + height: 90 + alignment: 7 + pivot: {x: .5, y: 0} + - name: land_23 + rect: + serializedVersion: 2 + x: 376 + y: 167 + width: 48 + height: 92 + alignment: 7 + pivot: {x: .5, y: 0} + - name: land_24 + rect: + serializedVersion: 2 + x: 437 + y: 165 + width: 51 + height: 92 + alignment: 7 + pivot: {x: .5, y: 0} + - name: land_25 + rect: + serializedVersion: 2 + x: 501 + y: 168 + width: 54 + height: 92 + alignment: 7 + pivot: {x: .5, y: 0} + - name: land_26 + rect: + serializedVersion: 2 + x: 567 + y: 169 + width: 56 + height: 90 + alignment: 7 + pivot: {x: .5, y: 0} + - name: land_27 + rect: + serializedVersion: 2 + x: 634 + y: 169 + width: 55 + height: 89 + alignment: 7 + pivot: {x: .5, y: 0} + - name: land_28 + rect: + serializedVersion: 2 + x: 710 + y: 167 + width: 54 + height: 90 + alignment: 7 + pivot: {x: .5, y: 0} + - name: land_29 + rect: + serializedVersion: 2 + x: 777 + y: 170 + width: 53 + height: 90 + alignment: 7 + pivot: {x: .5, y: 0} + - name: land_30 + rect: + serializedVersion: 2 + x: 837 + y: 170 + width: 52 + height: 90 + alignment: 7 + pivot: {x: .5, y: 0} + - name: land_31 + rect: + serializedVersion: 2 + x: 895 + y: 169 + width: 50 + height: 90 + alignment: 7 + pivot: {x: .5, y: 0} + - name: land_32 + rect: + serializedVersion: 2 + x: 955 + y: 168 + width: 48 + height: 89 + alignment: 7 + pivot: {x: .5, y: 0} + spritePackingTag: + userData: diff --git a/Assets/Photon Unity Networking/Demos/DemoBoxes.meta b/Assets/Photon Unity Networking/Demos/DemoBoxes.meta new file mode 100644 index 0000000..8a2a749 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoBoxes.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: a478a6c0315a64959829883a65588652 +folderAsset: yes +timeCreated: 1501014811 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Photon Unity Networking/Demos/DemoBoxes/ColorPerPlayer.cs b/Assets/Photon Unity Networking/Demos/DemoBoxes/ColorPerPlayer.cs new file mode 100644 index 0000000..99bdc24 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoBoxes/ColorPerPlayer.cs @@ -0,0 +1,137 @@ +using System.Collections.Generic; +using ExitGames.Client.Photon; +using Photon; +using UnityEngine; + +using ExitGames.UtilityScripts; + +/// +/// Basic script to assign a color per player in a PUN room. +/// +/// +/// This script is but one possible implementation to have players select a color in a room. +/// It uses a Custom Property per player to store currently selected colors. +/// When a player joins and someone else didn't pick a color yet, this script waits. +/// When a color is selected or a player leaves, this scripts selects a color if it didn't do that before. +/// +/// This could be extended to provide easy access to each player's color. Alternatively, you could write +/// extension methods for the PhotonPlayer class to access the Custom Property for colors in a seamless way. +/// See TeamExtensions for an example. +/// +public class ColorPerPlayer : PunBehaviour +{ + /// + /// Defines the available colors per room. There should be at least one color per available player spot. + /// + public Color[] Colors = new Color[] { Color.red, Color.blue, Color.yellow, Color.green }; + + /// + /// Property-key for Player Color. the value will be the index of the player's color in array Colors (0...) + /// + public const string ColorProp = "pc"; + + public bool ShowColorLabel; + public Rect ColorLabelArea = new Rect(0, 50, 100, 200); + public Texture2D img; + + /// + /// Color this player selected. Defaults to grey. + /// + public Color MyColor = Color.grey; + + public bool ColorPicked { get; set; } + + // we need to reach the PlayerRoomindexing Component. So for safe initialization, we avoid having to mess with script execution order + bool isInitialized; + + void OnEnable() + { + if (!isInitialized) + { + Init(); + } + } + + void Start() + { + if (!isInitialized) + { + Init(); + } + } + + void Init() + { + if (!isInitialized && PlayerRoomIndexing.instance!=null) + { + PlayerRoomIndexing.instance.OnRoomIndexingChanged += Refresh; + isInitialized = true; + } + } + + + void OnDisable() + { + PlayerRoomIndexing.instance.OnRoomIndexingChanged -= Refresh; + } + + void Refresh() + { + int _index = PhotonNetwork.player.GetRoomIndex(); + if (_index == -1) + { + this.Reset(); + }else{ + this.MyColor = this.Colors[_index]; + this.ColorPicked = true; + } + + } + + public override void OnJoinedRoom() + { + if (!isInitialized) + { + Init(); + } + } + + public override void OnLeftRoom() + { + // colors are select per room. + this.Reset(); + } + + + /// + /// Resets the color locally. In this class and the PhotonNetwork.player instance. + /// + public void Reset() + { + this.MyColor = Color.grey; + this.ColorPicked = false; + } + + + // simple UI to show color + private void OnGUI() + { + if (!this.ColorPicked || !this.ShowColorLabel) + { + return; + } + GUILayout.BeginArea(this.ColorLabelArea); + + GUILayout.BeginHorizontal(); + Color c = GUI.color; + GUI.color = this.MyColor; + GUILayout.Label(this.img); + GUI.color = c; + + string playerNote = (PhotonNetwork.isMasterClient) ? "is your color\nyou are the Master Client" : "is your color"; + GUILayout.Label(playerNote); + GUILayout.EndHorizontal(); + + GUILayout.EndArea(); + } +} \ No newline at end of file diff --git a/Assets/Photon Unity Networking/Demos/DemoBoxes/ColorPerPlayer.cs.meta b/Assets/Photon Unity Networking/Demos/DemoBoxes/ColorPerPlayer.cs.meta new file mode 100644 index 0000000..c107587 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoBoxes/ColorPerPlayer.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 22363507b0aff554ba53c98e8a40ff7c +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Photon Unity Networking/Demos/DemoBoxes/ColorPerPlayerApply.cs b/Assets/Photon Unity Networking/Demos/DemoBoxes/ColorPerPlayerApply.cs new file mode 100644 index 0000000..64da721 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoBoxes/ColorPerPlayerApply.cs @@ -0,0 +1,97 @@ +using Photon; +using UnityEngine; + +using ExitGames.UtilityScripts; + +/// Sample script that uses ColorPerPlayer to apply it to an object's material color. +public class ColorPerPlayerApply : PunBehaviour +{ + // ColorPerPlayer should be a singleton. As it's not, we cache the instance for all ColorPerPlayerApply + private static ColorPerPlayer colorPickerCache; + + // Cached, so we can apply color changes + private Renderer rendererComponent; + + // we need to reach the PlayerRoomindexing Component. So for safe initialization, we avoid having to mess with script execution order + bool isInitialized; + + void OnEnable() + { + if (!isInitialized) + { + Init(); + } + } + + void Start() + { + if (!isInitialized) + { + Init(); + } + } + + void Init() + { + if (!isInitialized && PlayerRoomIndexing.instance!=null) + { + PlayerRoomIndexing.instance.OnRoomIndexingChanged += ApplyColor; + isInitialized = true; + } + } + + + void OnDisable() + { + isInitialized = false; + if (PlayerRoomIndexing.instance!=null) + { + PlayerRoomIndexing.instance.OnRoomIndexingChanged -= ApplyColor; + } + } + + + public void Awake() + { + if (colorPickerCache == null) + { + colorPickerCache = FindObjectOfType() as ColorPerPlayer; + } + + if (colorPickerCache == null) + { + enabled = false; + } + if (photonView.isSceneView) + { + enabled = false; + } + + this.rendererComponent = GetComponent(); + } + + + /// Called by PUN on all components of network-instantiated GameObjects. + /// Details about this instantiation. + public override void OnPhotonInstantiate(PhotonMessageInfo info) + { + this.ApplyColor(); // this applies a color, even before the initial Update() call is done + } + + + public void ApplyColor() + { + if (photonView.owner == null) + { + return; + } + + int _index = photonView.owner.GetRoomIndex(); + + if (_index>=0 && _index<=colorPickerCache.Colors.Length) + { + this.rendererComponent.material.color = colorPickerCache.Colors[_index]; + } + + } +} \ No newline at end of file diff --git a/Assets/Photon Unity Networking/Demos/DemoBoxes/ColorPerPlayerApply.cs.meta b/Assets/Photon Unity Networking/Demos/DemoBoxes/ColorPerPlayerApply.cs.meta new file mode 100644 index 0000000..b8b18f7 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoBoxes/ColorPerPlayerApply.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 5939d811d6e07c04e98e97cfcdb57a59 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Photon Unity Networking/Demos/DemoBoxes/DemoBoxes-Scene.unity b/Assets/Photon Unity Networking/Demos/DemoBoxes/DemoBoxes-Scene.unity new file mode 100644 index 0000000..617101b Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/DemoBoxes/DemoBoxes-Scene.unity differ diff --git a/Assets/Photon Unity Networking/Demos/DemoBoxes/DemoBoxes-Scene.unity.meta b/Assets/Photon Unity Networking/Demos/DemoBoxes/DemoBoxes-Scene.unity.meta new file mode 100644 index 0000000..8cd2823 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoBoxes/DemoBoxes-Scene.unity.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 484b70123468e8d47b39976c6516756b diff --git a/Assets/Photon Unity Networking/Demos/DemoBoxes/DemoBoxesGui.cs b/Assets/Photon Unity Networking/Demos/DemoBoxes/DemoBoxesGui.cs new file mode 100644 index 0000000..5e9cf20 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoBoxes/DemoBoxesGui.cs @@ -0,0 +1,98 @@ +using System.Collections; +using UnityEngine; + +public class DemoBoxesGui : MonoBehaviour +{ + public bool HideUI = false; + + /// A GUI element to show tips in. + public GUIText GuiTextForTips; + + private int tipsIndex; + + private readonly string[] tips = new[] + { + "Click planes to instantiate boxes.", + "Click a box to send an RPC. This will flash the box.", + "Double click a box to destroy it. If it's yours.", + "Boxes send ~10 updates per second when moving.", + "Movement is not smoothed at all. It shows the updates 1:1.", + "The script ColorPerPlayer assigns a color per player.", + "When players leave, their boxes get destroyed. That's called clean up.", + "Scene Objects are not cleaned up. The Master Client can Instantiate them.", + "Scene Objects are not colored. They are controlled by the Master Client.", + "The elevated planes instantiate Scene Objects. Those don't get cleaned up.", + "Are you still reading?" + }; + + private const float TimePerTip = 3.0f; + private float timeSinceLastTip; + private const float FadeSpeedForTip = 0.05f; + + private void Update() + { + if (this.GuiTextForTips == null) + { + return; + } + + this.timeSinceLastTip += Time.deltaTime; + if (this.timeSinceLastTip > TimePerTip) + { + this.timeSinceLastTip = 0; + StartCoroutine("SwapTip"); // this does the fading. the coroutine ends when fading is done. + } + } + + + public IEnumerator SwapTip() + { + float alpha = 1.0f; + while (alpha > 0) + { + alpha -= FadeSpeedForTip; + this.timeSinceLastTip = 0; + this.GuiTextForTips.color = new Color(this.GuiTextForTips.color.r, this.GuiTextForTips.color.r, this.GuiTextForTips.color.r, alpha); + yield return null; + } + this.tipsIndex = (this.tipsIndex + 1)%this.tips.Length; + this.GuiTextForTips.text = this.tips[this.tipsIndex]; + while (alpha < 1.0f) + { + alpha += FadeSpeedForTip; + this.timeSinceLastTip = 0; + this.GuiTextForTips.color = new Color(this.GuiTextForTips.color.r, this.GuiTextForTips.color.r, this.GuiTextForTips.color.r, alpha); + yield return null; + } + } + + + private void OnGUI() + { + if (this.HideUI) + { + return; + } + + GUILayout.BeginArea(new Rect(0, 0, 300, Screen.height)); + GUILayout.FlexibleSpace(); + GUILayout.BeginHorizontal(); + if (!PhotonNetwork.connected) + { + if (GUILayout.Button("Connect", GUILayout.Width(100))) + { + PhotonNetwork.ConnectUsingSettings(null); + } + } + else + { + if (GUILayout.Button("Disconnect", GUILayout.Width(100))) + { + PhotonNetwork.Disconnect(); + } + } + GUILayout.Label(PhotonNetwork.connectionStateDetailed.ToString()); + GUILayout.EndHorizontal(); + GUILayout.EndArea(); + } +} \ No newline at end of file diff --git a/Assets/Photon Unity Networking/Demos/DemoBoxes/DemoBoxesGui.cs.meta b/Assets/Photon Unity Networking/Demos/DemoBoxes/DemoBoxesGui.cs.meta new file mode 100644 index 0000000..fad62c8 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoBoxes/DemoBoxesGui.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: e6348550714cc2848b5d10296ffb6cd6 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Photon Unity Networking/Demos/DemoBoxes/OnAwakePhysicsSettings.cs b/Assets/Photon Unity Networking/Demos/DemoBoxes/OnAwakePhysicsSettings.cs new file mode 100644 index 0000000..b938bf0 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoBoxes/OnAwakePhysicsSettings.cs @@ -0,0 +1,29 @@ +using UnityEngine; + +/// +/// Sets isKinematic to true, GameObject is owned by a another player (PhotonView.isMine == false). +/// For Rigidbody and Rigidbody2D. +/// +[RequireComponent(typeof (PhotonView))] +public class OnAwakePhysicsSettings : Photon.MonoBehaviour +{ + public void Awake() + { + if (!photonView.isMine) + { + Rigidbody attachedRigidbody = GetComponent(); + if (attachedRigidbody != null) + { + attachedRigidbody.isKinematic = true; + } + else + { + Rigidbody2D attachedRigidbody2d = GetComponent(); + if (attachedRigidbody2d != null) + { + attachedRigidbody2d.isKinematic = true; + } + } + } + } +} diff --git a/Assets/Photon Unity Networking/Demos/DemoBoxes/OnAwakePhysicsSettings.cs.meta b/Assets/Photon Unity Networking/Demos/DemoBoxes/OnAwakePhysicsSettings.cs.meta new file mode 100644 index 0000000..97f38e6 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoBoxes/OnAwakePhysicsSettings.cs.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 8f27e1c9e77b8774a97ded45b9c88268 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} diff --git a/Assets/Photon Unity Networking/Demos/DemoBoxes/OnClickFlashRpc.cs b/Assets/Photon Unity Networking/Demos/DemoBoxes/OnClickFlashRpc.cs new file mode 100644 index 0000000..ea06915 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoBoxes/OnClickFlashRpc.cs @@ -0,0 +1,50 @@ +using System.Collections; +using UnityEngine; + +public class OnClickFlashRpc : Photon.PunBehaviour +{ + private Material originalMaterial; + private Color originalColor; + private bool isFlashing; + + // called by InputToEvent. + // we use this GameObject's PhotonView to call an RPC on all clients in this room. + private void OnClick() + { + photonView.RPC("Flash", PhotonTargets.All); + } + + + // A PUN RPC. + // RPCs are only executed on the same GameObject that was used to call it. + // RPCs can be implemented as Coroutine, which is here used to flash the emissive color. + [PunRPC] + private IEnumerator Flash() + { + if (isFlashing) + { + yield break; + } + isFlashing = true; + + this.originalMaterial = GetComponent().material; + if (!this.originalMaterial.HasProperty("_Emission")) + { + Debug.LogWarning("Doesnt have emission, can't flash " + gameObject); + yield break; + } + + this.originalColor = this.originalMaterial.GetColor("_Emission"); + this.originalMaterial.SetColor("_Emission", Color.white); + + for (float f = 0.0f; f <= 1.0f; f += 0.08f) + { + Color lerped = Color.Lerp(Color.white, this.originalColor, f); + this.originalMaterial.SetColor("_Emission", lerped); + yield return null; + } + + this.originalMaterial.SetColor("_Emission", this.originalColor); + isFlashing = false; + } +} \ No newline at end of file diff --git a/Assets/Photon Unity Networking/Demos/DemoBoxes/OnClickFlashRpc.cs.meta b/Assets/Photon Unity Networking/Demos/DemoBoxes/OnClickFlashRpc.cs.meta new file mode 100644 index 0000000..4a043a7 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoBoxes/OnClickFlashRpc.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 39f5f392fce60324ba37de3e5a4c3272 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Photon Unity Networking/Demos/DemoBoxes/OnDoubleclickDestroy.cs b/Assets/Photon Unity Networking/Demos/DemoBoxes/OnDoubleclickDestroy.cs new file mode 100644 index 0000000..6d684fe --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoBoxes/OnDoubleclickDestroy.cs @@ -0,0 +1,31 @@ +using UnityEngine; + +public class OnDoubleclickDestroy : Photon.MonoBehaviour +{ + private float timeOfLastClick; + private const float ClickDeltaForDoubleclick = 0.2f; + + + // called by InputToEvent. + // we use a short timeout to detect double clicks. + // on double click, the networked object gets destroyed (on all clients). + private void OnClick() + { + if (!this.photonView.isMine) + { + // this networkView (provided by Photon.MonoBehaviour) says the object is not ours. + // so this client can't destroy it. + return; + } + + if (Time.time - this.timeOfLastClick < ClickDeltaForDoubleclick) + { + // double click => destory in network + PhotonNetwork.Destroy(gameObject); + } + else + { + this.timeOfLastClick = Time.time; + } + } +} \ No newline at end of file diff --git a/Assets/Photon Unity Networking/Demos/DemoBoxes/OnDoubleclickDestroy.cs.meta b/Assets/Photon Unity Networking/Demos/DemoBoxes/OnDoubleclickDestroy.cs.meta new file mode 100644 index 0000000..f8572fe --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoBoxes/OnDoubleclickDestroy.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: e4952a4e1868b224fb308a9fc6941aa4 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Photon Unity Networking/Demos/DemoBoxes/Resources.meta b/Assets/Photon Unity Networking/Demos/DemoBoxes/Resources.meta new file mode 100644 index 0000000..ce2352d --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoBoxes/Resources.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: c6025306e87f740ef9206ad946690e90 +folderAsset: yes +timeCreated: 1501014811 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Photon Unity Networking/Demos/DemoBoxes/Resources/BoxFlashPrefab.prefab b/Assets/Photon Unity Networking/Demos/DemoBoxes/Resources/BoxFlashPrefab.prefab new file mode 100644 index 0000000..df546ab Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/DemoBoxes/Resources/BoxFlashPrefab.prefab differ diff --git a/Assets/Photon Unity Networking/Demos/DemoBoxes/Resources/BoxFlashPrefab.prefab.meta b/Assets/Photon Unity Networking/Demos/DemoBoxes/Resources/BoxFlashPrefab.prefab.meta new file mode 100644 index 0000000..c68038a --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoBoxes/Resources/BoxFlashPrefab.prefab.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: fe06072e9e7fcb9478ad9b1e843e9148 +NativeFormatImporter: + userData: diff --git a/Assets/Photon Unity Networking/Demos/DemoBoxes/Resources/BoxPrefab.prefab b/Assets/Photon Unity Networking/Demos/DemoBoxes/Resources/BoxPrefab.prefab new file mode 100644 index 0000000..5e0ac60 Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/DemoBoxes/Resources/BoxPrefab.prefab differ diff --git a/Assets/Photon Unity Networking/Demos/DemoBoxes/Resources/BoxPrefab.prefab.meta b/Assets/Photon Unity Networking/Demos/DemoBoxes/Resources/BoxPrefab.prefab.meta new file mode 100644 index 0000000..3a1bceb --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoBoxes/Resources/BoxPrefab.prefab.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 0c55a789949849840bb994e514e8fa71 diff --git a/Assets/Photon Unity Networking/Demos/DemoBoxes/Resources/ColorPreview.png b/Assets/Photon Unity Networking/Demos/DemoBoxes/Resources/ColorPreview.png new file mode 100644 index 0000000..a8b9be4 Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/DemoBoxes/Resources/ColorPreview.png differ diff --git a/Assets/Photon Unity Networking/Demos/DemoBoxes/Resources/ColorPreview.png.meta b/Assets/Photon Unity Networking/Demos/DemoBoxes/Resources/ColorPreview.png.meta new file mode 100644 index 0000000..b24807b --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoBoxes/Resources/ColorPreview.png.meta @@ -0,0 +1,45 @@ +fileFormatVersion: 2 +guid: e824c90b700b59a48bb75bf8ac3b5682 +TextureImporter: + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + linearTexture: 1 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -1 + maxTextureSize: 32 + textureSettings: + filterMode: 0 + aniso: 1 + mipBias: -1 + wrapMode: 1 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spritePixelsToUnits: 100 + alphaIsTransparency: 1 + textureType: 2 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/Assets/Photon Unity Networking/Demos/DemoBoxes/Resources/UnitMaterial.mat b/Assets/Photon Unity Networking/Demos/DemoBoxes/Resources/UnitMaterial.mat new file mode 100644 index 0000000..1044ee0 Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/DemoBoxes/Resources/UnitMaterial.mat differ diff --git a/Assets/Photon Unity Networking/Demos/DemoBoxes/Resources/UnitMaterial.mat.meta b/Assets/Photon Unity Networking/Demos/DemoBoxes/Resources/UnitMaterial.mat.meta new file mode 100644 index 0000000..9a67975 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoBoxes/Resources/UnitMaterial.mat.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: c6fbde8aaae8bca4a8c7bf6490e6f981 diff --git a/Assets/Photon Unity Networking/Demos/DemoBoxes/Resources/UnitMaterialDark.mat b/Assets/Photon Unity Networking/Demos/DemoBoxes/Resources/UnitMaterialDark.mat new file mode 100644 index 0000000..cefb863 Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/DemoBoxes/Resources/UnitMaterialDark.mat differ diff --git a/Assets/Photon Unity Networking/Demos/DemoBoxes/Resources/UnitMaterialDark.mat.meta b/Assets/Photon Unity Networking/Demos/DemoBoxes/Resources/UnitMaterialDark.mat.meta new file mode 100644 index 0000000..2f5de19 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoBoxes/Resources/UnitMaterialDark.mat.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: bd82f7e1fdfa0704e9c2422e24e0e1b6 +NativeFormatImporter: + userData: diff --git a/Assets/Photon Unity Networking/Demos/DemoBoxes/Resources/UnitMaterialEmit.mat b/Assets/Photon Unity Networking/Demos/DemoBoxes/Resources/UnitMaterialEmit.mat new file mode 100644 index 0000000..391eaa5 Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/DemoBoxes/Resources/UnitMaterialEmit.mat differ diff --git a/Assets/Photon Unity Networking/Demos/DemoBoxes/Resources/UnitMaterialEmit.mat.meta b/Assets/Photon Unity Networking/Demos/DemoBoxes/Resources/UnitMaterialEmit.mat.meta new file mode 100644 index 0000000..ee66f57 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoBoxes/Resources/UnitMaterialEmit.mat.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 14ebb622e6e427a449df28289c7c9d01 diff --git a/Assets/Photon Unity Networking/Demos/DemoBoxes/Resources/UnitTexture.png b/Assets/Photon Unity Networking/Demos/DemoBoxes/Resources/UnitTexture.png new file mode 100644 index 0000000..d25adcb Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/DemoBoxes/Resources/UnitTexture.png differ diff --git a/Assets/Photon Unity Networking/Demos/DemoBoxes/Resources/UnitTexture.png.meta b/Assets/Photon Unity Networking/Demos/DemoBoxes/Resources/UnitTexture.png.meta new file mode 100644 index 0000000..d12a10b --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoBoxes/Resources/UnitTexture.png.meta @@ -0,0 +1,33 @@ +fileFormatVersion: 2 +guid: f64bcca960c279c4da8509f61a33db8f +TextureImporter: + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + linearTexture: 0 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + textureFormat: -1 + maxTextureSize: 512 + textureSettings: + filterMode: 2 + aniso: 5 + mipBias: -1 + wrapMode: 0 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + textureType: 0 + buildTargetSettings: [] diff --git a/Assets/Photon Unity Networking/Demos/DemoBoxes/Resources/eurof35.ttf b/Assets/Photon Unity Networking/Demos/DemoBoxes/Resources/eurof35.ttf new file mode 100644 index 0000000..ad174c3 Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/DemoBoxes/Resources/eurof35.ttf differ diff --git a/Assets/Photon Unity Networking/Demos/DemoBoxes/Resources/eurof35.ttf.meta b/Assets/Photon Unity Networking/Demos/DemoBoxes/Resources/eurof35.ttf.meta new file mode 100644 index 0000000..fca6c78 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoBoxes/Resources/eurof35.ttf.meta @@ -0,0 +1,13 @@ +fileFormatVersion: 2 +guid: 954746d370bc8934299c8c8267543f4f +TrueTypeFontImporter: + serializedVersion: 2 + fontSize: 16 + fontColor: {r: 1, g: 1, b: 1, a: 1} + forceTextureCase: -2 + renderMode: 0 + style: 0 + includeFontData: 1 + use2xBehaviour: 0 + fontNames: [] + customCharacters: diff --git a/Assets/Photon Unity Networking/Demos/DemoBoxes/Resources/eurof_tt.txt b/Assets/Photon Unity Networking/Demos/DemoBoxes/Resources/eurof_tt.txt new file mode 100644 index 0000000..9c45e6c --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoBoxes/Resources/eurof_tt.txt @@ -0,0 +1,21 @@ +------------------------------------------------------------------------ +The eurofurence typeface family by tobias b koehler (unci@tigerden.com) +------------------------------------------------------------------------ + +This is a family of geometric rounded sans serif fonts consisting of +three weights (light, medium, bold) in upright and italic styles, +originally designed for EuroFurence, the first European furry convention +1995 in Kaiser-Wilhelm-Koog. + +The character set includes Roman, Greek and Cyrillic characters. +File format is TrueType for PC (under Windows, Linux etc). + +These fonts are freeware and can be distributed as long as they are +together with this text file. I would appreciate it though if you could +contact me at unci@tigerden.com if you put them on a server. Free +samples from commercial users are always very welcome. :) + +For more information, please see the uncifonts WWW page at: +http://mercurio.iet.unipi.it/users/tobias/uncifonts.html + +Have fun! tobias b koehler, 2000-04-02 \ No newline at end of file diff --git a/Assets/Photon Unity Networking/Demos/DemoBoxes/Resources/eurof_tt.txt.meta b/Assets/Photon Unity Networking/Demos/DemoBoxes/Resources/eurof_tt.txt.meta new file mode 100644 index 0000000..9d50bfc --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoBoxes/Resources/eurof_tt.txt.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 32589b999b7dcf741bfc184e9d7db384 diff --git a/Assets/Photon Unity Networking/Demos/DemoChangeOwner.meta b/Assets/Photon Unity Networking/Demos/DemoChangeOwner.meta new file mode 100644 index 0000000..9d943a9 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoChangeOwner.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: ed8c68ea07e8d4617802e438757e87b6 +folderAsset: yes +timeCreated: 1501014811 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Photon Unity Networking/Demos/DemoChangeOwner/ClickAndDrag.cs b/Assets/Photon Unity Networking/Demos/DemoChangeOwner/ClickAndDrag.cs new file mode 100644 index 0000000..729e324 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoChangeOwner/ClickAndDrag.cs @@ -0,0 +1,46 @@ +using UnityEngine; +using System.Collections; + +public class ClickAndDrag : Photon.MonoBehaviour +{ + private Vector3 camOnPress; + private bool following; + private float factor = -0.1f; + + // Update is called once per frame + void Update () + { + if (!photonView.isMine) + { + return; + } + + InputToEvent input = Camera.main.GetComponent(); + if (input == null) return; + if (!following) + { + if (input.Dragging) + { + camOnPress = this.transform.position; + following = true; + } + else + { + return; + } + } + else + { + if (input.Dragging) + { + Vector3 target = camOnPress - (new Vector3(input.DragVector.x, 0, input.DragVector.y) * factor); + this.transform.position = Vector3.Lerp(this.transform.position, target, Time.deltaTime*.5f); + } + else + { + camOnPress = Vector3.zero; + following = false; + } + } + } +} diff --git a/Assets/Photon Unity Networking/Demos/DemoChangeOwner/ClickAndDrag.cs.meta b/Assets/Photon Unity Networking/Demos/DemoChangeOwner/ClickAndDrag.cs.meta new file mode 100644 index 0000000..6e62175 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoChangeOwner/ClickAndDrag.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 1e6ec0227782a2a4bb7f1402336782e9 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Photon Unity Networking/Demos/DemoChangeOwner/DemoChangeOwner-Scene.unity b/Assets/Photon Unity Networking/Demos/DemoChangeOwner/DemoChangeOwner-Scene.unity new file mode 100644 index 0000000..e878cc7 Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/DemoChangeOwner/DemoChangeOwner-Scene.unity differ diff --git a/Assets/Photon Unity Networking/Demos/DemoChangeOwner/DemoChangeOwner-Scene.unity.meta b/Assets/Photon Unity Networking/Demos/DemoChangeOwner/DemoChangeOwner-Scene.unity.meta new file mode 100644 index 0000000..954e1db --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoChangeOwner/DemoChangeOwner-Scene.unity.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: efb7b18562339d8459d546ede0a9e4cc diff --git a/Assets/Photon Unity Networking/Demos/DemoChangeOwner/DemoOwnershipGui.cs b/Assets/Photon Unity Networking/Demos/DemoChangeOwner/DemoOwnershipGui.cs new file mode 100644 index 0000000..092e8e1 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoChangeOwner/DemoOwnershipGui.cs @@ -0,0 +1,95 @@ +using UnityEngine; + +public class DemoOwnershipGui : MonoBehaviour +{ + public GUISkin Skin; + public bool TransferOwnershipOnRequest = true; + + public void OnOwnershipRequest(object[] viewAndPlayer) + { + PhotonView view = viewAndPlayer[0] as PhotonView; + PhotonPlayer requestingPlayer = viewAndPlayer[1] as PhotonPlayer; + + Debug.Log("OnOwnershipRequest(): Player " + requestingPlayer + " requests ownership of: " + view + "."); + if (this.TransferOwnershipOnRequest) + { + view.TransferOwnership(requestingPlayer.ID); + } + } + + public void OnOwnershipTransfered (object[] viewAndPlayers) + { + PhotonView view = viewAndPlayers[0] as PhotonView; + + PhotonPlayer newOwner = viewAndPlayers[1] as PhotonPlayer; + + PhotonPlayer oldOwner = viewAndPlayers[2] as PhotonPlayer; + + Debug.Log( "OnOwnershipTransfered for PhotonView"+view.ToString()+" from "+oldOwner+" to "+newOwner); + } + + + #region Unity + + public void OnGUI() + { + GUI.skin = this.Skin; + GUILayout.BeginArea(new Rect(Screen.width - 200, 0, 200, Screen.height)); + { + string label = TransferOwnershipOnRequest ? "passing objects" : "rejecting to pass"; + if (GUILayout.Button(label)) + { + this.TransferOwnershipOnRequest = !this.TransferOwnershipOnRequest; + } + } + GUILayout.EndArea(); + + + + if (PhotonNetwork.inRoom) + { + int playerNr = PhotonNetwork.player.ID; + string playerIsMaster = PhotonNetwork.player.IsMasterClient ? "(master) " : ""; + string playerColor = this.GetColorName(PhotonNetwork.player.ID); + GUILayout.Label(string.Format("player {0}, {1} {2}(you)", playerNr, playerColor, playerIsMaster)); + + foreach (PhotonPlayer otherPlayer in PhotonNetwork.otherPlayers) + { + playerNr = otherPlayer.ID; + playerIsMaster = otherPlayer.IsMasterClient ? "(master)" : ""; + playerColor = this.GetColorName(otherPlayer.ID); + GUILayout.Label(string.Format("player {0}, {1} {2}", playerNr, playerColor, playerIsMaster)); + } + + if (PhotonNetwork.inRoom && PhotonNetwork.otherPlayers.Length == 0) + { + GUILayout.Label("Join more clients to switch object-control."); + } + } + else + { + GUILayout.Label(PhotonNetwork.connectionStateDetailed.ToString()); + } + } + + #endregion + + private string GetColorName(int playerId) + { + int index = System.Array.IndexOf(ExitGames.UtilityScripts.PlayerRoomIndexing.instance.PlayerIds, playerId); + + switch (index) + { + case 0: + return "red"; + case 1: + return "blue"; + case 2: + return "yellow"; + case 3: + return "green"; + } + + return string.Empty; + } +} diff --git a/Assets/Photon Unity Networking/Demos/DemoChangeOwner/DemoOwnershipGui.cs.meta b/Assets/Photon Unity Networking/Demos/DemoChangeOwner/DemoOwnershipGui.cs.meta new file mode 100644 index 0000000..ee4b185 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoChangeOwner/DemoOwnershipGui.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ca927a251ea077448a4395637646cae7 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Photon Unity Networking/Demos/DemoChangeOwner/HighlightOwnedGameObj.cs b/Assets/Photon Unity Networking/Demos/DemoChangeOwner/HighlightOwnedGameObj.cs new file mode 100644 index 0000000..61cfc56 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoChangeOwner/HighlightOwnedGameObj.cs @@ -0,0 +1,33 @@ +using UnityEngine; + +[RequireComponent(typeof (PhotonView))] +public class HighlightOwnedGameObj : Photon.MonoBehaviour +{ + public GameObject PointerPrefab; + public float Offset = 0.5f; + private Transform markerTransform; + + + // Update is called once per frame + private void Update() + { + if (photonView.isMine) + { + if (this.markerTransform == null) + { + GameObject markerObject = (GameObject) GameObject.Instantiate(this.PointerPrefab); + markerObject.transform.parent = gameObject.transform; + this.markerTransform = markerObject.transform; + } + + Vector3 parentPos = gameObject.transform.position; + this.markerTransform.position = new Vector3(parentPos.x, parentPos.y + this.Offset, parentPos.z); + this.markerTransform.rotation = Quaternion.identity; + } + else if (this.markerTransform != null) + { + Destroy(this.markerTransform.gameObject); + this.markerTransform = null; + } + } +} \ No newline at end of file diff --git a/Assets/Photon Unity Networking/Demos/DemoChangeOwner/HighlightOwnedGameObj.cs.meta b/Assets/Photon Unity Networking/Demos/DemoChangeOwner/HighlightOwnedGameObj.cs.meta new file mode 100644 index 0000000..bfe5fcd --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoChangeOwner/HighlightOwnedGameObj.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 000ef710937cf394f83251fd684272ec +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Photon Unity Networking/Demos/DemoChangeOwner/InstantiateCube.cs b/Assets/Photon Unity Networking/Demos/DemoChangeOwner/InstantiateCube.cs new file mode 100644 index 0000000..d719c61 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoChangeOwner/InstantiateCube.cs @@ -0,0 +1,32 @@ +using UnityEngine; +using System.Collections; +using ExitGames.Client.Photon; + +public class InstantiateCube : MonoBehaviour +{ + public GameObject Prefab; + public int InstantiateType; + //private string[] InstantiateTypeNames = {"Mine", "Scene"}; + + public bool showGui; + + void OnClick() + { + if (PhotonNetwork.connectionStateDetailed != ClientState.Joined) + { + // only use PhotonNetwork.Instantiate while in a room. + return; + } + + switch (InstantiateType) + { + case 0: + PhotonNetwork.Instantiate(Prefab.name, this.transform.position + 3*Vector3.up, Quaternion.identity, 0); + break; + case 1: + PhotonNetwork.InstantiateSceneObject(Prefab.name, InputToEvent.inputHitPos + new Vector3(0, 5f, 0), Quaternion.identity, 0, null); + break; + } + } + +} diff --git a/Assets/Photon Unity Networking/Demos/DemoChangeOwner/InstantiateCube.cs.meta b/Assets/Photon Unity Networking/Demos/DemoChangeOwner/InstantiateCube.cs.meta new file mode 100644 index 0000000..d514fc3 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoChangeOwner/InstantiateCube.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: bf3aff376c18fab4da2db120453debef +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Photon Unity Networking/Demos/DemoChangeOwner/MaterialPerOwner.cs b/Assets/Photon Unity Networking/Demos/DemoChangeOwner/MaterialPerOwner.cs new file mode 100644 index 0000000..dcd5926 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoChangeOwner/MaterialPerOwner.cs @@ -0,0 +1,28 @@ +using UnityEngine; +using System.Collections; + + +[RequireComponent( typeof( PhotonView ) )] +public class MaterialPerOwner : Photon.MonoBehaviour +{ + private int assignedColorForUserId; + + Renderer m_Renderer; + + void Start() + { + m_Renderer = GetComponent(); + } + + // Update is called once per frame + private void Update() + { + if( this.photonView.ownerId != assignedColorForUserId ) + { + int index = System.Array.IndexOf(ExitGames.UtilityScripts.PlayerRoomIndexing.instance.PlayerIds, this.photonView.ownerId); + m_Renderer.material.color = FindObjectOfType().Colors[index]; + this.assignedColorForUserId = this.photonView.ownerId; + //Debug.Log("Switched Material to: " + this.assignedColorForUserId + " " + this.renderer.material.GetInstanceID()); + } + } +} diff --git a/Assets/Photon Unity Networking/Demos/DemoChangeOwner/MaterialPerOwner.cs.meta b/Assets/Photon Unity Networking/Demos/DemoChangeOwner/MaterialPerOwner.cs.meta new file mode 100644 index 0000000..188ab8f --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoChangeOwner/MaterialPerOwner.cs.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: e3ba58425bd67d642a93dc8b68ff902b +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} diff --git a/Assets/Photon Unity Networking/Demos/DemoChangeOwner/OnClickDisableObj.cs b/Assets/Photon Unity Networking/Demos/DemoChangeOwner/OnClickDisableObj.cs new file mode 100644 index 0000000..75de009 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoChangeOwner/OnClickDisableObj.cs @@ -0,0 +1,10 @@ +using UnityEngine; +using System.Collections; + +public class OnClickDisableObj : MonoBehaviour { + + + void OnClick() { + this.gameObject.SetActive(false); + } + } diff --git a/Assets/Photon Unity Networking/Demos/DemoChangeOwner/OnClickDisableObj.cs.meta b/Assets/Photon Unity Networking/Demos/DemoChangeOwner/OnClickDisableObj.cs.meta new file mode 100644 index 0000000..eed849a --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoChangeOwner/OnClickDisableObj.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 8c01b923b945e3b42963b668a2f96619 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Photon Unity Networking/Demos/DemoChangeOwner/OnClickRequestOwnership.cs b/Assets/Photon Unity Networking/Demos/DemoChangeOwner/OnClickRequestOwnership.cs new file mode 100644 index 0000000..420be5e --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoChangeOwner/OnClickRequestOwnership.cs @@ -0,0 +1,33 @@ +using UnityEngine; +using System.Collections; + +[RequireComponent( typeof( PhotonView ) )] +public class OnClickRequestOwnership : Photon.MonoBehaviour +{ + + public void OnClick() + { + if( Input.GetKey( KeyCode.LeftShift ) || Input.GetKey( KeyCode.RightShift ) ) + { + Vector3 colVector = new Vector3( Random.Range( 0.0f, 1.0f ), Random.Range( 0.0f, 1.0f ), Random.Range( 0.0f, 1.0f ) ); + this.photonView.RPC( "ColorRpc", PhotonTargets.AllBufferedViaServer, colVector ); + } + else + { + if( this.photonView.ownerId == PhotonNetwork.player.ID ) + { + Debug.Log( "Not requesting ownership. Already mine." ); + return; + } + + this.photonView.RequestOwnership(); + } + } + + [PunRPC] + public void ColorRpc( Vector3 col ) + { + Color color = new Color( col.x, col.y, col.z ); + this.gameObject.GetComponent().material.color = color; + } +} diff --git a/Assets/Photon Unity Networking/Demos/DemoChangeOwner/OnClickRequestOwnership.cs.meta b/Assets/Photon Unity Networking/Demos/DemoChangeOwner/OnClickRequestOwnership.cs.meta new file mode 100644 index 0000000..0bbb745 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoChangeOwner/OnClickRequestOwnership.cs.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: e70318fb95df612418c6f2f462f9b016 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} diff --git a/Assets/Photon Unity Networking/Demos/DemoChangeOwner/OnClickRightDestroy.cs b/Assets/Photon Unity Networking/Demos/DemoChangeOwner/OnClickRightDestroy.cs new file mode 100644 index 0000000..68bb060 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoChangeOwner/OnClickRightDestroy.cs @@ -0,0 +1,10 @@ +using UnityEngine; + +public class OnClickRightDestroy : MonoBehaviour +{ + public void OnPressRight() + { + Debug.Log("RightClick Destroy"); + PhotonNetwork.Destroy(gameObject); + } +} \ No newline at end of file diff --git a/Assets/Photon Unity Networking/Demos/DemoChangeOwner/OnClickRightDestroy.cs.meta b/Assets/Photon Unity Networking/Demos/DemoChangeOwner/OnClickRightDestroy.cs.meta new file mode 100644 index 0000000..437a692 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoChangeOwner/OnClickRightDestroy.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 5b1afb3ee89e70049af76b7f087b84d2 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Photon Unity Networking/Demos/DemoChangeOwner/Resources.meta b/Assets/Photon Unity Networking/Demos/DemoChangeOwner/Resources.meta new file mode 100644 index 0000000..5080b89 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoChangeOwner/Resources.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 147672a7ac09d43f682f933829cd20da +folderAsset: yes +timeCreated: 1501014811 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Photon Unity Networking/Demos/DemoChangeOwner/Resources/OwnershipCube.prefab b/Assets/Photon Unity Networking/Demos/DemoChangeOwner/Resources/OwnershipCube.prefab new file mode 100644 index 0000000..bdc5167 Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/DemoChangeOwner/Resources/OwnershipCube.prefab differ diff --git a/Assets/Photon Unity Networking/Demos/DemoChangeOwner/Resources/OwnershipCube.prefab.meta b/Assets/Photon Unity Networking/Demos/DemoChangeOwner/Resources/OwnershipCube.prefab.meta new file mode 100644 index 0000000..03d82e0 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoChangeOwner/Resources/OwnershipCube.prefab.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: b38a8c530a7b6864ab3be1edd768b4a5 +NativeFormatImporter: + userData: diff --git a/Assets/Photon Unity Networking/Demos/DemoChangeOwner/Resources/OwnershipSphere.prefab b/Assets/Photon Unity Networking/Demos/DemoChangeOwner/Resources/OwnershipSphere.prefab new file mode 100644 index 0000000..b948383 Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/DemoChangeOwner/Resources/OwnershipSphere.prefab differ diff --git a/Assets/Photon Unity Networking/Demos/DemoChangeOwner/Resources/OwnershipSphere.prefab.meta b/Assets/Photon Unity Networking/Demos/DemoChangeOwner/Resources/OwnershipSphere.prefab.meta new file mode 100644 index 0000000..356262d --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoChangeOwner/Resources/OwnershipSphere.prefab.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: bb733c4e80dbde84eaf61d8aace88c3d diff --git a/Assets/Photon Unity Networking/Demos/DemoChangeOwner/ShowInfoOfPlayer.cs b/Assets/Photon Unity Networking/Demos/DemoChangeOwner/ShowInfoOfPlayer.cs new file mode 100644 index 0000000..2587f45 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoChangeOwner/ShowInfoOfPlayer.cs @@ -0,0 +1,78 @@ +using UnityEngine; +using System.Collections; +using ExitGames.Client.Photon; +/// +/// Can be attached to a GameObject to show info about the owner of the PhotonView. +/// +/// +/// This is a Photon.Monobehaviour, which adds the property photonView (that's all). +/// +[RequireComponent(typeof(PhotonView))] +public class ShowInfoOfPlayer : Photon.MonoBehaviour +{ + private GameObject textGo; + private TextMesh tm; + public float CharacterSize = 0; + + public Font font; + public bool DisableOnOwnObjects; + + void Start() + { + if (font == null) + { + #if UNITY_3_5 + font = (Font)FindObjectsOfTypeIncludingAssets(typeof(Font))[0]; + #else + font = (Font)Resources.FindObjectsOfTypeAll(typeof(Font))[0]; + #endif + Debug.LogWarning("No font defined. Found font: " + font); + } + + if (tm == null) + { + textGo = new GameObject("3d text"); + //textGo.transform.localScale = new Vector3(0.2f, 0.2f, 0.2f); + textGo.transform.parent = this.gameObject.transform; + textGo.transform.localPosition = Vector3.zero; + + MeshRenderer mr = textGo.AddComponent(); + mr.material = font.material; + tm = textGo.AddComponent(); + tm.font = font; + tm.anchor = TextAnchor.MiddleCenter; + if (this.CharacterSize > 0) + { + tm.characterSize = this.CharacterSize; + } + } + } + + void Update() + { + bool showInfo = !this.DisableOnOwnObjects || this.photonView.isMine; + if (textGo != null) + { + textGo.SetActive(showInfo); + } + if (!showInfo) + { + return; + } + + + PhotonPlayer owner = this.photonView.owner; + if (owner != null) + { + tm.text = (string.IsNullOrEmpty(owner.NickName)) ? "player"+owner.ID : owner.NickName; + } + else if (this.photonView.isSceneView) + { + tm.text = "scn"; + } + else + { + tm.text = "n/a"; + } + } +} diff --git a/Assets/Photon Unity Networking/Demos/DemoChangeOwner/ShowInfoOfPlayer.cs.meta b/Assets/Photon Unity Networking/Demos/DemoChangeOwner/ShowInfoOfPlayer.cs.meta new file mode 100644 index 0000000..8bae35f --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoChangeOwner/ShowInfoOfPlayer.cs.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 6acb8d21564821e4e92aaa49ce2151cc +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} diff --git a/Assets/Photon Unity Networking/Demos/DemoChat.meta b/Assets/Photon Unity Networking/Demos/DemoChat.meta new file mode 100644 index 0000000..4a14303 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoChat.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 405eee32f7db74470bcbf824d53adc9b +folderAsset: yes +timeCreated: 1501014811 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Photon Unity Networking/Demos/DemoChat/ChannelSelector.cs b/Assets/Photon Unity Networking/Demos/DemoChat/ChannelSelector.cs new file mode 100644 index 0000000..e365fea --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoChat/ChannelSelector.cs @@ -0,0 +1,23 @@ +using ExitGames.Client.Photon.Chat; +using UnityEngine; +using System.Collections; +using UnityEngine.EventSystems; +using UnityEngine.UI; + +public class ChannelSelector : MonoBehaviour, IPointerClickHandler +{ + public string Channel; + + public void SetChannel(string channel) + { + this.Channel = channel; + Text t = GetComponentInChildren(); + t.text = this.Channel; + } + + public void OnPointerClick(PointerEventData eventData) + { + ChatGui handler = FindObjectOfType(); + handler.ShowChannel(this.Channel); + } +} diff --git a/Assets/Photon Unity Networking/Demos/DemoChat/ChannelSelector.cs.meta b/Assets/Photon Unity Networking/Demos/DemoChat/ChannelSelector.cs.meta new file mode 100644 index 0000000..e96ed0d --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoChat/ChannelSelector.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 48caa72710147fc4f9389b0b5ec6137d +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Photon Unity Networking/Demos/DemoChat/ChatAppIdCheckerUI.cs b/Assets/Photon Unity Networking/Demos/DemoChat/ChatAppIdCheckerUI.cs new file mode 100644 index 0000000..a7a488d --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoChat/ChatAppIdCheckerUI.cs @@ -0,0 +1,26 @@ +using UnityEngine; +using System.Collections; + +using UnityEngine.UI; + + +/// +/// This is used in the Editor Splash to properly inform the developer about the chat AppId requirement. +/// +[ExecuteInEditMode] +public class ChatAppIdCheckerUI : MonoBehaviour +{ + public Text Description; + + public void Update() + { + if (string.IsNullOrEmpty(PhotonNetwork.PhotonServerSettings.ChatAppID)) + { + Description.text = "WARNING:\nTo run this demo, please set the Chat AppId in the PhotonServerSettings file."; + } + else + { + Description.text = string.Empty; + } + } +} \ No newline at end of file diff --git a/Assets/Photon Unity Networking/Demos/DemoChat/ChatAppIdCheckerUI.cs.meta b/Assets/Photon Unity Networking/Demos/DemoChat/ChatAppIdCheckerUI.cs.meta new file mode 100644 index 0000000..a1a0c86 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoChat/ChatAppIdCheckerUI.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 4eb1284704a754507acb17b07b888086 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Photon Unity Networking/Demos/DemoChat/ChatGui.cs b/Assets/Photon Unity Networking/Demos/DemoChat/ChatGui.cs new file mode 100644 index 0000000..e146c67 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoChat/ChatGui.cs @@ -0,0 +1,591 @@ +using System; +using System.Collections.Generic; +using ExitGames.Client.Photon.Chat; +using UnityEngine; +using UnityEngine.UI; + +/// +/// This simple Chat UI demonstrate basics usages of the Chat Api +/// +/// +/// The ChatClient basically lets you create any number of channels. +/// +/// some friends are already set in the Chat demo "DemoChat-Scene", 'Joe', 'Jane' and 'Bob', simply log with them so that you can see the status changes in the Interface +/// +/// Workflow: +/// Create ChatClient, Connect to a server with your AppID, Authenticate the user (apply a unique name,) +/// and subscribe to some channels. +/// Subscribe a channel before you publish to that channel! +/// +/// +/// Note: +/// Don't forget to call ChatClient.Service() on Update to keep the Chatclient operational. +/// +public class ChatGui : MonoBehaviour, IChatClientListener +{ + + public string[] ChannelsToJoinOnConnect; // set in inspector. Demo channels to join automatically. + + public string[] FriendsList; + + public int HistoryLengthToFetch; // set in inspector. Up to a certain degree, previously sent messages can be fetched for context + + public string UserName { get; set; } + + private string selectedChannelName; // mainly used for GUI/input + + public ChatClient chatClient; + + public GameObject missingAppIdErrorPanel; + + public GameObject ConnectingLabel; + + public RectTransform ChatPanel; // set in inspector (to enable/disable panel) + public GameObject UserIdFormPanel; + public InputField InputFieldChat; // set in inspector + public Text CurrentChannelText; // set in inspector + public Toggle ChannelToggleToInstantiate; // set in inspector + + + public GameObject FriendListUiItemtoInstantiate; + + private readonly Dictionary channelToggles = new Dictionary(); + + private readonly Dictionary friendListItemLUT = new Dictionary(); + + public bool ShowState = true; + public GameObject Title; + public Text StateText; // set in inspector + public Text UserIdText; // set in inspector + + // private static string WelcomeText = "Welcome to chat. Type \\help to list commands."; + private static string HelpText = "\n -- HELP --\n" + + "To subscribe to channel(s):\n" + + "\t\\subscribe \n" + + "\tor\n" + + "\t\\s \n" + + "\n" + + "To leave channel(s):\n" + + "\t\\unsubscribe \n" + + "\tor\n" + + "\t\\u \n" + + "\n" + + "To switch the active channel\n" + + "\t\\join \n" + + "\tor\n" + + "\t\\j \n" + + "\n" + + "To send a private message:\n" + + "\t\\msg \n" + + "\n" + + "To change status:\n" + + "\t\\state \n" + + "0 = Offline " + + "1 = Invisible " + + "2 = Online " + + "3 = Away \n" + + "4 = Do not disturb " + + "5 = Looking For Group " + + "6 = Playing" + + "\n\n" + + "To clear the current chat tab (private chats get closed):\n" + + "\t\\clear"; + + + public void Start() + { + DontDestroyOnLoad(gameObject); + + + UserIdText.text = ""; + StateText.text = ""; + StateText.gameObject.SetActive(true); + UserIdText.gameObject.SetActive(true); + Title.SetActive(true); + ChatPanel.gameObject.SetActive(false); + ConnectingLabel.SetActive(false); + + if (string.IsNullOrEmpty(UserName)) + { + UserName = "user" + Environment.TickCount%99; //made-up username + } + + bool _AppIdPresent = string.IsNullOrEmpty(PhotonNetwork.PhotonServerSettings.ChatAppID); + this.missingAppIdErrorPanel.SetActive(_AppIdPresent); + + this.UserIdFormPanel.gameObject.SetActive(!_AppIdPresent); + + if (string.IsNullOrEmpty(PhotonNetwork.PhotonServerSettings.ChatAppID)) + { + Debug.LogError("You need to set the chat app ID in the PhotonServerSettings file in order to continue."); + return; + } + } + + public void Connect() + { + this.UserIdFormPanel.gameObject.SetActive(false); + + this.chatClient = new ChatClient(this); + #if !UNITY_WEBGL + this.chatClient.UseBackgroundWorkerForSending = true; + #endif + this.chatClient.Connect(PhotonNetwork.PhotonServerSettings.ChatAppID, "1.0", new ExitGames.Client.Photon.Chat.AuthenticationValues(UserName)); + + this.ChannelToggleToInstantiate.gameObject.SetActive(false); + Debug.Log("Connecting as: " + UserName); + + ConnectingLabel.SetActive(true); + } + + /// To avoid that the Editor becomes unresponsive, disconnect all Photon connections in OnDestroy. + public void OnDestroy() + { + if (this.chatClient != null) + { + this.chatClient.Disconnect(); + } + } + + /// To avoid that the Editor becomes unresponsive, disconnect all Photon connections in OnApplicationQuit. + public void OnApplicationQuit() + { + if (this.chatClient != null) + { + this.chatClient.Disconnect(); + } + } + + public void Update() + { + if (this.chatClient != null) + { + this.chatClient.Service(); // make sure to call this regularly! it limits effort internally, so calling often is ok! + } + + // check if we are missing context, which means we got kicked out to get back to the Photon Demo hub. + if ( this.StateText == null) + { + Destroy(this.gameObject); + return; + } + + this.StateText.gameObject.SetActive(ShowState); // this could be handled more elegantly, but for the demo it's ok. + } + + + public void OnEnterSend() + { + if (Input.GetKey(KeyCode.Return) || Input.GetKey(KeyCode.KeypadEnter)) + { + SendChatMessage(this.InputFieldChat.text); + this.InputFieldChat.text = ""; + } + } + + public void OnClickSend() + { + if (this.InputFieldChat != null) + { + SendChatMessage(this.InputFieldChat.text); + this.InputFieldChat.text = ""; + } + } + + + public int TestLength = 2048; + private byte[] testBytes = new byte[2048]; + + private void SendChatMessage(string inputLine) + { + if (string.IsNullOrEmpty(inputLine)) + { + return; + } + if ("test".Equals(inputLine)) + { + if (this.TestLength != this.testBytes.Length) + { + this.testBytes = new byte[this.TestLength]; + } + + this.chatClient.SendPrivateMessage(this.chatClient.AuthValues.UserId, testBytes, true); + } + + + bool doingPrivateChat = this.chatClient.PrivateChannels.ContainsKey(this.selectedChannelName); + string privateChatTarget = string.Empty; + if (doingPrivateChat) + { + // the channel name for a private conversation is (on the client!!) always composed of both user's IDs: "this:remote" + // so the remote ID is simple to figure out + + string[] splitNames = this.selectedChannelName.Split(new char[] { ':' }); + privateChatTarget = splitNames[1]; + } + //UnityEngine.Debug.Log("selectedChannelName: " + selectedChannelName + " doingPrivateChat: " + doingPrivateChat + " privateChatTarget: " + privateChatTarget); + + + if (inputLine[0].Equals('\\')) + { + string[] tokens = inputLine.Split(new char[] {' '}, 2); + if (tokens[0].Equals("\\help")) + { + PostHelpToCurrentChannel(); + } + if (tokens[0].Equals("\\state")) + { + int newState = 0; + + + List messages = new List(); + messages.Add ("i am state " + newState); + string[] subtokens = tokens[1].Split(new char[] {' ', ','}); + + if (subtokens.Length > 0) + { + newState = int.Parse(subtokens[0]); + } + + if (subtokens.Length > 1) + { + messages.Add(subtokens[1]); + } + + this.chatClient.SetOnlineStatus(newState,messages.ToArray()); // this is how you set your own state and (any) message + } + else if ((tokens[0].Equals("\\subscribe") || tokens[0].Equals("\\s")) && !string.IsNullOrEmpty(tokens[1])) + { + this.chatClient.Subscribe(tokens[1].Split(new char[] {' ', ','})); + } + else if ((tokens[0].Equals("\\unsubscribe") || tokens[0].Equals("\\u")) && !string.IsNullOrEmpty(tokens[1])) + { + this.chatClient.Unsubscribe(tokens[1].Split(new char[] {' ', ','})); + } + else if (tokens[0].Equals("\\clear")) + { + if (doingPrivateChat) + { + this.chatClient.PrivateChannels.Remove(this.selectedChannelName); + } + else + { + ChatChannel channel; + if (this.chatClient.TryGetChannel(this.selectedChannelName, doingPrivateChat, out channel)) + { + channel.ClearMessages(); + } + } + } + else if (tokens[0].Equals("\\msg") && !string.IsNullOrEmpty(tokens[1])) + { + string[] subtokens = tokens[1].Split(new char[] {' ', ','}, 2); + if (subtokens.Length < 2) return; + + string targetUser = subtokens[0]; + string message = subtokens[1]; + this.chatClient.SendPrivateMessage(targetUser, message); + } + else if ((tokens[0].Equals("\\join") || tokens[0].Equals("\\j")) && !string.IsNullOrEmpty(tokens[1])) + { + string[] subtokens = tokens[1].Split(new char[] { ' ', ',' }, 2); + + // If we are already subscribed to the channel we directly switch to it, otherwise we subscribe to it first and then switch to it implicitly + if (channelToggles.ContainsKey(subtokens[0])) + { + ShowChannel(subtokens[0]); + } + else + { + this.chatClient.Subscribe(new string[] { subtokens[0] }); + } + } + else + { + Debug.Log("The command '" + tokens[0] + "' is invalid."); + } + } + else + { + if (doingPrivateChat) + { + this.chatClient.SendPrivateMessage(privateChatTarget, inputLine); + } + else + { + this.chatClient.PublishMessage(this.selectedChannelName, inputLine); + } + } + } + + public void PostHelpToCurrentChannel() + { + this.CurrentChannelText.text += HelpText; + } + + public void DebugReturn(ExitGames.Client.Photon.DebugLevel level, string message) + { + if (level == ExitGames.Client.Photon.DebugLevel.ERROR) + { + UnityEngine.Debug.LogError(message); + } + else if (level == ExitGames.Client.Photon.DebugLevel.WARNING) + { + UnityEngine.Debug.LogWarning(message); + } + else + { + UnityEngine.Debug.Log(message); + } + } + + public void OnConnected() + { + if (this.ChannelsToJoinOnConnect != null && this.ChannelsToJoinOnConnect.Length > 0) + { + this.chatClient.Subscribe(this.ChannelsToJoinOnConnect, this.HistoryLengthToFetch); + } + + ConnectingLabel.SetActive(false); + + UserIdText.text = "Connected as "+ this.UserName; + + this.ChatPanel.gameObject.SetActive(true); + + if (FriendsList!=null && FriendsList.Length>0) + { + this.chatClient.AddFriends(FriendsList); // Add some users to the server-list to get their status updates + + // add to the UI as well + foreach(string _friend in FriendsList) + { + if (this.FriendListUiItemtoInstantiate != null && _friend!= this.UserName) + { + this.InstantiateFriendButton(_friend); + } + + } + + } + + if (this.FriendListUiItemtoInstantiate != null) + { + this.FriendListUiItemtoInstantiate.SetActive(false); + } + + + this.chatClient.SetOnlineStatus(ChatUserStatus.Online); // You can set your online state (without a mesage). + } + + public void OnDisconnected() + { + ConnectingLabel.SetActive(false); + } + + public void OnChatStateChange(ChatState state) + { + // use OnConnected() and OnDisconnected() + // this method might become more useful in the future, when more complex states are being used. + + this.StateText.text = state.ToString(); + } + + public void OnSubscribed(string[] channels, bool[] results) + { + // in this demo, we simply send a message into each channel. This is NOT a must have! + foreach (string channel in channels) + { + this.chatClient.PublishMessage(channel, "says 'hi'."); // you don't HAVE to send a msg on join but you could. + + if (this.ChannelToggleToInstantiate != null) + { + this.InstantiateChannelButton(channel); + + } + } + + Debug.Log("OnSubscribed: " + string.Join(", ", channels)); + + /* + // select first subscribed channel in alphabetical order + if (this.chatClient.PublicChannels.Count > 0) + { + var l = new List(this.chatClient.PublicChannels.Keys); + l.Sort(); + string selected = l[0]; + if (this.channelToggles.ContainsKey(selected)) + { + ShowChannel(selected); + foreach (var c in this.channelToggles) + { + c.Value.isOn = false; + } + this.channelToggles[selected].isOn = true; + AddMessageToSelectedChannel(WelcomeText); + } + } + */ + + // Switch to the first newly created channel + ShowChannel(channels[0]); + } + + private void InstantiateChannelButton(string channelName) + { + if (this.channelToggles.ContainsKey(channelName)) + { + Debug.Log("Skipping creation for an existing channel toggle."); + return; + } + + Toggle cbtn = (Toggle)GameObject.Instantiate(this.ChannelToggleToInstantiate); + cbtn.gameObject.SetActive(true); + cbtn.GetComponentInChildren().SetChannel(channelName); + cbtn.transform.SetParent(this.ChannelToggleToInstantiate.transform.parent, false); + + this.channelToggles.Add(channelName, cbtn); + } + + private void InstantiateFriendButton(string friendId) + { + GameObject fbtn = (GameObject)GameObject.Instantiate(this.FriendListUiItemtoInstantiate); + fbtn.gameObject.SetActive(true); + FriendItem _friendItem = fbtn.GetComponent(); + + _friendItem.FriendId = friendId; + + fbtn.transform.SetParent(this.FriendListUiItemtoInstantiate.transform.parent, false); + + this.friendListItemLUT[friendId] = _friendItem; + } + + + public void OnUnsubscribed(string[] channels) + { + foreach (string channelName in channels) + { + if (this.channelToggles.ContainsKey(channelName)) + { + Toggle t = this.channelToggles[channelName]; + Destroy(t.gameObject); + + this.channelToggles.Remove(channelName); + + Debug.Log("Unsubscribed from channel '" + channelName + "'."); + + // Showing another channel if the active channel is the one we unsubscribed from before + if (channelName == selectedChannelName && channelToggles.Count > 0) + { + IEnumerator> firstEntry = channelToggles.GetEnumerator(); + firstEntry.MoveNext(); + + ShowChannel(firstEntry.Current.Key); + + firstEntry.Current.Value.isOn = true; + } + } + else + { + Debug.Log("Can't unsubscribe from channel '" + channelName + "' because you are currently not subscribed to it."); + } + } + } + + public void OnGetMessages(string channelName, string[] senders, object[] messages) + { + if (channelName.Equals(this.selectedChannelName)) + { + // update text + ShowChannel(this.selectedChannelName); + } + } + + public void OnPrivateMessage(string sender, object message, string channelName) + { + // as the ChatClient is buffering the messages for you, this GUI doesn't need to do anything here + // you also get messages that you sent yourself. in that case, the channelName is determinded by the target of your msg + this.InstantiateChannelButton(channelName); + + byte[] msgBytes = message as byte[]; + if (msgBytes != null) + { + Debug.Log("Message with byte[].Length: "+ msgBytes.Length); + } + if (this.selectedChannelName.Equals(channelName)) + { + ShowChannel(channelName); + } + } + + /// + /// New status of another user (you get updates for users set in your friends list). + /// + /// Name of the user. + /// New status of that user. + /// True if the status contains a message you should cache locally. False: This status update does not include a + /// message (keep any you have). + /// Message that user set. + public void OnStatusUpdate(string user, int status, bool gotMessage, object message) + { + + Debug.LogWarning("status: " + string.Format("{0} is {1}. Msg:{2}", user, status, message)); + + if (friendListItemLUT.ContainsKey(user)) + { + FriendItem _friendItem = friendListItemLUT[user]; + if ( _friendItem!=null) _friendItem.OnFriendStatusUpdate(status,gotMessage,message); + } + } + + public void AddMessageToSelectedChannel(string msg) + { + ChatChannel channel = null; + bool found = this.chatClient.TryGetChannel(this.selectedChannelName, out channel); + if (!found) + { + Debug.Log("AddMessageToSelectedChannel failed to find channel: " + this.selectedChannelName); + return; + } + + if (channel != null) + { + channel.Add("Bot", msg); + } + } + + + + public void ShowChannel(string channelName) + { + if (string.IsNullOrEmpty(channelName)) + { + return; + } + + ChatChannel channel = null; + bool found = this.chatClient.TryGetChannel(channelName, out channel); + if (!found) + { + Debug.Log("ShowChannel failed to find channel: " + channelName); + return; + } + + this.selectedChannelName = channelName; + this.CurrentChannelText.text = channel.ToStringMessages(); + Debug.Log("ShowChannel: " + this.selectedChannelName); + + foreach (KeyValuePair pair in channelToggles) + { + pair.Value.isOn = pair.Key == channelName ? true : false; + } + } + + public void OpenDashboard() + { + Application.OpenURL("https://www.photonengine.com/en/Dashboard/Chat"); + } + + + + +} \ No newline at end of file diff --git a/Assets/Photon Unity Networking/Demos/DemoChat/ChatGui.cs.meta b/Assets/Photon Unity Networking/Demos/DemoChat/ChatGui.cs.meta new file mode 100644 index 0000000..58c9a18 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoChat/ChatGui.cs.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 02d148d0890b2d44dbdf7f1c1b39a499 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} diff --git a/Assets/Photon Unity Networking/Demos/DemoChat/DemoChat-Scene.unity b/Assets/Photon Unity Networking/Demos/DemoChat/DemoChat-Scene.unity new file mode 100644 index 0000000..aabeb78 Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/DemoChat/DemoChat-Scene.unity differ diff --git a/Assets/Photon Unity Networking/Demos/DemoChat/DemoChat-Scene.unity.meta b/Assets/Photon Unity Networking/Demos/DemoChat/DemoChat-Scene.unity.meta new file mode 100644 index 0000000..5ffe4ea --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoChat/DemoChat-Scene.unity.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: ec07267f6a28fb044ac89845274e79af diff --git a/Assets/Photon Unity Networking/Demos/DemoChat/FriendItem.cs b/Assets/Photon Unity Networking/Demos/DemoChat/FriendItem.cs new file mode 100644 index 0000000..65e275e --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoChat/FriendItem.cs @@ -0,0 +1,80 @@ +using UnityEngine; +using System.Collections; + +using UnityEngine.UI; + +/// +/// Friend UI item used to represent the friend status as well as message. +/// It aims at showing how to share health for a friend that plays on a different room than you for example. +/// But of course the message can be anything and a lot more complex. +/// +public class FriendItem : MonoBehaviour { + + [HideInInspector] + public string FriendId + { + set{ + NameLabel.text = value; + } + get{ + return NameLabel.text; + } + } + + public Text NameLabel; + public Text StatusLabel; + public Text Health; + + public void Awake() + { + Health.text = string.Empty; + } + + public void OnFriendStatusUpdate(int status, bool gotMessage, object message) + { + string _status; + + switch(status) + { + case 1: + _status = "Invisible"; + break; + case 2: + _status = "Online"; + break; + case 3: + _status = "Away"; + break; + case 4: + _status = "Do not disturb"; + break; + case 5: + _status = "Looking For Game/Group"; + break; + case 6: + _status = "Playing"; + break; + default: + _status = "Offline"; + break; + } + + StatusLabel.text = _status; + + if (gotMessage) + { + string _health = string.Empty; + if (message!=null) + { + string[] _messages = message as string[]; + if (_messages!=null && _messages.Length>=2) + { + _health = (string)_messages[1] + "%"; + } + + } + + Health.text = _health; + } + } +} diff --git a/Assets/Photon Unity Networking/Demos/DemoChat/FriendItem.cs.meta b/Assets/Photon Unity Networking/Demos/DemoChat/FriendItem.cs.meta new file mode 100644 index 0000000..3350da8 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoChat/FriendItem.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 660b16ba396d0465b98be14947420288 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Photon Unity Networking/Demos/DemoChat/IgnoreUiRaycastWhenInactive.cs b/Assets/Photon Unity Networking/Demos/DemoChat/IgnoreUiRaycastWhenInactive.cs new file mode 100644 index 0000000..58a8bce --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoChat/IgnoreUiRaycastWhenInactive.cs @@ -0,0 +1,10 @@ +using UnityEngine; + + +public class IgnoreUiRaycastWhenInactive : MonoBehaviour, ICanvasRaycastFilter +{ + public bool IsRaycastLocationValid(Vector2 screenPoint, Camera eventCamera) + { + return gameObject.activeInHierarchy; + } +} \ No newline at end of file diff --git a/Assets/Photon Unity Networking/Demos/DemoChat/IgnoreUiRaycastWhenInactive.cs.meta b/Assets/Photon Unity Networking/Demos/DemoChat/IgnoreUiRaycastWhenInactive.cs.meta new file mode 100644 index 0000000..7e17b08 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoChat/IgnoreUiRaycastWhenInactive.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 4ba4c747f6975ea46bcc0a55ffe3bfe8 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Photon Unity Networking/Demos/DemoChat/NamePickGui.cs b/Assets/Photon Unity Networking/Demos/DemoChat/NamePickGui.cs new file mode 100644 index 0000000..e6d03df --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoChat/NamePickGui.cs @@ -0,0 +1,44 @@ +using UnityEngine; +using UnityEngine.UI; + +[RequireComponent(typeof (ChatGui))] +public class NamePickGui : MonoBehaviour +{ + private const string UserNamePlayerPref = "NamePickUserName"; + + public ChatGui chatNewComponent; + + public InputField idInput; + + public void Start() + { + this.chatNewComponent = FindObjectOfType(); + + + string prefsName = PlayerPrefs.GetString(NamePickGui.UserNamePlayerPref); + if (!string.IsNullOrEmpty(prefsName)) + { + this.idInput.text = prefsName; + } + } + + + // new UI will fire "EndEdit" event also when loosing focus. So check "enter" key and only then StartChat. + public void EndEditOnEnter() + { + if (Input.GetKey(KeyCode.Return) || Input.GetKey(KeyCode.KeypadEnter)) + { + this.StartChat(); + } + } + + public void StartChat() + { + ChatGui chatNewComponent = FindObjectOfType(); + chatNewComponent.UserName = this.idInput.text.Trim(); + chatNewComponent.Connect(); + enabled = false; + + PlayerPrefs.SetString(NamePickGui.UserNamePlayerPref, chatNewComponent.UserName); + } +} \ No newline at end of file diff --git a/Assets/Photon Unity Networking/Demos/DemoChat/NamePickGui.cs.meta b/Assets/Photon Unity Networking/Demos/DemoChat/NamePickGui.cs.meta new file mode 100644 index 0000000..8146182 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoChat/NamePickGui.cs.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 696a5174ff5e707479b3540eb56d14b7 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} diff --git a/Assets/Photon Unity Networking/Demos/DemoFriendsAndCustomAuth.meta b/Assets/Photon Unity Networking/Demos/DemoFriendsAndCustomAuth.meta new file mode 100644 index 0000000..0025538 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoFriendsAndCustomAuth.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 9704e3459618845cc9bf36f480e9dd97 +folderAsset: yes +timeCreated: 1501014811 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Photon Unity Networking/Demos/DemoFriendsAndCustomAuth/DemoFriends-Scene.unity b/Assets/Photon Unity Networking/Demos/DemoFriendsAndCustomAuth/DemoFriends-Scene.unity new file mode 100644 index 0000000..91ad5df Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/DemoFriendsAndCustomAuth/DemoFriends-Scene.unity differ diff --git a/Assets/Photon Unity Networking/Demos/DemoFriendsAndCustomAuth/DemoFriends-Scene.unity.meta b/Assets/Photon Unity Networking/Demos/DemoFriendsAndCustomAuth/DemoFriends-Scene.unity.meta new file mode 100644 index 0000000..8282531 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoFriendsAndCustomAuth/DemoFriends-Scene.unity.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: ce42d7aa47657b740b3200a83d5874c6 diff --git a/Assets/Photon Unity Networking/Demos/DemoFriendsAndCustomAuth/GUICustomAuth.cs b/Assets/Photon Unity Networking/Demos/DemoFriendsAndCustomAuth/GUICustomAuth.cs new file mode 100644 index 0000000..9886d68 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoFriendsAndCustomAuth/GUICustomAuth.cs @@ -0,0 +1,193 @@ +using UnityEngine; +using System.Collections; + +public class GUICustomAuth : MonoBehaviour +{ + public Rect GuiRect; + + private string authName = "usr"; + private string authToken = "usr"; + private string authDebugMessage = string.Empty; + + + public void Start() + { + GuiRect = new Rect(Screen.width / 4, 80, Screen.width / 2, Screen.height - 100); + } + + + public void OnJoinedLobby() + { + // for ease of use, this script simply deactivates itself on successful connect + this.enabled = false; + } + + public void OnConnectedToMaster() + { + // for ease of use, this script simply deactivates itself on successful connect + this.enabled = false; + } + + + /// + /// This method is called when Custom Authentication is setup for your app but fails for any reasons. + /// + /// + /// Unless you setup a custom authentication service for your app (in the Dashboard), this won't be called. + /// If authentication is successful, this method is not called but OnJoinedLobby, OnConnectedToMaster and the + /// others will be called. + /// + /// + public void OnCustomAuthenticationFailed(string debugMessage) + { + this.authDebugMessage = debugMessage; + SetStateAuthFailed(); + } + + + enum GuiState { AuthOrNot, AuthInput, AuthHelp, AuthFailed } + private GuiState guiState; + public GameObject RootOf3dButtons; + + public void SetStateAuthInput() + { + RootOf3dButtons.SetActive(false); + guiState = GuiState.AuthInput; + } + + public void SetStateAuthHelp() + { + RootOf3dButtons.SetActive(false); + guiState = GuiState.AuthHelp; + } + + public void SetStateAuthOrNot() + { + RootOf3dButtons.SetActive(true); + guiState = GuiState.AuthOrNot; + } + + public void SetStateAuthFailed() + { + RootOf3dButtons.SetActive(false); + guiState = GuiState.AuthFailed; + } + + public void ConnectWithNickname() + { + RootOf3dButtons.SetActive(false); + + PhotonNetwork.AuthValues = new AuthenticationValues() {UserId = PhotonNetwork.playerName }; // null by default but maybe set in a previous session. + PhotonNetwork.playerName = PhotonNetwork.playerName + "Nick"; + PhotonNetwork.ConnectUsingSettings("1.0"); + + // PhotonNetwork.playerName gets set in GUIFriendFinding + // a UserID is not used in this case (no AuthValues set) + } + + void OnGUI() + { + if (PhotonNetwork.connected) + { + GUILayout.Label(PhotonNetwork.connectionStateDetailed.ToString()); + return; + } + + + GUILayout.BeginArea(GuiRect); + switch (guiState) + { + case GuiState.AuthFailed: + GUILayout.Label("Authentication Failed"); + + GUILayout.Space(10); + + GUILayout.Label("Error message:\n'" + this.authDebugMessage + "'"); + + GUILayout.Space(10); + + GUILayout.Label("For this demo set the Authentication URL in the Dashboard to:\nhttp://photon.webscript.io/auth-demo-equals"); + GUILayout.Label("That authentication-service has no user-database. It confirms any user if 'name equals password'."); + GUILayout.Label("The error message comes from that service and can be customized."); + + GUILayout.Space(10); + + GUILayout.BeginHorizontal(); + if (GUILayout.Button("Back")) + { + SetStateAuthInput(); + } + if (GUILayout.Button("Help")) + { + SetStateAuthHelp(); + } + GUILayout.EndHorizontal(); + break; + + case GuiState.AuthHelp: + + GUILayout.Label("By default, any player can connect to Photon.\n'Custom Authentication' can be enabled to reject players without valid user-account."); + + GUILayout.Label("The actual authentication must be done by a web-service which you host and customize. Example sourcecode for these services is available on the docs page."); + + GUILayout.Label("For this demo set the Authentication URL in the Dashboard to:\nhttp://photon.webscript.io/auth-demo-equals"); + GUILayout.Label("That authentication-service has no user-database. It confirms any user if 'name equals password'."); + + GUILayout.Space(10); + if (GUILayout.Button("Configure Authentication (Dashboard)")) + { + Application.OpenURL("https://www.photonengine.com/dashboard"); + } + if (GUILayout.Button("Authentication Docs")) + { + Application.OpenURL("http://doc.exitgames.com/en/pun/current/tutorials/pun-and-facebook-custom-authentication"); + } + + + GUILayout.Space(10); + if (GUILayout.Button("Back to input")) + { + SetStateAuthInput(); + } + break; + + case GuiState.AuthInput: + + GUILayout.Label("Authenticate yourself"); + + GUILayout.BeginHorizontal(); + this.authName = GUILayout.TextField(this.authName, GUILayout.Width(Screen.width/4 - 5)); + GUILayout.FlexibleSpace(); + this.authToken = GUILayout.TextField(this.authToken, GUILayout.Width(Screen.width/4 - 5)); + GUILayout.EndHorizontal(); + + + if (GUILayout.Button("Authenticate")) + { + // you need some auth values (before we connect): + PhotonNetwork.AuthValues = new AuthenticationValues(); + + // important: select authentication type (how / where the auth is verified) + PhotonNetwork.AuthValues.AuthType = CustomAuthenticationType.Custom; + + // the demo authentication-service expects values for "username" and "token": + PhotonNetwork.AuthValues.AddAuthParameter("username", this.authName); + PhotonNetwork.AuthValues.AddAuthParameter("token", this.authToken); + + // PUN uses the AuthValues in the connect workflow: + PhotonNetwork.ConnectUsingSettings("1.0"); + } + + GUILayout.Space(10); + + if (GUILayout.Button("Help", GUILayout.Width(100))) + { + SetStateAuthHelp(); + } + + break; + } + + GUILayout.EndArea(); + } +} \ No newline at end of file diff --git a/Assets/Photon Unity Networking/Demos/DemoFriendsAndCustomAuth/GUICustomAuth.cs.meta b/Assets/Photon Unity Networking/Demos/DemoFriendsAndCustomAuth/GUICustomAuth.cs.meta new file mode 100644 index 0000000..8339036 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoFriendsAndCustomAuth/GUICustomAuth.cs.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: f57b574c6a5e6e04e8a5df9aef373533 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} diff --git a/Assets/Photon Unity Networking/Demos/DemoFriendsAndCustomAuth/GUIFriendFinding.cs b/Assets/Photon Unity Networking/Demos/DemoFriendsAndCustomAuth/GUIFriendFinding.cs new file mode 100644 index 0000000..8fa3699 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoFriendsAndCustomAuth/GUIFriendFinding.cs @@ -0,0 +1,107 @@ +using UnityEngine; +using System.Collections; +using ExitGames.Client.Photon; + +public class GUIFriendFinding : MonoBehaviour +{ + private string[] friendListOfSomeCommunity; + public Rect GuiRect; + + private string ExpectedUsers; + + void Start() + { + // If a user should be "findable", the client must set a playerName before connecting. + // This is then used during connect and the client can be found by others. + // Setting the playerName before connect, enables others to locate your game: + PhotonNetwork.playerName = "usr" + (int)Random.Range(0, 9); + + + // Photon Cloud does not implement community features for users but can work with external friends lists. + // We assume you get some list of IDs of your friends. + friendListOfSomeCommunity = FetchFriendsFromCommunity(); + + + GuiRect = new Rect(Screen.width / 4, 80, Screen.width / 2, Screen.height - 100); + } + + + // In this demo, wo just make up some names instead of connecting somewhere + public static string[] FetchFriendsFromCommunity() + { + string[] friendsList = new string[9]; + int u = 0; + for (int i = 0; i < friendsList.Length; i++) + { + string usrName = "usr" + u++; + if (usrName.Equals(PhotonNetwork.playerName)) + { + usrName = "usr" + u++; // skip friend if the name is yours + } + friendsList[i] = usrName; + } + + return friendsList; + } + + + public void OnUpdatedFriendList() + { + Debug.Log("OnUpdatedFriendList is called when the list PhotonNetwork.Friends is refreshed."); + } + + + public void OnGUI() + { + if (!PhotonNetwork.connectedAndReady || PhotonNetwork.Server != ServerConnection.MasterServer) + { + // this feature is only available on the Master Client. Check either: insideLobby or + // PhotonNetwork.connectionStateDetailed == PeerState.Authenticated or + // PhotonNetwork.inRoomLobby + + // for simplicity (and cause we know we WILL join the lobby, we can just check that) + return; + } + + + GUILayout.BeginArea(GuiRect); + + GUILayout.Label("Your (random) name: " + PhotonNetwork.playerName); + GUILayout.Label("Your friends: " + string.Join(", ",this.friendListOfSomeCommunity)); + + + GUILayout.BeginHorizontal(); + if (GUILayout.Button("Find Friends")) + { + PhotonNetwork.FindFriends(this.friendListOfSomeCommunity); + } + if (GUILayout.Button("Create Room")) + { + PhotonNetwork.CreateRoom(null); // just a random room + } + + ExpectedUsers = GUILayout.TextField("Expected Users",ExpectedUsers); + + GUILayout.EndHorizontal(); + + + if (PhotonNetwork.Friends != null) + { + foreach (FriendInfo info in PhotonNetwork.Friends) + { + GUILayout.BeginHorizontal(); + GUILayout.Label(info.ToString()); + if (info.IsInRoom) + { + if (GUILayout.Button("join")) + { + PhotonNetwork.JoinRoom(info.Room); + } + } + GUILayout.EndHorizontal(); + } + } + + GUILayout.EndArea(); + } +} diff --git a/Assets/Photon Unity Networking/Demos/DemoFriendsAndCustomAuth/GUIFriendFinding.cs.meta b/Assets/Photon Unity Networking/Demos/DemoFriendsAndCustomAuth/GUIFriendFinding.cs.meta new file mode 100644 index 0000000..b131280 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoFriendsAndCustomAuth/GUIFriendFinding.cs.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 7955012e86bc1504d8aba54bf68201e7 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} diff --git a/Assets/Photon Unity Networking/Demos/DemoFriendsAndCustomAuth/GUIFriendsInRoom.cs b/Assets/Photon Unity Networking/Demos/DemoFriendsAndCustomAuth/GUIFriendsInRoom.cs new file mode 100644 index 0000000..4f9c8a8 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoFriendsAndCustomAuth/GUIFriendsInRoom.cs @@ -0,0 +1,40 @@ +using UnityEngine; +using System.Collections; + +public class GUIFriendsInRoom : MonoBehaviour +{ + public Rect GuiRect; + + + void Start() + { + GuiRect = new Rect(Screen.width / 4, 80, Screen.width / 2, Screen.height - 100); + } + + + public void OnGUI() + { + if (!PhotonNetwork.inRoom) + { + return; + } + + GUILayout.BeginArea(GuiRect); + + GUILayout.Label("In-Game"); + GUILayout.Label("For simplicity, this demo just shows the players in this room. The list will expand when more join."); + GUILayout.Label("Your (random) name: " + PhotonNetwork.playerName); + GUILayout.Label(PhotonNetwork.playerList.Length + " players in this room."); + GUILayout.Label("The others are:"); + foreach (PhotonPlayer player in PhotonNetwork.otherPlayers) + { + GUILayout.Label(player.ToString()); + } + + if (GUILayout.Button("Leave")) + { + PhotonNetwork.LeaveRoom(); + } + GUILayout.EndArea(); + } +} diff --git a/Assets/Photon Unity Networking/Demos/DemoFriendsAndCustomAuth/GUIFriendsInRoom.cs.meta b/Assets/Photon Unity Networking/Demos/DemoFriendsAndCustomAuth/GUIFriendsInRoom.cs.meta new file mode 100644 index 0000000..939ebab --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoFriendsAndCustomAuth/GUIFriendsInRoom.cs.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: ffba99130c6923e488e9b4221cdf9af8 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} diff --git a/Assets/Photon Unity Networking/Demos/DemoFriendsAndCustomAuth/OnClickCallMethod.cs b/Assets/Photon Unity Networking/Demos/DemoFriendsAndCustomAuth/OnClickCallMethod.cs new file mode 100644 index 0000000..6be9ed3 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoFriendsAndCustomAuth/OnClickCallMethod.cs @@ -0,0 +1,21 @@ +using UnityEngine; +using System.Collections; + +[RequireComponent(typeof(Collider))] +public class OnClickCallMethod : Photon.MonoBehaviour +{ + public GameObject TargetGameObject; + public string TargetMethod; + + // called by InputToEvent script if that's on a camera + public void OnClick() + { + if (this.TargetGameObject == null || string.IsNullOrEmpty(this.TargetMethod)) + { + Debug.LogWarning(this + " can't call, cause GO or Method are empty."); + return; + } + + this.TargetGameObject.SendMessage(this.TargetMethod); + } +} diff --git a/Assets/Photon Unity Networking/Demos/DemoFriendsAndCustomAuth/OnClickCallMethod.cs.meta b/Assets/Photon Unity Networking/Demos/DemoFriendsAndCustomAuth/OnClickCallMethod.cs.meta new file mode 100644 index 0000000..386fedf --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoFriendsAndCustomAuth/OnClickCallMethod.cs.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: a9985e7a9ccca8846a19e56ef2ed0772 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} diff --git a/Assets/Photon Unity Networking/Demos/DemoHub.meta b/Assets/Photon Unity Networking/Demos/DemoHub.meta new file mode 100644 index 0000000..bdf4938 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoHub.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 98cd002eeef4743e88235c10865292cd +folderAsset: yes +timeCreated: 1501014811 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Photon Unity Networking/Demos/DemoHub/DemoHub-Scene-V2.unity b/Assets/Photon Unity Networking/Demos/DemoHub/DemoHub-Scene-V2.unity new file mode 100644 index 0000000..08851a2 Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/DemoHub/DemoHub-Scene-V2.unity differ diff --git a/Assets/Photon Unity Networking/Demos/DemoHub/DemoHub-Scene-V2.unity.meta b/Assets/Photon Unity Networking/Demos/DemoHub/DemoHub-Scene-V2.unity.meta new file mode 100644 index 0000000..53bf3e9 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoHub/DemoHub-Scene-V2.unity.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: 7dfd47dc8b9484dd79d8636d8603a9e5 +DefaultImporter: + userData: diff --git a/Assets/Photon Unity Networking/Demos/DemoHub/Editor.meta b/Assets/Photon Unity Networking/Demos/DemoHub/Editor.meta new file mode 100644 index 0000000..9d82392 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoHub/Editor.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 36151b1ead8764972bb0c6efd9f5365d +folderAsset: yes +timeCreated: 1501014811 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Photon Unity Networking/Demos/DemoHub/Editor/PunStartup.cs b/Assets/Photon Unity Networking/Demos/DemoHub/Editor/PunStartup.cs new file mode 100644 index 0000000..ab91abf --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoHub/Editor/PunStartup.cs @@ -0,0 +1,129 @@ +using System; +using System.Collections.Generic; +using System.IO; +using UnityEditor.SceneManagement; +using UnityEngine; +using UnityEditor; + + +[InitializeOnLoad] +public class PunStartup : MonoBehaviour +{ + // paths to demo scenes to setup (if needed) + private const string demoBasePath = "Assets/Photon Unity Networking/Demos/"; + private static string[] demoPaths = + { + "DemoHub/DemoHub-Scene-V2.unity", + "DemoBoxes/DemoBoxes-Scene.unity", + "DemoWorker/DemoWorker-Scene.unity", + "DemoWorker/DemoWorkerGame-Scene.unity", + "MarcoPolo-Tutorial/MarcoPolo-Scene.unity", + "DemoSynchronization/DemoSynchronization-Scene.unity", + "DemoFriendsAndCustomAuth/DemoFriends-Scene.unity", + "DemoFriendsAndCustomAuth/DemoPickup-Scene.unity", + "DemoChat/DemoChat-Scene.unity" + }; + + static PunStartup() + { + bool doneBefore = EditorPrefs.GetBool("PunDemosOpenedBefore"); + if (!doneBefore) + { + EditorApplication.update += OnUpdate; + } + } + + static void OnUpdate() + { + if (EditorApplication.isUpdating) + { + return; + } + + bool doneBefore = EditorPrefs.GetBool("PunDemosOpenedBefore"); + if (doneBefore) + { + EditorApplication.update -= OnUpdate; + return; + } + + if (string.IsNullOrEmpty(SceneManagerHelper.EditorActiveSceneName) && EditorBuildSettings.scenes.Length == 0) + { + LoadPunDemoHub(); + SetPunDemoBuildSettings(); + EditorPrefs.SetBool("PunDemosOpenedBefore", true); + Debug.Log("No scene was open. Loaded PUN Demo Hub Scene and added demos to build settings. Ready to go! This auto-setup is now disabled in this Editor."); + } + else + { + EditorApplication.update -= OnUpdate; + } + } + + [MenuItem("Window/Photon Unity Networking/Configure Demos (build setup)", false, 5)] + public static void SetupDemo() + { + SetPunDemoBuildSettings(); + } + + //[MenuItem("Window/Photon Unity Networking/PUN Demo Loader Reset")] + //protected static void ResetDemoLoader() + //{ + // EditorPrefs.DeleteKey("PunDemosOpenedBefore"); + //} + + public static void LoadPunDemoHub() + { + EditorSceneManager.OpenScene(demoBasePath + demoPaths[0]); + Selection.activeObject = AssetDatabase.LoadMainAssetAtPath(demoBasePath + demoPaths[0]); + } + + /// + /// Finds scenes in "Assets/Photon Unity Networking/Demos/", excludes those in folder "PUNGuide_M2H" and applies remaining scenes to build settings. The one with "Hub" in it first. + /// + public static void SetPunDemoBuildSettings() + { + // find path of pun guide + string[] tempPaths = Directory.GetDirectories(Application.dataPath + "/Photon Unity Networking", "Demos", SearchOption.AllDirectories); + if (tempPaths == null || tempPaths.Length != 1) + { + return; + } + + // find scenes of guide + string guidePath = tempPaths[0]; + tempPaths = Directory.GetFiles(guidePath, "*.unity", SearchOption.AllDirectories); + + if (tempPaths == null || tempPaths.Length == 0) + { + return; + } + + // add found guide scenes to build settings + List sceneAr = new List(); + for (int i = 0; i < tempPaths.Length; i++) + { + //Debug.Log(tempPaths[i]); + string path = tempPaths[i].Substring(Application.dataPath.Length - "Assets".Length); + path = path.Replace('\\', '/'); + //Debug.Log(path); + + if (path.Contains("PUNGuide_M2H")) + { + continue; + } + + // edited to avoid old scene to be included. + if (path.Contains("DemoHub-Scene-V2")) + { + sceneAr.Insert(0, new EditorBuildSettingsScene(path, true)); + continue; + } + + sceneAr.Add(new EditorBuildSettingsScene(path, true)); + } + + EditorBuildSettings.scenes = sceneAr.ToArray(); + EditorSceneManager.OpenScene(sceneAr[0].path); + } +} \ No newline at end of file diff --git a/Assets/Photon Unity Networking/Demos/DemoHub/Editor/PunStartup.cs.meta b/Assets/Photon Unity Networking/Demos/DemoHub/Editor/PunStartup.cs.meta new file mode 100644 index 0000000..8e5597a --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoHub/Editor/PunStartup.cs.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 6bafe5c223c99ab44a5f70010efdae47 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} diff --git a/Assets/Photon Unity Networking/Demos/DemoHub/HubGui.cs b/Assets/Photon Unity Networking/Demos/DemoHub/HubGui.cs new file mode 100644 index 0000000..35de11b --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoHub/HubGui.cs @@ -0,0 +1,156 @@ +using UnityEngine; +using System.Collections; +using UnityEngine.SceneManagement; + +public class HubGui : MonoBehaviour +{ + + public GUISkin Skin; + + private Vector2 scrollPos = new Vector2(); + private string demoDescription = "PUN Demo Hub\n\nSelect a demo to learn more about it.\n\nYou should open individual scenes in the Editor to dissect how they work.\n\nLook out for Console output. Especially in Editor (double click logs to jump to their origin in source)."; + private struct DemoBtn + { + public string Text; + public string Link; + } + + private DemoBtn demoBtn; + private DemoBtn webLink; + + GUIStyle m_Headline; + + void Start() + { + if (PhotonNetwork.connected || PhotonNetwork.connecting) + { + PhotonNetwork.Disconnect(); + } + m_Headline = new GUIStyle(this.Skin.label); + m_Headline.padding = new RectOffset(3, 0, 0, 0); + } + + void OnGUI() + { + GUI.skin = this.Skin; + GUILayout.Space(10); + + GUILayout.BeginHorizontal(); + GUILayout.Space(10); + scrollPos = GUILayout.BeginScrollView(scrollPos, GUILayout.Width(320)); + + GUILayout.Label("Basics", m_Headline); + if (GUILayout.Button("Demo Boxes", GUILayout.Width(280))) + { + demoDescription = "Demo Boxes\n\nUses ConnectAndJoinRandom script.\n(joins a random room or creates one)\n\nInstantiates simple prefabs.\nSynchronizes positions without smoothing.\nShows that RPCs target a specific object."; + demoBtn = new DemoBtn() { Text = "Start", Link = "DemoBoxes-Scene" }; + } + if (GUILayout.Button("Demo Worker", GUILayout.Width(280))) + { + demoDescription = "Demo Worker\n\nJoins the default lobby and shows existing rooms.\nLets you create or join a room.\nInstantiates an animated character.\nSynchronizes position and animation state of character with smoothing.\nImplements simple in-room Chat via RPC calls."; + demoBtn = new DemoBtn() { Text = "Start", Link = "DemoWorker-Scene" }; + } + if (GUILayout.Button("Movement Smoothing", GUILayout.Width(280))) + { + demoDescription = "Movement Smoothing\n\nUses ConnectAndJoinRandom script.\nShows several basic ways to synchronize positions between controlling client and remote ones.\nThe TransformView is a good default to use."; + demoBtn = new DemoBtn() { Text = "Start", Link = "DemoSynchronization-Scene" }; + } + + + if (GUILayout.Button("Basic Tutorial", GUILayout.Width(280))) + { + demoDescription = "Basic tutorial\n\n" + + "All custom code for connection, player and scene management.\n" + + "Auto synchronization of room levels.\n" + + "Uses PhotonAnimatoView for Animator synch.\n" + + "New Unity UI all around, for Menus and player health HUD.\n" + + "Full step by step tutorial available online."; + demoBtn = new DemoBtn() { Text = "Start", Link = "PunBasics-Launcher" }; + } + + GUILayout.Label("Advanced", m_Headline); + if (GUILayout.Button("Ownership Transfer", GUILayout.Width(280))) + { + demoDescription = "Ownership Transfer\n\nShows how to transfer the ownership of a PhotonView.\nThe owner will send position updates of the GameObject.\nTransfer can be edited per PhotonView and set to Fixed (no transfer), Request (owner has to agree) or Takeover (owner can't object)."; + this.demoBtn = new DemoBtn() { Text = "Start", Link = "DemoChangeOwner-Scene" }; + this.webLink = new DemoBtn(); + } + if (GUILayout.Button("Pickup, Teams, Scores", GUILayout.Width(280))) + { + demoDescription = "Pickup, Teams, Scores\n\nUses ConnectAndJoinRandom script.\nImplements item pickup with RPCs.\nUses Custom Properties for Teams.\nCounts score per player and team.\nUses PhotonPlayer extension methods for easy Custom Property access."; + this.demoBtn = new DemoBtn() { Text = "Start", Link = "DemoPickup-Scene" }; + this.webLink = new DemoBtn(); + } + + GUILayout.Label("Feature Demos", m_Headline); + if (GUILayout.Button("Chat", GUILayout.Width(280))) + { + demoDescription = "Chat\n\nUses the Chat API (now part of PUN).\nSimple UI.\nYou can enter any User ID.\nAutomatically subscribes some channels.\nAllows simple commands via text.\n\nRequires configuration of Chat App ID in scene."; + this.demoBtn = new DemoBtn() { Text = "Start", Link = "DemoChat-Scene" }; + this.webLink = new DemoBtn(); + } + if (GUILayout.Button("RPG Movement", GUILayout.Width(280))) + { + demoDescription = "RPG Movement\n\nDemonstrates how to use the PhotonTransformView component to synchronize position updates smoothly using inter- and extrapolation.\n\nThis demo also shows how to setup a Mecanim Animator to update animations automatically based on received position updates (without sending explicit animation updates)."; + this.demoBtn = new DemoBtn() { Text = "Start", Link = "DemoRPGMovement-Scene" }; + this.webLink = new DemoBtn(); + } + if (GUILayout.Button("Mecanim Animations", GUILayout.Width(280))) + { + demoDescription = "Mecanim Animations\n\nThis demo shows how to use the PhotonAnimatorView component to easily synchronize Mecanim animations.\n\nIt also demonstrates another feature of the PhotonTransformView component which gives you more control how position updates are inter-/extrapolated by telling the component how fast the object moves and turns using SetSynchronizedValues()."; + this.demoBtn = new DemoBtn() { Text = "Start", Link = "DemoMecanim-Scene" }; + this.webLink = new DemoBtn(); + } + if (GUILayout.Button("2D Game", GUILayout.Width(280))) + { + demoDescription = "2D Game Demo\n\nSynchronizes animations, positions and physics in a 2D scene."; + this.demoBtn = new DemoBtn() { Text = "Start", Link = "Demo2DJumpAndRunWithPhysics-Scene" }; + this.webLink = new DemoBtn(); + } + if (GUILayout.Button("Friends & Authentication", GUILayout.Width(280))) + { + demoDescription = "Friends & Authentication\n\nShows connect with or without (server-side) authentication.\n\nAuthentication requires minor server-side setup (in Dashboard).\n\nOnce connected, you can find (made up) friends.\nJoin a room just to see how that gets visible in friends list."; + this.demoBtn = new DemoBtn() { Text = "Start", Link = "DemoFriends-Scene" }; + this.webLink = new DemoBtn(); + } + + if (GUILayout.Button("Turn Based Game", GUILayout.Width(280))) + { + demoDescription = "'Rock Paper Scissor' Turn Based Game\n\nDemonstrate TurnBased Game Mechanics using PUN.\n\nIt makes use of the TurnBasedManager Utility Script"; + this.demoBtn = new DemoBtn() { Text = "Start", Link = "DemoRPS-Scene" }; + this.webLink = new DemoBtn(); + } + + + GUILayout.Label("Tutorial", m_Headline); + if (GUILayout.Button("Marco Polo Tutorial", GUILayout.Width(280))) + { + demoDescription = "Marco Polo Tutorial\n\nFinal result you could get when you do the Marco Polo Tutorial.\nSlightly modified to be more compatible with this package."; + this.demoBtn = new DemoBtn() { Text = "Start", Link = "MarcoPolo-Scene" }; + this.webLink = new DemoBtn() { Text = "Open Tutorial (www)", Link = "http://tinyurl.com/nmylf44" }; + } + GUILayout.EndScrollView(); + + GUILayout.BeginVertical(GUILayout.Width(Screen.width - 345)); + GUILayout.Label(demoDescription); + GUILayout.Space(10); + if (!string.IsNullOrEmpty(this.demoBtn.Text)) + { + if (GUILayout.Button(this.demoBtn.Text)) + { + SceneManager.LoadScene(this.demoBtn.Link); + } + } + if (!string.IsNullOrEmpty(this.webLink.Text)) + { + if (GUILayout.Button(this.webLink.Text)) + { + Application.OpenURL(this.webLink.Link); + } + } + GUILayout.EndVertical(); + + + GUILayout.EndHorizontal(); + } +} \ No newline at end of file diff --git a/Assets/Photon Unity Networking/Demos/DemoHub/HubGui.cs.meta b/Assets/Photon Unity Networking/Demos/DemoHub/HubGui.cs.meta new file mode 100644 index 0000000..e7da3b0 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoHub/HubGui.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: a6f1bb55d1363b545b4a26ceaef9d1ad +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Photon Unity Networking/Demos/DemoHub/MoveCam.cs b/Assets/Photon Unity Networking/Demos/DemoHub/MoveCam.cs new file mode 100644 index 0000000..6a92aaa --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoHub/MoveCam.cs @@ -0,0 +1,31 @@ +using UnityEngine; +using System.Collections; + +[RequireComponent(typeof(Camera))] +public class MoveCam : MonoBehaviour +{ + private Vector3 originalPos; + private Vector3 randomPos; + private Transform camTransform; + public Transform lookAt; + + // Use this for initialization + void Start () + { + camTransform = GetComponent().transform; + originalPos = camTransform.position; + + randomPos = originalPos + new Vector3(Random.Range(-2, 2), Random.Range(-2, 2), Random.Range(-1, 1)); + } + + // Update is called once per frame + private void Update() + { + camTransform.position = Vector3.Slerp(camTransform.position, randomPos, Time.deltaTime); + camTransform.LookAt(lookAt); + if (Vector3.Distance(camTransform.position, randomPos) < 0.5f) + { + randomPos = originalPos + new Vector3(Random.Range(-2, 2), Random.Range(-2, 2), Random.Range(-1, 1)); + } + } +} diff --git a/Assets/Photon Unity Networking/Demos/DemoHub/MoveCam.cs.meta b/Assets/Photon Unity Networking/Demos/DemoHub/MoveCam.cs.meta new file mode 100644 index 0000000..f8792a7 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoHub/MoveCam.cs.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 66a8c34642b4b5e40b48bb982b8b96b9 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} diff --git a/Assets/Photon Unity Networking/Demos/DemoHub/Scripts.meta b/Assets/Photon Unity Networking/Demos/DemoHub/Scripts.meta new file mode 100644 index 0000000..d034844 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoHub/Scripts.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: c2331e1d3cc944f4899f297b956721af +folderAsset: yes +timeCreated: 1501014811 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Photon Unity Networking/Demos/DemoHub/Scripts/DemoHubManager.cs b/Assets/Photon Unity Networking/Demos/DemoHub/Scripts/DemoHubManager.cs new file mode 100644 index 0000000..5606527 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoHub/Scripts/DemoHubManager.cs @@ -0,0 +1,281 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Part of: Photon Unity Demos +// +// +// Used as starting point to let developer choose amongst all demos available. +// +// developer@exitgames.com +// -------------------------------------------------------------------------------------------------------------------- + + +using UnityEngine; +using System.Collections; +using System.Collections.Generic; + +using UnityEngine.UI; +using UnityEngine.EventSystems; + +using UnityEngine.SceneManagement; + +namespace ExitGames.Demos +{ + public class DemoHubManager : MonoBehaviour { + + + public Text TitleText; + public Text DescriptionText; + public GameObject OpenSceneButton; + public GameObject OpenTutorialLinkButton; + public GameObject OpenDocLinkButton; + + string MainDemoWebLink = "http://bit.ly/2f8OFu8"; + + struct DemoData + { + public string Title; + public string Description; + public string Scene; + public string TutorialLink; + public string DocLink; + } + + Dictionary _data = new Dictionary(); + + string currentSelection; + + // Use this for initialization + void Awake () { + + OpenSceneButton.SetActive(false); + + OpenTutorialLinkButton.SetActive(false); + OpenDocLinkButton.SetActive(false); + + // Setup data + _data.Add( + "DemoBoxes", + new DemoData() + { + Title = "Demo Boxes", + Description = "Uses ConnectAndJoinRandom script.\n" + + "(joins a random room or creates one)\n" + + "\n" + + "Instantiates simple prefabs.\n" + + "Synchronizes positions without smoothing.\n" + + "Shows that RPCs target a specific object.", + Scene = "DemoBoxes-Scene" + } + ); + + _data.Add( + "DemoWorker", + new DemoData() + { + Title = "Demo Worker", + Description = "Joins the default lobby and shows existing rooms.\n" + + "Lets you create or join a room.\n" + + "Instantiates an animated character.\n" + + "Synchronizes position and animation state of character with smoothing.\n" + + "Implements simple in-room Chat via RPC calls.", + Scene = "DemoWorker-Scene" + } + ); + + _data.Add( + "MovementSmoothing", + new DemoData() + { + Title = "Movement Smoothing", + Description = "Uses ConnectAndJoinRandom script.\n" + + "Shows several basic ways to synchronize positions between controlling client and remote ones.\n" + + "The TransformView is a good default to use.", + Scene = "DemoSynchronization-Scene" + } + ); + + _data.Add( + "BasicTutorial", + new DemoData() + { + Title = "Basic Tutorial", + Description = "All custom code for connection, player and scene management.\n" + + "Auto synchronization of room levels.\n" + + "Uses PhotonAnimatoView for Animator synch.\n" + + "New Unity UI all around, for Menus and player health HUD.\n" + + "Full step by step tutorial available online.", + Scene = "PunBasics-Launcher" , + TutorialLink = "http://j.mp/2dibZIM" + } + ); + + _data.Add( + "OwnershipTransfer", + new DemoData() + { + Title = "Ownership Transfer", + Description = "Shows how to transfer the ownership of a PhotonView.\n" + + "The owner will send position updates of the GameObject.\n" + + "Transfer can be edited per PhotonView and set to Fixed (no transfer), Request (owner has to agree) or Takeover (owner can't object).", + Scene = "DemoChangeOwner-Scene" + } + ); + + _data.Add( + "PickupTeamsScores", + new DemoData() + { + Title = "Pickup, Teams, Scores", + Description = "Uses ConnectAndJoinRandom script.\n" + + "Implements item pickup with RPCs.\n" + + "Uses Custom Properties for Teams.\n" + + "Counts score per player and team.\n" + + "Uses PhotonPlayer extension methods for easy Custom Property access.", + Scene = "DemoPickup-Scene" + } + ); + + _data.Add( + "Chat", + new DemoData() + { + Title = "Chat", + Description = "Uses the Chat API (now part of PUN).\n" + + "Simple UI.\n" + + "You can enter any User ID.\n" + + "Automatically subscribes some channels.\n" + + "Allows simple commands via text.\n" + + "\n" + + "Requires configuration of Chat App ID in scene.", + Scene = "DemoChat-Scene", + DocLink = "http://j.mp/2iwQkPJ" + } + ); + + _data.Add( + "RPGMovement", + new DemoData() + { + Title = "RPG Movement", + Description = "Demonstrates how to use the PhotonTransformView component to synchronize position updates smoothly using inter- and extrapolation.\n" + + "\n" + + "This demo also shows how to setup a Mecanim Animator to update animations automatically based on received position updates (without sending explicit animation updates).", + Scene = "DemoRPGMovement-Scene" + } + ); + + _data.Add( + "MecanimAnimations", + new DemoData() + { + Title = "Mecanim Animations", + Description = "This demo shows how to use the PhotonAnimatorView component to easily synchronize Mecanim animations.\n" + + "\n" + + "It also demonstrates another feature of the PhotonTransformView component which gives you more control how position updates are inter-/extrapolated by telling the component how fast the object moves and turns using SetSynchronizedValues().", + Scene = "DemoMecanim-Scene" + } + ); + + _data.Add( + "2DGame", + new DemoData() + { + Title = "2D Game Demo", + Description = "Synchronizes animations, positions and physics in a 2D scene.", + Scene = "Demo2DJumpAndRunWithPhysics-Scene" + } + ); + + _data.Add( + "FriendsAndAuth", + new DemoData() + { + Title = "Friends & Authentication", + Description = "Shows connect with or without (server-side) authentication.\n" + + "\n" + + "Authentication requires minor server-side setup (in Dashboard).\n" + + "\n" + + "Once connected, you can find (made up) friends.\nJoin a room just to see how that gets visible in friends list.", + Scene = "DemoFriends-Scene" + } + ); + + _data.Add( + "TurnBasedGame", + new DemoData() + { + Title = "'Rock Paper Scissor' Turn Based Game", + Description = "Demonstrate TurnBased Game Mechanics using PUN.\n" + + "\n" + + "It makes use of the TurnBasedManager Utility Script", + Scene = "DemoRPS-Scene" + } + ); + + _data.Add( + "MarcoPoloTutorial", + new DemoData() + { + Title = "Marco Polo Tutorial", + Description = "Final result you could get when you do the Marco Polo Tutorial.\n" + + "Slightly modified to be more compatible with this package.", + Scene = "MarcoPolo-Scene", + TutorialLink = "http://tinyurl.com/nmylf44" + } + ); + + + } + + public void SelectDemo(string Reference) + { + currentSelection = Reference; + + TitleText.text = _data[currentSelection].Title; + DescriptionText.text = _data[currentSelection].Description; + + OpenSceneButton.SetActive(!string.IsNullOrEmpty(_data[currentSelection].Scene)); + + OpenTutorialLinkButton.SetActive(!string.IsNullOrEmpty(_data[currentSelection].TutorialLink)); + OpenDocLinkButton.SetActive(!string.IsNullOrEmpty(_data[currentSelection].DocLink)); + } + + public void OpenScene() + { + if (string.IsNullOrEmpty(currentSelection)) + { + Debug.LogError("Bad setup, a CurrentSelection is expected at this point"); + return; + } + + SceneManager.LoadScene(_data[currentSelection].Scene); + } + + public void OpenTutorialLink() + { + if (string.IsNullOrEmpty(currentSelection)) + { + Debug.LogError("Bad setup, a CurrentSelection is expected at this point"); + return; + } + + Application.OpenURL(_data[currentSelection].TutorialLink); + } + + public void OpenDocLink() + { + if (string.IsNullOrEmpty(currentSelection)) + { + Debug.LogError("Bad setup, a CurrentSelection is expected at this point"); + return; + } + + Application.OpenURL(_data[currentSelection].DocLink); + } + + public void OpenMainWebLink() + { + Application.OpenURL(MainDemoWebLink); + } + } +} \ No newline at end of file diff --git a/Assets/Photon Unity Networking/Demos/DemoHub/Scripts/DemoHubManager.cs.meta b/Assets/Photon Unity Networking/Demos/DemoHub/Scripts/DemoHubManager.cs.meta new file mode 100644 index 0000000..42165ce --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoHub/Scripts/DemoHubManager.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ed6ca7d1055974cc7847025558e8a903 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Photon Unity Networking/Demos/DemoHub/Scripts/ToDemoHubButton.cs b/Assets/Photon Unity Networking/Demos/DemoHub/Scripts/ToDemoHubButton.cs new file mode 100644 index 0000000..e1e3a56 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoHub/Scripts/ToDemoHubButton.cs @@ -0,0 +1,125 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Part of: Photon Unity Demos +// +// +// Present a button on all launched demos from hub to allow getting back to the demo hub. +// +// developer@exitgames.com +// -------------------------------------------------------------------------------------------------------------------- + + + +#if UNITY_5 && (!UNITY_5_0 && !UNITY_5_1 && !UNITY_5_2 && !UNITY_5_3) || UNITY_6 +#define UNITY_MIN_5_4 +#endif + +using UnityEngine; +using UnityEngine.SceneManagement; +using UnityEngine.UI; +using UnityEngine.EventSystems; + +namespace ExitGames.Demos +{ + /// + /// Present a button on all launched demos from hub to allow getting back to the demo hub. + /// + public class ToDemoHubButton : MonoBehaviour + { + + private static ToDemoHubButton instance; + + + CanvasGroup _canvasGroup; + + public static ToDemoHubButton Instance + { + get + { + if (instance == null) + { + instance = FindObjectOfType(typeof (ToDemoHubButton)) as ToDemoHubButton; + } + + return instance; + } + } + + public void Awake() + { + if (Instance != null && Instance != this) + { + Destroy(gameObject); + } + } + + // Use this for initialization + public void Start() + { + DontDestroyOnLoad(gameObject); + + _canvasGroup = GetComponent(); + + + #if UNITY_MIN_5_4 + // Unity 5.4 has a new scene management. register a method to call CalledOnLevelWasLoaded. + UnityEngine.SceneManagement.SceneManager.sceneLoaded += (scene, loadingMode) => + { + this.CalledOnLevelWasLoaded(scene.buildIndex); + }; + #endif + + + } + + #if !UNITY_MIN_5_4 + /// See CalledOnLevelWasLoaded. Outdated in Unity 5.4. + void OnLevelWasLoaded(int level) + { + this.CalledOnLevelWasLoaded(level); + } + #endif + + + void CalledOnLevelWasLoaded(int level) + { + Debug.Log("CalledOnLevelWasLoaded"); + if (EventSystem.current == null) + { + Debug.LogError("no eventSystem"); + } + } + + + public void Update() + { + bool sceneZeroLoaded = false; + + #if UNITY_5 && !UNITY_5_0 && !UNITY_5_1 && !UNITY_5_2 + sceneZeroLoaded = SceneManager.GetActiveScene().buildIndex == 0; + #else + sceneZeroLoaded = Application.loadedLevel == 0; + #endif + + if (sceneZeroLoaded && _canvasGroup.alpha!= 0f) + { + _canvasGroup.alpha = 0f; + _canvasGroup.interactable = false; + } + + if (!sceneZeroLoaded && _canvasGroup.alpha!= 1f) + { + _canvasGroup.alpha = 1f; + _canvasGroup.interactable = true; + } + + } + + public void BackToHub() + { + PhotonNetwork.Disconnect(); + SceneManager.LoadScene(0); + } + + } +} \ No newline at end of file diff --git a/Assets/Photon Unity Networking/Demos/DemoHub/Scripts/ToDemoHubButton.cs.meta b/Assets/Photon Unity Networking/Demos/DemoHub/Scripts/ToDemoHubButton.cs.meta new file mode 100644 index 0000000..c09ac61 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoHub/Scripts/ToDemoHubButton.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: f877c2f2d403a4d4f975fb1fd64fe7e8 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Photon Unity Networking/Demos/DemoHub/Sprites.meta b/Assets/Photon Unity Networking/Demos/DemoHub/Sprites.meta new file mode 100644 index 0000000..d895a88 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoHub/Sprites.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: c8590514a6c6d47709d03c9564a5806c +folderAsset: yes +timeCreated: 1501014811 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Photon Unity Networking/Demos/DemoHub/Sprites/Gradient.png b/Assets/Photon Unity Networking/Demos/DemoHub/Sprites/Gradient.png new file mode 100644 index 0000000..67e1ce2 Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/DemoHub/Sprites/Gradient.png differ diff --git a/Assets/Photon Unity Networking/Demos/DemoHub/Sprites/Gradient.png.meta b/Assets/Photon Unity Networking/Demos/DemoHub/Sprites/Gradient.png.meta new file mode 100644 index 0000000..e61dbb4 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoHub/Sprites/Gradient.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: 66efb24ed46044ab8a039599cbc47d7b +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + linearTexture: 0 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -2 + maxTextureSize: 256 + textureSettings: + filterMode: 0 + aniso: 16 + mipBias: -1 + wrapMode: 1 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 1 + textureType: 8 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/Assets/Photon Unity Networking/Demos/DemoHub/Sprites/OutlinedSquaredBox.png b/Assets/Photon Unity Networking/Demos/DemoHub/Sprites/OutlinedSquaredBox.png new file mode 100644 index 0000000..59d02dc Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/DemoHub/Sprites/OutlinedSquaredBox.png differ diff --git a/Assets/Photon Unity Networking/Demos/DemoHub/Sprites/OutlinedSquaredBox.png.meta b/Assets/Photon Unity Networking/Demos/DemoHub/Sprites/OutlinedSquaredBox.png.meta new file mode 100644 index 0000000..e20e38f --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoHub/Sprites/OutlinedSquaredBox.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: c222cd02c447941edb09ecb6433229ce +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + linearTexture: 0 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -3 + maxTextureSize: 1024 + textureSettings: + filterMode: -1 + aniso: 1 + mipBias: -1 + wrapMode: 1 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 2, y: 2, z: 2, w: 2} + spritePixelsToUnits: 100 + alphaIsTransparency: 1 + textureType: 8 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/Assets/Photon Unity Networking/Demos/DemoHub/Sprites/PunIcon-White-129.png b/Assets/Photon Unity Networking/Demos/DemoHub/Sprites/PunIcon-White-129.png new file mode 100644 index 0000000..885c22f Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/DemoHub/Sprites/PunIcon-White-129.png differ diff --git a/Assets/Photon Unity Networking/Demos/DemoHub/Sprites/PunIcon-White-129.png.meta b/Assets/Photon Unity Networking/Demos/DemoHub/Sprites/PunIcon-White-129.png.meta new file mode 100644 index 0000000..c706df2 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoHub/Sprites/PunIcon-White-129.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: 56bbc6b42271d4177ac313247f47ac1f +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + linearTexture: 0 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -2 + maxTextureSize: 128 + textureSettings: + filterMode: -1 + aniso: 1 + mipBias: -1 + wrapMode: 1 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 1 + textureType: 8 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/Assets/Photon Unity Networking/Demos/DemoHub/Sprites/toHub.png b/Assets/Photon Unity Networking/Demos/DemoHub/Sprites/toHub.png new file mode 100644 index 0000000..4e76dd3 Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/DemoHub/Sprites/toHub.png differ diff --git a/Assets/Photon Unity Networking/Demos/DemoHub/Sprites/toHub.png.meta b/Assets/Photon Unity Networking/Demos/DemoHub/Sprites/toHub.png.meta new file mode 100644 index 0000000..38fb46b --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoHub/Sprites/toHub.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: 9587663c4d27e47b19a118aabaac4a08 +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + linearTexture: 0 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -1 + maxTextureSize: 1024 + textureSettings: + filterMode: -1 + aniso: 1 + mipBias: -1 + wrapMode: 1 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 1 + textureType: 8 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/Assets/Photon Unity Networking/Demos/DemoHub/ToHubButton.cs b/Assets/Photon Unity Networking/Demos/DemoHub/ToHubButton.cs new file mode 100644 index 0000000..317c41e --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoHub/ToHubButton.cs @@ -0,0 +1,66 @@ +using UnityEngine; +using UnityEngine.SceneManagement; + +public class ToHubButton : MonoBehaviour +{ + public Texture2D ButtonTexture; + private Rect ButtonRect; + + private static ToHubButton instance; + + public static ToHubButton Instance + { + get + { + if (instance == null) + { + instance = FindObjectOfType(typeof (ToHubButton)) as ToHubButton; + } + + return instance; + } + } + + public void Awake() + { + if (Instance != null && Instance != this) + { + Destroy(gameObject); + } + } + + // Use this for initialization + public void Start() + { + if (this.ButtonTexture == null) + { + gameObject.SetActive(false); + return; + } + DontDestroyOnLoad(gameObject); + } + + public void OnGUI() + { + bool sceneZeroLoaded = false; + + #if UNITY_5 && !UNITY_5_0 && !UNITY_5_1 && !UNITY_5_2 + sceneZeroLoaded = SceneManager.GetActiveScene().buildIndex == 0; + #else + sceneZeroLoaded = Application.loadedLevel == 0; + #endif + + if (!sceneZeroLoaded) + { + int w = this.ButtonTexture.width + 4; + int h = this.ButtonTexture.height + 4; + + this.ButtonRect = new Rect(Screen.width - w, Screen.height - h, w, h); + if (GUI.Button(this.ButtonRect, this.ButtonTexture, GUIStyle.none)) + { + PhotonNetwork.Disconnect(); + SceneManager.LoadScene(0); + } + } + } +} \ No newline at end of file diff --git a/Assets/Photon Unity Networking/Demos/DemoHub/ToHubButton.cs.meta b/Assets/Photon Unity Networking/Demos/DemoHub/ToHubButton.cs.meta new file mode 100644 index 0000000..c2bf55c --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoHub/ToHubButton.cs.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 7fc4721eaa3cf72458d71d8015deca17 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} diff --git a/Assets/Photon Unity Networking/Demos/DemoHub/toHub.png b/Assets/Photon Unity Networking/Demos/DemoHub/toHub.png new file mode 100644 index 0000000..4e76dd3 Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/DemoHub/toHub.png differ diff --git a/Assets/Photon Unity Networking/Demos/DemoHub/toHub.png.meta b/Assets/Photon Unity Networking/Demos/DemoHub/toHub.png.meta new file mode 100644 index 0000000..bc9ea27 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoHub/toHub.png.meta @@ -0,0 +1,33 @@ +fileFormatVersion: 2 +guid: 56d51860189dbec438e8e3fba90c46cc +TextureImporter: + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + linearTexture: 1 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + textureFormat: -1 + maxTextureSize: 1024 + textureSettings: + filterMode: -1 + aniso: 1 + mipBias: -1 + wrapMode: 1 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + textureType: 2 + buildTargetSettings: [] diff --git a/Assets/Photon Unity Networking/Demos/DemoMecanim.meta b/Assets/Photon Unity Networking/Demos/DemoMecanim.meta new file mode 100644 index 0000000..51fbc66 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoMecanim.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 66b2957a66ed44602a83579d1ae2f232 +folderAsset: yes +timeCreated: 1501014811 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Photon Unity Networking/Demos/DemoMecanim/DemoMecanim-Scene.unity b/Assets/Photon Unity Networking/Demos/DemoMecanim/DemoMecanim-Scene.unity new file mode 100644 index 0000000..5eb806b Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/DemoMecanim/DemoMecanim-Scene.unity differ diff --git a/Assets/Photon Unity Networking/Demos/DemoMecanim/DemoMecanim-Scene.unity.meta b/Assets/Photon Unity Networking/Demos/DemoMecanim/DemoMecanim-Scene.unity.meta new file mode 100644 index 0000000..0abb17c --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoMecanim/DemoMecanim-Scene.unity.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: 2fefc96b2a4a31b4092fa7bbea08afaf +DefaultImporter: + userData: diff --git a/Assets/Photon Unity Networking/Demos/DemoMecanim/Resources.meta b/Assets/Photon Unity Networking/Demos/DemoMecanim/Resources.meta new file mode 100644 index 0000000..3e1e876 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoMecanim/Resources.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 94d95350a1a444ce8909c2f9c0f0f079 +folderAsset: yes +timeCreated: 1501014811 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Photon Unity Networking/Demos/DemoMecanim/Resources/Robot Kyle Mecanim.prefab b/Assets/Photon Unity Networking/Demos/DemoMecanim/Resources/Robot Kyle Mecanim.prefab new file mode 100644 index 0000000..ea023a2 Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/DemoMecanim/Resources/Robot Kyle Mecanim.prefab differ diff --git a/Assets/Photon Unity Networking/Demos/DemoMecanim/Resources/Robot Kyle Mecanim.prefab.meta b/Assets/Photon Unity Networking/Demos/DemoMecanim/Resources/Robot Kyle Mecanim.prefab.meta new file mode 100644 index 0000000..47b00f9 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoMecanim/Resources/Robot Kyle Mecanim.prefab.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: bfe5ca06b824b5a45a5ddbe49d40d2ae +NativeFormatImporter: + userData: diff --git a/Assets/Photon Unity Networking/Demos/DemoMecanim/Scripts.meta b/Assets/Photon Unity Networking/Demos/DemoMecanim/Scripts.meta new file mode 100644 index 0000000..55c7e7c --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoMecanim/Scripts.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 322817949dd234a788d57821f0788c37 +folderAsset: yes +timeCreated: 1501014811 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Photon Unity Networking/Demos/DemoMecanim/Scripts/DemoMecanimGUI.cs b/Assets/Photon Unity Networking/Demos/DemoMecanim/Scripts/DemoMecanimGUI.cs new file mode 100644 index 0000000..cbb5e2d --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoMecanim/Scripts/DemoMecanimGUI.cs @@ -0,0 +1,205 @@ +using Photon; +using UnityEngine; +using System.Collections; + +using ExitGames.Client.Photon; + +public class DemoMecanimGUI : PunBehaviour +{ + #region Properties + + public GUISkin Skin; + + #endregion + + + #region Members + + private PhotonAnimatorView m_AnimatorView; // local animatorView. set when we create our character in CreatePlayerObject() + private Animator m_RemoteAnimator; // to display the synchronized values on the right side in the GUI. A third player will simply be ignored (until the second player leaves) + + private float m_SlideIn = 0f; + private float m_FoundPlayerSlideIn = 0f; + private bool m_IsOpen = false; + + #endregion + + + #region Unity + + public void Awake() + { + + } + + public void Update() + { + FindRemoteAnimator(); + + m_SlideIn = Mathf.Lerp( m_SlideIn, m_IsOpen ? 1f : 0f, Time.deltaTime * 9f ); + m_FoundPlayerSlideIn = Mathf.Lerp( m_FoundPlayerSlideIn, m_AnimatorView == null ? 0f : 1f, Time.deltaTime * 5f ); + } + + /// Finds the Animator component of a remote client on a GameObject tagged as Player and sets m_RemoteAnimator. + public void FindRemoteAnimator() + { + if( m_RemoteAnimator != null ) + { + return; + } + + // the prefab has to be tagged as Player + GameObject[] gos = GameObject.FindGameObjectsWithTag( "Player" ); + for( int i = 0; i < gos.Length; ++i ) + { + PhotonView view = gos[ i ].GetComponent(); + if( view != null && view.isMine == false ) + { + m_RemoteAnimator = gos[ i ].GetComponent(); + } + } + } + + public void OnGUI() + { + GUI.skin = Skin; + + string[] synchronizeTypeContent = new string[] { "Disabled", "Discrete", "Continuous" }; + + GUILayout.BeginArea( new Rect( Screen.width - 200 * m_FoundPlayerSlideIn - 400 * m_SlideIn, 0, 600, Screen.height ), GUI.skin.box ); + { + GUILayout.Label( "Mecanim Demo", GUI.skin.customStyles[ 0 ] ); + + GUI.color = Color.white; + string label = "Settings"; + + if( m_IsOpen == true ) + { + label = "Close"; + } + + if( GUILayout.Button( label, GUILayout.Width( 110 ) ) ) + { + m_IsOpen = !m_IsOpen; + } + + string parameters = ""; + + if( m_AnimatorView != null ) + { + parameters += "Send Values:\n"; + + for( int i = 0; i < m_AnimatorView.GetSynchronizedParameters().Count; ++i ) + { + PhotonAnimatorView.SynchronizedParameter parameter = m_AnimatorView.GetSynchronizedParameters()[ i ]; + + try + { + switch( parameter.Type ) + { + case PhotonAnimatorView.ParameterType.Bool: + parameters += parameter.Name + " (" + ( m_AnimatorView.GetComponent().GetBool( parameter.Name ) ? "True" : "False" ) + ")\n"; + break; + case PhotonAnimatorView.ParameterType.Int: + parameters += parameter.Name + " (" + m_AnimatorView.GetComponent().GetInteger( parameter.Name ) + ")\n"; + break; + case PhotonAnimatorView.ParameterType.Float: + parameters += parameter.Name + " (" + m_AnimatorView.GetComponent().GetFloat( parameter.Name ).ToString( "0.00" ) + ")\n"; + break; + } + } + catch + { + Debug.Log( "derrrr for " + parameter.Name ); + } + } + } + + if( m_RemoteAnimator != null ) + { + parameters += "\nReceived Values:\n"; + + for( int i = 0; i < m_AnimatorView.GetSynchronizedParameters().Count; ++i ) + { + PhotonAnimatorView.SynchronizedParameter parameter = m_AnimatorView.GetSynchronizedParameters()[ i ]; + + try + { + switch( parameter.Type ) + { + case PhotonAnimatorView.ParameterType.Bool: + parameters += parameter.Name + " (" + ( m_RemoteAnimator.GetBool( parameter.Name ) ? "True" : "False" ) + ")\n"; + break; + case PhotonAnimatorView.ParameterType.Int: + parameters += parameter.Name + " (" + m_RemoteAnimator.GetInteger( parameter.Name ) + ")\n"; + break; + case PhotonAnimatorView.ParameterType.Float: + parameters += parameter.Name + " (" + m_RemoteAnimator.GetFloat( parameter.Name ).ToString( "0.00" ) + ")\n"; + break; + } + } + catch + { + Debug.Log( "derrrr for " + parameter.Name ); + } + } + } + + GUIStyle style = new GUIStyle( GUI.skin.label ); + style.alignment = TextAnchor.UpperLeft; + + GUI.color = new Color( 1f, 1f, 1f, 1 - m_SlideIn ); + GUI.Label( new Rect( 10, 100, 600, Screen.height ), parameters, style ); + + if( m_AnimatorView != null ) + { + GUI.color = new Color( 1f, 1f, 1f, m_SlideIn ); + + GUILayout.Space( 20 ); + GUILayout.Label( "Synchronize Parameters" ); + + for( int i = 0; i < m_AnimatorView.GetSynchronizedParameters().Count; ++i ) + { + GUILayout.BeginHorizontal(); + { + PhotonAnimatorView.SynchronizedParameter parameter = m_AnimatorView.GetSynchronizedParameters()[ i ]; + + GUILayout.Label( parameter.Name, GUILayout.Width( 100 ), GUILayout.Height( 36 ) ); + + int selectedValue = (int)parameter.SynchronizeType; + int newValue = GUILayout.Toolbar( selectedValue, synchronizeTypeContent ); + + if( newValue != selectedValue ) + { + m_AnimatorView.SetParameterSynchronized( parameter.Name, parameter.Type, (PhotonAnimatorView.SynchronizeType)newValue ); + } + } + GUILayout.EndHorizontal(); + } + } + } + GUILayout.EndArea(); + } + + #endregion + + + #region Photon + + public override void OnJoinedRoom() + { + CreatePlayerObject(); + } + + private void CreatePlayerObject() + { + Vector3 position = new Vector3( -2, 0, 0 ); + position.x += Random.Range( -3f, 3f ); + position.z += Random.Range( -4f, 4f ); + + GameObject newPlayerObject = PhotonNetwork.Instantiate( "Robot Kyle Mecanim", position, Quaternion.identity, 0 ); + m_AnimatorView = newPlayerObject.GetComponent(); + } + + #endregion +} diff --git a/Assets/Photon Unity Networking/Demos/DemoMecanim/Scripts/DemoMecanimGUI.cs.meta b/Assets/Photon Unity Networking/Demos/DemoMecanim/Scripts/DemoMecanimGUI.cs.meta new file mode 100644 index 0000000..6b579bb --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoMecanim/Scripts/DemoMecanimGUI.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: e7b768dd0afabfb4a819f6f2b6abb262 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Photon Unity Networking/Demos/DemoPickup.meta b/Assets/Photon Unity Networking/Demos/DemoPickup.meta new file mode 100644 index 0000000..c0d6430 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoPickup.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 2ef638dd040c94f3a9567ae57f8d3b9e +folderAsset: yes +timeCreated: 1501014811 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Photon Unity Networking/Demos/DemoPickup/Assets.meta b/Assets/Photon Unity Networking/Demos/DemoPickup/Assets.meta new file mode 100644 index 0000000..1543a91 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoPickup/Assets.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 34f85b73781564244a502a2ec798d89e +folderAsset: yes +timeCreated: 1501014811 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Photon Unity Networking/Demos/DemoPickup/Assets/Materials.meta b/Assets/Photon Unity Networking/Demos/DemoPickup/Assets/Materials.meta new file mode 100644 index 0000000..6e836c8 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoPickup/Assets/Materials.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 5e8b22de87a7a4a6f862d0daf727edf8 +folderAsset: yes +timeCreated: 1501014812 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Photon Unity Networking/Demos/DemoPickup/Assets/Materials/CharMat.mat b/Assets/Photon Unity Networking/Demos/DemoPickup/Assets/Materials/CharMat.mat new file mode 100644 index 0000000..c62ec02 Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/DemoPickup/Assets/Materials/CharMat.mat differ diff --git a/Assets/Photon Unity Networking/Demos/DemoPickup/Assets/Materials/CharMat.mat.meta b/Assets/Photon Unity Networking/Demos/DemoPickup/Assets/Materials/CharMat.mat.meta new file mode 100644 index 0000000..49ac562 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoPickup/Assets/Materials/CharMat.mat.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 41f984acc95ee444787756c8fe13520f diff --git a/Assets/Photon Unity Networking/Demos/DemoPickup/Assets/Materials/DarkOverlay.mat b/Assets/Photon Unity Networking/Demos/DemoPickup/Assets/Materials/DarkOverlay.mat new file mode 100644 index 0000000..f6f22bb Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/DemoPickup/Assets/Materials/DarkOverlay.mat differ diff --git a/Assets/Photon Unity Networking/Demos/DemoPickup/Assets/Materials/DarkOverlay.mat.meta b/Assets/Photon Unity Networking/Demos/DemoPickup/Assets/Materials/DarkOverlay.mat.meta new file mode 100644 index 0000000..3424587 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoPickup/Assets/Materials/DarkOverlay.mat.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 0e64e67439050b24f992cb6e55e2ab68 diff --git a/Assets/Photon Unity Networking/Demos/DemoPickup/Assets/Materials/PickItem-Green.mat b/Assets/Photon Unity Networking/Demos/DemoPickup/Assets/Materials/PickItem-Green.mat new file mode 100644 index 0000000..7dc3706 Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/DemoPickup/Assets/Materials/PickItem-Green.mat differ diff --git a/Assets/Photon Unity Networking/Demos/DemoPickup/Assets/Materials/PickItem-Green.mat.meta b/Assets/Photon Unity Networking/Demos/DemoPickup/Assets/Materials/PickItem-Green.mat.meta new file mode 100644 index 0000000..c5ace22 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoPickup/Assets/Materials/PickItem-Green.mat.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 8d034628a1766f64bb892b8e4aea38ae diff --git a/Assets/Photon Unity Networking/Demos/DemoPickup/Assets/Materials/PickItem-Yellow.mat b/Assets/Photon Unity Networking/Demos/DemoPickup/Assets/Materials/PickItem-Yellow.mat new file mode 100644 index 0000000..53df0f9 Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/DemoPickup/Assets/Materials/PickItem-Yellow.mat differ diff --git a/Assets/Photon Unity Networking/Demos/DemoPickup/Assets/Materials/PickItem-Yellow.mat.meta b/Assets/Photon Unity Networking/Demos/DemoPickup/Assets/Materials/PickItem-Yellow.mat.meta new file mode 100644 index 0000000..8597149 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoPickup/Assets/Materials/PickItem-Yellow.mat.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 96c1e8103cb08074786e86c7dfc04f64 diff --git a/Assets/Photon Unity Networking/Demos/DemoPickup/Assets/Materials/PickLightMat.mat b/Assets/Photon Unity Networking/Demos/DemoPickup/Assets/Materials/PickLightMat.mat new file mode 100644 index 0000000..b004d70 Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/DemoPickup/Assets/Materials/PickLightMat.mat differ diff --git a/Assets/Photon Unity Networking/Demos/DemoPickup/Assets/Materials/PickLightMat.mat.meta b/Assets/Photon Unity Networking/Demos/DemoPickup/Assets/Materials/PickLightMat.mat.meta new file mode 100644 index 0000000..cba190f --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoPickup/Assets/Materials/PickLightMat.mat.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: b205376bcefa990488ef4615853255dd diff --git a/Assets/Photon Unity Networking/Demos/DemoPickup/Assets/Materials/PickTiledMat.mat b/Assets/Photon Unity Networking/Demos/DemoPickup/Assets/Materials/PickTiledMat.mat new file mode 100644 index 0000000..f1e71af Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/DemoPickup/Assets/Materials/PickTiledMat.mat differ diff --git a/Assets/Photon Unity Networking/Demos/DemoPickup/Assets/Materials/PickTiledMat.mat.meta b/Assets/Photon Unity Networking/Demos/DemoPickup/Assets/Materials/PickTiledMat.mat.meta new file mode 100644 index 0000000..791b5c2 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoPickup/Assets/Materials/PickTiledMat.mat.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 46ba1b9034891a845896863e11b0e97d diff --git a/Assets/Photon Unity Networking/Demos/DemoPickup/Assets/Materials/TeamPickBlueMat.mat b/Assets/Photon Unity Networking/Demos/DemoPickup/Assets/Materials/TeamPickBlueMat.mat new file mode 100644 index 0000000..b07dba4 Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/DemoPickup/Assets/Materials/TeamPickBlueMat.mat differ diff --git a/Assets/Photon Unity Networking/Demos/DemoPickup/Assets/Materials/TeamPickBlueMat.mat.meta b/Assets/Photon Unity Networking/Demos/DemoPickup/Assets/Materials/TeamPickBlueMat.mat.meta new file mode 100644 index 0000000..44be4e8 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoPickup/Assets/Materials/TeamPickBlueMat.mat.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 752a308575c9ae542b83f27c5a7746fe diff --git a/Assets/Photon Unity Networking/Demos/DemoPickup/Assets/Materials/TeamPickRedMat.mat b/Assets/Photon Unity Networking/Demos/DemoPickup/Assets/Materials/TeamPickRedMat.mat new file mode 100644 index 0000000..0c30409 Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/DemoPickup/Assets/Materials/TeamPickRedMat.mat differ diff --git a/Assets/Photon Unity Networking/Demos/DemoPickup/Assets/Materials/TeamPickRedMat.mat.meta b/Assets/Photon Unity Networking/Demos/DemoPickup/Assets/Materials/TeamPickRedMat.mat.meta new file mode 100644 index 0000000..7bb5637 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoPickup/Assets/Materials/TeamPickRedMat.mat.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: c7cf1bb431b424a468eb880c591a6177 diff --git a/Assets/Photon Unity Networking/Demos/DemoPickup/Assets/PickCharTexture.png b/Assets/Photon Unity Networking/Demos/DemoPickup/Assets/PickCharTexture.png new file mode 100644 index 0000000..00504cd Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/DemoPickup/Assets/PickCharTexture.png differ diff --git a/Assets/Photon Unity Networking/Demos/DemoPickup/Assets/PickCharTexture.png.meta b/Assets/Photon Unity Networking/Demos/DemoPickup/Assets/PickCharTexture.png.meta new file mode 100644 index 0000000..be9866b --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoPickup/Assets/PickCharTexture.png.meta @@ -0,0 +1,33 @@ +fileFormatVersion: 2 +guid: 50ddac281b22b4d439fed8088ba83950 +TextureImporter: + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + linearTexture: 0 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + textureFormat: -1 + maxTextureSize: 1024 + textureSettings: + filterMode: 0 + aniso: -1 + mipBias: -1 + wrapMode: -1 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + textureType: -1 + buildTargetSettings: [] diff --git a/Assets/Photon Unity Networking/Demos/DemoPickup/Assets/PickTexture.png b/Assets/Photon Unity Networking/Demos/DemoPickup/Assets/PickTexture.png new file mode 100644 index 0000000..d25adcb Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/DemoPickup/Assets/PickTexture.png differ diff --git a/Assets/Photon Unity Networking/Demos/DemoPickup/Assets/PickTexture.png.meta b/Assets/Photon Unity Networking/Demos/DemoPickup/Assets/PickTexture.png.meta new file mode 100644 index 0000000..9ea858a --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoPickup/Assets/PickTexture.png.meta @@ -0,0 +1,33 @@ +fileFormatVersion: 2 +guid: e65a2a70e34593c4cb2840252eb958be +TextureImporter: + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + linearTexture: 0 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + textureFormat: -1 + maxTextureSize: 512 + textureSettings: + filterMode: 2 + aniso: 5 + mipBias: -1 + wrapMode: 0 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + textureType: 0 + buildTargetSettings: [] diff --git a/Assets/Photon Unity Networking/Demos/DemoPickup/Assets/pick-idle.anim b/Assets/Photon Unity Networking/Demos/DemoPickup/Assets/pick-idle.anim new file mode 100644 index 0000000..f4c9383 Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/DemoPickup/Assets/pick-idle.anim differ diff --git a/Assets/Photon Unity Networking/Demos/DemoPickup/Assets/pick-idle.anim.meta b/Assets/Photon Unity Networking/Demos/DemoPickup/Assets/pick-idle.anim.meta new file mode 100644 index 0000000..2275754 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoPickup/Assets/pick-idle.anim.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 3134f209b47fdec49a880b887fc7ab39 diff --git a/Assets/Photon Unity Networking/Demos/DemoPickup/Assets/pick-run3.anim b/Assets/Photon Unity Networking/Demos/DemoPickup/Assets/pick-run3.anim new file mode 100644 index 0000000..d5a99b7 Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/DemoPickup/Assets/pick-run3.anim differ diff --git a/Assets/Photon Unity Networking/Demos/DemoPickup/Assets/pick-run3.anim.meta b/Assets/Photon Unity Networking/Demos/DemoPickup/Assets/pick-run3.anim.meta new file mode 100644 index 0000000..ea8da78 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoPickup/Assets/pick-run3.anim.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 99f1e72a5ed8fb04f865c759fcb1a0ea diff --git a/Assets/Photon Unity Networking/Demos/DemoPickup/Assets/pick-walk.anim b/Assets/Photon Unity Networking/Demos/DemoPickup/Assets/pick-walk.anim new file mode 100644 index 0000000..4f1d75f Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/DemoPickup/Assets/pick-walk.anim differ diff --git a/Assets/Photon Unity Networking/Demos/DemoPickup/Assets/pick-walk.anim.meta b/Assets/Photon Unity Networking/Demos/DemoPickup/Assets/pick-walk.anim.meta new file mode 100644 index 0000000..d9ed469 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoPickup/Assets/pick-walk.anim.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 60f84450dfd95594583f64e03886caca diff --git a/Assets/Photon Unity Networking/Demos/DemoPickup/Assets/quad-mesh.obj b/Assets/Photon Unity Networking/Demos/DemoPickup/Assets/quad-mesh.obj new file mode 100644 index 0000000..7889aaf --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoPickup/Assets/quad-mesh.obj @@ -0,0 +1,17 @@ +mtllib quad-mesh.mtl +o quad-mesh.obj +v -0.500000 0.000000 -0.500000 +v 0.500000 0.000000 -0.500000 +v -0.500000 0.000000 0.500000 +v 0.500000 0.000000 0.500000 +vn 0.000000 1.000000 0.000000 +vn 0.000000 1.000000 0.000000 +vn 0.000000 1.000000 0.000000 +vn 0.000000 1.000000 0.000000 +vt 0.004950 0.004950 +vt 0.995049 0.004950 +vt 0.995049 0.995049 +vt 0.004950 0.995049 +g Quad +usemtl Default +f 3/1/3 4/2/4 2/3/2 1/4/1 diff --git a/Assets/Photon Unity Networking/Demos/DemoPickup/Assets/quad-mesh.obj.meta b/Assets/Photon Unity Networking/Demos/DemoPickup/Assets/quad-mesh.obj.meta new file mode 100644 index 0000000..a93f053 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoPickup/Assets/quad-mesh.obj.meta @@ -0,0 +1,62 @@ +fileFormatVersion: 2 +guid: 50e49398ae6a71246b696fbc151d11f7 +ModelImporter: + fileIDToRecycleName: + 4300000: Quad + serializedVersion: 10 + materials: + importMaterials: 0 + materialName: 0 + materialSearch: 1 + animations: + generateAnimations: 0 + bakeSimulation: 0 + splitAnimations: 1 + animationCompression: 1 + animationRotationError: .5 + animationPositionError: .5 + animationScaleError: .5 + animationWrapMode: 0 + clipAnimations: [] + meshes: + lODScreenPercentages: [] + globalScale: 1 + meshCompression: 0 + addColliders: 1 + swapUVChannels: 0 + generateSecondaryUV: 0 + useFileUnits: 1 + optimizeMesh: 0 + secondaryUVAngleDistortion: 8 + secondaryUVAreaDistortion: 15.000001 + secondaryUVHardAngle: 88 + secondaryUVPackMargin: 4 + tangentSpace: + normalSmoothAngle: 60 + splitTangentsAcrossUV: 1 + normalImportMode: 0 + tangentImportMode: 1 + textMetaNamesToFileIDs: + //RootNode: + data: + first: 1 + second: a2860100 + data: + first: 4 + second: 821a0600 + Quad: + data: + first: 1 + second: a0860100 + data: + first: 4 + second: 801a0600 + data: + first: 23 + second: 60182300 + data: + first: 33 + second: a05a3200 + data: + first: 64 + second: 00a86100 diff --git a/Assets/Photon Unity Networking/Demos/DemoPickup/DemoPickup-Scene.unity b/Assets/Photon Unity Networking/Demos/DemoPickup/DemoPickup-Scene.unity new file mode 100644 index 0000000..85a8515 Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/DemoPickup/DemoPickup-Scene.unity differ diff --git a/Assets/Photon Unity Networking/Demos/DemoPickup/DemoPickup-Scene.unity.meta b/Assets/Photon Unity Networking/Demos/DemoPickup/DemoPickup-Scene.unity.meta new file mode 100644 index 0000000..c260480 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoPickup/DemoPickup-Scene.unity.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 42026d6c332a6b5438ed37ef7af9fba8 diff --git a/Assets/Photon Unity Networking/Demos/DemoPickup/Resources.meta b/Assets/Photon Unity Networking/Demos/DemoPickup/Resources.meta new file mode 100644 index 0000000..782e1bd --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoPickup/Resources.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 4713a21ede58140c49ef464cc9f30f90 +folderAsset: yes +timeCreated: 1501014811 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Photon Unity Networking/Demos/DemoPickup/Resources/PickupCharacter.prefab b/Assets/Photon Unity Networking/Demos/DemoPickup/Resources/PickupCharacter.prefab new file mode 100644 index 0000000..7a50761 Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/DemoPickup/Resources/PickupCharacter.prefab differ diff --git a/Assets/Photon Unity Networking/Demos/DemoPickup/Resources/PickupCharacter.prefab.meta b/Assets/Photon Unity Networking/Demos/DemoPickup/Resources/PickupCharacter.prefab.meta new file mode 100644 index 0000000..a7258f6 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoPickup/Resources/PickupCharacter.prefab.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 1f109488cb155864c839538b4a5d2133 diff --git a/Assets/Photon Unity Networking/Demos/DemoPickup/Scripts.meta b/Assets/Photon Unity Networking/Demos/DemoPickup/Scripts.meta new file mode 100644 index 0000000..718ebff --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoPickup/Scripts.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 8abe2262efb9445b8a5bf608b01882fa +folderAsset: yes +timeCreated: 1501014811 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Photon Unity Networking/Demos/DemoPickup/Scripts/MessageOverlay.cs b/Assets/Photon Unity Networking/Demos/DemoPickup/Scripts/MessageOverlay.cs new file mode 100644 index 0000000..26c3931 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoPickup/Scripts/MessageOverlay.cs @@ -0,0 +1,34 @@ +using UnityEngine; +using System.Collections; + +public class MessageOverlay : MonoBehaviour +{ + public GameObject[] Objects; + + public void Start() + { + SetActive(true); + } + + public void OnJoinedRoom() + { + SetActive(false); + } + + public void OnLeftRoom() + { + SetActive(true); + } + + void SetActive(bool enable) + { + foreach (GameObject o in Objects) + { + #if UNITY_3_5 + o.SetActiveRecursively(enable); + #else + o.SetActive(enable); + #endif + } + } +} diff --git a/Assets/Photon Unity Networking/Demos/DemoPickup/Scripts/MessageOverlay.cs.meta b/Assets/Photon Unity Networking/Demos/DemoPickup/Scripts/MessageOverlay.cs.meta new file mode 100644 index 0000000..f48e11f --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoPickup/Scripts/MessageOverlay.cs.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 81a213c68ddce5a42a2219277a76da09 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} diff --git a/Assets/Photon Unity Networking/Demos/DemoPickup/Scripts/OnCollideSwitchTeam.cs b/Assets/Photon Unity Networking/Demos/DemoPickup/Scripts/OnCollideSwitchTeam.cs new file mode 100644 index 0000000..b5a8b0b --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoPickup/Scripts/OnCollideSwitchTeam.cs @@ -0,0 +1,21 @@ +using UnityEngine; +using System.Collections; + +[RequireComponent(typeof(Collider))] +public class OnCollideSwitchTeam : MonoBehaviour +{ + public PunTeams.Team TeamToSwitchTo; + + public void OnTriggerEnter(Collider other) + { + // it's ridiculously easy to switch teams. you only have to make sure you do it for your own characters + // (this trigger is called on all clients, when a user's character enters the trigger...) + + // find a PhotonView and check if the character "isMine". Only then, set this client's player-team. + PhotonView otherPv = other.GetComponent(); + if (otherPv != null && otherPv.isMine) + { + PhotonNetwork.player.SetTeam(this.TeamToSwitchTo); + } + } +} diff --git a/Assets/Photon Unity Networking/Demos/DemoPickup/Scripts/OnCollideSwitchTeam.cs.meta b/Assets/Photon Unity Networking/Demos/DemoPickup/Scripts/OnCollideSwitchTeam.cs.meta new file mode 100644 index 0000000..a839ba3 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoPickup/Scripts/OnCollideSwitchTeam.cs.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: ed2bfd83928fad74da17bd2ca5b0f5f8 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} diff --git a/Assets/Photon Unity Networking/Demos/DemoPickup/Scripts/OnPickedUpScript.cs b/Assets/Photon Unity Networking/Demos/DemoPickup/Scripts/OnPickedUpScript.cs new file mode 100644 index 0000000..db9343a --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoPickup/Scripts/OnPickedUpScript.cs @@ -0,0 +1,18 @@ +using UnityEngine; +using System.Collections; + +public class OnPickedUpScript : MonoBehaviour { + + public void OnPickedUp(PickupItem item) + { + if (item.PickupIsMine) + { + Debug.Log("I picked up something. That's a score!"); + PhotonNetwork.player.AddScore(1); + } + else + { + Debug.Log("Someone else picked up something. Lucky!"); + } + } +} \ No newline at end of file diff --git a/Assets/Photon Unity Networking/Demos/DemoPickup/Scripts/OnPickedUpScript.cs.meta b/Assets/Photon Unity Networking/Demos/DemoPickup/Scripts/OnPickedUpScript.cs.meta new file mode 100644 index 0000000..c9d5db9 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoPickup/Scripts/OnPickedUpScript.cs.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: cd354f1d6db2546479ec3e80718a0556 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} diff --git a/Assets/Photon Unity Networking/Demos/DemoPickup/Scripts/PickupCamera.cs b/Assets/Photon Unity Networking/Demos/DemoPickup/Scripts/PickupCamera.cs new file mode 100644 index 0000000..1fe2a22 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoPickup/Scripts/PickupCamera.cs @@ -0,0 +1,248 @@ +using UnityEngine; +using System.Collections; + +public class PickupCamera : Photon.MonoBehaviour +{ + + public Transform cameraTransform; + private Transform _target; + + // The distance in the x-z plane to the target + + public float distance = 7.0f; + + // the height we want the camera to be above the target + public float height = 3.0f; + + public float angularSmoothLag = 0.3f; + public float angularMaxSpeed = 15.0f; + + public float heightSmoothLag = 0.3f; + + public float snapSmoothLag = 0.2f; + public float snapMaxSpeed = 720.0f; + + public float clampHeadPositionScreenSpace = 0.75f; + + public float lockCameraTimeout = 0.2f; + + private Vector3 headOffset = Vector3.zero; + private Vector3 centerOffset = Vector3.zero; + + private float heightVelocity = 0.0f; + private float angleVelocity = 0.0f; + private bool snap = false; + private PickupController controller; + private float targetHeight = 100000.0f; + + private Camera m_CameraTransformCamera; + + void OnEnable() + { + if( this.photonView != null && !this.photonView.isMine ) + { + this.enabled = false; + return; + } + + if( !cameraTransform && Camera.main ) + cameraTransform = Camera.main.transform; + if( !cameraTransform ) + { + Debug.Log( "Please assign a camera to the ThirdPersonCamera script." ); + enabled = false; + } + + m_CameraTransformCamera = cameraTransform.GetComponent(); + + + _target = transform; + if( _target ) + { + controller = _target.GetComponent(); + } + + if( controller ) + { + CharacterController characterController = (CharacterController)_target.GetComponent(); + centerOffset = characterController.bounds.center - _target.position; + headOffset = centerOffset; + headOffset.y = characterController.bounds.max.y - _target.position.y; + } + else + Debug.Log( "Please assign a target to the camera that has a ThirdPersonController script attached." ); + + + Cut( _target, centerOffset ); + } + + void DebugDrawStuff() + { + Debug.DrawLine( _target.position, _target.position + headOffset ); + + } + + float AngleDistance( float a, float b ) + { + a = Mathf.Repeat( a, 360 ); + b = Mathf.Repeat( b, 360 ); + + return Mathf.Abs( b - a ); + } + + void Apply( Transform dummyTarget, Vector3 dummyCenter ) + { + // Early out if we don't have a target + if( !controller ) + return; + + Vector3 targetCenter = _target.position + centerOffset; + Vector3 targetHead = _target.position + headOffset; + + // DebugDrawStuff(); + + // Calculate the current & target rotation angles + float originalTargetAngle = _target.eulerAngles.y; + float currentAngle = cameraTransform.eulerAngles.y; + + // Adjust real target angle when camera is locked + float targetAngle = originalTargetAngle; + + // When pressing Fire2 (alt) the camera will snap to the target direction real quick. + // It will stop snapping when it reaches the target + if( Input.GetButton( "Fire2" ) ) + snap = true; + + if( snap ) + { + // We are close to the target, so we can stop snapping now! + if( AngleDistance( currentAngle, originalTargetAngle ) < 3.0f ) + snap = false; + + currentAngle = Mathf.SmoothDampAngle( currentAngle, targetAngle, ref angleVelocity, snapSmoothLag, snapMaxSpeed ); + } + // Normal camera motion + else + { + if( controller.GetLockCameraTimer() < lockCameraTimeout ) + { + targetAngle = currentAngle; + } + + // Lock the camera when moving backwards! + // * It is really confusing to do 180 degree spins when turning around. + if( AngleDistance( currentAngle, targetAngle ) > 160 && controller.IsMovingBackwards() ) + targetAngle += 180; + + currentAngle = Mathf.SmoothDampAngle( currentAngle, targetAngle, ref angleVelocity, angularSmoothLag, angularMaxSpeed ); + } + + + // When jumping don't move camera upwards but only down! + if( controller.IsJumping() ) + { + // We'd be moving the camera upwards, do that only if it's really high + float newTargetHeight = targetCenter.y + height; + if( newTargetHeight < targetHeight || newTargetHeight - targetHeight > 5 ) + targetHeight = targetCenter.y + height; + } + // When walking always update the target height + else + { + targetHeight = targetCenter.y + height; + } + + // Damp the height + float currentHeight = cameraTransform.position.y; + currentHeight = Mathf.SmoothDamp( currentHeight, targetHeight, ref heightVelocity, heightSmoothLag ); + + // Convert the angle into a rotation, by which we then reposition the camera + Quaternion currentRotation = Quaternion.Euler( 0, currentAngle, 0 ); + + // Set the position of the camera on the x-z plane to: + // distance meters behind the target + cameraTransform.position = targetCenter; + cameraTransform.position += currentRotation * Vector3.back * distance; + + // Set the height of the camera + cameraTransform.position = new Vector3( cameraTransform.position.x, currentHeight, cameraTransform.position.z ); + + // Always look at the target + SetUpRotation( targetCenter, targetHead ); + } + + void LateUpdate() + { + Apply( transform, Vector3.zero ); + } + + void Cut( Transform dummyTarget, Vector3 dummyCenter ) + { + float oldHeightSmooth = heightSmoothLag; + float oldSnapMaxSpeed = snapMaxSpeed; + float oldSnapSmooth = snapSmoothLag; + + snapMaxSpeed = 10000; + snapSmoothLag = 0.001f; + heightSmoothLag = 0.001f; + + snap = true; + Apply( transform, Vector3.zero ); + + heightSmoothLag = oldHeightSmooth; + snapMaxSpeed = oldSnapMaxSpeed; + snapSmoothLag = oldSnapSmooth; + } + + void SetUpRotation( Vector3 centerPos, Vector3 headPos ) + { + // Now it's getting hairy. The devil is in the details here, the big issue is jumping of course. + // * When jumping up and down we don't want to center the guy in screen space. + // This is important to give a feel for how high you jump and avoiding large camera movements. + // + // * At the same time we dont want him to ever go out of screen and we want all rotations to be totally smooth. + // + // So here is what we will do: + // + // 1. We first find the rotation around the y axis. Thus he is always centered on the y-axis + // 2. When grounded we make him be centered + // 3. When jumping we keep the camera rotation but rotate the camera to get him back into view if his head is above some threshold + // 4. When landing we smoothly interpolate towards centering him on screen + Vector3 cameraPos = cameraTransform.position; + Vector3 offsetToCenter = centerPos - cameraPos; + + // Generate base rotation only around y-axis + Quaternion yRotation = Quaternion.LookRotation( new Vector3( offsetToCenter.x, 0, offsetToCenter.z ) ); + + Vector3 relativeOffset = Vector3.forward * distance + Vector3.down * height; + cameraTransform.rotation = yRotation * Quaternion.LookRotation( relativeOffset ); + + // Calculate the projected center position and top position in world space + Ray centerRay = m_CameraTransformCamera.ViewportPointToRay( new Vector3( 0.5f, 0.5f, 1 ) ); + Ray topRay = m_CameraTransformCamera.ViewportPointToRay( new Vector3( 0.5f, clampHeadPositionScreenSpace, 1 ) ); + + Vector3 centerRayPos = centerRay.GetPoint( distance ); + Vector3 topRayPos = topRay.GetPoint( distance ); + + float centerToTopAngle = Vector3.Angle( centerRay.direction, topRay.direction ); + + float heightToAngle = centerToTopAngle / ( centerRayPos.y - topRayPos.y ); + + float extraLookAngle = heightToAngle * ( centerRayPos.y - centerPos.y ); + if( extraLookAngle < centerToTopAngle ) + { + extraLookAngle = 0; + } + else + { + extraLookAngle = extraLookAngle - centerToTopAngle; + cameraTransform.rotation *= Quaternion.Euler( -extraLookAngle, 0, 0 ); + } + } + + Vector3 GetCenterOffset() + { + return centerOffset; + } + +} \ No newline at end of file diff --git a/Assets/Photon Unity Networking/Demos/DemoPickup/Scripts/PickupCamera.cs.meta b/Assets/Photon Unity Networking/Demos/DemoPickup/Scripts/PickupCamera.cs.meta new file mode 100644 index 0000000..72b4181 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoPickup/Scripts/PickupCamera.cs.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 1ca68f3c4e62e7840b32f2a9564be4be +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} diff --git a/Assets/Photon Unity Networking/Demos/DemoPickup/Scripts/PickupController.cs b/Assets/Photon Unity Networking/Demos/DemoPickup/Scripts/PickupController.cs new file mode 100644 index 0000000..691a1a6 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoPickup/Scripts/PickupController.cs @@ -0,0 +1,529 @@ +using UnityEngine; +using System.Collections; + +public enum PickupCharacterState +{ + Idle = 0, + Walking = 1, + Trotting = 2, + Running = 3, + Jumping = 4, +} + +[RequireComponent(typeof(CharacterController))] +public class PickupController : MonoBehaviour, IPunObservable +{ + + public AnimationClip idleAnimation; + public AnimationClip walkAnimation; + public AnimationClip runAnimation; + public AnimationClip jumpPoseAnimation; + + public float walkMaxAnimationSpeed = 0.75f; + public float trotMaxAnimationSpeed = 1.0f; + public float runMaxAnimationSpeed = 1.0f; + public float jumpAnimationSpeed = 1.15f; + public float landAnimationSpeed = 1.0f; + + private Animation _animation; + + + + public PickupCharacterState _characterState; + + // The speed when walking + public float walkSpeed = 2.0f; + // after trotAfterSeconds of walking we trot with trotSpeed + public float trotSpeed = 4.0f; + // when pressing "Fire3" button (cmd) we start running + public float runSpeed = 6.0f; + + public float inAirControlAcceleration = 3.0f; + + // How high do we jump when pressing jump and letting go immediately + public float jumpHeight = 0.5f; + + // The gravity for the character + public float gravity = 20.0f; + // The gravity in controlled descent mode + public float speedSmoothing = 10.0f; + public float rotateSpeed = 500.0f; + public float trotAfterSeconds = 3.0f; + + public bool canJump = false; + + private float jumpRepeatTime = 0.05f; + private float jumpTimeout = 0.15f; + private float groundedTimeout = 0.25f; + + // The camera doesnt start following the target immediately but waits for a split second to avoid too much waving around. + private float lockCameraTimer = 0.0f; + + // The current move direction in x-z + private Vector3 moveDirection = Vector3.zero; + // The current vertical speed + private float verticalSpeed = 0.0f; + // The current x-z move speed + private float moveSpeed = 0.0f; + + // The last collision flags returned from controller.Move + private CollisionFlags collisionFlags; + + // Are we jumping? (Initiated with jump button and not grounded yet) + private bool jumping = false; + private bool jumpingReachedApex = false; + + // Are we moving backwards (This locks the camera to not do a 180 degree spin) + private bool movingBack = false; + // Is the user pressing any keys? + private bool isMoving = false; + // When did the user start walking (Used for going into trot after a while) + private float walkTimeStart = 0.0f; + // Last time the jump button was clicked down + private float lastJumpButtonTime = -10.0f; + // Last time we performed a jump + private float lastJumpTime = -1.0f; + // the height we jumped from (Used to determine for how long to apply extra jump power after jumping.) + //private float lastJumpStartHeight = 0.0f; + private Vector3 inAirVelocity = Vector3.zero; + + private float lastGroundedTime = 0.0f; + Vector3 velocity = Vector3.zero; + private Vector3 lastPos; + private Vector3 remotePosition; + + public bool isControllable = false; + public bool DoRotate = true; + public float RemoteSmoothing = 5; + public bool AssignAsTagObject = true; + + void Awake() + { + // PUN: automatically determine isControllable, if this GO has a PhotonView + PhotonView pv = gameObject.GetComponent(); + if (pv != null) + { + this.isControllable = pv.isMine; + + // The pickup demo assigns this GameObject as the PhotonPlayer.TagObject. This way, we can access this character (controller, position, etc) easily + if (this.AssignAsTagObject) + { + pv.owner.TagObject = gameObject; + } + + // please note: we change this setting on ANY PickupController if "DoRotate" is off. not only locally when it's "our" GameObject! + if (!this.DoRotate && pv.ObservedComponents != null) + { + for (int i = 0; i < pv.ObservedComponents.Count; ++i) + { + if (pv.ObservedComponents[i] is Transform) + { + pv.onSerializeTransformOption = OnSerializeTransform.OnlyPosition; + break; + } + } + } + } + + + this.moveDirection = transform.TransformDirection(Vector3.forward); + + this._animation = GetComponent(); + if (!this._animation) + Debug.Log("The character you would like to control doesn't have animations. Moving her might look weird."); + + if (!this.idleAnimation) + { + this._animation = null; + Debug.Log("No idle animation found. Turning off animations."); + } + if (!this.walkAnimation) + { + this._animation = null; + Debug.Log("No walk animation found. Turning off animations."); + } + if (!this.runAnimation) + { + this._animation = null; + Debug.Log("No run animation found. Turning off animations."); + } + if (!this.jumpPoseAnimation && this.canJump) + { + this._animation = null; + Debug.Log("No jump animation found and the character has canJump enabled. Turning off animations."); + } + } + + void Update() + { + if (this.isControllable) + { + if (Input.GetButtonDown("Jump")) + { + this.lastJumpButtonTime = Time.time; + } + + this.UpdateSmoothedMovementDirection(); + + // Apply gravity + // - extra power jump modifies gravity + // - controlledDescent mode modifies gravity + this.ApplyGravity(); + + // Apply jumping logic + this.ApplyJumping(); + + + // Calculate actual motion + Vector3 movement = this.moveDirection *this.moveSpeed + new Vector3(0, this.verticalSpeed, 0) + this.inAirVelocity; + movement *= Time.deltaTime; + + //Debug.Log(movement.x.ToString("0.000") + ":" + movement.z.ToString("0.000")); + + // Move the controller + CharacterController controller = GetComponent(); + this.collisionFlags = controller.Move(movement); + + } + + // PUN: if a remote position is known, we smooth-move to it (being late(r) but smoother) + if (this.remotePosition != Vector3.zero) + { + transform.position = Vector3.Lerp(transform.position, this.remotePosition, Time.deltaTime * this.RemoteSmoothing); + } + + this.velocity = (transform.position - this.lastPos)*25; + + // ANIMATION sector + if (this._animation) + { + if (this._characterState == PickupCharacterState.Jumping) + { + if (!this.jumpingReachedApex) + { + this._animation[this.jumpPoseAnimation.name].speed = this.jumpAnimationSpeed; + this._animation[this.jumpPoseAnimation.name].wrapMode = WrapMode.ClampForever; + this._animation.CrossFade(this.jumpPoseAnimation.name); + } + else + { + this._animation[this.jumpPoseAnimation.name].speed = -this.landAnimationSpeed; + this._animation[this.jumpPoseAnimation.name].wrapMode = WrapMode.ClampForever; + this._animation.CrossFade(this.jumpPoseAnimation.name); + } + } + else + { + if (this._characterState == PickupCharacterState.Idle) + { + this._animation.CrossFade(this.idleAnimation.name); + } + else if (this._characterState == PickupCharacterState.Running) + { + this._animation[this.runAnimation.name].speed = this.runMaxAnimationSpeed; + if (this.isControllable) + { + this._animation[this.runAnimation.name].speed = Mathf.Clamp(this.velocity.magnitude, 0.0f, this.runMaxAnimationSpeed); + } + this._animation.CrossFade(this.runAnimation.name); + } + else if (this._characterState == PickupCharacterState.Trotting) + { + this._animation[this.walkAnimation.name].speed = this.trotMaxAnimationSpeed; + if (this.isControllable) + { + this._animation[this.walkAnimation.name].speed = Mathf.Clamp(this.velocity.magnitude, 0.0f, this.trotMaxAnimationSpeed); + } + this._animation.CrossFade(this.walkAnimation.name); + } + else if (this._characterState == PickupCharacterState.Walking) + { + this._animation[this.walkAnimation.name].speed = this.walkMaxAnimationSpeed; + if (this.isControllable) + { + this._animation[this.walkAnimation.name].speed = Mathf.Clamp(this.velocity.magnitude, 0.0f, this.walkMaxAnimationSpeed); + } + this._animation.CrossFade(this.walkAnimation.name); + } + + if (this._characterState != PickupCharacterState.Running) + { + this._animation[this.runAnimation.name].time = 0.0f; + } + } + } + // ANIMATION sector + + // Set rotation to the move direction + if (this.IsGrounded()) + { + // a specialty of this controller: you can disable rotation! + if (this.DoRotate) + { + transform.rotation = Quaternion.LookRotation(this.moveDirection); + } + } + else + { + /* This causes choppy behaviour when colliding with SIDES + * Vector3 xzMove = velocity; + xzMove.y = 0; + if (xzMove.sqrMagnitude > 0.001f) + { + transform.rotation = Quaternion.LookRotation(xzMove); + }*/ + } + + // We are in jump mode but just became grounded + if (this.IsGrounded()) + { + this.lastGroundedTime = Time.time; + this.inAirVelocity = Vector3.zero; + if (this.jumping) + { + this.jumping = false; + SendMessage("DidLand", SendMessageOptions.DontRequireReceiver); + } + } + + this.lastPos = transform.position; + } + + public void OnPhotonSerializeView(PhotonStream stream, PhotonMessageInfo info) + { + if (stream.isWriting) + { + stream.SendNext(transform.position); + stream.SendNext((byte)this._characterState); + } + else + { + bool initialRemotePosition = (this.remotePosition == Vector3.zero); + + this.remotePosition = (Vector3)stream.ReceiveNext(); + this._characterState = (PickupCharacterState)((byte)stream.ReceiveNext()); + + if (initialRemotePosition) + { + // avoids lerping the character from "center" to the "current" position when this client joins + transform.position = this.remotePosition; + } + } + } + + void UpdateSmoothedMovementDirection() + { + Transform cameraTransform = Camera.main.transform; + bool grounded = this.IsGrounded(); + + // Forward vector relative to the camera along the x-z plane + Vector3 forward = cameraTransform.TransformDirection(Vector3.forward); + forward.y = 0; + forward = forward.normalized; + + // Right vector relative to the camera + // Always orthogonal to the forward vector + Vector3 right = new Vector3(forward.z, 0, -forward.x); + + float v = Input.GetAxisRaw("Vertical"); + float h = Input.GetAxisRaw("Horizontal"); + + // Are we moving backwards or looking backwards + if (v < -0.2f) + this.movingBack = true; + else + this.movingBack = false; + + bool wasMoving = this.isMoving; + this.isMoving = Mathf.Abs(h) > 0.1f || Mathf.Abs(v) > 0.1f; + + // Target direction relative to the camera + Vector3 targetDirection = h * right + v * forward; + // Debug.Log("targetDirection " + targetDirection); + + // Grounded controls + if (grounded) + { + // Lock camera for short period when transitioning moving & standing still + this.lockCameraTimer += Time.deltaTime; + if (this.isMoving != wasMoving) + this.lockCameraTimer = 0.0f; + + // We store speed and direction seperately, + // so that when the character stands still we still have a valid forward direction + // moveDirection is always normalized, and we only update it if there is user input. + if (targetDirection != Vector3.zero) + { + // If we are really slow, just snap to the target direction + if (this.moveSpeed < this.walkSpeed * 0.9f && grounded) + { + this.moveDirection = targetDirection.normalized; + } + // Otherwise smoothly turn towards it + else + { + this.moveDirection = Vector3.RotateTowards(this.moveDirection, targetDirection, this.rotateSpeed * Mathf.Deg2Rad * Time.deltaTime, 1000); + + this.moveDirection = this.moveDirection.normalized; + } + } + + // Smooth the speed based on the current target direction + float curSmooth = this.speedSmoothing * Time.deltaTime; + + // Choose target speed + //* We want to support analog input but make sure you cant walk faster diagonally than just forward or sideways + float targetSpeed = Mathf.Min(targetDirection.magnitude, 1.0f); + + this._characterState = PickupCharacterState.Idle; + + // Pick speed modifier + if ((Input.GetKey(KeyCode.LeftShift) | Input.GetKey(KeyCode.RightShift)) && this.isMoving) + { + targetSpeed *= this.runSpeed; + this._characterState = PickupCharacterState.Running; + } + else if (Time.time - this.trotAfterSeconds > this.walkTimeStart) + { + targetSpeed *= this.trotSpeed; + this._characterState = PickupCharacterState.Trotting; + } + else if (this.isMoving) + { + targetSpeed *= this.walkSpeed; + this._characterState = PickupCharacterState.Walking; + } + + this.moveSpeed = Mathf.Lerp(this.moveSpeed, targetSpeed, curSmooth); + + // Reset walk time start when we slow down + if (this.moveSpeed < this.walkSpeed * 0.3f) + this.walkTimeStart = Time.time; + } + // In air controls + else + { + // Lock camera while in air + if (this.jumping) + this.lockCameraTimer = 0.0f; + + if (this.isMoving) + this.inAirVelocity += targetDirection.normalized * Time.deltaTime *this.inAirControlAcceleration; + } + } + + void ApplyJumping() + { + // Prevent jumping too fast after each other + if (this.lastJumpTime + this.jumpRepeatTime > Time.time) + return; + + if (this.IsGrounded()) + { + // Jump + // - Only when pressing the button down + // - With a timeout so you can press the button slightly before landing + if (this.canJump && Time.time < this.lastJumpButtonTime + this.jumpTimeout) + { + this.verticalSpeed = this.CalculateJumpVerticalSpeed(this.jumpHeight); + SendMessage("DidJump", SendMessageOptions.DontRequireReceiver); + } + } + } + + void ApplyGravity() + { + if (this.isControllable) // don't move player at all if not controllable. + { + // Apply gravity + //bool jumpButton = Input.GetButton("Jump"); + + // When we reach the apex of the jump we send out a message + if (this.jumping && !this.jumpingReachedApex && this.verticalSpeed <= 0.0f) + { + this.jumpingReachedApex = true; + SendMessage("DidJumpReachApex", SendMessageOptions.DontRequireReceiver); + } + + if (this.IsGrounded()) + this.verticalSpeed = 0.0f; + else + this.verticalSpeed -= this.gravity * Time.deltaTime; + } + } + + float CalculateJumpVerticalSpeed(float targetJumpHeight) + { + // From the jump height and gravity we deduce the upwards speed + // for the character to reach at the apex. + return Mathf.Sqrt(2 * targetJumpHeight *this.gravity); + } + + void DidJump() + { + this.jumping = true; + this.jumpingReachedApex = false; + this.lastJumpTime = Time.time; + //lastJumpStartHeight = transform.position.y; + this.lastJumpButtonTime = -10; + + this._characterState = PickupCharacterState.Jumping; + } + + void OnControllerColliderHit(ControllerColliderHit hit) + { + // Debug.DrawRay(hit.point, hit.normal); + if (hit.moveDirection.y > 0.01f) + return; + } + + public float GetSpeed() + { + return this.moveSpeed; + } + + public bool IsJumping() + { + return this.jumping; + } + + public bool IsGrounded() + { + return (this.collisionFlags & CollisionFlags.CollidedBelow) != 0; + } + + public Vector3 GetDirection() + { + return this.moveDirection; + } + + public bool IsMovingBackwards() + { + return this.movingBack; + } + + public float GetLockCameraTimer() + { + return this.lockCameraTimer; + } + + public bool IsMoving() + { + return Mathf.Abs(Input.GetAxisRaw("Vertical")) + Mathf.Abs(Input.GetAxisRaw("Horizontal")) > 0.5f; + } + + public bool HasJumpReachedApex() + { + return this.jumpingReachedApex; + } + + public bool IsGroundedWithTimeout() + { + return this.lastGroundedTime + this.groundedTimeout > Time.time; + } + + public void Reset() + { + gameObject.tag = "Player"; + } +} \ No newline at end of file diff --git a/Assets/Photon Unity Networking/Demos/DemoPickup/Scripts/PickupController.cs.meta b/Assets/Photon Unity Networking/Demos/DemoPickup/Scripts/PickupController.cs.meta new file mode 100644 index 0000000..8809787 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoPickup/Scripts/PickupController.cs.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: fea4ac359daaa3b4c8ae00070f645d97 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} diff --git a/Assets/Photon Unity Networking/Demos/DemoPickup/Scripts/PickupDemoGui.cs b/Assets/Photon Unity Networking/Demos/DemoPickup/Scripts/PickupDemoGui.cs new file mode 100644 index 0000000..ab89ade --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoPickup/Scripts/PickupDemoGui.cs @@ -0,0 +1,78 @@ +using System.Collections.Generic; +using UnityEngine; +using System.Collections; +using Hashtable = ExitGames.Client.Photon.Hashtable; + +public class PickupDemoGui : MonoBehaviour +{ + public bool ShowScores; + public bool ShowDropButton; + public bool ShowTeams; + public float DropOffset = 0.5f; + + + + public void OnGUI() + { + if (!PhotonNetwork.inRoom) + { + return; + } + + + if (this.ShowScores) + { + GUILayout.Label("Your Score: " + PhotonNetwork.player.GetScore()); + } + + + if (this.ShowDropButton) + { + foreach (PickupItem item in PickupItem.DisabledPickupItems) + { + if (item.PickupIsMine && item.SecondsBeforeRespawn <= 0) + { + if (GUILayout.Button("Drop " + item.name)) + { + item.Drop(); // drops the item at the place where it originates + } + + GameObject playerCharGo = PhotonNetwork.player.TagObject as GameObject; + if (playerCharGo != null && GUILayout.Button("Drop here " + item.name)) + { + // drop the item at some other place. next to the user's character would be fine... + Vector3 random = Random.insideUnitSphere; + random.y = 0; + random = random.normalized; + Vector3 itempos = playerCharGo.transform.position + this.DropOffset * random; + + item.Drop(itempos); + } + } + } + } + + + if (this.ShowTeams) + { + foreach (var teamName in PunTeams.PlayersPerTeam.Keys) + { + GUILayout.Label("Team: " + teamName.ToString()); + List teamPlayers = PunTeams.PlayersPerTeam[teamName]; + foreach (PhotonPlayer player in teamPlayers) + { + GUILayout.Label(" " + player.ToStringFull() + " Score: " + player.GetScore()); + } + } + + if (GUILayout.Button("to red")) + { + PhotonNetwork.player.SetTeam(PunTeams.Team.red); + } + if (GUILayout.Button("to blue")) + { + PhotonNetwork.player.SetTeam(PunTeams.Team.blue); + } + } + } +} \ No newline at end of file diff --git a/Assets/Photon Unity Networking/Demos/DemoPickup/Scripts/PickupDemoGui.cs.meta b/Assets/Photon Unity Networking/Demos/DemoPickup/Scripts/PickupDemoGui.cs.meta new file mode 100644 index 0000000..5db4300 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoPickup/Scripts/PickupDemoGui.cs.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 09e4272782f6acf4eb2168f38b594c5a +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} diff --git a/Assets/Photon Unity Networking/Demos/DemoPickup/Scripts/PickupTriggerForward.cs b/Assets/Photon Unity Networking/Demos/DemoPickup/Scripts/PickupTriggerForward.cs new file mode 100644 index 0000000..66e321d --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoPickup/Scripts/PickupTriggerForward.cs @@ -0,0 +1,26 @@ +using UnityEngine; +using System.Collections; + +/// +/// Simple script to forward a sub-objects OnTriggerEnter to the parent's PickupItem-component. +/// +/// +/// This is useful when a physcial object has a collider but also needs a trigger. +/// +public class PickupTriggerForward : MonoBehaviour { + + + + public void OnTriggerEnter(Collider other) + { + PickupItem parentPickupItem = this.transform.parent.GetComponent(); + if (parentPickupItem != null) + { + parentPickupItem.OnTriggerEnter(other); + } + + // by enabling this log, you can see that more triggers are forwarded than necessary. + // collisions with any collider will trigger, which is not perfect but OK in the demo. + //Debug.Log("Triggered. Called parent: " + ((parentPickupItem != null))); + } +} \ No newline at end of file diff --git a/Assets/Photon Unity Networking/Demos/DemoPickup/Scripts/PickupTriggerForward.cs.meta b/Assets/Photon Unity Networking/Demos/DemoPickup/Scripts/PickupTriggerForward.cs.meta new file mode 100644 index 0000000..2e746c1 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoPickup/Scripts/PickupTriggerForward.cs.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: a7667a1dc84fd4c4bb8947abf296c294 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} diff --git a/Assets/Photon Unity Networking/Demos/DemoRPGMovement.meta b/Assets/Photon Unity Networking/Demos/DemoRPGMovement.meta new file mode 100644 index 0000000..d458069 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoRPGMovement.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 48af45f6f8329493294e60b62bb36254 +folderAsset: yes +timeCreated: 1501014811 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Photon Unity Networking/Demos/DemoRPGMovement/DemoRPGMovement-Scene.unity b/Assets/Photon Unity Networking/Demos/DemoRPGMovement/DemoRPGMovement-Scene.unity new file mode 100644 index 0000000..eebf7a7 Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/DemoRPGMovement/DemoRPGMovement-Scene.unity differ diff --git a/Assets/Photon Unity Networking/Demos/DemoRPGMovement/DemoRPGMovement-Scene.unity.meta b/Assets/Photon Unity Networking/Demos/DemoRPGMovement/DemoRPGMovement-Scene.unity.meta new file mode 100644 index 0000000..a788e8b --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoRPGMovement/DemoRPGMovement-Scene.unity.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: 04d0690ecf8bf94489c8427dd8186299 +DefaultImporter: + userData: diff --git a/Assets/Photon Unity Networking/Demos/DemoRPGMovement/New Terrain.asset b/Assets/Photon Unity Networking/Demos/DemoRPGMovement/New Terrain.asset new file mode 100644 index 0000000..0f665b6 Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/DemoRPGMovement/New Terrain.asset differ diff --git a/Assets/Photon Unity Networking/Demos/DemoRPGMovement/New Terrain.asset.meta b/Assets/Photon Unity Networking/Demos/DemoRPGMovement/New Terrain.asset.meta new file mode 100644 index 0000000..cd7e985 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoRPGMovement/New Terrain.asset.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: f79ff8ffe534cf94994c4fc73568fecc +NativeFormatImporter: + userData: diff --git a/Assets/Photon Unity Networking/Demos/DemoRPGMovement/Resources.meta b/Assets/Photon Unity Networking/Demos/DemoRPGMovement/Resources.meta new file mode 100644 index 0000000..059f36d --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoRPGMovement/Resources.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 258f709200d91497c86e3072d411a980 +folderAsset: yes +timeCreated: 1501014811 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Photon Unity Networking/Demos/DemoRPGMovement/Resources/Robot Kyle RPG.prefab b/Assets/Photon Unity Networking/Demos/DemoRPGMovement/Resources/Robot Kyle RPG.prefab new file mode 100644 index 0000000..641195c Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/DemoRPGMovement/Resources/Robot Kyle RPG.prefab differ diff --git a/Assets/Photon Unity Networking/Demos/DemoRPGMovement/Resources/Robot Kyle RPG.prefab.meta b/Assets/Photon Unity Networking/Demos/DemoRPGMovement/Resources/Robot Kyle RPG.prefab.meta new file mode 100644 index 0000000..9cb8b58 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoRPGMovement/Resources/Robot Kyle RPG.prefab.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: ac2211405d10cff44855fe2b2d067ae1 +NativeFormatImporter: + userData: diff --git a/Assets/Photon Unity Networking/Demos/DemoRPGMovement/Scripts.meta b/Assets/Photon Unity Networking/Demos/DemoRPGMovement/Scripts.meta new file mode 100644 index 0000000..a44ff29 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoRPGMovement/Scripts.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: a02481e017b9e45e390706312a3aa59e +folderAsset: yes +timeCreated: 1501014811 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Photon Unity Networking/Demos/DemoRPGMovement/Scripts/DemoRPGMovement.cs b/Assets/Photon Unity Networking/Demos/DemoRPGMovement/Scripts/DemoRPGMovement.cs new file mode 100644 index 0000000..73c4b29 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoRPGMovement/Scripts/DemoRPGMovement.cs @@ -0,0 +1,21 @@ +using UnityEngine; +using System.Collections; + +public class DemoRPGMovement : MonoBehaviour +{ + public RPGCamera Camera; + + void OnJoinedRoom() + { + CreatePlayerObject(); + } + + void CreatePlayerObject() + { + Vector3 position = new Vector3( 33.5f, 1.5f, 20.5f ); + + GameObject newPlayerObject = PhotonNetwork.Instantiate( "Robot Kyle RPG", position, Quaternion.identity, 0 ); + + Camera.Target = newPlayerObject.transform; + } +} diff --git a/Assets/Photon Unity Networking/Demos/DemoRPGMovement/Scripts/DemoRPGMovement.cs.meta b/Assets/Photon Unity Networking/Demos/DemoRPGMovement/Scripts/DemoRPGMovement.cs.meta new file mode 100644 index 0000000..da11ac5 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoRPGMovement/Scripts/DemoRPGMovement.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: cb3059a2d50d44347a80ee255a939e18 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Photon Unity Networking/Demos/DemoRPGMovement/Scripts/RPGCamera.cs b/Assets/Photon Unity Networking/Demos/DemoRPGMovement/Scripts/RPGCamera.cs new file mode 100644 index 0000000..6aad7b2 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoRPGMovement/Scripts/RPGCamera.cs @@ -0,0 +1,70 @@ +using UnityEngine; +using System.Collections; + +public class RPGCamera : MonoBehaviour +{ + public Transform Target; + + public float MaximumDistance; + public float MinimumDistance; + + public float ScrollModifier; + public float TurnModifier; + + Transform m_CameraTransform; + + Vector3 m_LookAtPoint; + Vector3 m_LocalForwardVector; + float m_Distance; + + void Start() + { + m_CameraTransform = transform.GetChild( 0 ); + m_LocalForwardVector = m_CameraTransform.forward; + + m_Distance = -m_CameraTransform.localPosition.z / m_CameraTransform.forward.z; + m_Distance = Mathf.Clamp( m_Distance, MinimumDistance, MaximumDistance ); + m_LookAtPoint = m_CameraTransform.localPosition + m_LocalForwardVector * m_Distance; + } + + void LateUpdate() + { + UpdateDistance(); + UpdateZoom(); + UpdatePosition(); + UpdateRotation(); + } + + void UpdateDistance() + { + m_Distance = Mathf.Clamp( m_Distance - Input.GetAxis( "Mouse ScrollWheel" ) * ScrollModifier, MinimumDistance, MaximumDistance ); + } + + void UpdateZoom() + { + m_CameraTransform.localPosition = m_LookAtPoint - m_LocalForwardVector * m_Distance; + } + + void UpdatePosition() + { + if( Target == null ) + { + return; + } + + transform.position = Target.transform.position; + } + + void UpdateRotation() + { + if( Input.GetMouseButton( 0 ) == true || Input.GetMouseButton( 1 ) == true || Input.GetButton("Fire1") || Input.GetButton("Fire2")) + { + transform.Rotate( 0, Input.GetAxis( "Mouse X" ) * TurnModifier, 0 ); + } + + if((Input.GetMouseButton( 1 ) || Input.GetButton("Fire2")) && Target != null ) + { + Target.rotation = Quaternion.Euler( 0, transform.rotation.eulerAngles.y, 0 ); + } + } +} diff --git a/Assets/Photon Unity Networking/Demos/DemoRPGMovement/Scripts/RPGCamera.cs.meta b/Assets/Photon Unity Networking/Demos/DemoRPGMovement/Scripts/RPGCamera.cs.meta new file mode 100644 index 0000000..18df2c0 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoRPGMovement/Scripts/RPGCamera.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 45d2cd5ac7ae5de4d91fd395f8d61afd +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Photon Unity Networking/Demos/DemoRPGMovement/Scripts/RPGMovement.cs b/Assets/Photon Unity Networking/Demos/DemoRPGMovement/Scripts/RPGMovement.cs new file mode 100644 index 0000000..f66a368 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoRPGMovement/Scripts/RPGMovement.cs @@ -0,0 +1,149 @@ +using UnityEngine; +using System.Collections; + +[RequireComponent( typeof( CharacterController ) )] +public class RPGMovement : MonoBehaviour +{ + public float ForwardSpeed; + public float BackwardSpeed; + public float StrafeSpeed; + public float RotateSpeed; + + CharacterController m_CharacterController; + Vector3 m_LastPosition; + Animator m_Animator; + PhotonView m_PhotonView; + PhotonTransformView m_TransformView; + + float m_AnimatorSpeed; + Vector3 m_CurrentMovement; + float m_CurrentTurnSpeed; + + void Start() + { + m_CharacterController = GetComponent(); + m_Animator = GetComponent(); + m_PhotonView = GetComponent(); + m_TransformView = GetComponent(); + } + + void Update() + { + if( m_PhotonView.isMine == true ) + { + ResetSpeedValues(); + + UpdateRotateMovement(); + + UpdateForwardMovement(); + UpdateBackwardMovement(); + UpdateStrafeMovement(); + + MoveCharacterController(); + ApplyGravityToCharacterController(); + + ApplySynchronizedValues(); + } + + UpdateAnimation(); + } + + void UpdateAnimation() + { + Vector3 movementVector = transform.position - m_LastPosition; + + float speed = Vector3.Dot( movementVector.normalized, transform.forward ); + float direction = Vector3.Dot( movementVector.normalized, transform.right ); + + if( Mathf.Abs( speed ) < 0.2f ) + { + speed = 0f; + } + + if( speed > 0.6f ) + { + speed = 1f; + direction = 0f; + } + + if( speed >= 0f ) + { + if( Mathf.Abs( direction ) > 0.7f ) + { + speed = 1f; + } + } + + m_AnimatorSpeed = Mathf.MoveTowards( m_AnimatorSpeed, speed, Time.deltaTime * 5f ); + + m_Animator.SetFloat( "Speed", m_AnimatorSpeed ); + m_Animator.SetFloat( "Direction", direction ); + + m_LastPosition = transform.position; + } + + void ResetSpeedValues() + { + m_CurrentMovement = Vector3.zero; + m_CurrentTurnSpeed = 0; + } + + void ApplySynchronizedValues() + { + m_TransformView.SetSynchronizedValues( m_CurrentMovement, m_CurrentTurnSpeed ); + } + + void ApplyGravityToCharacterController() + { + m_CharacterController.Move( transform.up * Time.deltaTime * -9.81f ); + } + + void MoveCharacterController() + { + m_CharacterController.Move( m_CurrentMovement * Time.deltaTime ); + } + + void UpdateForwardMovement() + { + if( Input.GetKey( KeyCode.W ) || Input.GetAxisRaw("Vertical") > 0.1f ) + { + m_CurrentMovement = transform.forward * ForwardSpeed; + } + } + + void UpdateBackwardMovement() + { + if( Input.GetKey( KeyCode.S ) || Input.GetAxisRaw("Vertical") < -0.1f ) + { + m_CurrentMovement = -transform.forward * BackwardSpeed; + } + } + + void UpdateStrafeMovement() + { + if( Input.GetKey( KeyCode.Q ) == true ) + { + m_CurrentMovement = -transform.right * StrafeSpeed; + } + + if( Input.GetKey( KeyCode.E ) == true ) + { + m_CurrentMovement = transform.right * StrafeSpeed; + } + } + + void UpdateRotateMovement() + { + if( Input.GetKey( KeyCode.A ) || Input.GetAxisRaw("Horizontal") < -0.1f ) + { + m_CurrentTurnSpeed = -RotateSpeed; + transform.Rotate(0.0f, -RotateSpeed * Time.deltaTime, 0.0f); + } + + if( Input.GetKey( KeyCode.D ) || Input.GetAxisRaw("Horizontal") > 0.1f ) + { + m_CurrentTurnSpeed = RotateSpeed; + transform.Rotate(0.0f, RotateSpeed * Time.deltaTime, 0.0f); + } + } +} \ No newline at end of file diff --git a/Assets/Photon Unity Networking/Demos/DemoRPGMovement/Scripts/RPGMovement.cs.meta b/Assets/Photon Unity Networking/Demos/DemoRPGMovement/Scripts/RPGMovement.cs.meta new file mode 100644 index 0000000..d05051e --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoRPGMovement/Scripts/RPGMovement.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 747b79b3c36c70c40a71f4542e7e3934 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors.meta b/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors.meta new file mode 100644 index 0000000..c7450e4 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 48bb928f452cf49178c02794b2d19b87 +folderAsset: yes +timeCreated: 1501014811 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/Assets.meta b/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/Assets.meta new file mode 100644 index 0000000..cd82fb5 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/Assets.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: d8e53d6367b5f4a5da25d21d21a115bd +folderAsset: yes +timeCreated: 1501014812 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/Assets/BgCanvas.png b/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/Assets/BgCanvas.png new file mode 100644 index 0000000..0e88e0e Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/Assets/BgCanvas.png differ diff --git a/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/Assets/BgCanvas.png.meta b/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/Assets/BgCanvas.png.meta new file mode 100644 index 0000000..00a8354 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/Assets/BgCanvas.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: 03db1a73f7e7c9f4bb5d1580261ddeb3 +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + linearTexture: 0 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -1 + maxTextureSize: 1024 + textureSettings: + filterMode: -1 + aniso: 0 + mipBias: -1 + wrapMode: 1 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 3 + alphaIsTransparency: 1 + textureType: 8 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/Assets/BgTimeline.png b/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/Assets/BgTimeline.png new file mode 100644 index 0000000..89f5fd7 Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/Assets/BgTimeline.png differ diff --git a/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/Assets/BgTimeline.png.meta b/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/Assets/BgTimeline.png.meta new file mode 100644 index 0000000..8edc96f --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/Assets/BgTimeline.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: db758b787e38e3447b48317ec83eeed0 +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + linearTexture: 0 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -1 + maxTextureSize: 512 + textureSettings: + filterMode: 2 + aniso: 0 + mipBias: -1 + wrapMode: 1 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 1 + textureType: 8 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/Assets/IconAgain.png b/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/Assets/IconAgain.png new file mode 100644 index 0000000..d9828c4 Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/Assets/IconAgain.png differ diff --git a/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/Assets/IconAgain.png.meta b/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/Assets/IconAgain.png.meta new file mode 100644 index 0000000..ac9a900 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/Assets/IconAgain.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: a6e8dc287cf5072478409ca9df35bba6 +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + linearTexture: 0 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -1 + maxTextureSize: 1024 + textureSettings: + filterMode: -1 + aniso: 0 + mipBias: -1 + wrapMode: 1 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 3 + alphaIsTransparency: 1 + textureType: 8 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/Assets/IconPaper.png b/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/Assets/IconPaper.png new file mode 100644 index 0000000..b1bc142 Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/Assets/IconPaper.png differ diff --git a/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/Assets/IconPaper.png.meta b/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/Assets/IconPaper.png.meta new file mode 100644 index 0000000..538146e --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/Assets/IconPaper.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: 3dc2c106cbdb165459731317c0d54439 +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + linearTexture: 0 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -1 + maxTextureSize: 1024 + textureSettings: + filterMode: -1 + aniso: 0 + mipBias: -1 + wrapMode: 1 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 3 + alphaIsTransparency: 1 + textureType: 8 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/Assets/IconPaperSmall.png b/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/Assets/IconPaperSmall.png new file mode 100644 index 0000000..eed8ae6 Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/Assets/IconPaperSmall.png differ diff --git a/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/Assets/IconPaperSmall.png.meta b/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/Assets/IconPaperSmall.png.meta new file mode 100644 index 0000000..bd9bcb6 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/Assets/IconPaperSmall.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: ef975cc62c5a21740922e73f9d0a5dff +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + linearTexture: 0 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -1 + maxTextureSize: 1024 + textureSettings: + filterMode: -1 + aniso: 0 + mipBias: -1 + wrapMode: 1 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 3 + alphaIsTransparency: 1 + textureType: 8 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/Assets/IconResultDraw.png b/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/Assets/IconResultDraw.png new file mode 100644 index 0000000..1c99fb3 Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/Assets/IconResultDraw.png differ diff --git a/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/Assets/IconResultDraw.png.meta b/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/Assets/IconResultDraw.png.meta new file mode 100644 index 0000000..5a42076 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/Assets/IconResultDraw.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: f6910fb0d222b0d4b85db3cae6028924 +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + linearTexture: 0 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -1 + maxTextureSize: 512 + textureSettings: + filterMode: -1 + aniso: 0 + mipBias: -1 + wrapMode: 1 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 3 + alphaIsTransparency: 1 + textureType: 8 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/Assets/IconResultLoose.png b/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/Assets/IconResultLoose.png new file mode 100644 index 0000000..19a27c3 Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/Assets/IconResultLoose.png differ diff --git a/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/Assets/IconResultLoose.png.meta b/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/Assets/IconResultLoose.png.meta new file mode 100644 index 0000000..85fa4f7 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/Assets/IconResultLoose.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: 4fe8df95a3eb9254ca5bed23f34b37fd +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + linearTexture: 0 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -1 + maxTextureSize: 512 + textureSettings: + filterMode: -1 + aniso: 0 + mipBias: -1 + wrapMode: 1 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 3 + alphaIsTransparency: 1 + textureType: 8 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/Assets/IconResultWin.png b/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/Assets/IconResultWin.png new file mode 100644 index 0000000..e5210db Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/Assets/IconResultWin.png differ diff --git a/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/Assets/IconResultWin.png.meta b/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/Assets/IconResultWin.png.meta new file mode 100644 index 0000000..775dcd0 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/Assets/IconResultWin.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: 3214282c1b4644f4fa39f146ab71066d +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + linearTexture: 0 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -1 + maxTextureSize: 512 + textureSettings: + filterMode: -1 + aniso: 0 + mipBias: -1 + wrapMode: 1 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 3 + alphaIsTransparency: 1 + textureType: 8 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/Assets/IconRock.png b/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/Assets/IconRock.png new file mode 100644 index 0000000..6b3a1ea Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/Assets/IconRock.png differ diff --git a/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/Assets/IconRock.png.meta b/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/Assets/IconRock.png.meta new file mode 100644 index 0000000..a1bbb26 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/Assets/IconRock.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: 08fc1cc755dba584aa61c61aa0a70739 +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + linearTexture: 0 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -1 + maxTextureSize: 1024 + textureSettings: + filterMode: -1 + aniso: 0 + mipBias: -1 + wrapMode: 1 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 3 + alphaIsTransparency: 1 + textureType: 8 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/Assets/IconRockSmall.png b/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/Assets/IconRockSmall.png new file mode 100644 index 0000000..1670656 Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/Assets/IconRockSmall.png differ diff --git a/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/Assets/IconRockSmall.png.meta b/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/Assets/IconRockSmall.png.meta new file mode 100644 index 0000000..7aa482d --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/Assets/IconRockSmall.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: cad927d4fa484b747979bc2f208d3d66 +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + linearTexture: 0 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -1 + maxTextureSize: 1024 + textureSettings: + filterMode: -1 + aniso: 0 + mipBias: -1 + wrapMode: 1 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 3 + alphaIsTransparency: 1 + textureType: 8 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/Assets/IconScissors.png b/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/Assets/IconScissors.png new file mode 100644 index 0000000..edfb3a2 Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/Assets/IconScissors.png differ diff --git a/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/Assets/IconScissors.png.meta b/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/Assets/IconScissors.png.meta new file mode 100644 index 0000000..8ee0930 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/Assets/IconScissors.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: 6e8ea354be655a94ca1c30bfa104697c +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + linearTexture: 0 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -1 + maxTextureSize: 1024 + textureSettings: + filterMode: -1 + aniso: 0 + mipBias: -1 + wrapMode: 1 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 3 + alphaIsTransparency: 1 + textureType: 8 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/Assets/IconScissorsSmall.png b/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/Assets/IconScissorsSmall.png new file mode 100644 index 0000000..cffa752 Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/Assets/IconScissorsSmall.png differ diff --git a/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/Assets/IconScissorsSmall.png.meta b/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/Assets/IconScissorsSmall.png.meta new file mode 100644 index 0000000..0a30d9c --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/Assets/IconScissorsSmall.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: 047d6460ec8dc544a952b99b9693519c +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + linearTexture: 0 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -1 + maxTextureSize: 1024 + textureSettings: + filterMode: -1 + aniso: 0 + mipBias: -1 + wrapMode: 1 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 3 + alphaIsTransparency: 1 + textureType: 8 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/Assets/OpenSans.meta b/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/Assets/OpenSans.meta new file mode 100644 index 0000000..39ea078 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/Assets/OpenSans.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 11a510d3f9c4d4748b78421463295d86 +folderAsset: yes +timeCreated: 1501014812 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/Assets/OpenSans/Apache License.txt b/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/Assets/OpenSans/Apache License.txt new file mode 100644 index 0000000..989e2c5 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/Assets/OpenSans/Apache License.txt @@ -0,0 +1,201 @@ +Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. \ No newline at end of file diff --git a/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/Assets/OpenSans/Apache License.txt.meta b/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/Assets/OpenSans/Apache License.txt.meta new file mode 100644 index 0000000..fbdf894 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/Assets/OpenSans/Apache License.txt.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: 3132b20ffdf43924da403021f95590ae +TextScriptImporter: + userData: diff --git a/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/Assets/OpenSans/OpenSans-Bold.ttf b/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/Assets/OpenSans/OpenSans-Bold.ttf new file mode 100644 index 0000000..fd79d43 Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/Assets/OpenSans/OpenSans-Bold.ttf differ diff --git a/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/Assets/OpenSans/OpenSans-Bold.ttf.meta b/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/Assets/OpenSans/OpenSans-Bold.ttf.meta new file mode 100644 index 0000000..d7b0664 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/Assets/OpenSans/OpenSans-Bold.ttf.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: c2d622bc4892ff441aee9289a6006707 +TrueTypeFontImporter: + serializedVersion: 2 + fontSize: 16 + forceTextureCase: -2 + characterSpacing: 1 + characterPadding: 0 + includeFontData: 1 + use2xBehaviour: 0 + fontNames: [] + customCharacters: + fontRenderingMode: 0 + userData: diff --git a/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/Assets/OpenSans/OpenSans-Light.ttf b/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/Assets/OpenSans/OpenSans-Light.ttf new file mode 100644 index 0000000..0d38189 Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/Assets/OpenSans/OpenSans-Light.ttf differ diff --git a/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/Assets/OpenSans/OpenSans-Light.ttf.meta b/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/Assets/OpenSans/OpenSans-Light.ttf.meta new file mode 100644 index 0000000..d5ac5e3 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/Assets/OpenSans/OpenSans-Light.ttf.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: a6aa145e5b99127428ecde3a5acbf68b +TrueTypeFontImporter: + serializedVersion: 2 + fontSize: 16 + forceTextureCase: -2 + characterSpacing: 1 + characterPadding: 0 + includeFontData: 1 + use2xBehaviour: 0 + fontNames: [] + customCharacters: + fontRenderingMode: 0 + userData: diff --git a/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/Assets/OpenSans/OpenSans-Regular.ttf b/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/Assets/OpenSans/OpenSans-Regular.ttf new file mode 100644 index 0000000..db43334 Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/Assets/OpenSans/OpenSans-Regular.ttf differ diff --git a/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/Assets/OpenSans/OpenSans-Regular.ttf.meta b/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/Assets/OpenSans/OpenSans-Regular.ttf.meta new file mode 100644 index 0000000..142ad09 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/Assets/OpenSans/OpenSans-Regular.ttf.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: 439afd3f954cea94c8e910eef29cd81f +TrueTypeFontImporter: + serializedVersion: 2 + fontSize: 16 + forceTextureCase: -2 + characterSpacing: 1 + characterPadding: 0 + includeFontData: 1 + use2xBehaviour: 0 + fontNames: [] + customCharacters: + fontRenderingMode: 0 + userData: diff --git a/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/Assets/OpenSans/OpenSans-Semibold.ttf b/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/Assets/OpenSans/OpenSans-Semibold.ttf new file mode 100644 index 0000000..1a7679e Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/Assets/OpenSans/OpenSans-Semibold.ttf differ diff --git a/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/Assets/OpenSans/OpenSans-Semibold.ttf.meta b/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/Assets/OpenSans/OpenSans-Semibold.ttf.meta new file mode 100644 index 0000000..2d6fc0f --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/Assets/OpenSans/OpenSans-Semibold.ttf.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: 23ccffaf915b101419d098a118141d9a +TrueTypeFontImporter: + serializedVersion: 2 + fontSize: 16 + forceTextureCase: -2 + characterSpacing: 1 + characterPadding: 0 + includeFontData: 1 + use2xBehaviour: 0 + fontNames: [] + customCharacters: + fontRenderingMode: 0 + userData: diff --git a/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/Assets/RpsLogo.png b/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/Assets/RpsLogo.png new file mode 100644 index 0000000..89d43a0 Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/Assets/RpsLogo.png differ diff --git a/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/Assets/RpsLogo.png.meta b/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/Assets/RpsLogo.png.meta new file mode 100644 index 0000000..07ab8f2 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/Assets/RpsLogo.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: f0fdef7bd86f76b4d843423af0395ee7 +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + linearTexture: 0 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -1 + maxTextureSize: 1024 + textureSettings: + filterMode: -1 + aniso: 0 + mipBias: -1 + wrapMode: 1 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 3 + alphaIsTransparency: 1 + textureType: 8 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/DemoRPS-Connect-Scene.unity b/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/DemoRPS-Connect-Scene.unity new file mode 100644 index 0000000..753f573 Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/DemoRPS-Connect-Scene.unity differ diff --git a/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/DemoRPS-Connect-Scene.unity.meta b/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/DemoRPS-Connect-Scene.unity.meta new file mode 100644 index 0000000..d881f06 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/DemoRPS-Connect-Scene.unity.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: 96da012e5ddf34c42832a2b67bb519a7 +DefaultImporter: + userData: diff --git a/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/DemoRPS-Scene.unity b/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/DemoRPS-Scene.unity new file mode 100644 index 0000000..6d60d45 Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/DemoRPS-Scene.unity differ diff --git a/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/DemoRPS-Scene.unity.meta b/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/DemoRPS-Scene.unity.meta new file mode 100644 index 0000000..af98b78 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/DemoRPS-Scene.unity.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: 8a3480dd507edcd40b9a02e219e22da6 +DefaultImporter: + userData: diff --git a/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/Scripts.meta b/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/Scripts.meta new file mode 100644 index 0000000..245242c --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/Scripts.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: d166362c25de249ef9763776c06962bc +folderAsset: yes +timeCreated: 1501014811 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/Scripts/RpsCore.cs b/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/Scripts/RpsCore.cs new file mode 100644 index 0000000..541a5f2 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/Scripts/RpsCore.cs @@ -0,0 +1,540 @@ +using System; +using System.Collections; +using Photon; +using UnityEngine; +using UnityEngine.UI; +using Random = UnityEngine.Random; + +using ExitGames.Client.Photon; + +// the Photon server assigns a ActorNumber (player.ID) to each player, beginning at 1 +// for this game, we don't mind the actual number +// this game uses player 0 and 1, so clients need to figure out their number somehow +public class RpsCore : PunBehaviour, IPunTurnManagerCallbacks +{ + + [SerializeField] + private RectTransform ConnectUiView; + + [SerializeField] + private RectTransform GameUiView; + + [SerializeField] + private CanvasGroup ButtonCanvasGroup; + + [SerializeField] + private RectTransform TimerFillImage; + + [SerializeField] + private Text TurnText; + + [SerializeField] + private Text TimeText; + + [SerializeField] + private Text RemotePlayerText; + + [SerializeField] + private Text LocalPlayerText; + + [SerializeField] + private Image WinOrLossImage; + + + [SerializeField] + private Image localSelectionImage; + public Hand localSelection; + + [SerializeField] + private Image remoteSelectionImage; + public Hand remoteSelection; + + + [SerializeField] + private Sprite SelectedRock; + + [SerializeField] + private Sprite SelectedPaper; + + [SerializeField] + private Sprite SelectedScissors; + + [SerializeField] + private Sprite SpriteWin; + + [SerializeField] + private Sprite SpriteLose; + + [SerializeField] + private Sprite SpriteDraw; + + + [SerializeField] + private RectTransform DisconnectedPanel; + + private ResultType result; + + private PunTurnManager turnManager; + + public Hand randomHand; // used to show remote player's "hand" while local player didn't select anything + + // keep track of when we show the results to handle game logic. + private bool IsShowingResults; + + public enum Hand + { + None = 0, + Rock, + Paper, + Scissors + } + + public enum ResultType + { + None = 0, + Draw, + LocalWin, + LocalLoss + } + + public void Start() + { + this.turnManager = this.gameObject.AddComponent(); + this.turnManager.TurnManagerListener = this; + this.turnManager.TurnDuration = 5f; + + + this.localSelectionImage.gameObject.SetActive(false); + this.remoteSelectionImage.gameObject.SetActive(false); + this.StartCoroutine("CycleRemoteHandCoroutine"); + + RefreshUIViews(); + } + + public void Update() + { + // Check if we are out of context, which means we likely got back to the demo hub. + if (this.DisconnectedPanel ==null) + { + Destroy(this.gameObject); + } + + // for debugging, it's useful to have a few actions tied to keys: + if (Input.GetKeyUp(KeyCode.L)) + { + PhotonNetwork.LeaveRoom(); + } + if (Input.GetKeyUp(KeyCode.C)) + { + PhotonNetwork.ConnectUsingSettings(null); + PhotonHandler.StopFallbackSendAckThread(); + } + + + if ( ! PhotonNetwork.inRoom) + { + return; + } + + // disable the "reconnect panel" if PUN is connected or connecting + if (PhotonNetwork.connected && this.DisconnectedPanel.gameObject.GetActive()) + { + this.DisconnectedPanel.gameObject.SetActive(false); + } + if (!PhotonNetwork.connected && !PhotonNetwork.connecting && !this.DisconnectedPanel.gameObject.GetActive()) + { + this.DisconnectedPanel.gameObject.SetActive(true); + } + + + if (PhotonNetwork.room.PlayerCount>1) + { + if (this.turnManager.IsOver) + { + return; + } + + /* + // check if we ran out of time, in which case we loose + if (turnEnd<0f && !IsShowingResults) + { + Debug.Log("Calling OnTurnCompleted with turnEnd ="+turnEnd); + OnTurnCompleted(-1); + return; + } + */ + + if (this.TurnText != null) + { + this.TurnText.text = this.turnManager.Turn.ToString(); + } + + if (this.turnManager.Turn > 0 && this.TimeText != null && ! IsShowingResults) + { + + this.TimeText.text = this.turnManager.RemainingSecondsInTurn.ToString("F1") + " SECONDS"; + + TimerFillImage.anchorMax = new Vector2(1f- this.turnManager.RemainingSecondsInTurn/this.turnManager.TurnDuration,1f); + } + + + } + + this.UpdatePlayerTexts(); + + // show local player's selected hand + Sprite selected = SelectionToSprite(this.localSelection); + if (selected != null) + { + this.localSelectionImage.gameObject.SetActive(true); + this.localSelectionImage.sprite = selected; + } + + // remote player's selection is only shown, when the turn is complete (finished by both) + if (this.turnManager.IsCompletedByAll) + { + selected = SelectionToSprite(this.remoteSelection); + if (selected != null) + { + this.remoteSelectionImage.color = new Color(1,1,1,1); + this.remoteSelectionImage.sprite = selected; + } + } + else + { + ButtonCanvasGroup.interactable = PhotonNetwork.room.PlayerCount > 1; + + if (PhotonNetwork.room.PlayerCount < 2) + { + this.remoteSelectionImage.color = new Color(1, 1, 1, 0); + } + + // if the turn is not completed by all, we use a random image for the remote hand + else if (this.turnManager.Turn > 0 && !this.turnManager.IsCompletedByAll) + { + // alpha of the remote hand is used as indicator if the remote player "is active" and "made a turn" + PhotonPlayer remote = PhotonNetwork.player.GetNext(); + float alpha = 0.5f; + if (this.turnManager.GetPlayerFinishedTurn(remote)) + { + alpha = 1; + } + if (remote != null && remote.IsInactive) + { + alpha = 0.1f; + } + + this.remoteSelectionImage.color = new Color(1, 1, 1, alpha); + this.remoteSelectionImage.sprite = SelectionToSprite(randomHand); + } + } + + } + + #region TurnManager Callbacks + + /// Called when a turn begins (Master Client set a new Turn number). + public void OnTurnBegins(int turn) + { + Debug.Log("OnTurnBegins() turn: "+ turn); + this.localSelection = Hand.None; + this.remoteSelection = Hand.None; + + this.WinOrLossImage.gameObject.SetActive(false); + + this.localSelectionImage.gameObject.SetActive(false); + this.remoteSelectionImage.gameObject.SetActive(true); + + IsShowingResults = false; + ButtonCanvasGroup.interactable = true; + } + + + public void OnTurnCompleted(int obj) + { + Debug.Log("OnTurnCompleted: " + obj); + + this.CalculateWinAndLoss(); + this.UpdateScores(); + this.OnEndTurn(); + } + + + // when a player moved (but did not finish the turn) + public void OnPlayerMove(PhotonPlayer photonPlayer, int turn, object move) + { + Debug.Log("OnPlayerMove: " + photonPlayer + " turn: " + turn + " action: " + move); + throw new NotImplementedException(); + } + + + // when a player made the last/final move in a turn + public void OnPlayerFinished(PhotonPlayer photonPlayer, int turn, object move) + { + Debug.Log("OnTurnFinished: " + photonPlayer + " turn: " + turn + " action: " + move); + + if (photonPlayer.IsLocal) + { + this.localSelection = (Hand)(byte)move; + } + else + { + this.remoteSelection = (Hand)(byte)move; + } + } + + + + public void OnTurnTimeEnds(int obj) + { + if (!IsShowingResults) + { + Debug.Log("OnTurnTimeEnds: Calling OnTurnCompleted"); + OnTurnCompleted(-1); + } + } + + private void UpdateScores() + { + if (this.result == ResultType.LocalWin) + { + PhotonNetwork.player.AddScore(1); // this is an extension method for PhotonPlayer. you can see it's implementation + } + } + + #endregion + + #region Core Gameplay Methods + + + /// Call to start the turn (only the Master Client will send this). + public void StartTurn() + { + if (PhotonNetwork.isMasterClient) + { + this.turnManager.BeginTurn(); + } + } + + public void MakeTurn(Hand selection) + { + this.turnManager.SendMove((byte)selection, true); + } + + public void OnEndTurn() + { + this.StartCoroutine("ShowResultsBeginNextTurnCoroutine"); + } + + public IEnumerator ShowResultsBeginNextTurnCoroutine() + { + ButtonCanvasGroup.interactable = false; + IsShowingResults = true; + // yield return new WaitForSeconds(1.5f); + + if (this.result == ResultType.Draw) + { + this.WinOrLossImage.sprite = this.SpriteDraw; + } + else + { + this.WinOrLossImage.sprite = this.result == ResultType.LocalWin ? this.SpriteWin : SpriteLose; + } + this.WinOrLossImage.gameObject.SetActive(true); + + yield return new WaitForSeconds(2.0f); + + this.StartTurn(); + } + + + public void EndGame() + { + Debug.Log("EndGame"); + } + + private void CalculateWinAndLoss() + { + this.result = ResultType.Draw; + if (this.localSelection == this.remoteSelection) + { + return; + } + + if (this.localSelection == Hand.None) + { + this.result = ResultType.LocalLoss; + return; + } + + if (this.remoteSelection == Hand.None) + { + this.result = ResultType.LocalWin; + } + + if (this.localSelection == Hand.Rock) + { + this.result = (this.remoteSelection == Hand.Scissors) ? ResultType.LocalWin : ResultType.LocalLoss; + } + if (this.localSelection == Hand.Paper) + { + this.result = (this.remoteSelection == Hand.Rock) ? ResultType.LocalWin : ResultType.LocalLoss; + } + + if (this.localSelection == Hand.Scissors) + { + this.result = (this.remoteSelection == Hand.Paper) ? ResultType.LocalWin : ResultType.LocalLoss; + } + } + + private Sprite SelectionToSprite(Hand hand) + { + switch (hand) + { + case Hand.None: + break; + case Hand.Rock: + return this.SelectedRock; + case Hand.Paper: + return this.SelectedPaper; + case Hand.Scissors: + return this.SelectedScissors; + } + + return null; + } + + private void UpdatePlayerTexts() + { + PhotonPlayer remote = PhotonNetwork.player.GetNext(); + PhotonPlayer local = PhotonNetwork.player; + + if (remote != null) + { + // should be this format: "name 00" + this.RemotePlayerText.text = remote.NickName + " " + remote.GetScore().ToString("D2"); + } + else + { + + TimerFillImage.anchorMax = new Vector2(0f,1f); + this.TimeText.text = ""; + this.RemotePlayerText.text = "waiting for another player 00"; + } + + if (local != null) + { + // should be this format: "YOU 00" + this.LocalPlayerText.text = "YOU " + local.GetScore().ToString("D2"); + } + } + + public IEnumerator CycleRemoteHandCoroutine() + { + while (true) + { + // cycle through available images + this.randomHand = (Hand)Random.Range(1, 4); + yield return new WaitForSeconds(0.5f); + } + } + + #endregion + + + #region Handling Of Buttons + + public void OnClickRock() + { + this.MakeTurn(Hand.Rock); + } + + public void OnClickPaper() + { + this.MakeTurn(Hand.Paper); + } + + public void OnClickScissors() + { + this.MakeTurn(Hand.Scissors); + } + + public void OnClickConnect() + { + PhotonNetwork.ConnectUsingSettings(null); + PhotonHandler.StopFallbackSendAckThread(); // this is used in the demo to timeout in background! + } + + public void OnClickReConnectAndRejoin() + { + PhotonNetwork.ReconnectAndRejoin(); + PhotonHandler.StopFallbackSendAckThread(); // this is used in the demo to timeout in background! + } + + #endregion + + void RefreshUIViews() + { + TimerFillImage.anchorMax = new Vector2(0f,1f); + + ConnectUiView.gameObject.SetActive(!PhotonNetwork.inRoom); + GameUiView.gameObject.SetActive(PhotonNetwork.inRoom); + + ButtonCanvasGroup.interactable = PhotonNetwork.room!=null?PhotonNetwork.room.PlayerCount > 1:false; + } + + + public override void OnLeftRoom() + { + Debug.Log("OnLeftRoom()"); + + + + RefreshUIViews(); + } + + public override void OnJoinedRoom() + { + RefreshUIViews(); + + if (PhotonNetwork.room.PlayerCount == 2) + { + if (this.turnManager.Turn == 0) + { + // when the room has two players, start the first turn (later on, joining players won't trigger a turn) + this.StartTurn(); + } + } + else + { + Debug.Log("Waiting for another player"); + } + } + + public override void OnPhotonPlayerConnected(PhotonPlayer newPlayer) + { + Debug.Log("Other player arrived"); + + if (PhotonNetwork.room.PlayerCount == 2) + { + if (this.turnManager.Turn == 0) + { + // when the room has two players, start the first turn (later on, joining players won't trigger a turn) + this.StartTurn(); + } + } + } + + + public override void OnPhotonPlayerDisconnected(PhotonPlayer otherPlayer) + { + Debug.Log("Other player disconnected! "+otherPlayer.ToStringFull()); + } + + + public override void OnConnectionFail(DisconnectCause cause) + { + this.DisconnectedPanel.gameObject.SetActive(true); + } + +} diff --git a/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/Scripts/RpsCore.cs.meta b/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/Scripts/RpsCore.cs.meta new file mode 100644 index 0000000..ea85803 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/Scripts/RpsCore.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: e87b80e1402995346ba03f694dd757af +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/Scripts/RpsDebug.cs b/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/Scripts/RpsDebug.cs new file mode 100644 index 0000000..7ada597 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/Scripts/RpsDebug.cs @@ -0,0 +1,27 @@ +using UnityEngine; +using System.Collections; +using UnityEngine.UI; + +public class RpsDebug : MonoBehaviour { + + [SerializeField] + private Button ConnectionDebugButton; + + public bool ShowConnectionDebug; + + + public void ToggleConnectionDebug() + { + ShowConnectionDebug = !ShowConnectionDebug; + } + + public void Update() + { + if (this.ShowConnectionDebug) + { ConnectionDebugButton.GetComponentInChildren().text = PhotonNetwork.connectionStateDetailed.ToString(); } + else + { + ConnectionDebugButton.GetComponentInChildren().text = ""; + } + } +} diff --git a/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/Scripts/RpsDebug.cs.meta b/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/Scripts/RpsDebug.cs.meta new file mode 100644 index 0000000..7b74c57 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/Scripts/RpsDebug.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 47326751a9d474b46a967cb1c614020d +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/Scripts/RpsDemoConnect.cs b/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/Scripts/RpsDemoConnect.cs new file mode 100644 index 0000000..5e39e6d --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/Scripts/RpsDemoConnect.cs @@ -0,0 +1,127 @@ +using Photon; +using UnityEngine; +using UnityEngine.SceneManagement; +using UnityEngine.UI; + +using ExitGames.Client.Photon; + +public class RpsDemoConnect : PunBehaviour +{ + public InputField InputField; + public string UserId; + + string previousRoomPlayerPrefKey = "PUN:Demo:RPS:PreviousRoom"; + public string previousRoom; + + private const string MainSceneName = "DemoRPS-Scene"; + + const string NickNamePlayerPrefsKey = "NickName"; + + + void Start() + { + InputField.text = PlayerPrefs.HasKey(NickNamePlayerPrefsKey)?PlayerPrefs.GetString(NickNamePlayerPrefsKey):""; + } + + public void ApplyUserIdAndConnect() + { + string nickName = "DemoNick"; + if (this.InputField != null && !string.IsNullOrEmpty(this.InputField.text)) + { + nickName = this.InputField.text; + PlayerPrefs.SetString(NickNamePlayerPrefsKey,nickName); + } + //if (string.IsNullOrEmpty(UserId)) + //{ + // this.UserId = nickName + "ID"; + //} + + if (PhotonNetwork.AuthValues == null) + { + PhotonNetwork.AuthValues = new AuthenticationValues(); + } + //else + //{ + // Debug.Log("Re-using AuthValues. UserId: " + PhotonNetwork.AuthValues.UserId); + //} + + + PhotonNetwork.AuthValues.UserId = nickName; + + Debug.Log("Nickname: " + nickName + " userID: " + this.UserId,this); + + + + PhotonNetwork.playerName = nickName; + PhotonNetwork.ConnectUsingSettings("0.5"); + + // this way we can force timeouts by pausing the client (in editor) + PhotonHandler.StopFallbackSendAckThread(); + } + + + public override void OnConnectedToMaster() + { + // after connect + this.UserId = PhotonNetwork.player.UserId; + ////Debug.Log("UserID " + this.UserId); + + if (PlayerPrefs.HasKey(previousRoomPlayerPrefKey)) + { + Debug.Log("getting previous room from prefs: "); + this.previousRoom = PlayerPrefs.GetString(previousRoomPlayerPrefKey); + PlayerPrefs.DeleteKey(previousRoomPlayerPrefKey); // we don't keep this, it was only for initial recovery + } + + + // after timeout: re-join "old" room (if one is known) + if (!string.IsNullOrEmpty(this.previousRoom)) + { + Debug.Log("ReJoining previous room: " + this.previousRoom); + PhotonNetwork.ReJoinRoom(this.previousRoom); + this.previousRoom = null; // we only will try to re-join once. if this fails, we will get into a random/new room + } + else + { + // else: join a random room + PhotonNetwork.JoinRandomRoom(); + } + } + + public override void OnJoinedLobby() + { + OnConnectedToMaster(); // this way, it does not matter if we join a lobby or not + } + + public override void OnPhotonRandomJoinFailed(object[] codeAndMsg) + { + Debug.Log("OnPhotonRandomJoinFailed"); + PhotonNetwork.CreateRoom(null, new RoomOptions() { MaxPlayers = 2, PlayerTtl = 20000 }, null); + } + + public override void OnJoinedRoom() + { + Debug.Log("Joined room: " + PhotonNetwork.room.Name); + this.previousRoom = PhotonNetwork.room.Name; + PlayerPrefs.SetString(previousRoomPlayerPrefKey,this.previousRoom); + + } + + public override void OnPhotonJoinRoomFailed(object[] codeAndMsg) + { + Debug.Log("OnPhotonJoinRoomFailed"); + this.previousRoom = null; + PlayerPrefs.DeleteKey(previousRoomPlayerPrefKey); + } + + public override void OnConnectionFail(DisconnectCause cause) + { + Debug.Log("Disconnected due to: " + cause + ". this.previousRoom: " + this.previousRoom); + } + + public override void OnPhotonPlayerActivityChanged(PhotonPlayer otherPlayer) + { + Debug.Log("OnPhotonPlayerActivityChanged() for "+otherPlayer.NickName+" IsInactive: "+otherPlayer.IsInactive); + } + +} diff --git a/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/Scripts/RpsDemoConnect.cs.meta b/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/Scripts/RpsDemoConnect.cs.meta new file mode 100644 index 0000000..c81dc0a --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoRockPaperScissors/Scripts/RpsDemoConnect.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 1d3ffecc35e562e4ea9047ab293cedd7 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Photon Unity Networking/Demos/DemoSynchronization.meta b/Assets/Photon Unity Networking/Demos/DemoSynchronization.meta new file mode 100644 index 0000000..c7e7e1d --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoSynchronization.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 2b89655b5b2ee4c56ace51fe71be8a49 +folderAsset: yes +timeCreated: 1501014811 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Photon Unity Networking/Demos/DemoSynchronization/CubeExtra.cs b/Assets/Photon Unity Networking/Demos/DemoSynchronization/CubeExtra.cs new file mode 100644 index 0000000..4487233 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoSynchronization/CubeExtra.cs @@ -0,0 +1,81 @@ +// +// This script calculates how fast the object moved between any two consecutive updates. +// Assuming that the movement stays about the same, we can move the local copy of a cube fairly well. +// +// Note that CubeExtra doesn't lag as much as Interpolation. +// Based on what we know as given, we move our cube to a guessed (!) position where it probably is. +// As consequence, you will notice that this "simulation" does overshoot and speed might be higher/lower +// than in the original. +// +// This extrapolation script uses only position updates. This is very lean. +// The controlling client could calculate speed and send that, but it's not needed! +// + + +using UnityEngine; + +[RequireComponent(typeof (PhotonView))] +public class CubeExtra : Photon.MonoBehaviour, IPunObservable +{ + [Range(0.9f, 1.1f)] + public float Factor = 0.98f; // this factor makes the extrapolated movement a bit slower. the idea is to compensate some of the lag-dependent variance. + + // some internal values. see comments below + private Vector3 latestCorrectPos = Vector3.zero; + private Vector3 movementVector = Vector3.zero; + private Vector3 errorVector = Vector3.zero; + private double lastTime = 0; + + + public void Awake() + { + this.latestCorrectPos = transform.position; + } + + + // this method is called by PUN when this script is being "observed" by a PhotonView (setup in inspector) + public void OnPhotonSerializeView(PhotonStream stream, PhotonMessageInfo info) + { + if (stream.isWriting) + { + // the controlling player of a cube sends only the position + Vector3 pos = transform.localPosition; + stream.Serialize(ref pos); + } + else + { + // other players (not controlling this cube) will read the position and timing and calculate everything else based on this + Vector3 updatedLocalPos = Vector3.zero; + stream.Serialize(ref updatedLocalPos); + + double timeDiffOfUpdates = info.timestamp - this.lastTime; // the time that passed after the sender sent it's previous update + this.lastTime = info.timestamp; + + + // the movementVector calculates how far the "original" cube moved since it sent the last update. + // we calculate this based on the sender's timing, so we exclude network lag. that makes our movement smoother. + this.movementVector = (updatedLocalPos - this.latestCorrectPos) / (float)timeDiffOfUpdates; + + // the errorVector is how far our cube is away from the incoming position update. using this corrects errors somewhat, until the next update arrives. + // with this, we don't have to correct our cube's position with a new update (which introduces visible, hard stuttering). + this.errorVector = (updatedLocalPos - transform.localPosition) / (float)timeDiffOfUpdates; + + + // next time we get an update, we need this update's position: + this.latestCorrectPos = updatedLocalPos; + } + } + + + public void Update() + { + if (photonView.isMine) + { + return; // if this object is under our control, we don't need to apply received position-updates + } + + // we move the object, based on the movement it did between the last two updates. + // in addition, we factor in the error between the last correct update we got and our extrapolated position at that time. + transform.localPosition += (this.movementVector + this.errorVector) * this.Factor * Time.deltaTime; + } +} \ No newline at end of file diff --git a/Assets/Photon Unity Networking/Demos/DemoSynchronization/CubeExtra.cs.meta b/Assets/Photon Unity Networking/Demos/DemoSynchronization/CubeExtra.cs.meta new file mode 100644 index 0000000..96c50db --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoSynchronization/CubeExtra.cs.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 0f3dbbefce8d287489545c79a9baf8a0 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} diff --git a/Assets/Photon Unity Networking/Demos/DemoSynchronization/CubeInter.cs b/Assets/Photon Unity Networking/Demos/DemoSynchronization/CubeInter.cs new file mode 100644 index 0000000..79cf97b --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoSynchronization/CubeInter.cs @@ -0,0 +1,144 @@ +// +// This script achieves quite correct movement for remote objects, at the cost of lagging behind. +// +// You can define how much time you voluntarily lag behind via InterpolationDelay. +// This should be more than the lag. +// This script will replay the movement of a cube, based on already received position updates. +// +// Network interpolation is affected by the network sendRate. +// By default this is 10 times/second for OnSerialize. (See PhotonNetwork.sendIntervalOnSerialize) +// Raise the sendrate if you want to lower the interpolationBackTime. +// + +using System; +using UnityEngine; + +[RequireComponent(typeof (PhotonView))] +public class CubeInter : Photon.MonoBehaviour, IPunObservable +{ + internal struct State + { + internal double timestamp; + internal Vector3 pos; + internal Quaternion rot; + } + + // We store twenty states with "playback" information + private State[] m_BufferedState = new State[20]; + + // Keep track of what slots are used + private int m_TimestampCount; + + public double InterpolationDelay = 0.15; + + + public void OnPhotonSerializeView(PhotonStream stream, PhotonMessageInfo info) + { + // Always send transform (depending on reliability of the network view) + if (stream.isWriting) + { + Vector3 pos = transform.localPosition; + Quaternion rot = transform.localRotation; + stream.Serialize(ref pos); + stream.Serialize(ref rot); + stream.SendNext(Environment.TickCount); + } + // When receiving, buffer the information + else + { + + // Receive latest state information + Vector3 pos = Vector3.zero; + Quaternion rot = Quaternion.identity; + stream.Serialize(ref pos); + stream.Serialize(ref rot); + + //int localTimeOfSend = (int)stream.ReceiveNext(); + //Debug.Log("timeDiff" + (Environment.TickCount - localTimeOfSend) + " update age: " + (PhotonNetwork.time - info.timestamp)); + + // Shift buffer contents, oldest data erased, 18 becomes 19, ... , 0 becomes 1 + for (int i = this.m_BufferedState.Length - 1; i >= 1; i--) + { + this.m_BufferedState[i] = this.m_BufferedState[i - 1]; + } + + + // Save currect received state as 0 in the buffer, safe to overwrite after shifting + State state; + state.timestamp = info.timestamp; + state.pos = pos; + state.rot = rot; + this.m_BufferedState[0] = state; + + // Increment state count but never exceed buffer size + this.m_TimestampCount = Mathf.Min(this.m_TimestampCount + 1, this.m_BufferedState.Length); + + // Check integrity, lowest numbered state in the buffer is newest and so on + for (int i = 0; i < this.m_TimestampCount - 1; i++) + { + if (this.m_BufferedState[i].timestamp < this.m_BufferedState[i + 1].timestamp) + { + Debug.Log("State inconsistent"); + } + } + } + } + + + public void Update() + { + if (this.photonView.isMine || !PhotonNetwork.inRoom) + { + return; // if this object is under our control, we don't need to apply received position-updates + } + + double currentTime = PhotonNetwork.time; + double interpolationTime = currentTime - this.InterpolationDelay; + + // We have a window of InterpolationDelay where we basically play back old updates. + // By having InterpolationDelay the average ping, you will usually use interpolation. + // And only if no more data arrives we will use the latest known position. + + // Use interpolation, if the interpolated time is still "behind" the update timestamp time: + if (this.m_BufferedState[0].timestamp > interpolationTime) + { + for (int i = 0; i < this.m_TimestampCount; i++) + { + // Find the state which matches the interpolation time (time+0.1) or use last state + if (this.m_BufferedState[i].timestamp <= interpolationTime || i == this.m_TimestampCount - 1) + { + // The state one slot newer (<100ms) than the best playback state + State rhs = this.m_BufferedState[Mathf.Max(i - 1, 0)]; + // The best playback state (closest to 100 ms old (default time)) + State lhs = this.m_BufferedState[i]; + + // Use the time between the two slots to determine if interpolation is necessary + double diffBetweenUpdates = rhs.timestamp - lhs.timestamp; + float t = 0.0F; + // As the time difference gets closer to 100 ms t gets closer to 1 in + // which case rhs is only used + if (diffBetweenUpdates > 0.0001) + { + t = (float)((interpolationTime - lhs.timestamp)/diffBetweenUpdates); + } + + // if t=0 => lhs is used directly + transform.localPosition = Vector3.Lerp(lhs.pos, rhs.pos, t); + transform.localRotation = Quaternion.Slerp(lhs.rot, rhs.rot, t); + return; + } + } + } + else + { + // If our interpolation time catched up with the time of the latest update: + // Simply move to the latest known position. + + //Debug.Log("Lerping!"); + State latest = this.m_BufferedState[0]; + + transform.localPosition = Vector3.Lerp(transform.localPosition, latest.pos, Time.deltaTime*20); + transform.localRotation = latest.rot; + } + } +} \ No newline at end of file diff --git a/Assets/Photon Unity Networking/Demos/DemoSynchronization/CubeInter.cs.meta b/Assets/Photon Unity Networking/Demos/DemoSynchronization/CubeInter.cs.meta new file mode 100644 index 0000000..3f04c65 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoSynchronization/CubeInter.cs.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: aa368a4b347123d4db25f8f4faebf1ef +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} diff --git a/Assets/Photon Unity Networking/Demos/DemoSynchronization/CubeLerp.cs b/Assets/Photon Unity Networking/Demos/DemoSynchronization/CubeLerp.cs new file mode 100644 index 0000000..cdcb493 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoSynchronization/CubeLerp.cs @@ -0,0 +1,74 @@ +// +// A (very) simple network interpolation script, using Lerp(). +// +// This will lag-behind, compared to the moving cube on the controlling client. +// Actually, we deliberately lag behing a bit more, to avoid stops, if updates arrive late. +// +// This script does not hide loss very well and might stop the local cube. +// + +using UnityEngine; + +[RequireComponent(typeof (PhotonView))] +public class CubeLerp : Photon.MonoBehaviour, IPunObservable +{ + private Vector3 latestCorrectPos; + private Vector3 onUpdatePos; + private float fraction; + + + public void Start() + { + this.latestCorrectPos = transform.position; + this.onUpdatePos = transform.position; + } + + + public void OnPhotonSerializeView(PhotonStream stream, PhotonMessageInfo info) + { + if (stream.isWriting) + { + Vector3 pos = transform.localPosition; + Quaternion rot = transform.localRotation; + stream.Serialize(ref pos); + stream.Serialize(ref rot); + } + else + { + // Receive latest state information + Vector3 pos = Vector3.zero; + Quaternion rot = Quaternion.identity; + + stream.Serialize(ref pos); + stream.Serialize(ref rot); + + this.latestCorrectPos = pos; // save this to move towards it in FixedUpdate() + this.onUpdatePos = transform.localPosition; // we interpolate from here to latestCorrectPos + this.fraction = 0; // reset the fraction we alreay moved. see Update() + + transform.localRotation = rot; // this sample doesn't smooth rotation + } + } + + + public void Update() + { + if (this.photonView.isMine) + { + return; // if this object is under our control, we don't need to apply received position-updates + } + + // We get 10 updates per sec. Sometimes a few less or one or two more, depending on variation of lag. + // Due to that we want to reach the correct position in a little over 100ms. We get a new update then. + // This way, we can usually avoid a stop of our interpolated cube movement. + // + // Lerp() gets a fraction value between 0 and 1. This is how far we went from A to B. + // + // So in 100 ms, we want to move from our previous position to the latest known. + // Our fraction variable should reach 1 in 100ms, so we should multiply deltaTime by 10. + // We want it to take a bit longer, so we multiply with 9 instead! + + this.fraction = this.fraction + Time.deltaTime * 9; + transform.localPosition = Vector3.Lerp(this.onUpdatePos, this.latestCorrectPos, this.fraction); // set our pos between A and B + } +} \ No newline at end of file diff --git a/Assets/Photon Unity Networking/Demos/DemoSynchronization/CubeLerp.cs.meta b/Assets/Photon Unity Networking/Demos/DemoSynchronization/CubeLerp.cs.meta new file mode 100644 index 0000000..dcefed2 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoSynchronization/CubeLerp.cs.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 121cb4d5de47e0d4d95fee07b40d35ee +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} diff --git a/Assets/Photon Unity Networking/Demos/DemoSynchronization/DemoSynchronization-Scene.unity b/Assets/Photon Unity Networking/Demos/DemoSynchronization/DemoSynchronization-Scene.unity new file mode 100644 index 0000000..6ed9516 Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/DemoSynchronization/DemoSynchronization-Scene.unity differ diff --git a/Assets/Photon Unity Networking/Demos/DemoSynchronization/DemoSynchronization-Scene.unity.meta b/Assets/Photon Unity Networking/Demos/DemoSynchronization/DemoSynchronization-Scene.unity.meta new file mode 100644 index 0000000..578f51d --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoSynchronization/DemoSynchronization-Scene.unity.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: caec1ee6e27780946b8db3d1aebaa478 diff --git a/Assets/Photon Unity Networking/Demos/DemoSynchronization/DragToMove.cs b/Assets/Photon Unity Networking/Demos/DemoSynchronization/DragToMove.cs new file mode 100644 index 0000000..28d3fbb --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoSynchronization/DragToMove.cs @@ -0,0 +1,121 @@ +using System.Collections.Generic; +using ExitGames.Client.Photon; +using UnityEngine; +using System.Collections; +using Hashtable = ExitGames.Client.Photon.Hashtable; + + +/// +/// This component can be used to move objects along a path. Optionally, the path can be updated by +/// +public class DragToMove : MonoBehaviour +{ + public float speed = 5.0f; + public Transform[] cubes; + public List PositionsQueue = new List(20); + + private Vector3[] cubeStartPositions; + private int nextPosIndex = 0; + private float lerpTime = 0.0f; + + private bool recording; + + + /// + /// Initializes the positioning of the objects-to-move. + /// + public void Start() + { + // per object-to-move, we get the initial (position) offset, so we can move each object to a slightly separate position on the path. + this.cubeStartPositions = new Vector3[this.cubes.Length]; + for (int i = 0; i < this.cubes.Length; i++) + { + Transform cube = this.cubes[i]; + this.cubeStartPositions[i] = cube.position; + } + } + + + /// + /// This actually moves the objects along a defined path (unless a new path is being recorded). + /// + public void Update() + { + if (!PhotonNetwork.isMasterClient) + { + return; // only the Master Client can define the path + } + + if (recording) + { + return; + } + + if (Input.GetMouseButtonDown(0) || Input.touchCount > 0) + { + StartCoroutine("RecordMouse"); + return; + } + + if (PositionsQueue.Count == 0) + { + return; + } + + + Vector3 targetPos = PositionsQueue[nextPosIndex]; + + int prevPosIndex = this.nextPosIndex > 0 ? this.nextPosIndex - 1 : PositionsQueue.Count-1; + Vector3 prevPos = PositionsQueue[prevPosIndex]; + lerpTime = lerpTime+Time.deltaTime * speed; + + for (int i = 0; i < this.cubes.Length; i++) + { + Transform cube = this.cubes[i]; + + Vector3 cubeTargetPos = targetPos + this.cubeStartPositions[i]; + Vector3 cubePrevPos = prevPos + this.cubeStartPositions[i]; + + cube.transform.position = Vector3.Lerp(cubePrevPos, cubeTargetPos, lerpTime); + } + if (lerpTime > 1.0f) + { + nextPosIndex = (nextPosIndex + 1) % this.PositionsQueue.Count; + lerpTime = 0.0f; + } + } + + /// + /// Coroutine to record a path. Either records mouse- or touch-positions while (button) pressed. + /// + public IEnumerator RecordMouse() + { + recording = true; + PositionsQueue.Clear(); + + while (Input.GetMouseButton(0) || Input.touchCount > 0) + { + yield return new WaitForSeconds(0.1f); + + + Vector3 v3 = Input.mousePosition; + if (Input.touchCount > 0) + { + // if we have touch input, we use that instead of mouse + v3 = Input.GetTouch(0).position; + } + + + Ray inputRay = Camera.main.ScreenPointToRay(v3); + RaycastHit hit; + if (Physics.Raycast(inputRay, out hit)) + { + PositionsQueue.Add(hit.point); + } + } + + nextPosIndex = 0; + recording = false; + } + +} diff --git a/Assets/Photon Unity Networking/Demos/DemoSynchronization/DragToMove.cs.meta b/Assets/Photon Unity Networking/Demos/DemoSynchronization/DragToMove.cs.meta new file mode 100644 index 0000000..0902a76 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoSynchronization/DragToMove.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 2f35fdc59699923429c39a7d79d475dc +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Photon Unity Networking/Demos/DemoSynchronization/IELdemo.cs b/Assets/Photon Unity Networking/Demos/DemoSynchronization/IELdemo.cs new file mode 100644 index 0000000..984e8de --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoSynchronization/IELdemo.cs @@ -0,0 +1,48 @@ +using ExitGames.Client.Photon; +using UnityEngine; +using System.Collections; +using Hashtable = ExitGames.Client.Photon.Hashtable; + +/// +/// A minimal UI to show connection info in a demo. +/// +public class IELdemo : MonoBehaviour +{ + public GUISkin Skin; + + public void OnGUI() + { + if (this.Skin != null) + { + GUI.skin = this.Skin; + } + + if (PhotonNetwork.isMasterClient) + { + GUILayout.Label("Controlling client.\nPing: " + PhotonNetwork.GetPing()); + if (GUILayout.Button("disconnect", GUILayout.ExpandWidth(false))) + { + PhotonNetwork.Disconnect(); + } + } + else if (PhotonNetwork.isNonMasterClientInRoom) + { + GUILayout.Label("Receiving updates.\nPing: " + PhotonNetwork.GetPing()); + if (GUILayout.Button("disconnect", GUILayout.ExpandWidth(false))) + { + PhotonNetwork.Disconnect(); + } + } + else + { + GUILayout.Label("Not in room yet\n" + PhotonNetwork.connectionStateDetailed); + } + if (!PhotonNetwork.connected && !PhotonNetwork.connecting) + { + if (GUILayout.Button("connect", GUILayout.Width(80))) + { + PhotonNetwork.ConnectUsingSettings(null); // using null as parameter, re-uses previously set version. + } + } + } +} diff --git a/Assets/Photon Unity Networking/Demos/DemoSynchronization/IELdemo.cs.meta b/Assets/Photon Unity Networking/Demos/DemoSynchronization/IELdemo.cs.meta new file mode 100644 index 0000000..9378ab4 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoSynchronization/IELdemo.cs.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 74bd508a38b163e4b8138657cdb3ff5b +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} diff --git a/Assets/Photon Unity Networking/Demos/DemoSynchronization/MatCubeExtra.mat b/Assets/Photon Unity Networking/Demos/DemoSynchronization/MatCubeExtra.mat new file mode 100644 index 0000000..2494c2e Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/DemoSynchronization/MatCubeExtra.mat differ diff --git a/Assets/Photon Unity Networking/Demos/DemoSynchronization/MatCubeExtra.mat.meta b/Assets/Photon Unity Networking/Demos/DemoSynchronization/MatCubeExtra.mat.meta new file mode 100644 index 0000000..7380837 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoSynchronization/MatCubeExtra.mat.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: 9f1129974630774409da4274a848e31e +NativeFormatImporter: + userData: diff --git a/Assets/Photon Unity Networking/Demos/DemoSynchronization/MatCubeInter.mat b/Assets/Photon Unity Networking/Demos/DemoSynchronization/MatCubeInter.mat new file mode 100644 index 0000000..65f72e4 Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/DemoSynchronization/MatCubeInter.mat differ diff --git a/Assets/Photon Unity Networking/Demos/DemoSynchronization/MatCubeInter.mat.meta b/Assets/Photon Unity Networking/Demos/DemoSynchronization/MatCubeInter.mat.meta new file mode 100644 index 0000000..a022350 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoSynchronization/MatCubeInter.mat.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: 14ed06ac0127c154589d77e354a9dbd1 +NativeFormatImporter: + userData: diff --git a/Assets/Photon Unity Networking/Demos/DemoSynchronization/MatCubeLerp.mat b/Assets/Photon Unity Networking/Demos/DemoSynchronization/MatCubeLerp.mat new file mode 100644 index 0000000..49a36dd Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/DemoSynchronization/MatCubeLerp.mat differ diff --git a/Assets/Photon Unity Networking/Demos/DemoSynchronization/MatCubeLerp.mat.meta b/Assets/Photon Unity Networking/Demos/DemoSynchronization/MatCubeLerp.mat.meta new file mode 100644 index 0000000..7d068d2 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoSynchronization/MatCubeLerp.mat.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: c3b3cff6cfe342241a7c288b16235032 +NativeFormatImporter: + userData: diff --git a/Assets/Photon Unity Networking/Demos/DemoSynchronization/MatCubeTrans.mat b/Assets/Photon Unity Networking/Demos/DemoSynchronization/MatCubeTrans.mat new file mode 100644 index 0000000..27a34e0 Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/DemoSynchronization/MatCubeTrans.mat differ diff --git a/Assets/Photon Unity Networking/Demos/DemoSynchronization/MatCubeTrans.mat.meta b/Assets/Photon Unity Networking/Demos/DemoSynchronization/MatCubeTrans.mat.meta new file mode 100644 index 0000000..8516444 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoSynchronization/MatCubeTrans.mat.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: 2785b9b4734344844824f624d27da703 +NativeFormatImporter: + userData: diff --git a/Assets/Photon Unity Networking/Demos/DemoSynchronization/MatCubeView.mat b/Assets/Photon Unity Networking/Demos/DemoSynchronization/MatCubeView.mat new file mode 100644 index 0000000..55b8d40 Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/DemoSynchronization/MatCubeView.mat differ diff --git a/Assets/Photon Unity Networking/Demos/DemoSynchronization/MatCubeView.mat.meta b/Assets/Photon Unity Networking/Demos/DemoSynchronization/MatCubeView.mat.meta new file mode 100644 index 0000000..25da9bb --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoSynchronization/MatCubeView.mat.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: 3d0155f08a6886349aefc09c21a2d7cf +NativeFormatImporter: + userData: diff --git a/Assets/Photon Unity Networking/Demos/DemoWorker.meta b/Assets/Photon Unity Networking/Demos/DemoWorker.meta new file mode 100644 index 0000000..a052591 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoWorker.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 36a6e82a85d1e40d5b033a457832dc58 +folderAsset: yes +timeCreated: 1501014811 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Photon Unity Networking/Demos/DemoWorker/Art.meta b/Assets/Photon Unity Networking/Demos/DemoWorker/Art.meta new file mode 100644 index 0000000..6e0d397 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoWorker/Art.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 07b17bc2c84244b20872977ddb006fad +folderAsset: yes +timeCreated: 1501014811 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Photon Unity Networking/Demos/DemoWorker/Art/Character Controllers.meta b/Assets/Photon Unity Networking/Demos/DemoWorker/Art/Character Controllers.meta new file mode 100644 index 0000000..59fdb5b --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoWorker/Art/Character Controllers.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 81ccb9f854cde4507a612134a11d05b3 +folderAsset: yes +timeCreated: 1501014812 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Photon Unity Networking/Demos/DemoWorker/Art/Character Controllers/Sources.meta b/Assets/Photon Unity Networking/Demos/DemoWorker/Art/Character Controllers/Sources.meta new file mode 100644 index 0000000..7c7a73d --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoWorker/Art/Character Controllers/Sources.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 543161a275c4e417da678962490580de +folderAsset: yes +timeCreated: 1501014812 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Photon Unity Networking/Demos/DemoWorker/Art/Character Controllers/Sources/PrototypeCharacter.meta b/Assets/Photon Unity Networking/Demos/DemoWorker/Art/Character Controllers/Sources/PrototypeCharacter.meta new file mode 100644 index 0000000..6c1a84d --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoWorker/Art/Character Controllers/Sources/PrototypeCharacter.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 0c0e7ea7ba8c749cea2b335d7895855a +folderAsset: yes +timeCreated: 1501014812 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Photon Unity Networking/Demos/DemoWorker/Art/Character Controllers/Sources/PrototypeCharacter/Constructor.FBX b/Assets/Photon Unity Networking/Demos/DemoWorker/Art/Character Controllers/Sources/PrototypeCharacter/Constructor.FBX new file mode 100644 index 0000000..b3ee8f3 Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/DemoWorker/Art/Character Controllers/Sources/PrototypeCharacter/Constructor.FBX differ diff --git a/Assets/Photon Unity Networking/Demos/DemoWorker/Art/Character Controllers/Sources/PrototypeCharacter/Constructor.FBX.meta b/Assets/Photon Unity Networking/Demos/DemoWorker/Art/Character Controllers/Sources/PrototypeCharacter/Constructor.FBX.meta new file mode 100644 index 0000000..051163e --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoWorker/Art/Character Controllers/Sources/PrototypeCharacter/Constructor.FBX.meta @@ -0,0 +1,489 @@ +fileFormatVersion: 2 +guid: 449b48f7eb5d87a4baaa5fb73f875a59 +ModelImporter: + fileIDToRecycleName: + 4300000: construction_worker + 4300002: wrench + 7400000: Take 001 //// ConstructorDummy + 7400002: idle //// ConstructorDummy + 7400004: run //// ConstructorDummy + 7400006: idle0 //// ConstructorDummy + 7400008: walk //// ConstructorDummy + 7400010: jump_pose //// ConstructorDummy + 7400012: idle //// Constructor + 7400014: run //// Constructor + 7400016: walk //// Constructor + 7400018: jump_pose //// Constructor + 100100000: DataTemplate __Singleton__ + serializedVersion: 10 + materials: + importMaterials: 1 + materialName: 3 + materialSearch: 1 + animations: + generateAnimations: 3 + bakeSimulation: 0 + splitAnimations: 1 + animationCompression: 0 + animationRotationError: .5 + animationPositionError: .5 + animationScaleError: .5 + animationWrapMode: 0 + clipAnimations: + - name: idle + firstFrame: 2 + lastFrame: 62 + wrapMode: 2 + loop: 0 + - name: run + firstFrame: 65 + lastFrame: 81 + wrapMode: 2 + loop: 0 + - name: walk + firstFrame: 84 + lastFrame: 116 + wrapMode: 2 + loop: 0 + - name: jump_pose + firstFrame: 118 + lastFrame: 123 + wrapMode: 0 + loop: 0 + meshes: + lODScreenPercentages: [] + globalScale: .00999999978 + meshCompression: 0 + addColliders: 0 + swapUVChannels: 0 + generateSecondaryUV: 0 + useFileUnits: 1 + optimizeMesh: 0 + secondaryUVAngleDistortion: 8 + secondaryUVAreaDistortion: 15.000001 + secondaryUVHardAngle: 88 + secondaryUVPackMargin: 4 + tangentSpace: + normalSmoothAngle: 60 + splitTangentsAcrossUV: 1 + normalImportMode: 0 + tangentImportMode: 1 + textMetaNamesToFileIDs: + //RootNode: + data: + first: 1 + second: d4860100 + data: + first: 4 + second: b41a0600 + data: + first: 111 + second: 605fa900 + Bip001: + data: + first: 1 + second: 2c870100 + data: + first: 4 + second: 0c1b0600 + Bip001 Head: + data: + first: 1 + second: 1c870100 + data: + first: 4 + second: fc1a0600 + Bip001 L Calf: + data: + first: 1 + second: 14870100 + data: + first: 4 + second: f41a0600 + Bip001 L Clavicle: + data: + first: 1 + second: 04870100 + data: + first: 4 + second: e41a0600 + Bip001 L Finger0: + data: + first: 1 + second: fc860100 + data: + first: 4 + second: dc1a0600 + Bip001 L Finger01: + data: + first: 1 + second: fe860100 + data: + first: 4 + second: de1a0600 + Bip001 L Finger02: + data: + first: 1 + second: ec860100 + data: + first: 4 + second: cc1a0600 + Bip001 L Finger1: + data: + first: 1 + second: f0860100 + data: + first: 4 + second: d01a0600 + Bip001 L Finger11: + data: + first: 1 + second: f2860100 + data: + first: 4 + second: d21a0600 + Bip001 L Finger12: + data: + first: 1 + second: f4860100 + data: + first: 4 + second: d41a0600 + Bip001 L Finger2: + data: + first: 1 + second: f8860100 + data: + first: 4 + second: d81a0600 + Bip001 L Finger21: + data: + first: 1 + second: fa860100 + data: + first: 4 + second: da1a0600 + Bip001 L Finger22: + data: + first: 1 + second: ea860100 + data: + first: 4 + second: ca1a0600 + Bip001 L Finger3: + data: + first: 1 + second: da860100 + data: + first: 4 + second: ba1a0600 + Bip001 L Finger31: + data: + first: 1 + second: dc860100 + data: + first: 4 + second: bc1a0600 + Bip001 L Finger32: + data: + first: 1 + second: de860100 + data: + first: 4 + second: be1a0600 + Bip001 L Finger4: + data: + first: 1 + second: e2860100 + data: + first: 4 + second: c21a0600 + Bip001 L Finger41: + data: + first: 1 + second: e4860100 + data: + first: 4 + second: c41a0600 + Bip001 L Finger42: + data: + first: 1 + second: e6860100 + data: + first: 4 + second: c61a0600 + Bip001 L Foot: + data: + first: 1 + second: 12870100 + data: + first: 4 + second: f21a0600 + Bip001 L Forearm: + data: + first: 1 + second: 00870100 + data: + first: 4 + second: e01a0600 + Bip001 L Hand: + data: + first: 1 + second: 22870100 + data: + first: 4 + second: 021b0600 + Bip001 L Thigh: + data: + first: 1 + second: 16870100 + data: + first: 4 + second: f61a0600 + Bip001 L Toe0: + data: + first: 1 + second: 10870100 + data: + first: 4 + second: f01a0600 + Bip001 L UpperArm: + data: + first: 1 + second: 02870100 + data: + first: 4 + second: e21a0600 + Bip001 Neck: + data: + first: 1 + second: 24870100 + data: + first: 4 + second: 041b0600 + Bip001 Pelvis: + data: + first: 1 + second: 2a870100 + data: + first: 4 + second: 0a1b0600 + data: + first: 137 + second: a00bd100 + Bip001 R Calf: + data: + first: 1 + second: 0c870100 + data: + first: 4 + second: ec1a0600 + Bip001 R Clavicle: + data: + first: 1 + second: d6860100 + data: + first: 4 + second: b61a0600 + Bip001 R Finger0: + data: + first: 1 + second: cc860100 + data: + first: 4 + second: ac1a0600 + Bip001 R Finger01: + data: + first: 1 + second: ce860100 + data: + first: 4 + second: ae1a0600 + Bip001 R Finger02: + data: + first: 1 + second: a6860100 + data: + first: 4 + second: 861a0600 + Bip001 R Finger1: + data: + first: 1 + second: a0860100 + data: + first: 4 + second: 801a0600 + Bip001 R Finger11: + data: + first: 1 + second: a4860100 + data: + first: 4 + second: 841a0600 + Bip001 R Finger12: + data: + first: 1 + second: aa860100 + data: + first: 4 + second: 8a1a0600 + Bip001 R Finger2: + data: + first: 1 + second: c2860100 + data: + first: 4 + second: a21a0600 + Bip001 R Finger21: + data: + first: 1 + second: a2860100 + data: + first: 4 + second: 821a0600 + Bip001 R Finger22: + data: + first: 1 + second: c4860100 + data: + first: 4 + second: a41a0600 + Bip001 R Finger3: + data: + first: 1 + second: b6860100 + data: + first: 4 + second: 961a0600 + Bip001 R Finger31: + data: + first: 1 + second: b4860100 + data: + first: 4 + second: 941a0600 + Bip001 R Finger32: + data: + first: 1 + second: b2860100 + data: + first: 4 + second: 921a0600 + Bip001 R Finger4: + data: + first: 1 + second: ae860100 + data: + first: 4 + second: 8e1a0600 + Bip001 R Finger41: + data: + first: 1 + second: ac860100 + data: + first: 4 + second: 8c1a0600 + Bip001 R Finger42: + data: + first: 1 + second: bc860100 + data: + first: 4 + second: 9c1a0600 + Bip001 R Foot: + data: + first: 1 + second: 0a870100 + data: + first: 4 + second: ea1a0600 + Bip001 R Forearm: + data: + first: 1 + second: ca860100 + data: + first: 4 + second: aa1a0600 + Bip001 R Hand: + data: + first: 1 + second: 20870100 + data: + first: 4 + second: 001b0600 + Bip001 R Thigh: + data: + first: 1 + second: 0e870100 + data: + first: 4 + second: ee1a0600 + Bip001 R Toe0: + data: + first: 1 + second: 08870100 + data: + first: 4 + second: e81a0600 + Bip001 R UpperArm: + data: + first: 1 + second: c8860100 + data: + first: 4 + second: a81a0600 + Bip001 Spine: + data: + first: 1 + second: 28870100 + data: + first: 4 + second: 081b0600 + Bip001 Spine1: + data: + first: 1 + second: 26870100 + data: + first: 4 + second: 061b0600 + construction_worker: + data: + first: 1 + second: 06870100 + data: + first: 4 + second: e61a0600 + helmet_bone: + data: + first: 1 + second: 18870100 + data: + first: 4 + second: f81a0600 + hip_adjustment_bone_left: + data: + first: 1 + second: c0860100 + data: + first: 4 + second: a01a0600 + hip_adjustment_bone_right: + data: + first: 1 + second: ba860100 + data: + first: 4 + second: 9a1a0600 + wrench: + data: + first: 1 + second: 1e870100 + data: + first: 4 + second: fe1a0600 + data: + first: 23 + second: 60182300 + data: + first: 33 + second: a05a3200 diff --git a/Assets/Photon Unity Networking/Demos/DemoWorker/Art/Character Controllers/Sources/PrototypeCharacter/Materials.meta b/Assets/Photon Unity Networking/Demos/DemoWorker/Art/Character Controllers/Sources/PrototypeCharacter/Materials.meta new file mode 100644 index 0000000..a9a00fa --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoWorker/Art/Character Controllers/Sources/PrototypeCharacter/Materials.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 33db7b32d265748389cbdd1bdccbe7c3 +folderAsset: yes +timeCreated: 1501014812 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Photon Unity Networking/Demos/DemoWorker/Art/Character Controllers/Sources/PrototypeCharacter/Materials/constructor_done.mat b/Assets/Photon Unity Networking/Demos/DemoWorker/Art/Character Controllers/Sources/PrototypeCharacter/Materials/constructor_done.mat new file mode 100644 index 0000000..9b8dff8 Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/DemoWorker/Art/Character Controllers/Sources/PrototypeCharacter/Materials/constructor_done.mat differ diff --git a/Assets/Photon Unity Networking/Demos/DemoWorker/Art/Character Controllers/Sources/PrototypeCharacter/Materials/constructor_done.mat.meta b/Assets/Photon Unity Networking/Demos/DemoWorker/Art/Character Controllers/Sources/PrototypeCharacter/Materials/constructor_done.mat.meta new file mode 100644 index 0000000..1fdf3ab --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoWorker/Art/Character Controllers/Sources/PrototypeCharacter/Materials/constructor_done.mat.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: ca49380a71a2bb64c830d06bd421b9d1 diff --git a/Assets/Photon Unity Networking/Demos/DemoWorker/Art/Character Controllers/Sources/PrototypeCharacter/Textures.meta b/Assets/Photon Unity Networking/Demos/DemoWorker/Art/Character Controllers/Sources/PrototypeCharacter/Textures.meta new file mode 100644 index 0000000..07019ec --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoWorker/Art/Character Controllers/Sources/PrototypeCharacter/Textures.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 109a6afb84ba940889345946496699cf +folderAsset: yes +timeCreated: 1501014812 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Photon Unity Networking/Demos/DemoWorker/Art/Character Controllers/Sources/PrototypeCharacter/Textures/constructor_diffuse.png b/Assets/Photon Unity Networking/Demos/DemoWorker/Art/Character Controllers/Sources/PrototypeCharacter/Textures/constructor_diffuse.png new file mode 100644 index 0000000..59fef90 Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/DemoWorker/Art/Character Controllers/Sources/PrototypeCharacter/Textures/constructor_diffuse.png differ diff --git a/Assets/Photon Unity Networking/Demos/DemoWorker/Art/Character Controllers/Sources/PrototypeCharacter/Textures/constructor_diffuse.png.meta b/Assets/Photon Unity Networking/Demos/DemoWorker/Art/Character Controllers/Sources/PrototypeCharacter/Textures/constructor_diffuse.png.meta new file mode 100644 index 0000000..6df8d93 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoWorker/Art/Character Controllers/Sources/PrototypeCharacter/Textures/constructor_diffuse.png.meta @@ -0,0 +1,33 @@ +fileFormatVersion: 2 +guid: 97b050d43ac7c4d2b9f6cbb587650761 +TextureImporter: + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + linearTexture: 0 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + textureFormat: -1 + maxTextureSize: 1024 + textureSettings: + filterMode: -1 + aniso: -1 + mipBias: -1 + wrapMode: -1 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + textureType: -1 + buildTargetSettings: [] diff --git a/Assets/Photon Unity Networking/Demos/DemoWorker/Art/Character Controllers/Sources/PrototypeCharacter/Textures/constructor_normals.png b/Assets/Photon Unity Networking/Demos/DemoWorker/Art/Character Controllers/Sources/PrototypeCharacter/Textures/constructor_normals.png new file mode 100644 index 0000000..b312669 Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/DemoWorker/Art/Character Controllers/Sources/PrototypeCharacter/Textures/constructor_normals.png differ diff --git a/Assets/Photon Unity Networking/Demos/DemoWorker/Art/Character Controllers/Sources/PrototypeCharacter/Textures/constructor_normals.png.meta b/Assets/Photon Unity Networking/Demos/DemoWorker/Art/Character Controllers/Sources/PrototypeCharacter/Textures/constructor_normals.png.meta new file mode 100644 index 0000000..a8d8e3f --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoWorker/Art/Character Controllers/Sources/PrototypeCharacter/Textures/constructor_normals.png.meta @@ -0,0 +1,33 @@ +fileFormatVersion: 2 +guid: 531c14f8d5cdc4e5baa83ee6e16f783a +TextureImporter: + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + linearTexture: 1 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 1 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + textureFormat: -1 + maxTextureSize: 1024 + textureSettings: + filterMode: -1 + aniso: -1 + mipBias: -1 + wrapMode: -1 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + textureType: 1 + buildTargetSettings: [] diff --git a/Assets/Photon Unity Networking/Demos/DemoWorker/Art/Simple.png b/Assets/Photon Unity Networking/Demos/DemoWorker/Art/Simple.png new file mode 100644 index 0000000..d25adcb Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/DemoWorker/Art/Simple.png differ diff --git a/Assets/Photon Unity Networking/Demos/DemoWorker/Art/Simple.png.meta b/Assets/Photon Unity Networking/Demos/DemoWorker/Art/Simple.png.meta new file mode 100644 index 0000000..ced144f --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoWorker/Art/Simple.png.meta @@ -0,0 +1,33 @@ +fileFormatVersion: 2 +guid: 63208023146d7db48808272f2547b257 +TextureImporter: + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + linearTexture: 0 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + textureFormat: -1 + maxTextureSize: 512 + textureSettings: + filterMode: 2 + aniso: 5 + mipBias: -1 + wrapMode: -1 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + textureType: 0 + buildTargetSettings: [] diff --git a/Assets/Photon Unity Networking/Demos/DemoWorker/Art/SimpleMaterial.mat b/Assets/Photon Unity Networking/Demos/DemoWorker/Art/SimpleMaterial.mat new file mode 100644 index 0000000..46960c4 Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/DemoWorker/Art/SimpleMaterial.mat differ diff --git a/Assets/Photon Unity Networking/Demos/DemoWorker/Art/SimpleMaterial.mat.meta b/Assets/Photon Unity Networking/Demos/DemoWorker/Art/SimpleMaterial.mat.meta new file mode 100644 index 0000000..51949b2 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoWorker/Art/SimpleMaterial.mat.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 4b1c7167fbb213a4dab343997dde0961 diff --git a/Assets/Photon Unity Networking/Demos/DemoWorker/DemoWorker-Scene.unity b/Assets/Photon Unity Networking/Demos/DemoWorker/DemoWorker-Scene.unity new file mode 100644 index 0000000..5266806 Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/DemoWorker/DemoWorker-Scene.unity differ diff --git a/Assets/Photon Unity Networking/Demos/DemoWorker/DemoWorker-Scene.unity.meta b/Assets/Photon Unity Networking/Demos/DemoWorker/DemoWorker-Scene.unity.meta new file mode 100644 index 0000000..1d06708 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoWorker/DemoWorker-Scene.unity.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 2 +guid: d127e961917b252458a9910af185709e +labels: +- ExitGames +- PUN diff --git a/Assets/Photon Unity Networking/Demos/DemoWorker/DemoWorkerGame-Scene.unity b/Assets/Photon Unity Networking/Demos/DemoWorker/DemoWorkerGame-Scene.unity new file mode 100644 index 0000000..28fd0ae Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/DemoWorker/DemoWorkerGame-Scene.unity differ diff --git a/Assets/Photon Unity Networking/Demos/DemoWorker/DemoWorkerGame-Scene.unity.meta b/Assets/Photon Unity Networking/Demos/DemoWorker/DemoWorkerGame-Scene.unity.meta new file mode 100644 index 0000000..5cf1815 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoWorker/DemoWorkerGame-Scene.unity.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: b2b4086771d6a0e4cab81261c6e6c4f9 diff --git a/Assets/Photon Unity Networking/Demos/DemoWorker/Resources.meta b/Assets/Photon Unity Networking/Demos/DemoWorker/Resources.meta new file mode 100644 index 0000000..3debfa6 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoWorker/Resources.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 155d7c6fed8cb4ecdb3bc6c5d9ed3b73 +folderAsset: yes +timeCreated: 1501014811 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Photon Unity Networking/Demos/DemoWorker/Resources/Player.prefab b/Assets/Photon Unity Networking/Demos/DemoWorker/Resources/Player.prefab new file mode 100644 index 0000000..847af6a Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/DemoWorker/Resources/Player.prefab differ diff --git a/Assets/Photon Unity Networking/Demos/DemoWorker/Resources/Player.prefab.meta b/Assets/Photon Unity Networking/Demos/DemoWorker/Resources/Player.prefab.meta new file mode 100644 index 0000000..15a575f --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoWorker/Resources/Player.prefab.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 5fa239dc902776240b919279dd6748f5 diff --git a/Assets/Photon Unity Networking/Demos/DemoWorker/Scripts.meta b/Assets/Photon Unity Networking/Demos/DemoWorker/Scripts.meta new file mode 100644 index 0000000..8e541c3 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoWorker/Scripts.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: d4df1086415ba4b7897a667312814145 +folderAsset: yes +timeCreated: 1501014812 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Photon Unity Networking/Demos/DemoWorker/Scripts/Game.meta b/Assets/Photon Unity Networking/Demos/DemoWorker/Scripts/Game.meta new file mode 100644 index 0000000..04caaf7 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoWorker/Scripts/Game.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 58492e40aa34b4e70b0d6bf615cc9217 +folderAsset: yes +timeCreated: 1501014812 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Photon Unity Networking/Demos/DemoWorker/Scripts/Game/Player.meta b/Assets/Photon Unity Networking/Demos/DemoWorker/Scripts/Game/Player.meta new file mode 100644 index 0000000..e2c7113 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoWorker/Scripts/Game/Player.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 01d8c1469a7c34a45b65aed0b41de56f +folderAsset: yes +timeCreated: 1501014812 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Photon Unity Networking/Demos/DemoWorker/Scripts/Game/Player/ThirdPersonCamera.cs b/Assets/Photon Unity Networking/Demos/DemoWorker/Scripts/Game/Player/ThirdPersonCamera.cs new file mode 100644 index 0000000..3a7ac3d --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoWorker/Scripts/Game/Player/ThirdPersonCamera.cs @@ -0,0 +1,241 @@ +using UnityEngine; +using System.Collections; + +public class ThirdPersonCamera : MonoBehaviour +{ + + public Transform cameraTransform; + private Transform _target; + + // The distance in the x-z plane to the target + + public float distance = 7.0f; + + // the height we want the camera to be above the target + public float height = 3.0f; + + public float angularSmoothLag = 0.3f; + public float angularMaxSpeed = 15.0f; + + public float heightSmoothLag = 0.3f; + + public float snapSmoothLag = 0.2f; + public float snapMaxSpeed = 720.0f; + + public float clampHeadPositionScreenSpace = 0.75f; + + public float lockCameraTimeout = 0.2f; + + private Vector3 headOffset = Vector3.zero; + private Vector3 centerOffset = Vector3.zero; + + private float heightVelocity = 0.0f; + private float angleVelocity = 0.0f; + private bool snap = false; + private ThirdPersonController controller; + private float targetHeight = 100000.0f; + + private Camera m_CameraTransformCamera; + + void OnEnable() + { + if( !cameraTransform && Camera.main ) + cameraTransform = Camera.main.transform; + if( !cameraTransform ) + { + Debug.Log( "Please assign a camera to the ThirdPersonCamera script." ); + enabled = false; + } + + m_CameraTransformCamera = cameraTransform.GetComponent(); + + _target = transform; + if( _target ) + { + controller = _target.GetComponent(); + } + + if( controller ) + { + CharacterController characterController = (CharacterController)_target.GetComponent(); + centerOffset = characterController.bounds.center - _target.position; + headOffset = centerOffset; + headOffset.y = characterController.bounds.max.y - _target.position.y; + } + else + Debug.Log( "Please assign a target to the camera that has a ThirdPersonController script attached." ); + + + Cut( _target, centerOffset ); + } + + void DebugDrawStuff() + { + Debug.DrawLine( _target.position, _target.position + headOffset ); + + } + + float AngleDistance( float a, float b ) + { + a = Mathf.Repeat( a, 360 ); + b = Mathf.Repeat( b, 360 ); + + return Mathf.Abs( b - a ); + } + + void Apply( Transform dummyTarget, Vector3 dummyCenter ) + { + // Early out if we don't have a target + if( !controller ) + return; + + Vector3 targetCenter = _target.position + centerOffset; + Vector3 targetHead = _target.position + headOffset; + + // DebugDrawStuff(); + + // Calculate the current & target rotation angles + float originalTargetAngle = _target.eulerAngles.y; + float currentAngle = cameraTransform.eulerAngles.y; + + // Adjust real target angle when camera is locked + float targetAngle = originalTargetAngle; + + // When pressing Fire2 (alt) the camera will snap to the target direction real quick. + // It will stop snapping when it reaches the target + if( Input.GetButton( "Fire2" ) ) + snap = true; + + if( snap ) + { + // We are close to the target, so we can stop snapping now! + if( AngleDistance( currentAngle, originalTargetAngle ) < 3.0f ) + snap = false; + + currentAngle = Mathf.SmoothDampAngle( currentAngle, targetAngle, ref angleVelocity, snapSmoothLag, snapMaxSpeed ); + } + // Normal camera motion + else + { + if( controller.GetLockCameraTimer() < lockCameraTimeout ) + { + targetAngle = currentAngle; + } + + // Lock the camera when moving backwards! + // * It is really confusing to do 180 degree spins when turning around. + if( AngleDistance( currentAngle, targetAngle ) > 160 && controller.IsMovingBackwards() ) + targetAngle += 180; + + currentAngle = Mathf.SmoothDampAngle( currentAngle, targetAngle, ref angleVelocity, angularSmoothLag, angularMaxSpeed ); + } + + + // When jumping don't move camera upwards but only down! + if( controller.IsJumping() ) + { + // We'd be moving the camera upwards, do that only if it's really high + float newTargetHeight = targetCenter.y + height; + if( newTargetHeight < targetHeight || newTargetHeight - targetHeight > 5 ) + targetHeight = targetCenter.y + height; + } + // When walking always update the target height + else + { + targetHeight = targetCenter.y + height; + } + + // Damp the height + float currentHeight = cameraTransform.position.y; + currentHeight = Mathf.SmoothDamp( currentHeight, targetHeight, ref heightVelocity, heightSmoothLag ); + + // Convert the angle into a rotation, by which we then reposition the camera + Quaternion currentRotation = Quaternion.Euler( 0, currentAngle, 0 ); + + // Set the position of the camera on the x-z plane to: + // distance meters behind the target + cameraTransform.position = targetCenter; + cameraTransform.position += currentRotation * Vector3.back * distance; + + // Set the height of the camera + cameraTransform.position = new Vector3( cameraTransform.position.x, currentHeight, cameraTransform.position.z ); + + // Always look at the target + SetUpRotation( targetCenter, targetHead ); + } + + void LateUpdate() + { + Apply( transform, Vector3.zero ); + } + + void Cut( Transform dummyTarget, Vector3 dummyCenter ) + { + float oldHeightSmooth = heightSmoothLag; + float oldSnapMaxSpeed = snapMaxSpeed; + float oldSnapSmooth = snapSmoothLag; + + snapMaxSpeed = 10000; + snapSmoothLag = 0.001f; + heightSmoothLag = 0.001f; + + snap = true; + Apply( transform, Vector3.zero ); + + heightSmoothLag = oldHeightSmooth; + snapMaxSpeed = oldSnapMaxSpeed; + snapSmoothLag = oldSnapSmooth; + } + + void SetUpRotation( Vector3 centerPos, Vector3 headPos ) + { + // Now it's getting hairy. The devil is in the details here, the big issue is jumping of course. + // * When jumping up and down we don't want to center the guy in screen space. + // This is important to give a feel for how high you jump and avoiding large camera movements. + // + // * At the same time we dont want him to ever go out of screen and we want all rotations to be totally smooth. + // + // So here is what we will do: + // + // 1. We first find the rotation around the y axis. Thus he is always centered on the y-axis + // 2. When grounded we make him be centered + // 3. When jumping we keep the camera rotation but rotate the camera to get him back into view if his head is above some threshold + // 4. When landing we smoothly interpolate towards centering him on screen + Vector3 cameraPos = cameraTransform.position; + Vector3 offsetToCenter = centerPos - cameraPos; + + // Generate base rotation only around y-axis + Quaternion yRotation = Quaternion.LookRotation( new Vector3( offsetToCenter.x, 0, offsetToCenter.z ) ); + + Vector3 relativeOffset = Vector3.forward * distance + Vector3.down * height; + cameraTransform.rotation = yRotation * Quaternion.LookRotation( relativeOffset ); + + // Calculate the projected center position and top position in world space + Ray centerRay = m_CameraTransformCamera.ViewportPointToRay( new Vector3( 0.5f, 0.5f, 1 ) ); + Ray topRay = m_CameraTransformCamera.ViewportPointToRay( new Vector3( 0.5f, clampHeadPositionScreenSpace, 1 ) ); + + Vector3 centerRayPos = centerRay.GetPoint( distance ); + Vector3 topRayPos = topRay.GetPoint( distance ); + + float centerToTopAngle = Vector3.Angle( centerRay.direction, topRay.direction ); + + float heightToAngle = centerToTopAngle / ( centerRayPos.y - topRayPos.y ); + + float extraLookAngle = heightToAngle * ( centerRayPos.y - centerPos.y ); + if( extraLookAngle < centerToTopAngle ) + { + extraLookAngle = 0; + } + else + { + extraLookAngle = extraLookAngle - centerToTopAngle; + cameraTransform.rotation *= Quaternion.Euler( -extraLookAngle, 0, 0 ); + } + } + + Vector3 GetCenterOffset() + { + return centerOffset; + } + +} \ No newline at end of file diff --git a/Assets/Photon Unity Networking/Demos/DemoWorker/Scripts/Game/Player/ThirdPersonCamera.cs.meta b/Assets/Photon Unity Networking/Demos/DemoWorker/Scripts/Game/Player/ThirdPersonCamera.cs.meta new file mode 100644 index 0000000..d742881 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoWorker/Scripts/Game/Player/ThirdPersonCamera.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: f04aa96c3db9b22499df04b7c798e649 +labels: +- ExitGames +- PUN +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} diff --git a/Assets/Photon Unity Networking/Demos/DemoWorker/Scripts/Game/Player/ThirdPersonController.cs b/Assets/Photon Unity Networking/Demos/DemoWorker/Scripts/Game/Player/ThirdPersonController.cs new file mode 100644 index 0000000..1a4c842 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoWorker/Scripts/Game/Player/ThirdPersonController.cs @@ -0,0 +1,477 @@ +using UnityEngine; +using System.Collections; + +public enum CharacterState +{ + Idle = 0, + Walking = 1, + Trotting = 2, + Running = 3, + Jumping = 4, +} + +public class ThirdPersonController : MonoBehaviour +{ + + public AnimationClip idleAnimation; + public AnimationClip walkAnimation; + public AnimationClip runAnimation; + public AnimationClip jumpPoseAnimation; + + public float walkMaxAnimationSpeed = 0.75f; + public float trotMaxAnimationSpeed = 1.0f; + public float runMaxAnimationSpeed = 1.0f; + public float jumpAnimationSpeed = 1.15f; + public float landAnimationSpeed = 1.0f; + + private Animation _animation; + + + + public CharacterState _characterState; + + // The speed when walking + public float walkSpeed = 2.0f; + // after trotAfterSeconds of walking we trot with trotSpeed + public float trotSpeed = 4.0f; + // when pressing "Fire3" button (cmd) we start running + public float runSpeed = 6.0f; + + public float inAirControlAcceleration = 3.0f; + + // How high do we jump when pressing jump and letting go immediately + public float jumpHeight = 0.5f; + + // The gravity for the character + public float gravity = 20.0f; + // The gravity in controlled descent mode + public float speedSmoothing = 10.0f; + public float rotateSpeed = 500.0f; + public float trotAfterSeconds = 3.0f; + + public bool canJump = false; + + private float jumpRepeatTime = 0.05f; + private float jumpTimeout = 0.15f; + private float groundedTimeout = 0.25f; + + // The camera doesnt start following the target immediately but waits for a split second to avoid too much waving around. + private float lockCameraTimer = 0.0f; + + // The current move direction in x-z + private Vector3 moveDirection = Vector3.zero; + // The current vertical speed + private float verticalSpeed = 0.0f; + // The current x-z move speed + private float moveSpeed = 0.0f; + + // The last collision flags returned from controller.Move + private CollisionFlags collisionFlags; + + // Are we jumping? (Initiated with jump button and not grounded yet) + private bool jumping = false; + private bool jumpingReachedApex = false; + + // Are we moving backwards (This locks the camera to not do a 180 degree spin) + private bool movingBack = false; + // Is the user pressing any keys? + private bool isMoving = false; + // When did the user start walking (Used for going into trot after a while) + private float walkTimeStart = 0.0f; + // Last time the jump button was clicked down + private float lastJumpButtonTime = -10.0f; + // Last time we performed a jump + private float lastJumpTime = -1.0f; + // the height we jumped from (Used to determine for how long to apply extra jump power after jumping.) + //private float lastJumpStartHeight = 0.0f; + private Vector3 inAirVelocity = Vector3.zero; + + private float lastGroundedTime = 0.0f; + public bool isControllable = true; + + void Awake() + { + moveDirection = transform.TransformDirection(Vector3.forward); + + _animation = GetComponent(); + if (!_animation) + Debug.Log("The character you would like to control doesn't have animations. Moving her might look weird."); + + /* + public AnimationClip idleAnimation; + public AnimationClip walkAnimation; + public AnimationClip runAnimation; + public AnimationClip jumpPoseAnimation; + */ + if (!idleAnimation) + { + _animation = null; + Debug.Log("No idle animation found. Turning off animations."); + } + if (!walkAnimation) + { + _animation = null; + Debug.Log("No walk animation found. Turning off animations."); + } + if (!runAnimation) + { + _animation = null; + Debug.Log("No run animation found. Turning off animations."); + } + if (!jumpPoseAnimation && canJump) + { + _animation = null; + Debug.Log("No jump animation found and the character has canJump enabled. Turning off animations."); + } + + } + + private Vector3 lastPos; + + void UpdateSmoothedMovementDirection() + { + Transform cameraTransform = Camera.main.transform; + bool grounded = IsGrounded(); + + // Forward vector relative to the camera along the x-z plane + Vector3 forward = cameraTransform.TransformDirection(Vector3.forward); + forward.y = 0; + forward = forward.normalized; + + // Right vector relative to the camera + // Always orthogonal to the forward vector + Vector3 right = new Vector3(forward.z, 0, -forward.x); + + float v = Input.GetAxisRaw("Vertical"); + float h = Input.GetAxisRaw("Horizontal"); + + // Are we moving backwards or looking backwards + if (v < -0.2f) + movingBack = true; + else + movingBack = false; + + bool wasMoving = isMoving; + isMoving = Mathf.Abs(h) > 0.1f || Mathf.Abs(v) > 0.1f; + + // Target direction relative to the camera + Vector3 targetDirection = h * right + v * forward; + + // Grounded controls + if (grounded) + { + // Lock camera for short period when transitioning moving & standing still + lockCameraTimer += Time.deltaTime; + if (isMoving != wasMoving) + lockCameraTimer = 0.0f; + + // We store speed and direction seperately, + // so that when the character stands still we still have a valid forward direction + // moveDirection is always normalized, and we only update it if there is user input. + if (targetDirection != Vector3.zero) + { + // If we are really slow, just snap to the target direction + if (moveSpeed < walkSpeed * 0.9f && grounded) + { + moveDirection = targetDirection.normalized; + } + // Otherwise smoothly turn towards it + else + { + moveDirection = Vector3.RotateTowards(moveDirection, targetDirection, rotateSpeed * Mathf.Deg2Rad * Time.deltaTime, 1000); + + moveDirection = moveDirection.normalized; + } + } + + // Smooth the speed based on the current target direction + float curSmooth = speedSmoothing * Time.deltaTime; + + // Choose target speed + //* We want to support analog input but make sure you cant walk faster diagonally than just forward or sideways + float targetSpeed = Mathf.Min(targetDirection.magnitude, 1.0f); + + _characterState = CharacterState.Idle; + + // Pick speed modifier + if (Input.GetKey(KeyCode.LeftShift) | Input.GetKey(KeyCode.RightShift)) + { + targetSpeed *= runSpeed; + _characterState = CharacterState.Running; + } + else if (Time.time - trotAfterSeconds > walkTimeStart) + { + targetSpeed *= trotSpeed; + _characterState = CharacterState.Trotting; + } + else + { + targetSpeed *= walkSpeed; + _characterState = CharacterState.Walking; + } + + moveSpeed = Mathf.Lerp(moveSpeed, targetSpeed, curSmooth); + + // Reset walk time start when we slow down + if (moveSpeed < walkSpeed * 0.3f) + walkTimeStart = Time.time; + } + // In air controls + else + { + // Lock camera while in air + if (jumping) + lockCameraTimer = 0.0f; + + if (isMoving) + inAirVelocity += targetDirection.normalized * Time.deltaTime * inAirControlAcceleration; + } + + + + } + void ApplyJumping() + { + // Prevent jumping too fast after each other + if (lastJumpTime + jumpRepeatTime > Time.time) + return; + + if (IsGrounded()) + { + // Jump + // - Only when pressing the button down + // - With a timeout so you can press the button slightly before landing + if (canJump && Time.time < lastJumpButtonTime + jumpTimeout) + { + verticalSpeed = CalculateJumpVerticalSpeed(jumpHeight); + SendMessage("DidJump", SendMessageOptions.DontRequireReceiver); + } + } + } + void ApplyGravity() + { + if (isControllable) // don't move player at all if not controllable. + { + // Apply gravity + //bool jumpButton = Input.GetButton("Jump"); + + // When we reach the apex of the jump we send out a message + if (jumping && !jumpingReachedApex && verticalSpeed <= 0.0f) + { + jumpingReachedApex = true; + SendMessage("DidJumpReachApex", SendMessageOptions.DontRequireReceiver); + } + + if (IsGrounded()) + verticalSpeed = 0.0f; + else + verticalSpeed -= gravity * Time.deltaTime; + } + } + + float CalculateJumpVerticalSpeed(float targetJumpHeight) + { + // From the jump height and gravity we deduce the upwards speed + // for the character to reach at the apex. + return Mathf.Sqrt(2 * targetJumpHeight * gravity); + } + + void DidJump() + { + jumping = true; + jumpingReachedApex = false; + lastJumpTime = Time.time; + //lastJumpStartHeight = transform.position.y; + lastJumpButtonTime = -10; + + _characterState = CharacterState.Jumping; + } + + Vector3 velocity = Vector3.zero; + + void Update() + { + if (isControllable) + { + if (Input.GetButtonDown("Jump")) + { + lastJumpButtonTime = Time.time; + } + + UpdateSmoothedMovementDirection(); + + // Apply gravity + // - extra power jump modifies gravity + // - controlledDescent mode modifies gravity + ApplyGravity(); + + // Apply jumping logic + ApplyJumping(); + + + // Calculate actual motion + Vector3 movement = moveDirection * moveSpeed + new Vector3(0, verticalSpeed, 0) + inAirVelocity; + movement *= Time.deltaTime; + + // Move the controller + CharacterController controller = GetComponent(); + collisionFlags = controller.Move(movement); + } + velocity = (transform.position - lastPos)*25; + + // ANIMATION sector + if (_animation) + { + if (_characterState == CharacterState.Jumping) + { + if (!jumpingReachedApex) + { + _animation[jumpPoseAnimation.name].speed = jumpAnimationSpeed; + _animation[jumpPoseAnimation.name].wrapMode = WrapMode.ClampForever; + _animation.CrossFade(jumpPoseAnimation.name); + } + else + { + _animation[jumpPoseAnimation.name].speed = -landAnimationSpeed; + _animation[jumpPoseAnimation.name].wrapMode = WrapMode.ClampForever; + _animation.CrossFade(jumpPoseAnimation.name); + } + } + else + { + if (this.isControllable && velocity.sqrMagnitude < 0.001f) + { + _characterState = CharacterState.Idle; + _animation.CrossFade(idleAnimation.name); + } + else + { + if (_characterState == CharacterState.Idle) + { + _animation.CrossFade(idleAnimation.name); + } + else if (_characterState == CharacterState.Running) + { + _animation[runAnimation.name].speed = runMaxAnimationSpeed; + if (this.isControllable) + { + _animation[runAnimation.name].speed = Mathf.Clamp(velocity.magnitude, 0.0f, runMaxAnimationSpeed); + } + _animation.CrossFade(runAnimation.name); + } + else if (_characterState == CharacterState.Trotting) + { + _animation[walkAnimation.name].speed = trotMaxAnimationSpeed; + if (this.isControllable) + { + _animation[walkAnimation.name].speed = Mathf.Clamp(velocity.magnitude, 0.0f, trotMaxAnimationSpeed); + } + _animation.CrossFade(walkAnimation.name); + } + else if (_characterState == CharacterState.Walking) + { + _animation[walkAnimation.name].speed = walkMaxAnimationSpeed; + if (this.isControllable) + { + _animation[walkAnimation.name].speed = Mathf.Clamp(velocity.magnitude, 0.0f, walkMaxAnimationSpeed); + } + _animation.CrossFade(walkAnimation.name); + } + + } + } + } + // ANIMATION sector + + // Set rotation to the move direction + if (IsGrounded()) + { + + transform.rotation = Quaternion.LookRotation(moveDirection); + + } + else + { + /* This causes choppy behaviour when colliding with SIDES + * Vector3 xzMove = velocity; + xzMove.y = 0; + if (xzMove.sqrMagnitude > 0.001f) + { + transform.rotation = Quaternion.LookRotation(xzMove); + }*/ + } + + // We are in jump mode but just became grounded + if (IsGrounded()) + { + lastGroundedTime = Time.time; + inAirVelocity = Vector3.zero; + if (jumping) + { + jumping = false; + SendMessage("DidLand", SendMessageOptions.DontRequireReceiver); + } + } + + lastPos = transform.position; + } + + void OnControllerColliderHit(ControllerColliderHit hit) + { + // Debug.DrawRay(hit.point, hit.normal); + if (hit.moveDirection.y > 0.01f) + return; + } + + public float GetSpeed() + { + return moveSpeed; + } + + public bool IsJumping() + { + return jumping; + } + + public bool IsGrounded() + { + return (collisionFlags & CollisionFlags.CollidedBelow) != 0; + } + + public Vector3 GetDirection() + { + return moveDirection; + } + + public bool IsMovingBackwards() + { + return movingBack; + } + + public float GetLockCameraTimer() + { + return lockCameraTimer; + } + + public bool IsMoving() + { + return Mathf.Abs(Input.GetAxisRaw("Vertical")) + Mathf.Abs(Input.GetAxisRaw("Horizontal")) > 0.5f; + } + + public bool HasJumpReachedApex() + { + return jumpingReachedApex; + } + + public bool IsGroundedWithTimeout() + { + return lastGroundedTime + groundedTimeout > Time.time; + } + + public void Reset() + { + gameObject.tag = "Player"; + } + + +} \ No newline at end of file diff --git a/Assets/Photon Unity Networking/Demos/DemoWorker/Scripts/Game/Player/ThirdPersonController.cs.meta b/Assets/Photon Unity Networking/Demos/DemoWorker/Scripts/Game/Player/ThirdPersonController.cs.meta new file mode 100644 index 0000000..2ae18f0 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoWorker/Scripts/Game/Player/ThirdPersonController.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 955c74c013058e749bab96303414a7c6 +labels: +- ExitGames +- PUN +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} diff --git a/Assets/Photon Unity Networking/Demos/DemoWorker/Scripts/Game/Player/ThirdPersonNetwork.cs b/Assets/Photon Unity Networking/Demos/DemoWorker/Scripts/Game/Player/ThirdPersonNetwork.cs new file mode 100644 index 0000000..92bf6f2 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoWorker/Scripts/Game/Player/ThirdPersonNetwork.cs @@ -0,0 +1,79 @@ +using UnityEngine; +using System.Collections; + +public class ThirdPersonNetwork : Photon.MonoBehaviour +{ + ThirdPersonCamera cameraScript; + ThirdPersonController controllerScript; + + + bool firstTake = false; + + void OnEnable() + { + firstTake = true; + } + + void Awake() + { + cameraScript = GetComponent(); + controllerScript = GetComponent(); + + if (photonView.isMine) + { + //MINE: local player, simply enable the local scripts + cameraScript.enabled = true; + controllerScript.enabled = true; + } + else + { + cameraScript.enabled = false; + + controllerScript.enabled = true; + controllerScript.isControllable = false; + } + + gameObject.name = gameObject.name + photonView.viewID; + } + + void OnPhotonSerializeView(PhotonStream stream, PhotonMessageInfo info) + { + if (stream.isWriting) + { + //We own this player: send the others our data + stream.SendNext((int)controllerScript._characterState); + stream.SendNext(transform.position); + stream.SendNext(transform.rotation); + } + else + { + //Network player, receive data + controllerScript._characterState = (CharacterState)(int)stream.ReceiveNext(); + correctPlayerPos = (Vector3)stream.ReceiveNext(); + correctPlayerRot = (Quaternion)stream.ReceiveNext(); + + // avoids lerping the character from "center" to the "current" position when this client joins + if (firstTake) + { + firstTake = false; + this.transform.position = correctPlayerPos; + transform.rotation = correctPlayerRot; + } + + } + } + + private Vector3 correctPlayerPos = Vector3.zero; //We lerp towards this + private Quaternion correctPlayerRot = Quaternion.identity; //We lerp towards this + + void Update() + { + if (!photonView.isMine) + { + //Update remote player (smooth this, this looks good, at the cost of some accuracy) + transform.position = Vector3.Lerp(transform.position, correctPlayerPos, Time.deltaTime * 5); + transform.rotation = Quaternion.Lerp(transform.rotation, correctPlayerRot, Time.deltaTime * 5); + } + } + +} \ No newline at end of file diff --git a/Assets/Photon Unity Networking/Demos/DemoWorker/Scripts/Game/Player/ThirdPersonNetwork.cs.meta b/Assets/Photon Unity Networking/Demos/DemoWorker/Scripts/Game/Player/ThirdPersonNetwork.cs.meta new file mode 100644 index 0000000..0af2601 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoWorker/Scripts/Game/Player/ThirdPersonNetwork.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 13c4159c5850b1a498351cd423b910b3 +labels: +- ExitGames +- PUN +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} diff --git a/Assets/Photon Unity Networking/Demos/DemoWorker/Scripts/WorkerInGame.cs b/Assets/Photon Unity Networking/Demos/DemoWorker/Scripts/WorkerInGame.cs new file mode 100644 index 0000000..66cc1f7 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoWorker/Scripts/WorkerInGame.cs @@ -0,0 +1,97 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Part of: Photon Unity Networking +// +// -------------------------------------------------------------------------------------------------------------------- + +using UnityEngine; +using UnityEngine.SceneManagement; + +public class WorkerInGame : Photon.MonoBehaviour +{ + public Transform playerPrefab; + + public void Awake() + { + // in case we started this demo with the wrong scene being active, simply load the menu scene + if (!PhotonNetwork.connected) + { + SceneManager.LoadScene(WorkerMenu.SceneNameMenu); + return; + } + + // we're in a room. spawn a character for the local player. it gets synced by using PhotonNetwork.Instantiate + PhotonNetwork.Instantiate(this.playerPrefab.name, transform.position, Quaternion.identity, 0); + } + + public void OnGUI() + { + if (GUILayout.Button("Return to Lobby")) + { + PhotonNetwork.LeaveRoom(); // we will load the menu level when we successfully left the room + } + } + + public void OnMasterClientSwitched(PhotonPlayer player) + { + Debug.Log("OnMasterClientSwitched: " + player); + + string message; + InRoomChat chatComponent = GetComponent(); // if we find a InRoomChat component, we print out a short message + + if (chatComponent != null) + { + // to check if this client is the new master... + if (player.IsLocal) + { + message = "You are Master Client now."; + } + else + { + message = player.NickName + " is Master Client now."; + } + + + chatComponent.AddLine(message); // the Chat method is a RPC. as we don't want to send an RPC and neither create a PhotonMessageInfo, lets call AddLine() + } + } + + public void OnLeftRoom() + { + Debug.Log("OnLeftRoom (local)"); + + // back to main menu + SceneManager.LoadScene(WorkerMenu.SceneNameMenu); + } + + public void OnDisconnectedFromPhoton() + { + Debug.Log("OnDisconnectedFromPhoton"); + + // back to main menu + SceneManager.LoadScene(WorkerMenu.SceneNameMenu); + } + + public void OnPhotonInstantiate(PhotonMessageInfo info) + { + Debug.Log("OnPhotonInstantiate " + info.sender); // you could use this info to store this or react + } + + public void OnPhotonPlayerConnected(PhotonPlayer player) + { + Debug.Log("OnPhotonPlayerConnected: " + player); + } + + public void OnPhotonPlayerDisconnected(PhotonPlayer player) + { + Debug.Log("OnPlayerDisconneced: " + player); + } + + public void OnFailedToConnectToPhoton() + { + Debug.Log("OnFailedToConnectToPhoton"); + + // back to main menu + SceneManager.LoadScene(WorkerMenu.SceneNameMenu); + } +} \ No newline at end of file diff --git a/Assets/Photon Unity Networking/Demos/DemoWorker/Scripts/WorkerInGame.cs.meta b/Assets/Photon Unity Networking/Demos/DemoWorker/Scripts/WorkerInGame.cs.meta new file mode 100644 index 0000000..ed0f89a --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoWorker/Scripts/WorkerInGame.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 31d56c35722d75a4591577d224c275af +labels: +- ExitGames +- PUN +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} diff --git a/Assets/Photon Unity Networking/Demos/DemoWorker/Scripts/WorkerMenu.cs b/Assets/Photon Unity Networking/Demos/DemoWorker/Scripts/WorkerMenu.cs new file mode 100644 index 0000000..2934b32 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoWorker/Scripts/WorkerMenu.cs @@ -0,0 +1,244 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Part of: Photon Unity Networking +// +// -------------------------------------------------------------------------------------------------------------------- + +using System; +using UnityEngine; +using Random = UnityEngine.Random; +using ExitGames.Client.Photon; + +public class WorkerMenu : MonoBehaviour +{ + public GUISkin Skin; + public Vector2 WidthAndHeight = new Vector2(600, 400); + private string roomName = "myRoom"; + + private Vector2 scrollPos = Vector2.zero; + + private bool connectFailed = false; + + public static readonly string SceneNameMenu = "DemoWorker-Scene"; + + public static readonly string SceneNameGame = "DemoWorkerGame-Scene"; + + private string errorDialog; + private double timeToClearDialog; + + public string ErrorDialog + { + get { return this.errorDialog; } + private set + { + this.errorDialog = value; + if (!string.IsNullOrEmpty(value)) + { + this.timeToClearDialog = Time.time + 4.0f; + } + } + } + + public void Awake() + { + // this makes sure we can use PhotonNetwork.LoadLevel() on the master client and all clients in the same room sync their level automatically + PhotonNetwork.automaticallySyncScene = true; + + // the following line checks if this client was just created (and not yet online). if so, we connect + if (PhotonNetwork.connectionStateDetailed == ClientState.PeerCreated) + { + // Connect to the photon master-server. We use the settings saved in PhotonServerSettings (a .asset file in this project) + PhotonNetwork.ConnectUsingSettings("0.9"); + } + + // generate a name for this player, if none is assigned yet + if (String.IsNullOrEmpty(PhotonNetwork.playerName)) + { + PhotonNetwork.playerName = "Guest" + Random.Range(1, 9999); + } + + // if you wanted more debug out, turn this on: + // PhotonNetwork.logLevel = NetworkLogLevel.Full; + } + + public void OnGUI() + { + if (this.Skin != null) + { + GUI.skin = this.Skin; + } + + if (!PhotonNetwork.connected) + { + if (PhotonNetwork.connecting) + { + GUILayout.Label("Connecting to: " + PhotonNetwork.ServerAddress); + } + else + { + GUILayout.Label("Not connected. Check console output. Detailed connection state: " + PhotonNetwork.connectionStateDetailed + " Server: " + PhotonNetwork.ServerAddress); + } + + if (this.connectFailed) + { + GUILayout.Label("Connection failed. Check setup and use Setup Wizard to fix configuration."); + GUILayout.Label(String.Format("Server: {0}", new object[] {PhotonNetwork.ServerAddress})); + GUILayout.Label("AppId: " + PhotonNetwork.PhotonServerSettings.AppID.Substring(0, 8) + "****"); // only show/log first 8 characters. never log the full AppId. + + if (GUILayout.Button("Try Again", GUILayout.Width(100))) + { + this.connectFailed = false; + PhotonNetwork.ConnectUsingSettings("0.9"); + } + } + + return; + } + + Rect content = new Rect((Screen.width - this.WidthAndHeight.x)/2, (Screen.height - this.WidthAndHeight.y)/2, this.WidthAndHeight.x, this.WidthAndHeight.y); + GUI.Box(content, "Join or Create Room"); + GUILayout.BeginArea(content); + + GUILayout.Space(40); + + // Player name + GUILayout.BeginHorizontal(); + GUILayout.Label("Player name:", GUILayout.Width(150)); + PhotonNetwork.playerName = GUILayout.TextField(PhotonNetwork.playerName); + GUILayout.Space(158); + if (GUI.changed) + { + // Save name + PlayerPrefs.SetString("playerName", PhotonNetwork.playerName); + } + GUILayout.EndHorizontal(); + + GUILayout.Space(15); + + // Join room by title + GUILayout.BeginHorizontal(); + GUILayout.Label("Roomname:", GUILayout.Width(150)); + this.roomName = GUILayout.TextField(this.roomName); + + if (GUILayout.Button("Create Room", GUILayout.Width(150))) + { + PhotonNetwork.CreateRoom(this.roomName, new RoomOptions() { MaxPlayers = 10 }, null); + } + + GUILayout.EndHorizontal(); + + // Create a room (fails if exist!) + GUILayout.BeginHorizontal(); + GUILayout.FlexibleSpace(); + //this.roomName = GUILayout.TextField(this.roomName); + if (GUILayout.Button("Join Room", GUILayout.Width(150))) + { + PhotonNetwork.JoinRoom(this.roomName); + } + + GUILayout.EndHorizontal(); + + + if (!string.IsNullOrEmpty(ErrorDialog)) + { + GUILayout.Label(ErrorDialog); + + if (this.timeToClearDialog < Time.time) + { + this.timeToClearDialog = 0; + ErrorDialog = ""; + } + } + + GUILayout.Space(15); + + // Join random room + GUILayout.BeginHorizontal(); + + GUILayout.Label(PhotonNetwork.countOfPlayers + " users are online in " + PhotonNetwork.countOfRooms + " rooms."); + GUILayout.FlexibleSpace(); + if (GUILayout.Button("Join Random", GUILayout.Width(150))) + { + PhotonNetwork.JoinRandomRoom(); + } + + + GUILayout.EndHorizontal(); + + GUILayout.Space(15); + if (PhotonNetwork.GetRoomList().Length == 0) + { + GUILayout.Label("Currently no games are available."); + GUILayout.Label("Rooms will be listed here, when they become available."); + } + else + { + GUILayout.Label(PhotonNetwork.GetRoomList().Length + " rooms available:"); + + // Room listing: simply call GetRoomList: no need to fetch/poll whatever! + this.scrollPos = GUILayout.BeginScrollView(this.scrollPos); + foreach (RoomInfo roomInfo in PhotonNetwork.GetRoomList()) + { + GUILayout.BeginHorizontal(); + GUILayout.Label(roomInfo.Name + " " + roomInfo.PlayerCount + "/" + roomInfo.MaxPlayers); + if (GUILayout.Button("Join", GUILayout.Width(150))) + { + PhotonNetwork.JoinRoom(roomInfo.Name); + } + + GUILayout.EndHorizontal(); + } + + GUILayout.EndScrollView(); + } + + GUILayout.EndArea(); + } + + // We have two options here: we either joined(by title, list or random) or created a room. + public void OnJoinedRoom() + { + Debug.Log("OnJoinedRoom"); + } + + public void OnPhotonCreateRoomFailed() + { + ErrorDialog = "Error: Can't create room (room name maybe already used)."; + Debug.Log("OnPhotonCreateRoomFailed got called. This can happen if the room exists (even if not visible). Try another room name."); + } + + public void OnPhotonJoinRoomFailed(object[] cause) + { + ErrorDialog = "Error: Can't join room (full or unknown room name). " + cause[1]; + Debug.Log("OnPhotonJoinRoomFailed got called. This can happen if the room is not existing or full or closed."); + } + + public void OnPhotonRandomJoinFailed() + { + ErrorDialog = "Error: Can't join random room (none found)."; + Debug.Log("OnPhotonRandomJoinFailed got called. Happens if no room is available (or all full or invisible or closed). JoinrRandom filter-options can limit available rooms."); + } + + public void OnCreatedRoom() + { + Debug.Log("OnCreatedRoom"); + PhotonNetwork.LoadLevel(SceneNameGame); + } + + public void OnDisconnectedFromPhoton() + { + Debug.Log("Disconnected from Photon."); + } + + public void OnFailedToConnectToPhoton(object parameters) + { + this.connectFailed = true; + Debug.Log("OnFailedToConnectToPhoton. StatusCode: " + parameters + " ServerAddress: " + PhotonNetwork.ServerAddress); + } + + public void OnConnectedToMaster() + { + Debug.Log("As OnConnectedToMaster() got called, the PhotonServerSetting.AutoJoinLobby must be off. Joining lobby by calling PhotonNetwork.JoinLobby()."); + PhotonNetwork.JoinLobby(); + } +} diff --git a/Assets/Photon Unity Networking/Demos/DemoWorker/Scripts/WorkerMenu.cs.meta b/Assets/Photon Unity Networking/Demos/DemoWorker/Scripts/WorkerMenu.cs.meta new file mode 100644 index 0000000..de23682 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/DemoWorker/Scripts/WorkerMenu.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: a02ce27e88b39fa428538620fe0335e3 +labels: +- ExitGames +- PUN +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} diff --git a/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial.meta b/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial.meta new file mode 100644 index 0000000..65bdaae --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 976148bc62f2243fca4b7e46ecb1b7d2 +folderAsset: yes +timeCreated: 1501014811 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/AudioRpc.cs b/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/AudioRpc.cs new file mode 100644 index 0000000..8a75d70 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/AudioRpc.cs @@ -0,0 +1,48 @@ +using UnityEngine; + +public class AudioRpc : Photon.MonoBehaviour +{ + + public AudioClip marco; + public AudioClip polo; + + AudioSource m_Source; + + void Awake() + { + m_Source = GetComponent(); + } + + [PunRPC] + void Marco() + { + if( !this.enabled ) + { + return; + } + + Debug.Log( "Marco" ); + + m_Source.clip = marco; + m_Source.Play(); + } + + [PunRPC] + void Polo() + { + if( !this.enabled ) + { + return; + } + + Debug.Log( "Polo" ); + + m_Source.clip = polo; + m_Source.Play(); + } + + void OnApplicationFocus( bool focus ) + { + this.enabled = focus; + } +} diff --git a/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/AudioRpc.cs.meta b/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/AudioRpc.cs.meta new file mode 100644 index 0000000..49ae47e --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/AudioRpc.cs.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 186bba2843e9e314bb91d2f3c51b7553 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} diff --git a/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/ClickDetector.cs b/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/ClickDetector.cs new file mode 100644 index 0000000..2cdfbf3 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/ClickDetector.cs @@ -0,0 +1,43 @@ +using System; +using UnityEngine; + +public class ClickDetector : MonoBehaviour +{ + + public void Update() + { + // if this player is not "it", the player can't tag anyone, so don't do anything on collision + if (PhotonNetwork.player.ID != GameLogic.playerWhoIsIt) + { + return; + } + + if (Input.GetButton("Fire1")) + { + GameObject goPointedAt = RaycastObject(Input.mousePosition); + + if (goPointedAt != null && goPointedAt != this.gameObject && goPointedAt.name.Equals("monsterprefab(Clone)", StringComparison.OrdinalIgnoreCase)) + { + PhotonView rootView = goPointedAt.transform.root.GetComponent(); + GameLogic.TagPlayer(rootView.owner.ID); + } + } + } + + private GameObject RaycastObject(Vector2 screenPos) + { + RaycastHit info; + #if UNITY_3_5 + Camera cam = Camera.mainCamera; + #else + Camera cam = Camera.main; + #endif + + if (Physics.Raycast(cam.ScreenPointToRay(screenPos), out info, 200)) + { + return info.collider.gameObject; + } + + return null; + } +} diff --git a/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/ClickDetector.cs.meta b/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/ClickDetector.cs.meta new file mode 100644 index 0000000..74bb473 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/ClickDetector.cs.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 4f3ceebf3f8195149bb4b56495a28f7a +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} diff --git a/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/GameLogic.cs b/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/GameLogic.cs new file mode 100644 index 0000000..1af2271 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/GameLogic.cs @@ -0,0 +1,71 @@ +using UnityEngine; +using System.Collections; + +public class GameLogic : MonoBehaviour +{ + + public static int playerWhoIsIt = 0; + private static PhotonView ScenePhotonView; + + // Use this for initialization + public void Start() + { + ScenePhotonView = this.GetComponent(); + } + + public void OnJoinedRoom() + { + // game logic: if this is the only player, we're "it" + if (PhotonNetwork.playerList.Length == 1) + { + playerWhoIsIt = PhotonNetwork.player.ID; + } + + Debug.Log("playerWhoIsIt: " + playerWhoIsIt); + } + + public void OnPhotonPlayerConnected(PhotonPlayer player) + { + Debug.Log("OnPhotonPlayerConnected: " + player); + + // when new players join, we send "who's it" to let them know + // only one player will do this: the "master" + + if (PhotonNetwork.isMasterClient) + { + TagPlayer(playerWhoIsIt); + } + } + + public static void TagPlayer(int playerID) + { + Debug.Log("TagPlayer: " + playerID); + ScenePhotonView.RPC("TaggedPlayer", PhotonTargets.All, playerID); + } + + [PunRPC] + public void TaggedPlayer(int playerID) + { + playerWhoIsIt = playerID; + Debug.Log("TaggedPlayer: " + playerID); + } + + public void OnPhotonPlayerDisconnected(PhotonPlayer player) + { + Debug.Log("OnPhotonPlayerDisconnected: " + player); + + if (PhotonNetwork.isMasterClient) + { + if (player.ID == playerWhoIsIt) + { + // if the player who left was "it", the "master" is the new "it" + TagPlayer(PhotonNetwork.player.ID); + } + } + } + + public void OnMasterClientSwitched() + { + Debug.Log("OnMasterClientSwitched"); + } +} diff --git a/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/GameLogic.cs.meta b/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/GameLogic.cs.meta new file mode 100644 index 0000000..390247c --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/GameLogic.cs.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 9e3b529a63c710a4c9d4df2417d343a2 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} diff --git a/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/Marco.mp3 b/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/Marco.mp3 new file mode 100644 index 0000000..976f088 Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/Marco.mp3 differ diff --git a/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/Marco.mp3.meta b/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/Marco.mp3.meta new file mode 100644 index 0000000..d68cadc --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/Marco.mp3.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 77f32f4466e3e7f4b90691d51e114969 +AudioImporter: + serializedVersion: 4 + format: 0 + quality: .5 + stream: 1 + 3D: 1 + forceToMono: 0 + useHardware: 0 + loopable: 0 + userData: diff --git a/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/MarcoPolo-Scene.unity b/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/MarcoPolo-Scene.unity new file mode 100644 index 0000000..9661da0 Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/MarcoPolo-Scene.unity differ diff --git a/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/MarcoPolo-Scene.unity.meta b/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/MarcoPolo-Scene.unity.meta new file mode 100644 index 0000000..6790c6a --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/MarcoPolo-Scene.unity.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 4edb89b81eea36243978d62c589e60ad diff --git a/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/Monstergame.meta b/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/Monstergame.meta new file mode 100644 index 0000000..69e1707 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/Monstergame.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 30b5c6725aa234b93b24e8ad24559d36 +folderAsset: yes +timeCreated: 1501014811 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/Monstergame/Resources.meta b/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/Monstergame/Resources.meta new file mode 100644 index 0000000..b5d13d6 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/Monstergame/Resources.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: c5211c09feac94df189c726debb38c47 +folderAsset: yes +timeCreated: 1501014812 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/Monstergame/Resources/Materials.meta b/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/Monstergame/Resources/Materials.meta new file mode 100644 index 0000000..ec4fe3c --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/Monstergame/Resources/Materials.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 0f56331942f0c460a836f4b0cb9e24c8 +folderAsset: yes +timeCreated: 1501014812 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/Monstergame/Resources/Materials/creature1-tanden.1.mat b/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/Monstergame/Resources/Materials/creature1-tanden.1.mat new file mode 100644 index 0000000..5fbb237 Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/Monstergame/Resources/Materials/creature1-tanden.1.mat differ diff --git a/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/Monstergame/Resources/Materials/creature1-tanden.1.mat.meta b/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/Monstergame/Resources/Materials/creature1-tanden.1.mat.meta new file mode 100644 index 0000000..b428919 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/Monstergame/Resources/Materials/creature1-tanden.1.mat.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 4eb85af99fa90b5458b82b1712d9a38e diff --git a/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/Monstergame/Resources/Materials/creature1-tanden.mat b/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/Monstergame/Resources/Materials/creature1-tanden.mat new file mode 100644 index 0000000..4d1c149 Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/Monstergame/Resources/Materials/creature1-tanden.mat differ diff --git a/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/Monstergame/Resources/Materials/creature1-tanden.mat.meta b/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/Monstergame/Resources/Materials/creature1-tanden.mat.meta new file mode 100644 index 0000000..a2519d1 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/Monstergame/Resources/Materials/creature1-tanden.mat.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 98292beaa99b528409314e373d4bf6c8 diff --git a/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/Monstergame/Resources/Materials/muktarcolorgoed_1.mat b/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/Monstergame/Resources/Materials/muktarcolorgoed_1.mat new file mode 100644 index 0000000..b7fd126 Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/Monstergame/Resources/Materials/muktarcolorgoed_1.mat differ diff --git a/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/Monstergame/Resources/Materials/muktarcolorgoed_1.mat.meta b/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/Monstergame/Resources/Materials/muktarcolorgoed_1.mat.meta new file mode 100644 index 0000000..5517c6b --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/Monstergame/Resources/Materials/muktarcolorgoed_1.mat.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: e00d3462d66a5f7418d228981823b04d diff --git a/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/Monstergame/Resources/Materials/muktargame-Mat.mat b/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/Monstergame/Resources/Materials/muktargame-Mat.mat new file mode 100644 index 0000000..e9cd162 Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/Monstergame/Resources/Materials/muktargame-Mat.mat differ diff --git a/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/Monstergame/Resources/Materials/muktargame-Mat.mat.meta b/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/Monstergame/Resources/Materials/muktargame-Mat.mat.meta new file mode 100644 index 0000000..2b59f8d --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/Monstergame/Resources/Materials/muktargame-Mat.mat.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 4ddcafa983f02e742af239c8601583eb diff --git a/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/Monstergame/Resources/Materials/muktargame-No Name.mat b/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/Monstergame/Resources/Materials/muktargame-No Name.mat new file mode 100644 index 0000000..3a35917 Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/Monstergame/Resources/Materials/muktargame-No Name.mat differ diff --git a/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/Monstergame/Resources/Materials/muktargame-No Name.mat.meta b/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/Monstergame/Resources/Materials/muktargame-No Name.mat.meta new file mode 100644 index 0000000..49c2b09 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/Monstergame/Resources/Materials/muktargame-No Name.mat.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 7de122b788971734d91036434995bdb4 diff --git a/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/Monstergame/Resources/Materials/muktargame-oog.1.mat b/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/Monstergame/Resources/Materials/muktargame-oog.1.mat new file mode 100644 index 0000000..1cafe89 Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/Monstergame/Resources/Materials/muktargame-oog.1.mat differ diff --git a/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/Monstergame/Resources/Materials/muktargame-oog.1.mat.meta b/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/Monstergame/Resources/Materials/muktargame-oog.1.mat.meta new file mode 100644 index 0000000..5254b75 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/Monstergame/Resources/Materials/muktargame-oog.1.mat.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: a28420d6e950cb241aabb704d86c919a diff --git a/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/Monstergame/Resources/Materials/muktargame-oog.mat b/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/Monstergame/Resources/Materials/muktargame-oog.mat new file mode 100644 index 0000000..5559905 Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/Monstergame/Resources/Materials/muktargame-oog.mat differ diff --git a/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/Monstergame/Resources/Materials/muktargame-oog.mat.meta b/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/Monstergame/Resources/Materials/muktargame-oog.mat.meta new file mode 100644 index 0000000..ee28894 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/Monstergame/Resources/Materials/muktargame-oog.mat.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 4237e8c77361e6b43bdc3c785b6aa272 diff --git a/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/Monstergame/Resources/Materials/muktargame-tanden.1.mat b/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/Monstergame/Resources/Materials/muktargame-tanden.1.mat new file mode 100644 index 0000000..a338f1a Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/Monstergame/Resources/Materials/muktargame-tanden.1.mat differ diff --git a/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/Monstergame/Resources/Materials/muktargame-tanden.1.mat.meta b/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/Monstergame/Resources/Materials/muktargame-tanden.1.mat.meta new file mode 100644 index 0000000..295b696 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/Monstergame/Resources/Materials/muktargame-tanden.1.mat.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: c4868b40d578c5646a5d89e4dfc705a0 diff --git a/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/Monstergame/Resources/Materials/muktargame-tanden.mat b/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/Monstergame/Resources/Materials/muktargame-tanden.mat new file mode 100644 index 0000000..542aab6 Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/Monstergame/Resources/Materials/muktargame-tanden.mat differ diff --git a/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/Monstergame/Resources/Materials/muktargame-tanden.mat.meta b/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/Monstergame/Resources/Materials/muktargame-tanden.mat.meta new file mode 100644 index 0000000..967e686 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/Monstergame/Resources/Materials/muktargame-tanden.mat.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 0b1af9419dc8fd0458d208780f7d6704 diff --git a/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/Monstergame/Resources/Materials/oudemanoogcolor.mat b/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/Monstergame/Resources/Materials/oudemanoogcolor.mat new file mode 100644 index 0000000..12e765e Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/Monstergame/Resources/Materials/oudemanoogcolor.mat differ diff --git a/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/Monstergame/Resources/Materials/oudemanoogcolor.mat.meta b/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/Monstergame/Resources/Materials/oudemanoogcolor.mat.meta new file mode 100644 index 0000000..bff8257 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/Monstergame/Resources/Materials/oudemanoogcolor.mat.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 709a0be2fd7ac094fbde0f03dbab5354 diff --git a/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/Monstergame/Resources/Scripts.meta b/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/Monstergame/Resources/Scripts.meta new file mode 100644 index 0000000..b8d2c5e --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/Monstergame/Resources/Scripts.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: fe20145f7ac864679a7b3548c759b0b5 +folderAsset: yes +timeCreated: 1501014812 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/Monstergame/Resources/Scripts/footstep.wav b/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/Monstergame/Resources/Scripts/footstep.wav new file mode 100644 index 0000000..e936d4f Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/Monstergame/Resources/Scripts/footstep.wav differ diff --git a/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/Monstergame/Resources/Scripts/footstep.wav.meta b/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/Monstergame/Resources/Scripts/footstep.wav.meta new file mode 100644 index 0000000..91bc554 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/Monstergame/Resources/Scripts/footstep.wav.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7d93183d7fa55d34fa5e60699b70656f +AudioImporter: + serializedVersion: 4 + format: 0 + quality: -1 + stream: 1 + 3D: 1 + forceToMono: 1 + useHardware: 0 + loopable: 0 diff --git a/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/Monstergame/Resources/Scripts/myThirdPersonController.cs b/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/Monstergame/Resources/Scripts/myThirdPersonController.cs new file mode 100644 index 0000000..7945670 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/Monstergame/Resources/Scripts/myThirdPersonController.cs @@ -0,0 +1,13 @@ + +public class myThirdPersonController : ThirdPersonController +{ + // The actual controller is in ThirdPersonController. + // For the PUN package, we just inherit that. + + // This class replaces the JS version of the same name for this tutorial. + + // Actually, the ThirdPersonController works (more or less) the same way as it's JS counterpart, + // but it's much easier to integrate being in C# as well (no need to move files around). + + // Please bear with us for this little fake. +} diff --git a/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/Monstergame/Resources/Scripts/myThirdPersonController.cs.meta b/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/Monstergame/Resources/Scripts/myThirdPersonController.cs.meta new file mode 100644 index 0000000..ece2230 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/Monstergame/Resources/Scripts/myThirdPersonController.cs.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: d73edb06d4aa53540ac19898993544e3 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} diff --git a/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/Monstergame/Resources/monsterprefab.prefab b/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/Monstergame/Resources/monsterprefab.prefab new file mode 100644 index 0000000..c392ee5 Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/Monstergame/Resources/monsterprefab.prefab differ diff --git a/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/Monstergame/Resources/monsterprefab.prefab.meta b/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/Monstergame/Resources/monsterprefab.prefab.meta new file mode 100644 index 0000000..dd9237c --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/Monstergame/Resources/monsterprefab.prefab.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 72ee9cccb2898bd428491db82f55e60a diff --git a/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/Monstergame/Resources/muktargame.fbx b/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/Monstergame/Resources/muktargame.fbx new file mode 100644 index 0000000..1768ca1 Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/Monstergame/Resources/muktargame.fbx differ diff --git a/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/Monstergame/Resources/muktargame.fbx.meta b/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/Monstergame/Resources/muktargame.fbx.meta new file mode 100644 index 0000000..52b9c90 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/Monstergame/Resources/muktargame.fbx.meta @@ -0,0 +1,573 @@ +fileFormatVersion: 2 +guid: 492cc7eb84514c64da25775df488c9e6 +ModelImporter: + fileIDToRecycleName: + 4300000: L_OOG + 4300002: R_oog + 4300004: muktar_2 + 4300006: boventanden + 4300008: ondertanden + 7400000: C4D Animation Take //// muktargame + 7400002: idle //// muktargame + 7400004: walk //// muktargame + 7400006: run //// muktargame + 7400008: jump //// muktargame + 7400010: attack //// muktargame + 7400012: fall //// muktargame + 7400014: die //// muktargame + 7400016: gothit //// muktargame + 100100000: DataTemplate __Singleton__ + serializedVersion: 10 + materials: + importMaterials: 1 + materialName: 3 + materialSearch: 1 + animations: + generateAnimations: 3 + bakeSimulation: 0 + splitAnimations: 1 + animationCompression: 1 + animationRotationError: .5 + animationPositionError: .5 + animationScaleError: .5 + animationWrapMode: 0 + clipAnimations: + - name: idle + firstFrame: 0 + lastFrame: 89 + wrapMode: 2 + loop: 0 + - name: walk + firstFrame: 91 + lastFrame: 150 + wrapMode: 2 + loop: 0 + - name: run + firstFrame: 152 + lastFrame: 181 + wrapMode: 2 + loop: 0 + - name: jump + firstFrame: 183 + lastFrame: 210 + wrapMode: 8 + loop: 0 + - name: attack + firstFrame: 214 + lastFrame: 249 + wrapMode: 1 + loop: 0 + - name: fall + firstFrame: 251 + lastFrame: 269 + wrapMode: 2 + loop: 0 + - name: die + firstFrame: 271 + lastFrame: 288 + wrapMode: 8 + loop: 0 + - name: gothit + firstFrame: 290 + lastFrame: 305 + wrapMode: 1 + loop: 0 + meshes: + lODScreenPercentages: [] + globalScale: .00999999978 + meshCompression: 0 + addColliders: 0 + swapUVChannels: 0 + generateSecondaryUV: 0 + useFileUnits: 1 + optimizeMesh: 0 + secondaryUVAngleDistortion: 8 + secondaryUVAreaDistortion: 15.000001 + secondaryUVHardAngle: 88 + secondaryUVPackMargin: 4 + tangentSpace: + normalSmoothAngle: 60 + splitTangentsAcrossUV: 1 + normalImportMode: 0 + tangentImportMode: 1 + textMetaNamesToFileIDs: + //RootNode: + data: + first: 1 + second: a2860100 + data: + first: 4 + second: 821a0600 + data: + first: 111 + second: 605fa900 + L_FOOT: + data: + first: 1 + second: 20870100 + data: + first: 4 + second: 001b0600 + L_OOG: + data: + first: 1 + second: b4860100 + data: + first: 4 + second: 941a0600 + data: + first: 137 + second: a80bd100 + L_ankle: + data: + first: 1 + second: fa860100 + data: + first: 4 + second: da1a0600 + L_ankle_kontrol: + data: + first: 1 + second: 1a870100 + data: + first: 4 + second: fa1a0600 + L_arm: + data: + first: 1 + second: e8860100 + data: + first: 4 + second: c81a0600 + L_elbow: + data: + first: 1 + second: e6860100 + data: + first: 4 + second: c61a0600 + L_eye: + data: + first: 1 + second: c0860100 + data: + first: 4 + second: a01a0600 + L_finger1: + data: + first: 1 + second: dc860100 + data: + first: 4 + second: bc1a0600 + L_finger2: + data: + first: 1 + second: da860100 + data: + first: 4 + second: ba1a0600 + L_fingertip: + data: + first: 1 + second: d8860100 + data: + first: 4 + second: b81a0600 + L_foot: + data: + first: 1 + second: f8860100 + data: + first: 4 + second: d81a0600 + L_footkontrol: + data: + first: 1 + second: 1c870100 + data: + first: 4 + second: fc1a0600 + L_knee: + data: + first: 1 + second: fc860100 + data: + first: 4 + second: dc1a0600 + L_leg: + data: + first: 1 + second: fe860100 + data: + first: 4 + second: de1a0600 + L_leg_Pole: + data: + first: 1 + second: 10870100 + data: + first: 4 + second: f01a0600 + L_thumb1: + data: + first: 1 + second: e2860100 + data: + first: 4 + second: c21a0600 + L_thumb2: + data: + first: 1 + second: e0860100 + data: + first: 4 + second: c01a0600 + L_thumbtip: + data: + first: 1 + second: de860100 + data: + first: 4 + second: be1a0600 + L_toes: + data: + first: 1 + second: f6860100 + data: + first: 4 + second: d61a0600 + L_toeskontrol: + data: + first: 1 + second: 1e870100 + data: + first: 4 + second: fe1a0600 + L_wrist: + data: + first: 1 + second: e4860100 + data: + first: 4 + second: c41a0600 + L_wristkontrol: + data: + first: 1 + second: 0c870100 + data: + first: 4 + second: ec1a0600 + Null: + data: + first: 1 + second: b2860100 + data: + first: 4 + second: 921a0600 + Null_2: + data: + first: 1 + second: ae860100 + data: + first: 4 + second: 8e1a0600 + Null_3: + data: + first: 1 + second: aa860100 + data: + first: 4 + second: 8a1a0600 + Null_4: + data: + first: 1 + second: a6860100 + data: + first: 4 + second: 861a0600 + Null_5: + data: + first: 1 + second: a0860100 + data: + first: 4 + second: 801a0600 + R_FOOT: + data: + first: 1 + second: 18870100 + data: + first: 4 + second: f81a0600 + R_ankle: + data: + first: 1 + second: f0860100 + data: + first: 4 + second: d01a0600 + R_ankle_kontrol: + data: + first: 1 + second: 12870100 + data: + first: 4 + second: f21a0600 + R_arm: + data: + first: 1 + second: d6860100 + data: + first: 4 + second: b61a0600 + R_elbow: + data: + first: 1 + second: d4860100 + data: + first: 4 + second: b41a0600 + R_eye: + data: + first: 1 + second: be860100 + data: + first: 4 + second: 9e1a0600 + R_finger1: + data: + first: 1 + second: ca860100 + data: + first: 4 + second: aa1a0600 + R_finger2: + data: + first: 1 + second: c8860100 + data: + first: 4 + second: a81a0600 + R_fingertip: + data: + first: 1 + second: c6860100 + data: + first: 4 + second: a61a0600 + R_foot: + data: + first: 1 + second: ee860100 + data: + first: 4 + second: ce1a0600 + R_footkontrol: + data: + first: 1 + second: 14870100 + data: + first: 4 + second: f41a0600 + R_knee: + data: + first: 1 + second: f2860100 + data: + first: 4 + second: d21a0600 + R_leg: + data: + first: 1 + second: f4860100 + data: + first: 4 + second: d41a0600 + R_leg_Pole: + data: + first: 1 + second: 0e870100 + data: + first: 4 + second: ee1a0600 + R_oog: + data: + first: 1 + second: b0860100 + data: + first: 4 + second: 901a0600 + data: + first: 137 + second: a60bd100 + R_thumb1: + data: + first: 1 + second: d0860100 + data: + first: 4 + second: b01a0600 + R_thumb2: + data: + first: 1 + second: ce860100 + data: + first: 4 + second: ae1a0600 + R_thumbtip: + data: + first: 1 + second: cc860100 + data: + first: 4 + second: ac1a0600 + R_toes: + data: + first: 1 + second: ec860100 + data: + first: 4 + second: cc1a0600 + R_toeskontrol: + data: + first: 1 + second: 16870100 + data: + first: 4 + second: f61a0600 + R_wrist: + data: + first: 1 + second: d2860100 + data: + first: 4 + second: b21a0600 + R_wristkontrol: + data: + first: 1 + second: 0a870100 + data: + first: 4 + second: ea1a0600 + belly: + data: + first: 1 + second: ea860100 + data: + first: 4 + second: ca1a0600 + bellykontrol: + data: + first: 1 + second: 06870100 + data: + first: 4 + second: e61a0600 + boventanden: + data: + first: 1 + second: a8860100 + data: + first: 4 + second: 881a0600 + data: + first: 137 + second: a20bd100 + head: + data: + first: 1 + second: c2860100 + data: + first: 4 + second: a21a0600 + hip: + data: + first: 1 + second: 00870100 + data: + first: 4 + second: e01a0600 + hipkontrol: + data: + first: 1 + second: 04870100 + data: + first: 4 + second: e41a0600 + jaw: + data: + first: 1 + second: bc860100 + data: + first: 4 + second: 9c1a0600 + lip: + data: + first: 1 + second: ba860100 + data: + first: 4 + second: 9a1a0600 + muktar: + data: + first: 1 + second: b6860100 + data: + first: 4 + second: 961a0600 + muktar_2: + data: + first: 1 + second: ac860100 + data: + first: 4 + second: 8c1a0600 + data: + first: 137 + second: a40bd100 + n_Side: + data: + first: 1 + second: 22870100 + data: + first: 4 + second: 021b0600 + ondertanden: + data: + first: 1 + second: a4860100 + data: + first: 4 + second: 841a0600 + data: + first: 137 + second: a00bd100 + shoulder: + data: + first: 1 + second: c4860100 + data: + first: 4 + second: a41a0600 + shoulderkontrol: + data: + first: 1 + second: 08870100 + data: + first: 4 + second: e81a0600 + spine: + data: + first: 1 + second: 02870100 + data: + first: 4 + second: e21a0600 + top: + data: + first: 1 + second: b8860100 + data: + first: 4 + second: 981a0600 diff --git a/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/Monstergame/Resources/textures.meta b/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/Monstergame/Resources/textures.meta new file mode 100644 index 0000000..4613e69 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/Monstergame/Resources/textures.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: c7079dc6b64fe4881877e709711d90d7 +folderAsset: yes +timeCreated: 1501014812 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/Monstergame/Resources/textures/muktarcolorgoed_1.jpg b/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/Monstergame/Resources/textures/muktarcolorgoed_1.jpg new file mode 100644 index 0000000..2228381 Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/Monstergame/Resources/textures/muktarcolorgoed_1.jpg differ diff --git a/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/Monstergame/Resources/textures/muktarcolorgoed_1.jpg.meta b/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/Monstergame/Resources/textures/muktarcolorgoed_1.jpg.meta new file mode 100644 index 0000000..f0a6c23 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/Monstergame/Resources/textures/muktarcolorgoed_1.jpg.meta @@ -0,0 +1,33 @@ +fileFormatVersion: 2 +guid: 411b6fcda46437e41a6f9ad727cafe03 +TextureImporter: + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + linearTexture: 0 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + textureFormat: -1 + maxTextureSize: 2048 + textureSettings: + filterMode: 2 + aniso: 1 + mipBias: -1 + wrapMode: 0 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + textureType: 0 + buildTargetSettings: [] diff --git a/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/Monstergame/Resources/textures/muktarnormalhighq_1.jpg b/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/Monstergame/Resources/textures/muktarnormalhighq_1.jpg new file mode 100644 index 0000000..a37ac07 Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/Monstergame/Resources/textures/muktarnormalhighq_1.jpg differ diff --git a/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/Monstergame/Resources/textures/muktarnormalhighq_1.jpg.meta b/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/Monstergame/Resources/textures/muktarnormalhighq_1.jpg.meta new file mode 100644 index 0000000..12c05ef --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/Monstergame/Resources/textures/muktarnormalhighq_1.jpg.meta @@ -0,0 +1,33 @@ +fileFormatVersion: 2 +guid: 8f3b8af169a9a814698111fd64643579 +TextureImporter: + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + linearTexture: 1 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 1 + externalNormalMap: 1 + heightScale: .125599995 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + textureFormat: -1 + maxTextureSize: 1024 + textureSettings: + filterMode: -1 + aniso: -1 + mipBias: -1 + wrapMode: -1 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + textureType: 1 + buildTargetSettings: [] diff --git a/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/Monstergame/Resources/textures/oudemanoogcolor_1.jpg b/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/Monstergame/Resources/textures/oudemanoogcolor_1.jpg new file mode 100644 index 0000000..3f24406 Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/Monstergame/Resources/textures/oudemanoogcolor_1.jpg differ diff --git a/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/Monstergame/Resources/textures/oudemanoogcolor_1.jpg.meta b/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/Monstergame/Resources/textures/oudemanoogcolor_1.jpg.meta new file mode 100644 index 0000000..cea4b75 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/Monstergame/Resources/textures/oudemanoogcolor_1.jpg.meta @@ -0,0 +1,33 @@ +fileFormatVersion: 2 +guid: 4560358f08b2be84faf7909c817c6bdd +TextureImporter: + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + linearTexture: 0 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + textureFormat: -1 + maxTextureSize: 1024 + textureSettings: + filterMode: -1 + aniso: -1 + mipBias: -1 + wrapMode: -1 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + textureType: -1 + buildTargetSettings: [] diff --git a/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/NetworkCharacter.cs b/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/NetworkCharacter.cs new file mode 100644 index 0000000..ac548eb --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/NetworkCharacter.cs @@ -0,0 +1,38 @@ +using UnityEngine; + +public class NetworkCharacter : Photon.MonoBehaviour +{ + private Vector3 correctPlayerPos = Vector3.zero; // We lerp towards this + private Quaternion correctPlayerRot = Quaternion.identity; // We lerp towards this + // Update is called once per frame + void Update() + { + if (!photonView.isMine) + { + transform.position = Vector3.Lerp(transform.position, this.correctPlayerPos, Time.deltaTime * 5); + transform.rotation = Quaternion.Lerp(transform.rotation, this.correctPlayerRot, Time.deltaTime * 5); + } + } + + void OnPhotonSerializeView(PhotonStream stream, PhotonMessageInfo info) + { + if (stream.isWriting) + { + // We own this player: send the others our data + stream.SendNext(transform.position); + stream.SendNext(transform.rotation); + + myThirdPersonController myC = GetComponent(); + stream.SendNext((int)myC._characterState); + } + else + { + // Network player, receive data + this.correctPlayerPos = (Vector3)stream.ReceiveNext(); + this.correctPlayerRot = (Quaternion)stream.ReceiveNext(); + + myThirdPersonController myC = GetComponent(); + myC._characterState = (CharacterState)stream.ReceiveNext(); + } + } +} \ No newline at end of file diff --git a/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/NetworkCharacter.cs.meta b/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/NetworkCharacter.cs.meta new file mode 100644 index 0000000..db59bf7 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/NetworkCharacter.cs.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 6c59ba0703a79d54c93a0e9991174504 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} diff --git a/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/OnClickLoadSomething.cs b/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/OnClickLoadSomething.cs new file mode 100644 index 0000000..abcfb7f --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/OnClickLoadSomething.cs @@ -0,0 +1,32 @@ +using UnityEngine; +using System.Collections; +using UnityEngine.SceneManagement; + +/// +/// This component makes it easy to switch scenes or open webpages on click. +/// Requires a InputToEvent component on the camera to forward clicks on screen. +/// +public class OnClickLoadSomething : MonoBehaviour +{ + public enum ResourceTypeOption : byte + { + Scene, + Web + } + + public ResourceTypeOption ResourceTypeToLoad = ResourceTypeOption.Scene; + public string ResourceToLoad; + + public void OnClick() + { + switch (ResourceTypeToLoad) + { + case ResourceTypeOption.Scene: + SceneManager.LoadScene(ResourceToLoad); + break; + case ResourceTypeOption.Web: + Application.OpenURL(ResourceToLoad); + break; + } + } +} diff --git a/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/OnClickLoadSomething.cs.meta b/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/OnClickLoadSomething.cs.meta new file mode 100644 index 0000000..680947b --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/OnClickLoadSomething.cs.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: a9b53cc9db43d39428412f981834d9c1 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} diff --git a/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/Polo.mp3 b/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/Polo.mp3 new file mode 100644 index 0000000..27038ae Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/Polo.mp3 differ diff --git a/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/Polo.mp3.meta b/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/Polo.mp3.meta new file mode 100644 index 0000000..d3b18cf --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/Polo.mp3.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 4ad7633f7befb9d4b81c2123c39c2dae +AudioImporter: + serializedVersion: 4 + format: 0 + quality: .5 + stream: 1 + 3D: 1 + forceToMono: 0 + useHardware: 0 + loopable: 0 + userData: diff --git a/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/RandomMatchmaker.cs b/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/RandomMatchmaker.cs new file mode 100644 index 0000000..e39b49c --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/RandomMatchmaker.cs @@ -0,0 +1,55 @@ +using UnityEngine; + +public class RandomMatchmaker : Photon.PunBehaviour +{ + private PhotonView myPhotonView; + + // Use this for initialization + public void Start() + { + PhotonNetwork.ConnectUsingSettings("0.1"); + } + + public override void OnJoinedLobby() + { + Debug.Log("JoinRandom"); + PhotonNetwork.JoinRandomRoom(); + } + + public override void OnConnectedToMaster() + { + // when AutoJoinLobby is off, this method gets called when PUN finished the connection (instead of OnJoinedLobby()) + PhotonNetwork.JoinRandomRoom(); + } + + public void OnPhotonRandomJoinFailed() + { + PhotonNetwork.CreateRoom(null); + } + + public override void OnJoinedRoom() + { + GameObject monster = PhotonNetwork.Instantiate("monsterprefab", Vector3.zero, Quaternion.identity, 0); + monster.GetComponent().isControllable = true; + myPhotonView = monster.GetComponent(); + } + + public void OnGUI() + { + GUILayout.Label(PhotonNetwork.connectionStateDetailed.ToString()); + + if (PhotonNetwork.inRoom) + { + bool shoutMarco = GameLogic.playerWhoIsIt == PhotonNetwork.player.ID; + + if (shoutMarco && GUILayout.Button("Marco!")) + { + myPhotonView.RPC("Marco", PhotonTargets.All); + } + if (!shoutMarco && GUILayout.Button("Polo!")) + { + myPhotonView.RPC("Polo", PhotonTargets.All); + } + } + } +} diff --git a/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/RandomMatchmaker.cs.meta b/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/RandomMatchmaker.cs.meta new file mode 100644 index 0000000..bcd8c0e --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/RandomMatchmaker.cs.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: b522ba8b66e20ad4994ab4cad343795d +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} diff --git a/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/Substances_Free.meta b/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/Substances_Free.meta new file mode 100644 index 0000000..0e90e03 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/Substances_Free.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: c4420361e4df441b785551056b16cbf9 +folderAsset: yes +timeCreated: 1501014811 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/Substances_Free/Pavement_01.sbsar b/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/Substances_Free/Pavement_01.sbsar new file mode 100644 index 0000000..d000ebf Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/Substances_Free/Pavement_01.sbsar differ diff --git a/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/Substances_Free/Pavement_01.sbsar.meta b/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/Substances_Free/Pavement_01.sbsar.meta new file mode 100644 index 0000000..7a562cb --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/Substances_Free/Pavement_01.sbsar.meta @@ -0,0 +1,175 @@ +fileFormatVersion: 2 +guid: 99267cd9ef908d8469ef526e479775a6 +SubstanceImporter: + serializedVersion: 3 + materialInstances: + - name: Pavement_01 + prototypeName: Pavement_01 + shaderName: Bumped Specular + inputs: + - name: $normalformat + value: + scalar[0]: 0 + scalar[1]: 0 + scalar[2]: 0 + scalar[3]: 0 + texture: {instanceID: 0} + - name: $outputsize + value: + scalar[0]: 9 + scalar[1]: 9 + scalar[2]: 0 + scalar[3]: 0 + texture: {instanceID: 0} + - name: $randomseed + value: + scalar[0]: 0 + scalar[1]: 0 + scalar[2]: 0 + scalar[3]: 0 + texture: {instanceID: 0} + - name: Age + value: + scalar[0]: 0 + scalar[1]: 0 + scalar[2]: 0 + scalar[3]: 0 + texture: {instanceID: 0} + - name: Colour_Variation + value: + scalar[0]: .5 + scalar[1]: 0 + scalar[2]: 0 + scalar[3]: 0 + texture: {instanceID: 0} + - name: Water_Level + value: + scalar[0]: 0 + scalar[1]: 0 + scalar[2]: 0 + scalar[3]: 0 + texture: {instanceID: 0} + - name: Wavelets + value: + scalar[0]: 0 + scalar[1]: 0 + scalar[2]: 0 + scalar[3]: 0 + texture: {instanceID: 0} + - name: Depth + value: + scalar[0]: 0 + scalar[1]: 0 + scalar[2]: 0 + scalar[3]: 0 + texture: {instanceID: 0} + - name: Relief_Balance + value: + scalar[0]: 32 + scalar[1]: 0 + scalar[2]: 0 + scalar[3]: 0 + texture: {instanceID: 0} + - name: Normal + value: + scalar[0]: .5 + scalar[1]: 0 + scalar[2]: 0 + scalar[3]: 0 + texture: {instanceID: 0} + - name: Emboss + value: + scalar[0]: 5 + scalar[1]: 0 + scalar[2]: 0 + scalar[3]: 0 + texture: {instanceID: 0} + - name: Angle + value: + scalar[0]: .125 + scalar[1]: 0 + scalar[2]: 0 + scalar[3]: 0 + texture: {instanceID: 0} + - name: Hue_Shift + value: + scalar[0]: 0 + scalar[1]: 0 + scalar[2]: 0 + scalar[3]: 0 + texture: {instanceID: 0} + - name: Saturation + value: + scalar[0]: .5 + scalar[1]: 0 + scalar[2]: 0 + scalar[3]: 0 + texture: {instanceID: 0} + - name: Luminosity + value: + scalar[0]: .5 + scalar[1]: 0 + scalar[2]: 0 + scalar[3]: 0 + texture: {instanceID: 0} + - name: Contrast + value: + scalar[0]: 0 + scalar[1]: 0 + scalar[2]: 0 + scalar[3]: 0 + texture: {instanceID: 0} + materialInformation: + offset: {x: 0, y: 0} + scale: {x: 10, y: 10} + generatedAtLoading: 1 + generateAllOutputs: 1 + animationUpdateRate: 42 + materialProperties: + serializedVersion: 2 + texEnvs: {} + floats: {} + colors: {} + textureParameters: + - name: Pavement_01_Diffuse + alphaSource: 5 + filterMode: 1 + aniso: 1 + wrapMode: 0 + - name: Pavement_01_Specular + alphaSource: 0 + filterMode: 1 + aniso: 1 + wrapMode: 0 + - name: Pavement_01_Normal + alphaSource: 0 + filterMode: 1 + aniso: 1 + wrapMode: 0 + - name: Pavement_01_Bump + alphaSource: 0 + filterMode: 1 + aniso: 1 + wrapMode: 0 + - name: Pavement_01_Displacement + alphaSource: 0 + filterMode: 1 + aniso: 1 + wrapMode: 0 + - name: Pavement_01_Height + alphaSource: 0 + filterMode: 1 + aniso: 1 + wrapMode: 0 + - name: Pavement_01_Glossiness + alphaSource: 0 + filterMode: 1 + aniso: 1 + wrapMode: 0 + buildTargetSettings: + - serializedVersion: 2 + buildTarget: + textureWidth: 512 + textureHeight: 512 + textureFormat: 0 + deletedPrototypes: [] diff --git a/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/marcopolo-readme.txt b/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/marcopolo-readme.txt new file mode 100644 index 0000000..f808985 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/marcopolo-readme.txt @@ -0,0 +1,18 @@ + + +The Marco Polo Tutorial + is an online-only resource to learn the basics of using Photon Unity Networking (PUN). + Covered are: Connect, find a room, react to joining players, synchronizing positions and animations and more. + This package includes the result of the tutorial but in best case, you implement each step while reading. + + +The step-by-step guide can be found here: + http://doc.exitgames.com/en/pun/current/tutorials/tutorial-marco-polo + + +Disclaimer + The results of the tutorial have been adjusted to better fit into this packge: + The myThirdPersonController used here is a C# script (which saves some file moving). + A 3D Text offers you info and to open the tutorial online. + Some code will differ from the individual passages. + Removed some of the "Monster" package's to reduce package size. \ No newline at end of file diff --git a/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/marcopolo-readme.txt.meta b/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/marcopolo-readme.txt.meta new file mode 100644 index 0000000..eb496fa --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/MarcoPolo-Tutorial/marcopolo-readme.txt.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: ff8b741255b6ea5449005dd6acc486a4 diff --git a/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial.meta b/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial.meta new file mode 100644 index 0000000..9da4d45 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: b018e3750177e4b5f85e4e2be12c232a +folderAsset: yes +timeCreated: 1501014811 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Animator.meta b/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Animator.meta new file mode 100644 index 0000000..55a5620 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Animator.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 9d0e2008d4223456f9a5548ade1f461c +folderAsset: yes +timeCreated: 1501014811 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Animator/Kyle Robot.controller b/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Animator/Kyle Robot.controller new file mode 100644 index 0000000..bd3fb0f Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Animator/Kyle Robot.controller differ diff --git a/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Animator/Kyle Robot.controller.meta b/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Animator/Kyle Robot.controller.meta new file mode 100644 index 0000000..d66371a --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Animator/Kyle Robot.controller.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: 1b222757b9e3844209748206173481c3 +NativeFormatImporter: + userData: diff --git a/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Materials.meta b/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Materials.meta new file mode 100644 index 0000000..627aba9 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Materials.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 5ff04f518714f43399741d26756694f1 +folderAsset: yes +timeCreated: 1501014811 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Materials/Red Beam.mat b/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Materials/Red Beam.mat new file mode 100644 index 0000000..100a3b8 Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Materials/Red Beam.mat differ diff --git a/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Materials/Red Beam.mat.meta b/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Materials/Red Beam.mat.meta new file mode 100644 index 0000000..076d6ef --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Materials/Red Beam.mat.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: 409bf720e9924426b9f253cf037a8f4e +NativeFormatImporter: + userData: diff --git a/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Materials/UnitTextureGreen12x.mat b/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Materials/UnitTextureGreen12x.mat new file mode 100644 index 0000000..f1799ba Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Materials/UnitTextureGreen12x.mat differ diff --git a/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Materials/UnitTextureGreen12x.mat.meta b/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Materials/UnitTextureGreen12x.mat.meta new file mode 100644 index 0000000..6cad9e2 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Materials/UnitTextureGreen12x.mat.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: 8c13ddd2bc8fa4e85943376cf7c8bf7d +NativeFormatImporter: + userData: diff --git a/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Materials/UnitTextureRed12x.mat b/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Materials/UnitTextureRed12x.mat new file mode 100644 index 0000000..b1646eb Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Materials/UnitTextureRed12x.mat differ diff --git a/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Materials/UnitTextureRed12x.mat.meta b/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Materials/UnitTextureRed12x.mat.meta new file mode 100644 index 0000000..5e45bf6 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Materials/UnitTextureRed12x.mat.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: 3f171282ef46c4fbea54d9ab581fcb83 +NativeFormatImporter: + userData: diff --git a/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Materials/UnitTextureYellow12x.mat b/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Materials/UnitTextureYellow12x.mat new file mode 100644 index 0000000..c9608c6 Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Materials/UnitTextureYellow12x.mat differ diff --git a/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Materials/UnitTextureYellow12x.mat.meta b/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Materials/UnitTextureYellow12x.mat.meta new file mode 100644 index 0000000..cb98e4a --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Materials/UnitTextureYellow12x.mat.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: ceba02e8dfaf34474b36fe43b51b69db +NativeFormatImporter: + userData: diff --git a/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Prefabs.meta b/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Prefabs.meta new file mode 100644 index 0000000..ae120e8 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Prefabs.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 74e47081a20c349baaf92744999f7a6f +folderAsset: yes +timeCreated: 1501014811 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Prefabs/Demo Intro UI.prefab b/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Prefabs/Demo Intro UI.prefab new file mode 100644 index 0000000..b3b2677 Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Prefabs/Demo Intro UI.prefab differ diff --git a/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Prefabs/Demo Intro UI.prefab.meta b/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Prefabs/Demo Intro UI.prefab.meta new file mode 100644 index 0000000..8451f9a --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Prefabs/Demo Intro UI.prefab.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: f773d1fa10a4f4e0d88490eab5d5b46d +NativeFormatImporter: + userData: diff --git a/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Prefabs/Game Manager.prefab b/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Prefabs/Game Manager.prefab new file mode 100644 index 0000000..88880d5 Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Prefabs/Game Manager.prefab differ diff --git a/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Prefabs/Game Manager.prefab.meta b/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Prefabs/Game Manager.prefab.meta new file mode 100644 index 0000000..54560db --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Prefabs/Game Manager.prefab.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: b7fe671fa5d4d4772a4b20715fb9b0ff +NativeFormatImporter: + userData: diff --git a/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Prefabs/Player UI.prefab b/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Prefabs/Player UI.prefab new file mode 100644 index 0000000..8fdb797 Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Prefabs/Player UI.prefab differ diff --git a/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Prefabs/Player UI.prefab.meta b/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Prefabs/Player UI.prefab.meta new file mode 100644 index 0000000..4c67d54 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Prefabs/Player UI.prefab.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: e41946a981c3b444a84d15eb7c608ca4 +NativeFormatImporter: + userData: diff --git a/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Prefabs/Quit Room Button.prefab b/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Prefabs/Quit Room Button.prefab new file mode 100644 index 0000000..5cc7978 Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Prefabs/Quit Room Button.prefab differ diff --git a/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Prefabs/Quit Room Button.prefab.meta b/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Prefabs/Quit Room Button.prefab.meta new file mode 100644 index 0000000..1df0405 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Prefabs/Quit Room Button.prefab.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: b19bb80838bcf4457bf6f50a19c5593b +NativeFormatImporter: + userData: diff --git a/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Resources.meta b/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Resources.meta new file mode 100644 index 0000000..96f529d --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Resources.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 68498a33260a84efba07afc9f4a2a21e +folderAsset: yes +timeCreated: 1501014811 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Resources/My Robot Kyle.prefab b/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Resources/My Robot Kyle.prefab new file mode 100644 index 0000000..8f49e4a Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Resources/My Robot Kyle.prefab differ diff --git a/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Resources/My Robot Kyle.prefab.meta b/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Resources/My Robot Kyle.prefab.meta new file mode 100644 index 0000000..6b8b57f --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Resources/My Robot Kyle.prefab.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: fe764102aa5aa431795da15fa2dec0e2 +NativeFormatImporter: + userData: diff --git a/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Scenes.meta b/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Scenes.meta new file mode 100644 index 0000000..bf8ba78 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Scenes.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: b0dda30182d9e4a4a837c8dd9eaf5a92 +folderAsset: yes +timeCreated: 1501014811 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Scenes/PunBasics-Launcher.unity b/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Scenes/PunBasics-Launcher.unity new file mode 100644 index 0000000..d979471 Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Scenes/PunBasics-Launcher.unity differ diff --git a/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Scenes/PunBasics-Launcher.unity.meta b/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Scenes/PunBasics-Launcher.unity.meta new file mode 100644 index 0000000..cae0a86 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Scenes/PunBasics-Launcher.unity.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: bff77b01b50254edbb6edeeaba5ae8b3 +DefaultImporter: + userData: diff --git a/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Scenes/PunBasics-Room for 1.unity b/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Scenes/PunBasics-Room for 1.unity new file mode 100644 index 0000000..1bad34c Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Scenes/PunBasics-Room for 1.unity differ diff --git a/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Scenes/PunBasics-Room for 1.unity.meta b/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Scenes/PunBasics-Room for 1.unity.meta new file mode 100644 index 0000000..bb0b571 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Scenes/PunBasics-Room for 1.unity.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: 9b8561c6e396849a5ba48c3eb9524049 +DefaultImporter: + userData: diff --git a/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Scenes/PunBasics-Room for 2.unity b/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Scenes/PunBasics-Room for 2.unity new file mode 100644 index 0000000..6da186e Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Scenes/PunBasics-Room for 2.unity differ diff --git a/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Scenes/PunBasics-Room for 2.unity.meta b/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Scenes/PunBasics-Room for 2.unity.meta new file mode 100644 index 0000000..cc72049 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Scenes/PunBasics-Room for 2.unity.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: 764428c63577f4580af4ce54ca9f4b1b +DefaultImporter: + userData: diff --git a/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Scenes/PunBasics-Room for 3.unity b/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Scenes/PunBasics-Room for 3.unity new file mode 100644 index 0000000..f7bc0aa Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Scenes/PunBasics-Room for 3.unity differ diff --git a/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Scenes/PunBasics-Room for 3.unity.meta b/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Scenes/PunBasics-Room for 3.unity.meta new file mode 100644 index 0000000..afe5b22 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Scenes/PunBasics-Room for 3.unity.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: e07afcca5bf1a41f5bd28f498656b7b8 +DefaultImporter: + userData: diff --git a/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Scenes/PunBasics-Room for 4.unity b/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Scenes/PunBasics-Room for 4.unity new file mode 100644 index 0000000..05b5fed Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Scenes/PunBasics-Room for 4.unity differ diff --git a/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Scenes/PunBasics-Room for 4.unity.meta b/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Scenes/PunBasics-Room for 4.unity.meta new file mode 100644 index 0000000..c8f3f79 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Scenes/PunBasics-Room for 4.unity.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: e7a7f9734636d415ca84ef3aaf7680f6 +DefaultImporter: + userData: diff --git a/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Scripts.meta b/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Scripts.meta new file mode 100644 index 0000000..b5081f8 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Scripts.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 4e15eb1610c524b04bcfcfdd4220a600 +folderAsset: yes +timeCreated: 1501014811 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Scripts/CameraWork.cs b/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Scripts/CameraWork.cs new file mode 100644 index 0000000..9e388b8 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Scripts/CameraWork.cs @@ -0,0 +1,180 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Part of: Photon Unity Networking Demos +// +// +// Used in DemoAnimator to deal with the Camera work to follow the player +// +// developer@exitgames.com +// -------------------------------------------------------------------------------------------------------------------- + +using UnityEngine; +using System.Collections; + +namespace ExitGames.Demos.DemoAnimator +{ + /// + /// Camera work. Follow a target + /// + public class CameraWork : MonoBehaviour + { + + #region Public Properties + + [Tooltip("The distance in the local x-z plane to the target")] + public float distance = 7.0f; + + [Tooltip("The height we want the camera to be above the target")] + public float height = 3.0f; + + [Tooltip("The Smooth time lag for the height of the camera.")] + public float heightSmoothLag = 0.3f; + + [Tooltip("Allow the camera to be offseted vertically from the target, for example giving more view of the sceneray and less ground.")] + public Vector3 centerOffset = Vector3.zero; + + [Tooltip("Set this as false if a component of a prefab being instanciated by Photon Network, and manually call OnStartFollowing() when and if needed.")] + public bool followOnStart = false; + + #endregion + + #region Private Properties + + // cached transform of the target + Transform cameraTransform; + + // maintain a flag internally to reconnect if target is lost or camera is switched + bool isFollowing; + + // Represents the current velocity, this value is modified by SmoothDamp() every time you call it. + private float heightVelocity = 0.0f; + + // Represents the position we are trying to reach using SmoothDamp() + private float targetHeight = 100000.0f; + + #endregion + + #region MonoBehaviour Messages + + /// + /// MonoBehaviour method called on GameObject by Unity during initialization phase + /// + void Start() + { + // Start following the target if wanted. + if (followOnStart) + { + OnStartFollowing(); + } + + } + + /// + /// MonoBehaviour method called after all Update functions have been called. This is useful to order script execution. For example a follow camera should always be implemented in LateUpdate because it tracks objects that might have moved inside Update. + /// + void LateUpdate() + { + // The transform target may not destroy on level load, + // so we need to cover corner cases where the Main Camera is different everytime we load a new scene, and reconnect when that happens + if (cameraTransform == null && isFollowing) + { + OnStartFollowing(); + } + + // only follow is explicitly declared + if (isFollowing) { + Apply (); + } + } + + #endregion + + #region Public Methods + + /// + /// Raises the start following event. + /// Use this when you don't know at the time of editing what to follow, typically instances managed by the photon network. + /// + public void OnStartFollowing() + { + cameraTransform = Camera.main.transform; + isFollowing = true; + // we don't smooth anything, we go straight to the right camera shot + Cut(); + } + + #endregion + + #region Private Methods + + /// + /// Follow the target smoothly + /// + void Apply() + { + Vector3 targetCenter = transform.position + centerOffset; + + // Calculate the current & target rotation angles + float originalTargetAngle = transform.eulerAngles.y; + float currentAngle = cameraTransform.eulerAngles.y; + + // Adjust real target angle when camera is locked + float targetAngle = originalTargetAngle; + + currentAngle = targetAngle; + + targetHeight = targetCenter.y + height; + + // Damp the height + float currentHeight = cameraTransform.position.y; + currentHeight = Mathf.SmoothDamp( currentHeight, targetHeight, ref heightVelocity, heightSmoothLag ); + + // Convert the angle into a rotation, by which we then reposition the camera + Quaternion currentRotation = Quaternion.Euler( 0, currentAngle, 0 ); + + // Set the position of the camera on the x-z plane to: + // distance meters behind the target + cameraTransform.position = targetCenter; + cameraTransform.position += currentRotation * Vector3.back * distance; + + // Set the height of the camera + cameraTransform.position = new Vector3( cameraTransform.position.x, currentHeight, cameraTransform.position.z ); + + // Always look at the target + SetUpRotation(targetCenter); + } + + + /// + /// Directly position the camera to a the specified Target and center. + /// + void Cut( ) + { + float oldHeightSmooth = heightSmoothLag; + heightSmoothLag = 0.001f; + + Apply(); + + heightSmoothLag = oldHeightSmooth; + } + + /// + /// Sets up the rotation of the camera to always be behind the target + /// + /// Center position. + void SetUpRotation( Vector3 centerPos ) + { + Vector3 cameraPos = cameraTransform.position; + Vector3 offsetToCenter = centerPos - cameraPos; + + // Generate base rotation only around y-axis + Quaternion yRotation = Quaternion.LookRotation( new Vector3( offsetToCenter.x, 0, offsetToCenter.z ) ); + + Vector3 relativeOffset = Vector3.forward * distance + Vector3.down * height; + cameraTransform.rotation = yRotation * Quaternion.LookRotation( relativeOffset ); + + } + + #endregion + } +} \ No newline at end of file diff --git a/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Scripts/CameraWork.cs.meta b/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Scripts/CameraWork.cs.meta new file mode 100644 index 0000000..f06e365 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Scripts/CameraWork.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: fd08475b23aa548b7b9d28397d430b32 +labels: +- ExitGames +- PUN +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Scripts/GameManager.cs b/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Scripts/GameManager.cs new file mode 100644 index 0000000..d19e3db --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Scripts/GameManager.cs @@ -0,0 +1,173 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Part of: Photon Unity Networking Demos +// +// +// Used in "PUN Basic tutorial" to handle typical game management requirements +// +// developer@exitgames.com +// -------------------------------------------------------------------------------------------------------------------- + +using System; +using System.Collections; + +using UnityEngine; +using UnityEngine.SceneManagement; + +using ExitGames.Client.Photon; + +namespace ExitGames.Demos.DemoAnimator +{ + /// + /// Game manager. + /// Connects and watch Photon Status, Instantiate Player + /// Deals with quiting the room and the game + /// Deals with level loading (outside the in room synchronization) + /// + public class GameManager : Photon.MonoBehaviour { + + #region Public Variables + + static public GameManager Instance; + + [Tooltip("The prefab to use for representing the player")] + public GameObject playerPrefab; + + #endregion + + #region Private Variables + + private GameObject instance; + + #endregion + + #region MonoBehaviour CallBacks + + /// + /// MonoBehaviour method called on GameObject by Unity during initialization phase. + /// + void Start() + { + Instance = this; + + // in case we started this demo with the wrong scene being active, simply load the menu scene + if (!PhotonNetwork.connected) + { + SceneManager.LoadScene("PunBasics-Launcher"); + + return; + } + + if (playerPrefab == null) { // #Tip Never assume public properties of Components are filled up properly, always check and inform the developer of it. + + Debug.LogError("Missing playerPrefab Reference. Please set it up in GameObject 'Game Manager'",this); + } else { + + + if (PlayerManager.LocalPlayerInstance==null) + { + Debug.Log("We are Instantiating LocalPlayer from "+SceneManagerHelper.ActiveSceneName); + + // we're in a room. spawn a character for the local player. it gets synced by using PhotonNetwork.Instantiate + PhotonNetwork.Instantiate(this.playerPrefab.name, new Vector3(0f,5f,0f), Quaternion.identity, 0); + }else{ + + Debug.Log("Ignoring scene load for "+ SceneManagerHelper.ActiveSceneName); + } + + + } + + } + + /// + /// MonoBehaviour method called on GameObject by Unity on every frame. + /// + void Update() + { + // "back" button of phone equals "Escape". quit app if that's pressed + if (Input.GetKeyDown(KeyCode.Escape)) + { + QuitApplication(); + } + } + + #endregion + + #region Photon Messages + + /// + /// Called when a Photon Player got connected. We need to then load a bigger scene. + /// + /// Other. + public void OnPhotonPlayerConnected( PhotonPlayer other ) + { + Debug.Log( "OnPhotonPlayerConnected() " + other.NickName); // not seen if you're the player connecting + + if ( PhotonNetwork.isMasterClient ) + { + Debug.Log( "OnPhotonPlayerConnected isMasterClient " + PhotonNetwork.isMasterClient ); // called before OnPhotonPlayerDisconnected + + LoadArena(); + } + } + + /// + /// Called when a Photon Player got disconnected. We need to load a smaller scene. + /// + /// Other. + public void OnPhotonPlayerDisconnected( PhotonPlayer other ) + { + Debug.Log( "OnPhotonPlayerDisconnected() " + other.NickName ); // seen when other disconnects + + if ( PhotonNetwork.isMasterClient ) + { + Debug.Log( "OnPhotonPlayerConnected isMasterClient " + PhotonNetwork.isMasterClient ); // called before OnPhotonPlayerDisconnected + + LoadArena(); + } + } + + /// + /// Called when the local player left the room. We need to load the launcher scene. + /// + public virtual void OnLeftRoom() + { + SceneManager.LoadScene("PunBasics-Launcher"); + } + + #endregion + + #region Public Methods + + public void LeaveRoom() + { + PhotonNetwork.LeaveRoom(); + } + + public void QuitApplication() + { + Application.Quit(); + } + + #endregion + + #region Private Methods + + void LoadArena() + { + if ( ! PhotonNetwork.isMasterClient ) + { + Debug.LogError( "PhotonNetwork : Trying to Load a level but we are not the master Client" ); + } + + Debug.Log( "PhotonNetwork : Loading Level : " + PhotonNetwork.room.PlayerCount ); + + PhotonNetwork.LoadLevel("PunBasics-Room for "+PhotonNetwork.room.PlayerCount); + } + + #endregion + + } + +} \ No newline at end of file diff --git a/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Scripts/GameManager.cs.meta b/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Scripts/GameManager.cs.meta new file mode 100644 index 0000000..028e7a9 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Scripts/GameManager.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 4433564e76b1940028e7e531f171050d +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Scripts/Launcher.cs b/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Scripts/Launcher.cs new file mode 100644 index 0000000..6ef7f5b --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Scripts/Launcher.cs @@ -0,0 +1,236 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Part of: Photon Unity Networking Demos +// +// +// Used in "PUN Basic tutorial" to connect, and join/create room automatically +// +// developer@exitgames.com +// -------------------------------------------------------------------------------------------------------------------- + +using System; +using System.Collections; + +using UnityEngine; +using UnityEngine.UI; +using UnityEngine.SceneManagement; + +using Random = UnityEngine.Random; + +/// +/// Launch manager. Connect, join a random room or create one if none or all full. +/// +namespace ExitGames.Demos.DemoAnimator +{ + public class Launcher : Photon.PunBehaviour { + + #region Public Variables + + [Tooltip("The Ui Panel to let the user enter name, connect and play")] + public GameObject controlPanel; + + [Tooltip("The Ui Text to inform the user about the connection progress")] + public Text feedbackText; + + [Tooltip("The maximum number of players per room")] + public byte maxPlayersPerRoom = 4; + + [Tooltip("The UI Loader Anime")] + public LoaderAnime loaderAnime; + + #endregion + + #region Private Variables + /// + /// Keep track of the current process. Since connection is asynchronous and is based on several callbacks from Photon, + /// we need to keep track of this to properly adjust the behavior when we receive call back by Photon. + /// Typically this is used for the OnConnectedToMaster() callback. + /// + bool isConnecting; + + /// + /// This client's version number. Users are separated from each other by gameversion (which allows you to make breaking changes). + /// + string _gameVersion = "1"; + + #endregion + + #region MonoBehaviour CallBacks + + /// + /// MonoBehaviour method called on GameObject by Unity during early initialization phase. + /// + void Awake() + { + if (loaderAnime==null) + { + Debug.LogError("Missing loaderAnime Reference.",this); + } + + // #Critical + // we don't join the lobby. There is no need to join a lobby to get the list of rooms. + PhotonNetwork.autoJoinLobby = false; + + // #Critical + // this makes sure we can use PhotonNetwork.LoadLevel() on the master client and all clients in the same room sync their level automatically + PhotonNetwork.automaticallySyncScene = true; + + + } + + #endregion + + + #region Public Methods + + /// + /// Start the connection process. + /// - If already connected, we attempt joining a random room + /// - if not yet connected, Connect this application instance to Photon Cloud Network + /// + public void Connect() + { + // we want to make sure the log is clear everytime we connect, we might have several failed attempted if connection failed. + feedbackText.text = ""; + + // keep track of the will to join a room, because when we come back from the game we will get a callback that we are connected, so we need to know what to do then + isConnecting = true; + + // hide the Play button for visual consistency + controlPanel.SetActive(false); + + // start the loader animation for visual effect. + if (loaderAnime!=null) + { + loaderAnime.StartLoaderAnimation(); + } + + // we check if we are connected or not, we join if we are , else we initiate the connection to the server. + if (PhotonNetwork.connected) + { + LogFeedback("Joining Room..."); + // #Critical we need at this point to attempt joining a Random Room. If it fails, we'll get notified in OnPhotonRandomJoinFailed() and we'll create one. + PhotonNetwork.JoinRandomRoom(); + PhotonNetwork.JoinRandomRoom(null,(byte)(2)); + }else{ + + LogFeedback("Connecting..."); + + // #Critical, we must first and foremost connect to Photon Online Server. + PhotonNetwork.ConnectUsingSettings(_gameVersion); + } + } + + /// + /// Logs the feedback in the UI view for the player, as opposed to inside the Unity Editor for the developer. + /// + /// Message. + void LogFeedback(string message) + { + // we do not assume there is a feedbackText defined. + if (feedbackText == null) { + return; + } + + // add new messages as a new line and at the bottom of the log. + feedbackText.text += System.Environment.NewLine+message; + } + + #endregion + + + #region Photon.PunBehaviour CallBacks + // below, we implement some callbacks of PUN + // you can find PUN's callbacks in the class PunBehaviour or in enum PhotonNetworkingMessage + + + /// + /// Called after the connection to the master is established and authenticated but only when PhotonNetwork.autoJoinLobby is false. + /// + public override void OnConnectedToMaster() + { + + Debug.Log("Region:"+PhotonNetwork.networkingPeer.CloudRegion); + + // we don't want to do anything if we are not attempting to join a room. + // this case where isConnecting is false is typically when you lost or quit the game, when this level is loaded, OnConnectedToMaster will be called, in that case + // we don't want to do anything. + if (isConnecting) + { + LogFeedback("OnConnectedToMaster: Next -> try to Join Random Room"); + Debug.Log("DemoAnimator/Launcher: OnConnectedToMaster() was called by PUN. Now this client is connected and could join a room.\n Calling: PhotonNetwork.JoinRandomRoom(); Operation will fail if no room found"); + + // #Critical: The first we try to do is to join a potential existing room. If there is, good, else, we'll be called back with OnPhotonRandomJoinFailed() + PhotonNetwork.JoinRandomRoom(); + } + } + + /// + /// Called when a JoinRandom() call failed. The parameter provides ErrorCode and message. + /// + /// + /// Most likely all rooms are full or no rooms are available.
+ ///
+ /// codeAndMsg[0] is short ErrorCode. codeAndMsg[1] is string debug msg. + public override void OnPhotonRandomJoinFailed(object[] codeAndMsg) + { + LogFeedback("OnPhotonRandomJoinFailed: Next -> Create a new Room"); + Debug.Log("DemoAnimator/Launcher:OnPhotonRandomJoinFailed() was called by PUN. No random room available, so we create one.\nCalling: PhotonNetwork.CreateRoom(null, new RoomOptions() {maxPlayers = 4}, null);"); + + // #Critical: we failed to join a random room, maybe none exists or they are all full. No worries, we create a new room. + PhotonNetwork.CreateRoom(null, new RoomOptions() { MaxPlayers = this.maxPlayersPerRoom}, null); + } + + + /// + /// Called after disconnecting from the Photon server. + /// + /// + /// In some cases, other callbacks are called before OnDisconnectedFromPhoton is called. + /// Examples: OnConnectionFail() and OnFailedToConnectToPhoton(). + /// + public override void OnDisconnectedFromPhoton() + { + LogFeedback("OnDisconnectedFromPhoton"); + Debug.LogError("DemoAnimator/Launcher:Disconnected"); + + // #Critical: we failed to connect or got disconnected. There is not much we can do. Typically, a UI system should be in place to let the user attemp to connect again. + loaderAnime.StopLoaderAnimation(); + + isConnecting = false; + controlPanel.SetActive(true); + + } + + /// + /// Called when entering a room (by creating or joining it). Called on all clients (including the Master Client). + /// + /// + /// This method is commonly used to instantiate player characters. + /// If a match has to be started "actively", you can call an [PunRPC](@ref PhotonView.RPC) triggered by a user's button-press or a timer. + /// + /// When this is called, you can usually already access the existing players in the room via PhotonNetwork.playerList. + /// Also, all custom properties should be already available as Room.customProperties. Check Room..PlayerCount to find out if + /// enough players are in the room to start playing. + /// + public override void OnJoinedRoom() + { + LogFeedback("OnJoinedRoom with "+PhotonNetwork.room.PlayerCount+" Player(s)"); + Debug.Log("DemoAnimator/Launcher: OnJoinedRoom() called by PUN. Now this client is in a room.\nFrom here on, your game would be running. For reference, all callbacks are listed in enum: PhotonNetworkingMessage"); + + // #Critical: We only load if we are the first player, else we rely on PhotonNetwork.automaticallySyncScene to sync our instance scene. + if (PhotonNetwork.room.PlayerCount == 1) + { + Debug.Log("We load the 'Room for 1' "); + + // #Critical + // Load the Room Level. + PhotonNetwork.LoadLevel("PunBasics-Room for 1"); + + } + } + + #endregion + + } +} \ No newline at end of file diff --git a/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Scripts/Launcher.cs.meta b/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Scripts/Launcher.cs.meta new file mode 100644 index 0000000..27bc31f --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Scripts/Launcher.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 4796bc1963eb34e1fa021b0a45b29df4 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Scripts/LoaderAnime.cs b/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Scripts/LoaderAnime.cs new file mode 100644 index 0000000..583de43 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Scripts/LoaderAnime.cs @@ -0,0 +1,103 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Part of: Photon Unity Networking Demos +// +// +// Used in DemoAnimator to connect, and join/create room automatically +// +// developer@exitgames.com +// -------------------------------------------------------------------------------------------------------------------- + + +using UnityEngine; +using System.Collections; + +namespace ExitGames.Demos.DemoAnimator +{ + /// + /// Simple behaviour to animate particles around to create a typical "Ajax Loader". this is actually very important to visual inform the user that something is happening + /// or better say that the application is not frozen, so a animation of some sort helps reassuring the user that the system is idle and well. + /// + /// TODO: hide when connection failed. + /// + /// + public class LoaderAnime : MonoBehaviour { + + #region Public Variables + + [Tooltip("Angular Speed in degrees per seconds")] + public float speed = 180f; + + [Tooltip("Radius os the loader")] + public float radius = 1f; + + public GameObject particles; + + #endregion + + #region Private Variables + + Vector3 _offset; + + Transform _transform; + + Transform _particleTransform; + + bool _isAnimating; + + #endregion + + #region MonoBehaviour CallBacks + + /// + /// MonoBehaviour method called on GameObject by Unity during early initialization phase. + /// + void Awake() + { + // cache for efficiency + _particleTransform =particles.GetComponent(); + _transform = GetComponent(); + } + + + /// + /// MonoBehaviour method called on GameObject by Unity on every frame. + /// + void Update () { + + // only care about rotating particles if we are animating + if (_isAnimating) + { + // we rotate over time. Time.deltaTime is mandatory to have a frame rate independant animation, + _transform.Rotate(0f,0f,speed*Time.deltaTime); + + // we move from the center to the desired radius to prevent the visual artifacts of particles jumping from their current spot, it's not very nice visually + // so the particle is centered in the scene so that when it starts rotating, it doesn't jump and slowy we animate it to its final radius giving a smooth transition. + _particleTransform.localPosition = Vector3.MoveTowards(_particleTransform.localPosition, _offset, 0.5f*Time.deltaTime); + } + } + #endregion + + #region Public Methods + + /// + /// Starts the loader animation. Becomes visible + /// + public void StartLoaderAnimation() + { + _isAnimating = true; + _offset = new Vector3(radius,0f,0f); + particles.SetActive(true); + } + + /// + /// Stops the loader animation. Becomes invisible + /// + public void StopLoaderAnimation() + { + particles.SetActive(false); + } + + #endregion + } +} \ No newline at end of file diff --git a/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Scripts/LoaderAnime.cs.meta b/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Scripts/LoaderAnime.cs.meta new file mode 100644 index 0000000..bad4e92 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Scripts/LoaderAnime.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: df9597db7c55c44e885b8f74697d5ba0 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Scripts/PlayerAnimatorManager.cs b/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Scripts/PlayerAnimatorManager.cs new file mode 100644 index 0000000..d28ca0c --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Scripts/PlayerAnimatorManager.cs @@ -0,0 +1,87 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Part of: Photon Unity Networking Demos +// +// +// Used in DemoAnimator to cdeal with the networked player Animator Component controls. +// +// developer@exitgames.com +// -------------------------------------------------------------------------------------------------------------------- + + +using UnityEngine; +using System.Collections; + +namespace ExitGames.Demos.DemoAnimator +{ + public class PlayerAnimatorManager : Photon.MonoBehaviour + { + #region PUBLIC PROPERTIES + + public float DirectionDampTime = 0.25f; + + #endregion + + #region PRIVATE PROPERTIES + + Animator animator; + + #endregion + + #region MONOBEHAVIOUR MESSAGES + + /// + /// MonoBehaviour method called on GameObject by Unity during initialization phase. + /// + void Start () + { + animator = GetComponent(); + } + + /// + /// MonoBehaviour method called on GameObject by Unity on every frame. + /// + void Update () + { + + // Prevent control is connected to Photon and represent the localPlayer + if( photonView.isMine == false && PhotonNetwork.connected == true ) + { + return; + } + + // failSafe is missing Animator component on GameObject + if (!animator) + { + return; + } + + // deal with Jumping + AnimatorStateInfo stateInfo = animator.GetCurrentAnimatorStateInfo(0); + + // only allow jumping if we are running. + if (stateInfo.IsName("Base Layer.Run")) + { + // When using trigger parameter + if (Input.GetButtonDown("Fire2")) animator.SetTrigger("Jump"); + } + + // deal with movement + float h = Input.GetAxis("Horizontal"); + float v = Input.GetAxis("Vertical"); + + // prevent negative Speed. + if( v < 0 ) + { + v = 0; + } + + // set the Animator Parameters + animator.SetFloat( "Speed", h*h+v*v ); + animator.SetFloat( "Direction", h, DirectionDampTime, Time.deltaTime ); + } + + #endregion + + } +} \ No newline at end of file diff --git a/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Scripts/PlayerAnimatorManager.cs.meta b/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Scripts/PlayerAnimatorManager.cs.meta new file mode 100644 index 0000000..ca0db16 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Scripts/PlayerAnimatorManager.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 507e5741cec8a42dc964c8e0a4b55bd6 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Scripts/PlayerManager.cs b/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Scripts/PlayerManager.cs new file mode 100644 index 0000000..792fbc3 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Scripts/PlayerManager.cs @@ -0,0 +1,309 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Part of: Photon Unity Networking Demos +// +// +// Used in DemoAnimator to deal with the networked player instance +// +// developer@exitgames.com +// -------------------------------------------------------------------------------------------------------------------- + +#if UNITY_5 && (!UNITY_5_0 && !UNITY_5_1 && !UNITY_5_2 && !UNITY_5_3) || UNITY_6 +#define UNITY_MIN_5_4 +#endif + +using UnityEngine; +using UnityEngine.EventSystems; + +namespace ExitGames.Demos.DemoAnimator +{ + /// + /// Player manager. + /// Handles fire Input and Beams. + /// + public class PlayerManager : Photon.PunBehaviour, IPunObservable + { + #region Public Variables + + [Tooltip("The Player's UI GameObject Prefab")] + public GameObject PlayerUiPrefab; + + [Tooltip("The Beams GameObject to control")] + public GameObject Beams; + + [Tooltip("The current Health of our player")] + public float Health = 1f; + + [Tooltip("The local player instance. Use this to know if the local player is represented in the Scene")] + public static GameObject LocalPlayerInstance; + + #endregion + + #region Private Variables + + //True, when the user is firing + bool IsFiring; + + #endregion + + #region MonoBehaviour CallBacks + + /// + /// MonoBehaviour method called on GameObject by Unity during early initialization phase. + /// + public void Awake() + { + if (this.Beams == null) + { + Debug.LogError("Missing Beams Reference.", this); + } + else + { + this.Beams.SetActive(false); + } + + // #Important + // used in GameManager.cs: we keep track of the localPlayer instance to prevent instanciation when levels are synchronized + if (photonView.isMine) + { + LocalPlayerInstance = gameObject; + } + + // #Critical + // we flag as don't destroy on load so that instance survives level synchronization, thus giving a seamless experience when levels load. + DontDestroyOnLoad(gameObject); + } + + /// + /// MonoBehaviour method called on GameObject by Unity during initialization phase. + /// + public void Start() + { + CameraWork _cameraWork = gameObject.GetComponent(); + + if (_cameraWork != null) + { + if (photonView.isMine) + { + _cameraWork.OnStartFollowing(); + } + } + else + { + Debug.LogError("Missing CameraWork Component on player Prefab.", this); + } + + // Create the UI + if (this.PlayerUiPrefab != null) + { + GameObject _uiGo = Instantiate(this.PlayerUiPrefab) as GameObject; + _uiGo.SendMessage("SetTarget", this, SendMessageOptions.RequireReceiver); + } + else + { + Debug.LogWarning("Missing PlayerUiPrefab reference on player Prefab.", this); + } + + #if UNITY_MIN_5_4 + // Unity 5.4 has a new scene management. register a method to call CalledOnLevelWasLoaded. + UnityEngine.SceneManagement.SceneManager.sceneLoaded += OnSceneLoaded; + #endif + } + + + public void OnDisable() + { + #if UNITY_MIN_5_4 + UnityEngine.SceneManagement.SceneManager.sceneLoaded -= OnSceneLoaded; + #endif + } + + + /// + /// MonoBehaviour method called on GameObject by Unity on every frame. + /// Process Inputs if local player. + /// Show and hide the beams + /// Watch for end of game, when local player health is 0. + /// + public void Update() + { + // we only process Inputs and check health if we are the local player + if (photonView.isMine) + { + this.ProcessInputs(); + + if (this.Health <= 0f) + { + GameManager.Instance.LeaveRoom(); + } + } + + if (this.Beams != null && this.IsFiring != this.Beams.GetActive()) + { + this.Beams.SetActive(this.IsFiring); + } + } + + /// + /// MonoBehaviour method called when the Collider 'other' enters the trigger. + /// Affect Health of the Player if the collider is a beam + /// Note: when jumping and firing at the same, you'll find that the player's own beam intersects with itself + /// One could move the collider further away to prevent this or check if the beam belongs to the player. + /// + public void OnTriggerEnter(Collider other) + { + if (!photonView.isMine) + { + return; + } + + + // We are only interested in Beamers + // we should be using tags but for the sake of distribution, let's simply check by name. + if (!other.name.Contains("Beam")) + { + return; + } + + this.Health -= 0.1f; + } + + /// + /// MonoBehaviour method called once per frame for every Collider 'other' that is touching the trigger. + /// We're going to affect health while the beams are interesting the player + /// + /// Other. + public void OnTriggerStay(Collider other) + { + // we dont' do anything if we are not the local player. + if (!photonView.isMine) + { + return; + } + + // We are only interested in Beamers + // we should be using tags but for the sake of distribution, let's simply check by name. + if (!other.name.Contains("Beam")) + { + return; + } + + // we slowly affect health when beam is constantly hitting us, so player has to move to prevent death. + this.Health -= 0.1f*Time.deltaTime; + } + + + #if !UNITY_MIN_5_4 + /// See CalledOnLevelWasLoaded. Outdated in Unity 5.4. + void OnLevelWasLoaded(int level) + { + this.CalledOnLevelWasLoaded(level); + } + #endif + + + /// + /// MonoBehaviour method called after a new level of index 'level' was loaded. + /// We recreate the Player UI because it was destroy when we switched level. + /// Also reposition the player if outside the current arena. + /// + /// Level index loaded + void CalledOnLevelWasLoaded(int level) + { + // check if we are outside the Arena and if it's the case, spawn around the center of the arena in a safe zone + if (!Physics.Raycast(transform.position, -Vector3.up, 5f)) + { + transform.position = new Vector3(0f, 5f, 0f); + } + + GameObject _uiGo = Instantiate(this.PlayerUiPrefab) as GameObject; + _uiGo.SendMessage("SetTarget", this, SendMessageOptions.RequireReceiver); + } + + #endregion + + #region Private Methods + + + #if UNITY_MIN_5_4 + void OnSceneLoaded(UnityEngine.SceneManagement.Scene scene, UnityEngine.SceneManagement.LoadSceneMode loadingMode) + { + + this.CalledOnLevelWasLoaded(scene.buildIndex); + } + #endif + + /// + /// Processes the inputs. This MUST ONLY BE USED when the player has authority over this Networked GameObject (photonView.isMine == true) + /// + void ProcessInputs() + { + if (Input.GetButtonDown("Fire1")) + { + // we don't want to fire when we interact with UI buttons for example. IsPointerOverGameObject really means IsPointerOver*UI*GameObject + // notice we don't use on on GetbuttonUp() few lines down, because one can mouse down, move over a UI element and release, which would lead to not lower the isFiring Flag. + if (EventSystem.current.IsPointerOverGameObject()) + { + // return; + } + + if (!this.IsFiring) + { + this.IsFiring = true; + } + } + + if (Input.GetButtonUp("Fire1")) + { + if (this.IsFiring) + { + this.IsFiring = false; + } + } + } + + #endregion + + /* + #region IPunObservable implementation + + void IPunObservable.OnPhotonSerializeView (PhotonStream stream, PhotonMessageInfo info) + { + if (stream.isWriting) + { + // We own this player: send the others our data + stream.SendNext(IsFiring); + stream.SendNext(Health); + } + else + { + // Network player, receive data + this.IsFiring = (bool)stream.ReceiveNext(); + this.Health = (float)stream.ReceiveNext(); + } + } + + #endregion + */ + + #region IPunObservable implementation + + public void OnPhotonSerializeView(PhotonStream stream, PhotonMessageInfo info) + { + if (stream.isWriting) + { + // We own this player: send the others our data + stream.SendNext(this.IsFiring); + stream.SendNext(this.Health); + } + else + { + // Network player, receive data + this.IsFiring = (bool)stream.ReceiveNext(); + this.Health = (float)stream.ReceiveNext(); + } + } + + #endregion + } +} \ No newline at end of file diff --git a/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Scripts/PlayerManager.cs.meta b/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Scripts/PlayerManager.cs.meta new file mode 100644 index 0000000..0d81383 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Scripts/PlayerManager.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 98fac77b304554f238a61572f5720187 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Scripts/PlayerNameInputField.cs b/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Scripts/PlayerNameInputField.cs new file mode 100644 index 0000000..a516e17 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Scripts/PlayerNameInputField.cs @@ -0,0 +1,71 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Part of: Photon Unity Networking Demos +// +// +// Let the player input his name to be saved as the network player Name, viewed by alls players above each when in the same room. +// +// developer@exitgames.com +// -------------------------------------------------------------------------------------------------------------------- + +using UnityEngine; +using UnityEngine.UI; + +using System.Collections; + +namespace ExitGames.Demos.DemoAnimator +{ + /// + /// Player name input field. Let the user input his name, will appear above the player in the game. + /// + [RequireComponent(typeof(InputField))] + public class PlayerNameInputField : MonoBehaviour + { + #region Private Variables + + // Store the PlayerPref Key to avoid typos + static string playerNamePrefKey = "PlayerName"; + + #endregion + + #region MonoBehaviour CallBacks + + /// + /// MonoBehaviour method called on GameObject by Unity during initialization phase. + /// + void Start () { + + string defaultName = ""; + InputField _inputField = this.GetComponent(); + + if (_inputField!=null) + { + if (PlayerPrefs.HasKey(playerNamePrefKey)) + { + defaultName = PlayerPrefs.GetString(playerNamePrefKey); + _inputField.text = defaultName; + } + } + + PhotonNetwork.playerName = defaultName; + } + + #endregion + + #region Public Methods + + /// + /// Sets the name of the player, and save it in the PlayerPrefs for future sessions. + /// + /// The name of the Player + public void SetPlayerName(string value) + { + // #Important + PhotonNetwork.playerName = value + " "; // force a trailing space string in case value is an empty string, else playerName would not be updated. + + PlayerPrefs.SetString(playerNamePrefKey,value); + } + + #endregion + } +} diff --git a/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Scripts/PlayerNameInputField.cs.meta b/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Scripts/PlayerNameInputField.cs.meta new file mode 100644 index 0000000..786894e --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Scripts/PlayerNameInputField.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: c22ee30e9b2b34fe38b62e48c7d79dfa +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Scripts/PlayerUI.cs b/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Scripts/PlayerUI.cs new file mode 100644 index 0000000..6f5be90 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Scripts/PlayerUI.cs @@ -0,0 +1,143 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Part of: Photon Unity Networking Demos +// +// +// Used in DemoAnimator to deal with the networked player instance UI display tha follows a given player to show its health and name +// +// developer@exitgames.com +// -------------------------------------------------------------------------------------------------------------------- + + +using UnityEngine; +using UnityEngine.UI; + +using System.Collections; + +namespace ExitGames.Demos.DemoAnimator +{ + /// + /// Player UI. Constraint the UI to follow a PlayerManager GameObject in the world, + /// Affect a slider and text to display Player's name and health + /// + public class PlayerUI : MonoBehaviour { + + #region Public Properties + + [Tooltip("Pixel offset from the player target")] + public Vector3 ScreenOffset = new Vector3(0f,30f,0f); + + [Tooltip("UI Text to display Player's Name")] + public Text PlayerNameText; + + [Tooltip("UI Slider to display Player's Health")] + public Slider PlayerHealthSlider; + + #endregion + + #region Private Properties + + PlayerManager _target; + + float _characterControllerHeight = 0f; + + Transform _targetTransform; + + Renderer _targetRenderer; + + Vector3 _targetPosition; + + #endregion + + #region MonoBehaviour Messages + + /// + /// MonoBehaviour method called on GameObject by Unity during early initialization phase + /// + void Awake(){ + + this.GetComponent().SetParent (GameObject.Find("Canvas").GetComponent()); + } + + /// + /// MonoBehaviour method called on GameObject by Unity on every frame. + /// update the health slider to reflect the Player's health + /// + void Update() + { + // Destroy itself if the target is null, It's a fail safe when Photon is destroying Instances of a Player over the network + if (_target == null) { + Destroy(this.gameObject); + return; + } + + + // Reflect the Player Health + if (PlayerHealthSlider != null) { + PlayerHealthSlider.value = _target.Health; + } + } + + /// + /// MonoBehaviour method called after all Update functions have been called. This is useful to order script execution. + /// In our case since we are following a moving GameObject, we need to proceed after the player was moved during a particular frame. + /// + void LateUpdate () { + + // Do not show the UI if we are not visible to the camera, thus avoid potential bugs with seeing the UI, but not the player itself. + if (_targetRenderer!=null) { + this.gameObject.SetActive(_targetRenderer.isVisible); + } + + // #Critical + // Follow the Target GameObject on screen. + if (_targetTransform!=null) + { + _targetPosition = _targetTransform.position; + _targetPosition.y += _characterControllerHeight; + + this.transform.position = Camera.main.WorldToScreenPoint (_targetPosition) + ScreenOffset; + } + + } + + + + + #endregion + + #region Public Methods + + /// + /// Assigns a Player Target to Follow and represent. + /// + /// Target. + public void SetTarget(PlayerManager target){ + + if (target == null) { + Debug.LogError("Missing PlayMakerManager target for PlayerUI.SetTarget.",this); + return; + } + + // Cache references for efficiency because we are going to reuse them. + _target = target; + _targetTransform = _target.GetComponent(); + _targetRenderer = _target.GetComponent(); + + + CharacterController _characterController = _target.GetComponent (); + + // Get data from the Player that won't change during the lifetime of this Component + if (_characterController != null){ + _characterControllerHeight = _characterController.height; + } + + if (PlayerNameText != null) { + PlayerNameText.text = _target.photonView.owner.NickName; + } + } + + #endregion + + } +} \ No newline at end of file diff --git a/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Scripts/PlayerUI.cs.meta b/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Scripts/PlayerUI.cs.meta new file mode 100644 index 0000000..f7441aa --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/PunBasics-Tutorial/Scripts/PlayerUI.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: dba1a179e553446f0a08606778f559f1 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Photon Unity Networking/Demos/Shared Assets.meta b/Assets/Photon Unity Networking/Demos/Shared Assets.meta new file mode 100644 index 0000000..d2be95d --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/Shared Assets.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: a74442c0d326745c19238244b84e3c02 +folderAsset: yes +timeCreated: 1501014811 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Photon Unity Networking/Demos/Shared Assets/Animations.meta b/Assets/Photon Unity Networking/Demos/Shared Assets/Animations.meta new file mode 100644 index 0000000..c3515ed --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/Shared Assets/Animations.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 083d8173ff6804ace96cd35ce7ec80b4 +folderAsset: yes +timeCreated: 1501014811 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Photon Unity Networking/Demos/Shared Assets/Animations/Idles.fbx b/Assets/Photon Unity Networking/Demos/Shared Assets/Animations/Idles.fbx new file mode 100644 index 0000000..edc05b7 Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/Shared Assets/Animations/Idles.fbx differ diff --git a/Assets/Photon Unity Networking/Demos/Shared Assets/Animations/Idles.fbx.meta b/Assets/Photon Unity Networking/Demos/Shared Assets/Animations/Idles.fbx.meta new file mode 100644 index 0000000..68bd1fe --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/Shared Assets/Animations/Idles.fbx.meta @@ -0,0 +1,1420 @@ +fileFormatVersion: 2 +guid: ce448a8080b4e934b8473badd27be402 +ModelImporter: + serializedVersion: 16 + fileIDToRecycleName: + 100000: l_clavicleProxy_geo + 100002: l_shourderProxy_geo + 100004: l_erbowProxy_geo + 100006: l_wristProxy_geo + 100008: l_thumbProxy_01_geo + 100010: l_thumbProxy_02_geo + 100012: l_thumbProxy_03_geo + 100014: l_indexProxy_01_geo + 100016: l_indexProxy_02_geo + 100018: l_indexProxy_03_geo + 100020: l_middleProxy_01_geo + 100022: l_middleProxy_02_geo + 100024: l_middleProxy_03_geo + 100026: LeftHandMiddle13 + 100028: l_ringProxy_01_geo + 100030: l_ringProxy_02_geo + 100032: l_ringProxy_03_geo + 100034: l_pinkyProxy_01_geo + 100036: l_pinkyProxy_02_geo + 100038: l_pinkyProxy_03_geo + 100040: r_clavicleProxy_geo + 100042: r_shourderProxy_geo + 100044: r_erbowProxy_geo + 100046: r_wristProxy_geo + 100048: r_thumbProxy_01_geo + 100050: r_thumbProxy_02_geo + 100052: r_thumbProxy_03_geo + 100054: r_indexProxy_01_geo + 100056: r_indexProxy_02_geo + 100058: r_indexProxy_03_geo + 100060: r_middleProxy_01_geo + 100062: r_middleProxy_02_geo + 100064: l_ankleProxy_geo + 100066: r_ankleProxy_geo + 100068: r_middleProxy_03_geo + 100070: LeftHandMiddle17 + 100072: RightHandMiddle3 + 100074: RightHandMiddle2 + 100076: RightHandMiddle1 + 100078: r_ringProxy_01_geo + 100080: r_ringProxy_02_geo + 100082: r_ringProxy_03_geo + 100084: r_pinkyProxy_01_geo + 100086: r_pinkyProxy_02_geo + 100088: r_pinkyProxy_03_geo + 100090: UNI_01_Upper_teethProxy + 100092: RightEyelidLower + 100094: RightEyelidUpper + 100096: UNI_01_Lower_teethProxy + 100098: UNI_01_TongueTipProxy + 100100: UNI_01_TongueBaseProxy + 100102: //RootNode + 100104: l_hipProxy_geo + 100106: l_kneeProxy_geo + 100108: l_ballProxy_geo + 100110: LToeBase_End2 + 100112: LeftToes + 100114: LeftFoot + 100116: LeftLeg + 100118: LeftUpLeg + 100120: pelvisProxy_geo + 100122: r_hipProxy_geo + 100124: r_kneeProxy_geo + 100126: r_ballProxy_geo + 100128: LToeBase_End3 + 100130: RightToes + 100132: RightFoot + 100134: RightLeg + 100136: RightUpLeg + 100138: spineProxy_geo + 100140: LeftHandThumb13 + 100142: LeftHandThumb3 + 100144: LeftHandThumb2 + 100146: LeftHandThumb1 + 100148: LeftHandIndex13 + 100150: LeftHandIndex3 + 100152: LeftHandIndex2 + 100154: LeftHandIndex1 + 100156: LeftHandMiddle3 + 100158: LeftHandMiddle2 + 100160: LeftHandMiddle1 + 100162: LeftHandRing13 + 100164: LeftHandRing3 + 100166: LeftHandRing2 + 100168: LeftHandRing1 + 100170: LeftHandPinky13 + 100172: LeftHandPinky3 + 100174: LeftHandPinky2 + 100176: LeftHandPinky1 + 100178: LeftHand + 100180: LeftForeArm + 100182: LeftArm + 100184: LeftShoulder + 100186: chestProxy_geo + 100188: LeftHandThumb17 + 100190: RightHandThumb3 + 100192: RightHandThumb2 + 100194: RightHandThumb1 + 100196: LeftHandIndex17 + 100198: RightHandIndex3 + 100200: RightHandIndex2 + 100202: RightHandIndex1 + 100204: LeftHandRing17 + 100206: RightHandRing3 + 100208: RightHandRing2 + 100210: RightHandRing1 + 100212: LeftHandPinky17 + 100214: RightHandPinky3 + 100216: RightHandPinky2 + 100218: RightHandPinky1 + 100220: RightHand + 100222: RightForeArm + 100224: RightArm + 100226: RightShoulder + 100228: neckProxy_geo + 100230: headProxy_geo + 100232: RightLipUpper + 100234: RightNostril + 100236: RightCheek + 100238: RightIOuterBrow + 100240: RightInnerBrow + 100242: LeftIOuterBrow + 100244: LeftInnerBrow + 100246: LeftEyelidUpper + 100248: LeftEyelidLower + 100250: LeftCheek + 100252: LeftNostril + 100254: LeftLipUpper + 100256: jawProxy_geo + 100258: LeftLipCorner + 100260: RightLipCorner + 100262: RightLipLower + 100264: JawEND + 100266: LeftLipLower + 100268: TongueTip + 100270: TongueBack + 100272: Jaw + 100274: r_UNI_eye + 100276: RightEye + 100278: l_UNI_eye + 100280: LeftEye + 100282: HeadTop_End + 100284: Head + 100286: Neck + 100288: Chest + 100290: Spine + 100292: Hips + 100294: Reference + 400000: l_clavicleProxy_geo + 400002: l_shourderProxy_geo + 400004: l_erbowProxy_geo + 400006: l_wristProxy_geo + 400008: l_thumbProxy_01_geo + 400010: l_thumbProxy_02_geo + 400012: l_thumbProxy_03_geo + 400014: l_indexProxy_01_geo + 400016: l_indexProxy_02_geo + 400018: l_indexProxy_03_geo + 400020: l_middleProxy_01_geo + 400022: l_middleProxy_02_geo + 400024: l_middleProxy_03_geo + 400026: LeftHandMiddle13 + 400028: l_ringProxy_01_geo + 400030: l_ringProxy_02_geo + 400032: l_ringProxy_03_geo + 400034: l_pinkyProxy_01_geo + 400036: l_pinkyProxy_02_geo + 400038: l_pinkyProxy_03_geo + 400040: r_clavicleProxy_geo + 400042: r_shourderProxy_geo + 400044: r_erbowProxy_geo + 400046: r_wristProxy_geo + 400048: r_thumbProxy_01_geo + 400050: r_thumbProxy_02_geo + 400052: r_thumbProxy_03_geo + 400054: r_indexProxy_01_geo + 400056: r_indexProxy_02_geo + 400058: r_indexProxy_03_geo + 400060: r_middleProxy_01_geo + 400062: r_middleProxy_02_geo + 400064: l_ankleProxy_geo + 400066: r_ankleProxy_geo + 400068: r_middleProxy_03_geo + 400070: LeftHandMiddle17 + 400072: RightHandMiddle3 + 400074: RightHandMiddle2 + 400076: RightHandMiddle1 + 400078: r_ringProxy_01_geo + 400080: r_ringProxy_02_geo + 400082: r_ringProxy_03_geo + 400084: r_pinkyProxy_01_geo + 400086: r_pinkyProxy_02_geo + 400088: r_pinkyProxy_03_geo + 400090: UNI_01_Upper_teethProxy + 400092: RightEyelidLower + 400094: RightEyelidUpper + 400096: UNI_01_Lower_teethProxy + 400098: UNI_01_TongueTipProxy + 400100: UNI_01_TongueBaseProxy + 400102: //RootNode + 400104: l_hipProxy_geo + 400106: l_kneeProxy_geo + 400108: l_ballProxy_geo + 400110: LToeBase_End2 + 400112: LeftToes + 400114: LeftFoot + 400116: LeftLeg + 400118: LeftUpLeg + 400120: pelvisProxy_geo + 400122: r_hipProxy_geo + 400124: r_kneeProxy_geo + 400126: r_ballProxy_geo + 400128: LToeBase_End3 + 400130: RightToes + 400132: RightFoot + 400134: RightLeg + 400136: RightUpLeg + 400138: spineProxy_geo + 400140: LeftHandThumb13 + 400142: LeftHandThumb3 + 400144: LeftHandThumb2 + 400146: LeftHandThumb1 + 400148: LeftHandIndex13 + 400150: LeftHandIndex3 + 400152: LeftHandIndex2 + 400154: LeftHandIndex1 + 400156: LeftHandMiddle3 + 400158: LeftHandMiddle2 + 400160: LeftHandMiddle1 + 400162: LeftHandRing13 + 400164: LeftHandRing3 + 400166: LeftHandRing2 + 400168: LeftHandRing1 + 400170: LeftHandPinky13 + 400172: LeftHandPinky3 + 400174: LeftHandPinky2 + 400176: LeftHandPinky1 + 400178: LeftHand + 400180: LeftForeArm + 400182: LeftArm + 400184: LeftShoulder + 400186: chestProxy_geo + 400188: LeftHandThumb17 + 400190: RightHandThumb3 + 400192: RightHandThumb2 + 400194: RightHandThumb1 + 400196: LeftHandIndex17 + 400198: RightHandIndex3 + 400200: RightHandIndex2 + 400202: RightHandIndex1 + 400204: LeftHandRing17 + 400206: RightHandRing3 + 400208: RightHandRing2 + 400210: RightHandRing1 + 400212: LeftHandPinky17 + 400214: RightHandPinky3 + 400216: RightHandPinky2 + 400218: RightHandPinky1 + 400220: RightHand + 400222: RightForeArm + 400224: RightArm + 400226: RightShoulder + 400228: neckProxy_geo + 400230: headProxy_geo + 400232: RightLipUpper + 400234: RightNostril + 400236: RightCheek + 400238: RightIOuterBrow + 400240: RightInnerBrow + 400242: LeftIOuterBrow + 400244: LeftInnerBrow + 400246: LeftEyelidUpper + 400248: LeftEyelidLower + 400250: LeftCheek + 400252: LeftNostril + 400254: LeftLipUpper + 400256: jawProxy_geo + 400258: LeftLipCorner + 400260: RightLipCorner + 400262: RightLipLower + 400264: JawEND + 400266: LeftLipLower + 400268: TongueTip + 400270: TongueBack + 400272: Jaw + 400274: r_UNI_eye + 400276: RightEye + 400278: l_UNI_eye + 400280: LeftEye + 400282: HeadTop_End + 400284: Head + 400286: Neck + 400288: Chest + 400290: Spine + 400292: Hips + 400294: Reference + 2300000: l_clavicleProxy_geo + 2300002: l_shourderProxy_geo + 2300004: l_erbowProxy_geo + 2300006: l_wristProxy_geo + 2300008: l_thumbProxy_01_geo + 2300010: l_thumbProxy_02_geo + 2300012: l_thumbProxy_03_geo + 2300014: l_indexProxy_01_geo + 2300016: l_indexProxy_02_geo + 2300018: l_indexProxy_03_geo + 2300020: l_middleProxy_01_geo + 2300022: l_middleProxy_02_geo + 2300024: l_middleProxy_03_geo + 2300026: l_ringProxy_01_geo + 2300028: l_ringProxy_02_geo + 2300030: l_ringProxy_03_geo + 2300032: l_pinkyProxy_01_geo + 2300034: l_pinkyProxy_02_geo + 2300036: l_pinkyProxy_03_geo + 2300038: r_clavicleProxy_geo + 2300040: r_shourderProxy_geo + 2300042: r_erbowProxy_geo + 2300044: r_wristProxy_geo + 2300046: r_thumbProxy_01_geo + 2300048: r_thumbProxy_02_geo + 2300050: r_thumbProxy_03_geo + 2300052: r_indexProxy_01_geo + 2300054: r_indexProxy_02_geo + 2300056: r_indexProxy_03_geo + 2300058: r_middleProxy_01_geo + 2300060: r_middleProxy_02_geo + 2300062: l_ankleProxy_geo + 2300064: r_ankleProxy_geo + 2300066: r_middleProxy_03_geo + 2300068: r_ringProxy_01_geo + 2300070: r_ringProxy_02_geo + 2300072: r_ringProxy_03_geo + 2300074: r_pinkyProxy_01_geo + 2300076: r_pinkyProxy_02_geo + 2300078: r_pinkyProxy_03_geo + 2300080: UNI_01_Upper_teethProxy + 2300082: UNI_01_Lower_teethProxy + 2300084: UNI_01_TongueTipProxy + 2300086: UNI_01_TongueBaseProxy + 2300088: l_hipProxy_geo + 2300090: l_kneeProxy_geo + 2300092: l_ballProxy_geo + 2300094: pelvisProxy_geo + 2300096: r_hipProxy_geo + 2300098: r_kneeProxy_geo + 2300100: r_ballProxy_geo + 2300102: spineProxy_geo + 2300104: chestProxy_geo + 2300106: neckProxy_geo + 2300108: headProxy_geo + 2300110: jawProxy_geo + 2300112: r_UNI_eye + 2300114: l_UNI_eye + 3300000: l_clavicleProxy_geo + 3300002: l_shourderProxy_geo + 3300004: l_erbowProxy_geo + 3300006: l_wristProxy_geo + 3300008: l_thumbProxy_01_geo + 3300010: l_thumbProxy_02_geo + 3300012: l_thumbProxy_03_geo + 3300014: l_indexProxy_01_geo + 3300016: l_indexProxy_02_geo + 3300018: l_indexProxy_03_geo + 3300020: l_middleProxy_01_geo + 3300022: l_middleProxy_02_geo + 3300024: l_middleProxy_03_geo + 3300026: l_ringProxy_01_geo + 3300028: l_ringProxy_02_geo + 3300030: l_ringProxy_03_geo + 3300032: l_pinkyProxy_01_geo + 3300034: l_pinkyProxy_02_geo + 3300036: l_pinkyProxy_03_geo + 3300038: r_clavicleProxy_geo + 3300040: r_shourderProxy_geo + 3300042: r_erbowProxy_geo + 3300044: r_wristProxy_geo + 3300046: r_thumbProxy_01_geo + 3300048: r_thumbProxy_02_geo + 3300050: r_thumbProxy_03_geo + 3300052: r_indexProxy_01_geo + 3300054: r_indexProxy_02_geo + 3300056: r_indexProxy_03_geo + 3300058: r_middleProxy_01_geo + 3300060: r_middleProxy_02_geo + 3300062: l_ankleProxy_geo + 3300064: r_ankleProxy_geo + 3300066: r_middleProxy_03_geo + 3300068: r_ringProxy_01_geo + 3300070: r_ringProxy_02_geo + 3300072: r_ringProxy_03_geo + 3300074: r_pinkyProxy_01_geo + 3300076: r_pinkyProxy_02_geo + 3300078: r_pinkyProxy_03_geo + 3300080: UNI_01_Upper_teethProxy + 3300082: UNI_01_Lower_teethProxy + 3300084: UNI_01_TongueTipProxy + 3300086: UNI_01_TongueBaseProxy + 3300088: l_hipProxy_geo + 3300090: l_kneeProxy_geo + 3300092: l_ballProxy_geo + 3300094: pelvisProxy_geo + 3300096: r_hipProxy_geo + 3300098: r_kneeProxy_geo + 3300100: r_ballProxy_geo + 3300102: spineProxy_geo + 3300104: chestProxy_geo + 3300106: neckProxy_geo + 3300108: headProxy_geo + 3300110: jawProxy_geo + 3300112: r_UNI_eye + 3300114: l_UNI_eye + 4300000: l_UNI_eye + 4300002: r_UNI_eye + 4300004: UNI_01_TongueBaseProxy + 4300006: UNI_01_TongueTipProxy + 4300008: UNI_01_Lower_teethProxy + 4300010: jawProxy_geo + 4300012: headProxy_geo + 4300014: UNI_01_Upper_teethProxy + 4300016: neckProxy_geo + 4300018: r_pinkyProxy_03_geo + 4300020: r_pinkyProxy_02_geo + 4300022: r_pinkyProxy_01_geo + 4300024: r_ringProxy_03_geo + 4300026: r_ringProxy_02_geo + 4300028: r_ringProxy_01_geo + 4300030: r_middleProxy_03_geo + 4300032: r_middleProxy_02_geo + 4300034: r_middleProxy_01_geo + 4300036: r_indexProxy_03_geo + 4300038: r_indexProxy_02_geo + 4300040: r_indexProxy_01_geo + 4300042: r_thumbProxy_03_geo + 4300044: r_thumbProxy_02_geo + 4300046: r_thumbProxy_01_geo + 4300048: r_wristProxy_geo + 4300050: r_erbowProxy_geo + 4300052: r_shourderProxy_geo + 4300054: r_clavicleProxy_geo + 4300056: chestProxy_geo + 4300058: l_pinkyProxy_03_geo + 4300060: l_pinkyProxy_02_geo + 4300062: l_pinkyProxy_01_geo + 4300064: l_ringProxy_03_geo + 4300066: l_ringProxy_02_geo + 4300068: l_ringProxy_01_geo + 4300070: l_middleProxy_03_geo + 4300072: l_middleProxy_02_geo + 4300074: l_middleProxy_01_geo + 4300076: l_indexProxy_03_geo + 4300078: l_indexProxy_02_geo + 4300080: l_indexProxy_01_geo + 4300082: l_thumbProxy_03_geo + 4300084: l_thumbProxy_02_geo + 4300086: l_thumbProxy_01_geo + 4300088: l_wristProxy_geo + 4300090: l_erbowProxy_geo + 4300092: l_shourderProxy_geo + 4300094: l_clavicleProxy_geo + 4300096: spineProxy_geo + 4300098: r_ballProxy_geo + 4300100: r_ankleProxy_geo + 4300102: r_kneeProxy_geo + 4300104: r_hipProxy_geo + 4300106: pelvisProxy_geo + 4300108: l_ballProxy_geo + 4300110: l_ankleProxy_geo + 4300112: l_kneeProxy_geo + 4300114: l_hipProxy_geo + 7400000: _89_90B_a_U1_M_P_Walk2Idle_Idle2WalkBackward_Fb_p0_No_0_0 + 7400002: _87_a_U1_M_P_idle_Neutral__Fb_p0_No_1 + 7400004: _88_a_U1_M_P_idle_Ready_R_Fb_p0_No_0_PJ_0 + 7400006: _105_to_108_a_U1_M_P_idle2walk_AllAngles__Fb_p45-180_No_0_PJ_1 + 7400008: _97_TO_100_a_U1_M_P_idle_NeutralTO45IdleTONeutralIdle__Fb_p45_No_0_PJ_2 + 7400010: _88B_a_U1_M_P_idle_ReadyToNeutral_R_Fb_p0_No_0_PJ_0 + 7400012: _117_to_120_a_U1_M_P_idle2Strafe_AllAngles__Fb_p45-180_No_0_PJ_1 + 7400014: IdleShort + 7400016: __preview__Idle + 7400020: Idle + 11100000: //RootNode + materials: + importMaterials: 1 + materialName: 0 + materialSearch: 1 + animations: + legacyGenerateAnimations: 4 + bakeSimulation: 0 + optimizeGameObjects: 0 + motionNodeName: + animationCompression: 0 + animationRotationError: .5 + animationPositionError: .5 + animationScaleError: .5 + animationWrapMode: 0 + extraExposedTransformPaths: [] + clipAnimations: + - serializedVersion: 16 + name: Idle + takeName: Idle + firstFrame: 464.391632 + lastFrame: 850.268311 + wrapMode: 0 + orientationOffsetY: 0 + level: 0 + cycleOffset: 0 + loop: 0 + loopTime: 1 + loopBlend: 1 + loopBlendOrientation: 1 + loopBlendPositionY: 1 + loopBlendPositionXZ: 1 + keepOriginalOrientation: 0 + keepOriginalPositionY: 1 + keepOriginalPositionXZ: 0 + heightFromFeet: 0 + mirror: 0 + bodyMask: 01000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000 + curves: [] + events: [] + transformMask: [] + maskType: 0 + maskSource: {instanceID: 0} + - serializedVersion: 16 + name: IdleShort + takeName: Idle + firstFrame: 130 + lastFrame: 253 + wrapMode: 0 + orientationOffsetY: 0 + level: 0 + cycleOffset: 0 + loop: 0 + loopTime: 1 + loopBlend: 1 + loopBlendOrientation: 1 + loopBlendPositionY: 1 + loopBlendPositionXZ: 1 + keepOriginalOrientation: 0 + keepOriginalPositionY: 1 + keepOriginalPositionXZ: 0 + heightFromFeet: 0 + mirror: 0 + bodyMask: 01000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000 + curves: [] + events: [] + transformMask: [] + maskType: 0 + maskSource: {instanceID: 0} + isReadable: 1 + meshes: + lODScreenPercentages: [] + globalScale: .00999999978 + meshCompression: 0 + addColliders: 0 + importBlendShapes: 1 + swapUVChannels: 0 + generateSecondaryUV: 0 + useFileUnits: 1 + optimizeMeshForGPU: 1 + weldVertices: 1 + secondaryUVAngleDistortion: 8 + secondaryUVAreaDistortion: 15.000001 + secondaryUVHardAngle: 88 + secondaryUVPackMargin: 4 + tangentSpace: + normalSmoothAngle: 60 + splitTangentsAcrossUV: 1 + normalImportMode: 0 + tangentImportMode: 1 + importAnimation: 1 + copyAvatar: 1 + humanDescription: + human: + - boneName: Hips + humanName: Hips + limit: + min: {x: -40, y: -40, z: -40} + max: {x: 40, y: 40, z: 40} + value: {x: .0748811588, y: 0, z: .0374405794} + length: .0936014801 + modified: 1 + - boneName: LeftUpLeg + humanName: LeftUpperLeg + limit: + min: {x: -60.0000038, y: -60.0000038, z: -90} + max: {x: 60.0000038, y: 60.0000038, z: 50} + value: {x: .327766716, y: 0, z: .163883358} + length: .40970853 + modified: 1 + - boneName: RightUpLeg + humanName: RightUpperLeg + limit: + min: {x: -60.0000038, y: -60.0000038, z: -90} + max: {x: 60.0000038, y: 60.0000038, z: 50} + value: {x: .327766716, y: 0, z: .163883358} + length: .40970853 + modified: 1 + - boneName: LeftLeg + humanName: LeftLowerLeg + limit: + min: {x: -90, y: 0, z: -80} + max: {x: 90, y: 0, z: 80} + value: {x: .338686436, y: 0, z: .169343218} + length: .423358172 + modified: 1 + - boneName: RightLeg + humanName: RightLowerLeg + limit: + min: {x: -90, y: 0, z: -80} + max: {x: 90, y: 0, z: 80} + value: {x: .338686436, y: 0, z: .169343218} + length: .423358172 + modified: 1 + - boneName: LeftFoot + humanName: LeftFoot + limit: + min: {x: 0, y: -30.0000019, z: -50} + max: {x: 0, y: 30.0000019, z: 50} + value: {x: .0686753467, y: 0, z: .0343376733} + length: .0858442187 + modified: 1 + - boneName: RightFoot + humanName: RightFoot + limit: + min: {x: 0, y: -30.0000019, z: -50} + max: {x: 0, y: 30.0000019, z: 50} + value: {x: .0686753467, y: 0, z: .0343376733} + length: .0858442187 + modified: 1 + - boneName: Spine + humanName: Spine + limit: + min: {x: -40, y: -40, z: -40} + max: {x: 40, y: 40, z: 40} + value: {x: .131201819, y: 0, z: .0656009093} + length: .164002344 + modified: 1 + - boneName: Chest + humanName: Chest + limit: + min: {x: -40, y: -40, z: -40} + max: {x: 40, y: 40, z: 40} + value: {x: .190353557, y: 0, z: .0951767787} + length: .237942025 + modified: 1 + - boneName: Neck + humanName: Neck + limit: + min: {x: -40, y: -40, z: -40} + max: {x: 40, y: 40, z: 40} + value: {x: .0855657607, y: 0, z: .0427828804} + length: .106957234 + modified: 1 + - boneName: Head + humanName: Head + limit: + min: {x: -40, y: -40, z: -40} + max: {x: 40, y: 40, z: 40} + value: {x: .0855657607, y: 0, z: .0427828804} + length: .106957234 + modified: 1 + - boneName: LeftShoulder + humanName: LeftShoulder + limit: + min: {x: 0, y: -15.000001, z: -15.000001} + max: {x: 0, y: 15.000001, z: 30.0000019} + value: {x: .072829701, y: 0, z: .0364148505} + length: .0910371616 + modified: 1 + - boneName: RightShoulder + humanName: RightShoulder + limit: + min: {x: 0, y: -15.000001, z: -15.000001} + max: {x: 0, y: 15.000001, z: 30.0000019} + value: {x: .072829701, y: 0, z: .0364148505} + length: .0910371616 + modified: 1 + - boneName: LeftArm + humanName: LeftUpperArm + limit: + min: {x: -90, y: -100, z: -60.0000038} + max: {x: 90, y: 100, z: 100} + value: {x: .203239605, y: 0, z: .101619802} + length: .254049569 + modified: 1 + - boneName: RightArm + humanName: RightUpperArm + limit: + min: {x: -90, y: -100, z: -60.0000038} + max: {x: 90, y: 100, z: 100} + value: {x: .203239486, y: 0, z: .101619743} + length: .25404942 + modified: 1 + - boneName: LeftForeArm + humanName: LeftLowerArm + limit: + min: {x: -90, y: 0, z: -80} + max: {x: 90, y: 0, z: 80} + value: {x: .197111428, y: 0, z: .0985557139} + length: .246389359 + modified: 1 + - boneName: RightForeArm + humanName: RightLowerArm + limit: + min: {x: -90, y: 0, z: -80} + max: {x: 90, y: 0, z: 80} + value: {x: .197110936, y: 0, z: .098555468} + length: .246388748 + modified: 1 + - boneName: LeftHand + humanName: LeftHand + limit: + min: {x: 0, y: -40, z: -80} + max: {x: 0, y: 40, z: 80} + value: {x: .0985557139, y: 0, z: .0492778569} + length: .12319468 + modified: 1 + - boneName: RightHand + humanName: RightHand + limit: + min: {x: 0, y: -40, z: -80} + max: {x: 0, y: 40, z: 80} + value: {x: .098555468, y: 0, z: .049277734} + length: .123194374 + modified: 1 + - boneName: LeftToes + humanName: LeftToes + limit: + min: {x: 0, y: 0, z: -50} + max: {x: 0, y: 0, z: 50} + value: {x: .0651871562, y: 0, z: .0325935781} + length: .0814839825 + modified: 1 + - boneName: RightToes + humanName: RightToes + limit: + min: {x: 0, y: 0, z: -50} + max: {x: 0, y: 0, z: 50} + value: {x: .0651872903, y: 0, z: .0325936452} + length: .0814841464 + modified: 1 + - boneName: LeftEye + humanName: LeftEye + limit: + min: {x: 0, y: -20, z: -10} + max: {x: 0, y: 20, z: 15.000001} + value: {x: .0799999759, y: 0, z: .0399999879} + length: .100000001 + modified: 1 + - boneName: RightEye + humanName: RightEye + limit: + min: {x: 0, y: -20, z: -10} + max: {x: 0, y: 20, z: 15.000001} + value: {x: .0799999759, y: 0, z: .0399999879} + length: .100000001 + modified: 1 + - boneName: Jaw + humanName: Jaw + limit: + min: {x: 0, y: -10, z: -10} + max: {x: 0, y: 10, z: 10} + value: {x: .0799999759, y: 0, z: .0399999879} + length: .100000001 + modified: 1 + - boneName: LeftHandThumb1 + humanName: Left Thumb Proximal + limit: + min: {x: 0, y: -25, z: -20} + max: {x: 0, y: 25, z: 20} + value: {x: .0232954584, y: 0, z: .0116477292} + length: .0291193314 + modified: 1 + - boneName: LeftHandThumb2 + humanName: Left Thumb Intermediate + limit: + min: {x: 0, y: 0, z: -40} + max: {x: 0, y: 0, z: 35} + value: {x: .0270181261, y: 0, z: .0135090631} + length: .033772666 + modified: 1 + - boneName: LeftHandThumb3 + humanName: Left Thumb Distal + limit: + min: {x: 0, y: 0, z: -40} + max: {x: 0, y: 0, z: 35} + value: {x: .0202635936, y: 0, z: .0101317968} + length: .0253295004 + modified: 1 + - boneName: LeftHandIndex1 + humanName: Left Index Proximal + limit: + min: {x: 0, y: -20, z: -50} + max: {x: 0, y: 20, z: 50} + value: {x: .0318517797, y: 0, z: .0159258898} + length: .0398147404 + modified: 1 + - boneName: LeftHandIndex2 + humanName: Left Index Intermediate + limit: + min: {x: 0, y: 0, z: -45} + max: {x: 0, y: 0, z: 45} + value: {x: .0223747883, y: 0, z: .0111873941} + length: .0279684942 + modified: 1 + - boneName: LeftHandIndex3 + humanName: Left Index Distal + limit: + min: {x: 0, y: 0, z: -45} + max: {x: 0, y: 0, z: 45} + value: {x: .0167810898, y: 0, z: .00839054491} + length: .0209763702 + modified: 1 + - boneName: LeftHandMiddle1 + humanName: Left Middle Proximal + limit: + min: {x: 0, y: -7.50000048, z: -50} + max: {x: 0, y: 7.50000048, z: 50} + value: {x: .0354260914, y: 0, z: .0177130457} + length: .0442826301 + modified: 1 + - boneName: LeftHandMiddle2 + humanName: Left Middle Intermediate + limit: + min: {x: 0, y: 0, z: -45} + max: {x: 0, y: 0, z: 45} + value: {x: .0271718036, y: 0, z: .0135859018} + length: .0339647643 + modified: 1 + - boneName: LeftHandMiddle3 + humanName: Left Middle Distal + limit: + min: {x: 0, y: 0, z: -45} + max: {x: 0, y: 0, z: 45} + value: {x: .0203788504, y: 0, z: .0101894252} + length: .0254735723 + modified: 1 + - boneName: LeftHandRing1 + humanName: Left Ring Proximal + limit: + min: {x: 0, y: -7.50000048, z: -50} + max: {x: 0, y: 7.50000048, z: 50} + value: {x: .0345545448, y: 0, z: .0172772724} + length: .0431931987 + modified: 1 + - boneName: LeftHandRing2 + humanName: Left Ring Intermediate + limit: + min: {x: 0, y: 0, z: -45} + max: {x: 0, y: 0, z: 45} + value: {x: .0246683266, y: 0, z: .0123341633} + length: .030835418 + modified: 1 + - boneName: LeftHandRing3 + humanName: Left Ring Distal + limit: + min: {x: 0, y: 0, z: -45} + max: {x: 0, y: 0, z: 45} + value: {x: .0185012426, y: 0, z: .00925062131} + length: .0231265631 + modified: 1 + - boneName: LeftHandPinky1 + humanName: Left Little Proximal + limit: + min: {x: 0, y: -20, z: -50} + max: {x: 0, y: 20, z: 50} + value: {x: .024671508, y: 0, z: .012335754} + length: .0308393929 + modified: 1 + - boneName: LeftHandPinky2 + humanName: Left Little Intermediate + limit: + min: {x: 0, y: 0, z: -45} + max: {x: 0, y: 0, z: 45} + value: {x: .0184510797, y: 0, z: .00922553986} + length: .023063859 + modified: 1 + - boneName: LeftHandPinky3 + humanName: Left Little Distal + limit: + min: {x: 0, y: 0, z: -45} + max: {x: 0, y: 0, z: 45} + value: {x: .0138383117, y: 0, z: .00691915583} + length: .0172978938 + modified: 1 + - boneName: RightHandThumb1 + humanName: Right Thumb Proximal + limit: + min: {x: 0, y: -25, z: -20} + max: {x: 0, y: 25, z: 20} + value: {x: .0232954696, y: 0, z: .0116477348} + length: .0291193463 + modified: 1 + - boneName: RightHandThumb2 + humanName: Right Thumb Intermediate + limit: + min: {x: 0, y: 0, z: -40} + max: {x: 0, y: 0, z: 35} + value: {x: .0270182006, y: 0, z: .0135091003} + length: .0337727591 + modified: 1 + - boneName: RightHandThumb3 + humanName: Right Thumb Distal + limit: + min: {x: 0, y: 0, z: -40} + max: {x: 0, y: 0, z: 35} + value: {x: .0202636477, y: 0, z: .0101318238} + length: .0253295694 + modified: 1 + - boneName: RightHandIndex1 + humanName: Right Index Proximal + limit: + min: {x: 0, y: -20, z: -50} + max: {x: 0, y: 20, z: 50} + value: {x: .0318517946, y: 0, z: .0159258973} + length: .039814759 + modified: 1 + - boneName: RightHandIndex2 + humanName: Right Index Intermediate + limit: + min: {x: 0, y: 0, z: -45} + max: {x: 0, y: 0, z: 45} + value: {x: .0223747734, y: 0, z: .0111873867} + length: .0279684756 + modified: 1 + - boneName: RightHandIndex3 + humanName: Right Index Distal + limit: + min: {x: 0, y: 0, z: -45} + max: {x: 0, y: 0, z: 45} + value: {x: .0167810787, y: 0, z: .00839053933} + length: .0209763572 + modified: 1 + - boneName: RightHandMiddle1 + humanName: Right Middle Proximal + limit: + min: {x: 0, y: -7.50000048, z: -50} + max: {x: 0, y: 7.50000048, z: 50} + value: {x: .0354261473, y: 0, z: .0177130736} + length: .0442827009 + modified: 1 + - boneName: RightHandMiddle2 + humanName: Right Middle Intermediate + limit: + min: {x: 0, y: 0, z: -45} + max: {x: 0, y: 0, z: 45} + value: {x: .0271718968, y: 0, z: .0135859484} + length: .0339648798 + modified: 1 + - boneName: RightHandMiddle3 + humanName: Right Middle Distal + limit: + min: {x: 0, y: 0, z: -45} + max: {x: 0, y: 0, z: 45} + value: {x: .0203789212, y: 0, z: .0101894606} + length: .0254736599 + modified: 1 + - boneName: RightHandRing1 + humanName: Right Ring Proximal + limit: + min: {x: 0, y: -7.50000048, z: -50} + max: {x: 0, y: 7.50000048, z: 50} + value: {x: .0345547274, y: 0, z: .0172773637} + length: .043193426 + modified: 1 + - boneName: RightHandRing2 + humanName: Right Ring Intermediate + limit: + min: {x: 0, y: 0, z: -45} + max: {x: 0, y: 0, z: 45} + value: {x: .0246685483, y: 0, z: .0123342741} + length: .0308356937 + modified: 1 + - boneName: RightHandRing3 + humanName: Right Ring Distal + limit: + min: {x: 0, y: 0, z: -45} + max: {x: 0, y: 0, z: 45} + value: {x: .0185014084, y: 0, z: .0092507042} + length: .0231267698 + modified: 1 + - boneName: RightHandPinky1 + humanName: Right Little Proximal + limit: + min: {x: 0, y: -20, z: -50} + max: {x: 0, y: 20, z: 50} + value: {x: .0246716533, y: 0, z: .0123358266} + length: .0308395755 + modified: 1 + - boneName: RightHandPinky2 + humanName: Right Little Intermediate + limit: + min: {x: 0, y: 0, z: -45} + max: {x: 0, y: 0, z: 45} + value: {x: .018451266, y: 0, z: .009225633} + length: .0230640918 + modified: 1 + - boneName: RightHandPinky3 + humanName: Right Little Distal + limit: + min: {x: 0, y: 0, z: -45} + max: {x: 0, y: 0, z: 45} + value: {x: .0138384514, y: 0, z: .00691922568} + length: .0172980689 + modified: 1 + skeleton: + - name: Dude + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: Reference + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: Hips + position: {x: 0, y: .963793993, z: -.0235067774} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: LeftUpLeg + position: {x: -.0754494965, y: -.0456640124, z: 0} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: LeftLeg + position: {x: -.0205505043, y: -.409129977, z: .00717136636} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: LeftFoot + position: {x: -.00515300781, y: -.423155904, z: -.0120320898} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: LeftToes + position: {x: -.00748699158, y: -.0731672645, z: .145427138} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: RightUpLeg + position: {x: .0754495338, y: -.0456640124, z: 0} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: RightLeg + position: {x: .0205504671, y: -.409129977, z: .00717136636} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: RightFoot + position: {x: .00515300035, y: -.423155904, z: -.0120320898} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: RightToes + position: {x: .00748699903, y: -.0731672645, z: .14542751} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: Spine + position: {x: 0, y: .0922632217, z: .0157713331} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: Chest + position: {x: 0, y: .162540197, z: .02185072} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: LeftShoulder + position: {x: -.0382435732, y: .192178011, z: -.017063085} + rotation: {x: -.0140067078, y: -.0595068112, z: .228689864, w: .971577883} + scale: {x: 1.00000024, y: 1, z: 1} + transformModified: 1 + - name: LeftArm + position: {x: -.083574675, y: .0360975936, z: -1.50734021e-08} + rotation: {x: .00946438964, y: .0436916873, z: -.223042384, w: .973783076} + scale: {x: 1, y: 1, z: 1.00000012} + transformModified: 1 + - name: LeftForeArm + position: {x: -.254049391, y: 4.70318128e-07, z: -2.19768759e-09} + rotation: {x: -.000616520061, y: .0220786203, z: -.0160702374, w: .999626815} + scale: {x: .99999994, y: 1, z: .999999881} + transformModified: 1 + - name: LeftHand + position: {x: -.246389359, y: -1.89769892e-07, z: -5.73217829e-09} + rotation: {x: 2.86021179e-10, y: -9.59063384e-10, z: -.0214135442, w: .999770641} + scale: {x: .99999994, y: 1, z: 1} + transformModified: 1 + - name: LeftHandIndex1 + position: {x: -.0751256943, y: -.0078413263, z: .0326526687} + rotation: {x: -.00211891951, y: .0802574232, z: .0175381787, w: .996617556} + scale: {x: 1, y: 1, z: .99999994} + transformModified: 1 + - name: LeftHandIndex2 + position: {x: -.0397970602, y: 4.9526192e-05, z: .00118574023} + rotation: {x: .000501931063, y: .0154708987, z: .040414121, w: .999063075} + scale: {x: 1.00000024, y: 1.00000024, z: .99999994} + transformModified: 1 + - name: LeftHandIndex3 + position: {x: -.0279685091, y: -1.79063633e-07, z: -9.18437095e-08} + rotation: {x: 4.33656722e-10, y: -1.75894304e-08, z: -1.0378705e-08, w: .99999994} + scale: {x: 1, y: 1.00000012, z: .999999881} + transformModified: 1 + - name: LeftHandMiddle1 + position: {x: -.0760235488, y: -.00188508059, z: .0101412414} + rotation: {x: -.000768872735, y: .0333210714, z: .0209075287, w: .999225616} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: LeftHandMiddle2 + position: {x: -.0442805924, y: 4.51253936e-06, z: -.000425422273} + rotation: {x: -.00136214169, y: -.0191537682, z: .0378897563, w: .999097347} + scale: {x: 1, y: 1.00000012, z: 1} + transformModified: 1 + - name: LeftHandMiddle3 + position: {x: -.0339647792, y: 1.61085282e-07, z: 5.41929612e-09} + rotation: {x: 6.13220641e-10, y: -4.12468948e-09, z: 1.82216331e-09, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: LeftHandPinky1 + position: {x: -.0656598732, y: -.00782526191, z: -.0322512463} + rotation: {x: -.000913206779, y: .0121623203, z: .0212220494, w: .999700308} + scale: {x: 1.00000012, y: 1, z: .999999881} + transformModified: 1 + - name: LeftHandPinky2 + position: {x: -.0308053754, y: -3.11739277e-05, z: -.00144808914} + rotation: {x: -.000170628555, y: -.0096613653, z: -.00536239706, w: .999938905} + scale: {x: 1, y: .999999821, z: 1.00000012} + transformModified: 1 + - name: LeftHandPinky3 + position: {x: -.0230638776, y: -6.67785343e-06, z: 6.90349244e-09} + rotation: {x: -8.51873905e-10, y: -9.4255892e-09, z: -1.31619666e-08, w: .99999994} + scale: {x: 1, y: 1, z: .99999994} + transformModified: 1 + - name: LeftHandRing1 + position: {x: -.0703021139, y: -.00374528999, z: -.0114117898} + rotation: {x: -.000324091874, y: .0115982238, z: .0247380193, w: .999626577} + scale: {x: 1, y: 1.00000024, z: .99999994} + transformModified: 1 + - name: LeftHandRing2 + position: {x: -.0431353189, y: -2.08693382e-05, z: -.00223518023} + rotation: {x: -.00120324548, y: -.0231137574, z: .040979635, w: .99889183} + scale: {x: .999999881, y: .999999702, z: .99999994} + transformModified: 1 + - name: LeftHandRing3 + position: {x: -.0308354236, y: -1.56879963e-07, z: -1.40963357e-08} + rotation: {x: 4.93614594e-10, y: -1.5807432e-09, z: -5.78796033e-09, w: .99999994} + scale: {x: 1, y: .99999994, z: .999999881} + transformModified: 1 + - name: LeftHandThumb1 + position: {x: -.0142313093, y: -.012377888, z: .0255316831} + rotation: {x: -.0123126386, y: -.0085253641, z: .0125855142, w: .999808609} + scale: {x: 1, y: 1, z: 1.00000012} + transformModified: 1 + - name: LeftHandThumb2 + position: {x: -.0163739249, y: -.00528992061, z: .0234914143} + rotation: {x: -.0260628555, y: .0966900289, z: .00360696716, w: .994966686} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: LeftHandThumb3 + position: {x: -.0254599936, y: -.00763992406, z: .020832995} + rotation: {x: 4.41585328e-08, y: 1.10925613e-09, z: -7.80932541e-10, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: Neck + position: {x: 0, y: .235723972, z: -.0324132554} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: Head + position: {x: 0, y: .106355786, z: .0113267824} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: Jaw + position: {x: 0, y: .0111267567, z: .0103275422} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: JawEND + position: {x: -0, y: -.0482887588, z: .071851708} + rotation: {x: 0, y: -0, z: -0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: LeftLipCorner + position: {x: -.032843262, y: -.01657876, z: .0661217645} + rotation: {x: 0, y: -0, z: -0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: LeftLipLower + position: {x: -.0142508168, y: -.0216887593, z: .0822406337} + rotation: {x: 0, y: -0, z: -0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: RightLipCorner + position: {x: .0328399986, y: -.01657876, z: .0661187842} + rotation: {x: 0, y: -0, z: -0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: RightLipLower + position: {x: .0142508168, y: -.0216887593, z: .0822387859} + rotation: {x: 0, y: -0, z: -0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: TongueBack + position: {x: -0, y: -.022869369, z: .0100954091} + rotation: {x: 0, y: -0, z: -0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: TongueTip + position: {x: -0, y: -.000409444125, z: .0282272995} + rotation: {x: 0, y: -0, z: -0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: LeftCheek + position: {x: -.0542440265, y: .0337019488, z: .0594304018} + rotation: {x: 0, y: -0, z: -0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: LeftEye + position: {x: -.0208482333, y: .0825027227, z: .0554274321} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: Le_Eye_Mesh + position: {x: -.00168411608, y: .000405807485, z: .00531818997} + rotation: {x: 0, y: -0, z: -0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: LeftEyelidLower + position: {x: -.0356189571, y: .0650736615, z: .076234743} + rotation: {x: -.0348994918, y: 0, z: -0, w: .999390781} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: LeftEyelidUpper + position: {x: -.0344068967, y: .10060814, z: .0802053064} + rotation: {x: 0, y: -0, z: -0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: LeftInnerBrow + position: {x: -.0120626912, y: .118765265, z: .0934668258} + rotation: {x: 0, y: -0, z: -0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: LeftIOuterBrow + position: {x: -.0550398715, y: .114825293, z: .061777398} + rotation: {x: 0, y: -0, z: -0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: LeftLipUpper + position: {x: -.0145013221, y: -.00511181122, z: .094618842} + rotation: {x: 0, y: -0, z: -0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: LeftNostril + position: {x: -.0178999994, y: .0263128281, z: .0908674002} + rotation: {x: 0, y: -0, z: -0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: RightCheek + position: {x: .0542399958, y: .033702828, z: .0594273992} + rotation: {x: 0, y: -0, z: -0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: RightEye + position: {x: .020849999, y: .0825027227, z: .0554273948} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: Ri_Eye_Mesh + position: {x: .00166187854, y: .000383453356, z: .00531667331} + rotation: {x: 0, y: -0, z: -0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: RightEyelidLower + position: {x: .0356200002, y: .065072827, z: .0762374029} + rotation: {x: -.0348994918, y: 0, z: -0, w: .999390781} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: RightEyelidUpper + position: {x: .0344099998, y: .100612827, z: .0802073926} + rotation: {x: 0, y: -0, z: -0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: RightInnerBrow + position: {x: .0120626874, y: .118765265, z: .0934668258} + rotation: {x: 0, y: -0, z: -0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: RightIOuterBrow + position: {x: .0550400019, y: .114822827, z: .061777398} + rotation: {x: 0, y: -0, z: -0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: RightLipUpper + position: {x: .0145013221, y: -.00510717137, z: .094617404} + rotation: {x: 0, y: -0, z: -0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: RightNostril + position: {x: .0178999994, y: .0263089053, z: .0908706188} + rotation: {x: 0, y: -0, z: -0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: RightShoulder + position: {x: .038328547, y: .192177057, z: -.0170630887} + rotation: {x: .228671983, y: .971582115, z: -.0140056778, w: -.05950737} + scale: {x: 1, y: 1.00000012, z: .99999994} + transformModified: 1 + - name: RightArm + position: {x: -.0835753977, y: .0360959396, z: -4.69747263e-08} + rotation: {x: -.211052075, y: -.974394023, z: .0173116978, w: -.0755877271} + scale: {x: .999999821, y: 1.00000012, z: .999999702} + transformModified: 1 + - name: RightForeArm + position: {x: .253428489, y: .00601093518, z: -.0167045332} + rotation: {x: -.000616519072, y: .0220786221, z: -.0160702337, w: .999626815} + scale: {x: .99999994, y: .999999881, z: .99999994} + transformModified: 1 + - name: RightHand + position: {x: .245373741, y: .0216420237, z: .00555047346} + rotation: {x: 5.43189438e-10, y: 3.12476184e-10, z: .0214136969, w: .999770641} + scale: {x: 1, y: 1, z: 1.00000012} + transformModified: 1 + - name: RightHandIndex1 + position: {x: .0747697875, y: -.00124282821, z: .0343445241} + rotation: {x: -.00211892067, y: .0802574307, z: .0175381824, w: .996617556} + scale: {x: 1.00000012, y: 1, z: .99999994} + transformModified: 1 + - name: RightHandIndex2 + position: {x: .037058223, y: .000725421763, z: .0145388739} + rotation: {x: -.0033212963, y: .0159312561, z: .060620904, w: .998028159} + scale: {x: 1, y: .99999994, z: 1} + transformModified: 1 + - name: RightHandIndex3 + position: {x: .0252250955, y: -.00496621709, z: .0110121826} + rotation: {x: 2.16179208e-09, y: 1.06850013e-08, z: -8.50230109e-09, w: .99999994} + scale: {x: 1, y: 1.00000012, z: 1.00000012} + transformModified: 1 + - name: RightHandMiddle1 + position: {x: .0756474286, y: .00479083089, z: .0118531957} + rotation: {x: -.00076887355, y: .0333210677, z: .0209075324, w: .999225616} + scale: {x: 1.00000012, y: .999999821, z: .999999881} + transformModified: 1 + - name: RightHandMiddle2 + position: {x: .0438093096, y: .000194165463, z: .00645493949} + rotation: {x: -.0041302545, y: -.0335112214, z: .0761189237, w: .996526837} + scale: {x: 1, y: .999999881, z: 1.00000012} + transformModified: 1 + - name: RightHandMiddle3 + position: {x: .0330725648, y: -.00754737761, z: .00168985641} + rotation: {x: -3.7425496e-10, y: -4.22918101e-09, z: -1.05837286e-08, w: .99999994} + scale: {x: 1, y: .999999881, z: 1} + transformModified: 1 + - name: RightHandPinky1 + position: {x: .0668031499, y: -.00199452811, z: -.0307561476} + rotation: {x: .00317558926, y: -.192005113, z: .045110438, w: .980351448} + scale: {x: 1.00000024, y: 1, z: .99999994} + transformModified: 1 + - name: RightHandPinky2 + position: {x: .0285309609, y: -.00139694544, z: -.0116238492} + rotation: {x: -.000170628467, y: -.00966134015, z: -.00536239473, w: .999938905} + scale: {x: .999999881, y: 1, z: .99999994} + transformModified: 1 + - name: RightHandPinky3 + position: {x: .0214269403, y: -.000553725113, z: -.00851663202} + rotation: {x: -8.53474014e-10, y: 1.63788556e-08, z: -1.38467984e-08, w: .99999994} + scale: {x: 1, y: 1, z: 1.00000012} + transformModified: 1 + - name: RightHandRing1 + position: {x: .070598565, y: .00245756772, z: -.00982147083} + rotation: {x: .000710569788, y: -.054343082, z: .0349452496, w: .99791038} + scale: {x: 1.00000012, y: 1, z: 1} + transformModified: 1 + - name: RightHandRing2 + position: {x: .0428872742, y: -.0013759057, z: -.00494588772} + rotation: {x: .000482838717, y: -.0212902706, z: .0698495656, w: .997330129} + scale: {x: 1, y: 1, z: 1.00000024} + transformModified: 1 + - name: RightHandRing3 + position: {x: .0295008179, y: -.00769269653, z: -.00462226616} + rotation: {x: -2.61377653e-09, y: -8.06309508e-09, z: -6.11845863e-09, w: .99999994} + scale: {x: 1, y: 1, z: 1.00000012} + transformModified: 1 + - name: RightHandThumb1 + position: {x: .014684936, y: -.0111049525, z: .025858108} + rotation: {x: -.0128134964, y: -.00325657125, z: .031457644, w: .999417603} + scale: {x: 1.00000012, y: 1, z: 1} + transformModified: 1 + - name: RightHandThumb2 + position: {x: .0163741205, y: -.00528976135, z: .0234913807} + rotation: {x: -.0260671675, y: -.0966875851, z: -.00360274338, w: .994966805} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: RightHandThumb3 + position: {x: .0254600029, y: -.00764030218, z: .0208330136} + rotation: {x: 1.31814044e-08, y: 1.05642828e-09, z: -2.01141503e-09, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + armTwist: .5 + foreArmTwist: .5 + upperLegTwist: .5 + legTwist: .5 + armStretch: .0500000007 + legStretch: .0500000007 + feetSpacing: 0 + rootMotionBoneName: + lastHumanDescriptionAvatarSource: {fileID: 9000000, guid: e194d39a231e29a489a36758f9fb175e, + type: 3} + animationType: 3 + additionalBone: 1 + userData: diff --git a/Assets/Photon Unity Networking/Demos/Shared Assets/Animations/IdlesWave.fbx b/Assets/Photon Unity Networking/Demos/Shared Assets/Animations/IdlesWave.fbx new file mode 100644 index 0000000..672e913 Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/Shared Assets/Animations/IdlesWave.fbx differ diff --git a/Assets/Photon Unity Networking/Demos/Shared Assets/Animations/IdlesWave.fbx.meta b/Assets/Photon Unity Networking/Demos/Shared Assets/Animations/IdlesWave.fbx.meta new file mode 100644 index 0000000..2f73e83 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/Shared Assets/Animations/IdlesWave.fbx.meta @@ -0,0 +1,1423 @@ +fileFormatVersion: 2 +guid: c387a0e47b4244f2b86c50372341024a +ModelImporter: + serializedVersion: 16 + fileIDToRecycleName: + 100000: LeftEye + 100002: Character_Ctrl:Reference + 100004: Character_Ctrl:HipsFK + 100006: l_hipProxy_geo + 100008: l_kneeProxy_geo + 100010: LToeBase_End2 + 100012: LeftLeg + 100014: pelvisProxy_geo + 100016: LeftUpLeg + 100018: r_kneeProxy_geo + 100020: Jaw + 100022: LeftArm + 100024: spineProxy_geo + 100026: LeftHandMiddle1 + 100028: UNI_01_TongueBaseProxy + 100030: Character_Ctrl:RightHandPinkyEffector + 100032: Character_Ctrl:RightHandMiddleEffector + 100034: Character_Ctrl:RightHandRingEffector + 100036: Character_Ctrl:RightHandThumbEffector + 100038: Character_Ctrl:RightHandIndexEffector + 100040: Character_Ctrl:LeftHandRingEffector + 100042: Character_Ctrl:LeftHandPinkyEffector + 100044: Character_Ctrl:LeftHandIndexEffector + 100046: Character_Ctrl:LeftHandMiddleEffector + 100048: //RootNode + 100050: Character_Ctrl:LeftHipEffector + 100052: Character_Ctrl:RightHipEffector + 100054: Character_Ctrl:RightHandPinky1 + 100056: Character_Ctrl:RightHandPinky2 + 100058: Hips + 100060: Character_Ctrl:RightShoulderEffector + 100062: Character_Ctrl:HeadEffector + 100064: Character_Ctrl:ChestEndEffector + 100066: Character_Ctrl:LeftShoulderEffector + 100068: Character_Ctrl:RightElbowEffector + 100070: Character_Ctrl:ChestOriginEffector + 100072: Character_Ctrl:LeftElbowEffector + 100074: Character_Ctrl:LeftHandThumbEffector + 100076: LeftHandRing1 + 100078: Character_Ctrl:LeftKneeEffector + 100080: Character_Ctrl:RightKneeEffector + 100082: Character_Ctrl:LeftWristEffector + 100084: Character_Ctrl:RightWristEffector + 100086: Character_Ctrl:LeftAnkleEffector + 100088: Character_Ctrl:RightAnkleEffector + 100090: Character_Ctrl:Head + 100092: Character_Ctrl:Neck + 100094: Character_Ctrl:RightHandPinky3 + 100096: Character_Ctrl:HipsEffector + 100098: Character_Ctrl:Spine + 100100: Character_Ctrl:RightHandRing2 + 100102: Character_Ctrl:RightHandRing3 + 100104: Character_Ctrl:RightHandMiddle3 + 100106: Character_Ctrl:RightHandRing1 + 100108: Character_Ctrl:RightHandMiddle1 + 100110: Character_Ctrl:RightHandMiddle2 + 100112: Character_Ctrl:RightHandIndex2 + 100114: Character_Ctrl:RightHandIndex3 + 100116: Character_Ctrl:RightHandThumb3 + 100118: Character_Ctrl:RightHandIndex1 + 100120: Character_Ctrl:RightHandThumb1 + 100122: Character_Ctrl:RightHandThumb2 + 100124: Character_Ctrl:RightForeArm + 100126: Character_Ctrl:RightHand + 100128: Character_Ctrl:RightShoulder + 100130: Character_Ctrl:RightArm + 100132: Character_Ctrl:LeftHandPinky2 + 100134: Character_Ctrl:LeftHandPinky3 + 100136: Character_Ctrl:LeftHandPinky1 + 100138: Character_Ctrl:LeftHandRing2 + 100140: Character_Ctrl:LeftHandRing3 + 100142: Character_Ctrl:LeftHandMiddle3 + 100144: Character_Ctrl:LeftHandRing1 + 100146: Character_Ctrl:LeftHandMiddle1 + 100148: Character_Ctrl:LeftHandMiddle2 + 100150: Character_Ctrl:LeftHandIndex2 + 100152: Character_Ctrl:LeftHandIndex3 + 100154: Character_Ctrl:LeftHandThumb3 + 100156: Character_Ctrl:LeftHandIndex1 + 100158: Character_Ctrl:LeftHandThumb2 + 100160: Character_Ctrl:LeftHand + 100162: Character_Ctrl:LeftHandThumb1 + 100164: Character_Ctrl:LeftArm + 100166: Character_Ctrl:LeftForeArm + 100168: Character_Ctrl:LeftShoulder + 100170: Character_Ctrl:RightLeg + 100172: Character_Ctrl:RightFoot + 100174: Character_Ctrl:LeftFoot + 100176: Character_Ctrl:RightUpLeg + 100178: Character_Ctrl:Spine1 + 100180: Character_Ctrl:LeftUpLeg + 100182: Character_Ctrl:LeftLeg + 100184: l_ankleProxy_geo + 100186: l_ballProxy_geo + 100188: LeftToes + 100190: LeftFoot + 100192: r_hipProxy_geo + 100194: r_ankleProxy_geo + 100196: r_ballProxy_geo + 100198: LToeBase_End3 + 100200: RightToes + 100202: RightFoot + 100204: RightLeg + 100206: RightUpLeg + 100208: l_clavicleProxy_geo + 100210: l_shourderProxy_geo + 100212: l_erbowProxy_geo + 100214: l_wristProxy_geo + 100216: l_thumbProxy_01_geo + 100218: l_thumbProxy_02_geo + 100220: l_thumbProxy_03_geo + 100222: LeftHandThumb13 + 100224: LeftHandThumb3 + 100226: LeftHandThumb1 + 100228: l_indexProxy_01_geo + 100230: l_indexProxy_02_geo + 100232: l_indexProxy_03_geo + 100234: LeftHandIndex13 + 100236: LeftHandIndex3 + 100238: LeftHandIndex2 + 100240: LeftHandIndex1 + 100242: l_middleProxy_01_geo + 100244: l_middleProxy_02_geo + 100246: l_middleProxy_03_geo + 100248: LeftHandMiddle13 + 100250: LeftHandMiddle3 + 100252: LeftHandMiddle2 + 100254: LeftHandThumb2 + 100256: l_ringProxy_01_geo + 100258: l_ringProxy_02_geo + 100260: l_ringProxy_03_geo + 100262: LeftHandRing13 + 100264: LeftHandRing3 + 100266: Reference + 100268: Head + 100270: TongueBack + 100272: Neck + 100274: Chest + 100276: HeadTop_End + 100278: Spine + 100280: l_UNI_eye + 100282: l_pinkyProxy_01_geo + 100284: l_pinkyProxy_02_geo + 100286: l_pinkyProxy_03_geo + 100288: LeftHandPinky13 + 100290: LeftHandPinky3 + 100292: LeftHandPinky2 + 100294: LeftHandPinky1 + 100296: LeftHand + 100298: LeftForeArm + 100300: LeftShoulder + 100302: chestProxy_geo + 100304: r_clavicleProxy_geo + 100306: r_shourderProxy_geo + 100308: r_erbowProxy_geo + 100310: r_wristProxy_geo + 100312: r_thumbProxy_01_geo + 100314: r_thumbProxy_02_geo + 100316: r_thumbProxy_03_geo + 100318: LeftHandThumb17 + 100320: RightHandThumb3 + 100322: RightHandThumb2 + 100324: RightHandThumb1 + 100326: r_indexProxy_01_geo + 100328: r_indexProxy_02_geo + 100330: LeftHandRing2 + 100332: r_indexProxy_03_geo + 100334: LeftHandIndex17 + 100336: RightHandIndex3 + 100338: RightHandIndex2 + 100340: RightHandIndex1 + 100342: r_middleProxy_01_geo + 100344: r_middleProxy_02_geo + 100346: r_middleProxy_03_geo + 100348: LeftHandMiddle17 + 100350: RightHandMiddle3 + 100352: RightHandMiddle2 + 100354: RightHandMiddle1 + 100356: r_ringProxy_01_geo + 100358: r_ringProxy_02_geo + 100360: r_ringProxy_03_geo + 100362: LeftHandRing17 + 100364: RightHandRing2 + 100366: RightHandRing1 + 100368: RightHandRing3 + 100370: r_pinkyProxy_01_geo + 100372: r_pinkyProxy_02_geo + 100374: r_pinkyProxy_03_geo + 100376: LeftHandPinky17 + 100378: RightHandPinky3 + 100380: RightHandPinky2 + 100382: RightHandPinky1 + 100384: RightHand + 100386: RightForeArm + 100388: RightArm + 100390: RightShoulder + 100392: UNI_01_Upper_teethProxy + 100394: neckProxy_geo + 100396: headProxy_geo + 100398: RightLipUpper + 100400: RightNostril + 100402: RightCheek + 100404: RightEyelidLower + 100406: RightEyelidUpper + 100408: RightIOuterBrow + 100410: RightInnerBrow + 100412: LeftIOuterBrow + 100414: LeftInnerBrow + 100416: LeftEyelidUpper + 100418: LeftEyelidLower + 100420: LeftCheek + 100422: LeftNostril + 100424: LeftLipUpper + 100426: jawProxy_geo + 100428: UNI_01_Lower_teethProxy + 100430: LeftLipCorner + 100432: RightLipCorner + 100434: RightLipLower + 100436: JawEND + 100438: LeftLipLower + 100440: UNI_01_TongueTipProxy + 100442: TongueTip + 100444: r_UNI_eye + 100446: RightEye + 400000: LeftEye + 400002: Character_Ctrl:Reference + 400004: Character_Ctrl:HipsFK + 400006: l_hipProxy_geo + 400008: l_kneeProxy_geo + 400010: LToeBase_End2 + 400012: LeftLeg + 400014: pelvisProxy_geo + 400016: LeftUpLeg + 400018: r_kneeProxy_geo + 400020: Jaw + 400022: LeftArm + 400024: spineProxy_geo + 400026: LeftHandMiddle1 + 400028: UNI_01_TongueBaseProxy + 400030: Character_Ctrl:RightHandPinkyEffector + 400032: Character_Ctrl:RightHandMiddleEffector + 400034: Character_Ctrl:RightHandRingEffector + 400036: Character_Ctrl:RightHandThumbEffector + 400038: Character_Ctrl:RightHandIndexEffector + 400040: Character_Ctrl:LeftHandRingEffector + 400042: Character_Ctrl:LeftHandPinkyEffector + 400044: Character_Ctrl:LeftHandIndexEffector + 400046: Character_Ctrl:LeftHandMiddleEffector + 400048: //RootNode + 400050: Character_Ctrl:LeftHipEffector + 400052: Character_Ctrl:RightHipEffector + 400054: Character_Ctrl:RightHandPinky1 + 400056: Character_Ctrl:RightHandPinky2 + 400058: Hips + 400060: Character_Ctrl:RightShoulderEffector + 400062: Character_Ctrl:HeadEffector + 400064: Character_Ctrl:ChestEndEffector + 400066: Character_Ctrl:LeftShoulderEffector + 400068: Character_Ctrl:RightElbowEffector + 400070: Character_Ctrl:ChestOriginEffector + 400072: Character_Ctrl:LeftElbowEffector + 400074: Character_Ctrl:LeftHandThumbEffector + 400076: LeftHandRing1 + 400078: Character_Ctrl:LeftKneeEffector + 400080: Character_Ctrl:RightKneeEffector + 400082: Character_Ctrl:LeftWristEffector + 400084: Character_Ctrl:RightWristEffector + 400086: Character_Ctrl:LeftAnkleEffector + 400088: Character_Ctrl:RightAnkleEffector + 400090: Character_Ctrl:Head + 400092: Character_Ctrl:Neck + 400094: Character_Ctrl:RightHandPinky3 + 400096: Character_Ctrl:HipsEffector + 400098: Character_Ctrl:Spine + 400100: Character_Ctrl:RightHandRing2 + 400102: Character_Ctrl:RightHandRing3 + 400104: Character_Ctrl:RightHandMiddle3 + 400106: Character_Ctrl:RightHandRing1 + 400108: Character_Ctrl:RightHandMiddle1 + 400110: Character_Ctrl:RightHandMiddle2 + 400112: Character_Ctrl:RightHandIndex2 + 400114: Character_Ctrl:RightHandIndex3 + 400116: Character_Ctrl:RightHandThumb3 + 400118: Character_Ctrl:RightHandIndex1 + 400120: Character_Ctrl:RightHandThumb1 + 400122: Character_Ctrl:RightHandThumb2 + 400124: Character_Ctrl:RightForeArm + 400126: Character_Ctrl:RightHand + 400128: Character_Ctrl:RightShoulder + 400130: Character_Ctrl:RightArm + 400132: Character_Ctrl:LeftHandPinky2 + 400134: Character_Ctrl:LeftHandPinky3 + 400136: Character_Ctrl:LeftHandPinky1 + 400138: Character_Ctrl:LeftHandRing2 + 400140: Character_Ctrl:LeftHandRing3 + 400142: Character_Ctrl:LeftHandMiddle3 + 400144: Character_Ctrl:LeftHandRing1 + 400146: Character_Ctrl:LeftHandMiddle1 + 400148: Character_Ctrl:LeftHandMiddle2 + 400150: Character_Ctrl:LeftHandIndex2 + 400152: Character_Ctrl:LeftHandIndex3 + 400154: Character_Ctrl:LeftHandThumb3 + 400156: Character_Ctrl:LeftHandIndex1 + 400158: Character_Ctrl:LeftHandThumb2 + 400160: Character_Ctrl:LeftHand + 400162: Character_Ctrl:LeftHandThumb1 + 400164: Character_Ctrl:LeftArm + 400166: Character_Ctrl:LeftForeArm + 400168: Character_Ctrl:LeftShoulder + 400170: Character_Ctrl:RightLeg + 400172: Character_Ctrl:RightFoot + 400174: Character_Ctrl:LeftFoot + 400176: Character_Ctrl:RightUpLeg + 400178: Character_Ctrl:Spine1 + 400180: Character_Ctrl:LeftUpLeg + 400182: Character_Ctrl:LeftLeg + 400184: l_ankleProxy_geo + 400186: l_ballProxy_geo + 400188: LeftToes + 400190: LeftFoot + 400192: r_hipProxy_geo + 400194: r_ankleProxy_geo + 400196: r_ballProxy_geo + 400198: LToeBase_End3 + 400200: RightToes + 400202: RightFoot + 400204: RightLeg + 400206: RightUpLeg + 400208: l_clavicleProxy_geo + 400210: l_shourderProxy_geo + 400212: l_erbowProxy_geo + 400214: l_wristProxy_geo + 400216: l_thumbProxy_01_geo + 400218: l_thumbProxy_02_geo + 400220: l_thumbProxy_03_geo + 400222: LeftHandThumb13 + 400224: LeftHandThumb3 + 400226: LeftHandThumb1 + 400228: l_indexProxy_01_geo + 400230: l_indexProxy_02_geo + 400232: l_indexProxy_03_geo + 400234: LeftHandIndex13 + 400236: LeftHandIndex3 + 400238: LeftHandIndex2 + 400240: LeftHandIndex1 + 400242: l_middleProxy_01_geo + 400244: l_middleProxy_02_geo + 400246: l_middleProxy_03_geo + 400248: LeftHandMiddle13 + 400250: LeftHandMiddle3 + 400252: LeftHandMiddle2 + 400254: LeftHandThumb2 + 400256: l_ringProxy_01_geo + 400258: l_ringProxy_02_geo + 400260: l_ringProxy_03_geo + 400262: LeftHandRing13 + 400264: LeftHandRing3 + 400266: Reference + 400268: Head + 400270: TongueBack + 400272: Neck + 400274: Chest + 400276: HeadTop_End + 400278: Spine + 400280: l_UNI_eye + 400282: l_pinkyProxy_01_geo + 400284: l_pinkyProxy_02_geo + 400286: l_pinkyProxy_03_geo + 400288: LeftHandPinky13 + 400290: LeftHandPinky3 + 400292: LeftHandPinky2 + 400294: LeftHandPinky1 + 400296: LeftHand + 400298: LeftForeArm + 400300: LeftShoulder + 400302: chestProxy_geo + 400304: r_clavicleProxy_geo + 400306: r_shourderProxy_geo + 400308: r_erbowProxy_geo + 400310: r_wristProxy_geo + 400312: r_thumbProxy_01_geo + 400314: r_thumbProxy_02_geo + 400316: r_thumbProxy_03_geo + 400318: LeftHandThumb17 + 400320: RightHandThumb3 + 400322: RightHandThumb2 + 400324: RightHandThumb1 + 400326: r_indexProxy_01_geo + 400328: r_indexProxy_02_geo + 400330: LeftHandRing2 + 400332: r_indexProxy_03_geo + 400334: LeftHandIndex17 + 400336: RightHandIndex3 + 400338: RightHandIndex2 + 400340: RightHandIndex1 + 400342: r_middleProxy_01_geo + 400344: r_middleProxy_02_geo + 400346: r_middleProxy_03_geo + 400348: LeftHandMiddle17 + 400350: RightHandMiddle3 + 400352: RightHandMiddle2 + 400354: RightHandMiddle1 + 400356: r_ringProxy_01_geo + 400358: r_ringProxy_02_geo + 400360: r_ringProxy_03_geo + 400362: LeftHandRing17 + 400364: RightHandRing2 + 400366: RightHandRing1 + 400368: RightHandRing3 + 400370: r_pinkyProxy_01_geo + 400372: r_pinkyProxy_02_geo + 400374: r_pinkyProxy_03_geo + 400376: LeftHandPinky17 + 400378: RightHandPinky3 + 400380: RightHandPinky2 + 400382: RightHandPinky1 + 400384: RightHand + 400386: RightForeArm + 400388: RightArm + 400390: RightShoulder + 400392: UNI_01_Upper_teethProxy + 400394: neckProxy_geo + 400396: headProxy_geo + 400398: RightLipUpper + 400400: RightNostril + 400402: RightCheek + 400404: RightEyelidLower + 400406: RightEyelidUpper + 400408: RightIOuterBrow + 400410: RightInnerBrow + 400412: LeftIOuterBrow + 400414: LeftInnerBrow + 400416: LeftEyelidUpper + 400418: LeftEyelidLower + 400420: LeftCheek + 400422: LeftNostril + 400424: LeftLipUpper + 400426: jawProxy_geo + 400428: UNI_01_Lower_teethProxy + 400430: LeftLipCorner + 400432: RightLipCorner + 400434: RightLipLower + 400436: JawEND + 400438: LeftLipLower + 400440: UNI_01_TongueTipProxy + 400442: TongueTip + 400444: r_UNI_eye + 400446: RightEye + 2300000: l_hipProxy_geo + 2300002: l_kneeProxy_geo + 2300004: pelvisProxy_geo + 2300006: r_kneeProxy_geo + 2300008: spineProxy_geo + 2300010: UNI_01_TongueBaseProxy + 2300012: l_ankleProxy_geo + 2300014: l_ballProxy_geo + 2300016: r_hipProxy_geo + 2300018: r_ankleProxy_geo + 2300020: r_ballProxy_geo + 2300022: l_clavicleProxy_geo + 2300024: l_shourderProxy_geo + 2300026: l_erbowProxy_geo + 2300028: l_wristProxy_geo + 2300030: l_thumbProxy_01_geo + 2300032: l_thumbProxy_02_geo + 2300034: l_thumbProxy_03_geo + 2300036: l_indexProxy_01_geo + 2300038: l_indexProxy_02_geo + 2300040: l_indexProxy_03_geo + 2300042: l_middleProxy_01_geo + 2300044: l_middleProxy_02_geo + 2300046: l_middleProxy_03_geo + 2300048: l_ringProxy_01_geo + 2300050: l_ringProxy_02_geo + 2300052: l_ringProxy_03_geo + 2300054: l_UNI_eye + 2300056: l_pinkyProxy_01_geo + 2300058: l_pinkyProxy_02_geo + 2300060: l_pinkyProxy_03_geo + 2300062: chestProxy_geo + 2300064: r_clavicleProxy_geo + 2300066: r_shourderProxy_geo + 2300068: r_erbowProxy_geo + 2300070: r_wristProxy_geo + 2300072: r_thumbProxy_01_geo + 2300074: r_thumbProxy_02_geo + 2300076: r_thumbProxy_03_geo + 2300078: r_indexProxy_01_geo + 2300080: r_indexProxy_02_geo + 2300082: r_indexProxy_03_geo + 2300084: r_middleProxy_01_geo + 2300086: r_middleProxy_02_geo + 2300088: r_middleProxy_03_geo + 2300090: r_ringProxy_01_geo + 2300092: r_ringProxy_02_geo + 2300094: r_ringProxy_03_geo + 2300096: r_pinkyProxy_01_geo + 2300098: r_pinkyProxy_02_geo + 2300100: r_pinkyProxy_03_geo + 2300102: UNI_01_Upper_teethProxy + 2300104: neckProxy_geo + 2300106: headProxy_geo + 2300108: jawProxy_geo + 2300110: UNI_01_Lower_teethProxy + 2300112: UNI_01_TongueTipProxy + 2300114: r_UNI_eye + 3300000: l_hipProxy_geo + 3300002: l_kneeProxy_geo + 3300004: pelvisProxy_geo + 3300006: r_kneeProxy_geo + 3300008: spineProxy_geo + 3300010: UNI_01_TongueBaseProxy + 3300012: l_ankleProxy_geo + 3300014: l_ballProxy_geo + 3300016: r_hipProxy_geo + 3300018: r_ankleProxy_geo + 3300020: r_ballProxy_geo + 3300022: l_clavicleProxy_geo + 3300024: l_shourderProxy_geo + 3300026: l_erbowProxy_geo + 3300028: l_wristProxy_geo + 3300030: l_thumbProxy_01_geo + 3300032: l_thumbProxy_02_geo + 3300034: l_thumbProxy_03_geo + 3300036: l_indexProxy_01_geo + 3300038: l_indexProxy_02_geo + 3300040: l_indexProxy_03_geo + 3300042: l_middleProxy_01_geo + 3300044: l_middleProxy_02_geo + 3300046: l_middleProxy_03_geo + 3300048: l_ringProxy_01_geo + 3300050: l_ringProxy_02_geo + 3300052: l_ringProxy_03_geo + 3300054: l_UNI_eye + 3300056: l_pinkyProxy_01_geo + 3300058: l_pinkyProxy_02_geo + 3300060: l_pinkyProxy_03_geo + 3300062: chestProxy_geo + 3300064: r_clavicleProxy_geo + 3300066: r_shourderProxy_geo + 3300068: r_erbowProxy_geo + 3300070: r_wristProxy_geo + 3300072: r_thumbProxy_01_geo + 3300074: r_thumbProxy_02_geo + 3300076: r_thumbProxy_03_geo + 3300078: r_indexProxy_01_geo + 3300080: r_indexProxy_02_geo + 3300082: r_indexProxy_03_geo + 3300084: r_middleProxy_01_geo + 3300086: r_middleProxy_02_geo + 3300088: r_middleProxy_03_geo + 3300090: r_ringProxy_01_geo + 3300092: r_ringProxy_02_geo + 3300094: r_ringProxy_03_geo + 3300096: r_pinkyProxy_01_geo + 3300098: r_pinkyProxy_02_geo + 3300100: r_pinkyProxy_03_geo + 3300102: UNI_01_Upper_teethProxy + 3300104: neckProxy_geo + 3300106: headProxy_geo + 3300108: jawProxy_geo + 3300110: UNI_01_Lower_teethProxy + 3300112: UNI_01_TongueTipProxy + 3300114: r_UNI_eye + 4300000: l_UNI_eye + 4300002: r_UNI_eye + 4300004: UNI_01_TongueBaseProxy + 4300006: UNI_01_TongueTipProxy + 4300008: UNI_01_Lower_teethProxy + 4300010: jawProxy_geo + 4300012: headProxy_geo + 4300014: UNI_01_Upper_teethProxy + 4300016: neckProxy_geo + 4300018: r_pinkyProxy_03_geo + 4300020: r_pinkyProxy_02_geo + 4300022: r_pinkyProxy_01_geo + 4300024: r_ringProxy_03_geo + 4300026: r_ringProxy_02_geo + 4300028: r_ringProxy_01_geo + 4300030: r_middleProxy_03_geo + 4300032: r_middleProxy_02_geo + 4300034: r_middleProxy_01_geo + 4300036: r_indexProxy_03_geo + 4300038: r_indexProxy_02_geo + 4300040: r_indexProxy_01_geo + 4300042: r_thumbProxy_03_geo + 4300044: r_thumbProxy_02_geo + 4300046: r_thumbProxy_01_geo + 4300048: r_wristProxy_geo + 4300050: r_erbowProxy_geo + 4300052: r_shourderProxy_geo + 4300054: r_clavicleProxy_geo + 4300056: chestProxy_geo + 4300058: l_pinkyProxy_03_geo + 4300060: l_pinkyProxy_02_geo + 4300062: l_pinkyProxy_01_geo + 4300064: l_ringProxy_03_geo + 4300066: l_ringProxy_02_geo + 4300068: l_ringProxy_01_geo + 4300070: l_middleProxy_03_geo + 4300072: l_middleProxy_02_geo + 4300074: l_middleProxy_01_geo + 4300076: l_indexProxy_03_geo + 4300078: l_indexProxy_02_geo + 4300080: l_indexProxy_01_geo + 4300082: l_thumbProxy_03_geo + 4300084: l_thumbProxy_02_geo + 4300086: l_thumbProxy_01_geo + 4300088: l_wristProxy_geo + 4300090: l_erbowProxy_geo + 4300092: l_shourderProxy_geo + 4300094: l_clavicleProxy_geo + 4300096: spineProxy_geo + 4300098: r_ballProxy_geo + 4300100: r_ankleProxy_geo + 4300102: r_kneeProxy_geo + 4300104: r_hipProxy_geo + 4300106: pelvisProxy_geo + 4300108: l_ballProxy_geo + 4300110: l_ankleProxy_geo + 4300112: l_kneeProxy_geo + 4300114: l_hipProxy_geo + 7400002: Wave + 7400004: Wave + 11100000: //RootNode + materials: + importMaterials: 1 + materialName: 0 + materialSearch: 1 + animations: + legacyGenerateAnimations: 4 + bakeSimulation: 0 + optimizeGameObjects: 0 + motionNodeName: + animationCompression: 1 + animationRotationError: .5 + animationPositionError: .5 + animationScaleError: .5 + animationWrapMode: 0 + extraExposedTransformPaths: [] + clipAnimations: + - serializedVersion: 16 + name: Wave + takeName: Idle + firstFrame: 120 + lastFrame: 229 + wrapMode: 0 + orientationOffsetY: 0 + level: 0 + cycleOffset: 0 + loop: 0 + loopTime: 1 + loopBlend: 1 + loopBlendOrientation: 1 + loopBlendPositionY: 1 + loopBlendPositionXZ: 1 + keepOriginalOrientation: 0 + keepOriginalPositionY: 1 + keepOriginalPositionXZ: 0 + heightFromFeet: 0 + mirror: 0 + bodyMask: 01000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000 + curves: [] + events: [] + transformMask: [] + maskType: 0 + maskSource: {instanceID: 0} + isReadable: 1 + meshes: + lODScreenPercentages: [] + globalScale: .00999999978 + meshCompression: 0 + addColliders: 0 + importBlendShapes: 1 + swapUVChannels: 0 + generateSecondaryUV: 0 + useFileUnits: 1 + optimizeMeshForGPU: 1 + weldVertices: 1 + secondaryUVAngleDistortion: 8 + secondaryUVAreaDistortion: 15.000001 + secondaryUVHardAngle: 88 + secondaryUVPackMargin: 4 + tangentSpace: + normalSmoothAngle: 60 + splitTangentsAcrossUV: 1 + normalImportMode: 0 + tangentImportMode: 1 + importAnimation: 1 + copyAvatar: 1 + humanDescription: + human: + - boneName: Hips + humanName: Hips + limit: + min: {x: -40, y: -40, z: -40} + max: {x: 40, y: 40, z: 40} + value: {x: .0748811588, y: 0, z: .0374405794} + length: .0936014801 + modified: 1 + - boneName: LeftUpLeg + humanName: LeftUpperLeg + limit: + min: {x: -60.0000038, y: -60.0000038, z: -90} + max: {x: 60.0000038, y: 60.0000038, z: 50} + value: {x: .327766716, y: 0, z: .163883358} + length: .40970853 + modified: 1 + - boneName: RightUpLeg + humanName: RightUpperLeg + limit: + min: {x: -60.0000038, y: -60.0000038, z: -90} + max: {x: 60.0000038, y: 60.0000038, z: 50} + value: {x: .327766716, y: 0, z: .163883358} + length: .40970853 + modified: 1 + - boneName: LeftLeg + humanName: LeftLowerLeg + limit: + min: {x: -90, y: 0, z: -80} + max: {x: 90, y: 0, z: 80} + value: {x: .338686436, y: 0, z: .169343218} + length: .423358172 + modified: 1 + - boneName: RightLeg + humanName: RightLowerLeg + limit: + min: {x: -90, y: 0, z: -80} + max: {x: 90, y: 0, z: 80} + value: {x: .338686436, y: 0, z: .169343218} + length: .423358172 + modified: 1 + - boneName: LeftFoot + humanName: LeftFoot + limit: + min: {x: 0, y: -30.0000019, z: -50} + max: {x: 0, y: 30.0000019, z: 50} + value: {x: .0686753467, y: 0, z: .0343376733} + length: .0858442187 + modified: 1 + - boneName: RightFoot + humanName: RightFoot + limit: + min: {x: 0, y: -30.0000019, z: -50} + max: {x: 0, y: 30.0000019, z: 50} + value: {x: .0686753467, y: 0, z: .0343376733} + length: .0858442187 + modified: 1 + - boneName: Spine + humanName: Spine + limit: + min: {x: -40, y: -40, z: -40} + max: {x: 40, y: 40, z: 40} + value: {x: .131201819, y: 0, z: .0656009093} + length: .164002344 + modified: 1 + - boneName: Chest + humanName: Chest + limit: + min: {x: -40, y: -40, z: -40} + max: {x: 40, y: 40, z: 40} + value: {x: .190353557, y: 0, z: .0951767787} + length: .237942025 + modified: 1 + - boneName: Neck + humanName: Neck + limit: + min: {x: -40, y: -40, z: -40} + max: {x: 40, y: 40, z: 40} + value: {x: .0855657607, y: 0, z: .0427828804} + length: .106957234 + modified: 1 + - boneName: Head + humanName: Head + limit: + min: {x: -40, y: -40, z: -40} + max: {x: 40, y: 40, z: 40} + value: {x: .0855657607, y: 0, z: .0427828804} + length: .106957234 + modified: 1 + - boneName: LeftShoulder + humanName: LeftShoulder + limit: + min: {x: 0, y: -15.000001, z: -15.000001} + max: {x: 0, y: 15.000001, z: 30.0000019} + value: {x: .072829701, y: 0, z: .0364148505} + length: .0910371616 + modified: 1 + - boneName: RightShoulder + humanName: RightShoulder + limit: + min: {x: 0, y: -15.000001, z: -15.000001} + max: {x: 0, y: 15.000001, z: 30.0000019} + value: {x: .072829701, y: 0, z: .0364148505} + length: .0910371616 + modified: 1 + - boneName: LeftArm + humanName: LeftUpperArm + limit: + min: {x: -90, y: -100, z: -60.0000038} + max: {x: 90, y: 100, z: 100} + value: {x: .203239605, y: 0, z: .101619802} + length: .254049569 + modified: 1 + - boneName: RightArm + humanName: RightUpperArm + limit: + min: {x: -90, y: -100, z: -60.0000038} + max: {x: 90, y: 100, z: 100} + value: {x: .203239486, y: 0, z: .101619743} + length: .25404942 + modified: 1 + - boneName: LeftForeArm + humanName: LeftLowerArm + limit: + min: {x: -90, y: 0, z: -80} + max: {x: 90, y: 0, z: 80} + value: {x: .197111428, y: 0, z: .0985557139} + length: .246389359 + modified: 1 + - boneName: RightForeArm + humanName: RightLowerArm + limit: + min: {x: -90, y: 0, z: -80} + max: {x: 90, y: 0, z: 80} + value: {x: .197110936, y: 0, z: .098555468} + length: .246388748 + modified: 1 + - boneName: LeftHand + humanName: LeftHand + limit: + min: {x: 0, y: -40, z: -80} + max: {x: 0, y: 40, z: 80} + value: {x: .0985557139, y: 0, z: .0492778569} + length: .12319468 + modified: 1 + - boneName: RightHand + humanName: RightHand + limit: + min: {x: 0, y: -40, z: -80} + max: {x: 0, y: 40, z: 80} + value: {x: .098555468, y: 0, z: .049277734} + length: .123194374 + modified: 1 + - boneName: LeftToes + humanName: LeftToes + limit: + min: {x: 0, y: 0, z: -50} + max: {x: 0, y: 0, z: 50} + value: {x: .0651871562, y: 0, z: .0325935781} + length: .0814839825 + modified: 1 + - boneName: RightToes + humanName: RightToes + limit: + min: {x: 0, y: 0, z: -50} + max: {x: 0, y: 0, z: 50} + value: {x: .0651872903, y: 0, z: .0325936452} + length: .0814841464 + modified: 1 + - boneName: LeftEye + humanName: LeftEye + limit: + min: {x: 0, y: -20, z: -10} + max: {x: 0, y: 20, z: 15.000001} + value: {x: .0799999759, y: 0, z: .0399999879} + length: .100000001 + modified: 1 + - boneName: RightEye + humanName: RightEye + limit: + min: {x: 0, y: -20, z: -10} + max: {x: 0, y: 20, z: 15.000001} + value: {x: .0799999759, y: 0, z: .0399999879} + length: .100000001 + modified: 1 + - boneName: Jaw + humanName: Jaw + limit: + min: {x: 0, y: -10, z: -10} + max: {x: 0, y: 10, z: 10} + value: {x: .0799999759, y: 0, z: .0399999879} + length: .100000001 + modified: 1 + - boneName: LeftHandThumb1 + humanName: Left Thumb Proximal + limit: + min: {x: 0, y: -25, z: -20} + max: {x: 0, y: 25, z: 20} + value: {x: .0232954584, y: 0, z: .0116477292} + length: .0291193314 + modified: 1 + - boneName: LeftHandThumb2 + humanName: Left Thumb Intermediate + limit: + min: {x: 0, y: 0, z: -40} + max: {x: 0, y: 0, z: 35} + value: {x: .0270181261, y: 0, z: .0135090631} + length: .033772666 + modified: 1 + - boneName: LeftHandThumb3 + humanName: Left Thumb Distal + limit: + min: {x: 0, y: 0, z: -40} + max: {x: 0, y: 0, z: 35} + value: {x: .0202635936, y: 0, z: .0101317968} + length: .0253295004 + modified: 1 + - boneName: LeftHandIndex1 + humanName: Left Index Proximal + limit: + min: {x: 0, y: -20, z: -50} + max: {x: 0, y: 20, z: 50} + value: {x: .0318517797, y: 0, z: .0159258898} + length: .0398147404 + modified: 1 + - boneName: LeftHandIndex2 + humanName: Left Index Intermediate + limit: + min: {x: 0, y: 0, z: -45} + max: {x: 0, y: 0, z: 45} + value: {x: .0223747883, y: 0, z: .0111873941} + length: .0279684942 + modified: 1 + - boneName: LeftHandIndex3 + humanName: Left Index Distal + limit: + min: {x: 0, y: 0, z: -45} + max: {x: 0, y: 0, z: 45} + value: {x: .0167810898, y: 0, z: .00839054491} + length: .0209763702 + modified: 1 + - boneName: LeftHandMiddle1 + humanName: Left Middle Proximal + limit: + min: {x: 0, y: -7.50000048, z: -50} + max: {x: 0, y: 7.50000048, z: 50} + value: {x: .0354260914, y: 0, z: .0177130457} + length: .0442826301 + modified: 1 + - boneName: LeftHandMiddle2 + humanName: Left Middle Intermediate + limit: + min: {x: 0, y: 0, z: -45} + max: {x: 0, y: 0, z: 45} + value: {x: .0271718036, y: 0, z: .0135859018} + length: .0339647643 + modified: 1 + - boneName: LeftHandMiddle3 + humanName: Left Middle Distal + limit: + min: {x: 0, y: 0, z: -45} + max: {x: 0, y: 0, z: 45} + value: {x: .0203788504, y: 0, z: .0101894252} + length: .0254735723 + modified: 1 + - boneName: LeftHandRing1 + humanName: Left Ring Proximal + limit: + min: {x: 0, y: -7.50000048, z: -50} + max: {x: 0, y: 7.50000048, z: 50} + value: {x: .0345545448, y: 0, z: .0172772724} + length: .0431931987 + modified: 1 + - boneName: LeftHandRing2 + humanName: Left Ring Intermediate + limit: + min: {x: 0, y: 0, z: -45} + max: {x: 0, y: 0, z: 45} + value: {x: .0246683266, y: 0, z: .0123341633} + length: .030835418 + modified: 1 + - boneName: LeftHandRing3 + humanName: Left Ring Distal + limit: + min: {x: 0, y: 0, z: -45} + max: {x: 0, y: 0, z: 45} + value: {x: .0185012426, y: 0, z: .00925062131} + length: .0231265631 + modified: 1 + - boneName: LeftHandPinky1 + humanName: Left Little Proximal + limit: + min: {x: 0, y: -20, z: -50} + max: {x: 0, y: 20, z: 50} + value: {x: .024671508, y: 0, z: .012335754} + length: .0308393929 + modified: 1 + - boneName: LeftHandPinky2 + humanName: Left Little Intermediate + limit: + min: {x: 0, y: 0, z: -45} + max: {x: 0, y: 0, z: 45} + value: {x: .0184510797, y: 0, z: .00922553986} + length: .023063859 + modified: 1 + - boneName: LeftHandPinky3 + humanName: Left Little Distal + limit: + min: {x: 0, y: 0, z: -45} + max: {x: 0, y: 0, z: 45} + value: {x: .0138383117, y: 0, z: .00691915583} + length: .0172978938 + modified: 1 + - boneName: RightHandThumb1 + humanName: Right Thumb Proximal + limit: + min: {x: 0, y: -25, z: -20} + max: {x: 0, y: 25, z: 20} + value: {x: .0232954696, y: 0, z: .0116477348} + length: .0291193463 + modified: 1 + - boneName: RightHandThumb2 + humanName: Right Thumb Intermediate + limit: + min: {x: 0, y: 0, z: -40} + max: {x: 0, y: 0, z: 35} + value: {x: .0270182006, y: 0, z: .0135091003} + length: .0337727591 + modified: 1 + - boneName: RightHandThumb3 + humanName: Right Thumb Distal + limit: + min: {x: 0, y: 0, z: -40} + max: {x: 0, y: 0, z: 35} + value: {x: .0202636477, y: 0, z: .0101318238} + length: .0253295694 + modified: 1 + - boneName: RightHandIndex1 + humanName: Right Index Proximal + limit: + min: {x: 0, y: -20, z: -50} + max: {x: 0, y: 20, z: 50} + value: {x: .0318517946, y: 0, z: .0159258973} + length: .039814759 + modified: 1 + - boneName: RightHandIndex2 + humanName: Right Index Intermediate + limit: + min: {x: 0, y: 0, z: -45} + max: {x: 0, y: 0, z: 45} + value: {x: .0223747734, y: 0, z: .0111873867} + length: .0279684756 + modified: 1 + - boneName: RightHandIndex3 + humanName: Right Index Distal + limit: + min: {x: 0, y: 0, z: -45} + max: {x: 0, y: 0, z: 45} + value: {x: .0167810787, y: 0, z: .00839053933} + length: .0209763572 + modified: 1 + - boneName: RightHandMiddle1 + humanName: Right Middle Proximal + limit: + min: {x: 0, y: -7.50000048, z: -50} + max: {x: 0, y: 7.50000048, z: 50} + value: {x: .0354261473, y: 0, z: .0177130736} + length: .0442827009 + modified: 1 + - boneName: RightHandMiddle2 + humanName: Right Middle Intermediate + limit: + min: {x: 0, y: 0, z: -45} + max: {x: 0, y: 0, z: 45} + value: {x: .0271718968, y: 0, z: .0135859484} + length: .0339648798 + modified: 1 + - boneName: RightHandMiddle3 + humanName: Right Middle Distal + limit: + min: {x: 0, y: 0, z: -45} + max: {x: 0, y: 0, z: 45} + value: {x: .0203789212, y: 0, z: .0101894606} + length: .0254736599 + modified: 1 + - boneName: RightHandRing1 + humanName: Right Ring Proximal + limit: + min: {x: 0, y: -7.50000048, z: -50} + max: {x: 0, y: 7.50000048, z: 50} + value: {x: .0345547274, y: 0, z: .0172773637} + length: .043193426 + modified: 1 + - boneName: RightHandRing2 + humanName: Right Ring Intermediate + limit: + min: {x: 0, y: 0, z: -45} + max: {x: 0, y: 0, z: 45} + value: {x: .0246685483, y: 0, z: .0123342741} + length: .0308356937 + modified: 1 + - boneName: RightHandRing3 + humanName: Right Ring Distal + limit: + min: {x: 0, y: 0, z: -45} + max: {x: 0, y: 0, z: 45} + value: {x: .0185014084, y: 0, z: .0092507042} + length: .0231267698 + modified: 1 + - boneName: RightHandPinky1 + humanName: Right Little Proximal + limit: + min: {x: 0, y: -20, z: -50} + max: {x: 0, y: 20, z: 50} + value: {x: .0246716533, y: 0, z: .0123358266} + length: .0308395755 + modified: 1 + - boneName: RightHandPinky2 + humanName: Right Little Intermediate + limit: + min: {x: 0, y: 0, z: -45} + max: {x: 0, y: 0, z: 45} + value: {x: .018451266, y: 0, z: .009225633} + length: .0230640918 + modified: 1 + - boneName: RightHandPinky3 + humanName: Right Little Distal + limit: + min: {x: 0, y: 0, z: -45} + max: {x: 0, y: 0, z: 45} + value: {x: .0138384514, y: 0, z: .00691922568} + length: .0172980689 + modified: 1 + skeleton: + - name: Dude + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: Reference + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: Hips + position: {x: 0, y: .963793993, z: -.0235067774} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: LeftUpLeg + position: {x: -.0754494965, y: -.0456640124, z: 0} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: LeftLeg + position: {x: -.0205505043, y: -.409129977, z: .00717136636} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: LeftFoot + position: {x: -.00515300781, y: -.423155904, z: -.0120320898} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: LeftToes + position: {x: -.00748699158, y: -.0731672645, z: .145427138} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: RightUpLeg + position: {x: .0754495338, y: -.0456640124, z: 0} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: RightLeg + position: {x: .0205504671, y: -.409129977, z: .00717136636} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: RightFoot + position: {x: .00515300035, y: -.423155904, z: -.0120320898} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: RightToes + position: {x: .00748699903, y: -.0731672645, z: .14542751} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: Spine + position: {x: 0, y: .0922632217, z: .0157713331} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: Chest + position: {x: 0, y: .162540197, z: .02185072} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: LeftShoulder + position: {x: -.0382435732, y: .192178011, z: -.017063085} + rotation: {x: -.0140067078, y: -.0595068112, z: .228689864, w: .971577883} + scale: {x: 1.00000024, y: 1, z: 1} + transformModified: 1 + - name: LeftArm + position: {x: -.083574675, y: .0360975936, z: -1.50734021e-08} + rotation: {x: .00946438964, y: .0436916873, z: -.223042384, w: .973783076} + scale: {x: 1, y: 1, z: 1.00000012} + transformModified: 1 + - name: LeftForeArm + position: {x: -.254049391, y: 4.70318128e-07, z: -2.19768759e-09} + rotation: {x: -.000616520061, y: .0220786203, z: -.0160702374, w: .999626815} + scale: {x: .99999994, y: 1, z: .999999881} + transformModified: 1 + - name: LeftHand + position: {x: -.246389359, y: -1.89769892e-07, z: -5.73217829e-09} + rotation: {x: 2.86021179e-10, y: -9.59063384e-10, z: -.0214135442, w: .999770641} + scale: {x: .99999994, y: 1, z: 1} + transformModified: 1 + - name: LeftHandIndex1 + position: {x: -.0751256943, y: -.0078413263, z: .0326526687} + rotation: {x: -.00211891951, y: .0802574232, z: .0175381787, w: .996617556} + scale: {x: 1, y: 1, z: .99999994} + transformModified: 1 + - name: LeftHandIndex2 + position: {x: -.0397970602, y: 4.9526192e-05, z: .00118574023} + rotation: {x: .000501931063, y: .0154708987, z: .040414121, w: .999063075} + scale: {x: 1.00000024, y: 1.00000024, z: .99999994} + transformModified: 1 + - name: LeftHandIndex3 + position: {x: -.0279685091, y: -1.79063633e-07, z: -9.18437095e-08} + rotation: {x: 4.33656722e-10, y: -1.75894304e-08, z: -1.0378705e-08, w: .99999994} + scale: {x: 1, y: 1.00000012, z: .999999881} + transformModified: 1 + - name: LeftHandMiddle1 + position: {x: -.0760235488, y: -.00188508059, z: .0101412414} + rotation: {x: -.000768872735, y: .0333210714, z: .0209075287, w: .999225616} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: LeftHandMiddle2 + position: {x: -.0442805924, y: 4.51253936e-06, z: -.000425422273} + rotation: {x: -.00136214169, y: -.0191537682, z: .0378897563, w: .999097347} + scale: {x: 1, y: 1.00000012, z: 1} + transformModified: 1 + - name: LeftHandMiddle3 + position: {x: -.0339647792, y: 1.61085282e-07, z: 5.41929612e-09} + rotation: {x: 6.13220641e-10, y: -4.12468948e-09, z: 1.82216331e-09, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: LeftHandPinky1 + position: {x: -.0656598732, y: -.00782526191, z: -.0322512463} + rotation: {x: -.000913206779, y: .0121623203, z: .0212220494, w: .999700308} + scale: {x: 1.00000012, y: 1, z: .999999881} + transformModified: 1 + - name: LeftHandPinky2 + position: {x: -.0308053754, y: -3.11739277e-05, z: -.00144808914} + rotation: {x: -.000170628555, y: -.0096613653, z: -.00536239706, w: .999938905} + scale: {x: 1, y: .999999821, z: 1.00000012} + transformModified: 1 + - name: LeftHandPinky3 + position: {x: -.0230638776, y: -6.67785343e-06, z: 6.90349244e-09} + rotation: {x: -8.51873905e-10, y: -9.4255892e-09, z: -1.31619666e-08, w: .99999994} + scale: {x: 1, y: 1, z: .99999994} + transformModified: 1 + - name: LeftHandRing1 + position: {x: -.0703021139, y: -.00374528999, z: -.0114117898} + rotation: {x: -.000324091874, y: .0115982238, z: .0247380193, w: .999626577} + scale: {x: 1, y: 1.00000024, z: .99999994} + transformModified: 1 + - name: LeftHandRing2 + position: {x: -.0431353189, y: -2.08693382e-05, z: -.00223518023} + rotation: {x: -.00120324548, y: -.0231137574, z: .040979635, w: .99889183} + scale: {x: .999999881, y: .999999702, z: .99999994} + transformModified: 1 + - name: LeftHandRing3 + position: {x: -.0308354236, y: -1.56879963e-07, z: -1.40963357e-08} + rotation: {x: 4.93614594e-10, y: -1.5807432e-09, z: -5.78796033e-09, w: .99999994} + scale: {x: 1, y: .99999994, z: .999999881} + transformModified: 1 + - name: LeftHandThumb1 + position: {x: -.0142313093, y: -.012377888, z: .0255316831} + rotation: {x: -.0123126386, y: -.0085253641, z: .0125855142, w: .999808609} + scale: {x: 1, y: 1, z: 1.00000012} + transformModified: 1 + - name: LeftHandThumb2 + position: {x: -.0163739249, y: -.00528992061, z: .0234914143} + rotation: {x: -.0260628555, y: .0966900289, z: .00360696716, w: .994966686} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: LeftHandThumb3 + position: {x: -.0254599936, y: -.00763992406, z: .020832995} + rotation: {x: 4.41585328e-08, y: 1.10925613e-09, z: -7.80932541e-10, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: Neck + position: {x: 0, y: .235723972, z: -.0324132554} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: Head + position: {x: 0, y: .106355786, z: .0113267824} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: Jaw + position: {x: 0, y: .0111267567, z: .0103275422} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: LeftEye + position: {x: -.0208482333, y: .0825027227, z: .0554274321} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: RightEye + position: {x: .020849999, y: .0825027227, z: .0554273948} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: RightShoulder + position: {x: .038328547, y: .192177057, z: -.0170630887} + rotation: {x: .228671983, y: .971582115, z: -.0140056778, w: -.05950737} + scale: {x: 1, y: 1.00000012, z: .99999994} + transformModified: 1 + - name: RightArm + position: {x: -.0835753977, y: .0360959396, z: -4.69747263e-08} + rotation: {x: -.211052075, y: -.974394023, z: .0173116978, w: -.0755877271} + scale: {x: .999999821, y: 1.00000012, z: .999999702} + transformModified: 1 + - name: RightForeArm + position: {x: .253428489, y: .00601093518, z: -.0167045332} + rotation: {x: -.000616519072, y: .0220786221, z: -.0160702337, w: .999626815} + scale: {x: .99999994, y: .999999881, z: .99999994} + transformModified: 1 + - name: RightHand + position: {x: .245373741, y: .0216420237, z: .00555047346} + rotation: {x: 5.43189438e-10, y: 3.12476184e-10, z: .0214136969, w: .999770641} + scale: {x: 1, y: 1, z: 1.00000012} + transformModified: 1 + - name: RightHandIndex1 + position: {x: .0747697875, y: -.00124282821, z: .0343445241} + rotation: {x: -.00211892067, y: .0802574307, z: .0175381824, w: .996617556} + scale: {x: 1.00000012, y: 1, z: .99999994} + transformModified: 1 + - name: RightHandIndex2 + position: {x: .037058223, y: .000725421763, z: .0145388739} + rotation: {x: -.0033212963, y: .0159312561, z: .060620904, w: .998028159} + scale: {x: 1, y: .99999994, z: 1} + transformModified: 1 + - name: RightHandIndex3 + position: {x: .0252250955, y: -.00496621709, z: .0110121826} + rotation: {x: 2.16179208e-09, y: 1.06850013e-08, z: -8.50230109e-09, w: .99999994} + scale: {x: 1, y: 1.00000012, z: 1.00000012} + transformModified: 1 + - name: RightHandMiddle1 + position: {x: .0756474286, y: .00479083089, z: .0118531957} + rotation: {x: -.00076887355, y: .0333210677, z: .0209075324, w: .999225616} + scale: {x: 1.00000012, y: .999999821, z: .999999881} + transformModified: 1 + - name: RightHandMiddle2 + position: {x: .0438093096, y: .000194165463, z: .00645493949} + rotation: {x: -.0041302545, y: -.0335112214, z: .0761189237, w: .996526837} + scale: {x: 1, y: .999999881, z: 1.00000012} + transformModified: 1 + - name: RightHandMiddle3 + position: {x: .0330725648, y: -.00754737761, z: .00168985641} + rotation: {x: -3.7425496e-10, y: -4.22918101e-09, z: -1.05837286e-08, w: .99999994} + scale: {x: 1, y: .999999881, z: 1} + transformModified: 1 + - name: RightHandPinky1 + position: {x: .0668031499, y: -.00199452811, z: -.0307561476} + rotation: {x: .00317558926, y: -.192005113, z: .045110438, w: .980351448} + scale: {x: 1.00000024, y: 1, z: .99999994} + transformModified: 1 + - name: RightHandPinky2 + position: {x: .0285309609, y: -.00139694544, z: -.0116238492} + rotation: {x: -.000170628467, y: -.00966134015, z: -.00536239473, w: .999938905} + scale: {x: .999999881, y: 1, z: .99999994} + transformModified: 1 + - name: RightHandPinky3 + position: {x: .0214269403, y: -.000553725113, z: -.00851663202} + rotation: {x: -8.53474014e-10, y: 1.63788556e-08, z: -1.38467984e-08, w: .99999994} + scale: {x: 1, y: 1, z: 1.00000012} + transformModified: 1 + - name: RightHandRing1 + position: {x: .070598565, y: .00245756772, z: -.00982147083} + rotation: {x: .000710569788, y: -.054343082, z: .0349452496, w: .99791038} + scale: {x: 1.00000012, y: 1, z: 1} + transformModified: 1 + - name: RightHandRing2 + position: {x: .0428872742, y: -.0013759057, z: -.00494588772} + rotation: {x: .000482838717, y: -.0212902706, z: .0698495656, w: .997330129} + scale: {x: 1, y: 1, z: 1.00000024} + transformModified: 1 + - name: RightHandRing3 + position: {x: .0295008179, y: -.00769269653, z: -.00462226616} + rotation: {x: -2.61377653e-09, y: -8.06309508e-09, z: -6.11845863e-09, w: .99999994} + scale: {x: 1, y: 1, z: 1.00000012} + transformModified: 1 + - name: RightHandThumb1 + position: {x: .014684936, y: -.0111049525, z: .025858108} + rotation: {x: -.0128134964, y: -.00325657125, z: .031457644, w: .999417603} + scale: {x: 1.00000012, y: 1, z: 1} + transformModified: 1 + - name: RightHandThumb2 + position: {x: .0163741205, y: -.00528976135, z: .0234913807} + rotation: {x: -.0260671675, y: -.0966875851, z: -.00360274338, w: .994966805} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: RightHandThumb3 + position: {x: .0254600029, y: -.00764030218, z: .0208330136} + rotation: {x: 1.31814044e-08, y: 1.05642828e-09, z: -2.01141503e-09, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + armTwist: .5 + foreArmTwist: .5 + upperLegTwist: .5 + legTwist: .5 + armStretch: .0500000007 + legStretch: .0500000007 + feetSpacing: 0 + rootMotionBoneName: + lastHumanDescriptionAvatarSource: {fileID: 9000000, guid: e194d39a231e29a489a36758f9fb175e, + type: 3} + animationType: 3 + additionalBone: 1 + userData: diff --git a/Assets/Photon Unity Networking/Demos/Shared Assets/Animations/JogBackward_NtrlFaceFwd.fbx b/Assets/Photon Unity Networking/Demos/Shared Assets/Animations/JogBackward_NtrlFaceFwd.fbx new file mode 100644 index 0000000..eee0217 Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/Shared Assets/Animations/JogBackward_NtrlFaceFwd.fbx differ diff --git a/Assets/Photon Unity Networking/Demos/Shared Assets/Animations/JogBackward_NtrlFaceFwd.fbx.meta b/Assets/Photon Unity Networking/Demos/Shared Assets/Animations/JogBackward_NtrlFaceFwd.fbx.meta new file mode 100644 index 0000000..472139f --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/Shared Assets/Animations/JogBackward_NtrlFaceFwd.fbx.meta @@ -0,0 +1,957 @@ +fileFormatVersion: 2 +guid: 4c299da8335ebd746bc4ade9f15d7d93 +ModelImporter: + serializedVersion: 16 + fileIDToRecycleName: + 100000: //RootNode + 100002: Chest + 100004: Head + 100006: Hips + 100008: Jaw + 100010: JawEND + 100012: LeftArm + 100014: LeftCheek + 100016: LeftEye + 100018: LeftEyelidLower + 100020: LeftEyelidUpper + 100022: LeftFoot + 100024: LeftForeArm + 100026: LeftHand + 100028: LeftHandIndex1 + 100030: LeftHandIndex2 + 100032: LeftHandIndex3 + 100034: LeftHandMiddle1 + 100036: LeftHandMiddle2 + 100038: LeftHandMiddle3 + 100040: LeftHandPinky1 + 100042: LeftHandPinky2 + 100044: LeftHandPinky3 + 100046: LeftHandRing1 + 100048: LeftHandRing2 + 100050: LeftHandRing3 + 100052: LeftHandThumb1 + 100054: LeftHandThumb2 + 100056: LeftHandThumb3 + 100058: LeftInnerBrow + 100060: LeftIOuterBrow + 100062: LeftLeg + 100064: LeftLipCorner + 100066: LeftLipLower + 100068: LeftLipUpper + 100070: LeftNostril + 100072: LeftShoulder + 100074: LeftToes + 100076: LeftUpLeg + 100078: Neck + 100080: Pivot + 100082: Reference + 100084: RightArm + 100086: RightCheek + 100088: RightEye + 100090: RightEyelidLower + 100092: RightEyelidUpper + 100094: RightFoot + 100096: RightForeArm + 100098: RightHand + 100100: RightHandIndex1 + 100102: RightHandIndex2 + 100104: RightHandIndex3 + 100106: RightHandMiddle1 + 100108: RightHandMiddle2 + 100110: RightHandMiddle3 + 100112: RightHandPinky1 + 100114: RightHandPinky2 + 100116: RightHandPinky3 + 100118: RightHandRing1 + 100120: RightHandRing2 + 100122: RightHandRing3 + 100124: RightHandThumb1 + 100126: RightHandThumb2 + 100128: RightHandThumb3 + 100130: RightInnerBrow + 100132: RightIOuterBrow + 100134: RightLeg + 100136: RightLipCorner + 100138: RightLipLower + 100140: RightLipUpper + 100142: RightNostril + 100144: RightShoulder + 100146: RightToes + 100148: RightUpLeg + 100150: Root + 100152: Spine + 100154: TongueBack + 100156: TongueTip + 400000: //RootNode + 400002: Chest + 400004: Head + 400006: Hips + 400008: Jaw + 400010: JawEND + 400012: LeftArm + 400014: LeftCheek + 400016: LeftEye + 400018: LeftEyelidLower + 400020: LeftEyelidUpper + 400022: LeftFoot + 400024: LeftForeArm + 400026: LeftHand + 400028: LeftHandIndex1 + 400030: LeftHandIndex2 + 400032: LeftHandIndex3 + 400034: LeftHandMiddle1 + 400036: LeftHandMiddle2 + 400038: LeftHandMiddle3 + 400040: LeftHandPinky1 + 400042: LeftHandPinky2 + 400044: LeftHandPinky3 + 400046: LeftHandRing1 + 400048: LeftHandRing2 + 400050: LeftHandRing3 + 400052: LeftHandThumb1 + 400054: LeftHandThumb2 + 400056: LeftHandThumb3 + 400058: LeftInnerBrow + 400060: LeftIOuterBrow + 400062: LeftLeg + 400064: LeftLipCorner + 400066: LeftLipLower + 400068: LeftLipUpper + 400070: LeftNostril + 400072: LeftShoulder + 400074: LeftToes + 400076: LeftUpLeg + 400078: Neck + 400080: Pivot + 400082: Reference + 400084: RightArm + 400086: RightCheek + 400088: RightEye + 400090: RightEyelidLower + 400092: RightEyelidUpper + 400094: RightFoot + 400096: RightForeArm + 400098: RightHand + 400100: RightHandIndex1 + 400102: RightHandIndex2 + 400104: RightHandIndex3 + 400106: RightHandMiddle1 + 400108: RightHandMiddle2 + 400110: RightHandMiddle3 + 400112: RightHandPinky1 + 400114: RightHandPinky2 + 400116: RightHandPinky3 + 400118: RightHandRing1 + 400120: RightHandRing2 + 400122: RightHandRing3 + 400124: RightHandThumb1 + 400126: RightHandThumb2 + 400128: RightHandThumb3 + 400130: RightInnerBrow + 400132: RightIOuterBrow + 400134: RightLeg + 400136: RightLipCorner + 400138: RightLipLower + 400140: RightLipUpper + 400142: RightNostril + 400144: RightShoulder + 400146: RightToes + 400148: RightUpLeg + 400150: Root + 400152: Spine + 400154: TongueBack + 400156: TongueTip + 7400000: JogBackward_NtrlFaceFwd + 9500000: //RootNode + materials: + importMaterials: 1 + materialName: 0 + materialSearch: 1 + animations: + legacyGenerateAnimations: 4 + bakeSimulation: 0 + optimizeGameObjects: 0 + animationCompression: 1 + animationRotationError: .5 + animationPositionError: .5 + animationScaleError: .5 + animationWrapMode: 0 + extraExposedTransformPaths: [] + clipAnimations: + - serializedVersion: 16 + name: JogBackward_NtrlFaceFwd + takeName: _13_a_U1_M_P_JogBackward_NtrlFaceFwd__Fb_p0_No_0_PJ_2 + firstFrame: 89 + lastFrame: 108 + wrapMode: 0 + orientationOffsetY: 0 + level: 0 + cycleOffset: 0 + loop: 0 + loopTime: 1 + loopBlend: 0 + loopBlendOrientation: 0 + loopBlendPositionY: 0 + loopBlendPositionXZ: 0 + keepOriginalOrientation: 0 + keepOriginalPositionY: 1 + keepOriginalPositionXZ: 0 + heightFromFeet: 0 + mirror: 0 + bodyMask: 01000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000 + curves: [] + events: [] + transformMask: [] + maskType: 0 + maskSource: {instanceID: 0} + isReadable: 1 + meshes: + lODScreenPercentages: [] + globalScale: .00999999978 + meshCompression: 0 + addColliders: 0 + importBlendShapes: 1 + swapUVChannels: 0 + generateSecondaryUV: 0 + useFileUnits: 1 + optimizeMeshForGPU: 1 + weldVertices: 1 + secondaryUVAngleDistortion: 8 + secondaryUVAreaDistortion: 15.000001 + secondaryUVHardAngle: 88 + secondaryUVPackMargin: 4 + tangentSpace: + normalSmoothAngle: 60 + splitTangentsAcrossUV: 1 + normalImportMode: 0 + tangentImportMode: 1 + importAnimation: 1 + copyAvatar: 1 + humanDescription: + human: + - boneName: Hips + humanName: Hips + limit: + min: {x: -40, y: -40, z: -40} + max: {x: 40, y: 40, z: 40} + value: {x: .0748811588, y: 0, z: .0374405794} + length: .0936014801 + modified: 1 + - boneName: LeftUpLeg + humanName: LeftUpperLeg + limit: + min: {x: -60.0000038, y: -60.0000038, z: -90} + max: {x: 60.0000038, y: 60.0000038, z: 50} + value: {x: .327766716, y: 0, z: .163883358} + length: .40970853 + modified: 1 + - boneName: RightUpLeg + humanName: RightUpperLeg + limit: + min: {x: -60.0000038, y: -60.0000038, z: -90} + max: {x: 60.0000038, y: 60.0000038, z: 50} + value: {x: .327766716, y: 0, z: .163883358} + length: .40970853 + modified: 1 + - boneName: LeftLeg + humanName: LeftLowerLeg + limit: + min: {x: -90, y: 0, z: -80} + max: {x: 90, y: 0, z: 80} + value: {x: .338686436, y: 0, z: .169343218} + length: .423358172 + modified: 1 + - boneName: RightLeg + humanName: RightLowerLeg + limit: + min: {x: -90, y: 0, z: -80} + max: {x: 90, y: 0, z: 80} + value: {x: .338686436, y: 0, z: .169343218} + length: .423358172 + modified: 1 + - boneName: LeftFoot + humanName: LeftFoot + limit: + min: {x: 0, y: -30.0000019, z: -50} + max: {x: 0, y: 30.0000019, z: 50} + value: {x: .0686753467, y: 0, z: .0343376733} + length: .0858442187 + modified: 1 + - boneName: RightFoot + humanName: RightFoot + limit: + min: {x: 0, y: -30.0000019, z: -50} + max: {x: 0, y: 30.0000019, z: 50} + value: {x: .0686753467, y: 0, z: .0343376733} + length: .0858442187 + modified: 1 + - boneName: Spine + humanName: Spine + limit: + min: {x: -40, y: -40, z: -40} + max: {x: 40, y: 40, z: 40} + value: {x: .131201819, y: 0, z: .0656009093} + length: .164002344 + modified: 1 + - boneName: Chest + humanName: Chest + limit: + min: {x: -40, y: -40, z: -40} + max: {x: 40, y: 40, z: 40} + value: {x: .190353557, y: 0, z: .0951767787} + length: .237942025 + modified: 1 + - boneName: Neck + humanName: Neck + limit: + min: {x: -40, y: -40, z: -40} + max: {x: 40, y: 40, z: 40} + value: {x: .0855657607, y: 0, z: .0427828804} + length: .106957234 + modified: 1 + - boneName: Head + humanName: Head + limit: + min: {x: -40, y: -40, z: -40} + max: {x: 40, y: 40, z: 40} + value: {x: .0855657607, y: 0, z: .0427828804} + length: .106957234 + modified: 1 + - boneName: LeftShoulder + humanName: LeftShoulder + limit: + min: {x: 0, y: -15.000001, z: -15.000001} + max: {x: 0, y: 15.000001, z: 30.0000019} + value: {x: .072829701, y: 0, z: .0364148505} + length: .0910371616 + modified: 1 + - boneName: RightShoulder + humanName: RightShoulder + limit: + min: {x: 0, y: -15.000001, z: -15.000001} + max: {x: 0, y: 15.000001, z: 30.0000019} + value: {x: .072829701, y: 0, z: .0364148505} + length: .0910371616 + modified: 1 + - boneName: LeftArm + humanName: LeftUpperArm + limit: + min: {x: -90, y: -100, z: -60.0000038} + max: {x: 90, y: 100, z: 100} + value: {x: .203239605, y: 0, z: .101619802} + length: .254049569 + modified: 1 + - boneName: RightArm + humanName: RightUpperArm + limit: + min: {x: -90, y: -100, z: -60.0000038} + max: {x: 90, y: 100, z: 100} + value: {x: .203239575, y: 0, z: .101619788} + length: .25404954 + modified: 1 + - boneName: LeftForeArm + humanName: LeftLowerArm + limit: + min: {x: -90, y: 0, z: -80} + max: {x: 90, y: 0, z: 80} + value: {x: .197111532, y: 0, z: .098555766} + length: .246389478 + modified: 1 + - boneName: RightForeArm + humanName: RightLowerArm + limit: + min: {x: -90, y: 0, z: -80} + max: {x: 90, y: 0, z: 80} + value: {x: .197110936, y: 0, z: .098555468} + length: .246388748 + modified: 1 + - boneName: LeftHand + humanName: LeftHand + limit: + min: {x: 0, y: -40, z: -80} + max: {x: 0, y: 40, z: 80} + value: {x: .098555766, y: 0, z: .049277883} + length: .123194739 + modified: 1 + - boneName: RightHand + humanName: RightHand + limit: + min: {x: 0, y: -40, z: -80} + max: {x: 0, y: 40, z: 80} + value: {x: .098555468, y: 0, z: .049277734} + length: .123194374 + modified: 1 + - boneName: LeftToes + humanName: LeftToes + limit: + min: {x: 0, y: 0, z: -50} + max: {x: 0, y: 0, z: 50} + value: {x: .0651871562, y: 0, z: .0325935781} + length: .0814839825 + modified: 1 + - boneName: RightToes + humanName: RightToes + limit: + min: {x: 0, y: 0, z: -50} + max: {x: 0, y: 0, z: 50} + value: {x: .0651872903, y: 0, z: .0325936452} + length: .0814841464 + modified: 1 + - boneName: LeftEye + humanName: LeftEye + limit: + min: {x: 0, y: -20, z: -10} + max: {x: 0, y: 20, z: 15.000001} + value: {x: .0799999759, y: 0, z: .0399999879} + length: .100000001 + modified: 1 + - boneName: RightEye + humanName: RightEye + limit: + min: {x: 0, y: -20, z: -10} + max: {x: 0, y: 20, z: 15.000001} + value: {x: .0799999759, y: 0, z: .0399999879} + length: .100000001 + modified: 1 + - boneName: Jaw + humanName: Jaw + limit: + min: {x: 0, y: -10, z: -10} + max: {x: 0, y: 10, z: 10} + value: {x: .0799999759, y: 0, z: .0399999879} + length: .100000001 + modified: 1 + - boneName: LeftHandThumb1 + humanName: Left Thumb Proximal + limit: + min: {x: 0, y: -25, z: -20} + max: {x: 0, y: 25, z: 20} + value: {x: .0232954584, y: 0, z: .0116477292} + length: .0291193314 + modified: 1 + - boneName: LeftHandThumb2 + humanName: Left Thumb Intermediate + limit: + min: {x: 0, y: 0, z: -40} + max: {x: 0, y: 0, z: 35} + value: {x: .0270181261, y: 0, z: .0135090631} + length: .033772666 + modified: 1 + - boneName: LeftHandThumb3 + humanName: Left Thumb Distal + limit: + min: {x: 0, y: 0, z: -40} + max: {x: 0, y: 0, z: 35} + value: {x: .0202635936, y: 0, z: .0101317968} + length: .0253295004 + modified: 1 + - boneName: LeftHandIndex1 + humanName: Left Index Proximal + limit: + min: {x: 0, y: -20, z: -50} + max: {x: 0, y: 20, z: 50} + value: {x: .0318517797, y: 0, z: .0159258898} + length: .0398147404 + modified: 1 + - boneName: LeftHandIndex2 + humanName: Left Index Intermediate + limit: + min: {x: 0, y: 0, z: -45} + max: {x: 0, y: 0, z: 45} + value: {x: .0223747883, y: 0, z: .0111873941} + length: .0279684942 + modified: 1 + - boneName: LeftHandIndex3 + humanName: Left Index Distal + limit: + min: {x: 0, y: 0, z: -45} + max: {x: 0, y: 0, z: 45} + value: {x: .0167810898, y: 0, z: .00839054491} + length: .0209763702 + modified: 1 + - boneName: LeftHandMiddle1 + humanName: Left Middle Proximal + limit: + min: {x: 0, y: -7.50000048, z: -50} + max: {x: 0, y: 7.50000048, z: 50} + value: {x: .0354260914, y: 0, z: .0177130457} + length: .0442826301 + modified: 1 + - boneName: LeftHandMiddle2 + humanName: Left Middle Intermediate + limit: + min: {x: 0, y: 0, z: -45} + max: {x: 0, y: 0, z: 45} + value: {x: .0271718036, y: 0, z: .0135859018} + length: .0339647643 + modified: 1 + - boneName: LeftHandMiddle3 + humanName: Left Middle Distal + limit: + min: {x: 0, y: 0, z: -45} + max: {x: 0, y: 0, z: 45} + value: {x: .0203788504, y: 0, z: .0101894252} + length: .0254735723 + modified: 1 + - boneName: LeftHandRing1 + humanName: Left Ring Proximal + limit: + min: {x: 0, y: -7.50000048, z: -50} + max: {x: 0, y: 7.50000048, z: 50} + value: {x: .0345545448, y: 0, z: .0172772724} + length: .0431931987 + modified: 1 + - boneName: LeftHandRing2 + humanName: Left Ring Intermediate + limit: + min: {x: 0, y: 0, z: -45} + max: {x: 0, y: 0, z: 45} + value: {x: .0246683266, y: 0, z: .0123341633} + length: .030835418 + modified: 1 + - boneName: LeftHandRing3 + humanName: Left Ring Distal + limit: + min: {x: 0, y: 0, z: -45} + max: {x: 0, y: 0, z: 45} + value: {x: .0185012426, y: 0, z: .00925062131} + length: .0231265631 + modified: 1 + - boneName: LeftHandPinky1 + humanName: Left Little Proximal + limit: + min: {x: 0, y: -20, z: -50} + max: {x: 0, y: 20, z: 50} + value: {x: .024671508, y: 0, z: .012335754} + length: .0308393929 + modified: 1 + - boneName: LeftHandPinky2 + humanName: Left Little Intermediate + limit: + min: {x: 0, y: 0, z: -45} + max: {x: 0, y: 0, z: 45} + value: {x: .0184510797, y: 0, z: .00922553986} + length: .023063859 + modified: 1 + - boneName: LeftHandPinky3 + humanName: Left Little Distal + limit: + min: {x: 0, y: 0, z: -45} + max: {x: 0, y: 0, z: 45} + value: {x: .0138383117, y: 0, z: .00691915583} + length: .0172978938 + modified: 1 + - boneName: RightHandThumb1 + humanName: Right Thumb Proximal + limit: + min: {x: 0, y: -25, z: -20} + max: {x: 0, y: 25, z: 20} + value: {x: .0232954752, y: 0, z: .0116477376} + length: .0291193537 + modified: 1 + - boneName: RightHandThumb2 + humanName: Right Thumb Intermediate + limit: + min: {x: 0, y: 0, z: -40} + max: {x: 0, y: 0, z: 35} + value: {x: .0270181969, y: 0, z: .0135090984} + length: .0337727554 + modified: 1 + - boneName: RightHandThumb3 + humanName: Right Thumb Distal + limit: + min: {x: 0, y: 0, z: -40} + max: {x: 0, y: 0, z: 35} + value: {x: .0202636477, y: 0, z: .0101318238} + length: .0253295675 + modified: 1 + - boneName: RightHandIndex1 + humanName: Right Index Proximal + limit: + min: {x: 0, y: -20, z: -50} + max: {x: 0, y: 20, z: 50} + value: {x: .0318517946, y: 0, z: .0159258973} + length: .039814759 + modified: 1 + - boneName: RightHandIndex2 + humanName: Right Index Intermediate + limit: + min: {x: 0, y: 0, z: -45} + max: {x: 0, y: 0, z: 45} + value: {x: .0223747734, y: 0, z: .0111873867} + length: .0279684756 + modified: 1 + - boneName: RightHandIndex3 + humanName: Right Index Distal + limit: + min: {x: 0, y: 0, z: -45} + max: {x: 0, y: 0, z: 45} + value: {x: .0167810787, y: 0, z: .00839053933} + length: .0209763572 + modified: 1 + - boneName: RightHandMiddle1 + humanName: Right Middle Proximal + limit: + min: {x: 0, y: -7.50000048, z: -50} + max: {x: 0, y: 7.50000048, z: 50} + value: {x: .0354261473, y: 0, z: .0177130736} + length: .0442827009 + modified: 1 + - boneName: RightHandMiddle2 + humanName: Right Middle Intermediate + limit: + min: {x: 0, y: 0, z: -45} + max: {x: 0, y: 0, z: 45} + value: {x: .0271718968, y: 0, z: .0135859484} + length: .0339648798 + modified: 1 + - boneName: RightHandMiddle3 + humanName: Right Middle Distal + limit: + min: {x: 0, y: 0, z: -45} + max: {x: 0, y: 0, z: 45} + value: {x: .0203789212, y: 0, z: .0101894606} + length: .0254736599 + modified: 1 + - boneName: RightHandRing1 + humanName: Right Ring Proximal + limit: + min: {x: 0, y: -7.50000048, z: -50} + max: {x: 0, y: 7.50000048, z: 50} + value: {x: .0345547274, y: 0, z: .0172773637} + length: .043193426 + modified: 1 + - boneName: RightHandRing2 + humanName: Right Ring Intermediate + limit: + min: {x: 0, y: 0, z: -45} + max: {x: 0, y: 0, z: 45} + value: {x: .0246685483, y: 0, z: .0123342741} + length: .0308356937 + modified: 1 + - boneName: RightHandRing3 + humanName: Right Ring Distal + limit: + min: {x: 0, y: 0, z: -45} + max: {x: 0, y: 0, z: 45} + value: {x: .0185014084, y: 0, z: .0092507042} + length: .0231267698 + modified: 1 + - boneName: RightHandPinky1 + humanName: Right Little Proximal + limit: + min: {x: 0, y: -20, z: -50} + max: {x: 0, y: 20, z: 50} + value: {x: .0246716533, y: 0, z: .0123358266} + length: .0308395755 + modified: 1 + - boneName: RightHandPinky2 + humanName: Right Little Intermediate + limit: + min: {x: 0, y: 0, z: -45} + max: {x: 0, y: 0, z: 45} + value: {x: .018451266, y: 0, z: .009225633} + length: .0230640918 + modified: 1 + - boneName: RightHandPinky3 + humanName: Right Little Distal + limit: + min: {x: 0, y: 0, z: -45} + max: {x: 0, y: 0, z: 45} + value: {x: .0138384514, y: 0, z: .00691922568} + length: .0172980689 + modified: 1 + skeleton: + - name: DefaultAvatar + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: Reference + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: -0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: Hips + position: {x: 0, y: .963793993, z: -.0235067774} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: LeftUpLeg + position: {x: -.0754494965, y: -.0456640124, z: 0} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: LeftLeg + position: {x: -.0205505043, y: -.409129977, z: .00717136636} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: LeftFoot + position: {x: -.00515300781, y: -.423155904, z: -.0120320898} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: LeftToes + position: {x: -.00748699158, y: -.0731672645, z: .145427138} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: RightUpLeg + position: {x: .0754495338, y: -.0456640124, z: 0} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: RightLeg + position: {x: .0205504671, y: -.409129977, z: .00717136636} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: RightFoot + position: {x: .00515300035, y: -.423155904, z: -.0120320898} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: RightToes + position: {x: .00748699903, y: -.0731672645, z: .14542751} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: Spine + position: {x: 0, y: .0922632217, z: .0157713331} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: Chest + position: {x: 0, y: .162540197, z: .02185072} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: LeftShoulder + position: {x: -.0382435732, y: .192178011, z: -.017063085} + rotation: {x: -.0140067078, y: -.0595068112, z: .228689864, w: .971577883} + scale: {x: 1.00000024, y: 1, z: 1} + transformModified: 1 + - name: LeftArm + position: {x: -.083574675, y: .0360975936, z: -1.50734021e-08} + rotation: {x: .00946438964, y: .0436916873, z: -.223042384, w: .973783076} + scale: {x: 1, y: 1, z: 1.00000012} + transformModified: 1 + - name: LeftForeArm + position: {x: -.254049391, y: 4.70318128e-07, z: -2.19768759e-09} + rotation: {x: -.000616520119, y: .0220786221, z: -.0160702392, w: .999626875} + scale: {x: .99999994, y: 1, z: .999999881} + transformModified: 1 + - name: LeftHand + position: {x: -.246389359, y: -1.89769892e-07, z: -5.73217829e-09} + rotation: {x: 2.86021207e-10, y: -9.59063495e-10, z: -.0214135461, w: .999770701} + scale: {x: .99999994, y: 1, z: 1} + transformModified: 1 + - name: LeftHandIndex1 + position: {x: -.0751256943, y: -.0078413263, z: .0326526687} + rotation: {x: -.00211891974, y: .0802574307, z: .0175381806, w: .996617615} + scale: {x: 1, y: 1, z: .99999994} + transformModified: 1 + - name: LeftHandIndex2 + position: {x: -.0397970602, y: 4.9526192e-05, z: .00118574023} + rotation: {x: .000501931063, y: .0154708987, z: .040414121, w: .999063075} + scale: {x: 1.00000024, y: 1.00000024, z: .99999994} + transformModified: 1 + - name: LeftHandIndex3 + position: {x: -.0279685091, y: -1.79063633e-07, z: -9.18437095e-08} + rotation: {x: 4.33656722e-10, y: -1.75894304e-08, z: -1.0378705e-08, w: .99999994} + scale: {x: 1, y: 1.00000012, z: .999999881} + transformModified: 1 + - name: LeftHandMiddle1 + position: {x: -.0760235488, y: -.00188508059, z: .0101412414} + rotation: {x: -.000768872793, y: .0333210751, z: .0209075306, w: .999225676} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: LeftHandMiddle2 + position: {x: -.0442805924, y: 4.51253936e-06, z: -.000425422273} + rotation: {x: -.0013621418, y: -.0191537701, z: .03788976, w: .999097407} + scale: {x: 1, y: 1.00000012, z: 1} + transformModified: 1 + - name: LeftHandMiddle3 + position: {x: -.0339647792, y: 1.61085282e-07, z: 5.41929612e-09} + rotation: {x: 6.13220641e-10, y: -4.12468948e-09, z: 1.82216331e-09, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: LeftHandPinky1 + position: {x: -.0656598732, y: -.00782526191, z: -.0322512463} + rotation: {x: -.000913206837, y: .0121623212, z: .0212220512, w: .999700367} + scale: {x: 1.00000012, y: 1, z: .999999881} + transformModified: 1 + - name: LeftHandPinky2 + position: {x: -.0308053754, y: -3.11739277e-05, z: -.00144808914} + rotation: {x: -.000170628555, y: -.0096613653, z: -.00536239706, w: .999938905} + scale: {x: 1, y: .999999821, z: 1.00000012} + transformModified: 1 + - name: LeftHandPinky3 + position: {x: -.0230638776, y: -6.67785343e-06, z: 6.90349244e-09} + rotation: {x: -8.51873905e-10, y: -9.4255892e-09, z: -1.31619666e-08, w: .99999994} + scale: {x: 1, y: 1, z: .99999994} + transformModified: 1 + - name: LeftHandRing1 + position: {x: -.0703021139, y: -.00374528999, z: -.0114117898} + rotation: {x: -.000324091874, y: .0115982238, z: .0247380193, w: .999626577} + scale: {x: 1, y: 1.00000024, z: .99999994} + transformModified: 1 + - name: LeftHandRing2 + position: {x: -.0431353189, y: -2.08693382e-05, z: -.00223518023} + rotation: {x: -.0012032456, y: -.0231137592, z: .0409796387, w: .99889189} + scale: {x: .999999881, y: .999999702, z: .99999994} + transformModified: 1 + - name: LeftHandRing3 + position: {x: -.0308354236, y: -1.56879963e-07, z: -1.40963357e-08} + rotation: {x: 4.93614594e-10, y: -1.5807432e-09, z: -5.78796033e-09, w: .99999994} + scale: {x: 1, y: .99999994, z: .999999881} + transformModified: 1 + - name: LeftHandThumb1 + position: {x: -.0142313093, y: -.012377888, z: .0255316831} + rotation: {x: -.0123126386, y: -.0085253641, z: .0125855142, w: .999808609} + scale: {x: 1, y: 1, z: 1.00000012} + transformModified: 1 + - name: LeftHandThumb2 + position: {x: -.0163739249, y: -.00528992061, z: .0234914143} + rotation: {x: -.0260628555, y: .0966900289, z: .00360696716, w: .994966686} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: LeftHandThumb3 + position: {x: -.0254599936, y: -.00763992406, z: .020832995} + rotation: {x: 4.41585328e-08, y: 1.10925613e-09, z: -7.80932541e-10, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: Neck + position: {x: 0, y: .235723972, z: -.0324132554} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: Head + position: {x: 0, y: .106355786, z: .0113267824} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: Jaw + position: {x: 0, y: .0111267567, z: .0103275422} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: LeftEye + position: {x: -.0208482333, y: .0825027227, z: .0554274321} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: RightEye + position: {x: .020849999, y: .0825027227, z: .0554273948} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: RightShoulder + position: {x: .038328547, y: .192177057, z: -.0170630887} + rotation: {x: .228671983, y: .971582115, z: -.0140056778, w: -.05950737} + scale: {x: 1, y: 1.00000012, z: .99999994} + transformModified: 1 + - name: RightArm + position: {x: -.0835753977, y: .0360959396, z: -4.69747263e-08} + rotation: {x: -.21105209, y: -.974394083, z: .0173116997, w: -.0755877346} + scale: {x: .999999821, y: 1.00000012, z: .999999702} + transformModified: 1 + - name: RightForeArm + position: {x: .253428489, y: .00601093518, z: -.0167045332} + rotation: {x: -.00061651913, y: .022078624, z: -.0160702355, w: .999626875} + scale: {x: .99999994, y: .999999881, z: .99999994} + transformModified: 1 + - name: RightHand + position: {x: .245373741, y: .0216420237, z: .00555047346} + rotation: {x: 5.43189438e-10, y: 3.12476184e-10, z: .0214136969, w: .999770641} + scale: {x: 1, y: 1, z: 1.00000012} + transformModified: 1 + - name: RightHandIndex1 + position: {x: .0747697875, y: -.00124282821, z: .0343445241} + rotation: {x: -.00211892067, y: .0802574307, z: .0175381824, w: .996617556} + scale: {x: 1.00000012, y: 1, z: .99999994} + transformModified: 1 + - name: RightHandIndex2 + position: {x: .037058223, y: .000725421763, z: .0145388739} + rotation: {x: -.0033212963, y: .0159312561, z: .060620904, w: .998028159} + scale: {x: 1, y: .99999994, z: 1} + transformModified: 1 + - name: RightHandIndex3 + position: {x: .0252250955, y: -.00496621709, z: .0110121826} + rotation: {x: 2.16179208e-09, y: 1.06850013e-08, z: -8.50230109e-09, w: .99999994} + scale: {x: 1, y: 1.00000012, z: 1.00000012} + transformModified: 1 + - name: RightHandMiddle1 + position: {x: .0756474286, y: .00479083089, z: .0118531957} + rotation: {x: -.00076887355, y: .0333210677, z: .0209075324, w: .999225616} + scale: {x: 1.00000012, y: .999999821, z: .999999881} + transformModified: 1 + - name: RightHandMiddle2 + position: {x: .0438093096, y: .000194165463, z: .00645493949} + rotation: {x: -.00413025497, y: -.0335112251, z: .0761189312, w: .996526897} + scale: {x: 1, y: .999999881, z: 1.00000012} + transformModified: 1 + - name: RightHandMiddle3 + position: {x: .0330725648, y: -.00754737761, z: .00168985641} + rotation: {x: -3.7425496e-10, y: -4.22918101e-09, z: -1.05837286e-08, w: .99999994} + scale: {x: 1, y: .999999881, z: 1} + transformModified: 1 + - name: RightHandPinky1 + position: {x: .0668031499, y: -.00199452811, z: -.0307561476} + rotation: {x: .00317558926, y: -.192005113, z: .045110438, w: .980351448} + scale: {x: 1.00000024, y: 1, z: .99999994} + transformModified: 1 + - name: RightHandPinky2 + position: {x: .0285309609, y: -.00139694544, z: -.0116238492} + rotation: {x: -.000170628482, y: -.00966134109, z: -.0053623952, w: .999938965} + scale: {x: .999999881, y: 1, z: .99999994} + transformModified: 1 + - name: RightHandPinky3 + position: {x: .0214269403, y: -.000553725113, z: -.00851663202} + rotation: {x: -8.53474014e-10, y: 1.63788556e-08, z: -1.38467984e-08, w: .99999994} + scale: {x: 1, y: 1, z: 1.00000012} + transformModified: 1 + - name: RightHandRing1 + position: {x: .070598565, y: .00245756772, z: -.00982147083} + rotation: {x: .000710569788, y: -.054343082, z: .0349452496, w: .99791038} + scale: {x: 1.00000012, y: 1, z: 1} + transformModified: 1 + - name: RightHandRing2 + position: {x: .0428872742, y: -.0013759057, z: -.00494588772} + rotation: {x: .000482838717, y: -.0212902706, z: .0698495656, w: .997330129} + scale: {x: 1, y: 1, z: 1.00000024} + transformModified: 1 + - name: RightHandRing3 + position: {x: .0295008179, y: -.00769269653, z: -.00462226616} + rotation: {x: -2.61377653e-09, y: -8.06309508e-09, z: -6.11845863e-09, w: .99999994} + scale: {x: 1, y: 1, z: 1.00000012} + transformModified: 1 + - name: RightHandThumb1 + position: {x: .014684936, y: -.0111049525, z: .025858108} + rotation: {x: -.0128134973, y: -.00325657148, z: .0314576477, w: .999417663} + scale: {x: 1.00000012, y: 1, z: 1} + transformModified: 1 + - name: RightHandThumb2 + position: {x: .0163741205, y: -.00528976135, z: .0234913807} + rotation: {x: -.0260671675, y: -.0966875851, z: -.00360274338, w: .994966805} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: RightHandThumb3 + position: {x: .0254600029, y: -.00764030218, z: .0208330136} + rotation: {x: 1.31814044e-08, y: 1.05642828e-09, z: -2.01141503e-09, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + armTwist: .5 + foreArmTwist: .5 + upperLegTwist: .5 + legTwist: .5 + armStretch: .0500000007 + legStretch: .0500000007 + feetSpacing: 0 + rootMotionBoneName: + lastHumanDescriptionAvatarSource: {fileID: 9000000, guid: 2ab0893f5bba9b243b65e309e78089d0, + type: 3} + animationType: 3 + additionalBone: 0 + userData: diff --git a/Assets/Photon Unity Networking/Demos/Shared Assets/Animations/Jump.fbx b/Assets/Photon Unity Networking/Demos/Shared Assets/Animations/Jump.fbx new file mode 100644 index 0000000..2966ac5 Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/Shared Assets/Animations/Jump.fbx differ diff --git a/Assets/Photon Unity Networking/Demos/Shared Assets/Animations/Jump.fbx.meta b/Assets/Photon Unity Networking/Demos/Shared Assets/Animations/Jump.fbx.meta new file mode 100644 index 0000000..b657dac --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/Shared Assets/Animations/Jump.fbx.meta @@ -0,0 +1,1277 @@ +fileFormatVersion: 2 +guid: cbb67ab5509bfe24dba7db2d65a9632f +ModelImporter: + serializedVersion: 16 + fileIDToRecycleName: + 100000: l_ankleProxy_geo + 100002: l_middleProxy_01_geo + 100004: l_middleProxy_02_geo + 100006: l_middleProxy_03_geo + 100008: LeftHandMiddle13 + 100010: l_ringProxy_01_geo + 100012: l_ringProxy_02_geo + 100014: l_ringProxy_03_geo + 100016: l_pinkyProxy_01_geo + 100018: l_pinkyProxy_02_geo + 100020: r_indexProxy_02_geo + 100022: r_indexProxy_03_geo + 100024: r_middleProxy_01_geo + 100026: r_middleProxy_02_geo + 100028: r_middleProxy_03_geo + 100030: LeftHandMiddle17 + 100032: RightHandMiddle3 + 100034: RightHandMiddle2 + 100036: RightHandMiddle1 + 100038: r_ringProxy_01_geo + 100040: r_ringProxy_02_geo + 100042: r_ringProxy_03_geo + 100044: r_pinkyProxy_01_geo + 100046: r_pinkyProxy_02_geo + 100048: r_pinkyProxy_03_geo + 100050: UNI_01_Upper_teethProxy + 100052: RightEyelidLower + 100054: RightEyelidUpper + 100056: r_ankleProxy_geo + 100058: //RootNode + 100060: l_clavicleProxy_geo + 100062: l_pinkyProxy_03_geo + 100064: r_clavicleProxy_geo + 100066: r_shourderProxy_geo + 100068: r_erbowProxy_geo + 100070: r_wristProxy_geo + 100072: r_thumbProxy_01_geo + 100074: r_thumbProxy_02_geo + 100076: r_thumbProxy_03_geo + 100078: r_indexProxy_01_geo + 100080: UNI_01_Lower_teethProxy + 100082: UNI_01_TongueTipProxy + 100084: UNI_01_TongueBaseProxy + 100086: l_shourderProxy_geo + 100088: l_erbowProxy_geo + 100090: l_wristProxy_geo + 100092: l_thumbProxy_01_geo + 100094: l_thumbProxy_02_geo + 100096: l_thumbProxy_03_geo + 100098: l_indexProxy_01_geo + 100100: l_indexProxy_02_geo + 100102: l_indexProxy_03_geo + 100104: LeftHandMiddle1 + 100106: LeftHandRing13 + 100108: LeftHandRing3 + 100110: LeftHandRing2 + 100112: LeftHandRing1 + 100114: LeftHandPinky13 + 100116: LeftHandPinky3 + 100118: LeftHandPinky2 + 100120: LeftHandPinky1 + 100122: LeftHand + 100124: LeftForeArm + 100126: LeftArm + 100128: LeftShoulder + 100130: chestProxy_geo + 100132: LeftHandThumb17 + 100134: RightHandThumb3 + 100136: RightHandThumb2 + 100138: RightHandThumb1 + 100140: LeftHandIndex17 + 100142: RightHandIndex3 + 100144: RightHandIndex2 + 100146: RightHandIndex1 + 100148: LeftHandRing17 + 100150: RightHandRing3 + 100152: RightHandRing2 + 100154: RightHandRing1 + 100156: LeftHandPinky17 + 100158: RightHandPinky3 + 100160: RightHandPinky2 + 100162: RightHandPinky1 + 100164: RightHand + 100166: RightForeArm + 100168: RightArm + 100170: RightShoulder + 100172: neckProxy_geo + 100174: headProxy_geo + 100176: RightLipUpper + 100178: RightNostril + 100180: RightCheek + 100182: RightIOuterBrow + 100184: RightInnerBrow + 100186: LeftIOuterBrow + 100188: LeftInnerBrow + 100190: LeftEyelidUpper + 100192: LeftEyelidLower + 100194: LeftCheek + 100196: LeftNostril + 100198: LeftLipUpper + 100200: jawProxy_geo + 100202: LeftLipCorner + 100204: RightLipCorner + 100206: RightLipLower + 100208: JawEND + 100210: LeftLipLower + 100212: TongueTip + 100214: TongueBack + 100216: Jaw + 100218: r_UNI_eye + 100220: RightEye + 100222: l_UNI_eye + 100224: LeftEye + 100226: HeadTop_End + 100228: Head + 100230: Neck + 100232: Chest + 100234: Spine + 100236: Hips + 100238: Reference + 100240: l_hipProxy_geo + 100242: l_kneeProxy_geo + 100244: l_ballProxy_geo + 100246: LToeBase_End2 + 100248: LeftToes + 100250: LeftFoot + 100252: LeftLeg + 100254: LeftUpLeg + 100256: pelvisProxy_geo + 100258: r_hipProxy_geo + 100260: r_kneeProxy_geo + 100262: r_ballProxy_geo + 100264: LToeBase_End3 + 100266: RightToes + 100268: RightFoot + 100270: RightLeg + 100272: RightUpLeg + 100274: spineProxy_geo + 100276: LeftHandThumb13 + 100278: LeftHandThumb3 + 100280: LeftHandThumb2 + 100282: LeftHandThumb1 + 100284: LeftHandIndex13 + 100286: LeftHandIndex3 + 100288: LeftHandIndex2 + 100290: LeftHandIndex1 + 100292: LeftHandMiddle3 + 100294: LeftHandMiddle2 + 400000: l_ankleProxy_geo + 400002: l_middleProxy_01_geo + 400004: l_middleProxy_02_geo + 400006: l_middleProxy_03_geo + 400008: LeftHandMiddle13 + 400010: l_ringProxy_01_geo + 400012: l_ringProxy_02_geo + 400014: l_ringProxy_03_geo + 400016: l_pinkyProxy_01_geo + 400018: l_pinkyProxy_02_geo + 400020: r_indexProxy_02_geo + 400022: r_indexProxy_03_geo + 400024: r_middleProxy_01_geo + 400026: r_middleProxy_02_geo + 400028: r_middleProxy_03_geo + 400030: LeftHandMiddle17 + 400032: RightHandMiddle3 + 400034: RightHandMiddle2 + 400036: RightHandMiddle1 + 400038: r_ringProxy_01_geo + 400040: r_ringProxy_02_geo + 400042: r_ringProxy_03_geo + 400044: r_pinkyProxy_01_geo + 400046: r_pinkyProxy_02_geo + 400048: r_pinkyProxy_03_geo + 400050: UNI_01_Upper_teethProxy + 400052: RightEyelidLower + 400054: RightEyelidUpper + 400056: r_ankleProxy_geo + 400058: //RootNode + 400060: l_clavicleProxy_geo + 400062: l_pinkyProxy_03_geo + 400064: r_clavicleProxy_geo + 400066: r_shourderProxy_geo + 400068: r_erbowProxy_geo + 400070: r_wristProxy_geo + 400072: r_thumbProxy_01_geo + 400074: r_thumbProxy_02_geo + 400076: r_thumbProxy_03_geo + 400078: r_indexProxy_01_geo + 400080: UNI_01_Lower_teethProxy + 400082: UNI_01_TongueTipProxy + 400084: UNI_01_TongueBaseProxy + 400086: l_shourderProxy_geo + 400088: l_erbowProxy_geo + 400090: l_wristProxy_geo + 400092: l_thumbProxy_01_geo + 400094: l_thumbProxy_02_geo + 400096: l_thumbProxy_03_geo + 400098: l_indexProxy_01_geo + 400100: l_indexProxy_02_geo + 400102: l_indexProxy_03_geo + 400104: LeftHandMiddle1 + 400106: LeftHandRing13 + 400108: LeftHandRing3 + 400110: LeftHandRing2 + 400112: LeftHandRing1 + 400114: LeftHandPinky13 + 400116: LeftHandPinky3 + 400118: LeftHandPinky2 + 400120: LeftHandPinky1 + 400122: LeftHand + 400124: LeftForeArm + 400126: LeftArm + 400128: LeftShoulder + 400130: chestProxy_geo + 400132: LeftHandThumb17 + 400134: RightHandThumb3 + 400136: RightHandThumb2 + 400138: RightHandThumb1 + 400140: LeftHandIndex17 + 400142: RightHandIndex3 + 400144: RightHandIndex2 + 400146: RightHandIndex1 + 400148: LeftHandRing17 + 400150: RightHandRing3 + 400152: RightHandRing2 + 400154: RightHandRing1 + 400156: LeftHandPinky17 + 400158: RightHandPinky3 + 400160: RightHandPinky2 + 400162: RightHandPinky1 + 400164: RightHand + 400166: RightForeArm + 400168: RightArm + 400170: RightShoulder + 400172: neckProxy_geo + 400174: headProxy_geo + 400176: RightLipUpper + 400178: RightNostril + 400180: RightCheek + 400182: RightIOuterBrow + 400184: RightInnerBrow + 400186: LeftIOuterBrow + 400188: LeftInnerBrow + 400190: LeftEyelidUpper + 400192: LeftEyelidLower + 400194: LeftCheek + 400196: LeftNostril + 400198: LeftLipUpper + 400200: jawProxy_geo + 400202: LeftLipCorner + 400204: RightLipCorner + 400206: RightLipLower + 400208: JawEND + 400210: LeftLipLower + 400212: TongueTip + 400214: TongueBack + 400216: Jaw + 400218: r_UNI_eye + 400220: RightEye + 400222: l_UNI_eye + 400224: LeftEye + 400226: HeadTop_End + 400228: Head + 400230: Neck + 400232: Chest + 400234: Spine + 400236: Hips + 400238: Reference + 400240: l_hipProxy_geo + 400242: l_kneeProxy_geo + 400244: l_ballProxy_geo + 400246: LToeBase_End2 + 400248: LeftToes + 400250: LeftFoot + 400252: LeftLeg + 400254: LeftUpLeg + 400256: pelvisProxy_geo + 400258: r_hipProxy_geo + 400260: r_kneeProxy_geo + 400262: r_ballProxy_geo + 400264: LToeBase_End3 + 400266: RightToes + 400268: RightFoot + 400270: RightLeg + 400272: RightUpLeg + 400274: spineProxy_geo + 400276: LeftHandThumb13 + 400278: LeftHandThumb3 + 400280: LeftHandThumb2 + 400282: LeftHandThumb1 + 400284: LeftHandIndex13 + 400286: LeftHandIndex3 + 400288: LeftHandIndex2 + 400290: LeftHandIndex1 + 400292: LeftHandMiddle3 + 400294: LeftHandMiddle2 + 2300000: l_ankleProxy_geo + 2300002: l_middleProxy_01_geo + 2300004: l_middleProxy_02_geo + 2300006: l_middleProxy_03_geo + 2300008: l_ringProxy_01_geo + 2300010: l_ringProxy_02_geo + 2300012: l_ringProxy_03_geo + 2300014: l_pinkyProxy_01_geo + 2300016: l_pinkyProxy_02_geo + 2300018: r_indexProxy_02_geo + 2300020: r_indexProxy_03_geo + 2300022: r_middleProxy_01_geo + 2300024: r_middleProxy_02_geo + 2300026: r_middleProxy_03_geo + 2300028: r_ringProxy_01_geo + 2300030: r_ringProxy_02_geo + 2300032: r_ringProxy_03_geo + 2300034: r_pinkyProxy_01_geo + 2300036: r_pinkyProxy_02_geo + 2300038: r_pinkyProxy_03_geo + 2300040: UNI_01_Upper_teethProxy + 2300042: r_ankleProxy_geo + 2300044: l_clavicleProxy_geo + 2300046: l_pinkyProxy_03_geo + 2300048: r_clavicleProxy_geo + 2300050: r_shourderProxy_geo + 2300052: r_erbowProxy_geo + 2300054: r_wristProxy_geo + 2300056: r_thumbProxy_01_geo + 2300058: r_thumbProxy_02_geo + 2300060: r_thumbProxy_03_geo + 2300062: r_indexProxy_01_geo + 2300064: UNI_01_Lower_teethProxy + 2300066: UNI_01_TongueTipProxy + 2300068: UNI_01_TongueBaseProxy + 2300070: l_shourderProxy_geo + 2300072: l_erbowProxy_geo + 2300074: l_wristProxy_geo + 2300076: l_thumbProxy_01_geo + 2300078: l_thumbProxy_02_geo + 2300080: l_thumbProxy_03_geo + 2300082: l_indexProxy_01_geo + 2300084: l_indexProxy_02_geo + 2300086: l_indexProxy_03_geo + 2300088: chestProxy_geo + 2300090: neckProxy_geo + 2300092: headProxy_geo + 2300094: jawProxy_geo + 2300096: r_UNI_eye + 2300098: l_UNI_eye + 2300100: l_hipProxy_geo + 2300102: l_kneeProxy_geo + 2300104: l_ballProxy_geo + 2300106: pelvisProxy_geo + 2300108: r_hipProxy_geo + 2300110: r_kneeProxy_geo + 2300112: r_ballProxy_geo + 2300114: spineProxy_geo + 3300000: l_ankleProxy_geo + 3300002: l_middleProxy_01_geo + 3300004: l_middleProxy_02_geo + 3300006: l_middleProxy_03_geo + 3300008: l_ringProxy_01_geo + 3300010: l_ringProxy_02_geo + 3300012: l_ringProxy_03_geo + 3300014: l_pinkyProxy_01_geo + 3300016: l_pinkyProxy_02_geo + 3300018: r_indexProxy_02_geo + 3300020: r_indexProxy_03_geo + 3300022: r_middleProxy_01_geo + 3300024: r_middleProxy_02_geo + 3300026: r_middleProxy_03_geo + 3300028: r_ringProxy_01_geo + 3300030: r_ringProxy_02_geo + 3300032: r_ringProxy_03_geo + 3300034: r_pinkyProxy_01_geo + 3300036: r_pinkyProxy_02_geo + 3300038: r_pinkyProxy_03_geo + 3300040: UNI_01_Upper_teethProxy + 3300042: r_ankleProxy_geo + 3300044: l_clavicleProxy_geo + 3300046: l_pinkyProxy_03_geo + 3300048: r_clavicleProxy_geo + 3300050: r_shourderProxy_geo + 3300052: r_erbowProxy_geo + 3300054: r_wristProxy_geo + 3300056: r_thumbProxy_01_geo + 3300058: r_thumbProxy_02_geo + 3300060: r_thumbProxy_03_geo + 3300062: r_indexProxy_01_geo + 3300064: UNI_01_Lower_teethProxy + 3300066: UNI_01_TongueTipProxy + 3300068: UNI_01_TongueBaseProxy + 3300070: l_shourderProxy_geo + 3300072: l_erbowProxy_geo + 3300074: l_wristProxy_geo + 3300076: l_thumbProxy_01_geo + 3300078: l_thumbProxy_02_geo + 3300080: l_thumbProxy_03_geo + 3300082: l_indexProxy_01_geo + 3300084: l_indexProxy_02_geo + 3300086: l_indexProxy_03_geo + 3300088: chestProxy_geo + 3300090: neckProxy_geo + 3300092: headProxy_geo + 3300094: jawProxy_geo + 3300096: r_UNI_eye + 3300098: l_UNI_eye + 3300100: l_hipProxy_geo + 3300102: l_kneeProxy_geo + 3300104: l_ballProxy_geo + 3300106: pelvisProxy_geo + 3300108: r_hipProxy_geo + 3300110: r_kneeProxy_geo + 3300112: r_ballProxy_geo + 3300114: spineProxy_geo + 4300000: l_UNI_eye + 4300002: r_UNI_eye + 4300004: UNI_01_TongueBaseProxy + 4300006: UNI_01_TongueTipProxy + 4300008: UNI_01_Lower_teethProxy + 4300010: jawProxy_geo + 4300012: headProxy_geo + 4300014: UNI_01_Upper_teethProxy + 4300016: neckProxy_geo + 4300018: r_pinkyProxy_03_geo + 4300020: r_pinkyProxy_02_geo + 4300022: r_pinkyProxy_01_geo + 4300024: r_ringProxy_03_geo + 4300026: r_ringProxy_02_geo + 4300028: r_ringProxy_01_geo + 4300030: r_middleProxy_03_geo + 4300032: r_middleProxy_02_geo + 4300034: r_middleProxy_01_geo + 4300036: r_indexProxy_03_geo + 4300038: r_indexProxy_02_geo + 4300040: r_indexProxy_01_geo + 4300042: r_thumbProxy_03_geo + 4300044: r_thumbProxy_02_geo + 4300046: r_thumbProxy_01_geo + 4300048: r_wristProxy_geo + 4300050: r_erbowProxy_geo + 4300052: r_shourderProxy_geo + 4300054: r_clavicleProxy_geo + 4300056: chestProxy_geo + 4300058: l_pinkyProxy_03_geo + 4300060: l_pinkyProxy_02_geo + 4300062: l_pinkyProxy_01_geo + 4300064: l_ringProxy_03_geo + 4300066: l_ringProxy_02_geo + 4300068: l_ringProxy_01_geo + 4300070: l_middleProxy_03_geo + 4300072: l_middleProxy_02_geo + 4300074: l_middleProxy_01_geo + 4300076: l_indexProxy_03_geo + 4300078: l_indexProxy_02_geo + 4300080: l_indexProxy_01_geo + 4300082: l_thumbProxy_03_geo + 4300084: l_thumbProxy_02_geo + 4300086: l_thumbProxy_01_geo + 4300088: l_wristProxy_geo + 4300090: l_erbowProxy_geo + 4300092: l_shourderProxy_geo + 4300094: l_clavicleProxy_geo + 4300096: spineProxy_geo + 4300098: r_ballProxy_geo + 4300100: r_ankleProxy_geo + 4300102: r_kneeProxy_geo + 4300104: r_hipProxy_geo + 4300106: pelvisProxy_geo + 4300108: l_ballProxy_geo + 4300110: l_ankleProxy_geo + 4300112: l_kneeProxy_geo + 4300114: l_hipProxy_geo + 7400000: Avatar_TStance + 7400002: Run_Jumpvault_SideFlip_R_Run + 7400004: Run_Jumpvault_SideFlip_L_Run + 7400006: Avatar_TStance + 7400008: Run_Jumpvault_SideFlip_R_Run + 7400010: Run_Jumpvault_SideFlip_L_Run + 7400012: Jump + 7400014: __preview__Jump + 11100000: //RootNode + materials: + importMaterials: 1 + materialName: 0 + materialSearch: 1 + animations: + legacyGenerateAnimations: 4 + bakeSimulation: 0 + optimizeGameObjects: 0 + motionNodeName: + animationCompression: 1 + animationRotationError: .5 + animationPositionError: .5 + animationScaleError: .5 + animationWrapMode: 0 + extraExposedTransformPaths: [] + clipAnimations: + - serializedVersion: 16 + name: Jump + takeName: Jump + firstFrame: 261 + lastFrame: 338 + wrapMode: 0 + orientationOffsetY: 0 + level: 0 + cycleOffset: 0 + loop: 0 + loopTime: 0 + loopBlend: 0 + loopBlendOrientation: 1 + loopBlendPositionY: 1 + loopBlendPositionXZ: 0 + keepOriginalOrientation: 0 + keepOriginalPositionY: 1 + keepOriginalPositionXZ: 0 + heightFromFeet: 0 + mirror: 0 + bodyMask: 01000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000 + curves: [] + events: [] + transformMask: [] + maskType: 0 + maskSource: {instanceID: 0} + isReadable: 1 + meshes: + lODScreenPercentages: [] + globalScale: .00999999978 + meshCompression: 0 + addColliders: 0 + importBlendShapes: 1 + swapUVChannels: 0 + generateSecondaryUV: 0 + useFileUnits: 1 + optimizeMeshForGPU: 1 + weldVertices: 1 + secondaryUVAngleDistortion: 8 + secondaryUVAreaDistortion: 15.000001 + secondaryUVHardAngle: 88 + secondaryUVPackMargin: 4 + tangentSpace: + normalSmoothAngle: 60 + splitTangentsAcrossUV: 1 + normalImportMode: 0 + tangentImportMode: 1 + importAnimation: 1 + copyAvatar: 1 + humanDescription: + human: + - boneName: Hips + humanName: Hips + limit: + min: {x: -40, y: -40, z: -40} + max: {x: 40, y: 40, z: 40} + value: {x: .0748811588, y: 0, z: .0374405794} + length: .0936014801 + modified: 0 + - boneName: LeftUpLeg + humanName: LeftUpperLeg + limit: + min: {x: -60.0000038, y: -60.0000038, z: -90} + max: {x: 60.0000038, y: 60.0000038, z: 50} + value: {x: .327766716, y: 0, z: .163883358} + length: .40970853 + modified: 0 + - boneName: RightUpLeg + humanName: RightUpperLeg + limit: + min: {x: -60.0000038, y: -60.0000038, z: -90} + max: {x: 60.0000038, y: 60.0000038, z: 50} + value: {x: .327766716, y: 0, z: .163883358} + length: .40970853 + modified: 0 + - boneName: LeftLeg + humanName: LeftLowerLeg + limit: + min: {x: -90, y: 0, z: -80} + max: {x: 90, y: 0, z: 80} + value: {x: .338686436, y: 0, z: .169343218} + length: .423358172 + modified: 0 + - boneName: RightLeg + humanName: RightLowerLeg + limit: + min: {x: -90, y: 0, z: -80} + max: {x: 90, y: 0, z: 80} + value: {x: .338686436, y: 0, z: .169343218} + length: .423358172 + modified: 0 + - boneName: LeftFoot + humanName: LeftFoot + limit: + min: {x: 0, y: -30.0000019, z: -50} + max: {x: 0, y: 30.0000019, z: 50} + value: {x: .0686753467, y: 0, z: .0343376733} + length: .0858442187 + modified: 0 + - boneName: RightFoot + humanName: RightFoot + limit: + min: {x: 0, y: -30.0000019, z: -50} + max: {x: 0, y: 30.0000019, z: 50} + value: {x: .0686753467, y: 0, z: .0343376733} + length: .0858442187 + modified: 0 + - boneName: Spine + humanName: Spine + limit: + min: {x: -40, y: -40, z: -40} + max: {x: 40, y: 40, z: 40} + value: {x: .131201819, y: 0, z: .0656009093} + length: .164002344 + modified: 0 + - boneName: Chest + humanName: Chest + limit: + min: {x: -40, y: -40, z: -40} + max: {x: 40, y: 40, z: 40} + value: {x: .190353557, y: 0, z: .0951767787} + length: .237942025 + modified: 0 + - boneName: Neck + humanName: Neck + limit: + min: {x: -40, y: -40, z: -40} + max: {x: 40, y: 40, z: 40} + value: {x: .0855657607, y: 0, z: .0427828804} + length: .106957234 + modified: 0 + - boneName: Head + humanName: Head + limit: + min: {x: -40, y: -40, z: -40} + max: {x: 40, y: 40, z: 40} + value: {x: .0855657607, y: 0, z: .0427828804} + length: .106957234 + modified: 0 + - boneName: LeftShoulder + humanName: LeftShoulder + limit: + min: {x: 0, y: -15.000001, z: -15.000001} + max: {x: 0, y: 15.000001, z: 30.0000019} + value: {x: .072829701, y: 0, z: .0364148505} + length: .0910371616 + modified: 0 + - boneName: RightShoulder + humanName: RightShoulder + limit: + min: {x: 0, y: -15.000001, z: -15.000001} + max: {x: 0, y: 15.000001, z: 30.0000019} + value: {x: .072829701, y: 0, z: .0364148505} + length: .0910371616 + modified: 0 + - boneName: LeftArm + humanName: LeftUpperArm + limit: + min: {x: -90, y: -100, z: -60.0000038} + max: {x: 90, y: 100, z: 100} + value: {x: .203239605, y: 0, z: .101619802} + length: .254049569 + modified: 0 + - boneName: RightArm + humanName: RightUpperArm + limit: + min: {x: -90, y: -100, z: -60.0000038} + max: {x: 90, y: 100, z: 100} + value: {x: .203239486, y: 0, z: .101619743} + length: .25404942 + modified: 0 + - boneName: LeftForeArm + humanName: LeftLowerArm + limit: + min: {x: -90, y: 0, z: -80} + max: {x: 90, y: 0, z: 80} + value: {x: .197111338, y: 0, z: .0985556692} + length: .24638924 + modified: 0 + - boneName: RightForeArm + humanName: RightLowerArm + limit: + min: {x: -90, y: 0, z: -80} + max: {x: 90, y: 0, z: 80} + value: {x: .197110936, y: 0, z: .098555468} + length: .246388748 + modified: 0 + - boneName: LeftHand + humanName: LeftHand + limit: + min: {x: 0, y: -40, z: -80} + max: {x: 0, y: 40, z: 80} + value: {x: .0985556692, y: 0, z: .0492778346} + length: .12319462 + modified: 0 + - boneName: RightHand + humanName: RightHand + limit: + min: {x: 0, y: -40, z: -80} + max: {x: 0, y: 40, z: 80} + value: {x: .098555468, y: 0, z: .049277734} + length: .123194374 + modified: 0 + - boneName: LeftToes + humanName: LeftToes + limit: + min: {x: 0, y: 0, z: -50} + max: {x: 0, y: 0, z: 50} + value: {x: .0651871562, y: 0, z: .0325935781} + length: .0814839825 + modified: 0 + - boneName: RightToes + humanName: RightToes + limit: + min: {x: 0, y: 0, z: -50} + max: {x: 0, y: 0, z: 50} + value: {x: .0651872903, y: 0, z: .0325936452} + length: .0814841464 + modified: 0 + - boneName: LeftEye + humanName: LeftEye + limit: + min: {x: 0, y: -20, z: -10} + max: {x: 0, y: 20, z: 15.000001} + value: {x: .0799999759, y: 0, z: .0399999879} + length: .100000001 + modified: 0 + - boneName: RightEye + humanName: RightEye + limit: + min: {x: 0, y: -20, z: -10} + max: {x: 0, y: 20, z: 15.000001} + value: {x: .0799999759, y: 0, z: .0399999879} + length: .100000001 + modified: 0 + - boneName: Jaw + humanName: Jaw + limit: + min: {x: 0, y: -10, z: -10} + max: {x: 0, y: 10, z: 10} + value: {x: .0799999759, y: 0, z: .0399999879} + length: .100000001 + modified: 0 + - boneName: LeftHandThumb1 + humanName: Left Thumb Proximal + limit: + min: {x: 0, y: -25, z: -20} + max: {x: 0, y: 25, z: 20} + value: {x: .0232954584, y: 0, z: .0116477292} + length: .0291193314 + modified: 0 + - boneName: LeftHandThumb2 + humanName: Left Thumb Intermediate + limit: + min: {x: 0, y: 0, z: -40} + max: {x: 0, y: 0, z: 35} + value: {x: .027018128, y: 0, z: .013509064} + length: .0337726697 + modified: 0 + - boneName: LeftHandThumb3 + humanName: Left Thumb Distal + limit: + min: {x: 0, y: 0, z: -40} + max: {x: 0, y: 0, z: 35} + value: {x: .0202635955, y: 0, z: .0101317978} + length: .0253295023 + modified: 0 + - boneName: LeftHandIndex1 + humanName: Left Index Proximal + limit: + min: {x: 0, y: -20, z: -50} + max: {x: 0, y: 20, z: 50} + value: {x: .0318517797, y: 0, z: .0159258898} + length: .0398147404 + modified: 0 + - boneName: LeftHandIndex2 + humanName: Left Index Intermediate + limit: + min: {x: 0, y: 0, z: -45} + max: {x: 0, y: 0, z: 45} + value: {x: .0223747883, y: 0, z: .0111873941} + length: .0279684942 + modified: 0 + - boneName: LeftHandIndex3 + humanName: Left Index Distal + limit: + min: {x: 0, y: 0, z: -45} + max: {x: 0, y: 0, z: 45} + value: {x: .0167810898, y: 0, z: .00839054491} + length: .0209763702 + modified: 0 + - boneName: LeftHandMiddle1 + humanName: Left Middle Proximal + limit: + min: {x: 0, y: -7.50000048, z: -50} + max: {x: 0, y: 7.50000048, z: 50} + value: {x: .0354260914, y: 0, z: .0177130457} + length: .0442826301 + modified: 0 + - boneName: LeftHandMiddle2 + humanName: Left Middle Intermediate + limit: + min: {x: 0, y: 0, z: -45} + max: {x: 0, y: 0, z: 45} + value: {x: .0271718036, y: 0, z: .0135859018} + length: .0339647643 + modified: 0 + - boneName: LeftHandMiddle3 + humanName: Left Middle Distal + limit: + min: {x: 0, y: 0, z: -45} + max: {x: 0, y: 0, z: 45} + value: {x: .0203788504, y: 0, z: .0101894252} + length: .0254735723 + modified: 0 + - boneName: LeftHandRing1 + humanName: Left Ring Proximal + limit: + min: {x: 0, y: -7.50000048, z: -50} + max: {x: 0, y: 7.50000048, z: 50} + value: {x: .0345545448, y: 0, z: .0172772724} + length: .0431931987 + modified: 0 + - boneName: LeftHandRing2 + humanName: Left Ring Intermediate + limit: + min: {x: 0, y: 0, z: -45} + max: {x: 0, y: 0, z: 45} + value: {x: .0246683266, y: 0, z: .0123341633} + length: .030835418 + modified: 0 + - boneName: LeftHandRing3 + humanName: Left Ring Distal + limit: + min: {x: 0, y: 0, z: -45} + max: {x: 0, y: 0, z: 45} + value: {x: .0185012426, y: 0, z: .00925062131} + length: .0231265631 + modified: 0 + - boneName: LeftHandPinky1 + humanName: Left Little Proximal + limit: + min: {x: 0, y: -20, z: -50} + max: {x: 0, y: 20, z: 50} + value: {x: .024671508, y: 0, z: .012335754} + length: .0308393929 + modified: 0 + - boneName: LeftHandPinky2 + humanName: Left Little Intermediate + limit: + min: {x: 0, y: 0, z: -45} + max: {x: 0, y: 0, z: 45} + value: {x: .0184510797, y: 0, z: .00922553986} + length: .023063859 + modified: 0 + - boneName: LeftHandPinky3 + humanName: Left Little Distal + limit: + min: {x: 0, y: 0, z: -45} + max: {x: 0, y: 0, z: 45} + value: {x: .0138383117, y: 0, z: .00691915583} + length: .0172978938 + modified: 0 + - boneName: RightHandThumb1 + humanName: Right Thumb Proximal + limit: + min: {x: 0, y: -25, z: -20} + max: {x: 0, y: 25, z: 20} + value: {x: .0232954696, y: 0, z: .0116477348} + length: .0291193463 + modified: 0 + - boneName: RightHandThumb2 + humanName: Right Thumb Intermediate + limit: + min: {x: 0, y: 0, z: -40} + max: {x: 0, y: 0, z: 35} + value: {x: .0270182006, y: 0, z: .0135091003} + length: .0337727591 + modified: 0 + - boneName: RightHandThumb3 + humanName: Right Thumb Distal + limit: + min: {x: 0, y: 0, z: -40} + max: {x: 0, y: 0, z: 35} + value: {x: .0202636477, y: 0, z: .0101318238} + length: .0253295694 + modified: 0 + - boneName: RightHandIndex1 + humanName: Right Index Proximal + limit: + min: {x: 0, y: -20, z: -50} + max: {x: 0, y: 20, z: 50} + value: {x: .0318517946, y: 0, z: .0159258973} + length: .039814759 + modified: 0 + - boneName: RightHandIndex2 + humanName: Right Index Intermediate + limit: + min: {x: 0, y: 0, z: -45} + max: {x: 0, y: 0, z: 45} + value: {x: .0223747734, y: 0, z: .0111873867} + length: .0279684756 + modified: 0 + - boneName: RightHandIndex3 + humanName: Right Index Distal + limit: + min: {x: 0, y: 0, z: -45} + max: {x: 0, y: 0, z: 45} + value: {x: .0167810787, y: 0, z: .00839053933} + length: .0209763572 + modified: 0 + - boneName: RightHandMiddle1 + humanName: Right Middle Proximal + limit: + min: {x: 0, y: -7.50000048, z: -50} + max: {x: 0, y: 7.50000048, z: 50} + value: {x: .0354261473, y: 0, z: .0177130736} + length: .0442827009 + modified: 0 + - boneName: RightHandMiddle2 + humanName: Right Middle Intermediate + limit: + min: {x: 0, y: 0, z: -45} + max: {x: 0, y: 0, z: 45} + value: {x: .0271718968, y: 0, z: .0135859484} + length: .0339648798 + modified: 0 + - boneName: RightHandMiddle3 + humanName: Right Middle Distal + limit: + min: {x: 0, y: 0, z: -45} + max: {x: 0, y: 0, z: 45} + value: {x: .0203789212, y: 0, z: .0101894606} + length: .0254736599 + modified: 0 + - boneName: RightHandRing1 + humanName: Right Ring Proximal + limit: + min: {x: 0, y: -7.50000048, z: -50} + max: {x: 0, y: 7.50000048, z: 50} + value: {x: .0345547274, y: 0, z: .0172773637} + length: .043193426 + modified: 0 + - boneName: RightHandRing2 + humanName: Right Ring Intermediate + limit: + min: {x: 0, y: 0, z: -45} + max: {x: 0, y: 0, z: 45} + value: {x: .0246685483, y: 0, z: .0123342741} + length: .0308356937 + modified: 0 + - boneName: RightHandRing3 + humanName: Right Ring Distal + limit: + min: {x: 0, y: 0, z: -45} + max: {x: 0, y: 0, z: 45} + value: {x: .0185014084, y: 0, z: .0092507042} + length: .0231267698 + modified: 0 + - boneName: RightHandPinky1 + humanName: Right Little Proximal + limit: + min: {x: 0, y: -20, z: -50} + max: {x: 0, y: 20, z: 50} + value: {x: .0246716533, y: 0, z: .0123358266} + length: .0308395755 + modified: 0 + - boneName: RightHandPinky2 + humanName: Right Little Intermediate + limit: + min: {x: 0, y: 0, z: -45} + max: {x: 0, y: 0, z: 45} + value: {x: .018451266, y: 0, z: .009225633} + length: .0230640918 + modified: 0 + - boneName: RightHandPinky3 + humanName: Right Little Distal + limit: + min: {x: 0, y: 0, z: -45} + max: {x: 0, y: 0, z: 45} + value: {x: .0138384514, y: 0, z: .00691922568} + length: .0172980689 + modified: 0 + skeleton: + - name: Dude + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: Reference + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: Hips + position: {x: 0, y: .963793993, z: -.0235067774} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: LeftUpLeg + position: {x: -.0754494965, y: -.0456640124, z: 0} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: LeftLeg + position: {x: -.0205505043, y: -.409129977, z: .00717136636} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: LeftFoot + position: {x: -.00515300781, y: -.423155904, z: -.0120320898} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: LeftToes + position: {x: -.00748699158, y: -.0731672645, z: .145427138} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: RightUpLeg + position: {x: .0754495338, y: -.0456640124, z: 0} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: RightLeg + position: {x: .0205504671, y: -.409129977, z: .00717136636} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: RightFoot + position: {x: .00515300035, y: -.423155904, z: -.0120320898} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: RightToes + position: {x: .00748699903, y: -.0731672645, z: .14542751} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: Spine + position: {x: 0, y: .0922632217, z: .0157713331} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: Chest + position: {x: 0, y: .162540197, z: .02185072} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: LeftShoulder + position: {x: -.0382435732, y: .192178011, z: -.017063085} + rotation: {x: -.0140067078, y: -.0595068112, z: .228689864, w: .971577883} + scale: {x: 1.00000024, y: 1, z: 1} + transformModified: 1 + - name: LeftArm + position: {x: -.083574675, y: .0360975936, z: -1.50734021e-08} + rotation: {x: .00946438964, y: .0436916873, z: -.223042384, w: .973783076} + scale: {x: 1, y: 1, z: 1.00000012} + transformModified: 1 + - name: LeftForeArm + position: {x: -.254049391, y: 4.70318128e-07, z: -2.19768759e-09} + rotation: {x: -.000616520061, y: .0220786203, z: -.0160702374, w: .999626815} + scale: {x: .99999994, y: 1, z: .999999881} + transformModified: 1 + - name: LeftHand + position: {x: -.246389359, y: -1.89769892e-07, z: -5.73217829e-09} + rotation: {x: 2.86021179e-10, y: -9.59063384e-10, z: -.0214135442, w: .999770641} + scale: {x: .99999994, y: 1, z: 1} + transformModified: 1 + - name: LeftHandIndex1 + position: {x: -.0751256943, y: -.0078413263, z: .0326526687} + rotation: {x: -.00211891951, y: .0802574232, z: .0175381787, w: .996617556} + scale: {x: 1, y: 1, z: .99999994} + transformModified: 1 + - name: LeftHandIndex2 + position: {x: -.0397970602, y: 4.9526192e-05, z: .00118574023} + rotation: {x: .000501931063, y: .0154708987, z: .040414121, w: .999063075} + scale: {x: 1.00000024, y: 1.00000024, z: .99999994} + transformModified: 1 + - name: LeftHandIndex3 + position: {x: -.0279685091, y: -1.79063633e-07, z: -9.18437095e-08} + rotation: {x: 4.33656722e-10, y: -1.75894304e-08, z: -1.0378705e-08, w: .99999994} + scale: {x: 1, y: 1.00000012, z: .999999881} + transformModified: 1 + - name: LeftHandMiddle1 + position: {x: -.0760235488, y: -.00188508059, z: .0101412414} + rotation: {x: -.000768872735, y: .0333210714, z: .0209075287, w: .999225616} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: LeftHandMiddle2 + position: {x: -.0442805924, y: 4.51253936e-06, z: -.000425422273} + rotation: {x: -.00136214169, y: -.0191537682, z: .0378897563, w: .999097347} + scale: {x: 1, y: 1.00000012, z: 1} + transformModified: 1 + - name: LeftHandMiddle3 + position: {x: -.0339647792, y: 1.61085282e-07, z: 5.41929612e-09} + rotation: {x: 6.13220641e-10, y: -4.12468948e-09, z: 1.82216331e-09, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: LeftHandPinky1 + position: {x: -.0656598732, y: -.00782526191, z: -.0322512463} + rotation: {x: -.000913206779, y: .0121623203, z: .0212220494, w: .999700308} + scale: {x: 1.00000012, y: 1, z: .999999881} + transformModified: 1 + - name: LeftHandPinky2 + position: {x: -.0308053754, y: -3.11739277e-05, z: -.00144808914} + rotation: {x: -.000170628555, y: -.0096613653, z: -.00536239706, w: .999938905} + scale: {x: 1, y: .999999821, z: 1.00000012} + transformModified: 1 + - name: LeftHandPinky3 + position: {x: -.0230638776, y: -6.67785343e-06, z: 6.90349244e-09} + rotation: {x: -8.51873905e-10, y: -9.4255892e-09, z: -1.31619666e-08, w: .99999994} + scale: {x: 1, y: 1, z: .99999994} + transformModified: 1 + - name: LeftHandRing1 + position: {x: -.0703021139, y: -.00374528999, z: -.0114117898} + rotation: {x: -.000324091874, y: .0115982238, z: .0247380193, w: .999626577} + scale: {x: 1, y: 1.00000024, z: .99999994} + transformModified: 1 + - name: LeftHandRing2 + position: {x: -.0431353189, y: -2.08693382e-05, z: -.00223518023} + rotation: {x: -.00120324548, y: -.0231137574, z: .040979635, w: .99889183} + scale: {x: .999999881, y: .999999702, z: .99999994} + transformModified: 1 + - name: LeftHandRing3 + position: {x: -.0308354236, y: -1.56879963e-07, z: -1.40963357e-08} + rotation: {x: 4.93614594e-10, y: -1.5807432e-09, z: -5.78796033e-09, w: .99999994} + scale: {x: 1, y: .99999994, z: .999999881} + transformModified: 1 + - name: LeftHandThumb1 + position: {x: -.0142313093, y: -.012377888, z: .0255316831} + rotation: {x: -.0123126386, y: -.0085253641, z: .0125855142, w: .999808609} + scale: {x: 1, y: 1, z: 1.00000012} + transformModified: 1 + - name: LeftHandThumb2 + position: {x: -.0163739249, y: -.00528992061, z: .0234914143} + rotation: {x: -.0260628555, y: .0966900289, z: .00360696716, w: .994966686} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: LeftHandThumb3 + position: {x: -.0254599936, y: -.00763992406, z: .020832995} + rotation: {x: 4.41585328e-08, y: 1.10925613e-09, z: -7.80932541e-10, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: Neck + position: {x: 0, y: .235723972, z: -.0324132554} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: Head + position: {x: 0, y: .106355786, z: .0113267824} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: Jaw + position: {x: 0, y: .0111267567, z: .0103275422} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: LeftEye + position: {x: -.0208482333, y: .0825027227, z: .0554274321} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: RightEye + position: {x: .020849999, y: .0825027227, z: .0554273948} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: RightShoulder + position: {x: .038328547, y: .192177057, z: -.0170630887} + rotation: {x: .228671983, y: .971582115, z: -.0140056778, w: -.05950737} + scale: {x: 1, y: 1.00000012, z: .99999994} + transformModified: 1 + - name: RightArm + position: {x: -.0835753977, y: .0360959396, z: -4.69747263e-08} + rotation: {x: -.211052075, y: -.974394023, z: .0173116978, w: -.0755877271} + scale: {x: .999999821, y: 1.00000012, z: .999999702} + transformModified: 1 + - name: RightForeArm + position: {x: .253428489, y: .00601093518, z: -.0167045332} + rotation: {x: -.000616519072, y: .0220786221, z: -.0160702337, w: .999626815} + scale: {x: .99999994, y: .999999881, z: .99999994} + transformModified: 1 + - name: RightHand + position: {x: .245373741, y: .0216420237, z: .00555047346} + rotation: {x: 5.43189438e-10, y: 3.12476184e-10, z: .0214136969, w: .999770641} + scale: {x: 1, y: 1, z: 1.00000012} + transformModified: 1 + - name: RightHandIndex1 + position: {x: .0747697875, y: -.00124282821, z: .0343445241} + rotation: {x: -.00211892067, y: .0802574307, z: .0175381824, w: .996617556} + scale: {x: 1.00000012, y: 1, z: .99999994} + transformModified: 1 + - name: RightHandIndex2 + position: {x: .037058223, y: .000725421763, z: .0145388739} + rotation: {x: -.0033212963, y: .0159312561, z: .060620904, w: .998028159} + scale: {x: 1, y: .99999994, z: 1} + transformModified: 1 + - name: RightHandIndex3 + position: {x: .0252250955, y: -.00496621709, z: .0110121826} + rotation: {x: 2.16179208e-09, y: 1.06850013e-08, z: -8.50230109e-09, w: .99999994} + scale: {x: 1, y: 1.00000012, z: 1.00000012} + transformModified: 1 + - name: RightHandMiddle1 + position: {x: .0756474286, y: .00479083089, z: .0118531957} + rotation: {x: -.00076887355, y: .0333210677, z: .0209075324, w: .999225616} + scale: {x: 1.00000012, y: .999999821, z: .999999881} + transformModified: 1 + - name: RightHandMiddle2 + position: {x: .0438093096, y: .000194165463, z: .00645493949} + rotation: {x: -.0041302545, y: -.0335112214, z: .0761189237, w: .996526837} + scale: {x: 1, y: .999999881, z: 1.00000012} + transformModified: 1 + - name: RightHandMiddle3 + position: {x: .0330725648, y: -.00754737761, z: .00168985641} + rotation: {x: -3.7425496e-10, y: -4.22918101e-09, z: -1.05837286e-08, w: .99999994} + scale: {x: 1, y: .999999881, z: 1} + transformModified: 1 + - name: RightHandPinky1 + position: {x: .0668031499, y: -.00199452811, z: -.0307561476} + rotation: {x: .00317558926, y: -.192005113, z: .045110438, w: .980351448} + scale: {x: 1.00000024, y: 1, z: .99999994} + transformModified: 1 + - name: RightHandPinky2 + position: {x: .0285309609, y: -.00139694544, z: -.0116238492} + rotation: {x: -.000170628467, y: -.00966134015, z: -.00536239473, w: .999938905} + scale: {x: .999999881, y: 1, z: .99999994} + transformModified: 1 + - name: RightHandPinky3 + position: {x: .0214269403, y: -.000553725113, z: -.00851663202} + rotation: {x: -8.53474014e-10, y: 1.63788556e-08, z: -1.38467984e-08, w: .99999994} + scale: {x: 1, y: 1, z: 1.00000012} + transformModified: 1 + - name: RightHandRing1 + position: {x: .070598565, y: .00245756772, z: -.00982147083} + rotation: {x: .000710569788, y: -.054343082, z: .0349452496, w: .99791038} + scale: {x: 1.00000012, y: 1, z: 1} + transformModified: 1 + - name: RightHandRing2 + position: {x: .0428872742, y: -.0013759057, z: -.00494588772} + rotation: {x: .000482838717, y: -.0212902706, z: .0698495656, w: .997330129} + scale: {x: 1, y: 1, z: 1.00000024} + transformModified: 1 + - name: RightHandRing3 + position: {x: .0295008179, y: -.00769269653, z: -.00462226616} + rotation: {x: -2.61377653e-09, y: -8.06309508e-09, z: -6.11845863e-09, w: .99999994} + scale: {x: 1, y: 1, z: 1.00000012} + transformModified: 1 + - name: RightHandThumb1 + position: {x: .014684936, y: -.0111049525, z: .025858108} + rotation: {x: -.0128134964, y: -.00325657125, z: .031457644, w: .999417603} + scale: {x: 1.00000012, y: 1, z: 1} + transformModified: 1 + - name: RightHandThumb2 + position: {x: .0163741205, y: -.00528976135, z: .0234913807} + rotation: {x: -.0260671675, y: -.0966875851, z: -.00360274338, w: .994966805} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: RightHandThumb3 + position: {x: .0254600029, y: -.00764030218, z: .0208330136} + rotation: {x: 1.31814044e-08, y: 1.05642828e-09, z: -2.01141503e-09, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + armTwist: .5 + foreArmTwist: .5 + upperLegTwist: .5 + legTwist: .5 + armStretch: .0500000007 + legStretch: .0500000007 + feetSpacing: 0 + rootMotionBoneName: + lastHumanDescriptionAvatarSource: {fileID: 9000000, guid: e194d39a231e29a489a36758f9fb175e, + type: 3} + animationType: 3 + additionalBone: 1 + userData: diff --git a/Assets/Photon Unity Networking/Demos/Shared Assets/Animations/Jump_Land.fbx b/Assets/Photon Unity Networking/Demos/Shared Assets/Animations/Jump_Land.fbx new file mode 100644 index 0000000..9a9931e Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/Shared Assets/Animations/Jump_Land.fbx differ diff --git a/Assets/Photon Unity Networking/Demos/Shared Assets/Animations/Jump_Land.fbx.meta b/Assets/Photon Unity Networking/Demos/Shared Assets/Animations/Jump_Land.fbx.meta new file mode 100644 index 0000000..c8ab126 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/Shared Assets/Animations/Jump_Land.fbx.meta @@ -0,0 +1,953 @@ +fileFormatVersion: 2 +guid: b33e456ae548c4d4ca6c71bd1d2c203d +ModelImporter: + serializedVersion: 16 + fileIDToRecycleName: + 100000: //RootNode + 100002: Chest + 100004: Head + 100006: Hips + 100008: Jaw + 100010: JawEND + 100012: LeftArm + 100014: LeftCheek + 100016: LeftEye + 100018: LeftEyelidLower + 100020: LeftEyelidUpper + 100022: LeftFoot + 100024: LeftForeArm + 100026: LeftHand + 100028: LeftHandIndex1 + 100030: LeftHandIndex2 + 100032: LeftHandIndex3 + 100034: LeftHandMiddle1 + 100036: LeftHandMiddle2 + 100038: LeftHandMiddle3 + 100040: LeftHandPinky1 + 100042: LeftHandPinky2 + 100044: LeftHandPinky3 + 100046: LeftHandRing1 + 100048: LeftHandRing2 + 100050: LeftHandRing3 + 100052: LeftHandThumb1 + 100054: LeftHandThumb2 + 100056: LeftHandThumb3 + 100058: LeftInnerBrow + 100060: LeftIOuterBrow + 100062: LeftLeg + 100064: LeftLipCorner + 100066: LeftLipLower + 100068: LeftLipUpper + 100070: LeftNostril + 100072: LeftShoulder + 100074: LeftToes + 100076: LeftUpLeg + 100078: Neck + 100080: Reference + 100082: RightArm + 100084: RightCheek + 100086: RightEye + 100088: RightEyelidLower + 100090: RightEyelidUpper + 100092: RightFoot + 100094: RightForeArm + 100096: RightHand + 100098: RightHandIndex1 + 100100: RightHandIndex2 + 100102: RightHandIndex3 + 100104: RightHandMiddle1 + 100106: RightHandMiddle2 + 100108: RightHandMiddle3 + 100110: RightHandPinky1 + 100112: RightHandPinky2 + 100114: RightHandPinky3 + 100116: RightHandRing1 + 100118: RightHandRing2 + 100120: RightHandRing3 + 100122: RightHandThumb1 + 100124: RightHandThumb2 + 100126: RightHandThumb3 + 100128: RightInnerBrow + 100130: RightIOuterBrow + 100132: RightLeg + 100134: RightLipCorner + 100136: RightLipLower + 100138: RightLipUpper + 100140: RightNostril + 100142: RightShoulder + 100144: RightToes + 100146: RightUpLeg + 100148: Spine + 100150: TongueBack + 100152: TongueTip + 400000: //RootNode + 400002: Chest + 400004: Head + 400006: Hips + 400008: Jaw + 400010: JawEND + 400012: LeftArm + 400014: LeftCheek + 400016: LeftEye + 400018: LeftEyelidLower + 400020: LeftEyelidUpper + 400022: LeftFoot + 400024: LeftForeArm + 400026: LeftHand + 400028: LeftHandIndex1 + 400030: LeftHandIndex2 + 400032: LeftHandIndex3 + 400034: LeftHandMiddle1 + 400036: LeftHandMiddle2 + 400038: LeftHandMiddle3 + 400040: LeftHandPinky1 + 400042: LeftHandPinky2 + 400044: LeftHandPinky3 + 400046: LeftHandRing1 + 400048: LeftHandRing2 + 400050: LeftHandRing3 + 400052: LeftHandThumb1 + 400054: LeftHandThumb2 + 400056: LeftHandThumb3 + 400058: LeftInnerBrow + 400060: LeftIOuterBrow + 400062: LeftLeg + 400064: LeftLipCorner + 400066: LeftLipLower + 400068: LeftLipUpper + 400070: LeftNostril + 400072: LeftShoulder + 400074: LeftToes + 400076: LeftUpLeg + 400078: Neck + 400080: Reference + 400082: RightArm + 400084: RightCheek + 400086: RightEye + 400088: RightEyelidLower + 400090: RightEyelidUpper + 400092: RightFoot + 400094: RightForeArm + 400096: RightHand + 400098: RightHandIndex1 + 400100: RightHandIndex2 + 400102: RightHandIndex3 + 400104: RightHandMiddle1 + 400106: RightHandMiddle2 + 400108: RightHandMiddle3 + 400110: RightHandPinky1 + 400112: RightHandPinky2 + 400114: RightHandPinky3 + 400116: RightHandRing1 + 400118: RightHandRing2 + 400120: RightHandRing3 + 400122: RightHandThumb1 + 400124: RightHandThumb2 + 400126: RightHandThumb3 + 400128: RightInnerBrow + 400130: RightIOuterBrow + 400132: RightLeg + 400134: RightLipCorner + 400136: RightLipLower + 400138: RightLipUpper + 400140: RightNostril + 400142: RightShoulder + 400144: RightToes + 400146: RightUpLeg + 400148: Spine + 400150: TongueBack + 400152: TongueTip + 7400000: Jump_Land + 9500000: //RootNode + materials: + importMaterials: 1 + materialName: 0 + materialSearch: 1 + animations: + legacyGenerateAnimations: 4 + bakeSimulation: 0 + optimizeGameObjects: 0 + animationCompression: 1 + animationRotationError: .5 + animationPositionError: .5 + animationScaleError: .5 + animationWrapMode: 0 + extraExposedTransformPaths: [] + clipAnimations: + - serializedVersion: 16 + name: Jump_Land + takeName: _197_Idle_JumpDownLow_Idle + firstFrame: 187 + lastFrame: 218 + wrapMode: 0 + orientationOffsetY: 0 + level: 0 + cycleOffset: 0 + loop: 0 + loopTime: 0 + loopBlend: 0 + loopBlendOrientation: 0 + loopBlendPositionY: 0 + loopBlendPositionXZ: 0 + keepOriginalOrientation: 0 + keepOriginalPositionY: 0 + keepOriginalPositionXZ: 0 + heightFromFeet: 1 + mirror: 0 + bodyMask: 01000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000 + curves: [] + events: [] + transformMask: [] + maskType: 0 + maskSource: {instanceID: 0} + isReadable: 1 + meshes: + lODScreenPercentages: [] + globalScale: .00999999978 + meshCompression: 0 + addColliders: 0 + importBlendShapes: 1 + swapUVChannels: 0 + generateSecondaryUV: 0 + useFileUnits: 1 + optimizeMeshForGPU: 1 + weldVertices: 1 + secondaryUVAngleDistortion: 8 + secondaryUVAreaDistortion: 15.000001 + secondaryUVHardAngle: 88 + secondaryUVPackMargin: 4 + tangentSpace: + normalSmoothAngle: 60 + splitTangentsAcrossUV: 1 + normalImportMode: 0 + tangentImportMode: 1 + importAnimation: 1 + copyAvatar: 1 + humanDescription: + human: + - boneName: Hips + humanName: Hips + limit: + min: {x: -40, y: -40, z: -40} + max: {x: 40, y: 40, z: 40} + value: {x: .0748811588, y: 0, z: .0374405794} + length: .0936014801 + modified: 1 + - boneName: LeftUpLeg + humanName: LeftUpperLeg + limit: + min: {x: -60.0000038, y: -60.0000038, z: -90} + max: {x: 60.0000038, y: 60.0000038, z: 50} + value: {x: .327766716, y: 0, z: .163883358} + length: .40970853 + modified: 1 + - boneName: RightUpLeg + humanName: RightUpperLeg + limit: + min: {x: -60.0000038, y: -60.0000038, z: -90} + max: {x: 60.0000038, y: 60.0000038, z: 50} + value: {x: .327766716, y: 0, z: .163883358} + length: .40970853 + modified: 1 + - boneName: LeftLeg + humanName: LeftLowerLeg + limit: + min: {x: -90, y: 0, z: -80} + max: {x: 90, y: 0, z: 80} + value: {x: .338686436, y: 0, z: .169343218} + length: .423358172 + modified: 1 + - boneName: RightLeg + humanName: RightLowerLeg + limit: + min: {x: -90, y: 0, z: -80} + max: {x: 90, y: 0, z: 80} + value: {x: .338686436, y: 0, z: .169343218} + length: .423358172 + modified: 1 + - boneName: LeftFoot + humanName: LeftFoot + limit: + min: {x: 0, y: -30.0000019, z: -50} + max: {x: 0, y: 30.0000019, z: 50} + value: {x: .0686753467, y: 0, z: .0343376733} + length: .0858442187 + modified: 1 + - boneName: RightFoot + humanName: RightFoot + limit: + min: {x: 0, y: -30.0000019, z: -50} + max: {x: 0, y: 30.0000019, z: 50} + value: {x: .0686753467, y: 0, z: .0343376733} + length: .0858442187 + modified: 1 + - boneName: Spine + humanName: Spine + limit: + min: {x: -40, y: -40, z: -40} + max: {x: 40, y: 40, z: 40} + value: {x: .131201819, y: 0, z: .0656009093} + length: .164002344 + modified: 1 + - boneName: Chest + humanName: Chest + limit: + min: {x: -40, y: -40, z: -40} + max: {x: 40, y: 40, z: 40} + value: {x: .190353557, y: 0, z: .0951767787} + length: .237942025 + modified: 1 + - boneName: Neck + humanName: Neck + limit: + min: {x: -40, y: -40, z: -40} + max: {x: 40, y: 40, z: 40} + value: {x: .0855657607, y: 0, z: .0427828804} + length: .106957234 + modified: 1 + - boneName: Head + humanName: Head + limit: + min: {x: -40, y: -40, z: -40} + max: {x: 40, y: 40, z: 40} + value: {x: .0855657607, y: 0, z: .0427828804} + length: .106957234 + modified: 1 + - boneName: LeftShoulder + humanName: LeftShoulder + limit: + min: {x: 0, y: -15.000001, z: -15.000001} + max: {x: 0, y: 15.000001, z: 30.0000019} + value: {x: .072829701, y: 0, z: .0364148505} + length: .0910371616 + modified: 1 + - boneName: RightShoulder + humanName: RightShoulder + limit: + min: {x: 0, y: -15.000001, z: -15.000001} + max: {x: 0, y: 15.000001, z: 30.0000019} + value: {x: .072829701, y: 0, z: .0364148505} + length: .0910371616 + modified: 1 + - boneName: LeftArm + humanName: LeftUpperArm + limit: + min: {x: -90, y: -100, z: -60.0000038} + max: {x: 90, y: 100, z: 100} + value: {x: .203239605, y: 0, z: .101619802} + length: .254049569 + modified: 1 + - boneName: RightArm + humanName: RightUpperArm + limit: + min: {x: -90, y: -100, z: -60.0000038} + max: {x: 90, y: 100, z: 100} + value: {x: .203239575, y: 0, z: .101619788} + length: .25404954 + modified: 1 + - boneName: LeftForeArm + humanName: LeftLowerArm + limit: + min: {x: -90, y: 0, z: -80} + max: {x: 90, y: 0, z: 80} + value: {x: .197111532, y: 0, z: .098555766} + length: .246389478 + modified: 1 + - boneName: RightForeArm + humanName: RightLowerArm + limit: + min: {x: -90, y: 0, z: -80} + max: {x: 90, y: 0, z: 80} + value: {x: .197110936, y: 0, z: .098555468} + length: .246388748 + modified: 1 + - boneName: LeftHand + humanName: LeftHand + limit: + min: {x: 0, y: -40, z: -80} + max: {x: 0, y: 40, z: 80} + value: {x: .098555766, y: 0, z: .049277883} + length: .123194739 + modified: 1 + - boneName: RightHand + humanName: RightHand + limit: + min: {x: 0, y: -40, z: -80} + max: {x: 0, y: 40, z: 80} + value: {x: .098555468, y: 0, z: .049277734} + length: .123194374 + modified: 1 + - boneName: LeftToes + humanName: LeftToes + limit: + min: {x: 0, y: 0, z: -50} + max: {x: 0, y: 0, z: 50} + value: {x: .0651871562, y: 0, z: .0325935781} + length: .0814839825 + modified: 1 + - boneName: RightToes + humanName: RightToes + limit: + min: {x: 0, y: 0, z: -50} + max: {x: 0, y: 0, z: 50} + value: {x: .0651872903, y: 0, z: .0325936452} + length: .0814841464 + modified: 1 + - boneName: LeftEye + humanName: LeftEye + limit: + min: {x: 0, y: -20, z: -10} + max: {x: 0, y: 20, z: 15.000001} + value: {x: .0799999759, y: 0, z: .0399999879} + length: .100000001 + modified: 1 + - boneName: RightEye + humanName: RightEye + limit: + min: {x: 0, y: -20, z: -10} + max: {x: 0, y: 20, z: 15.000001} + value: {x: .0799999759, y: 0, z: .0399999879} + length: .100000001 + modified: 1 + - boneName: Jaw + humanName: Jaw + limit: + min: {x: 0, y: -10, z: -10} + max: {x: 0, y: 10, z: 10} + value: {x: .0799999759, y: 0, z: .0399999879} + length: .100000001 + modified: 1 + - boneName: LeftHandThumb1 + humanName: Left Thumb Proximal + limit: + min: {x: 0, y: -25, z: -20} + max: {x: 0, y: 25, z: 20} + value: {x: .0232954584, y: 0, z: .0116477292} + length: .0291193314 + modified: 1 + - boneName: LeftHandThumb2 + humanName: Left Thumb Intermediate + limit: + min: {x: 0, y: 0, z: -40} + max: {x: 0, y: 0, z: 35} + value: {x: .0270181261, y: 0, z: .0135090631} + length: .033772666 + modified: 1 + - boneName: LeftHandThumb3 + humanName: Left Thumb Distal + limit: + min: {x: 0, y: 0, z: -40} + max: {x: 0, y: 0, z: 35} + value: {x: .0202635936, y: 0, z: .0101317968} + length: .0253295004 + modified: 1 + - boneName: LeftHandIndex1 + humanName: Left Index Proximal + limit: + min: {x: 0, y: -20, z: -50} + max: {x: 0, y: 20, z: 50} + value: {x: .0318517797, y: 0, z: .0159258898} + length: .0398147404 + modified: 1 + - boneName: LeftHandIndex2 + humanName: Left Index Intermediate + limit: + min: {x: 0, y: 0, z: -45} + max: {x: 0, y: 0, z: 45} + value: {x: .0223747883, y: 0, z: .0111873941} + length: .0279684942 + modified: 1 + - boneName: LeftHandIndex3 + humanName: Left Index Distal + limit: + min: {x: 0, y: 0, z: -45} + max: {x: 0, y: 0, z: 45} + value: {x: .0167810898, y: 0, z: .00839054491} + length: .0209763702 + modified: 1 + - boneName: LeftHandMiddle1 + humanName: Left Middle Proximal + limit: + min: {x: 0, y: -7.50000048, z: -50} + max: {x: 0, y: 7.50000048, z: 50} + value: {x: .0354260914, y: 0, z: .0177130457} + length: .0442826301 + modified: 1 + - boneName: LeftHandMiddle2 + humanName: Left Middle Intermediate + limit: + min: {x: 0, y: 0, z: -45} + max: {x: 0, y: 0, z: 45} + value: {x: .0271718036, y: 0, z: .0135859018} + length: .0339647643 + modified: 1 + - boneName: LeftHandMiddle3 + humanName: Left Middle Distal + limit: + min: {x: 0, y: 0, z: -45} + max: {x: 0, y: 0, z: 45} + value: {x: .0203788504, y: 0, z: .0101894252} + length: .0254735723 + modified: 1 + - boneName: LeftHandRing1 + humanName: Left Ring Proximal + limit: + min: {x: 0, y: -7.50000048, z: -50} + max: {x: 0, y: 7.50000048, z: 50} + value: {x: .0345545448, y: 0, z: .0172772724} + length: .0431931987 + modified: 1 + - boneName: LeftHandRing2 + humanName: Left Ring Intermediate + limit: + min: {x: 0, y: 0, z: -45} + max: {x: 0, y: 0, z: 45} + value: {x: .0246683266, y: 0, z: .0123341633} + length: .030835418 + modified: 1 + - boneName: LeftHandRing3 + humanName: Left Ring Distal + limit: + min: {x: 0, y: 0, z: -45} + max: {x: 0, y: 0, z: 45} + value: {x: .0185012426, y: 0, z: .00925062131} + length: .0231265631 + modified: 1 + - boneName: LeftHandPinky1 + humanName: Left Little Proximal + limit: + min: {x: 0, y: -20, z: -50} + max: {x: 0, y: 20, z: 50} + value: {x: .024671508, y: 0, z: .012335754} + length: .0308393929 + modified: 1 + - boneName: LeftHandPinky2 + humanName: Left Little Intermediate + limit: + min: {x: 0, y: 0, z: -45} + max: {x: 0, y: 0, z: 45} + value: {x: .0184510797, y: 0, z: .00922553986} + length: .023063859 + modified: 1 + - boneName: LeftHandPinky3 + humanName: Left Little Distal + limit: + min: {x: 0, y: 0, z: -45} + max: {x: 0, y: 0, z: 45} + value: {x: .0138383117, y: 0, z: .00691915583} + length: .0172978938 + modified: 1 + - boneName: RightHandThumb1 + humanName: Right Thumb Proximal + limit: + min: {x: 0, y: -25, z: -20} + max: {x: 0, y: 25, z: 20} + value: {x: .0232954752, y: 0, z: .0116477376} + length: .0291193537 + modified: 1 + - boneName: RightHandThumb2 + humanName: Right Thumb Intermediate + limit: + min: {x: 0, y: 0, z: -40} + max: {x: 0, y: 0, z: 35} + value: {x: .0270181969, y: 0, z: .0135090984} + length: .0337727554 + modified: 1 + - boneName: RightHandThumb3 + humanName: Right Thumb Distal + limit: + min: {x: 0, y: 0, z: -40} + max: {x: 0, y: 0, z: 35} + value: {x: .0202636477, y: 0, z: .0101318238} + length: .0253295675 + modified: 1 + - boneName: RightHandIndex1 + humanName: Right Index Proximal + limit: + min: {x: 0, y: -20, z: -50} + max: {x: 0, y: 20, z: 50} + value: {x: .0318517946, y: 0, z: .0159258973} + length: .039814759 + modified: 1 + - boneName: RightHandIndex2 + humanName: Right Index Intermediate + limit: + min: {x: 0, y: 0, z: -45} + max: {x: 0, y: 0, z: 45} + value: {x: .0223747734, y: 0, z: .0111873867} + length: .0279684756 + modified: 1 + - boneName: RightHandIndex3 + humanName: Right Index Distal + limit: + min: {x: 0, y: 0, z: -45} + max: {x: 0, y: 0, z: 45} + value: {x: .0167810787, y: 0, z: .00839053933} + length: .0209763572 + modified: 1 + - boneName: RightHandMiddle1 + humanName: Right Middle Proximal + limit: + min: {x: 0, y: -7.50000048, z: -50} + max: {x: 0, y: 7.50000048, z: 50} + value: {x: .0354261473, y: 0, z: .0177130736} + length: .0442827009 + modified: 1 + - boneName: RightHandMiddle2 + humanName: Right Middle Intermediate + limit: + min: {x: 0, y: 0, z: -45} + max: {x: 0, y: 0, z: 45} + value: {x: .0271718968, y: 0, z: .0135859484} + length: .0339648798 + modified: 1 + - boneName: RightHandMiddle3 + humanName: Right Middle Distal + limit: + min: {x: 0, y: 0, z: -45} + max: {x: 0, y: 0, z: 45} + value: {x: .0203789212, y: 0, z: .0101894606} + length: .0254736599 + modified: 1 + - boneName: RightHandRing1 + humanName: Right Ring Proximal + limit: + min: {x: 0, y: -7.50000048, z: -50} + max: {x: 0, y: 7.50000048, z: 50} + value: {x: .0345547274, y: 0, z: .0172773637} + length: .043193426 + modified: 1 + - boneName: RightHandRing2 + humanName: Right Ring Intermediate + limit: + min: {x: 0, y: 0, z: -45} + max: {x: 0, y: 0, z: 45} + value: {x: .0246685483, y: 0, z: .0123342741} + length: .0308356937 + modified: 1 + - boneName: RightHandRing3 + humanName: Right Ring Distal + limit: + min: {x: 0, y: 0, z: -45} + max: {x: 0, y: 0, z: 45} + value: {x: .0185014084, y: 0, z: .0092507042} + length: .0231267698 + modified: 1 + - boneName: RightHandPinky1 + humanName: Right Little Proximal + limit: + min: {x: 0, y: -20, z: -50} + max: {x: 0, y: 20, z: 50} + value: {x: .0246716533, y: 0, z: .0123358266} + length: .0308395755 + modified: 1 + - boneName: RightHandPinky2 + humanName: Right Little Intermediate + limit: + min: {x: 0, y: 0, z: -45} + max: {x: 0, y: 0, z: 45} + value: {x: .018451266, y: 0, z: .009225633} + length: .0230640918 + modified: 1 + - boneName: RightHandPinky3 + humanName: Right Little Distal + limit: + min: {x: 0, y: 0, z: -45} + max: {x: 0, y: 0, z: 45} + value: {x: .0138384514, y: 0, z: .00691922568} + length: .0172980689 + modified: 1 + skeleton: + - name: DefaultAvatar + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: Reference + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: -0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: Hips + position: {x: 0, y: .963793993, z: -.0235067774} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: LeftUpLeg + position: {x: -.0754494965, y: -.0456640124, z: 0} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: LeftLeg + position: {x: -.0205505043, y: -.409129977, z: .00717136636} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: LeftFoot + position: {x: -.00515300781, y: -.423155904, z: -.0120320898} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: LeftToes + position: {x: -.00748699158, y: -.0731672645, z: .145427138} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: RightUpLeg + position: {x: .0754495338, y: -.0456640124, z: 0} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: RightLeg + position: {x: .0205504671, y: -.409129977, z: .00717136636} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: RightFoot + position: {x: .00515300035, y: -.423155904, z: -.0120320898} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: RightToes + position: {x: .00748699903, y: -.0731672645, z: .14542751} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: Spine + position: {x: 0, y: .0922632217, z: .0157713331} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: Chest + position: {x: 0, y: .162540197, z: .02185072} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: LeftShoulder + position: {x: -.0382435732, y: .192178011, z: -.017063085} + rotation: {x: -.0140067078, y: -.0595068112, z: .228689864, w: .971577883} + scale: {x: 1.00000024, y: 1, z: 1} + transformModified: 1 + - name: LeftArm + position: {x: -.083574675, y: .0360975936, z: -1.50734021e-08} + rotation: {x: .00946438964, y: .0436916873, z: -.223042384, w: .973783076} + scale: {x: 1, y: 1, z: 1.00000012} + transformModified: 1 + - name: LeftForeArm + position: {x: -.254049391, y: 4.70318128e-07, z: -2.19768759e-09} + rotation: {x: -.000616520119, y: .0220786221, z: -.0160702392, w: .999626875} + scale: {x: .99999994, y: 1, z: .999999881} + transformModified: 1 + - name: LeftHand + position: {x: -.246389359, y: -1.89769892e-07, z: -5.73217829e-09} + rotation: {x: 2.86021207e-10, y: -9.59063495e-10, z: -.0214135461, w: .999770701} + scale: {x: .99999994, y: 1, z: 1} + transformModified: 1 + - name: LeftHandIndex1 + position: {x: -.0751256943, y: -.0078413263, z: .0326526687} + rotation: {x: -.00211891974, y: .0802574307, z: .0175381806, w: .996617615} + scale: {x: 1, y: 1, z: .99999994} + transformModified: 1 + - name: LeftHandIndex2 + position: {x: -.0397970602, y: 4.9526192e-05, z: .00118574023} + rotation: {x: .000501931063, y: .0154708987, z: .040414121, w: .999063075} + scale: {x: 1.00000024, y: 1.00000024, z: .99999994} + transformModified: 1 + - name: LeftHandIndex3 + position: {x: -.0279685091, y: -1.79063633e-07, z: -9.18437095e-08} + rotation: {x: 4.33656722e-10, y: -1.75894304e-08, z: -1.0378705e-08, w: .99999994} + scale: {x: 1, y: 1.00000012, z: .999999881} + transformModified: 1 + - name: LeftHandMiddle1 + position: {x: -.0760235488, y: -.00188508059, z: .0101412414} + rotation: {x: -.000768872793, y: .0333210751, z: .0209075306, w: .999225676} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: LeftHandMiddle2 + position: {x: -.0442805924, y: 4.51253936e-06, z: -.000425422273} + rotation: {x: -.0013621418, y: -.0191537701, z: .03788976, w: .999097407} + scale: {x: 1, y: 1.00000012, z: 1} + transformModified: 1 + - name: LeftHandMiddle3 + position: {x: -.0339647792, y: 1.61085282e-07, z: 5.41929612e-09} + rotation: {x: 6.13220641e-10, y: -4.12468948e-09, z: 1.82216331e-09, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: LeftHandPinky1 + position: {x: -.0656598732, y: -.00782526191, z: -.0322512463} + rotation: {x: -.000913206837, y: .0121623212, z: .0212220512, w: .999700367} + scale: {x: 1.00000012, y: 1, z: .999999881} + transformModified: 1 + - name: LeftHandPinky2 + position: {x: -.0308053754, y: -3.11739277e-05, z: -.00144808914} + rotation: {x: -.000170628555, y: -.0096613653, z: -.00536239706, w: .999938905} + scale: {x: 1, y: .999999821, z: 1.00000012} + transformModified: 1 + - name: LeftHandPinky3 + position: {x: -.0230638776, y: -6.67785343e-06, z: 6.90349244e-09} + rotation: {x: -8.51873905e-10, y: -9.4255892e-09, z: -1.31619666e-08, w: .99999994} + scale: {x: 1, y: 1, z: .99999994} + transformModified: 1 + - name: LeftHandRing1 + position: {x: -.0703021139, y: -.00374528999, z: -.0114117898} + rotation: {x: -.000324091874, y: .0115982238, z: .0247380193, w: .999626577} + scale: {x: 1, y: 1.00000024, z: .99999994} + transformModified: 1 + - name: LeftHandRing2 + position: {x: -.0431353189, y: -2.08693382e-05, z: -.00223518023} + rotation: {x: -.0012032456, y: -.0231137592, z: .0409796387, w: .99889189} + scale: {x: .999999881, y: .999999702, z: .99999994} + transformModified: 1 + - name: LeftHandRing3 + position: {x: -.0308354236, y: -1.56879963e-07, z: -1.40963357e-08} + rotation: {x: 4.93614594e-10, y: -1.5807432e-09, z: -5.78796033e-09, w: .99999994} + scale: {x: 1, y: .99999994, z: .999999881} + transformModified: 1 + - name: LeftHandThumb1 + position: {x: -.0142313093, y: -.012377888, z: .0255316831} + rotation: {x: -.0123126386, y: -.0085253641, z: .0125855142, w: .999808609} + scale: {x: 1, y: 1, z: 1.00000012} + transformModified: 1 + - name: LeftHandThumb2 + position: {x: -.0163739249, y: -.00528992061, z: .0234914143} + rotation: {x: -.0260628555, y: .0966900289, z: .00360696716, w: .994966686} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: LeftHandThumb3 + position: {x: -.0254599936, y: -.00763992406, z: .020832995} + rotation: {x: 4.41585328e-08, y: 1.10925613e-09, z: -7.80932541e-10, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: Neck + position: {x: 0, y: .235723972, z: -.0324132554} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: Head + position: {x: 0, y: .106355786, z: .0113267824} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: Jaw + position: {x: 0, y: .0111267567, z: .0103275422} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: LeftEye + position: {x: -.0208482333, y: .0825027227, z: .0554274321} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: RightEye + position: {x: .020849999, y: .0825027227, z: .0554273948} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: RightShoulder + position: {x: .038328547, y: .192177057, z: -.0170630887} + rotation: {x: .228671983, y: .971582115, z: -.0140056778, w: -.05950737} + scale: {x: 1, y: 1.00000012, z: .99999994} + transformModified: 1 + - name: RightArm + position: {x: -.0835753977, y: .0360959396, z: -4.69747263e-08} + rotation: {x: -.21105209, y: -.974394083, z: .0173116997, w: -.0755877346} + scale: {x: .999999821, y: 1.00000012, z: .999999702} + transformModified: 1 + - name: RightForeArm + position: {x: .253428489, y: .00601093518, z: -.0167045332} + rotation: {x: -.00061651913, y: .022078624, z: -.0160702355, w: .999626875} + scale: {x: .99999994, y: .999999881, z: .99999994} + transformModified: 1 + - name: RightHand + position: {x: .245373741, y: .0216420237, z: .00555047346} + rotation: {x: 5.43189438e-10, y: 3.12476184e-10, z: .0214136969, w: .999770641} + scale: {x: 1, y: 1, z: 1.00000012} + transformModified: 1 + - name: RightHandIndex1 + position: {x: .0747697875, y: -.00124282821, z: .0343445241} + rotation: {x: -.00211892067, y: .0802574307, z: .0175381824, w: .996617556} + scale: {x: 1.00000012, y: 1, z: .99999994} + transformModified: 1 + - name: RightHandIndex2 + position: {x: .037058223, y: .000725421763, z: .0145388739} + rotation: {x: -.0033212963, y: .0159312561, z: .060620904, w: .998028159} + scale: {x: 1, y: .99999994, z: 1} + transformModified: 1 + - name: RightHandIndex3 + position: {x: .0252250955, y: -.00496621709, z: .0110121826} + rotation: {x: 2.16179208e-09, y: 1.06850013e-08, z: -8.50230109e-09, w: .99999994} + scale: {x: 1, y: 1.00000012, z: 1.00000012} + transformModified: 1 + - name: RightHandMiddle1 + position: {x: .0756474286, y: .00479083089, z: .0118531957} + rotation: {x: -.00076887355, y: .0333210677, z: .0209075324, w: .999225616} + scale: {x: 1.00000012, y: .999999821, z: .999999881} + transformModified: 1 + - name: RightHandMiddle2 + position: {x: .0438093096, y: .000194165463, z: .00645493949} + rotation: {x: -.00413025497, y: -.0335112251, z: .0761189312, w: .996526897} + scale: {x: 1, y: .999999881, z: 1.00000012} + transformModified: 1 + - name: RightHandMiddle3 + position: {x: .0330725648, y: -.00754737761, z: .00168985641} + rotation: {x: -3.7425496e-10, y: -4.22918101e-09, z: -1.05837286e-08, w: .99999994} + scale: {x: 1, y: .999999881, z: 1} + transformModified: 1 + - name: RightHandPinky1 + position: {x: .0668031499, y: -.00199452811, z: -.0307561476} + rotation: {x: .00317558926, y: -.192005113, z: .045110438, w: .980351448} + scale: {x: 1.00000024, y: 1, z: .99999994} + transformModified: 1 + - name: RightHandPinky2 + position: {x: .0285309609, y: -.00139694544, z: -.0116238492} + rotation: {x: -.000170628482, y: -.00966134109, z: -.0053623952, w: .999938965} + scale: {x: .999999881, y: 1, z: .99999994} + transformModified: 1 + - name: RightHandPinky3 + position: {x: .0214269403, y: -.000553725113, z: -.00851663202} + rotation: {x: -8.53474014e-10, y: 1.63788556e-08, z: -1.38467984e-08, w: .99999994} + scale: {x: 1, y: 1, z: 1.00000012} + transformModified: 1 + - name: RightHandRing1 + position: {x: .070598565, y: .00245756772, z: -.00982147083} + rotation: {x: .000710569788, y: -.054343082, z: .0349452496, w: .99791038} + scale: {x: 1.00000012, y: 1, z: 1} + transformModified: 1 + - name: RightHandRing2 + position: {x: .0428872742, y: -.0013759057, z: -.00494588772} + rotation: {x: .000482838717, y: -.0212902706, z: .0698495656, w: .997330129} + scale: {x: 1, y: 1, z: 1.00000024} + transformModified: 1 + - name: RightHandRing3 + position: {x: .0295008179, y: -.00769269653, z: -.00462226616} + rotation: {x: -2.61377653e-09, y: -8.06309508e-09, z: -6.11845863e-09, w: .99999994} + scale: {x: 1, y: 1, z: 1.00000012} + transformModified: 1 + - name: RightHandThumb1 + position: {x: .014684936, y: -.0111049525, z: .025858108} + rotation: {x: -.0128134973, y: -.00325657148, z: .0314576477, w: .999417663} + scale: {x: 1.00000012, y: 1, z: 1} + transformModified: 1 + - name: RightHandThumb2 + position: {x: .0163741205, y: -.00528976135, z: .0234913807} + rotation: {x: -.0260671675, y: -.0966875851, z: -.00360274338, w: .994966805} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: RightHandThumb3 + position: {x: .0254600029, y: -.00764030218, z: .0208330136} + rotation: {x: 1.31814044e-08, y: 1.05642828e-09, z: -2.01141503e-09, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + armTwist: .5 + foreArmTwist: .5 + upperLegTwist: .5 + legTwist: .5 + armStretch: .0500000007 + legStretch: .0500000007 + feetSpacing: 0 + rootMotionBoneName: + lastHumanDescriptionAvatarSource: {fileID: 9000000, guid: 2ab0893f5bba9b243b65e309e78089d0, + type: 3} + animationType: 3 + additionalBone: 0 + userData: diff --git a/Assets/Photon Unity Networking/Demos/Shared Assets/Animations/Jump_Start.fbx b/Assets/Photon Unity Networking/Demos/Shared Assets/Animations/Jump_Start.fbx new file mode 100644 index 0000000..d5575cf Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/Shared Assets/Animations/Jump_Start.fbx differ diff --git a/Assets/Photon Unity Networking/Demos/Shared Assets/Animations/Jump_Start.fbx.meta b/Assets/Photon Unity Networking/Demos/Shared Assets/Animations/Jump_Start.fbx.meta new file mode 100644 index 0000000..0fbc595 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/Shared Assets/Animations/Jump_Start.fbx.meta @@ -0,0 +1,1134 @@ +fileFormatVersion: 2 +guid: debe92d6197cd1149ae919c2aa5e90ab +ModelImporter: + serializedVersion: 16 + fileIDToRecycleName: + 100000: //RootNode + 100002: Chest + 100004: Head + 100006: Hips + 100008: Jaw + 100010: JawEND + 100012: LeftArm + 100014: LeftCheek + 100016: LeftEye + 100018: LeftEyelidLower + 100020: LeftEyelidUpper + 100022: LeftFoot + 100024: LeftForeArm + 100026: LeftHand + 100028: LeftHandIndex1 + 100030: LeftHandIndex2 + 100032: LeftHandIndex3 + 100034: LeftHandMiddle1 + 100036: LeftHandMiddle2 + 100038: LeftHandMiddle3 + 100040: LeftHandPinky1 + 100042: LeftHandPinky2 + 100044: LeftHandPinky3 + 100046: LeftHandRing1 + 100048: LeftHandRing2 + 100050: LeftHandRing3 + 100052: LeftHandThumb1 + 100054: LeftHandThumb2 + 100056: LeftHandThumb3 + 100058: LeftInnerBrow + 100060: LeftIOuterBrow + 100062: LeftLeg + 100064: LeftLipCorner + 100066: LeftLipLower + 100068: LeftLipUpper + 100070: LeftNostril + 100072: LeftShoulder + 100074: LeftToes + 100076: LeftUpLeg + 100078: Neck + 100080: Reference + 100082: RightArm + 100084: RightCheek + 100086: RightEye + 100088: RightEyelidLower + 100090: RightEyelidUpper + 100092: RightFoot + 100094: RightForeArm + 100096: RightHand + 100098: RightHandIndex1 + 100100: RightHandIndex2 + 100102: RightHandIndex3 + 100104: RightHandMiddle1 + 100106: RightHandMiddle2 + 100108: RightHandMiddle3 + 100110: RightHandPinky1 + 100112: RightHandPinky2 + 100114: RightHandPinky3 + 100116: RightHandRing1 + 100118: RightHandRing2 + 100120: RightHandRing3 + 100122: RightHandThumb1 + 100124: RightHandThumb2 + 100126: RightHandThumb3 + 100128: RightInnerBrow + 100130: RightIOuterBrow + 100132: RightLeg + 100134: RightLipCorner + 100136: RightLipLower + 100138: RightLipUpper + 100140: RightNostril + 100142: RightShoulder + 100144: RightToes + 100146: RightUpLeg + 100148: Spine + 100150: TongueBack + 100152: TongueTip + 400000: //RootNode + 400002: Chest + 400004: Head + 400006: Hips + 400008: Jaw + 400010: JawEND + 400012: LeftArm + 400014: LeftCheek + 400016: LeftEye + 400018: LeftEyelidLower + 400020: LeftEyelidUpper + 400022: LeftFoot + 400024: LeftForeArm + 400026: LeftHand + 400028: LeftHandIndex1 + 400030: LeftHandIndex2 + 400032: LeftHandIndex3 + 400034: LeftHandMiddle1 + 400036: LeftHandMiddle2 + 400038: LeftHandMiddle3 + 400040: LeftHandPinky1 + 400042: LeftHandPinky2 + 400044: LeftHandPinky3 + 400046: LeftHandRing1 + 400048: LeftHandRing2 + 400050: LeftHandRing3 + 400052: LeftHandThumb1 + 400054: LeftHandThumb2 + 400056: LeftHandThumb3 + 400058: LeftInnerBrow + 400060: LeftIOuterBrow + 400062: LeftLeg + 400064: LeftLipCorner + 400066: LeftLipLower + 400068: LeftLipUpper + 400070: LeftNostril + 400072: LeftShoulder + 400074: LeftToes + 400076: LeftUpLeg + 400078: Neck + 400080: Reference + 400082: RightArm + 400084: RightCheek + 400086: RightEye + 400088: RightEyelidLower + 400090: RightEyelidUpper + 400092: RightFoot + 400094: RightForeArm + 400096: RightHand + 400098: RightHandIndex1 + 400100: RightHandIndex2 + 400102: RightHandIndex3 + 400104: RightHandMiddle1 + 400106: RightHandMiddle2 + 400108: RightHandMiddle3 + 400110: RightHandPinky1 + 400112: RightHandPinky2 + 400114: RightHandPinky3 + 400116: RightHandRing1 + 400118: RightHandRing2 + 400120: RightHandRing3 + 400122: RightHandThumb1 + 400124: RightHandThumb2 + 400126: RightHandThumb3 + 400128: RightInnerBrow + 400130: RightIOuterBrow + 400132: RightLeg + 400134: RightLipCorner + 400136: RightLipLower + 400138: RightLipUpper + 400140: RightNostril + 400142: RightShoulder + 400144: RightToes + 400146: RightUpLeg + 400148: Spine + 400150: TongueBack + 400152: TongueTip + 7400000: Jump_Start + 7400002: Jump_Air + 9500000: //RootNode + materials: + importMaterials: 1 + materialName: 0 + materialSearch: 1 + animations: + legacyGenerateAnimations: 4 + bakeSimulation: 0 + optimizeGameObjects: 0 + animationCompression: 1 + animationRotationError: .5 + animationPositionError: .5 + animationScaleError: .5 + animationWrapMode: 0 + extraExposedTransformPaths: [] + clipAnimations: + - serializedVersion: 16 + name: Jump_Start + takeName: _207_Idle_JumpUpMedium_NoHands1Step_Idle + firstFrame: 116 + lastFrame: 130 + wrapMode: 0 + orientationOffsetY: 0 + level: 0 + cycleOffset: 0 + loop: 0 + loopTime: 0 + loopBlend: 0 + loopBlendOrientation: 0 + loopBlendPositionY: 0 + loopBlendPositionXZ: 0 + keepOriginalOrientation: 0 + keepOriginalPositionY: 0 + keepOriginalPositionXZ: 0 + heightFromFeet: 1 + mirror: 0 + bodyMask: 01000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000 + curves: [] + events: [] + transformMask: [] + maskType: 0 + maskSource: {instanceID: 0} + - serializedVersion: 16 + name: Jump_Air + takeName: _207_Idle_JumpUpMedium_NoHands1Step_Idle + firstFrame: 130 + lastFrame: 130.100006 + wrapMode: 0 + orientationOffsetY: 0 + level: 0 + cycleOffset: 0 + loop: 0 + loopTime: 0 + loopBlend: 0 + loopBlendOrientation: 0 + loopBlendPositionY: 1 + loopBlendPositionXZ: 0 + keepOriginalOrientation: 0 + keepOriginalPositionY: 0 + keepOriginalPositionXZ: 0 + heightFromFeet: 1 + mirror: 0 + bodyMask: 01000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000 + curves: [] + events: [] + transformMask: + - path: + weight: 1 + - path: Reference + weight: 1 + - path: Reference/Hips + weight: 1 + - path: Reference/Hips/LeftUpLeg + weight: 1 + - path: Reference/Hips/LeftUpLeg/LeftLeg + weight: 1 + - path: Reference/Hips/LeftUpLeg/LeftLeg/LeftFoot + weight: 1 + - path: Reference/Hips/LeftUpLeg/LeftLeg/LeftFoot/LeftToes + weight: 1 + - path: Reference/Hips/RightUpLeg + weight: 1 + - path: Reference/Hips/RightUpLeg/RightLeg + weight: 1 + - path: Reference/Hips/RightUpLeg/RightLeg/RightFoot + weight: 1 + - path: Reference/Hips/RightUpLeg/RightLeg/RightFoot/RightToes + weight: 1 + - path: Reference/Hips/Spine + weight: 1 + - path: Reference/Hips/Spine/Chest + weight: 1 + - path: Reference/Hips/Spine/Chest/LeftShoulder + weight: 1 + - path: Reference/Hips/Spine/Chest/LeftShoulder/LeftArm + weight: 1 + - path: Reference/Hips/Spine/Chest/LeftShoulder/LeftArm/LeftForeArm + weight: 1 + - path: Reference/Hips/Spine/Chest/LeftShoulder/LeftArm/LeftForeArm/LeftHand + weight: 1 + - path: Reference/Hips/Spine/Chest/LeftShoulder/LeftArm/LeftForeArm/LeftHand/LeftHandIndex1 + weight: 1 + - path: Reference/Hips/Spine/Chest/LeftShoulder/LeftArm/LeftForeArm/LeftHand/LeftHandIndex1/LeftHandIndex2 + weight: 1 + - path: Reference/Hips/Spine/Chest/LeftShoulder/LeftArm/LeftForeArm/LeftHand/LeftHandIndex1/LeftHandIndex2/LeftHandIndex3 + weight: 1 + - path: Reference/Hips/Spine/Chest/LeftShoulder/LeftArm/LeftForeArm/LeftHand/LeftHandMiddle1 + weight: 1 + - path: Reference/Hips/Spine/Chest/LeftShoulder/LeftArm/LeftForeArm/LeftHand/LeftHandMiddle1/LeftHandMiddle2 + weight: 1 + - path: Reference/Hips/Spine/Chest/LeftShoulder/LeftArm/LeftForeArm/LeftHand/LeftHandMiddle1/LeftHandMiddle2/LeftHandMiddle3 + weight: 1 + - path: Reference/Hips/Spine/Chest/LeftShoulder/LeftArm/LeftForeArm/LeftHand/LeftHandPinky1 + weight: 1 + - path: Reference/Hips/Spine/Chest/LeftShoulder/LeftArm/LeftForeArm/LeftHand/LeftHandPinky1/LeftHandPinky2 + weight: 1 + - path: Reference/Hips/Spine/Chest/LeftShoulder/LeftArm/LeftForeArm/LeftHand/LeftHandPinky1/LeftHandPinky2/LeftHandPinky3 + weight: 1 + - path: Reference/Hips/Spine/Chest/LeftShoulder/LeftArm/LeftForeArm/LeftHand/LeftHandRing1 + weight: 1 + - path: Reference/Hips/Spine/Chest/LeftShoulder/LeftArm/LeftForeArm/LeftHand/LeftHandRing1/LeftHandRing2 + weight: 1 + - path: Reference/Hips/Spine/Chest/LeftShoulder/LeftArm/LeftForeArm/LeftHand/LeftHandRing1/LeftHandRing2/LeftHandRing3 + weight: 1 + - path: Reference/Hips/Spine/Chest/LeftShoulder/LeftArm/LeftForeArm/LeftHand/LeftHandThumb1 + weight: 1 + - path: Reference/Hips/Spine/Chest/LeftShoulder/LeftArm/LeftForeArm/LeftHand/LeftHandThumb1/LeftHandThumb2 + weight: 1 + - path: Reference/Hips/Spine/Chest/LeftShoulder/LeftArm/LeftForeArm/LeftHand/LeftHandThumb1/LeftHandThumb2/LeftHandThumb3 + weight: 1 + - path: Reference/Hips/Spine/Chest/Neck + weight: 1 + - path: Reference/Hips/Spine/Chest/Neck/Head + weight: 1 + - path: Reference/Hips/Spine/Chest/Neck/Head/Jaw + weight: 1 + - path: Reference/Hips/Spine/Chest/Neck/Head/Jaw/JawEND + weight: 0 + - path: Reference/Hips/Spine/Chest/Neck/Head/Jaw/LeftLipCorner + weight: 0 + - path: Reference/Hips/Spine/Chest/Neck/Head/Jaw/LeftLipLower + weight: 0 + - path: Reference/Hips/Spine/Chest/Neck/Head/Jaw/RightLipCorner + weight: 0 + - path: Reference/Hips/Spine/Chest/Neck/Head/Jaw/RightLipLower + weight: 0 + - path: Reference/Hips/Spine/Chest/Neck/Head/Jaw/TongueBack + weight: 0 + - path: Reference/Hips/Spine/Chest/Neck/Head/Jaw/TongueTip + weight: 0 + - path: Reference/Hips/Spine/Chest/Neck/Head/LeftCheek + weight: 0 + - path: Reference/Hips/Spine/Chest/Neck/Head/LeftEye + weight: 1 + - path: Reference/Hips/Spine/Chest/Neck/Head/LeftEyelidLower + weight: 0 + - path: Reference/Hips/Spine/Chest/Neck/Head/LeftEyelidUpper + weight: 0 + - path: Reference/Hips/Spine/Chest/Neck/Head/LeftInnerBrow + weight: 0 + - path: Reference/Hips/Spine/Chest/Neck/Head/LeftIOuterBrow + weight: 0 + - path: Reference/Hips/Spine/Chest/Neck/Head/LeftLipUpper + weight: 0 + - path: Reference/Hips/Spine/Chest/Neck/Head/LeftNostril + weight: 0 + - path: Reference/Hips/Spine/Chest/Neck/Head/RightCheek + weight: 0 + - path: Reference/Hips/Spine/Chest/Neck/Head/RightEye + weight: 1 + - path: Reference/Hips/Spine/Chest/Neck/Head/RightEyelidLower + weight: 0 + - path: Reference/Hips/Spine/Chest/Neck/Head/RightEyelidUpper + weight: 0 + - path: Reference/Hips/Spine/Chest/Neck/Head/RightInnerBrow + weight: 0 + - path: Reference/Hips/Spine/Chest/Neck/Head/RightIOuterBrow + weight: 0 + - path: Reference/Hips/Spine/Chest/Neck/Head/RightLipUpper + weight: 0 + - path: Reference/Hips/Spine/Chest/Neck/Head/RightNostril + weight: 0 + - path: Reference/Hips/Spine/Chest/RightShoulder + weight: 1 + - path: Reference/Hips/Spine/Chest/RightShoulder/RightArm + weight: 1 + - path: Reference/Hips/Spine/Chest/RightShoulder/RightArm/RightForeArm + weight: 1 + - path: Reference/Hips/Spine/Chest/RightShoulder/RightArm/RightForeArm/RightHand + weight: 1 + - path: Reference/Hips/Spine/Chest/RightShoulder/RightArm/RightForeArm/RightHand/RightHandIndex1 + weight: 1 + - path: Reference/Hips/Spine/Chest/RightShoulder/RightArm/RightForeArm/RightHand/RightHandIndex1/RightHandIndex2 + weight: 1 + - path: Reference/Hips/Spine/Chest/RightShoulder/RightArm/RightForeArm/RightHand/RightHandIndex1/RightHandIndex2/RightHandIndex3 + weight: 1 + - path: Reference/Hips/Spine/Chest/RightShoulder/RightArm/RightForeArm/RightHand/RightHandMiddle1 + weight: 1 + - path: Reference/Hips/Spine/Chest/RightShoulder/RightArm/RightForeArm/RightHand/RightHandMiddle1/RightHandMiddle2 + weight: 1 + - path: Reference/Hips/Spine/Chest/RightShoulder/RightArm/RightForeArm/RightHand/RightHandMiddle1/RightHandMiddle2/RightHandMiddle3 + weight: 1 + - path: Reference/Hips/Spine/Chest/RightShoulder/RightArm/RightForeArm/RightHand/RightHandPinky1 + weight: 1 + - path: Reference/Hips/Spine/Chest/RightShoulder/RightArm/RightForeArm/RightHand/RightHandPinky1/RightHandPinky2 + weight: 1 + - path: Reference/Hips/Spine/Chest/RightShoulder/RightArm/RightForeArm/RightHand/RightHandPinky1/RightHandPinky2/RightHandPinky3 + weight: 1 + - path: Reference/Hips/Spine/Chest/RightShoulder/RightArm/RightForeArm/RightHand/RightHandRing1 + weight: 1 + - path: Reference/Hips/Spine/Chest/RightShoulder/RightArm/RightForeArm/RightHand/RightHandRing1/RightHandRing2 + weight: 1 + - path: Reference/Hips/Spine/Chest/RightShoulder/RightArm/RightForeArm/RightHand/RightHandRing1/RightHandRing2/RightHandRing3 + weight: 1 + - path: Reference/Hips/Spine/Chest/RightShoulder/RightArm/RightForeArm/RightHand/RightHandThumb1 + weight: 1 + - path: Reference/Hips/Spine/Chest/RightShoulder/RightArm/RightForeArm/RightHand/RightHandThumb1/RightHandThumb2 + weight: 1 + - path: Reference/Hips/Spine/Chest/RightShoulder/RightArm/RightForeArm/RightHand/RightHandThumb1/RightHandThumb2/RightHandThumb3 + weight: 1 + maskType: 0 + maskSource: {instanceID: 0} + isReadable: 1 + meshes: + lODScreenPercentages: [] + globalScale: .00999999978 + meshCompression: 0 + addColliders: 0 + importBlendShapes: 1 + swapUVChannels: 0 + generateSecondaryUV: 0 + useFileUnits: 1 + optimizeMeshForGPU: 1 + weldVertices: 1 + secondaryUVAngleDistortion: 8 + secondaryUVAreaDistortion: 15.000001 + secondaryUVHardAngle: 88 + secondaryUVPackMargin: 4 + tangentSpace: + normalSmoothAngle: 60 + splitTangentsAcrossUV: 1 + normalImportMode: 0 + tangentImportMode: 1 + importAnimation: 1 + copyAvatar: 1 + humanDescription: + human: + - boneName: Hips + humanName: Hips + limit: + min: {x: -40, y: -40, z: -40} + max: {x: 40, y: 40, z: 40} + value: {x: .0748811588, y: 0, z: .0374405794} + length: .0936014801 + modified: 1 + - boneName: LeftUpLeg + humanName: LeftUpperLeg + limit: + min: {x: -60.0000038, y: -60.0000038, z: -90} + max: {x: 60.0000038, y: 60.0000038, z: 50} + value: {x: .327766716, y: 0, z: .163883358} + length: .40970853 + modified: 1 + - boneName: RightUpLeg + humanName: RightUpperLeg + limit: + min: {x: -60.0000038, y: -60.0000038, z: -90} + max: {x: 60.0000038, y: 60.0000038, z: 50} + value: {x: .327766716, y: 0, z: .163883358} + length: .40970853 + modified: 1 + - boneName: LeftLeg + humanName: LeftLowerLeg + limit: + min: {x: -90, y: 0, z: -80} + max: {x: 90, y: 0, z: 80} + value: {x: .338686436, y: 0, z: .169343218} + length: .423358172 + modified: 1 + - boneName: RightLeg + humanName: RightLowerLeg + limit: + min: {x: -90, y: 0, z: -80} + max: {x: 90, y: 0, z: 80} + value: {x: .338686436, y: 0, z: .169343218} + length: .423358172 + modified: 1 + - boneName: LeftFoot + humanName: LeftFoot + limit: + min: {x: 0, y: -30.0000019, z: -50} + max: {x: 0, y: 30.0000019, z: 50} + value: {x: .0686753467, y: 0, z: .0343376733} + length: .0858442187 + modified: 1 + - boneName: RightFoot + humanName: RightFoot + limit: + min: {x: 0, y: -30.0000019, z: -50} + max: {x: 0, y: 30.0000019, z: 50} + value: {x: .0686753467, y: 0, z: .0343376733} + length: .0858442187 + modified: 1 + - boneName: Spine + humanName: Spine + limit: + min: {x: -40, y: -40, z: -40} + max: {x: 40, y: 40, z: 40} + value: {x: .131201819, y: 0, z: .0656009093} + length: .164002344 + modified: 1 + - boneName: Chest + humanName: Chest + limit: + min: {x: -40, y: -40, z: -40} + max: {x: 40, y: 40, z: 40} + value: {x: .190353557, y: 0, z: .0951767787} + length: .237942025 + modified: 1 + - boneName: Neck + humanName: Neck + limit: + min: {x: -40, y: -40, z: -40} + max: {x: 40, y: 40, z: 40} + value: {x: .0855657607, y: 0, z: .0427828804} + length: .106957234 + modified: 1 + - boneName: Head + humanName: Head + limit: + min: {x: -40, y: -40, z: -40} + max: {x: 40, y: 40, z: 40} + value: {x: .0855657607, y: 0, z: .0427828804} + length: .106957234 + modified: 1 + - boneName: LeftShoulder + humanName: LeftShoulder + limit: + min: {x: 0, y: -15.000001, z: -15.000001} + max: {x: 0, y: 15.000001, z: 30.0000019} + value: {x: .072829701, y: 0, z: .0364148505} + length: .0910371616 + modified: 1 + - boneName: RightShoulder + humanName: RightShoulder + limit: + min: {x: 0, y: -15.000001, z: -15.000001} + max: {x: 0, y: 15.000001, z: 30.0000019} + value: {x: .072829701, y: 0, z: .0364148505} + length: .0910371616 + modified: 1 + - boneName: LeftArm + humanName: LeftUpperArm + limit: + min: {x: -90, y: -100, z: -60.0000038} + max: {x: 90, y: 100, z: 100} + value: {x: .203239605, y: 0, z: .101619802} + length: .254049569 + modified: 1 + - boneName: RightArm + humanName: RightUpperArm + limit: + min: {x: -90, y: -100, z: -60.0000038} + max: {x: 90, y: 100, z: 100} + value: {x: .203239575, y: 0, z: .101619788} + length: .25404954 + modified: 1 + - boneName: LeftForeArm + humanName: LeftLowerArm + limit: + min: {x: -90, y: 0, z: -80} + max: {x: 90, y: 0, z: 80} + value: {x: .197111532, y: 0, z: .098555766} + length: .246389478 + modified: 1 + - boneName: RightForeArm + humanName: RightLowerArm + limit: + min: {x: -90, y: 0, z: -80} + max: {x: 90, y: 0, z: 80} + value: {x: .197110936, y: 0, z: .098555468} + length: .246388748 + modified: 1 + - boneName: LeftHand + humanName: LeftHand + limit: + min: {x: 0, y: -40, z: -80} + max: {x: 0, y: 40, z: 80} + value: {x: .098555766, y: 0, z: .049277883} + length: .123194739 + modified: 1 + - boneName: RightHand + humanName: RightHand + limit: + min: {x: 0, y: -40, z: -80} + max: {x: 0, y: 40, z: 80} + value: {x: .098555468, y: 0, z: .049277734} + length: .123194374 + modified: 1 + - boneName: LeftToes + humanName: LeftToes + limit: + min: {x: 0, y: 0, z: -50} + max: {x: 0, y: 0, z: 50} + value: {x: .0651871562, y: 0, z: .0325935781} + length: .0814839825 + modified: 1 + - boneName: RightToes + humanName: RightToes + limit: + min: {x: 0, y: 0, z: -50} + max: {x: 0, y: 0, z: 50} + value: {x: .0651872903, y: 0, z: .0325936452} + length: .0814841464 + modified: 1 + - boneName: LeftEye + humanName: LeftEye + limit: + min: {x: 0, y: -20, z: -10} + max: {x: 0, y: 20, z: 15.000001} + value: {x: .0799999759, y: 0, z: .0399999879} + length: .100000001 + modified: 1 + - boneName: RightEye + humanName: RightEye + limit: + min: {x: 0, y: -20, z: -10} + max: {x: 0, y: 20, z: 15.000001} + value: {x: .0799999759, y: 0, z: .0399999879} + length: .100000001 + modified: 1 + - boneName: Jaw + humanName: Jaw + limit: + min: {x: 0, y: -10, z: -10} + max: {x: 0, y: 10, z: 10} + value: {x: .0799999759, y: 0, z: .0399999879} + length: .100000001 + modified: 1 + - boneName: LeftHandThumb1 + humanName: Left Thumb Proximal + limit: + min: {x: 0, y: -25, z: -20} + max: {x: 0, y: 25, z: 20} + value: {x: .0232954584, y: 0, z: .0116477292} + length: .0291193314 + modified: 1 + - boneName: LeftHandThumb2 + humanName: Left Thumb Intermediate + limit: + min: {x: 0, y: 0, z: -40} + max: {x: 0, y: 0, z: 35} + value: {x: .0270181261, y: 0, z: .0135090631} + length: .033772666 + modified: 1 + - boneName: LeftHandThumb3 + humanName: Left Thumb Distal + limit: + min: {x: 0, y: 0, z: -40} + max: {x: 0, y: 0, z: 35} + value: {x: .0202635936, y: 0, z: .0101317968} + length: .0253295004 + modified: 1 + - boneName: LeftHandIndex1 + humanName: Left Index Proximal + limit: + min: {x: 0, y: -20, z: -50} + max: {x: 0, y: 20, z: 50} + value: {x: .0318517797, y: 0, z: .0159258898} + length: .0398147404 + modified: 1 + - boneName: LeftHandIndex2 + humanName: Left Index Intermediate + limit: + min: {x: 0, y: 0, z: -45} + max: {x: 0, y: 0, z: 45} + value: {x: .0223747883, y: 0, z: .0111873941} + length: .0279684942 + modified: 1 + - boneName: LeftHandIndex3 + humanName: Left Index Distal + limit: + min: {x: 0, y: 0, z: -45} + max: {x: 0, y: 0, z: 45} + value: {x: .0167810898, y: 0, z: .00839054491} + length: .0209763702 + modified: 1 + - boneName: LeftHandMiddle1 + humanName: Left Middle Proximal + limit: + min: {x: 0, y: -7.50000048, z: -50} + max: {x: 0, y: 7.50000048, z: 50} + value: {x: .0354260914, y: 0, z: .0177130457} + length: .0442826301 + modified: 1 + - boneName: LeftHandMiddle2 + humanName: Left Middle Intermediate + limit: + min: {x: 0, y: 0, z: -45} + max: {x: 0, y: 0, z: 45} + value: {x: .0271718036, y: 0, z: .0135859018} + length: .0339647643 + modified: 1 + - boneName: LeftHandMiddle3 + humanName: Left Middle Distal + limit: + min: {x: 0, y: 0, z: -45} + max: {x: 0, y: 0, z: 45} + value: {x: .0203788504, y: 0, z: .0101894252} + length: .0254735723 + modified: 1 + - boneName: LeftHandRing1 + humanName: Left Ring Proximal + limit: + min: {x: 0, y: -7.50000048, z: -50} + max: {x: 0, y: 7.50000048, z: 50} + value: {x: .0345545448, y: 0, z: .0172772724} + length: .0431931987 + modified: 1 + - boneName: LeftHandRing2 + humanName: Left Ring Intermediate + limit: + min: {x: 0, y: 0, z: -45} + max: {x: 0, y: 0, z: 45} + value: {x: .0246683266, y: 0, z: .0123341633} + length: .030835418 + modified: 1 + - boneName: LeftHandRing3 + humanName: Left Ring Distal + limit: + min: {x: 0, y: 0, z: -45} + max: {x: 0, y: 0, z: 45} + value: {x: .0185012426, y: 0, z: .00925062131} + length: .0231265631 + modified: 1 + - boneName: LeftHandPinky1 + humanName: Left Little Proximal + limit: + min: {x: 0, y: -20, z: -50} + max: {x: 0, y: 20, z: 50} + value: {x: .024671508, y: 0, z: .012335754} + length: .0308393929 + modified: 1 + - boneName: LeftHandPinky2 + humanName: Left Little Intermediate + limit: + min: {x: 0, y: 0, z: -45} + max: {x: 0, y: 0, z: 45} + value: {x: .0184510797, y: 0, z: .00922553986} + length: .023063859 + modified: 1 + - boneName: LeftHandPinky3 + humanName: Left Little Distal + limit: + min: {x: 0, y: 0, z: -45} + max: {x: 0, y: 0, z: 45} + value: {x: .0138383117, y: 0, z: .00691915583} + length: .0172978938 + modified: 1 + - boneName: RightHandThumb1 + humanName: Right Thumb Proximal + limit: + min: {x: 0, y: -25, z: -20} + max: {x: 0, y: 25, z: 20} + value: {x: .0232954752, y: 0, z: .0116477376} + length: .0291193537 + modified: 1 + - boneName: RightHandThumb2 + humanName: Right Thumb Intermediate + limit: + min: {x: 0, y: 0, z: -40} + max: {x: 0, y: 0, z: 35} + value: {x: .0270181969, y: 0, z: .0135090984} + length: .0337727554 + modified: 1 + - boneName: RightHandThumb3 + humanName: Right Thumb Distal + limit: + min: {x: 0, y: 0, z: -40} + max: {x: 0, y: 0, z: 35} + value: {x: .0202636477, y: 0, z: .0101318238} + length: .0253295675 + modified: 1 + - boneName: RightHandIndex1 + humanName: Right Index Proximal + limit: + min: {x: 0, y: -20, z: -50} + max: {x: 0, y: 20, z: 50} + value: {x: .0318517946, y: 0, z: .0159258973} + length: .039814759 + modified: 1 + - boneName: RightHandIndex2 + humanName: Right Index Intermediate + limit: + min: {x: 0, y: 0, z: -45} + max: {x: 0, y: 0, z: 45} + value: {x: .0223747734, y: 0, z: .0111873867} + length: .0279684756 + modified: 1 + - boneName: RightHandIndex3 + humanName: Right Index Distal + limit: + min: {x: 0, y: 0, z: -45} + max: {x: 0, y: 0, z: 45} + value: {x: .0167810787, y: 0, z: .00839053933} + length: .0209763572 + modified: 1 + - boneName: RightHandMiddle1 + humanName: Right Middle Proximal + limit: + min: {x: 0, y: -7.50000048, z: -50} + max: {x: 0, y: 7.50000048, z: 50} + value: {x: .0354261473, y: 0, z: .0177130736} + length: .0442827009 + modified: 1 + - boneName: RightHandMiddle2 + humanName: Right Middle Intermediate + limit: + min: {x: 0, y: 0, z: -45} + max: {x: 0, y: 0, z: 45} + value: {x: .0271718968, y: 0, z: .0135859484} + length: .0339648798 + modified: 1 + - boneName: RightHandMiddle3 + humanName: Right Middle Distal + limit: + min: {x: 0, y: 0, z: -45} + max: {x: 0, y: 0, z: 45} + value: {x: .0203789212, y: 0, z: .0101894606} + length: .0254736599 + modified: 1 + - boneName: RightHandRing1 + humanName: Right Ring Proximal + limit: + min: {x: 0, y: -7.50000048, z: -50} + max: {x: 0, y: 7.50000048, z: 50} + value: {x: .0345547274, y: 0, z: .0172773637} + length: .043193426 + modified: 1 + - boneName: RightHandRing2 + humanName: Right Ring Intermediate + limit: + min: {x: 0, y: 0, z: -45} + max: {x: 0, y: 0, z: 45} + value: {x: .0246685483, y: 0, z: .0123342741} + length: .0308356937 + modified: 1 + - boneName: RightHandRing3 + humanName: Right Ring Distal + limit: + min: {x: 0, y: 0, z: -45} + max: {x: 0, y: 0, z: 45} + value: {x: .0185014084, y: 0, z: .0092507042} + length: .0231267698 + modified: 1 + - boneName: RightHandPinky1 + humanName: Right Little Proximal + limit: + min: {x: 0, y: -20, z: -50} + max: {x: 0, y: 20, z: 50} + value: {x: .0246716533, y: 0, z: .0123358266} + length: .0308395755 + modified: 1 + - boneName: RightHandPinky2 + humanName: Right Little Intermediate + limit: + min: {x: 0, y: 0, z: -45} + max: {x: 0, y: 0, z: 45} + value: {x: .018451266, y: 0, z: .009225633} + length: .0230640918 + modified: 1 + - boneName: RightHandPinky3 + humanName: Right Little Distal + limit: + min: {x: 0, y: 0, z: -45} + max: {x: 0, y: 0, z: 45} + value: {x: .0138384514, y: 0, z: .00691922568} + length: .0172980689 + modified: 1 + skeleton: + - name: DefaultAvatar + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: Reference + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: -0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: Hips + position: {x: 0, y: .963793993, z: -.0235067774} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: LeftUpLeg + position: {x: -.0754494965, y: -.0456640124, z: 0} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: LeftLeg + position: {x: -.0205505043, y: -.409129977, z: .00717136636} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: LeftFoot + position: {x: -.00515300781, y: -.423155904, z: -.0120320898} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: LeftToes + position: {x: -.00748699158, y: -.0731672645, z: .145427138} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: RightUpLeg + position: {x: .0754495338, y: -.0456640124, z: 0} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: RightLeg + position: {x: .0205504671, y: -.409129977, z: .00717136636} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: RightFoot + position: {x: .00515300035, y: -.423155904, z: -.0120320898} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: RightToes + position: {x: .00748699903, y: -.0731672645, z: .14542751} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: Spine + position: {x: 0, y: .0922632217, z: .0157713331} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: Chest + position: {x: 0, y: .162540197, z: .02185072} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: LeftShoulder + position: {x: -.0382435732, y: .192178011, z: -.017063085} + rotation: {x: -.0140067078, y: -.0595068112, z: .228689864, w: .971577883} + scale: {x: 1.00000024, y: 1, z: 1} + transformModified: 1 + - name: LeftArm + position: {x: -.083574675, y: .0360975936, z: -1.50734021e-08} + rotation: {x: .00946438964, y: .0436916873, z: -.223042384, w: .973783076} + scale: {x: 1, y: 1, z: 1.00000012} + transformModified: 1 + - name: LeftForeArm + position: {x: -.254049391, y: 4.70318128e-07, z: -2.19768759e-09} + rotation: {x: -.000616520119, y: .0220786221, z: -.0160702392, w: .999626875} + scale: {x: .99999994, y: 1, z: .999999881} + transformModified: 1 + - name: LeftHand + position: {x: -.246389359, y: -1.89769892e-07, z: -5.73217829e-09} + rotation: {x: 2.86021207e-10, y: -9.59063495e-10, z: -.0214135461, w: .999770701} + scale: {x: .99999994, y: 1, z: 1} + transformModified: 1 + - name: LeftHandIndex1 + position: {x: -.0751256943, y: -.0078413263, z: .0326526687} + rotation: {x: -.00211891974, y: .0802574307, z: .0175381806, w: .996617615} + scale: {x: 1, y: 1, z: .99999994} + transformModified: 1 + - name: LeftHandIndex2 + position: {x: -.0397970602, y: 4.9526192e-05, z: .00118574023} + rotation: {x: .000501931063, y: .0154708987, z: .040414121, w: .999063075} + scale: {x: 1.00000024, y: 1.00000024, z: .99999994} + transformModified: 1 + - name: LeftHandIndex3 + position: {x: -.0279685091, y: -1.79063633e-07, z: -9.18437095e-08} + rotation: {x: 4.33656722e-10, y: -1.75894304e-08, z: -1.0378705e-08, w: .99999994} + scale: {x: 1, y: 1.00000012, z: .999999881} + transformModified: 1 + - name: LeftHandMiddle1 + position: {x: -.0760235488, y: -.00188508059, z: .0101412414} + rotation: {x: -.000768872793, y: .0333210751, z: .0209075306, w: .999225676} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: LeftHandMiddle2 + position: {x: -.0442805924, y: 4.51253936e-06, z: -.000425422273} + rotation: {x: -.0013621418, y: -.0191537701, z: .03788976, w: .999097407} + scale: {x: 1, y: 1.00000012, z: 1} + transformModified: 1 + - name: LeftHandMiddle3 + position: {x: -.0339647792, y: 1.61085282e-07, z: 5.41929612e-09} + rotation: {x: 6.13220641e-10, y: -4.12468948e-09, z: 1.82216331e-09, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: LeftHandPinky1 + position: {x: -.0656598732, y: -.00782526191, z: -.0322512463} + rotation: {x: -.000913206837, y: .0121623212, z: .0212220512, w: .999700367} + scale: {x: 1.00000012, y: 1, z: .999999881} + transformModified: 1 + - name: LeftHandPinky2 + position: {x: -.0308053754, y: -3.11739277e-05, z: -.00144808914} + rotation: {x: -.000170628555, y: -.0096613653, z: -.00536239706, w: .999938905} + scale: {x: 1, y: .999999821, z: 1.00000012} + transformModified: 1 + - name: LeftHandPinky3 + position: {x: -.0230638776, y: -6.67785343e-06, z: 6.90349244e-09} + rotation: {x: -8.51873905e-10, y: -9.4255892e-09, z: -1.31619666e-08, w: .99999994} + scale: {x: 1, y: 1, z: .99999994} + transformModified: 1 + - name: LeftHandRing1 + position: {x: -.0703021139, y: -.00374528999, z: -.0114117898} + rotation: {x: -.000324091874, y: .0115982238, z: .0247380193, w: .999626577} + scale: {x: 1, y: 1.00000024, z: .99999994} + transformModified: 1 + - name: LeftHandRing2 + position: {x: -.0431353189, y: -2.08693382e-05, z: -.00223518023} + rotation: {x: -.0012032456, y: -.0231137592, z: .0409796387, w: .99889189} + scale: {x: .999999881, y: .999999702, z: .99999994} + transformModified: 1 + - name: LeftHandRing3 + position: {x: -.0308354236, y: -1.56879963e-07, z: -1.40963357e-08} + rotation: {x: 4.93614594e-10, y: -1.5807432e-09, z: -5.78796033e-09, w: .99999994} + scale: {x: 1, y: .99999994, z: .999999881} + transformModified: 1 + - name: LeftHandThumb1 + position: {x: -.0142313093, y: -.012377888, z: .0255316831} + rotation: {x: -.0123126386, y: -.0085253641, z: .0125855142, w: .999808609} + scale: {x: 1, y: 1, z: 1.00000012} + transformModified: 1 + - name: LeftHandThumb2 + position: {x: -.0163739249, y: -.00528992061, z: .0234914143} + rotation: {x: -.0260628555, y: .0966900289, z: .00360696716, w: .994966686} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: LeftHandThumb3 + position: {x: -.0254599936, y: -.00763992406, z: .020832995} + rotation: {x: 4.41585328e-08, y: 1.10925613e-09, z: -7.80932541e-10, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: Neck + position: {x: 0, y: .235723972, z: -.0324132554} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: Head + position: {x: 0, y: .106355786, z: .0113267824} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: Jaw + position: {x: 0, y: .0111267567, z: .0103275422} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: LeftEye + position: {x: -.0208482333, y: .0825027227, z: .0554274321} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: RightEye + position: {x: .020849999, y: .0825027227, z: .0554273948} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: RightShoulder + position: {x: .038328547, y: .192177057, z: -.0170630887} + rotation: {x: .228671983, y: .971582115, z: -.0140056778, w: -.05950737} + scale: {x: 1, y: 1.00000012, z: .99999994} + transformModified: 1 + - name: RightArm + position: {x: -.0835753977, y: .0360959396, z: -4.69747263e-08} + rotation: {x: -.21105209, y: -.974394083, z: .0173116997, w: -.0755877346} + scale: {x: .999999821, y: 1.00000012, z: .999999702} + transformModified: 1 + - name: RightForeArm + position: {x: .253428489, y: .00601093518, z: -.0167045332} + rotation: {x: -.00061651913, y: .022078624, z: -.0160702355, w: .999626875} + scale: {x: .99999994, y: .999999881, z: .99999994} + transformModified: 1 + - name: RightHand + position: {x: .245373741, y: .0216420237, z: .00555047346} + rotation: {x: 5.43189438e-10, y: 3.12476184e-10, z: .0214136969, w: .999770641} + scale: {x: 1, y: 1, z: 1.00000012} + transformModified: 1 + - name: RightHandIndex1 + position: {x: .0747697875, y: -.00124282821, z: .0343445241} + rotation: {x: -.00211892067, y: .0802574307, z: .0175381824, w: .996617556} + scale: {x: 1.00000012, y: 1, z: .99999994} + transformModified: 1 + - name: RightHandIndex2 + position: {x: .037058223, y: .000725421763, z: .0145388739} + rotation: {x: -.0033212963, y: .0159312561, z: .060620904, w: .998028159} + scale: {x: 1, y: .99999994, z: 1} + transformModified: 1 + - name: RightHandIndex3 + position: {x: .0252250955, y: -.00496621709, z: .0110121826} + rotation: {x: 2.16179208e-09, y: 1.06850013e-08, z: -8.50230109e-09, w: .99999994} + scale: {x: 1, y: 1.00000012, z: 1.00000012} + transformModified: 1 + - name: RightHandMiddle1 + position: {x: .0756474286, y: .00479083089, z: .0118531957} + rotation: {x: -.00076887355, y: .0333210677, z: .0209075324, w: .999225616} + scale: {x: 1.00000012, y: .999999821, z: .999999881} + transformModified: 1 + - name: RightHandMiddle2 + position: {x: .0438093096, y: .000194165463, z: .00645493949} + rotation: {x: -.00413025497, y: -.0335112251, z: .0761189312, w: .996526897} + scale: {x: 1, y: .999999881, z: 1.00000012} + transformModified: 1 + - name: RightHandMiddle3 + position: {x: .0330725648, y: -.00754737761, z: .00168985641} + rotation: {x: -3.7425496e-10, y: -4.22918101e-09, z: -1.05837286e-08, w: .99999994} + scale: {x: 1, y: .999999881, z: 1} + transformModified: 1 + - name: RightHandPinky1 + position: {x: .0668031499, y: -.00199452811, z: -.0307561476} + rotation: {x: .00317558926, y: -.192005113, z: .045110438, w: .980351448} + scale: {x: 1.00000024, y: 1, z: .99999994} + transformModified: 1 + - name: RightHandPinky2 + position: {x: .0285309609, y: -.00139694544, z: -.0116238492} + rotation: {x: -.000170628482, y: -.00966134109, z: -.0053623952, w: .999938965} + scale: {x: .999999881, y: 1, z: .99999994} + transformModified: 1 + - name: RightHandPinky3 + position: {x: .0214269403, y: -.000553725113, z: -.00851663202} + rotation: {x: -8.53474014e-10, y: 1.63788556e-08, z: -1.38467984e-08, w: .99999994} + scale: {x: 1, y: 1, z: 1.00000012} + transformModified: 1 + - name: RightHandRing1 + position: {x: .070598565, y: .00245756772, z: -.00982147083} + rotation: {x: .000710569788, y: -.054343082, z: .0349452496, w: .99791038} + scale: {x: 1.00000012, y: 1, z: 1} + transformModified: 1 + - name: RightHandRing2 + position: {x: .0428872742, y: -.0013759057, z: -.00494588772} + rotation: {x: .000482838717, y: -.0212902706, z: .0698495656, w: .997330129} + scale: {x: 1, y: 1, z: 1.00000024} + transformModified: 1 + - name: RightHandRing3 + position: {x: .0295008179, y: -.00769269653, z: -.00462226616} + rotation: {x: -2.61377653e-09, y: -8.06309508e-09, z: -6.11845863e-09, w: .99999994} + scale: {x: 1, y: 1, z: 1.00000012} + transformModified: 1 + - name: RightHandThumb1 + position: {x: .014684936, y: -.0111049525, z: .025858108} + rotation: {x: -.0128134973, y: -.00325657148, z: .0314576477, w: .999417663} + scale: {x: 1.00000012, y: 1, z: 1} + transformModified: 1 + - name: RightHandThumb2 + position: {x: .0163741205, y: -.00528976135, z: .0234913807} + rotation: {x: -.0260671675, y: -.0966875851, z: -.00360274338, w: .994966805} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: RightHandThumb3 + position: {x: .0254600029, y: -.00764030218, z: .0208330136} + rotation: {x: 1.31814044e-08, y: 1.05642828e-09, z: -2.01141503e-09, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + armTwist: .5 + foreArmTwist: .5 + upperLegTwist: .5 + legTwist: .5 + armStretch: .0500000007 + legStretch: .0500000007 + feetSpacing: 0 + rootMotionBoneName: + lastHumanDescriptionAvatarSource: {fileID: 9000000, guid: 2ab0893f5bba9b243b65e309e78089d0, + type: 3} + animationType: 3 + additionalBone: 0 + userData: diff --git a/Assets/Photon Unity Networking/Demos/Shared Assets/Animations/Layer.controller b/Assets/Photon Unity Networking/Demos/Shared Assets/Animations/Layer.controller new file mode 100644 index 0000000..e7d08ab Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/Shared Assets/Animations/Layer.controller differ diff --git a/Assets/Photon Unity Networking/Demos/Shared Assets/Animations/Layer.controller.meta b/Assets/Photon Unity Networking/Demos/Shared Assets/Animations/Layer.controller.meta new file mode 100644 index 0000000..f70b4c4 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/Shared Assets/Animations/Layer.controller.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: 042914e107241244896b36a14ff15f88 +NativeFormatImporter: + userData: diff --git a/Assets/Photon Unity Networking/Demos/Shared Assets/Animations/Materials.meta b/Assets/Photon Unity Networking/Demos/Shared Assets/Animations/Materials.meta new file mode 100644 index 0000000..b7be5c4 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/Shared Assets/Animations/Materials.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 683edaf21b0df430db61db1f557f8fb0 +folderAsset: yes +timeCreated: 1501014812 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Photon Unity Networking/Demos/Shared Assets/Animations/Materials/EyesMaterial.mat b/Assets/Photon Unity Networking/Demos/Shared Assets/Animations/Materials/EyesMaterial.mat new file mode 100644 index 0000000..a14b5aa Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/Shared Assets/Animations/Materials/EyesMaterial.mat differ diff --git a/Assets/Photon Unity Networking/Demos/Shared Assets/Animations/Materials/EyesMaterial.mat.meta b/Assets/Photon Unity Networking/Demos/Shared Assets/Animations/Materials/EyesMaterial.mat.meta new file mode 100644 index 0000000..f46c104 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/Shared Assets/Animations/Materials/EyesMaterial.mat.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: ce5a83fcea7762541ba43ca5bd854dae +NativeFormatImporter: + userData: diff --git a/Assets/Photon Unity Networking/Demos/Shared Assets/Animations/Materials/SkinMaterial.mat b/Assets/Photon Unity Networking/Demos/Shared Assets/Animations/Materials/SkinMaterial.mat new file mode 100644 index 0000000..6ff6377 Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/Shared Assets/Animations/Materials/SkinMaterial.mat differ diff --git a/Assets/Photon Unity Networking/Demos/Shared Assets/Animations/Materials/SkinMaterial.mat.meta b/Assets/Photon Unity Networking/Demos/Shared Assets/Animations/Materials/SkinMaterial.mat.meta new file mode 100644 index 0000000..95be427 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/Shared Assets/Animations/Materials/SkinMaterial.mat.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: 37d0d4d178b5dbf449ff0814718dc354 +NativeFormatImporter: + userData: diff --git a/Assets/Photon Unity Networking/Demos/Shared Assets/Animations/Materials/SuitMaterial.mat b/Assets/Photon Unity Networking/Demos/Shared Assets/Animations/Materials/SuitMaterial.mat new file mode 100644 index 0000000..87e2507 Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/Shared Assets/Animations/Materials/SuitMaterial.mat differ diff --git a/Assets/Photon Unity Networking/Demos/Shared Assets/Animations/Materials/SuitMaterial.mat.meta b/Assets/Photon Unity Networking/Demos/Shared Assets/Animations/Materials/SuitMaterial.mat.meta new file mode 100644 index 0000000..b2eba30 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/Shared Assets/Animations/Materials/SuitMaterial.mat.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: ed4e4079e2e99084d8d914283565fc5c +NativeFormatImporter: + userData: diff --git a/Assets/Photon Unity Networking/Demos/Shared Assets/Animations/Materials/TeethMaterial.mat b/Assets/Photon Unity Networking/Demos/Shared Assets/Animations/Materials/TeethMaterial.mat new file mode 100644 index 0000000..1db1d8e Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/Shared Assets/Animations/Materials/TeethMaterial.mat differ diff --git a/Assets/Photon Unity Networking/Demos/Shared Assets/Animations/Materials/TeethMaterial.mat.meta b/Assets/Photon Unity Networking/Demos/Shared Assets/Animations/Materials/TeethMaterial.mat.meta new file mode 100644 index 0000000..9416ddb --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/Shared Assets/Animations/Materials/TeethMaterial.mat.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: 17dd34e8a826d0641a0e0f43da1e03a0 +NativeFormatImporter: + userData: diff --git a/Assets/Photon Unity Networking/Demos/Shared Assets/Animations/Materials/TongueMaterial.mat b/Assets/Photon Unity Networking/Demos/Shared Assets/Animations/Materials/TongueMaterial.mat new file mode 100644 index 0000000..5686c26 Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/Shared Assets/Animations/Materials/TongueMaterial.mat differ diff --git a/Assets/Photon Unity Networking/Demos/Shared Assets/Animations/Materials/TongueMaterial.mat.meta b/Assets/Photon Unity Networking/Demos/Shared Assets/Animations/Materials/TongueMaterial.mat.meta new file mode 100644 index 0000000..89c98fd --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/Shared Assets/Animations/Materials/TongueMaterial.mat.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: 28498b9ebcb776a46b3c9479a664bfc7 +NativeFormatImporter: + userData: diff --git a/Assets/Photon Unity Networking/Demos/Shared Assets/Animations/RPGController.controller b/Assets/Photon Unity Networking/Demos/Shared Assets/Animations/RPGController.controller new file mode 100644 index 0000000..945b583 Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/Shared Assets/Animations/RPGController.controller differ diff --git a/Assets/Photon Unity Networking/Demos/Shared Assets/Animations/RPGController.controller.meta b/Assets/Photon Unity Networking/Demos/Shared Assets/Animations/RPGController.controller.meta new file mode 100644 index 0000000..e4a8f2a --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/Shared Assets/Animations/RPGController.controller.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: 2608c949cda1edd44a9ae292d08e55d3 +NativeFormatImporter: + userData: diff --git a/Assets/Photon Unity Networking/Demos/Shared Assets/Animations/RapidStrafe_Left.fbx b/Assets/Photon Unity Networking/Demos/Shared Assets/Animations/RapidStrafe_Left.fbx new file mode 100644 index 0000000..6ecb91b Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/Shared Assets/Animations/RapidStrafe_Left.fbx differ diff --git a/Assets/Photon Unity Networking/Demos/Shared Assets/Animations/RapidStrafe_Left.fbx.meta b/Assets/Photon Unity Networking/Demos/Shared Assets/Animations/RapidStrafe_Left.fbx.meta new file mode 100644 index 0000000..061dc76 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/Shared Assets/Animations/RapidStrafe_Left.fbx.meta @@ -0,0 +1,957 @@ +fileFormatVersion: 2 +guid: 08257633e3910e54a8cc5e8ed9cc9afe +ModelImporter: + serializedVersion: 16 + fileIDToRecycleName: + 100000: //RootNode + 100002: Chest + 100004: Head + 100006: Hips + 100008: Jaw + 100010: JawEND + 100012: LeftArm + 100014: LeftCheek + 100016: LeftEye + 100018: LeftEyelidLower + 100020: LeftEyelidUpper + 100022: LeftFoot + 100024: LeftForeArm + 100026: LeftHand + 100028: LeftHandIndex1 + 100030: LeftHandIndex2 + 100032: LeftHandIndex3 + 100034: LeftHandMiddle1 + 100036: LeftHandMiddle2 + 100038: LeftHandMiddle3 + 100040: LeftHandPinky1 + 100042: LeftHandPinky2 + 100044: LeftHandPinky3 + 100046: LeftHandRing1 + 100048: LeftHandRing2 + 100050: LeftHandRing3 + 100052: LeftHandThumb1 + 100054: LeftHandThumb2 + 100056: LeftHandThumb3 + 100058: LeftInnerBrow + 100060: LeftIOuterBrow + 100062: LeftLeg + 100064: LeftLipCorner + 100066: LeftLipLower + 100068: LeftLipUpper + 100070: LeftNostril + 100072: LeftShoulder + 100074: LeftToes + 100076: LeftUpLeg + 100078: Neck + 100080: Pivot + 100082: Reference + 100084: RightArm + 100086: RightCheek + 100088: RightEye + 100090: RightEyelidLower + 100092: RightEyelidUpper + 100094: RightFoot + 100096: RightForeArm + 100098: RightHand + 100100: RightHandIndex1 + 100102: RightHandIndex2 + 100104: RightHandIndex3 + 100106: RightHandMiddle1 + 100108: RightHandMiddle2 + 100110: RightHandMiddle3 + 100112: RightHandPinky1 + 100114: RightHandPinky2 + 100116: RightHandPinky3 + 100118: RightHandRing1 + 100120: RightHandRing2 + 100122: RightHandRing3 + 100124: RightHandThumb1 + 100126: RightHandThumb2 + 100128: RightHandThumb3 + 100130: RightInnerBrow + 100132: RightIOuterBrow + 100134: RightLeg + 100136: RightLipCorner + 100138: RightLipLower + 100140: RightLipUpper + 100142: RightNostril + 100144: RightShoulder + 100146: RightToes + 100148: RightUpLeg + 100150: Root + 100152: Spine + 100154: TongueBack + 100156: TongueTip + 400000: //RootNode + 400002: Chest + 400004: Head + 400006: Hips + 400008: Jaw + 400010: JawEND + 400012: LeftArm + 400014: LeftCheek + 400016: LeftEye + 400018: LeftEyelidLower + 400020: LeftEyelidUpper + 400022: LeftFoot + 400024: LeftForeArm + 400026: LeftHand + 400028: LeftHandIndex1 + 400030: LeftHandIndex2 + 400032: LeftHandIndex3 + 400034: LeftHandMiddle1 + 400036: LeftHandMiddle2 + 400038: LeftHandMiddle3 + 400040: LeftHandPinky1 + 400042: LeftHandPinky2 + 400044: LeftHandPinky3 + 400046: LeftHandRing1 + 400048: LeftHandRing2 + 400050: LeftHandRing3 + 400052: LeftHandThumb1 + 400054: LeftHandThumb2 + 400056: LeftHandThumb3 + 400058: LeftInnerBrow + 400060: LeftIOuterBrow + 400062: LeftLeg + 400064: LeftLipCorner + 400066: LeftLipLower + 400068: LeftLipUpper + 400070: LeftNostril + 400072: LeftShoulder + 400074: LeftToes + 400076: LeftUpLeg + 400078: Neck + 400080: Pivot + 400082: Reference + 400084: RightArm + 400086: RightCheek + 400088: RightEye + 400090: RightEyelidLower + 400092: RightEyelidUpper + 400094: RightFoot + 400096: RightForeArm + 400098: RightHand + 400100: RightHandIndex1 + 400102: RightHandIndex2 + 400104: RightHandIndex3 + 400106: RightHandMiddle1 + 400108: RightHandMiddle2 + 400110: RightHandMiddle3 + 400112: RightHandPinky1 + 400114: RightHandPinky2 + 400116: RightHandPinky3 + 400118: RightHandRing1 + 400120: RightHandRing2 + 400122: RightHandRing3 + 400124: RightHandThumb1 + 400126: RightHandThumb2 + 400128: RightHandThumb3 + 400130: RightInnerBrow + 400132: RightIOuterBrow + 400134: RightLeg + 400136: RightLipCorner + 400138: RightLipLower + 400140: RightLipUpper + 400142: RightNostril + 400144: RightShoulder + 400146: RightToes + 400148: RightUpLeg + 400150: Root + 400152: Spine + 400154: TongueBack + 400156: TongueTip + 7400000: RapidStrafe_Left + 9500000: //RootNode + materials: + importMaterials: 1 + materialName: 0 + materialSearch: 1 + animations: + legacyGenerateAnimations: 4 + bakeSimulation: 0 + optimizeGameObjects: 0 + animationCompression: 1 + animationRotationError: .5 + animationPositionError: .5 + animationScaleError: .5 + animationWrapMode: 0 + extraExposedTransformPaths: [] + clipAnimations: + - serializedVersion: 16 + name: RapidStrafe_Left + takeName: _60_a_U1_M_P_RapidStrafe_90HipsLeftFaceFwd__Fb_p90_No_0_PJ_5 + firstFrame: 160 + lastFrame: 178 + wrapMode: 0 + orientationOffsetY: 0 + level: 0 + cycleOffset: 0 + loop: 0 + loopTime: 1 + loopBlend: 0 + loopBlendOrientation: 0 + loopBlendPositionY: 0 + loopBlendPositionXZ: 0 + keepOriginalOrientation: 0 + keepOriginalPositionY: 1 + keepOriginalPositionXZ: 0 + heightFromFeet: 0 + mirror: 1 + bodyMask: 01000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000 + curves: [] + events: [] + transformMask: [] + maskType: 0 + maskSource: {instanceID: 0} + isReadable: 1 + meshes: + lODScreenPercentages: [] + globalScale: .00999999978 + meshCompression: 0 + addColliders: 0 + importBlendShapes: 1 + swapUVChannels: 0 + generateSecondaryUV: 0 + useFileUnits: 1 + optimizeMeshForGPU: 1 + weldVertices: 1 + secondaryUVAngleDistortion: 8 + secondaryUVAreaDistortion: 15.000001 + secondaryUVHardAngle: 88 + secondaryUVPackMargin: 4 + tangentSpace: + normalSmoothAngle: 60 + splitTangentsAcrossUV: 1 + normalImportMode: 0 + tangentImportMode: 1 + importAnimation: 1 + copyAvatar: 1 + humanDescription: + human: + - boneName: Hips + humanName: Hips + limit: + min: {x: -40, y: -40, z: -40} + max: {x: 40, y: 40, z: 40} + value: {x: .0748811588, y: 0, z: .0374405794} + length: .0936014801 + modified: 1 + - boneName: LeftUpLeg + humanName: LeftUpperLeg + limit: + min: {x: -60.0000038, y: -60.0000038, z: -90} + max: {x: 60.0000038, y: 60.0000038, z: 50} + value: {x: .327766716, y: 0, z: .163883358} + length: .40970853 + modified: 1 + - boneName: RightUpLeg + humanName: RightUpperLeg + limit: + min: {x: -60.0000038, y: -60.0000038, z: -90} + max: {x: 60.0000038, y: 60.0000038, z: 50} + value: {x: .327766716, y: 0, z: .163883358} + length: .40970853 + modified: 1 + - boneName: LeftLeg + humanName: LeftLowerLeg + limit: + min: {x: -90, y: 0, z: -80} + max: {x: 90, y: 0, z: 80} + value: {x: .338686436, y: 0, z: .169343218} + length: .423358172 + modified: 1 + - boneName: RightLeg + humanName: RightLowerLeg + limit: + min: {x: -90, y: 0, z: -80} + max: {x: 90, y: 0, z: 80} + value: {x: .338686436, y: 0, z: .169343218} + length: .423358172 + modified: 1 + - boneName: LeftFoot + humanName: LeftFoot + limit: + min: {x: 0, y: -30.0000019, z: -50} + max: {x: 0, y: 30.0000019, z: 50} + value: {x: .0686753467, y: 0, z: .0343376733} + length: .0858442187 + modified: 1 + - boneName: RightFoot + humanName: RightFoot + limit: + min: {x: 0, y: -30.0000019, z: -50} + max: {x: 0, y: 30.0000019, z: 50} + value: {x: .0686753467, y: 0, z: .0343376733} + length: .0858442187 + modified: 1 + - boneName: Spine + humanName: Spine + limit: + min: {x: -40, y: -40, z: -40} + max: {x: 40, y: 40, z: 40} + value: {x: .131201819, y: 0, z: .0656009093} + length: .164002344 + modified: 1 + - boneName: Chest + humanName: Chest + limit: + min: {x: -40, y: -40, z: -40} + max: {x: 40, y: 40, z: 40} + value: {x: .190353557, y: 0, z: .0951767787} + length: .237942025 + modified: 1 + - boneName: Neck + humanName: Neck + limit: + min: {x: -40, y: -40, z: -40} + max: {x: 40, y: 40, z: 40} + value: {x: .0855657607, y: 0, z: .0427828804} + length: .106957234 + modified: 1 + - boneName: Head + humanName: Head + limit: + min: {x: -40, y: -40, z: -40} + max: {x: 40, y: 40, z: 40} + value: {x: .0855657607, y: 0, z: .0427828804} + length: .106957234 + modified: 1 + - boneName: LeftShoulder + humanName: LeftShoulder + limit: + min: {x: 0, y: -15.000001, z: -15.000001} + max: {x: 0, y: 15.000001, z: 30.0000019} + value: {x: .072829701, y: 0, z: .0364148505} + length: .0910371616 + modified: 1 + - boneName: RightShoulder + humanName: RightShoulder + limit: + min: {x: 0, y: -15.000001, z: -15.000001} + max: {x: 0, y: 15.000001, z: 30.0000019} + value: {x: .072829701, y: 0, z: .0364148505} + length: .0910371616 + modified: 1 + - boneName: LeftArm + humanName: LeftUpperArm + limit: + min: {x: -90, y: -100, z: -60.0000038} + max: {x: 90, y: 100, z: 100} + value: {x: .203239605, y: 0, z: .101619802} + length: .254049569 + modified: 1 + - boneName: RightArm + humanName: RightUpperArm + limit: + min: {x: -90, y: -100, z: -60.0000038} + max: {x: 90, y: 100, z: 100} + value: {x: .203239575, y: 0, z: .101619788} + length: .25404954 + modified: 1 + - boneName: LeftForeArm + humanName: LeftLowerArm + limit: + min: {x: -90, y: 0, z: -80} + max: {x: 90, y: 0, z: 80} + value: {x: .197111532, y: 0, z: .098555766} + length: .246389478 + modified: 1 + - boneName: RightForeArm + humanName: RightLowerArm + limit: + min: {x: -90, y: 0, z: -80} + max: {x: 90, y: 0, z: 80} + value: {x: .197110936, y: 0, z: .098555468} + length: .246388748 + modified: 1 + - boneName: LeftHand + humanName: LeftHand + limit: + min: {x: 0, y: -40, z: -80} + max: {x: 0, y: 40, z: 80} + value: {x: .098555766, y: 0, z: .049277883} + length: .123194739 + modified: 1 + - boneName: RightHand + humanName: RightHand + limit: + min: {x: 0, y: -40, z: -80} + max: {x: 0, y: 40, z: 80} + value: {x: .098555468, y: 0, z: .049277734} + length: .123194374 + modified: 1 + - boneName: LeftToes + humanName: LeftToes + limit: + min: {x: 0, y: 0, z: -50} + max: {x: 0, y: 0, z: 50} + value: {x: .0651871562, y: 0, z: .0325935781} + length: .0814839825 + modified: 1 + - boneName: RightToes + humanName: RightToes + limit: + min: {x: 0, y: 0, z: -50} + max: {x: 0, y: 0, z: 50} + value: {x: .0651872903, y: 0, z: .0325936452} + length: .0814841464 + modified: 1 + - boneName: LeftEye + humanName: LeftEye + limit: + min: {x: 0, y: -20, z: -10} + max: {x: 0, y: 20, z: 15.000001} + value: {x: .0799999759, y: 0, z: .0399999879} + length: .100000001 + modified: 1 + - boneName: RightEye + humanName: RightEye + limit: + min: {x: 0, y: -20, z: -10} + max: {x: 0, y: 20, z: 15.000001} + value: {x: .0799999759, y: 0, z: .0399999879} + length: .100000001 + modified: 1 + - boneName: Jaw + humanName: Jaw + limit: + min: {x: 0, y: -10, z: -10} + max: {x: 0, y: 10, z: 10} + value: {x: .0799999759, y: 0, z: .0399999879} + length: .100000001 + modified: 1 + - boneName: LeftHandThumb1 + humanName: Left Thumb Proximal + limit: + min: {x: 0, y: -25, z: -20} + max: {x: 0, y: 25, z: 20} + value: {x: .0232954584, y: 0, z: .0116477292} + length: .0291193314 + modified: 1 + - boneName: LeftHandThumb2 + humanName: Left Thumb Intermediate + limit: + min: {x: 0, y: 0, z: -40} + max: {x: 0, y: 0, z: 35} + value: {x: .0270181261, y: 0, z: .0135090631} + length: .033772666 + modified: 1 + - boneName: LeftHandThumb3 + humanName: Left Thumb Distal + limit: + min: {x: 0, y: 0, z: -40} + max: {x: 0, y: 0, z: 35} + value: {x: .0202635936, y: 0, z: .0101317968} + length: .0253295004 + modified: 1 + - boneName: LeftHandIndex1 + humanName: Left Index Proximal + limit: + min: {x: 0, y: -20, z: -50} + max: {x: 0, y: 20, z: 50} + value: {x: .0318517797, y: 0, z: .0159258898} + length: .0398147404 + modified: 1 + - boneName: LeftHandIndex2 + humanName: Left Index Intermediate + limit: + min: {x: 0, y: 0, z: -45} + max: {x: 0, y: 0, z: 45} + value: {x: .0223747883, y: 0, z: .0111873941} + length: .0279684942 + modified: 1 + - boneName: LeftHandIndex3 + humanName: Left Index Distal + limit: + min: {x: 0, y: 0, z: -45} + max: {x: 0, y: 0, z: 45} + value: {x: .0167810898, y: 0, z: .00839054491} + length: .0209763702 + modified: 1 + - boneName: LeftHandMiddle1 + humanName: Left Middle Proximal + limit: + min: {x: 0, y: -7.50000048, z: -50} + max: {x: 0, y: 7.50000048, z: 50} + value: {x: .0354260914, y: 0, z: .0177130457} + length: .0442826301 + modified: 1 + - boneName: LeftHandMiddle2 + humanName: Left Middle Intermediate + limit: + min: {x: 0, y: 0, z: -45} + max: {x: 0, y: 0, z: 45} + value: {x: .0271718036, y: 0, z: .0135859018} + length: .0339647643 + modified: 1 + - boneName: LeftHandMiddle3 + humanName: Left Middle Distal + limit: + min: {x: 0, y: 0, z: -45} + max: {x: 0, y: 0, z: 45} + value: {x: .0203788504, y: 0, z: .0101894252} + length: .0254735723 + modified: 1 + - boneName: LeftHandRing1 + humanName: Left Ring Proximal + limit: + min: {x: 0, y: -7.50000048, z: -50} + max: {x: 0, y: 7.50000048, z: 50} + value: {x: .0345545448, y: 0, z: .0172772724} + length: .0431931987 + modified: 1 + - boneName: LeftHandRing2 + humanName: Left Ring Intermediate + limit: + min: {x: 0, y: 0, z: -45} + max: {x: 0, y: 0, z: 45} + value: {x: .0246683266, y: 0, z: .0123341633} + length: .030835418 + modified: 1 + - boneName: LeftHandRing3 + humanName: Left Ring Distal + limit: + min: {x: 0, y: 0, z: -45} + max: {x: 0, y: 0, z: 45} + value: {x: .0185012426, y: 0, z: .00925062131} + length: .0231265631 + modified: 1 + - boneName: LeftHandPinky1 + humanName: Left Little Proximal + limit: + min: {x: 0, y: -20, z: -50} + max: {x: 0, y: 20, z: 50} + value: {x: .024671508, y: 0, z: .012335754} + length: .0308393929 + modified: 1 + - boneName: LeftHandPinky2 + humanName: Left Little Intermediate + limit: + min: {x: 0, y: 0, z: -45} + max: {x: 0, y: 0, z: 45} + value: {x: .0184510797, y: 0, z: .00922553986} + length: .023063859 + modified: 1 + - boneName: LeftHandPinky3 + humanName: Left Little Distal + limit: + min: {x: 0, y: 0, z: -45} + max: {x: 0, y: 0, z: 45} + value: {x: .0138383117, y: 0, z: .00691915583} + length: .0172978938 + modified: 1 + - boneName: RightHandThumb1 + humanName: Right Thumb Proximal + limit: + min: {x: 0, y: -25, z: -20} + max: {x: 0, y: 25, z: 20} + value: {x: .0232954752, y: 0, z: .0116477376} + length: .0291193537 + modified: 1 + - boneName: RightHandThumb2 + humanName: Right Thumb Intermediate + limit: + min: {x: 0, y: 0, z: -40} + max: {x: 0, y: 0, z: 35} + value: {x: .0270181969, y: 0, z: .0135090984} + length: .0337727554 + modified: 1 + - boneName: RightHandThumb3 + humanName: Right Thumb Distal + limit: + min: {x: 0, y: 0, z: -40} + max: {x: 0, y: 0, z: 35} + value: {x: .0202636477, y: 0, z: .0101318238} + length: .0253295675 + modified: 1 + - boneName: RightHandIndex1 + humanName: Right Index Proximal + limit: + min: {x: 0, y: -20, z: -50} + max: {x: 0, y: 20, z: 50} + value: {x: .0318517946, y: 0, z: .0159258973} + length: .039814759 + modified: 1 + - boneName: RightHandIndex2 + humanName: Right Index Intermediate + limit: + min: {x: 0, y: 0, z: -45} + max: {x: 0, y: 0, z: 45} + value: {x: .0223747734, y: 0, z: .0111873867} + length: .0279684756 + modified: 1 + - boneName: RightHandIndex3 + humanName: Right Index Distal + limit: + min: {x: 0, y: 0, z: -45} + max: {x: 0, y: 0, z: 45} + value: {x: .0167810787, y: 0, z: .00839053933} + length: .0209763572 + modified: 1 + - boneName: RightHandMiddle1 + humanName: Right Middle Proximal + limit: + min: {x: 0, y: -7.50000048, z: -50} + max: {x: 0, y: 7.50000048, z: 50} + value: {x: .0354261473, y: 0, z: .0177130736} + length: .0442827009 + modified: 1 + - boneName: RightHandMiddle2 + humanName: Right Middle Intermediate + limit: + min: {x: 0, y: 0, z: -45} + max: {x: 0, y: 0, z: 45} + value: {x: .0271718968, y: 0, z: .0135859484} + length: .0339648798 + modified: 1 + - boneName: RightHandMiddle3 + humanName: Right Middle Distal + limit: + min: {x: 0, y: 0, z: -45} + max: {x: 0, y: 0, z: 45} + value: {x: .0203789212, y: 0, z: .0101894606} + length: .0254736599 + modified: 1 + - boneName: RightHandRing1 + humanName: Right Ring Proximal + limit: + min: {x: 0, y: -7.50000048, z: -50} + max: {x: 0, y: 7.50000048, z: 50} + value: {x: .0345547274, y: 0, z: .0172773637} + length: .043193426 + modified: 1 + - boneName: RightHandRing2 + humanName: Right Ring Intermediate + limit: + min: {x: 0, y: 0, z: -45} + max: {x: 0, y: 0, z: 45} + value: {x: .0246685483, y: 0, z: .0123342741} + length: .0308356937 + modified: 1 + - boneName: RightHandRing3 + humanName: Right Ring Distal + limit: + min: {x: 0, y: 0, z: -45} + max: {x: 0, y: 0, z: 45} + value: {x: .0185014084, y: 0, z: .0092507042} + length: .0231267698 + modified: 1 + - boneName: RightHandPinky1 + humanName: Right Little Proximal + limit: + min: {x: 0, y: -20, z: -50} + max: {x: 0, y: 20, z: 50} + value: {x: .0246716533, y: 0, z: .0123358266} + length: .0308395755 + modified: 1 + - boneName: RightHandPinky2 + humanName: Right Little Intermediate + limit: + min: {x: 0, y: 0, z: -45} + max: {x: 0, y: 0, z: 45} + value: {x: .018451266, y: 0, z: .009225633} + length: .0230640918 + modified: 1 + - boneName: RightHandPinky3 + humanName: Right Little Distal + limit: + min: {x: 0, y: 0, z: -45} + max: {x: 0, y: 0, z: 45} + value: {x: .0138384514, y: 0, z: .00691922568} + length: .0172980689 + modified: 1 + skeleton: + - name: DefaultAvatar + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: Reference + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: -0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: Hips + position: {x: 0, y: .963793993, z: -.0235067774} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: LeftUpLeg + position: {x: -.0754494965, y: -.0456640124, z: 0} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: LeftLeg + position: {x: -.0205505043, y: -.409129977, z: .00717136636} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: LeftFoot + position: {x: -.00515300781, y: -.423155904, z: -.0120320898} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: LeftToes + position: {x: -.00748699158, y: -.0731672645, z: .145427138} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: RightUpLeg + position: {x: .0754495338, y: -.0456640124, z: 0} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: RightLeg + position: {x: .0205504671, y: -.409129977, z: .00717136636} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: RightFoot + position: {x: .00515300035, y: -.423155904, z: -.0120320898} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: RightToes + position: {x: .00748699903, y: -.0731672645, z: .14542751} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: Spine + position: {x: 0, y: .0922632217, z: .0157713331} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: Chest + position: {x: 0, y: .162540197, z: .02185072} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: LeftShoulder + position: {x: -.0382435732, y: .192178011, z: -.017063085} + rotation: {x: -.0140067078, y: -.0595068112, z: .228689864, w: .971577883} + scale: {x: 1.00000024, y: 1, z: 1} + transformModified: 1 + - name: LeftArm + position: {x: -.083574675, y: .0360975936, z: -1.50734021e-08} + rotation: {x: .00946438964, y: .0436916873, z: -.223042384, w: .973783076} + scale: {x: 1, y: 1, z: 1.00000012} + transformModified: 1 + - name: LeftForeArm + position: {x: -.254049391, y: 4.70318128e-07, z: -2.19768759e-09} + rotation: {x: -.000616520119, y: .0220786221, z: -.0160702392, w: .999626875} + scale: {x: .99999994, y: 1, z: .999999881} + transformModified: 1 + - name: LeftHand + position: {x: -.246389359, y: -1.89769892e-07, z: -5.73217829e-09} + rotation: {x: 2.86021207e-10, y: -9.59063495e-10, z: -.0214135461, w: .999770701} + scale: {x: .99999994, y: 1, z: 1} + transformModified: 1 + - name: LeftHandIndex1 + position: {x: -.0751256943, y: -.0078413263, z: .0326526687} + rotation: {x: -.00211891974, y: .0802574307, z: .0175381806, w: .996617615} + scale: {x: 1, y: 1, z: .99999994} + transformModified: 1 + - name: LeftHandIndex2 + position: {x: -.0397970602, y: 4.9526192e-05, z: .00118574023} + rotation: {x: .000501931063, y: .0154708987, z: .040414121, w: .999063075} + scale: {x: 1.00000024, y: 1.00000024, z: .99999994} + transformModified: 1 + - name: LeftHandIndex3 + position: {x: -.0279685091, y: -1.79063633e-07, z: -9.18437095e-08} + rotation: {x: 4.33656722e-10, y: -1.75894304e-08, z: -1.0378705e-08, w: .99999994} + scale: {x: 1, y: 1.00000012, z: .999999881} + transformModified: 1 + - name: LeftHandMiddle1 + position: {x: -.0760235488, y: -.00188508059, z: .0101412414} + rotation: {x: -.000768872793, y: .0333210751, z: .0209075306, w: .999225676} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: LeftHandMiddle2 + position: {x: -.0442805924, y: 4.51253936e-06, z: -.000425422273} + rotation: {x: -.0013621418, y: -.0191537701, z: .03788976, w: .999097407} + scale: {x: 1, y: 1.00000012, z: 1} + transformModified: 1 + - name: LeftHandMiddle3 + position: {x: -.0339647792, y: 1.61085282e-07, z: 5.41929612e-09} + rotation: {x: 6.13220641e-10, y: -4.12468948e-09, z: 1.82216331e-09, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: LeftHandPinky1 + position: {x: -.0656598732, y: -.00782526191, z: -.0322512463} + rotation: {x: -.000913206837, y: .0121623212, z: .0212220512, w: .999700367} + scale: {x: 1.00000012, y: 1, z: .999999881} + transformModified: 1 + - name: LeftHandPinky2 + position: {x: -.0308053754, y: -3.11739277e-05, z: -.00144808914} + rotation: {x: -.000170628555, y: -.0096613653, z: -.00536239706, w: .999938905} + scale: {x: 1, y: .999999821, z: 1.00000012} + transformModified: 1 + - name: LeftHandPinky3 + position: {x: -.0230638776, y: -6.67785343e-06, z: 6.90349244e-09} + rotation: {x: -8.51873905e-10, y: -9.4255892e-09, z: -1.31619666e-08, w: .99999994} + scale: {x: 1, y: 1, z: .99999994} + transformModified: 1 + - name: LeftHandRing1 + position: {x: -.0703021139, y: -.00374528999, z: -.0114117898} + rotation: {x: -.000324091874, y: .0115982238, z: .0247380193, w: .999626577} + scale: {x: 1, y: 1.00000024, z: .99999994} + transformModified: 1 + - name: LeftHandRing2 + position: {x: -.0431353189, y: -2.08693382e-05, z: -.00223518023} + rotation: {x: -.0012032456, y: -.0231137592, z: .0409796387, w: .99889189} + scale: {x: .999999881, y: .999999702, z: .99999994} + transformModified: 1 + - name: LeftHandRing3 + position: {x: -.0308354236, y: -1.56879963e-07, z: -1.40963357e-08} + rotation: {x: 4.93614594e-10, y: -1.5807432e-09, z: -5.78796033e-09, w: .99999994} + scale: {x: 1, y: .99999994, z: .999999881} + transformModified: 1 + - name: LeftHandThumb1 + position: {x: -.0142313093, y: -.012377888, z: .0255316831} + rotation: {x: -.0123126386, y: -.0085253641, z: .0125855142, w: .999808609} + scale: {x: 1, y: 1, z: 1.00000012} + transformModified: 1 + - name: LeftHandThumb2 + position: {x: -.0163739249, y: -.00528992061, z: .0234914143} + rotation: {x: -.0260628555, y: .0966900289, z: .00360696716, w: .994966686} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: LeftHandThumb3 + position: {x: -.0254599936, y: -.00763992406, z: .020832995} + rotation: {x: 4.41585328e-08, y: 1.10925613e-09, z: -7.80932541e-10, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: Neck + position: {x: 0, y: .235723972, z: -.0324132554} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: Head + position: {x: 0, y: .106355786, z: .0113267824} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: Jaw + position: {x: 0, y: .0111267567, z: .0103275422} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: LeftEye + position: {x: -.0208482333, y: .0825027227, z: .0554274321} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: RightEye + position: {x: .020849999, y: .0825027227, z: .0554273948} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: RightShoulder + position: {x: .038328547, y: .192177057, z: -.0170630887} + rotation: {x: .228671983, y: .971582115, z: -.0140056778, w: -.05950737} + scale: {x: 1, y: 1.00000012, z: .99999994} + transformModified: 1 + - name: RightArm + position: {x: -.0835753977, y: .0360959396, z: -4.69747263e-08} + rotation: {x: -.21105209, y: -.974394083, z: .0173116997, w: -.0755877346} + scale: {x: .999999821, y: 1.00000012, z: .999999702} + transformModified: 1 + - name: RightForeArm + position: {x: .253428489, y: .00601093518, z: -.0167045332} + rotation: {x: -.00061651913, y: .022078624, z: -.0160702355, w: .999626875} + scale: {x: .99999994, y: .999999881, z: .99999994} + transformModified: 1 + - name: RightHand + position: {x: .245373741, y: .0216420237, z: .00555047346} + rotation: {x: 5.43189438e-10, y: 3.12476184e-10, z: .0214136969, w: .999770641} + scale: {x: 1, y: 1, z: 1.00000012} + transformModified: 1 + - name: RightHandIndex1 + position: {x: .0747697875, y: -.00124282821, z: .0343445241} + rotation: {x: -.00211892067, y: .0802574307, z: .0175381824, w: .996617556} + scale: {x: 1.00000012, y: 1, z: .99999994} + transformModified: 1 + - name: RightHandIndex2 + position: {x: .037058223, y: .000725421763, z: .0145388739} + rotation: {x: -.0033212963, y: .0159312561, z: .060620904, w: .998028159} + scale: {x: 1, y: .99999994, z: 1} + transformModified: 1 + - name: RightHandIndex3 + position: {x: .0252250955, y: -.00496621709, z: .0110121826} + rotation: {x: 2.16179208e-09, y: 1.06850013e-08, z: -8.50230109e-09, w: .99999994} + scale: {x: 1, y: 1.00000012, z: 1.00000012} + transformModified: 1 + - name: RightHandMiddle1 + position: {x: .0756474286, y: .00479083089, z: .0118531957} + rotation: {x: -.00076887355, y: .0333210677, z: .0209075324, w: .999225616} + scale: {x: 1.00000012, y: .999999821, z: .999999881} + transformModified: 1 + - name: RightHandMiddle2 + position: {x: .0438093096, y: .000194165463, z: .00645493949} + rotation: {x: -.00413025497, y: -.0335112251, z: .0761189312, w: .996526897} + scale: {x: 1, y: .999999881, z: 1.00000012} + transformModified: 1 + - name: RightHandMiddle3 + position: {x: .0330725648, y: -.00754737761, z: .00168985641} + rotation: {x: -3.7425496e-10, y: -4.22918101e-09, z: -1.05837286e-08, w: .99999994} + scale: {x: 1, y: .999999881, z: 1} + transformModified: 1 + - name: RightHandPinky1 + position: {x: .0668031499, y: -.00199452811, z: -.0307561476} + rotation: {x: .00317558926, y: -.192005113, z: .045110438, w: .980351448} + scale: {x: 1.00000024, y: 1, z: .99999994} + transformModified: 1 + - name: RightHandPinky2 + position: {x: .0285309609, y: -.00139694544, z: -.0116238492} + rotation: {x: -.000170628482, y: -.00966134109, z: -.0053623952, w: .999938965} + scale: {x: .999999881, y: 1, z: .99999994} + transformModified: 1 + - name: RightHandPinky3 + position: {x: .0214269403, y: -.000553725113, z: -.00851663202} + rotation: {x: -8.53474014e-10, y: 1.63788556e-08, z: -1.38467984e-08, w: .99999994} + scale: {x: 1, y: 1, z: 1.00000012} + transformModified: 1 + - name: RightHandRing1 + position: {x: .070598565, y: .00245756772, z: -.00982147083} + rotation: {x: .000710569788, y: -.054343082, z: .0349452496, w: .99791038} + scale: {x: 1.00000012, y: 1, z: 1} + transformModified: 1 + - name: RightHandRing2 + position: {x: .0428872742, y: -.0013759057, z: -.00494588772} + rotation: {x: .000482838717, y: -.0212902706, z: .0698495656, w: .997330129} + scale: {x: 1, y: 1, z: 1.00000024} + transformModified: 1 + - name: RightHandRing3 + position: {x: .0295008179, y: -.00769269653, z: -.00462226616} + rotation: {x: -2.61377653e-09, y: -8.06309508e-09, z: -6.11845863e-09, w: .99999994} + scale: {x: 1, y: 1, z: 1.00000012} + transformModified: 1 + - name: RightHandThumb1 + position: {x: .014684936, y: -.0111049525, z: .025858108} + rotation: {x: -.0128134973, y: -.00325657148, z: .0314576477, w: .999417663} + scale: {x: 1.00000012, y: 1, z: 1} + transformModified: 1 + - name: RightHandThumb2 + position: {x: .0163741205, y: -.00528976135, z: .0234913807} + rotation: {x: -.0260671675, y: -.0966875851, z: -.00360274338, w: .994966805} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: RightHandThumb3 + position: {x: .0254600029, y: -.00764030218, z: .0208330136} + rotation: {x: 1.31814044e-08, y: 1.05642828e-09, z: -2.01141503e-09, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + armTwist: .5 + foreArmTwist: .5 + upperLegTwist: .5 + legTwist: .5 + armStretch: .0500000007 + legStretch: .0500000007 + feetSpacing: 0 + rootMotionBoneName: + lastHumanDescriptionAvatarSource: {fileID: 9000000, guid: 2ab0893f5bba9b243b65e309e78089d0, + type: 3} + animationType: 3 + additionalBone: 0 + userData: diff --git a/Assets/Photon Unity Networking/Demos/Shared Assets/Animations/RapidStrafe_Right.fbx b/Assets/Photon Unity Networking/Demos/Shared Assets/Animations/RapidStrafe_Right.fbx new file mode 100644 index 0000000..6ecb91b Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/Shared Assets/Animations/RapidStrafe_Right.fbx differ diff --git a/Assets/Photon Unity Networking/Demos/Shared Assets/Animations/RapidStrafe_Right.fbx.meta b/Assets/Photon Unity Networking/Demos/Shared Assets/Animations/RapidStrafe_Right.fbx.meta new file mode 100644 index 0000000..9497cd0 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/Shared Assets/Animations/RapidStrafe_Right.fbx.meta @@ -0,0 +1,957 @@ +fileFormatVersion: 2 +guid: 15fe083e5eaac314d8eea8ef3ed65046 +ModelImporter: + serializedVersion: 16 + fileIDToRecycleName: + 100000: //RootNode + 100002: Chest + 100004: Head + 100006: Hips + 100008: Jaw + 100010: JawEND + 100012: LeftArm + 100014: LeftCheek + 100016: LeftEye + 100018: LeftEyelidLower + 100020: LeftEyelidUpper + 100022: LeftFoot + 100024: LeftForeArm + 100026: LeftHand + 100028: LeftHandIndex1 + 100030: LeftHandIndex2 + 100032: LeftHandIndex3 + 100034: LeftHandMiddle1 + 100036: LeftHandMiddle2 + 100038: LeftHandMiddle3 + 100040: LeftHandPinky1 + 100042: LeftHandPinky2 + 100044: LeftHandPinky3 + 100046: LeftHandRing1 + 100048: LeftHandRing2 + 100050: LeftHandRing3 + 100052: LeftHandThumb1 + 100054: LeftHandThumb2 + 100056: LeftHandThumb3 + 100058: LeftInnerBrow + 100060: LeftIOuterBrow + 100062: LeftLeg + 100064: LeftLipCorner + 100066: LeftLipLower + 100068: LeftLipUpper + 100070: LeftNostril + 100072: LeftShoulder + 100074: LeftToes + 100076: LeftUpLeg + 100078: Neck + 100080: Pivot + 100082: Reference + 100084: RightArm + 100086: RightCheek + 100088: RightEye + 100090: RightEyelidLower + 100092: RightEyelidUpper + 100094: RightFoot + 100096: RightForeArm + 100098: RightHand + 100100: RightHandIndex1 + 100102: RightHandIndex2 + 100104: RightHandIndex3 + 100106: RightHandMiddle1 + 100108: RightHandMiddle2 + 100110: RightHandMiddle3 + 100112: RightHandPinky1 + 100114: RightHandPinky2 + 100116: RightHandPinky3 + 100118: RightHandRing1 + 100120: RightHandRing2 + 100122: RightHandRing3 + 100124: RightHandThumb1 + 100126: RightHandThumb2 + 100128: RightHandThumb3 + 100130: RightInnerBrow + 100132: RightIOuterBrow + 100134: RightLeg + 100136: RightLipCorner + 100138: RightLipLower + 100140: RightLipUpper + 100142: RightNostril + 100144: RightShoulder + 100146: RightToes + 100148: RightUpLeg + 100150: Root + 100152: Spine + 100154: TongueBack + 100156: TongueTip + 400000: //RootNode + 400002: Chest + 400004: Head + 400006: Hips + 400008: Jaw + 400010: JawEND + 400012: LeftArm + 400014: LeftCheek + 400016: LeftEye + 400018: LeftEyelidLower + 400020: LeftEyelidUpper + 400022: LeftFoot + 400024: LeftForeArm + 400026: LeftHand + 400028: LeftHandIndex1 + 400030: LeftHandIndex2 + 400032: LeftHandIndex3 + 400034: LeftHandMiddle1 + 400036: LeftHandMiddle2 + 400038: LeftHandMiddle3 + 400040: LeftHandPinky1 + 400042: LeftHandPinky2 + 400044: LeftHandPinky3 + 400046: LeftHandRing1 + 400048: LeftHandRing2 + 400050: LeftHandRing3 + 400052: LeftHandThumb1 + 400054: LeftHandThumb2 + 400056: LeftHandThumb3 + 400058: LeftInnerBrow + 400060: LeftIOuterBrow + 400062: LeftLeg + 400064: LeftLipCorner + 400066: LeftLipLower + 400068: LeftLipUpper + 400070: LeftNostril + 400072: LeftShoulder + 400074: LeftToes + 400076: LeftUpLeg + 400078: Neck + 400080: Pivot + 400082: Reference + 400084: RightArm + 400086: RightCheek + 400088: RightEye + 400090: RightEyelidLower + 400092: RightEyelidUpper + 400094: RightFoot + 400096: RightForeArm + 400098: RightHand + 400100: RightHandIndex1 + 400102: RightHandIndex2 + 400104: RightHandIndex3 + 400106: RightHandMiddle1 + 400108: RightHandMiddle2 + 400110: RightHandMiddle3 + 400112: RightHandPinky1 + 400114: RightHandPinky2 + 400116: RightHandPinky3 + 400118: RightHandRing1 + 400120: RightHandRing2 + 400122: RightHandRing3 + 400124: RightHandThumb1 + 400126: RightHandThumb2 + 400128: RightHandThumb3 + 400130: RightInnerBrow + 400132: RightIOuterBrow + 400134: RightLeg + 400136: RightLipCorner + 400138: RightLipLower + 400140: RightLipUpper + 400142: RightNostril + 400144: RightShoulder + 400146: RightToes + 400148: RightUpLeg + 400150: Root + 400152: Spine + 400154: TongueBack + 400156: TongueTip + 7400000: RapidStrafe_Right + 9500000: //RootNode + materials: + importMaterials: 1 + materialName: 0 + materialSearch: 1 + animations: + legacyGenerateAnimations: 4 + bakeSimulation: 0 + optimizeGameObjects: 0 + animationCompression: 1 + animationRotationError: .5 + animationPositionError: .5 + animationScaleError: .5 + animationWrapMode: 0 + extraExposedTransformPaths: [] + clipAnimations: + - serializedVersion: 16 + name: RapidStrafe_Right + takeName: _60_a_U1_M_P_RapidStrafe_90HipsLeftFaceFwd__Fb_p90_No_0_PJ_5 + firstFrame: 160 + lastFrame: 178 + wrapMode: 0 + orientationOffsetY: 0 + level: 0 + cycleOffset: 0 + loop: 0 + loopTime: 1 + loopBlend: 0 + loopBlendOrientation: 0 + loopBlendPositionY: 0 + loopBlendPositionXZ: 0 + keepOriginalOrientation: 0 + keepOriginalPositionY: 1 + keepOriginalPositionXZ: 0 + heightFromFeet: 0 + mirror: 0 + bodyMask: 01000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000 + curves: [] + events: [] + transformMask: [] + maskType: 0 + maskSource: {instanceID: 0} + isReadable: 1 + meshes: + lODScreenPercentages: [] + globalScale: .00999999978 + meshCompression: 0 + addColliders: 0 + importBlendShapes: 1 + swapUVChannels: 0 + generateSecondaryUV: 0 + useFileUnits: 1 + optimizeMeshForGPU: 1 + weldVertices: 1 + secondaryUVAngleDistortion: 8 + secondaryUVAreaDistortion: 15.000001 + secondaryUVHardAngle: 88 + secondaryUVPackMargin: 4 + tangentSpace: + normalSmoothAngle: 60 + splitTangentsAcrossUV: 1 + normalImportMode: 0 + tangentImportMode: 1 + importAnimation: 1 + copyAvatar: 1 + humanDescription: + human: + - boneName: Hips + humanName: Hips + limit: + min: {x: -40, y: -40, z: -40} + max: {x: 40, y: 40, z: 40} + value: {x: .0748811588, y: 0, z: .0374405794} + length: .0936014801 + modified: 1 + - boneName: LeftUpLeg + humanName: LeftUpperLeg + limit: + min: {x: -60.0000038, y: -60.0000038, z: -90} + max: {x: 60.0000038, y: 60.0000038, z: 50} + value: {x: .327766716, y: 0, z: .163883358} + length: .40970853 + modified: 1 + - boneName: RightUpLeg + humanName: RightUpperLeg + limit: + min: {x: -60.0000038, y: -60.0000038, z: -90} + max: {x: 60.0000038, y: 60.0000038, z: 50} + value: {x: .327766716, y: 0, z: .163883358} + length: .40970853 + modified: 1 + - boneName: LeftLeg + humanName: LeftLowerLeg + limit: + min: {x: -90, y: 0, z: -80} + max: {x: 90, y: 0, z: 80} + value: {x: .338686436, y: 0, z: .169343218} + length: .423358172 + modified: 1 + - boneName: RightLeg + humanName: RightLowerLeg + limit: + min: {x: -90, y: 0, z: -80} + max: {x: 90, y: 0, z: 80} + value: {x: .338686436, y: 0, z: .169343218} + length: .423358172 + modified: 1 + - boneName: LeftFoot + humanName: LeftFoot + limit: + min: {x: 0, y: -30.0000019, z: -50} + max: {x: 0, y: 30.0000019, z: 50} + value: {x: .0686753467, y: 0, z: .0343376733} + length: .0858442187 + modified: 1 + - boneName: RightFoot + humanName: RightFoot + limit: + min: {x: 0, y: -30.0000019, z: -50} + max: {x: 0, y: 30.0000019, z: 50} + value: {x: .0686753467, y: 0, z: .0343376733} + length: .0858442187 + modified: 1 + - boneName: Spine + humanName: Spine + limit: + min: {x: -40, y: -40, z: -40} + max: {x: 40, y: 40, z: 40} + value: {x: .131201819, y: 0, z: .0656009093} + length: .164002344 + modified: 1 + - boneName: Chest + humanName: Chest + limit: + min: {x: -40, y: -40, z: -40} + max: {x: 40, y: 40, z: 40} + value: {x: .190353557, y: 0, z: .0951767787} + length: .237942025 + modified: 1 + - boneName: Neck + humanName: Neck + limit: + min: {x: -40, y: -40, z: -40} + max: {x: 40, y: 40, z: 40} + value: {x: .0855657607, y: 0, z: .0427828804} + length: .106957234 + modified: 1 + - boneName: Head + humanName: Head + limit: + min: {x: -40, y: -40, z: -40} + max: {x: 40, y: 40, z: 40} + value: {x: .0855657607, y: 0, z: .0427828804} + length: .106957234 + modified: 1 + - boneName: LeftShoulder + humanName: LeftShoulder + limit: + min: {x: 0, y: -15.000001, z: -15.000001} + max: {x: 0, y: 15.000001, z: 30.0000019} + value: {x: .072829701, y: 0, z: .0364148505} + length: .0910371616 + modified: 1 + - boneName: RightShoulder + humanName: RightShoulder + limit: + min: {x: 0, y: -15.000001, z: -15.000001} + max: {x: 0, y: 15.000001, z: 30.0000019} + value: {x: .072829701, y: 0, z: .0364148505} + length: .0910371616 + modified: 1 + - boneName: LeftArm + humanName: LeftUpperArm + limit: + min: {x: -90, y: -100, z: -60.0000038} + max: {x: 90, y: 100, z: 100} + value: {x: .203239605, y: 0, z: .101619802} + length: .254049569 + modified: 1 + - boneName: RightArm + humanName: RightUpperArm + limit: + min: {x: -90, y: -100, z: -60.0000038} + max: {x: 90, y: 100, z: 100} + value: {x: .203239575, y: 0, z: .101619788} + length: .25404954 + modified: 1 + - boneName: LeftForeArm + humanName: LeftLowerArm + limit: + min: {x: -90, y: 0, z: -80} + max: {x: 90, y: 0, z: 80} + value: {x: .197111532, y: 0, z: .098555766} + length: .246389478 + modified: 1 + - boneName: RightForeArm + humanName: RightLowerArm + limit: + min: {x: -90, y: 0, z: -80} + max: {x: 90, y: 0, z: 80} + value: {x: .197110936, y: 0, z: .098555468} + length: .246388748 + modified: 1 + - boneName: LeftHand + humanName: LeftHand + limit: + min: {x: 0, y: -40, z: -80} + max: {x: 0, y: 40, z: 80} + value: {x: .098555766, y: 0, z: .049277883} + length: .123194739 + modified: 1 + - boneName: RightHand + humanName: RightHand + limit: + min: {x: 0, y: -40, z: -80} + max: {x: 0, y: 40, z: 80} + value: {x: .098555468, y: 0, z: .049277734} + length: .123194374 + modified: 1 + - boneName: LeftToes + humanName: LeftToes + limit: + min: {x: 0, y: 0, z: -50} + max: {x: 0, y: 0, z: 50} + value: {x: .0651871562, y: 0, z: .0325935781} + length: .0814839825 + modified: 1 + - boneName: RightToes + humanName: RightToes + limit: + min: {x: 0, y: 0, z: -50} + max: {x: 0, y: 0, z: 50} + value: {x: .0651872903, y: 0, z: .0325936452} + length: .0814841464 + modified: 1 + - boneName: LeftEye + humanName: LeftEye + limit: + min: {x: 0, y: -20, z: -10} + max: {x: 0, y: 20, z: 15.000001} + value: {x: .0799999759, y: 0, z: .0399999879} + length: .100000001 + modified: 1 + - boneName: RightEye + humanName: RightEye + limit: + min: {x: 0, y: -20, z: -10} + max: {x: 0, y: 20, z: 15.000001} + value: {x: .0799999759, y: 0, z: .0399999879} + length: .100000001 + modified: 1 + - boneName: Jaw + humanName: Jaw + limit: + min: {x: 0, y: -10, z: -10} + max: {x: 0, y: 10, z: 10} + value: {x: .0799999759, y: 0, z: .0399999879} + length: .100000001 + modified: 1 + - boneName: LeftHandThumb1 + humanName: Left Thumb Proximal + limit: + min: {x: 0, y: -25, z: -20} + max: {x: 0, y: 25, z: 20} + value: {x: .0232954584, y: 0, z: .0116477292} + length: .0291193314 + modified: 1 + - boneName: LeftHandThumb2 + humanName: Left Thumb Intermediate + limit: + min: {x: 0, y: 0, z: -40} + max: {x: 0, y: 0, z: 35} + value: {x: .0270181261, y: 0, z: .0135090631} + length: .033772666 + modified: 1 + - boneName: LeftHandThumb3 + humanName: Left Thumb Distal + limit: + min: {x: 0, y: 0, z: -40} + max: {x: 0, y: 0, z: 35} + value: {x: .0202635936, y: 0, z: .0101317968} + length: .0253295004 + modified: 1 + - boneName: LeftHandIndex1 + humanName: Left Index Proximal + limit: + min: {x: 0, y: -20, z: -50} + max: {x: 0, y: 20, z: 50} + value: {x: .0318517797, y: 0, z: .0159258898} + length: .0398147404 + modified: 1 + - boneName: LeftHandIndex2 + humanName: Left Index Intermediate + limit: + min: {x: 0, y: 0, z: -45} + max: {x: 0, y: 0, z: 45} + value: {x: .0223747883, y: 0, z: .0111873941} + length: .0279684942 + modified: 1 + - boneName: LeftHandIndex3 + humanName: Left Index Distal + limit: + min: {x: 0, y: 0, z: -45} + max: {x: 0, y: 0, z: 45} + value: {x: .0167810898, y: 0, z: .00839054491} + length: .0209763702 + modified: 1 + - boneName: LeftHandMiddle1 + humanName: Left Middle Proximal + limit: + min: {x: 0, y: -7.50000048, z: -50} + max: {x: 0, y: 7.50000048, z: 50} + value: {x: .0354260914, y: 0, z: .0177130457} + length: .0442826301 + modified: 1 + - boneName: LeftHandMiddle2 + humanName: Left Middle Intermediate + limit: + min: {x: 0, y: 0, z: -45} + max: {x: 0, y: 0, z: 45} + value: {x: .0271718036, y: 0, z: .0135859018} + length: .0339647643 + modified: 1 + - boneName: LeftHandMiddle3 + humanName: Left Middle Distal + limit: + min: {x: 0, y: 0, z: -45} + max: {x: 0, y: 0, z: 45} + value: {x: .0203788504, y: 0, z: .0101894252} + length: .0254735723 + modified: 1 + - boneName: LeftHandRing1 + humanName: Left Ring Proximal + limit: + min: {x: 0, y: -7.50000048, z: -50} + max: {x: 0, y: 7.50000048, z: 50} + value: {x: .0345545448, y: 0, z: .0172772724} + length: .0431931987 + modified: 1 + - boneName: LeftHandRing2 + humanName: Left Ring Intermediate + limit: + min: {x: 0, y: 0, z: -45} + max: {x: 0, y: 0, z: 45} + value: {x: .0246683266, y: 0, z: .0123341633} + length: .030835418 + modified: 1 + - boneName: LeftHandRing3 + humanName: Left Ring Distal + limit: + min: {x: 0, y: 0, z: -45} + max: {x: 0, y: 0, z: 45} + value: {x: .0185012426, y: 0, z: .00925062131} + length: .0231265631 + modified: 1 + - boneName: LeftHandPinky1 + humanName: Left Little Proximal + limit: + min: {x: 0, y: -20, z: -50} + max: {x: 0, y: 20, z: 50} + value: {x: .024671508, y: 0, z: .012335754} + length: .0308393929 + modified: 1 + - boneName: LeftHandPinky2 + humanName: Left Little Intermediate + limit: + min: {x: 0, y: 0, z: -45} + max: {x: 0, y: 0, z: 45} + value: {x: .0184510797, y: 0, z: .00922553986} + length: .023063859 + modified: 1 + - boneName: LeftHandPinky3 + humanName: Left Little Distal + limit: + min: {x: 0, y: 0, z: -45} + max: {x: 0, y: 0, z: 45} + value: {x: .0138383117, y: 0, z: .00691915583} + length: .0172978938 + modified: 1 + - boneName: RightHandThumb1 + humanName: Right Thumb Proximal + limit: + min: {x: 0, y: -25, z: -20} + max: {x: 0, y: 25, z: 20} + value: {x: .0232954752, y: 0, z: .0116477376} + length: .0291193537 + modified: 1 + - boneName: RightHandThumb2 + humanName: Right Thumb Intermediate + limit: + min: {x: 0, y: 0, z: -40} + max: {x: 0, y: 0, z: 35} + value: {x: .0270181969, y: 0, z: .0135090984} + length: .0337727554 + modified: 1 + - boneName: RightHandThumb3 + humanName: Right Thumb Distal + limit: + min: {x: 0, y: 0, z: -40} + max: {x: 0, y: 0, z: 35} + value: {x: .0202636477, y: 0, z: .0101318238} + length: .0253295675 + modified: 1 + - boneName: RightHandIndex1 + humanName: Right Index Proximal + limit: + min: {x: 0, y: -20, z: -50} + max: {x: 0, y: 20, z: 50} + value: {x: .0318517946, y: 0, z: .0159258973} + length: .039814759 + modified: 1 + - boneName: RightHandIndex2 + humanName: Right Index Intermediate + limit: + min: {x: 0, y: 0, z: -45} + max: {x: 0, y: 0, z: 45} + value: {x: .0223747734, y: 0, z: .0111873867} + length: .0279684756 + modified: 1 + - boneName: RightHandIndex3 + humanName: Right Index Distal + limit: + min: {x: 0, y: 0, z: -45} + max: {x: 0, y: 0, z: 45} + value: {x: .0167810787, y: 0, z: .00839053933} + length: .0209763572 + modified: 1 + - boneName: RightHandMiddle1 + humanName: Right Middle Proximal + limit: + min: {x: 0, y: -7.50000048, z: -50} + max: {x: 0, y: 7.50000048, z: 50} + value: {x: .0354261473, y: 0, z: .0177130736} + length: .0442827009 + modified: 1 + - boneName: RightHandMiddle2 + humanName: Right Middle Intermediate + limit: + min: {x: 0, y: 0, z: -45} + max: {x: 0, y: 0, z: 45} + value: {x: .0271718968, y: 0, z: .0135859484} + length: .0339648798 + modified: 1 + - boneName: RightHandMiddle3 + humanName: Right Middle Distal + limit: + min: {x: 0, y: 0, z: -45} + max: {x: 0, y: 0, z: 45} + value: {x: .0203789212, y: 0, z: .0101894606} + length: .0254736599 + modified: 1 + - boneName: RightHandRing1 + humanName: Right Ring Proximal + limit: + min: {x: 0, y: -7.50000048, z: -50} + max: {x: 0, y: 7.50000048, z: 50} + value: {x: .0345547274, y: 0, z: .0172773637} + length: .043193426 + modified: 1 + - boneName: RightHandRing2 + humanName: Right Ring Intermediate + limit: + min: {x: 0, y: 0, z: -45} + max: {x: 0, y: 0, z: 45} + value: {x: .0246685483, y: 0, z: .0123342741} + length: .0308356937 + modified: 1 + - boneName: RightHandRing3 + humanName: Right Ring Distal + limit: + min: {x: 0, y: 0, z: -45} + max: {x: 0, y: 0, z: 45} + value: {x: .0185014084, y: 0, z: .0092507042} + length: .0231267698 + modified: 1 + - boneName: RightHandPinky1 + humanName: Right Little Proximal + limit: + min: {x: 0, y: -20, z: -50} + max: {x: 0, y: 20, z: 50} + value: {x: .0246716533, y: 0, z: .0123358266} + length: .0308395755 + modified: 1 + - boneName: RightHandPinky2 + humanName: Right Little Intermediate + limit: + min: {x: 0, y: 0, z: -45} + max: {x: 0, y: 0, z: 45} + value: {x: .018451266, y: 0, z: .009225633} + length: .0230640918 + modified: 1 + - boneName: RightHandPinky3 + humanName: Right Little Distal + limit: + min: {x: 0, y: 0, z: -45} + max: {x: 0, y: 0, z: 45} + value: {x: .0138384514, y: 0, z: .00691922568} + length: .0172980689 + modified: 1 + skeleton: + - name: DefaultAvatar + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: Reference + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: -0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: Hips + position: {x: 0, y: .963793993, z: -.0235067774} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: LeftUpLeg + position: {x: -.0754494965, y: -.0456640124, z: 0} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: LeftLeg + position: {x: -.0205505043, y: -.409129977, z: .00717136636} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: LeftFoot + position: {x: -.00515300781, y: -.423155904, z: -.0120320898} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: LeftToes + position: {x: -.00748699158, y: -.0731672645, z: .145427138} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: RightUpLeg + position: {x: .0754495338, y: -.0456640124, z: 0} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: RightLeg + position: {x: .0205504671, y: -.409129977, z: .00717136636} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: RightFoot + position: {x: .00515300035, y: -.423155904, z: -.0120320898} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: RightToes + position: {x: .00748699903, y: -.0731672645, z: .14542751} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: Spine + position: {x: 0, y: .0922632217, z: .0157713331} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: Chest + position: {x: 0, y: .162540197, z: .02185072} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: LeftShoulder + position: {x: -.0382435732, y: .192178011, z: -.017063085} + rotation: {x: -.0140067078, y: -.0595068112, z: .228689864, w: .971577883} + scale: {x: 1.00000024, y: 1, z: 1} + transformModified: 1 + - name: LeftArm + position: {x: -.083574675, y: .0360975936, z: -1.50734021e-08} + rotation: {x: .00946438964, y: .0436916873, z: -.223042384, w: .973783076} + scale: {x: 1, y: 1, z: 1.00000012} + transformModified: 1 + - name: LeftForeArm + position: {x: -.254049391, y: 4.70318128e-07, z: -2.19768759e-09} + rotation: {x: -.000616520119, y: .0220786221, z: -.0160702392, w: .999626875} + scale: {x: .99999994, y: 1, z: .999999881} + transformModified: 1 + - name: LeftHand + position: {x: -.246389359, y: -1.89769892e-07, z: -5.73217829e-09} + rotation: {x: 2.86021207e-10, y: -9.59063495e-10, z: -.0214135461, w: .999770701} + scale: {x: .99999994, y: 1, z: 1} + transformModified: 1 + - name: LeftHandIndex1 + position: {x: -.0751256943, y: -.0078413263, z: .0326526687} + rotation: {x: -.00211891974, y: .0802574307, z: .0175381806, w: .996617615} + scale: {x: 1, y: 1, z: .99999994} + transformModified: 1 + - name: LeftHandIndex2 + position: {x: -.0397970602, y: 4.9526192e-05, z: .00118574023} + rotation: {x: .000501931063, y: .0154708987, z: .040414121, w: .999063075} + scale: {x: 1.00000024, y: 1.00000024, z: .99999994} + transformModified: 1 + - name: LeftHandIndex3 + position: {x: -.0279685091, y: -1.79063633e-07, z: -9.18437095e-08} + rotation: {x: 4.33656722e-10, y: -1.75894304e-08, z: -1.0378705e-08, w: .99999994} + scale: {x: 1, y: 1.00000012, z: .999999881} + transformModified: 1 + - name: LeftHandMiddle1 + position: {x: -.0760235488, y: -.00188508059, z: .0101412414} + rotation: {x: -.000768872793, y: .0333210751, z: .0209075306, w: .999225676} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: LeftHandMiddle2 + position: {x: -.0442805924, y: 4.51253936e-06, z: -.000425422273} + rotation: {x: -.0013621418, y: -.0191537701, z: .03788976, w: .999097407} + scale: {x: 1, y: 1.00000012, z: 1} + transformModified: 1 + - name: LeftHandMiddle3 + position: {x: -.0339647792, y: 1.61085282e-07, z: 5.41929612e-09} + rotation: {x: 6.13220641e-10, y: -4.12468948e-09, z: 1.82216331e-09, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: LeftHandPinky1 + position: {x: -.0656598732, y: -.00782526191, z: -.0322512463} + rotation: {x: -.000913206837, y: .0121623212, z: .0212220512, w: .999700367} + scale: {x: 1.00000012, y: 1, z: .999999881} + transformModified: 1 + - name: LeftHandPinky2 + position: {x: -.0308053754, y: -3.11739277e-05, z: -.00144808914} + rotation: {x: -.000170628555, y: -.0096613653, z: -.00536239706, w: .999938905} + scale: {x: 1, y: .999999821, z: 1.00000012} + transformModified: 1 + - name: LeftHandPinky3 + position: {x: -.0230638776, y: -6.67785343e-06, z: 6.90349244e-09} + rotation: {x: -8.51873905e-10, y: -9.4255892e-09, z: -1.31619666e-08, w: .99999994} + scale: {x: 1, y: 1, z: .99999994} + transformModified: 1 + - name: LeftHandRing1 + position: {x: -.0703021139, y: -.00374528999, z: -.0114117898} + rotation: {x: -.000324091874, y: .0115982238, z: .0247380193, w: .999626577} + scale: {x: 1, y: 1.00000024, z: .99999994} + transformModified: 1 + - name: LeftHandRing2 + position: {x: -.0431353189, y: -2.08693382e-05, z: -.00223518023} + rotation: {x: -.0012032456, y: -.0231137592, z: .0409796387, w: .99889189} + scale: {x: .999999881, y: .999999702, z: .99999994} + transformModified: 1 + - name: LeftHandRing3 + position: {x: -.0308354236, y: -1.56879963e-07, z: -1.40963357e-08} + rotation: {x: 4.93614594e-10, y: -1.5807432e-09, z: -5.78796033e-09, w: .99999994} + scale: {x: 1, y: .99999994, z: .999999881} + transformModified: 1 + - name: LeftHandThumb1 + position: {x: -.0142313093, y: -.012377888, z: .0255316831} + rotation: {x: -.0123126386, y: -.0085253641, z: .0125855142, w: .999808609} + scale: {x: 1, y: 1, z: 1.00000012} + transformModified: 1 + - name: LeftHandThumb2 + position: {x: -.0163739249, y: -.00528992061, z: .0234914143} + rotation: {x: -.0260628555, y: .0966900289, z: .00360696716, w: .994966686} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: LeftHandThumb3 + position: {x: -.0254599936, y: -.00763992406, z: .020832995} + rotation: {x: 4.41585328e-08, y: 1.10925613e-09, z: -7.80932541e-10, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: Neck + position: {x: 0, y: .235723972, z: -.0324132554} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: Head + position: {x: 0, y: .106355786, z: .0113267824} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: Jaw + position: {x: 0, y: .0111267567, z: .0103275422} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: LeftEye + position: {x: -.0208482333, y: .0825027227, z: .0554274321} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: RightEye + position: {x: .020849999, y: .0825027227, z: .0554273948} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: RightShoulder + position: {x: .038328547, y: .192177057, z: -.0170630887} + rotation: {x: .228671983, y: .971582115, z: -.0140056778, w: -.05950737} + scale: {x: 1, y: 1.00000012, z: .99999994} + transformModified: 1 + - name: RightArm + position: {x: -.0835753977, y: .0360959396, z: -4.69747263e-08} + rotation: {x: -.21105209, y: -.974394083, z: .0173116997, w: -.0755877346} + scale: {x: .999999821, y: 1.00000012, z: .999999702} + transformModified: 1 + - name: RightForeArm + position: {x: .253428489, y: .00601093518, z: -.0167045332} + rotation: {x: -.00061651913, y: .022078624, z: -.0160702355, w: .999626875} + scale: {x: .99999994, y: .999999881, z: .99999994} + transformModified: 1 + - name: RightHand + position: {x: .245373741, y: .0216420237, z: .00555047346} + rotation: {x: 5.43189438e-10, y: 3.12476184e-10, z: .0214136969, w: .999770641} + scale: {x: 1, y: 1, z: 1.00000012} + transformModified: 1 + - name: RightHandIndex1 + position: {x: .0747697875, y: -.00124282821, z: .0343445241} + rotation: {x: -.00211892067, y: .0802574307, z: .0175381824, w: .996617556} + scale: {x: 1.00000012, y: 1, z: .99999994} + transformModified: 1 + - name: RightHandIndex2 + position: {x: .037058223, y: .000725421763, z: .0145388739} + rotation: {x: -.0033212963, y: .0159312561, z: .060620904, w: .998028159} + scale: {x: 1, y: .99999994, z: 1} + transformModified: 1 + - name: RightHandIndex3 + position: {x: .0252250955, y: -.00496621709, z: .0110121826} + rotation: {x: 2.16179208e-09, y: 1.06850013e-08, z: -8.50230109e-09, w: .99999994} + scale: {x: 1, y: 1.00000012, z: 1.00000012} + transformModified: 1 + - name: RightHandMiddle1 + position: {x: .0756474286, y: .00479083089, z: .0118531957} + rotation: {x: -.00076887355, y: .0333210677, z: .0209075324, w: .999225616} + scale: {x: 1.00000012, y: .999999821, z: .999999881} + transformModified: 1 + - name: RightHandMiddle2 + position: {x: .0438093096, y: .000194165463, z: .00645493949} + rotation: {x: -.00413025497, y: -.0335112251, z: .0761189312, w: .996526897} + scale: {x: 1, y: .999999881, z: 1.00000012} + transformModified: 1 + - name: RightHandMiddle3 + position: {x: .0330725648, y: -.00754737761, z: .00168985641} + rotation: {x: -3.7425496e-10, y: -4.22918101e-09, z: -1.05837286e-08, w: .99999994} + scale: {x: 1, y: .999999881, z: 1} + transformModified: 1 + - name: RightHandPinky1 + position: {x: .0668031499, y: -.00199452811, z: -.0307561476} + rotation: {x: .00317558926, y: -.192005113, z: .045110438, w: .980351448} + scale: {x: 1.00000024, y: 1, z: .99999994} + transformModified: 1 + - name: RightHandPinky2 + position: {x: .0285309609, y: -.00139694544, z: -.0116238492} + rotation: {x: -.000170628482, y: -.00966134109, z: -.0053623952, w: .999938965} + scale: {x: .999999881, y: 1, z: .99999994} + transformModified: 1 + - name: RightHandPinky3 + position: {x: .0214269403, y: -.000553725113, z: -.00851663202} + rotation: {x: -8.53474014e-10, y: 1.63788556e-08, z: -1.38467984e-08, w: .99999994} + scale: {x: 1, y: 1, z: 1.00000012} + transformModified: 1 + - name: RightHandRing1 + position: {x: .070598565, y: .00245756772, z: -.00982147083} + rotation: {x: .000710569788, y: -.054343082, z: .0349452496, w: .99791038} + scale: {x: 1.00000012, y: 1, z: 1} + transformModified: 1 + - name: RightHandRing2 + position: {x: .0428872742, y: -.0013759057, z: -.00494588772} + rotation: {x: .000482838717, y: -.0212902706, z: .0698495656, w: .997330129} + scale: {x: 1, y: 1, z: 1.00000024} + transformModified: 1 + - name: RightHandRing3 + position: {x: .0295008179, y: -.00769269653, z: -.00462226616} + rotation: {x: -2.61377653e-09, y: -8.06309508e-09, z: -6.11845863e-09, w: .99999994} + scale: {x: 1, y: 1, z: 1.00000012} + transformModified: 1 + - name: RightHandThumb1 + position: {x: .014684936, y: -.0111049525, z: .025858108} + rotation: {x: -.0128134973, y: -.00325657148, z: .0314576477, w: .999417663} + scale: {x: 1.00000012, y: 1, z: 1} + transformModified: 1 + - name: RightHandThumb2 + position: {x: .0163741205, y: -.00528976135, z: .0234913807} + rotation: {x: -.0260671675, y: -.0966875851, z: -.00360274338, w: .994966805} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: RightHandThumb3 + position: {x: .0254600029, y: -.00764030218, z: .0208330136} + rotation: {x: 1.31814044e-08, y: 1.05642828e-09, z: -2.01141503e-09, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + armTwist: .5 + foreArmTwist: .5 + upperLegTwist: .5 + legTwist: .5 + armStretch: .0500000007 + legStretch: .0500000007 + feetSpacing: 0 + rootMotionBoneName: + lastHumanDescriptionAvatarSource: {fileID: 9000000, guid: 2ab0893f5bba9b243b65e309e78089d0, + type: 3} + animationType: 3 + additionalBone: 0 + userData: diff --git a/Assets/Photon Unity Networking/Demos/Shared Assets/Animations/RightArm.mask b/Assets/Photon Unity Networking/Demos/Shared Assets/Animations/RightArm.mask new file mode 100644 index 0000000..7fcdd4e --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/Shared Assets/Animations/RightArm.mask @@ -0,0 +1,9 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1011 &101100000 +AvatarBodyMask: + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_Name: RightArm + m_Mask: 00000000000000000000000000000000000000000000000001000000000000000100000000000000000000000000000001000000 diff --git a/Assets/Photon Unity Networking/Demos/Shared Assets/Animations/RightArm.mask.meta b/Assets/Photon Unity Networking/Demos/Shared Assets/Animations/RightArm.mask.meta new file mode 100644 index 0000000..aa3aea9 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/Shared Assets/Animations/RightArm.mask.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: 6880eb91962094861bbf23c5035c40c6 +NativeFormatImporter: + userData: diff --git a/Assets/Photon Unity Networking/Demos/Shared Assets/Animations/Runs.fbx b/Assets/Photon Unity Networking/Demos/Shared Assets/Animations/Runs.fbx new file mode 100644 index 0000000..434dc87 Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/Shared Assets/Animations/Runs.fbx differ diff --git a/Assets/Photon Unity Networking/Demos/Shared Assets/Animations/Runs.fbx.meta b/Assets/Photon Unity Networking/Demos/Shared Assets/Animations/Runs.fbx.meta new file mode 100644 index 0000000..dd53150 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/Shared Assets/Animations/Runs.fbx.meta @@ -0,0 +1,1710 @@ +fileFormatVersion: 2 +guid: b35bea543177b624b8e504a16956614d +ModelImporter: + serializedVersion: 16 + fileIDToRecycleName: + 100000: RightHandMiddle2 + 100002: RightHandMiddle1 + 100004: r_ringProxy_01_geo + 100006: r_ringProxy_02_geo + 100008: r_ringProxy_03_geo + 100010: r_pinkyProxy_01_geo + 100012: r_pinkyProxy_02_geo + 100014: RightShoulderEffector + 100016: LeftShoulderEffector + 100018: ChestEndEffector + 100020: ChestOriginEffector + 100022: RightElbowEffector + 100024: r_pinkyProxy_03_geo + 100026: UNI_01_Upper_teethProxy + 100028: RightEyelidLower + 100030: RightEyelidUpper + 100032: UNI_01_Lower_teethProxy + 100034: UNI_01_TongueTipProxy + 100036: UNI_01_TongueBaseProxy + 100038: RightHandPinkyEffector + 100040: RightHandRingEffector + 100042: RightHandMiddleEffector + 100044: RightHandIndexEffector + 100046: RightHandThumbEffector + 100048: l_middleProxy_02_geo + 100050: l_middleProxy_03_geo + 100052: LeftHandMiddle13 + 100054: l_ringProxy_01_geo + 100056: l_ringProxy_02_geo + 100058: l_ringProxy_03_geo + 100060: r_ankleProxy_geo + 100062: l_clavicleProxy_geo + 100064: l_shourderProxy_geo + 100066: l_erbowProxy_geo + 100068: l_wristProxy_geo + 100070: l_thumbProxy_01_geo + 100072: LeftAnkleEffector + 100074: RightHandMiddle6 + 100076: RightHandMiddle5 + 100078: RightHandMiddle4 + 100080: Character_Ctrl:Reference + 100082: l_ankleProxy_geo + 100084: r_indexProxy_03_geo + 100086: r_middleProxy_01_geo + 100088: r_middleProxy_02_geo + 100090: r_middleProxy_03_geo + 100092: LeftHandMiddle17 + 100094: RightHandMiddle3 + 100096: l_thumbProxy_02_geo + 100098: l_thumbProxy_03_geo + 100100: l_indexProxy_01_geo + 100102: l_indexProxy_02_geo + 100104: l_indexProxy_03_geo + 100106: l_middleProxy_01_geo + 100108: LeftElbowEffector + 100110: RightKneeEffector + 100112: LeftKneeEffector + 100114: RightWristEffector + 100116: LeftWristEffector + 100118: RightAnkleEffector + 100120: r_wristProxy_geo + 100122: r_thumbProxy_01_geo + 100124: r_thumbProxy_02_geo + 100126: r_thumbProxy_03_geo + 100128: r_indexProxy_01_geo + 100130: r_indexProxy_02_geo + 100132: LeftHandPinkyEffector + 100134: LeftHandRingEffector + 100136: LeftHandMiddleEffector + 100138: LeftHandIndexEffector + 100140: LeftHandThumbEffector + 100142: RightHipEffector + 100144: l_pinkyProxy_01_geo + 100146: l_pinkyProxy_02_geo + 100148: l_pinkyProxy_03_geo + 100150: r_clavicleProxy_geo + 100152: r_shourderProxy_geo + 100154: r_erbowProxy_geo + 100156: //RootNode + 100158: LeftHipEffector + 100160: HeadEffector + 100162: HipsEffector + 100164: Head 1 + 100166: Neck 1 + 100168: RightHandPinky6 + 100170: RightHandPinky5 + 100172: RightHandPinky4 + 100174: RightHandRing6 + 100176: RightHandRing5 + 100178: RightHandRing4 + 100180: RightHandIndex6 + 100182: RightHandIndex5 + 100184: RightHandIndex4 + 100186: RightHandThumb6 + 100188: RightHandThumb5 + 100190: RightHandThumb4 + 100192: RightHand 1 + 100194: RightForeArm 1 + 100196: RightArm 1 + 100198: RightShoulder 1 + 100200: LeftHandPinky6 + 100202: LeftHandPinky5 + 100204: LeftHandPinky4 + 100206: LeftHandRing6 + 100208: LeftHandRing5 + 100210: LeftHandRing4 + 100212: LeftHandMiddle6 + 100214: LeftHandMiddle5 + 100216: LeftHandMiddle4 + 100218: LeftHandIndex6 + 100220: LeftHandIndex5 + 100222: LeftHandIndex4 + 100224: LeftHandThumb6 + 100226: LeftHandThumb5 + 100228: LeftHandThumb4 + 100230: LeftHand 1 + 100232: LeftForeArm 1 + 100234: LeftArm 1 + 100236: LeftShoulder 1 + 100238: Spine1 + 100240: Spine 1 + 100242: RightFoot 1 + 100244: RightLeg 1 + 100246: RightUpLeg 1 + 100248: LeftFoot 1 + 100250: LeftLeg 1 + 100252: LeftUpLeg 1 + 100254: Hips 1 + 100256: l_hipProxy_geo + 100258: l_kneeProxy_geo + 100260: l_ballProxy_geo + 100262: LToeBase_End2 + 100264: LeftToes + 100266: LeftFoot + 100268: LeftLeg + 100270: LeftUpLeg + 100272: pelvisProxy_geo + 100274: r_hipProxy_geo + 100276: r_kneeProxy_geo + 100278: r_ballProxy_geo + 100280: LToeBase_End3 + 100282: RightToes + 100284: RightFoot + 100286: RightLeg + 100288: RightUpLeg + 100290: spineProxy_geo + 100292: LeftHandThumb13 + 100294: LeftHandThumb3 + 100296: LeftHandThumb2 + 100298: LeftHandThumb1 + 100300: LeftHandIndex13 + 100302: LeftHandIndex3 + 100304: LeftHandIndex2 + 100306: LeftHandIndex1 + 100308: LeftHandMiddle3 + 100310: LeftHandMiddle2 + 100312: LeftHandMiddle1 + 100314: LeftHandRing13 + 100316: LeftHandRing3 + 100318: LeftHandRing2 + 100320: LeftHandRing1 + 100322: LeftHandPinky13 + 100324: LeftHandPinky3 + 100326: LeftHandPinky2 + 100328: LeftHandPinky1 + 100330: LeftHand + 100332: LeftForeArm + 100334: LeftArm + 100336: LeftShoulder + 100338: chestProxy_geo + 100340: LeftHandThumb17 + 100342: RightHandThumb3 + 100344: RightHandThumb2 + 100346: RightHandThumb1 + 100348: LeftHandIndex17 + 100350: RightHandIndex3 + 100352: RightHandIndex2 + 100354: RightHandIndex1 + 100356: LeftHandRing17 + 100358: RightHandRing3 + 100360: RightHandRing2 + 100362: RightHandRing1 + 100364: LeftHandPinky17 + 100366: RightHandPinky3 + 100368: RightHandPinky2 + 100370: RightHandPinky1 + 100372: RightHand + 100374: RightForeArm + 100376: RightArm + 100378: RightShoulder + 100380: neckProxy_geo + 100382: headProxy_geo + 100384: RightLipUpper + 100386: RightNostril + 100388: RightCheek + 100390: RightIOuterBrow + 100392: RightInnerBrow + 100394: LeftIOuterBrow + 100396: LeftInnerBrow + 100398: LeftEyelidUpper + 100400: LeftEyelidLower + 100402: LeftCheek + 100404: LeftNostril + 100406: LeftLipUpper + 100408: jawProxy_geo + 100410: LeftLipCorner + 100412: RightLipCorner + 100414: RightLipLower + 100416: JawEND + 100418: LeftLipLower + 100420: TongueTip + 100422: TongueBack + 100424: Jaw + 100426: r_UNI_eye + 100428: RightEye + 100430: l_UNI_eye + 100432: LeftEye + 100434: HeadTop_End + 100436: Head + 100438: Neck + 100440: Chest + 100442: Spine + 100444: Hips + 100446: Reference + 400000: RightHandMiddle2 + 400002: RightHandMiddle1 + 400004: r_ringProxy_01_geo + 400006: r_ringProxy_02_geo + 400008: r_ringProxy_03_geo + 400010: r_pinkyProxy_01_geo + 400012: r_pinkyProxy_02_geo + 400014: RightShoulderEffector + 400016: LeftShoulderEffector + 400018: ChestEndEffector + 400020: ChestOriginEffector + 400022: RightElbowEffector + 400024: r_pinkyProxy_03_geo + 400026: UNI_01_Upper_teethProxy + 400028: RightEyelidLower + 400030: RightEyelidUpper + 400032: UNI_01_Lower_teethProxy + 400034: UNI_01_TongueTipProxy + 400036: UNI_01_TongueBaseProxy + 400038: RightHandPinkyEffector + 400040: RightHandRingEffector + 400042: RightHandMiddleEffector + 400044: RightHandIndexEffector + 400046: RightHandThumbEffector + 400048: l_middleProxy_02_geo + 400050: l_middleProxy_03_geo + 400052: LeftHandMiddle13 + 400054: l_ringProxy_01_geo + 400056: l_ringProxy_02_geo + 400058: l_ringProxy_03_geo + 400060: r_ankleProxy_geo + 400062: l_clavicleProxy_geo + 400064: l_shourderProxy_geo + 400066: l_erbowProxy_geo + 400068: l_wristProxy_geo + 400070: l_thumbProxy_01_geo + 400072: LeftAnkleEffector + 400074: RightHandMiddle6 + 400076: RightHandMiddle5 + 400078: RightHandMiddle4 + 400080: Character_Ctrl:Reference + 400082: l_ankleProxy_geo + 400084: r_indexProxy_03_geo + 400086: r_middleProxy_01_geo + 400088: r_middleProxy_02_geo + 400090: r_middleProxy_03_geo + 400092: LeftHandMiddle17 + 400094: RightHandMiddle3 + 400096: l_thumbProxy_02_geo + 400098: l_thumbProxy_03_geo + 400100: l_indexProxy_01_geo + 400102: l_indexProxy_02_geo + 400104: l_indexProxy_03_geo + 400106: l_middleProxy_01_geo + 400108: LeftElbowEffector + 400110: RightKneeEffector + 400112: LeftKneeEffector + 400114: RightWristEffector + 400116: LeftWristEffector + 400118: RightAnkleEffector + 400120: r_wristProxy_geo + 400122: r_thumbProxy_01_geo + 400124: r_thumbProxy_02_geo + 400126: r_thumbProxy_03_geo + 400128: r_indexProxy_01_geo + 400130: r_indexProxy_02_geo + 400132: LeftHandPinkyEffector + 400134: LeftHandRingEffector + 400136: LeftHandMiddleEffector + 400138: LeftHandIndexEffector + 400140: LeftHandThumbEffector + 400142: RightHipEffector + 400144: l_pinkyProxy_01_geo + 400146: l_pinkyProxy_02_geo + 400148: l_pinkyProxy_03_geo + 400150: r_clavicleProxy_geo + 400152: r_shourderProxy_geo + 400154: r_erbowProxy_geo + 400156: //RootNode + 400158: LeftHipEffector + 400160: HeadEffector + 400162: HipsEffector + 400164: Head 1 + 400166: Neck 1 + 400168: RightHandPinky6 + 400170: RightHandPinky5 + 400172: RightHandPinky4 + 400174: RightHandRing6 + 400176: RightHandRing5 + 400178: RightHandRing4 + 400180: RightHandIndex6 + 400182: RightHandIndex5 + 400184: RightHandIndex4 + 400186: RightHandThumb6 + 400188: RightHandThumb5 + 400190: RightHandThumb4 + 400192: RightHand 1 + 400194: RightForeArm 1 + 400196: RightArm 1 + 400198: RightShoulder 1 + 400200: LeftHandPinky6 + 400202: LeftHandPinky5 + 400204: LeftHandPinky4 + 400206: LeftHandRing6 + 400208: LeftHandRing5 + 400210: LeftHandRing4 + 400212: LeftHandMiddle6 + 400214: LeftHandMiddle5 + 400216: LeftHandMiddle4 + 400218: LeftHandIndex6 + 400220: LeftHandIndex5 + 400222: LeftHandIndex4 + 400224: LeftHandThumb6 + 400226: LeftHandThumb5 + 400228: LeftHandThumb4 + 400230: LeftHand 1 + 400232: LeftForeArm 1 + 400234: LeftArm 1 + 400236: LeftShoulder 1 + 400238: Spine1 + 400240: Spine 1 + 400242: RightFoot 1 + 400244: RightLeg 1 + 400246: RightUpLeg 1 + 400248: LeftFoot 1 + 400250: LeftLeg 1 + 400252: LeftUpLeg 1 + 400254: Hips 1 + 400256: l_hipProxy_geo + 400258: l_kneeProxy_geo + 400260: l_ballProxy_geo + 400262: LToeBase_End2 + 400264: LeftToes + 400266: LeftFoot + 400268: LeftLeg + 400270: LeftUpLeg + 400272: pelvisProxy_geo + 400274: r_hipProxy_geo + 400276: r_kneeProxy_geo + 400278: r_ballProxy_geo + 400280: LToeBase_End3 + 400282: RightToes + 400284: RightFoot + 400286: RightLeg + 400288: RightUpLeg + 400290: spineProxy_geo + 400292: LeftHandThumb13 + 400294: LeftHandThumb3 + 400296: LeftHandThumb2 + 400298: LeftHandThumb1 + 400300: LeftHandIndex13 + 400302: LeftHandIndex3 + 400304: LeftHandIndex2 + 400306: LeftHandIndex1 + 400308: LeftHandMiddle3 + 400310: LeftHandMiddle2 + 400312: LeftHandMiddle1 + 400314: LeftHandRing13 + 400316: LeftHandRing3 + 400318: LeftHandRing2 + 400320: LeftHandRing1 + 400322: LeftHandPinky13 + 400324: LeftHandPinky3 + 400326: LeftHandPinky2 + 400328: LeftHandPinky1 + 400330: LeftHand + 400332: LeftForeArm + 400334: LeftArm + 400336: LeftShoulder + 400338: chestProxy_geo + 400340: LeftHandThumb17 + 400342: RightHandThumb3 + 400344: RightHandThumb2 + 400346: RightHandThumb1 + 400348: LeftHandIndex17 + 400350: RightHandIndex3 + 400352: RightHandIndex2 + 400354: RightHandIndex1 + 400356: LeftHandRing17 + 400358: RightHandRing3 + 400360: RightHandRing2 + 400362: RightHandRing1 + 400364: LeftHandPinky17 + 400366: RightHandPinky3 + 400368: RightHandPinky2 + 400370: RightHandPinky1 + 400372: RightHand + 400374: RightForeArm + 400376: RightArm + 400378: RightShoulder + 400380: neckProxy_geo + 400382: headProxy_geo + 400384: RightLipUpper + 400386: RightNostril + 400388: RightCheek + 400390: RightIOuterBrow + 400392: RightInnerBrow + 400394: LeftIOuterBrow + 400396: LeftInnerBrow + 400398: LeftEyelidUpper + 400400: LeftEyelidLower + 400402: LeftCheek + 400404: LeftNostril + 400406: LeftLipUpper + 400408: jawProxy_geo + 400410: LeftLipCorner + 400412: RightLipCorner + 400414: RightLipLower + 400416: JawEND + 400418: LeftLipLower + 400420: TongueTip + 400422: TongueBack + 400424: Jaw + 400426: r_UNI_eye + 400428: RightEye + 400430: l_UNI_eye + 400432: LeftEye + 400434: HeadTop_End + 400436: Head + 400438: Neck + 400440: Chest + 400442: Spine + 400444: Hips + 400446: Reference + 2300000: r_ringProxy_01_geo + 2300002: r_ringProxy_02_geo + 2300004: r_ringProxy_03_geo + 2300006: r_pinkyProxy_01_geo + 2300008: r_pinkyProxy_02_geo + 2300010: r_pinkyProxy_03_geo + 2300012: UNI_01_Upper_teethProxy + 2300014: UNI_01_Lower_teethProxy + 2300016: UNI_01_TongueTipProxy + 2300018: UNI_01_TongueBaseProxy + 2300020: l_middleProxy_02_geo + 2300022: l_middleProxy_03_geo + 2300024: l_ringProxy_01_geo + 2300026: l_ringProxy_02_geo + 2300028: l_ringProxy_03_geo + 2300030: r_ankleProxy_geo + 2300032: l_clavicleProxy_geo + 2300034: l_shourderProxy_geo + 2300036: l_erbowProxy_geo + 2300038: l_wristProxy_geo + 2300040: l_thumbProxy_01_geo + 2300042: l_ankleProxy_geo + 2300044: r_indexProxy_03_geo + 2300046: r_middleProxy_01_geo + 2300048: r_middleProxy_02_geo + 2300050: r_middleProxy_03_geo + 2300052: l_thumbProxy_02_geo + 2300054: l_thumbProxy_03_geo + 2300056: l_indexProxy_01_geo + 2300058: l_indexProxy_02_geo + 2300060: l_indexProxy_03_geo + 2300062: l_middleProxy_01_geo + 2300064: r_wristProxy_geo + 2300066: r_thumbProxy_01_geo + 2300068: r_thumbProxy_02_geo + 2300070: r_thumbProxy_03_geo + 2300072: r_indexProxy_01_geo + 2300074: r_indexProxy_02_geo + 2300076: l_pinkyProxy_01_geo + 2300078: l_pinkyProxy_02_geo + 2300080: l_pinkyProxy_03_geo + 2300082: r_clavicleProxy_geo + 2300084: r_shourderProxy_geo + 2300086: r_erbowProxy_geo + 2300088: l_hipProxy_geo + 2300090: l_kneeProxy_geo + 2300092: l_ballProxy_geo + 2300094: pelvisProxy_geo + 2300096: r_hipProxy_geo + 2300098: r_kneeProxy_geo + 2300100: r_ballProxy_geo + 2300102: spineProxy_geo + 2300104: chestProxy_geo + 2300106: neckProxy_geo + 2300108: headProxy_geo + 2300110: jawProxy_geo + 2300112: r_UNI_eye + 2300114: l_UNI_eye + 3300000: r_ringProxy_01_geo + 3300002: r_ringProxy_02_geo + 3300004: r_ringProxy_03_geo + 3300006: r_pinkyProxy_01_geo + 3300008: r_pinkyProxy_02_geo + 3300010: r_pinkyProxy_03_geo + 3300012: UNI_01_Upper_teethProxy + 3300014: UNI_01_Lower_teethProxy + 3300016: UNI_01_TongueTipProxy + 3300018: UNI_01_TongueBaseProxy + 3300020: l_middleProxy_02_geo + 3300022: l_middleProxy_03_geo + 3300024: l_ringProxy_01_geo + 3300026: l_ringProxy_02_geo + 3300028: l_ringProxy_03_geo + 3300030: r_ankleProxy_geo + 3300032: l_clavicleProxy_geo + 3300034: l_shourderProxy_geo + 3300036: l_erbowProxy_geo + 3300038: l_wristProxy_geo + 3300040: l_thumbProxy_01_geo + 3300042: l_ankleProxy_geo + 3300044: r_indexProxy_03_geo + 3300046: r_middleProxy_01_geo + 3300048: r_middleProxy_02_geo + 3300050: r_middleProxy_03_geo + 3300052: l_thumbProxy_02_geo + 3300054: l_thumbProxy_03_geo + 3300056: l_indexProxy_01_geo + 3300058: l_indexProxy_02_geo + 3300060: l_indexProxy_03_geo + 3300062: l_middleProxy_01_geo + 3300064: r_wristProxy_geo + 3300066: r_thumbProxy_01_geo + 3300068: r_thumbProxy_02_geo + 3300070: r_thumbProxy_03_geo + 3300072: r_indexProxy_01_geo + 3300074: r_indexProxy_02_geo + 3300076: l_pinkyProxy_01_geo + 3300078: l_pinkyProxy_02_geo + 3300080: l_pinkyProxy_03_geo + 3300082: r_clavicleProxy_geo + 3300084: r_shourderProxy_geo + 3300086: r_erbowProxy_geo + 3300088: l_hipProxy_geo + 3300090: l_kneeProxy_geo + 3300092: l_ballProxy_geo + 3300094: pelvisProxy_geo + 3300096: r_hipProxy_geo + 3300098: r_kneeProxy_geo + 3300100: r_ballProxy_geo + 3300102: spineProxy_geo + 3300104: chestProxy_geo + 3300106: neckProxy_geo + 3300108: headProxy_geo + 3300110: jawProxy_geo + 3300112: r_UNI_eye + 3300114: l_UNI_eye + 4300000: l_UNI_eye + 4300002: r_UNI_eye + 4300004: UNI_01_TongueBaseProxy + 4300006: UNI_01_TongueTipProxy + 4300008: UNI_01_Lower_teethProxy + 4300010: jawProxy_geo + 4300012: headProxy_geo + 4300014: UNI_01_Upper_teethProxy + 4300016: neckProxy_geo + 4300018: r_pinkyProxy_03_geo + 4300020: r_pinkyProxy_02_geo + 4300022: r_pinkyProxy_01_geo + 4300024: r_ringProxy_03_geo + 4300026: r_ringProxy_02_geo + 4300028: r_ringProxy_01_geo + 4300030: r_middleProxy_03_geo + 4300032: r_middleProxy_02_geo + 4300034: r_middleProxy_01_geo + 4300036: r_indexProxy_03_geo + 4300038: r_indexProxy_02_geo + 4300040: r_indexProxy_01_geo + 4300042: r_thumbProxy_03_geo + 4300044: r_thumbProxy_02_geo + 4300046: r_thumbProxy_01_geo + 4300048: r_wristProxy_geo + 4300050: r_erbowProxy_geo + 4300052: r_shourderProxy_geo + 4300054: r_clavicleProxy_geo + 4300056: chestProxy_geo + 4300058: l_pinkyProxy_03_geo + 4300060: l_pinkyProxy_02_geo + 4300062: l_pinkyProxy_01_geo + 4300064: l_ringProxy_03_geo + 4300066: l_ringProxy_02_geo + 4300068: l_ringProxy_01_geo + 4300070: l_middleProxy_03_geo + 4300072: l_middleProxy_02_geo + 4300074: l_middleProxy_01_geo + 4300076: l_indexProxy_03_geo + 4300078: l_indexProxy_02_geo + 4300080: l_indexProxy_01_geo + 4300082: l_thumbProxy_03_geo + 4300084: l_thumbProxy_02_geo + 4300086: l_thumbProxy_01_geo + 4300088: l_wristProxy_geo + 4300090: l_erbowProxy_geo + 4300092: l_shourderProxy_geo + 4300094: l_clavicleProxy_geo + 4300096: spineProxy_geo + 4300098: r_ballProxy_geo + 4300100: r_ankleProxy_geo + 4300102: r_kneeProxy_geo + 4300104: r_hipProxy_geo + 4300106: pelvisProxy_geo + 4300108: l_ballProxy_geo + 4300110: l_ankleProxy_geo + 4300112: l_kneeProxy_geo + 4300114: l_hipProxy_geo + 7400000: Take 001 + 7400002: Avatart_T_Stance + 7400004: _24_a_U1_M_P_RunForward_NtrlFaceFwd__Fb_p0_No_0_PJ_10 + 7400006: _32_a_U1_M_P_RunForwardTurnRight_NtrlShort__Fb_Dia1m_No_0_PJ_5 + 7400008: _30_a_U1_M_P_RunForwardTurnRight_NtrlWide__Fb_Dia3m_No_0_PJ_4 + 7400010: _31_a_U1_M_P_RunForwardTurnRight_NtrlMedium__Fb_Dia2m_No_0_PJ_4 + 7400012: IdleToRun0_R + 7400014: Run0 + 7400016: Run0ToIdle_R + 7400018: IdleToRun0_L + 7400020: Run0ToIdle_L + 7400022: RunRight + 7400024: Run + 7400026: RunLeft + 7400028: __preview__RunRight + 7400030: __preview__Run + 7400032: __preview__RunLeft + 9500000: //RootNode + 11100000: //RootNode + materials: + importMaterials: 1 + materialName: 0 + materialSearch: 1 + animations: + legacyGenerateAnimations: 4 + bakeSimulation: 0 + optimizeGameObjects: 0 + motionNodeName: + animationCompression: 0 + animationRotationError: .5 + animationPositionError: .5 + animationScaleError: .5 + animationWrapMode: 0 + extraExposedTransformPaths: [] + clipAnimations: + - serializedVersion: 16 + name: Run + takeName: Run + firstFrame: 301.677368 + lastFrame: 318.635284 + wrapMode: 0 + orientationOffsetY: 0 + level: 0 + cycleOffset: 0 + loop: 0 + loopTime: 1 + loopBlend: 1 + loopBlendOrientation: 1 + loopBlendPositionY: 1 + loopBlendPositionXZ: 0 + keepOriginalOrientation: 0 + keepOriginalPositionY: 1 + keepOriginalPositionXZ: 0 + heightFromFeet: 0 + mirror: 0 + bodyMask: 01000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000 + curves: [] + events: [] + transformMask: [] + maskType: 0 + maskSource: {instanceID: 0} + - serializedVersion: 16 + name: RunLeft + takeName: RunLeft + firstFrame: 59.3699989 + lastFrame: 76.3199997 + wrapMode: 0 + orientationOffsetY: 0 + level: 0 + cycleOffset: .5 + loop: 0 + loopTime: 1 + loopBlend: 1 + loopBlendOrientation: 0 + loopBlendPositionY: 1 + loopBlendPositionXZ: 0 + keepOriginalOrientation: 0 + keepOriginalPositionY: 1 + keepOriginalPositionXZ: 0 + heightFromFeet: 0 + mirror: 1 + bodyMask: 01000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000 + curves: [] + events: [] + transformMask: [] + maskType: 0 + maskSource: {instanceID: 0} + - serializedVersion: 16 + name: RunRight + takeName: RunRight + firstFrame: 59.3878822 + lastFrame: 76.346199 + wrapMode: 0 + orientationOffsetY: 0 + level: 0 + cycleOffset: 0 + loop: 0 + loopTime: 1 + loopBlend: 1 + loopBlendOrientation: 0 + loopBlendPositionY: 1 + loopBlendPositionXZ: 0 + keepOriginalOrientation: 0 + keepOriginalPositionY: 1 + keepOriginalPositionXZ: 0 + heightFromFeet: 0 + mirror: 0 + bodyMask: 01000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000 + curves: [] + events: [] + transformMask: [] + maskType: 0 + maskSource: {instanceID: 0} + isReadable: 1 + meshes: + lODScreenPercentages: [] + globalScale: .00999999978 + meshCompression: 0 + addColliders: 0 + importBlendShapes: 1 + swapUVChannels: 0 + generateSecondaryUV: 0 + useFileUnits: 1 + optimizeMeshForGPU: 1 + weldVertices: 1 + secondaryUVAngleDistortion: 8 + secondaryUVAreaDistortion: 15.000001 + secondaryUVHardAngle: 88 + secondaryUVPackMargin: 4 + tangentSpace: + normalSmoothAngle: 60 + splitTangentsAcrossUV: 1 + normalImportMode: 0 + tangentImportMode: 1 + importAnimation: 1 + copyAvatar: 0 + humanDescription: + human: + - boneName: Hips + humanName: Hips + limit: + min: {x: -40, y: -40, z: -40} + max: {x: 40, y: 40, z: 40} + value: {x: .0748811588, y: 0, z: .0374405794} + length: .0936014801 + modified: 1 + - boneName: LeftUpLeg + humanName: LeftUpperLeg + limit: + min: {x: -60.0000038, y: -60.0000038, z: -90} + max: {x: 60.0000038, y: 60.0000038, z: 50} + value: {x: .327766716, y: 0, z: .163883358} + length: .40970853 + modified: 1 + - boneName: RightUpLeg + humanName: RightUpperLeg + limit: + min: {x: -60.0000038, y: -60.0000038, z: -90} + max: {x: 60.0000038, y: 60.0000038, z: 50} + value: {x: .327766716, y: 0, z: .163883358} + length: .40970853 + modified: 1 + - boneName: LeftLeg + humanName: LeftLowerLeg + limit: + min: {x: -90, y: 0, z: -80} + max: {x: 90, y: 0, z: 80} + value: {x: .338686436, y: 0, z: .169343218} + length: .423358172 + modified: 1 + - boneName: RightLeg + humanName: RightLowerLeg + limit: + min: {x: -90, y: 0, z: -80} + max: {x: 90, y: 0, z: 80} + value: {x: .338686436, y: 0, z: .169343218} + length: .423358172 + modified: 1 + - boneName: LeftFoot + humanName: LeftFoot + limit: + min: {x: 0, y: -30.0000019, z: -50} + max: {x: 0, y: 30.0000019, z: 50} + value: {x: .0686753467, y: 0, z: .0343376733} + length: .0858442187 + modified: 1 + - boneName: RightFoot + humanName: RightFoot + limit: + min: {x: 0, y: -30.0000019, z: -50} + max: {x: 0, y: 30.0000019, z: 50} + value: {x: .0686753467, y: 0, z: .0343376733} + length: .0858442187 + modified: 1 + - boneName: Spine + humanName: Spine + limit: + min: {x: -40, y: -40, z: -40} + max: {x: 40, y: 40, z: 40} + value: {x: .131201819, y: 0, z: .0656009093} + length: .164002344 + modified: 1 + - boneName: Chest + humanName: Chest + limit: + min: {x: -40, y: -40, z: -40} + max: {x: 40, y: 40, z: 40} + value: {x: .190353557, y: 0, z: .0951767787} + length: .237942025 + modified: 1 + - boneName: Neck + humanName: Neck + limit: + min: {x: -40, y: -40, z: -40} + max: {x: 40, y: 40, z: 40} + value: {x: .0855657607, y: 0, z: .0427828804} + length: .106957234 + modified: 1 + - boneName: Head + humanName: Head + limit: + min: {x: -40, y: -40, z: -40} + max: {x: 40, y: 40, z: 40} + value: {x: .0855657607, y: 0, z: .0427828804} + length: .106957234 + modified: 1 + - boneName: LeftShoulder + humanName: LeftShoulder + limit: + min: {x: 0, y: -15.000001, z: -15.000001} + max: {x: 0, y: 15.000001, z: 30.0000019} + value: {x: .072829701, y: 0, z: .0364148505} + length: .0910371616 + modified: 1 + - boneName: RightShoulder + humanName: RightShoulder + limit: + min: {x: 0, y: -15.000001, z: -15.000001} + max: {x: 0, y: 15.000001, z: 30.0000019} + value: {x: .072829701, y: 0, z: .0364148505} + length: .0910371616 + modified: 1 + - boneName: LeftArm + humanName: LeftUpperArm + limit: + min: {x: -90, y: -100, z: -60.0000038} + max: {x: 90, y: 100, z: 100} + value: {x: .203239605, y: 0, z: .101619802} + length: .254049569 + modified: 1 + - boneName: RightArm + humanName: RightUpperArm + limit: + min: {x: -90, y: -100, z: -60.0000038} + max: {x: 90, y: 100, z: 100} + value: {x: .203239486, y: 0, z: .101619743} + length: .25404942 + modified: 1 + - boneName: LeftForeArm + humanName: LeftLowerArm + limit: + min: {x: -90, y: 0, z: -80} + max: {x: 90, y: 0, z: 80} + value: {x: .197111428, y: 0, z: .0985557139} + length: .246389359 + modified: 1 + - boneName: RightForeArm + humanName: RightLowerArm + limit: + min: {x: -90, y: 0, z: -80} + max: {x: 90, y: 0, z: 80} + value: {x: .197110936, y: 0, z: .098555468} + length: .246388748 + modified: 1 + - boneName: LeftHand + humanName: LeftHand + limit: + min: {x: 0, y: -40, z: -80} + max: {x: 0, y: 40, z: 80} + value: {x: .0985557139, y: 0, z: .0492778569} + length: .12319468 + modified: 1 + - boneName: RightHand + humanName: RightHand + limit: + min: {x: 0, y: -40, z: -80} + max: {x: 0, y: 40, z: 80} + value: {x: .098555468, y: 0, z: .049277734} + length: .123194374 + modified: 1 + - boneName: LeftToes + humanName: LeftToes + limit: + min: {x: 0, y: 0, z: -50} + max: {x: 0, y: 0, z: 50} + value: {x: .0651871562, y: 0, z: .0325935781} + length: .0814839825 + modified: 1 + - boneName: RightToes + humanName: RightToes + limit: + min: {x: 0, y: 0, z: -50} + max: {x: 0, y: 0, z: 50} + value: {x: .0651872903, y: 0, z: .0325936452} + length: .0814841464 + modified: 1 + - boneName: LeftEye + humanName: LeftEye + limit: + min: {x: 0, y: -20, z: -10} + max: {x: 0, y: 20, z: 15.000001} + value: {x: .0799999759, y: 0, z: .0399999879} + length: .100000001 + modified: 1 + - boneName: RightEye + humanName: RightEye + limit: + min: {x: 0, y: -20, z: -10} + max: {x: 0, y: 20, z: 15.000001} + value: {x: .0799999759, y: 0, z: .0399999879} + length: .100000001 + modified: 1 + - boneName: Jaw + humanName: Jaw + limit: + min: {x: 0, y: -10, z: -10} + max: {x: 0, y: 10, z: 10} + value: {x: .0799999759, y: 0, z: .0399999879} + length: .100000001 + modified: 1 + skeleton: + - name: Runs + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: Reference + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: Hips + position: {x: 0, y: .963793993, z: -.0235067774} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: LeftUpLeg + position: {x: -.0754494965, y: -.0456640124, z: 0} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: l_hipProxy_geo + position: {x: .0754494965, y: -.91813004, z: 0} + rotation: {x: -6.1232336e-17, y: .99999994, z: 6.1232336e-17, w: -6.12323294e-17} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: LeftLeg + position: {x: -.0205505043, y: -.409129977, z: .00717136636} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: l_kneeProxy_geo + position: {x: .0960000008, y: -.509000003, z: .000718647963} + rotation: {x: -6.1232336e-17, y: .99999994, z: 6.1232336e-17, w: -6.12323294e-17} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: LeftFoot + position: {x: -.00515300781, y: -.423155904, z: -.0120320898} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: l_ankleProxy_geo + position: {x: .101153001, y: -.0858440921, z: .0283674989} + rotation: {x: 0, y: -0, z: -0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: LeftToes + position: {x: -.00748699158, y: -.0731672645, z: .145427138} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: l_ballProxy_geo + position: {x: .10864, y: -.0126768006, z: -.117059626} + rotation: {x: 0, y: -0, z: -0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: LToeBase_End2 + position: {x: .0126400003, y: -.0131357787, z: .0358933695} + rotation: {x: 2.4286127e-17, y: -1.21972736e-17, z: 1.040834e-17, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: pelvisProxy_geo + position: {x: -0, y: -.963793993, z: 0} + rotation: {x: 0, y: -0, z: -0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: RightUpLeg + position: {x: .0754495338, y: -.0456640124, z: 0} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: r_hipProxy_geo + position: {x: -.0754495338, y: -.91813004, z: 0} + rotation: {x: 0, y: -0, z: -0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: RightLeg + position: {x: .0205504671, y: -.409129977, z: .00717136636} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: r_kneeProxy_geo + position: {x: -.0960000008, y: -.509000003, z: .000718647963} + rotation: {x: 0, y: -0, z: -0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: RightFoot + position: {x: .00515300035, y: -.423155904, z: -.0120320898} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: r_ankleProxy_geo + position: {x: -.101153001, y: -.0858440921, z: .0283674989} + rotation: {x: 0, y: -0, z: -0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: RightToes + position: {x: .00748699903, y: -.0731672645, z: .14542751} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: LToeBase_End3 + position: {x: -.0126400003, y: -.0131357787, z: .0358929969} + rotation: {x: 8.67361738e-18, y: -2.89210896e-17, z: 2.08166801e-17, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: r_ballProxy_geo + position: {x: -.10864, y: -.0126768006, z: -.117059998} + rotation: {x: 0, y: -0, z: -0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: Spine + position: {x: 0, y: .0922632217, z: .0157713331} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: Chest + position: {x: 0, y: .162540197, z: .02185072} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: chestProxy_geo + position: {x: -2.6469779e-25, y: -1.21859741, z: -.0141152758} + rotation: {x: 0, y: -0, z: -0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: LeftShoulder + position: {x: -.0382435732, y: .192178011, z: -.017063085} + rotation: {x: -.0140067078, y: -.0595068112, z: .228689864, w: .971577883} + scale: {x: 1.00000024, y: 1, z: 1} + transformModified: 1 + - name: l_clavicleProxy_geo + position: {x: -.576741397, y: -1.3202554, z: -.00174654822} + rotation: {x: .0132958526, y: .0596696734, z: -.217083618, w: .974236786} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: LeftArm + position: {x: -.083574675, y: .0360975936, z: -1.50734021e-08} + rotation: {x: .00946438964, y: .0436916873, z: -.223042384, w: .973783076} + scale: {x: 1, y: 1, z: 1.00000012} + transformModified: 1 + - name: l_shourderProxy_geo + position: {x: .145532504, y: -1.39592445, z: .00981439184} + rotation: {x: -9.73998613e-05, y: .0164502338, z: .00591997476, w: .999847114} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: LeftForeArm + position: {x: -.254049391, y: 4.70318128e-07, z: -2.19768759e-09} + rotation: {x: -.000616520003, y: .0220786203, z: -.0160702374, w: .999626815} + scale: {x: .99999994, y: 1, z: .999999881} + transformModified: 1 + - name: l_erbowProxy_geo + position: {x: .443439782, y: -1.38239443, z: .0267205685} + rotation: {x: .000123997524, y: -.00563636655, z: .0219935421, w: .99974221} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: LeftHand + position: {x: -.246389359, y: -1.89769068e-07, z: -5.73265124e-09} + rotation: {x: 2.86021179e-10, y: -9.59063384e-10, z: -.0214135442, w: .999770641} + scale: {x: .99999994, y: 1, z: 1} + transformModified: 1 + - name: l_wristProxy_geo + position: {x: .689829111, y: -1.38239443, z: .0267205685} + rotation: {x: .000123997524, y: -.00563636655, z: .0219935421, w: .99974221} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: LeftHandIndex1 + position: {x: -.0751256943, y: -.0078413263, z: .0326526687} + rotation: {x: -.00211891951, y: .0802574232, z: .0175381787, w: .996617556} + scale: {x: 1, y: 1, z: .99999994} + transformModified: 1 + - name: l_indexProxy_01_geo + position: {x: .707995355, y: -1.40068793, z: .106783867} + rotation: {x: .00037795541, y: -.085902825, z: .00438349554, w: .996293783} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: LeftHandIndex2 + position: {x: -.0397970602, y: 4.9526192e-05, z: .00118574023} + rotation: {x: .000658528355, y: .0156148076, z: .0509195141, w: .998580396} + scale: {x: 1.00000024, y: 1.00000024, z: .99999994} + transformModified: 1 + - name: l_indexProxy_02_geo + position: {x: .597788155, y: -1.46919715, z: .12853159} + rotation: {x: -.00472124387, y: -.101354167, z: -.0462910496, w: .993761599} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: LeftHandIndex3 + position: {x: -.0279685091, y: -1.79063633e-07, z: -9.18437095e-08} + rotation: {x: 7.06372461e-10, y: -1.01822932e-08, z: -1.04085336e-08, w: .99999994} + scale: {x: 1, y: 1.00000012, z: .999999881} + transformModified: 1 + - name: l_indexProxy_03_geo + position: {x: .625756621, y: -1.46919715, z: .128531635} + rotation: {x: -.00472124387, y: -.101354167, z: -.0462910496, w: .993761599} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: LeftHandIndex13 + position: {x: -.0186619535, y: .00437378185, z: -.00384002062} + rotation: {x: -.00472124387, y: -.101354167, z: -.0462910496, w: .993761599} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: LeftHandMiddle1 + position: {x: -.0760235488, y: -.00188508059, z: .0101412414} + rotation: {x: -.000768872735, y: .0333210714, z: .0209075287, w: .999225616} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: l_middleProxy_01_geo + position: {x: .704767466, y: -1.41134179, z: .0634717271} + rotation: {x: 4.18855452e-05, y: -.0389639921, z: .00107416383, w: .999239981} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: LeftHandMiddle2 + position: {x: -.0442805924, y: 4.51253936e-06, z: -.000425422273} + rotation: {x: -.00145348604, y: -.0264088288, z: .0570813306, w: .998019099} + scale: {x: 1, y: 1.00000012, z: 1} + transformModified: 1 + - name: l_middleProxy_02_geo + position: {x: .585567176, y: -1.48780787, z: .0243592989} + rotation: {x: -.000701564888, y: -.0125020016, z: -.056023661, w: .998350859} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: LeftHandMiddle3 + position: {x: -.0339647792, y: 1.61085282e-07, z: 5.41929612e-09} + rotation: {x: 6.13220641e-10, y: -4.12468948e-09, z: 1.82216331e-09, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: l_middleProxy_03_geo + position: {x: .619532049, y: -1.48780787, z: .0243592951} + rotation: {x: -.000701564888, y: -.0125020016, z: -.056023661, w: .998350859} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: LeftHandMiddle13 + position: {x: -.0196716003, y: .00392550742, z: -.000558814674} + rotation: {x: -.000701564888, y: -.0125020016, z: -.056023661, w: .998350859} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: LeftHandPinky1 + position: {x: -.0656598732, y: -.00782526191, z: -.0322512463} + rotation: {x: .000947935856, y: -.0904071629, z: .0333630778, w: .995345414} + scale: {x: 1.00000012, y: 1, z: .999999881} + transformModified: 1 + - name: l_pinkyProxy_01_geo + position: {x: .66101706, y: -1.42205703, z: -.067025952} + rotation: {x: .000976056792, y: .0847904608, z: -.0114691779, w: .996332288} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: LeftHandPinky2 + position: {x: -.0308053754, y: -3.11739277e-05, z: -.00144808914} + rotation: {x: -.000170629763, y: -.0096613802, z: -.00536239706, w: .999938905} + scale: {x: 1, y: .999999821, z: 1.00000012} + transformModified: 1 + - name: l_pinkyProxy_02_geo + position: {x: .705631673, y: -1.41450727, z: -.07956402} + rotation: {x: .000580511522, y: .0944183841, z: -.00612070551, w: .995513558} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: LeftHandPinky3 + position: {x: -.0230638776, y: -6.67785298e-06, z: 7.59126451e-09} + rotation: {x: -2.0493815e-10, y: 5.41109646e-09, z: -1.31806317e-08, w: .99999994} + scale: {x: 1, y: 1, z: .99999994} + transformModified: 1 + - name: l_pinkyProxy_03_geo + position: {x: .72869575, y: -1.41450083, z: -.0795640349} + rotation: {x: .000580511522, y: .0944183841, z: -.00612070551, w: .995513558} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: LeftHandPinky13 + position: {x: -.0169720035, y: .00202884316, z: .00314032449} + rotation: {x: .00058051158, y: .0944183841, z: -.00612070551, w: .995513558} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: LeftHandRing1 + position: {x: -.0703021139, y: -.00374528999, z: -.0114117898} + rotation: {x: .000302014843, y: -.0213824473, z: .0298566632, w: .999325335} + scale: {x: 1, y: 1.00000024, z: .99999994} + transformModified: 1 + - name: l_ringProxy_01_geo + position: {x: .67746079, y: -1.4215858, z: .00821865257} + rotation: {x: .000123969745, y: .0157473143, z: -.00787121616, w: .999844968} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: LeftHandRing2 + position: {x: -.0431353189, y: -2.08693382e-05, z: -.00223518023} + rotation: {x: -.00157919142, y: -.0221169777, z: .0554940216, w: .998212695} + scale: {x: .999999881, y: .999999702, z: .99999994} + transformModified: 1 + - name: l_ringProxy_02_geo + position: {x: .558318734, y: -1.49264503, z: -.0224928856} + rotation: {x: .00240248838, y: .0378382728, z: -.0633204356, w: .99727273} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: LeftHandRing3 + position: {x: -.0308354236, y: -1.57109852e-07, z: -1.43269485e-08} + rotation: {x: -6.36231345e-10, y: -5.2477982e-09, z: -5.76942361e-09, w: .99999994} + scale: {x: 1, y: .99999994, z: .999999881} + transformModified: 1 + - name: l_ringProxy_03_geo + position: {x: .589154303, y: -1.49264503, z: -.0224928688} + rotation: {x: .00240248838, y: .0378382728, z: -.0633204356, w: .99727273} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: LeftHandRing13 + position: {x: -.0205416437, y: .00325418473, z: .00137918349} + rotation: {x: .00240248838, y: .0378382728, z: -.0633204356, w: .99727273} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: LeftHandThumb1 + position: {x: -.0142313093, y: -.012377888, z: .0255316831} + rotation: {x: .000123995487, y: -.00563636562, z: .0219935384, w: .99974221} + scale: {x: 1, y: 1, z: 1.00000012} + transformModified: 1 + - name: l_thumbProxy_01_geo + position: {x: .643102229, y: -1.39965379, z: -.00606264407} + rotation: {x: 1.89761473e-09, y: -1.12757018e-17, z: -5.58892398e-18, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: LeftHandThumb2 + position: {x: -.0163739249, y: -.00528992061, z: .0234914143} + rotation: {x: 7.35145e-10, y: 9.31883903e-10, z: -1.47482648e-08, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: l_thumbProxy_02_geo + position: {x: .659476221, y: -1.39436388, z: -.0295540728} + rotation: {x: 1.89761451e-09, y: 1.42085206e-08, z: -1.75474479e-08, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: LeftHandThumb3 + position: {x: -.0254599936, y: -.00763992406, z: .020832995} + rotation: {x: 4.41585328e-08, y: 1.10925613e-09, z: -7.80932541e-10, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: l_thumbProxy_03_geo + position: {x: .684936106, y: -1.38672376, z: -.0503869802} + rotation: {x: -3.84998025e-08, y: 2.97005407e-08, z: -3.37486235e-08, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: LeftHandThumb13 + position: {x: -.031868998, y: -.00529999891, z: .0258005001} + rotation: {x: -1.38777878e-16, y: -8.32667202e-17, z: -1.6653344e-16, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: Neck + position: {x: 0, y: .235723972, z: -.0324132554} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: Head + position: {x: 0, y: .106355786, z: .0113267824} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: headProxy_geo + position: {x: -0, y: -1.56067717, z: .00697119767} + rotation: {x: 0, y: -0, z: -0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: HeadTop_End + position: {x: -5.17045744e-18, y: .188178703, z: .0121086892} + rotation: {x: 2.08166801e-17, y: -8.56519634e-18, z: 7.80625399e-18, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: Jaw + position: {x: 0, y: .0111267567, z: .0103275422} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: JawEND + position: {x: 0, y: -.0482889414, z: .0718517154} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: jawProxy_geo + position: {x: -1.73472344e-20, y: -1.57180381, z: -.003356345} + rotation: {x: 0, y: -0, z: -0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: LeftLipCorner + position: {x: -.032843262, y: -.0165787935, z: .0661217719} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: LeftLipLower + position: {x: -.0142508168, y: -.0216888189, z: .0822406411} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: RightLipCorner + position: {x: .0328399986, y: -.0165787935, z: .0661187768} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: RightLipLower + position: {x: .0142508168, y: -.0216888189, z: .0822387934} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: TongueBack + position: {x: 0, y: -.0228693485, z: .0100954082} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: UNI_01_TongueBaseProxy + position: {x: -0, y: -1.54893458, z: -.0134517532} + rotation: {x: 0, y: -0, z: -0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: TongueTip + position: {x: 0, y: -.00040948391, z: .0282273013} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: UNI_01_TongueTipProxy + position: {x: -0, y: -1.54852509, z: -.0416790508} + rotation: {x: 0, y: -0, z: -0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: UNI_01_Lower_teethProxy + position: {x: -1.73472344e-20, y: -1.57180381, z: -.003356345} + rotation: {x: 0, y: -0, z: -0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: LeftCheek + position: {x: -.0542440265, y: .0337018967, z: .0594304055} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: LeftEye + position: {x: -.0208482333, y: .0825027227, z: .0554274321} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: l_UNI_eye + position: {x: .0208482333, y: -1.64317989, z: -.048456233} + rotation: {x: 0, y: -0, z: -0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: LeftEyelidLower + position: {x: -.0356189571, y: .0650734901, z: .0762347504} + rotation: {x: -.0348994881, y: 0, z: -0, w: .999390781} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: LeftEyelidUpper + position: {x: -.0344068967, y: .10060811, z: .0802053139} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: LeftInnerBrow + position: {x: -.0120626912, y: .118765235, z: .0934668258} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: LeftIOuterBrow + position: {x: -.0550398715, y: .114825249, z: .0617774054} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: LeftLipUpper + position: {x: -.0145013221, y: -.00511181355, z: .0946188495} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: LeftNostril + position: {x: -.0178999994, y: .0263128281, z: .0908674076} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: RightCheek + position: {x: .0542399958, y: .0337028503, z: .0594273955} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: RightEye + position: {x: .020849999, y: .0825027227, z: .0554273948} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: r_UNI_eye + position: {x: -.020849999, y: -1.64317989, z: -.0484561995} + rotation: {x: 0, y: -0, z: -0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: RightEyelidLower + position: {x: .0356200002, y: .0650727749, z: .0762374178} + rotation: {x: -.0348994881, y: 0, z: -0, w: .999390781} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: RightEyelidUpper + position: {x: .0344099998, y: .10061276, z: .0802074} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: RightInnerBrow + position: {x: .0120626874, y: .118765235, z: .0934668258} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: RightIOuterBrow + position: {x: .0550400019, y: .114822865, z: .0617774054} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: RightLipUpper + position: {x: .0145013221, y: -.00510716438, z: .094617404} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: RightNostril + position: {x: .0178999994, y: .0263088942, z: .0908706263} + rotation: {x: 0, y: 0, z: 0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: UNI_01_Upper_teethProxy + position: {x: -0, y: -1.56067717, z: .00697119767} + rotation: {x: 0, y: -0, z: -0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: neckProxy_geo + position: {x: -2.6469779e-25, y: -1.47760677, z: .0182979777} + rotation: {x: 0, y: -0, z: -0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: RightShoulder + position: {x: .038328547, y: .192177057, z: -.0170630887} + rotation: {x: .228671983, y: .971582115, z: -.0140056778, w: -.05950737} + scale: {x: 1, y: 1.00000012, z: .99999994} + transformModified: 1 + - name: r_clavicleProxy_geo + position: {x: -.576691985, y: -1.32027555, z: .00174657279} + rotation: {x: .217065617, y: .974240839, z: -.0132948142, w: .0596702136} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: RightArm + position: {x: -.0835753977, y: .0360959396, z: -4.69747263e-08} + rotation: {x: -.211052075, y: -.974394023, z: .0173116978, w: -.0755877271} + scale: {x: .999999821, y: 1.00000012, z: .999999702} + transformModified: 1 + - name: r_shourderProxy_geo + position: {x: -.111510262, y: -1.39896846, z: .0182753969} + rotation: {x: -9.73998685e-05, y: .0164502338, z: .00591997476, w: .999847114} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: RightForeArm + position: {x: .253428489, y: .00601093518, z: -.0167045332} + rotation: {x: -.000616519072, y: .0220786221, z: -.0160702337, w: .999626815} + scale: {x: .99999994, y: .999999881, z: .99999994} + transformModified: 1 + - name: r_erbowProxy_geo + position: {x: -.320759475, y: -1.41603601, z: .0180951431} + rotation: {x: .000123997524, y: -.00563636655, z: .0219935421, w: .99974221} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: RightHand + position: {x: .245373741, y: .0216420237, z: .00555047346} + rotation: {x: 5.48409873e-10, y: 3.13884974e-10, z: .0214136951, w: .999770641} + scale: {x: 1, y: 1, z: 1.00000012} + transformModified: 1 + - name: r_wristProxy_geo + position: {x: -.566133142, y: -1.43767774, z: .0125446785} + rotation: {x: .000123997524, y: -.00563636655, z: .0219935421, w: .99974221} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: RightHandIndex1 + position: {x: .0747697875, y: -.00124282786, z: .0343445241} + rotation: {x: -.00211892161, y: .0802574307, z: .0175381824, w: .996617556} + scale: {x: 1.00000012, y: 1, z: .99999994} + transformModified: 1 + - name: r_indexProxy_01_geo + position: {x: -.67848891, y: -1.41288495, z: -.134108156} + rotation: {x: .00037795541, y: -.085902825, z: .00438349554, w: .996293783} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: RightHandIndex2 + position: {x: .037058223, y: .000725421996, z: .0145388739} + rotation: {x: .000658529578, y: .0156148057, z: .0509195291, w: .998580396} + scale: {x: 1, y: .99999994, z: 1} + transformModified: 1 + - name: r_indexProxy_02_geo + position: {x: -.850647688, y: -1.33395886, z: -.171325743} + rotation: {x: -.00472124387, y: -.101354167, z: -.0462910496, w: .993761599} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: RightHandIndex3 + position: {x: .0252250955, y: -.00496621709, z: .0110121826} + rotation: {x: 1.23673272e-09, y: 1.07368576e-08, z: -8.59681037e-09, w: .99999994} + scale: {x: 1, y: 1.00000012, z: 1.00000012} + transformModified: 1 + - name: LeftHandIndex17 + position: {x: .019119991, y: .000846237526, z: .0039816522} + rotation: {x: -.00472124387, y: -.101354167, z: -.0462910496, w: .993761599} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: r_indexProxy_03_geo + position: {x: -.875872731, y: -1.32899249, z: -.182337865} + rotation: {x: -.00472124387, y: -.101354167, z: -.0462910496, w: .993761599} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: RightHandMiddle1 + position: {x: .0756474286, y: .00479083089, z: .0118531957} + rotation: {x: -.000768874481, y: .0333210677, z: .0209075324, w: .999225616} + scale: {x: 1.00000012, y: .999999821, z: .999999881} + transformModified: 1 + - name: r_middleProxy_01_geo + position: {x: -.700037003, y: -1.41435838, z: -.0462522097} + rotation: {x: 4.18855452e-05, y: -.0389639921, z: .00107416383, w: .999239981} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: RightHandMiddle2 + position: {x: .0438093096, y: .000194165928, z: .00645493949} + rotation: {x: -.00145348522, y: -.0264088213, z: .0570813194, w: .998019099} + scale: {x: 1, y: .999999881, z: 1.00000012} + transformModified: 1 + - name: r_middleProxy_02_geo + position: {x: -.902008593, y: -1.32032251, z: -.013138772} + rotation: {x: -.000701564888, y: -.0125020016, z: -.056023661, w: .998350859} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: RightHandMiddle3 + position: {x: .0330725648, y: -.00754737761, z: .00168985641} + rotation: {x: -4.32332725e-10, y: -4.22536495e-09, z: -1.05844622e-08, w: .99999994} + scale: {x: 1, y: .999999881, z: 1} + transformModified: 1 + - name: LeftHandMiddle17 + position: {x: .0200548694, y: -.000547174306, z: .000442590157} + rotation: {x: -.000701564888, y: -.0125020016, z: -.056023661, w: .998350859} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: r_middleProxy_03_geo + position: {x: -.935081065, y: -1.3127749, z: -.0148286186} + rotation: {x: -.000701564888, y: -.0125020016, z: -.056023661, w: .998350859} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: RightHandPinky1 + position: {x: .0668031499, y: -.00199452788, z: -.0307561476} + rotation: {x: .000947934634, y: -.0904071927, z: .0333630815, w: .995345414} + scale: {x: 1.00000024, y: 1, z: .99999994} + transformModified: 1 + - name: r_pinkyProxy_01_geo + position: {x: -.708490908, y: -1.39051926, z: .167834207} + rotation: {x: .000976056792, y: .0847904608, z: -.0114691779, w: .996332288} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: RightHandPinky2 + position: {x: .0285309609, y: -.00139694533, z: -.0116238492} + rotation: {x: -.000170628467, y: -.00966134015, z: -.00536239473, w: .999938905} + scale: {x: .999999881, y: 1, z: .99999994} + transformModified: 1 + - name: r_pinkyProxy_02_geo + position: {x: -.718481421, y: -1.39699113, z: .193045571} + rotation: {x: .000580511522, y: .0944183841, z: -.00612070551, w: .995513558} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: RightHandPinky3 + position: {x: .0214269403, y: -.000553725229, z: -.00851663202} + rotation: {x: 2.73883738e-09, y: 1.63219589e-08, z: -1.41874184e-08, w: .99999994} + scale: {x: 1, y: 1, z: 1.00000012} + transformModified: 1 + - name: LeftHandPinky17 + position: {x: .0169751048, y: .00161139411, z: -.00335796922} + rotation: {x: .00058051158, y: .0944183841, z: -.00612070551, w: .995513558} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: r_pinkyProxy_03_geo + position: {x: -.739908278, y: -1.39643753, z: .201562166} + rotation: {x: .000580511522, y: .0944183841, z: -.00612070551, w: .995513558} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: RightHandRing1 + position: {x: .070598565, y: .00245756796, z: -.00982147083} + rotation: {x: .000302013039, y: -.0213824473, z: .0298566632, w: .999325335} + scale: {x: 1.00000012, y: 1, z: 1} + transformModified: 1 + - name: r_ringProxy_01_geo + position: {x: -.719976664, y: -1.39957821, z: .0522536784} + rotation: {x: .000123969745, y: .0157473143, z: -.00787121616, w: .999844968} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: RightHandRing2 + position: {x: .0428872742, y: -.00137590547, z: -.00494588772} + rotation: {x: -.00157919107, y: -.0221169721, z: .0554940179, w: .998212695} + scale: {x: 1, y: 1, z: 1.00000024} + transformModified: 1 + - name: r_ringProxy_02_geo + position: {x: -.909907341, y: -1.30544066, z: .0899852142} + rotation: {x: .00240248838, y: .0378382728, z: -.0633204356, w: .99727273} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: RightHandRing3 + position: {x: .0295008179, y: -.00769269653, z: -.0046222657} + rotation: {x: -4.8581611e-10, y: -4.48621096e-09, z: -6.17667784e-09, w: .99999994} + scale: {x: 1, y: 1, z: 1.00000012} + transformModified: 1 + - name: LeftHandRing17 + position: {x: .0206709281, y: -.00200046902, z: -.00177803345} + rotation: {x: .00240248838, y: .0378382728, z: -.0633204356, w: .99727273} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: r_ringProxy_03_geo + position: {x: -.939407945, y: -1.29774773, z: .094607465} + rotation: {x: .00240248838, y: .0378382728, z: -.0633204356, w: .99727273} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: RightHandThumb1 + position: {x: .014684936, y: -.0111049516, z: .025858108} + rotation: {x: .000123993843, y: -.00563636841, z: .0219935384, w: .99974221} + scale: {x: 1.00000012, y: 1, z: 1} + transformModified: 1 + - name: r_thumbProxy_01_geo + position: {x: -.64310205, y: -1.39964998, z: -.006062645} + rotation: {x: 1.89764271e-09, y: 1.26634801e-16, z: 1.04058686e-15, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: RightHandThumb2 + position: {x: .0163741205, y: -.00528976228, z: .0234913807} + rotation: {x: 3.75115605e-10, y: 1.0535206e-09, z: -2.01192996e-09, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: r_thumbProxy_02_geo + position: {x: -.659475982, y: -1.39436007, z: -.0295539852} + rotation: {x: 1.89764249e-09, y: 1.42085206e-08, z: -1.75474462e-08, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: RightHandThumb3 + position: {x: .0254600029, y: -.00764030218, z: .0208330136} + rotation: {x: 1.31813698e-08, y: 1.05279052e-09, z: -2.01141948e-09, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: LeftHandThumb17 + position: {x: .031868998, y: -.00529999938, z: .0258005001} + rotation: {x: 1.2143063e-16, y: -2.7755574e-17, z: -2.7755574e-17, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: r_thumbProxy_03_geo + position: {x: -.684936047, y: -1.38671994, z: -.0503868572} + rotation: {x: -3.65033941e-08, y: 2.97005407e-08, z: -3.37486235e-08, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: spineProxy_geo + position: {x: -2.6469779e-25, y: -1.05605721, z: -.0157713313} + rotation: {x: 0, y: -0, z: -0, w: .99999994} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + armTwist: .5 + foreArmTwist: .5 + upperLegTwist: .5 + legTwist: .5 + armStretch: .0500000007 + legStretch: .0500000007 + feetSpacing: 0 + rootMotionBoneName: + lastHumanDescriptionAvatarSource: {instanceID: 0} + animationType: 3 + additionalBone: 1 + userData: diff --git a/Assets/Photon Unity Networking/Demos/Shared Assets/Materials.meta b/Assets/Photon Unity Networking/Demos/Shared Assets/Materials.meta new file mode 100644 index 0000000..6fbc96f --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/Shared Assets/Materials.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: cd70e7139ff694591975f853dfdf7193 +folderAsset: yes +timeCreated: 1501014811 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Photon Unity Networking/Demos/Shared Assets/Materials/Gradient.mat b/Assets/Photon Unity Networking/Demos/Shared Assets/Materials/Gradient.mat new file mode 100644 index 0000000..1925dca Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/Shared Assets/Materials/Gradient.mat differ diff --git a/Assets/Photon Unity Networking/Demos/Shared Assets/Materials/Gradient.mat.meta b/Assets/Photon Unity Networking/Demos/Shared Assets/Materials/Gradient.mat.meta new file mode 100644 index 0000000..f279bfc --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/Shared Assets/Materials/Gradient.mat.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: 32e7ed8e6b80b884bbed8260b788648b +NativeFormatImporter: + userData: diff --git a/Assets/Photon Unity Networking/Demos/Shared Assets/Materials/PlayerDiamond.mat b/Assets/Photon Unity Networking/Demos/Shared Assets/Materials/PlayerDiamond.mat new file mode 100644 index 0000000..716735e Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/Shared Assets/Materials/PlayerDiamond.mat differ diff --git a/Assets/Photon Unity Networking/Demos/Shared Assets/Materials/PlayerDiamond.mat.meta b/Assets/Photon Unity Networking/Demos/Shared Assets/Materials/PlayerDiamond.mat.meta new file mode 100644 index 0000000..8225a99 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/Shared Assets/Materials/PlayerDiamond.mat.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: c597444fc6a08854d89baeeff4ba511d +NativeFormatImporter: + userData: diff --git a/Assets/Photon Unity Networking/Demos/Shared Assets/Materials/Robot_Color.mat b/Assets/Photon Unity Networking/Demos/Shared Assets/Materials/Robot_Color.mat new file mode 100644 index 0000000..caa9d60 Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/Shared Assets/Materials/Robot_Color.mat differ diff --git a/Assets/Photon Unity Networking/Demos/Shared Assets/Materials/Robot_Color.mat.meta b/Assets/Photon Unity Networking/Demos/Shared Assets/Materials/Robot_Color.mat.meta new file mode 100644 index 0000000..c6972ce --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/Shared Assets/Materials/Robot_Color.mat.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: 0aa851515cd3747d6b3b3e461199a2ed +NativeFormatImporter: + userData: diff --git a/Assets/Photon Unity Networking/Demos/Shared Assets/Materials/UnitCircleMaterial.mat b/Assets/Photon Unity Networking/Demos/Shared Assets/Materials/UnitCircleMaterial.mat new file mode 100644 index 0000000..8604e6b Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/Shared Assets/Materials/UnitCircleMaterial.mat differ diff --git a/Assets/Photon Unity Networking/Demos/Shared Assets/Materials/UnitCircleMaterial.mat.meta b/Assets/Photon Unity Networking/Demos/Shared Assets/Materials/UnitCircleMaterial.mat.meta new file mode 100644 index 0000000..9989702 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/Shared Assets/Materials/UnitCircleMaterial.mat.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: fb6c12085a6b0a5429029fcd6478a816 +NativeFormatImporter: + userData: diff --git a/Assets/Photon Unity Networking/Demos/Shared Assets/Materials/UnitCircleTexture.mat b/Assets/Photon Unity Networking/Demos/Shared Assets/Materials/UnitCircleTexture.mat new file mode 100644 index 0000000..b5d6e35 Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/Shared Assets/Materials/UnitCircleTexture.mat differ diff --git a/Assets/Photon Unity Networking/Demos/Shared Assets/Materials/UnitCircleTexture.mat.meta b/Assets/Photon Unity Networking/Demos/Shared Assets/Materials/UnitCircleTexture.mat.meta new file mode 100644 index 0000000..3dac6c3 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/Shared Assets/Materials/UnitCircleTexture.mat.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: 80114bc117609cd4e9c988f8692e7a68 +NativeFormatImporter: + userData: diff --git a/Assets/Photon Unity Networking/Demos/Shared Assets/Materials/UnitTextureBlue.mat b/Assets/Photon Unity Networking/Demos/Shared Assets/Materials/UnitTextureBlue.mat new file mode 100644 index 0000000..b4f6daa Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/Shared Assets/Materials/UnitTextureBlue.mat differ diff --git a/Assets/Photon Unity Networking/Demos/Shared Assets/Materials/UnitTextureBlue.mat.meta b/Assets/Photon Unity Networking/Demos/Shared Assets/Materials/UnitTextureBlue.mat.meta new file mode 100644 index 0000000..3f5baa2 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/Shared Assets/Materials/UnitTextureBlue.mat.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: 1401c9e6acd739e49a9caa91ab07ac7a +NativeFormatImporter: + userData: diff --git a/Assets/Photon Unity Networking/Demos/Shared Assets/Materials/UnitTextureBlue12x.mat b/Assets/Photon Unity Networking/Demos/Shared Assets/Materials/UnitTextureBlue12x.mat new file mode 100644 index 0000000..6ddfa13 Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/Shared Assets/Materials/UnitTextureBlue12x.mat differ diff --git a/Assets/Photon Unity Networking/Demos/Shared Assets/Materials/UnitTextureBlue12x.mat.meta b/Assets/Photon Unity Networking/Demos/Shared Assets/Materials/UnitTextureBlue12x.mat.meta new file mode 100644 index 0000000..9a550d6 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/Shared Assets/Materials/UnitTextureBlue12x.mat.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: c676d877ef241ab4686e2f237b1e2f13 +NativeFormatImporter: + userData: diff --git a/Assets/Photon Unity Networking/Demos/Shared Assets/Materials/UnitTextureRed.mat b/Assets/Photon Unity Networking/Demos/Shared Assets/Materials/UnitTextureRed.mat new file mode 100644 index 0000000..d391afa Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/Shared Assets/Materials/UnitTextureRed.mat differ diff --git a/Assets/Photon Unity Networking/Demos/Shared Assets/Materials/UnitTextureRed.mat.meta b/Assets/Photon Unity Networking/Demos/Shared Assets/Materials/UnitTextureRed.mat.meta new file mode 100644 index 0000000..1c827d8 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/Shared Assets/Materials/UnitTextureRed.mat.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: 4c506c95d32f3494e9453ef5c0124b0e +NativeFormatImporter: + userData: diff --git a/Assets/Photon Unity Networking/Demos/Shared Assets/Models.meta b/Assets/Photon Unity Networking/Demos/Shared Assets/Models.meta new file mode 100644 index 0000000..b25cb7e --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/Shared Assets/Models.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 699945066a74c484396e8200fe1c4534 +folderAsset: yes +timeCreated: 1501014811 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Photon Unity Networking/Demos/Shared Assets/Models/BoundingMesh.obj b/Assets/Photon Unity Networking/Demos/Shared Assets/Models/BoundingMesh.obj new file mode 100644 index 0000000..88b2095 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/Shared Assets/Models/BoundingMesh.obj @@ -0,0 +1,337 @@ +g LevelCubes2[-934] +v -6 0 -6 +v 6 0 -6 +v -6 2 -6 +v 6 2 -6 +v -6 2 -26 +v 6 2 -26 +v -6 0 -26 +v 6 0 -26 +v -6 2 -6 +v 6 2 -6 +v -6 2 -26 +v 6 2 -26 +v -6 0 -26 +v 6 0 -6 +v 6 0 -26 +v -6 0 -6 +v 6 0 -6 +v 6 2 -26 +v 6 0 -26 +v 6 2 -6 +v -6 0 -26 +v -6 2 -6 +v -6 0 -6 +v -6 2 -26 +v -6 0 26 +v 6 0 26 +v -6 2 26 +v 6 2 26 +v -6 2 6 +v 6 2 6 +v -6 0 6 +v 6 0 6 +v -6 2 26 +v 6 2 26 +v -6 2 6 +v 6 2 6 +v -6 0 6 +v 6 0 26 +v 6 0 6 +v -6 0 26 +v 6 0 26 +v 6 2 6 +v 6 0 6 +v 6 2 26 +v -6 0 6 +v -6 2 26 +v -6 0 26 +v -6 2 6 +v -26 0 26 +v -6 0 26 +v -26 2 26 +v -6 2 26 +v -26 2 -26 +v -6 2 -26 +v -26 0 -26 +v -6 0 -26 +v -26 2 26 +v -6 2 26 +v -26 2 -26 +v -6 2 -26 +v -26 0 -26 +v -6 0 26 +v -6 0 -26 +v -26 0 26 +v -6 0 26 +v -6 2 -26 +v -6 0 -26 +v -6 2 26 +v -26 0 -26 +v -26 2 26 +v -26 0 26 +v -26 2 -26 +v 6 0 26 +v 26 0 26 +v 6 2 26 +v 26 2 26 +v 6 2 -26 +v 26 2 -26 +v 6 0 -26 +v 26 0 -26 +v 6 2 26 +v 26 2 26 +v 6 2 -26 +v 26 2 -26 +v 6 0 -26 +v 26 0 26 +v 26 0 -26 +v 6 0 26 +v 26 0 26 +v 26 2 -26 +v 26 0 -26 +v 26 2 26 +v 6 0 -26 +v 6 2 26 +v 6 0 26 +v 6 2 -26 +vn 0 0 1 +vn 0 0 1 +vn 0 0 1 +vn 0 0 1 +vn 0 1 0 +vn 0 1 0 +vn 0 0 -1 +vn 0 0 -1 +vn 0 1 0 +vn 0 1 0 +vn 0 0 -1 +vn 0 0 -1 +vn 0 -1 0 +vn 0 -1 0 +vn 0 -1 0 +vn 0 -1 0 +vn 1 0 0 +vn 1 0 0 +vn 1 0 0 +vn 1 0 0 +vn -1 0 0 +vn -1 0 0 +vn -1 0 0 +vn -1 0 0 +vn 0 0 1 +vn 0 0 1 +vn 0 0 1 +vn 0 0 1 +vn 0 1 0 +vn 0 1 0 +vn 0 0 -1 +vn 0 0 -1 +vn 0 1 0 +vn 0 1 0 +vn 0 0 -1 +vn 0 0 -1 +vn 0 -1 0 +vn 0 -1 0 +vn 0 -1 0 +vn 0 -1 0 +vn 1 0 0 +vn 1 0 0 +vn 1 0 0 +vn 1 0 0 +vn -1 0 0 +vn -1 0 0 +vn -1 0 0 +vn -1 0 0 +vn 0 0 1 +vn 0 0 1 +vn 0 0 1 +vn 0 0 1 +vn 0 1 0 +vn 0 1 0 +vn 0 0 -1 +vn 0 0 -1 +vn 0 1 0 +vn 0 1 0 +vn 0 0 -1 +vn 0 0 -1 +vn 0 -1 0 +vn 0 -1 0 +vn 0 -1 0 +vn 0 -1 0 +vn 1 0 0 +vn 1 0 0 +vn 1 0 0 +vn 1 0 0 +vn -1 0 0 +vn -1 0 0 +vn -1 0 0 +vn -1 0 0 +vn 0 0 1 +vn 0 0 1 +vn 0 0 1 +vn 0 0 1 +vn 0 1 0 +vn 0 1 0 +vn 0 0 -1 +vn 0 0 -1 +vn 0 1 0 +vn 0 1 0 +vn 0 0 -1 +vn 0 0 -1 +vn 0 -1 0 +vn 0 -1 0 +vn 0 -1 0 +vn 0 -1 0 +vn 1 0 0 +vn 1 0 0 +vn 1 0 0 +vn 1 0 0 +vn -1 0 0 +vn -1 0 0 +vn -1 0 0 +vn -1 0 0 +vt 0 0 +vt 12 0 +vt 0 2 +vt 12 2 +vt 0 20 +vt 12 20 +vt 0 2 +vt 12 2 +vt 0 0 +vt 12 0 +vt 0 0 +vt 12 0 +vt 0 0 +vt 12 20 +vt 12 0 +vt 0 20 +vt 0 0 +vt 20 2 +vt 20 0 +vt 0 2 +vt 0 0 +vt 20 2 +vt 20 0 +vt 0 2 +vt 0 0 +vt 12 0 +vt 0 2 +vt 12 2 +vt 0 20 +vt 12 20 +vt 0 2 +vt 12 2 +vt 0 0 +vt 12 0 +vt 0 0 +vt 12 0 +vt 0 0 +vt 12 20 +vt 12 0 +vt 0 20 +vt 0 0 +vt 20 2 +vt 20 0 +vt 0 2 +vt 0 0 +vt 20 2 +vt 20 0 +vt 0 2 +vt 0 0 +vt 20 0 +vt 0 2 +vt 20 2 +vt 0 52 +vt 20 52 +vt 0 2 +vt 20 2 +vt 0 0 +vt 20 0 +vt 0 0 +vt 20 0 +vt 0 0 +vt 20 52 +vt 20 0 +vt 0 52 +vt 0 0 +vt 52 2 +vt 52 0 +vt 0 2 +vt 0 0 +vt 52 2 +vt 52 0 +vt 0 2 +vt 0 0 +vt 20 0 +vt 0 2 +vt 20 2 +vt 0 52 +vt 20 52 +vt 0 2 +vt 20 2 +vt 0 0 +vt 20 0 +vt 0 0 +vt 20 0 +vt 0 0 +vt 20 52 +vt 20 0 +vt 0 52 +vt 0 0 +vt 52 2 +vt 52 0 +vt 0 2 +vt 0 0 +vt 52 2 +vt 52 0 +vt 0 2 +f 2/2/2 4/4/4 1/1/1 +f 4/4/4 3/3/3 1/1/1 +f 10/10/10 6/6/6 9/9/9 +f 6/6/6 5/5/5 9/9/9 +f 12/12/12 8/8/8 11/11/11 +f 8/8/8 7/7/7 11/11/11 +f 15/15/15 14/14/14 13/13/13 +f 14/14/14 16/16/16 13/13/13 +f 19/19/19 18/18/18 17/17/17 +f 18/18/18 20/20/20 17/17/17 +f 23/23/23 22/22/22 21/21/21 +f 22/22/22 24/24/24 21/21/21 +f 26/26/26 28/28/28 25/25/25 +f 28/28/28 27/27/27 25/25/25 +f 34/34/34 30/30/30 33/33/33 +f 30/30/30 29/29/29 33/33/33 +f 36/36/36 32/32/32 35/35/35 +f 32/32/32 31/31/31 35/35/35 +f 39/39/39 38/38/38 37/37/37 +f 38/38/38 40/40/40 37/37/37 +f 43/43/43 42/42/42 41/41/41 +f 42/42/42 44/44/44 41/41/41 +f 47/47/47 46/46/46 45/45/45 +f 46/46/46 48/48/48 45/45/45 +f 50/50/50 52/52/52 49/49/49 +f 52/52/52 51/51/51 49/49/49 +f 58/58/58 54/54/54 57/57/57 +f 54/54/54 53/53/53 57/57/57 +f 60/60/60 56/56/56 59/59/59 +f 56/56/56 55/55/55 59/59/59 +f 63/63/63 62/62/62 61/61/61 +f 62/62/62 64/64/64 61/61/61 +f 67/67/67 66/66/66 65/65/65 +f 66/66/66 68/68/68 65/65/65 +f 71/71/71 70/70/70 69/69/69 +f 70/70/70 72/72/72 69/69/69 +f 74/74/74 76/76/76 73/73/73 +f 76/76/76 75/75/75 73/73/73 +f 82/82/82 78/78/78 81/81/81 +f 78/78/78 77/77/77 81/81/81 +f 84/84/84 80/80/80 83/83/83 +f 80/80/80 79/79/79 83/83/83 +f 87/87/87 86/86/86 85/85/85 +f 86/86/86 88/88/88 85/85/85 +f 91/91/91 90/90/90 89/89/89 +f 90/90/90 92/92/92 89/89/89 +f 95/95/95 94/94/94 93/93/93 +f 94/94/94 96/96/96 93/93/93 diff --git a/Assets/Photon Unity Networking/Demos/Shared Assets/Models/BoundingMesh.obj.meta b/Assets/Photon Unity Networking/Demos/Shared Assets/Models/BoundingMesh.obj.meta new file mode 100644 index 0000000..dacdbf7 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/Shared Assets/Models/BoundingMesh.obj.meta @@ -0,0 +1,68 @@ +fileFormatVersion: 2 +guid: a494fd02c2f15b842ba2f5393004cfa3 +ModelImporter: + serializedVersion: 16 + fileIDToRecycleName: + 100000: LevelCubes2[-934] + 100002: //RootNode + 400000: LevelCubes2[-934] + 400002: //RootNode + 2300000: LevelCubes2[-934] + 3300000: LevelCubes2[-934] + 4300000: LevelCubes2[-934] + 6400000: LevelCubes2[-934] + 9500000: //RootNode + 11100000: //RootNode + materials: + importMaterials: 0 + materialName: 0 + materialSearch: 1 + animations: + legacyGenerateAnimations: 4 + bakeSimulation: 0 + optimizeGameObjects: 0 + animationCompression: 1 + animationRotationError: .5 + animationPositionError: .5 + animationScaleError: .5 + animationWrapMode: 0 + extraExposedTransformPaths: [] + clipAnimations: [] + isReadable: 1 + meshes: + lODScreenPercentages: [] + globalScale: 1 + meshCompression: 0 + addColliders: 1 + importBlendShapes: 1 + swapUVChannels: 0 + generateSecondaryUV: 0 + useFileUnits: 1 + optimizeMeshForGPU: 1 + weldVertices: 1 + secondaryUVAngleDistortion: 8 + secondaryUVAreaDistortion: 15.000001 + secondaryUVHardAngle: 88 + secondaryUVPackMargin: 4 + tangentSpace: + normalSmoothAngle: 60 + splitTangentsAcrossUV: 0 + normalImportMode: 0 + tangentImportMode: 1 + importAnimation: 0 + copyAvatar: 0 + humanDescription: + human: [] + skeleton: [] + armTwist: .5 + foreArmTwist: .5 + upperLegTwist: .5 + legTwist: .5 + armStretch: .0500000007 + legStretch: .0500000007 + feetSpacing: 0 + rootMotionBoneName: + lastHumanDescriptionAvatarSource: {instanceID: 0} + animationType: 0 + additionalBone: 0 + userData: diff --git a/Assets/Photon Unity Networking/Demos/Shared Assets/Models/Pointer.fbx b/Assets/Photon Unity Networking/Demos/Shared Assets/Models/Pointer.fbx new file mode 100644 index 0000000..bca2ad7 Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/Shared Assets/Models/Pointer.fbx differ diff --git a/Assets/Photon Unity Networking/Demos/Shared Assets/Models/Pointer.fbx.meta b/Assets/Photon Unity Networking/Demos/Shared Assets/Models/Pointer.fbx.meta new file mode 100644 index 0000000..820c223 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/Shared Assets/Models/Pointer.fbx.meta @@ -0,0 +1,64 @@ +fileFormatVersion: 2 +guid: 0baebe6c8f51e754a96dd7d4dee9bb4e +ModelImporter: + serializedVersion: 16 + fileIDToRecycleName: + 100000: //RootNode + 400000: //RootNode + 2300000: //RootNode + 3300000: //RootNode + 4300000: Pointer + 9500000: //RootNode + materials: + importMaterials: 0 + materialName: 0 + materialSearch: 1 + animations: + legacyGenerateAnimations: 4 + bakeSimulation: 0 + optimizeGameObjects: 0 + animationCompression: 1 + animationRotationError: .5 + animationPositionError: .5 + animationScaleError: .5 + animationWrapMode: 0 + extraExposedTransformPaths: [] + clipAnimations: [] + isReadable: 1 + meshes: + lODScreenPercentages: [] + globalScale: .400000006 + meshCompression: 0 + addColliders: 0 + importBlendShapes: 0 + swapUVChannels: 0 + generateSecondaryUV: 0 + useFileUnits: 1 + optimizeMeshForGPU: 1 + weldVertices: 1 + secondaryUVAngleDistortion: 8 + secondaryUVAreaDistortion: 15.000001 + secondaryUVHardAngle: 88 + secondaryUVPackMargin: 4 + tangentSpace: + normalSmoothAngle: 0 + splitTangentsAcrossUV: 1 + normalImportMode: 1 + tangentImportMode: 1 + importAnimation: 0 + copyAvatar: 0 + humanDescription: + human: [] + skeleton: [] + armTwist: .5 + foreArmTwist: .5 + upperLegTwist: .5 + legTwist: .5 + armStretch: .0500000007 + legStretch: .0500000007 + feetSpacing: 0 + rootMotionBoneName: + lastHumanDescriptionAvatarSource: {instanceID: 0} + animationType: 2 + additionalBone: 0 + userData: diff --git a/Assets/Photon Unity Networking/Demos/Shared Assets/Models/Robot Kyle.fbx b/Assets/Photon Unity Networking/Demos/Shared Assets/Models/Robot Kyle.fbx new file mode 100644 index 0000000..ce78d21 Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/Shared Assets/Models/Robot Kyle.fbx differ diff --git a/Assets/Photon Unity Networking/Demos/Shared Assets/Models/Robot Kyle.fbx.meta b/Assets/Photon Unity Networking/Demos/Shared Assets/Models/Robot Kyle.fbx.meta new file mode 100644 index 0000000..25ff0f2 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/Shared Assets/Models/Robot Kyle.fbx.meta @@ -0,0 +1,803 @@ +fileFormatVersion: 2 +guid: 320b1c2af77554f99a1658df4a6d3d5c +ModelImporter: + serializedVersion: 16 + fileIDToRecycleName: + 100000: //RootNode + 100002: Right_Toe_Joint_01 + 100004: Right_Ankle_Joint_01 + 100006: Right_Knee_Joint_01 + 100008: Right_Thigh_Joint_01 + 100010: Left_Toe_Joint_01 + 100012: Left_Ankle_Joint_01 + 100014: Left_Knee_Joint_01 + 100016: Left_Thigh_Joint_01 + 100018: Hip + 100020: Right_Thumb_Joint_01b + 100022: Right_Thumb_Joint_01a + 100024: Right_Pinky_Finger_Joint_01c + 100026: Right_Pinky_Finger_Joint_01b + 100028: Right_Pinky_Finger_Joint_01a + 100030: Right_Ring_Finger_Joint_01c + 100032: Right_Ring_Finger_Joint_01b + 100034: Right_Ring_Finger_Joint_01a + 100036: Right_Middle_Finger_Joint_01c + 100038: Right_Middle_Finger_Joint_01b + 100040: Right_Middle_Finger_Joint_01a + 100042: Right_Index_Finger_Joint_01c + 100044: Right_Index_Finger_Joint_01b + 100046: Right_Index_Finger_Joint_01a + 100048: Right_Wrist_Joint_01 + 100050: Right_Forearm_Joint_01 + 100052: Right_Upper_Arm_Joint_01 + 100054: Right_Shoulder_Joint_01 + 100056: Left_Thumb_Joint_01b + 100058: Left_Thumb_Joint_01a + 100060: Left_Pinky_Finger_Joint_01c + 100062: Left_Pinky_Finger_Joint_01b + 100064: Left_Pinky_Finger_Joint_01a + 100066: Left_Ring_Finger_Joint_01c + 100068: Left_Ring_Finger_Joint_01b + 100070: Left_Ring_Finger_Joint_01a + 100072: Left_Middle_Finger_Joint_01c + 100074: Left_Middle_Finger_Joint_01b + 100076: Left_Middle_Finger_Joint_01a + 100078: Left_Index_Finger_Joint_01c + 100080: Left_Index_Finger_Joint_01b + 100082: Left_Index_Finger_Joint_01a + 100084: Left_Wrist_Joint_01 + 100086: Left_Forearm_Joint_01 + 100088: Left_Upper_Arm_Joint_01 + 100090: Left_Shoulder_Joint_01 + 100092: Head + 100094: Neck + 100096: Ribs + 100098: Root + 100100: Robot2 + 400000: //RootNode + 400002: Right_Toe_Joint_01 + 400004: Right_Ankle_Joint_01 + 400006: Right_Knee_Joint_01 + 400008: Right_Thigh_Joint_01 + 400010: Left_Toe_Joint_01 + 400012: Left_Ankle_Joint_01 + 400014: Left_Knee_Joint_01 + 400016: Left_Thigh_Joint_01 + 400018: Hip + 400020: Right_Thumb_Joint_01b + 400022: Right_Thumb_Joint_01a + 400024: Right_Pinky_Finger_Joint_01c + 400026: Right_Pinky_Finger_Joint_01b + 400028: Right_Pinky_Finger_Joint_01a + 400030: Right_Ring_Finger_Joint_01c + 400032: Right_Ring_Finger_Joint_01b + 400034: Right_Ring_Finger_Joint_01a + 400036: Right_Middle_Finger_Joint_01c + 400038: Right_Middle_Finger_Joint_01b + 400040: Right_Middle_Finger_Joint_01a + 400042: Right_Index_Finger_Joint_01c + 400044: Right_Index_Finger_Joint_01b + 400046: Right_Index_Finger_Joint_01a + 400048: Right_Wrist_Joint_01 + 400050: Right_Forearm_Joint_01 + 400052: Right_Upper_Arm_Joint_01 + 400054: Right_Shoulder_Joint_01 + 400056: Left_Thumb_Joint_01b + 400058: Left_Thumb_Joint_01a + 400060: Left_Pinky_Finger_Joint_01c + 400062: Left_Pinky_Finger_Joint_01b + 400064: Left_Pinky_Finger_Joint_01a + 400066: Left_Ring_Finger_Joint_01c + 400068: Left_Ring_Finger_Joint_01b + 400070: Left_Ring_Finger_Joint_01a + 400072: Left_Middle_Finger_Joint_01c + 400074: Left_Middle_Finger_Joint_01b + 400076: Left_Middle_Finger_Joint_01a + 400078: Left_Index_Finger_Joint_01c + 400080: Left_Index_Finger_Joint_01b + 400082: Left_Index_Finger_Joint_01a + 400084: Left_Wrist_Joint_01 + 400086: Left_Forearm_Joint_01 + 400088: Left_Upper_Arm_Joint_01 + 400090: Left_Shoulder_Joint_01 + 400092: Head + 400094: Neck + 400096: Ribs + 400098: Root + 400100: Robot2 + 4300000: Robot2 + 9500000: //RootNode + 11100000: //RootNode + 13700000: Robot2 + materials: + importMaterials: 1 + materialName: 0 + materialSearch: 1 + animations: + legacyGenerateAnimations: 4 + bakeSimulation: 0 + optimizeGameObjects: 0 + animationCompression: 3 + animationRotationError: .5 + animationPositionError: .5 + animationScaleError: .5 + animationWrapMode: 0 + extraExposedTransformPaths: [] + clipAnimations: [] + isReadable: 1 + meshes: + lODScreenPercentages: [] + globalScale: .00999999978 + meshCompression: 0 + addColliders: 0 + importBlendShapes: 1 + swapUVChannels: 0 + generateSecondaryUV: 0 + useFileUnits: 1 + optimizeMeshForGPU: 1 + weldVertices: 1 + secondaryUVAngleDistortion: 8 + secondaryUVAreaDistortion: 15.000001 + secondaryUVHardAngle: 88 + secondaryUVPackMargin: 4 + tangentSpace: + normalSmoothAngle: 60 + splitTangentsAcrossUV: 1 + normalImportMode: 0 + tangentImportMode: 1 + importAnimation: 1 + copyAvatar: 0 + humanDescription: + human: + - boneName: Root + humanName: Hips + limit: + min: {x: 0, y: 0, z: 0} + max: {x: 0, y: 0, z: 0} + value: {x: 0, y: 0, z: 0} + length: 0 + modified: 0 + - boneName: Left_Thigh_Joint_01 + humanName: LeftUpperLeg + limit: + min: {x: 0, y: 0, z: 0} + max: {x: 0, y: 0, z: 0} + value: {x: 0, y: 0, z: 0} + length: 0 + modified: 0 + - boneName: Right_Thigh_Joint_01 + humanName: RightUpperLeg + limit: + min: {x: 0, y: 0, z: 0} + max: {x: 0, y: 0, z: 0} + value: {x: 0, y: 0, z: 0} + length: 0 + modified: 0 + - boneName: Left_Knee_Joint_01 + humanName: LeftLowerLeg + limit: + min: {x: 0, y: 0, z: 0} + max: {x: 0, y: 0, z: 0} + value: {x: 0, y: 0, z: 0} + length: 0 + modified: 0 + - boneName: Right_Knee_Joint_01 + humanName: RightLowerLeg + limit: + min: {x: 0, y: 0, z: 0} + max: {x: 0, y: 0, z: 0} + value: {x: 0, y: 0, z: 0} + length: 0 + modified: 0 + - boneName: Left_Ankle_Joint_01 + humanName: LeftFoot + limit: + min: {x: 0, y: 0, z: 0} + max: {x: 0, y: 0, z: 0} + value: {x: 0, y: 0, z: 0} + length: 0 + modified: 0 + - boneName: Right_Ankle_Joint_01 + humanName: RightFoot + limit: + min: {x: 0, y: 0, z: 0} + max: {x: 0, y: 0, z: 0} + value: {x: 0, y: 0, z: 0} + length: 0 + modified: 0 + - boneName: Ribs + humanName: Spine + limit: + min: {x: 0, y: 0, z: 0} + max: {x: 0, y: 0, z: 0} + value: {x: 0, y: 0, z: 0} + length: 0 + modified: 0 + - boneName: Neck + humanName: Neck + limit: + min: {x: 0, y: 0, z: 0} + max: {x: 0, y: 0, z: 0} + value: {x: 0, y: 0, z: 0} + length: 0 + modified: 0 + - boneName: Head + humanName: Head + limit: + min: {x: 0, y: 0, z: 0} + max: {x: 0, y: 0, z: 0} + value: {x: 0, y: 0, z: 0} + length: 0 + modified: 0 + - boneName: Left_Shoulder_Joint_01 + humanName: LeftShoulder + limit: + min: {x: 0, y: 0, z: 0} + max: {x: 0, y: 0, z: 0} + value: {x: 0, y: 0, z: 0} + length: 0 + modified: 0 + - boneName: Right_Shoulder_Joint_01 + humanName: RightShoulder + limit: + min: {x: 0, y: 0, z: 0} + max: {x: 0, y: 0, z: 0} + value: {x: 0, y: 0, z: 0} + length: 0 + modified: 0 + - boneName: Left_Upper_Arm_Joint_01 + humanName: LeftUpperArm + limit: + min: {x: 0, y: 0, z: 0} + max: {x: 0, y: 0, z: 0} + value: {x: 0, y: 0, z: 0} + length: 0 + modified: 0 + - boneName: Right_Upper_Arm_Joint_01 + humanName: RightUpperArm + limit: + min: {x: 0, y: 0, z: 0} + max: {x: 0, y: 0, z: 0} + value: {x: 0, y: 0, z: 0} + length: 0 + modified: 0 + - boneName: Left_Forearm_Joint_01 + humanName: LeftLowerArm + limit: + min: {x: 0, y: 0, z: 0} + max: {x: 0, y: 0, z: 0} + value: {x: 0, y: 0, z: 0} + length: 0 + modified: 0 + - boneName: Right_Forearm_Joint_01 + humanName: RightLowerArm + limit: + min: {x: 0, y: 0, z: 0} + max: {x: 0, y: 0, z: 0} + value: {x: 0, y: 0, z: 0} + length: 0 + modified: 0 + - boneName: Left_Wrist_Joint_01 + humanName: LeftHand + limit: + min: {x: 0, y: 0, z: 0} + max: {x: 0, y: 0, z: 0} + value: {x: 0, y: 0, z: 0} + length: 0 + modified: 0 + - boneName: Right_Wrist_Joint_01 + humanName: RightHand + limit: + min: {x: 0, y: 0, z: 0} + max: {x: 0, y: 0, z: 0} + value: {x: 0, y: 0, z: 0} + length: 0 + modified: 0 + - boneName: Left_Toe_Joint_01 + humanName: LeftToes + limit: + min: {x: 0, y: 0, z: 0} + max: {x: 0, y: 0, z: 0} + value: {x: 0, y: 0, z: 0} + length: 0 + modified: 0 + - boneName: Right_Toe_Joint_01 + humanName: RightToes + limit: + min: {x: 0, y: 0, z: 0} + max: {x: 0, y: 0, z: 0} + value: {x: 0, y: 0, z: 0} + length: 0 + modified: 0 + - boneName: Left_Thumb_Joint_01a + humanName: Left Thumb Proximal + limit: + min: {x: 0, y: 0, z: 0} + max: {x: 0, y: 0, z: 0} + value: {x: 0, y: 0, z: 0} + length: 0 + modified: 0 + - boneName: Left_Thumb_Joint_01b + humanName: Left Thumb Intermediate + limit: + min: {x: 0, y: 0, z: 0} + max: {x: 0, y: 0, z: 0} + value: {x: 0, y: 0, z: 0} + length: 0 + modified: 0 + - boneName: Left_Index_Finger_Joint_01a + humanName: Left Index Proximal + limit: + min: {x: 0, y: 0, z: 0} + max: {x: 0, y: 0, z: 0} + value: {x: 0, y: 0, z: 0} + length: 0 + modified: 0 + - boneName: Left_Index_Finger_Joint_01b + humanName: Left Index Intermediate + limit: + min: {x: 0, y: 0, z: 0} + max: {x: 0, y: 0, z: 0} + value: {x: 0, y: 0, z: 0} + length: 0 + modified: 0 + - boneName: Left_Index_Finger_Joint_01c + humanName: Left Index Distal + limit: + min: {x: 0, y: 0, z: 0} + max: {x: 0, y: 0, z: 0} + value: {x: 0, y: 0, z: 0} + length: 0 + modified: 0 + - boneName: Left_Middle_Finger_Joint_01a + humanName: Left Middle Proximal + limit: + min: {x: 0, y: 0, z: 0} + max: {x: 0, y: 0, z: 0} + value: {x: 0, y: 0, z: 0} + length: 0 + modified: 0 + - boneName: Left_Middle_Finger_Joint_01b + humanName: Left Middle Intermediate + limit: + min: {x: 0, y: 0, z: 0} + max: {x: 0, y: 0, z: 0} + value: {x: 0, y: 0, z: 0} + length: 0 + modified: 0 + - boneName: Left_Middle_Finger_Joint_01c + humanName: Left Middle Distal + limit: + min: {x: 0, y: 0, z: 0} + max: {x: 0, y: 0, z: 0} + value: {x: 0, y: 0, z: 0} + length: 0 + modified: 0 + - boneName: Left_Ring_Finger_Joint_01a + humanName: Left Ring Proximal + limit: + min: {x: 0, y: 0, z: 0} + max: {x: 0, y: 0, z: 0} + value: {x: 0, y: 0, z: 0} + length: 0 + modified: 0 + - boneName: Left_Ring_Finger_Joint_01b + humanName: Left Ring Intermediate + limit: + min: {x: 0, y: 0, z: 0} + max: {x: 0, y: 0, z: 0} + value: {x: 0, y: 0, z: 0} + length: 0 + modified: 0 + - boneName: Left_Ring_Finger_Joint_01c + humanName: Left Ring Distal + limit: + min: {x: 0, y: 0, z: 0} + max: {x: 0, y: 0, z: 0} + value: {x: 0, y: 0, z: 0} + length: 0 + modified: 0 + - boneName: Left_Pinky_Finger_Joint_01a + humanName: Left Little Proximal + limit: + min: {x: 0, y: 0, z: 0} + max: {x: 0, y: 0, z: 0} + value: {x: 0, y: 0, z: 0} + length: 0 + modified: 0 + - boneName: Left_Pinky_Finger_Joint_01b + humanName: Left Little Intermediate + limit: + min: {x: 0, y: 0, z: 0} + max: {x: 0, y: 0, z: 0} + value: {x: 0, y: 0, z: 0} + length: 0 + modified: 0 + - boneName: Left_Pinky_Finger_Joint_01c + humanName: Left Little Distal + limit: + min: {x: 0, y: 0, z: 0} + max: {x: 0, y: 0, z: 0} + value: {x: 0, y: 0, z: 0} + length: 0 + modified: 0 + - boneName: Right_Thumb_Joint_01a + humanName: Right Thumb Proximal + limit: + min: {x: 0, y: 0, z: 0} + max: {x: 0, y: 0, z: 0} + value: {x: 0, y: 0, z: 0} + length: 0 + modified: 0 + - boneName: Right_Thumb_Joint_01b + humanName: Right Thumb Intermediate + limit: + min: {x: 0, y: 0, z: 0} + max: {x: 0, y: 0, z: 0} + value: {x: 0, y: 0, z: 0} + length: 0 + modified: 0 + - boneName: Right_Index_Finger_Joint_01a + humanName: Right Index Proximal + limit: + min: {x: 0, y: 0, z: 0} + max: {x: 0, y: 0, z: 0} + value: {x: 0, y: 0, z: 0} + length: 0 + modified: 0 + - boneName: Right_Index_Finger_Joint_01b + humanName: Right Index Intermediate + limit: + min: {x: 0, y: 0, z: 0} + max: {x: 0, y: 0, z: 0} + value: {x: 0, y: 0, z: 0} + length: 0 + modified: 0 + - boneName: Right_Index_Finger_Joint_01c + humanName: Right Index Distal + limit: + min: {x: 0, y: 0, z: 0} + max: {x: 0, y: 0, z: 0} + value: {x: 0, y: 0, z: 0} + length: 0 + modified: 0 + - boneName: Right_Middle_Finger_Joint_01a + humanName: Right Middle Proximal + limit: + min: {x: 0, y: 0, z: 0} + max: {x: 0, y: 0, z: 0} + value: {x: 0, y: 0, z: 0} + length: 0 + modified: 0 + - boneName: Right_Middle_Finger_Joint_01b + humanName: Right Middle Intermediate + limit: + min: {x: 0, y: 0, z: 0} + max: {x: 0, y: 0, z: 0} + value: {x: 0, y: 0, z: 0} + length: 0 + modified: 0 + - boneName: Right_Middle_Finger_Joint_01c + humanName: Right Middle Distal + limit: + min: {x: 0, y: 0, z: 0} + max: {x: 0, y: 0, z: 0} + value: {x: 0, y: 0, z: 0} + length: 0 + modified: 0 + - boneName: Right_Ring_Finger_Joint_01a + humanName: Right Ring Proximal + limit: + min: {x: 0, y: 0, z: 0} + max: {x: 0, y: 0, z: 0} + value: {x: 0, y: 0, z: 0} + length: 0 + modified: 0 + - boneName: Right_Ring_Finger_Joint_01b + humanName: Right Ring Intermediate + limit: + min: {x: 0, y: 0, z: 0} + max: {x: 0, y: 0, z: 0} + value: {x: 0, y: 0, z: 0} + length: 0 + modified: 0 + - boneName: Right_Ring_Finger_Joint_01c + humanName: Right Ring Distal + limit: + min: {x: 0, y: 0, z: 0} + max: {x: 0, y: 0, z: 0} + value: {x: 0, y: 0, z: 0} + length: 0 + modified: 0 + - boneName: Right_Pinky_Finger_Joint_01a + humanName: Right Little Proximal + limit: + min: {x: 0, y: 0, z: 0} + max: {x: 0, y: 0, z: 0} + value: {x: 0, y: 0, z: 0} + length: 0 + modified: 0 + - boneName: Right_Pinky_Finger_Joint_01b + humanName: Right Little Intermediate + limit: + min: {x: 0, y: 0, z: 0} + max: {x: 0, y: 0, z: 0} + value: {x: 0, y: 0, z: 0} + length: 0 + modified: 0 + - boneName: Right_Pinky_Finger_Joint_01c + humanName: Right Little Distal + limit: + min: {x: 0, y: 0, z: 0} + max: {x: 0, y: 0, z: 0} + value: {x: 0, y: 0, z: 0} + length: 0 + modified: 0 + skeleton: + - name: Robot Kyle(Clone) + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: Robot2 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: -0, z: 0, w: 1} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: Root + position: {x: -2.18785635e-33, y: 1.06283081, z: .0351298526} + rotation: {x: .472944587, y: -.525664806, z: -.472944587, w: .525664806} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: Hip + position: {x: .028992068, y: -.00259387214, z: 1.22991095e-17} + rotation: {x: .0377401859, y: .999287605, z: 5.51196334e-17, w: 1.63008619e-16} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: Left_Thigh_Joint_01 + position: {x: -.122133613, y: .0113319969, z: -.0689055547} + rotation: {x: .995700479, y: .0926313698, z: 6.73769248e-17, w: 7.24238846e-16} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: Left_Knee_Joint_01 + position: {x: -.371733814, y: -.00199661148, z: .0730361715} + rotation: {x: 4.44010621e-16, y: 8.35449275e-18, z: .0188126452, w: .999823034} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: Left_Ankle_Joint_01 + position: {x: -.434050143, y: -8.42735248e-18, z: -8.746468e-18} + rotation: {x: .86925447, y: .494364947, z: 3.02711212e-17, w: 5.3226485e-17} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: Left_Toe_Joint_01 + position: {x: -.137871921, y: -2.6645352e-17, z: 3.5527136e-17} + rotation: {x: -.227291971, y: -.669580758, z: -.227291971, w: .669580758} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: Right_Thigh_Joint_01 + position: {x: -.122133501, y: .011331954, z: .0689055994} + rotation: {x: -0, y: 0, z: .995700479, w: -.0926313698} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: Right_Knee_Joint_01 + position: {x: .371734113, y: -.00199670601, z: .073036395} + rotation: {x: 0, y: 0, z: -.0188126452, w: .999823034} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: Right_Ankle_Joint_01 + position: {x: .434049755, y: 7.89986814e-08, z: -1.7763568e-17} + rotation: {x: 0, y: 0, z: -.494364947, w: .86925447} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: Right_Toe_Joint_01 + position: {x: .13787201, y: 6.44108695e-08, z: -3.5527136e-17} + rotation: {x: 1.22199291e-08, y: -4.14810586e-09, z: -.321439385, w: .94693017} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: Ribs + position: {x: -.0802452713, y: .000621672545, z: -9.82317013e-18} + rotation: {x: 0, y: 0, z: -.00937534776, w: .999956071} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: Left_Shoulder_Joint_01 + position: {x: -.24796544, y: -.0189683326, z: .131307259} + rotation: {x: -.410582304, y: .447834492, z: .536756396, w: .585456371} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: Left_Upper_Arm_Joint_01 + position: {x: -.0635852665, y: 0, z: -3.10862448e-17} + rotation: {x: .0810573399, y: .12253882, z: .0857569054, w: .985423625} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: Left_Forearm_Joint_01 + position: {x: -.238371104, y: .0353246704, z: -.00126056455} + rotation: {x: -.00227935403, y: -.0410712138, z: -.526821613, w: .848980069} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: Left_Wrist_Joint_01 + position: {x: -.176925823, y: -.248301715, z: .0419350788} + rotation: {x: -.00276813749, y: .00809799042, z: .462680191, w: .886484027} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: Left_Index_Finger_Joint_01a + position: {x: -.0701322183, y: .0124753257, z: .0255052447} + rotation: {x: .0102327066, y: .00696108537, z: -.00866493769, w: .999885917} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: Left_Index_Finger_Joint_01b + position: {x: -.0405339487, y: -2.33146828e-17, z: 9.92263839e-19} + rotation: {x: .000711358734, y: .000479860872, z: .011196685, w: .999936938} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: Left_Index_Finger_Joint_01c + position: {x: -.0229451396, y: -3.19098593e-16, z: 9.77516636e-18} + rotation: {x: -.0110166054, y: -.000252159196, z: -.0228816289, w: .999677479} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: Left_Middle_Finger_Joint_01a + position: {x: -.0718098655, y: .0124753257, z: .00505481893} + rotation: {x: .0102417199, y: .00672140811, z: -.00870271865, w: .999887109} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: Left_Middle_Finger_Joint_01b + position: {x: -.0440528281, y: 2.220446e-18, z: 1.31478208e-18} + rotation: {x: .000649813446, y: .000440957752, z: .0103045162, w: .999946594} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: Left_Middle_Finger_Joint_01c + position: {x: -.0249333773, y: 1.4801235e-16, z: -4.9960034e-18} + rotation: {x: -.0109563544, y: -.00023076385, z: -.0210561678, w: .999718249} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: Left_Pinky_Finger_Joint_01a + position: {x: -.0721200481, y: .0124753257, z: -.0332361907} + rotation: {x: .0101916166, y: .00790770072, z: -.00853110664, w: .999880433} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: Left_Pinky_Finger_Joint_01b + position: {x: -.0305155125, y: -3.15025781e-17, z: 2.47200941e-18} + rotation: {x: .000973835588, y: .000640973856, z: .0148621332, w: .999888897} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: Left_Pinky_Finger_Joint_01c + position: {x: -.0172837134, y: -3.86662229e-16, z: 1.52742391e-17} + rotation: {x: -.0112725943, y: -.000342671672, z: -.0303826835, w: .999474704} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: Left_Ring_Finger_Joint_01a + position: {x: -.0722572058, y: .0124753257, z: -.014861824} + rotation: {x: .0102260066, y: .00713092694, z: -.00863911677, w: .999884963} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: Left_Ring_Finger_Joint_01b + position: {x: -.0383335873, y: -2.4980017e-18, z: 4.41263923e-18} + rotation: {x: .000756177469, y: .000507914403, z: .0118389875, w: .999929488} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: Left_Ring_Finger_Joint_01c + position: {x: -.021700656, y: -6.47745087e-17, z: 8.27463095e-18} + rotation: {x: -.0110604241, y: -.000267697003, z: -.024194574, w: .999646068} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: Left_Thumb_Joint_01a + position: {x: -.0468873158, y: -.00486531109, z: .0469883345} + rotation: {x: .381583214, y: .381183654, z: -.197721139, w: .818535089} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: Left_Thumb_Joint_01b + position: {x: -.0287782475, y: -.00164805842, z: -.00240386301} + rotation: {x: -.420362532, y: -.371804148, z: .0835276917, w: .823456287} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: Neck + position: {x: -.395399421, y: 1.28785867e-16, z: -8.90155064e-17} + rotation: {x: 0, y: 0, z: -.151223585, w: .988499582} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: Head + position: {x: -.0795931146, y: 0, z: -2.09621381e-17} + rotation: {x: 0, y: -0, z: -0, w: 1} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: Right_Shoulder_Joint_01 + position: {x: -.247969925, y: -.0189679097, z: -.131306991} + rotation: {x: .447834492, y: .410582304, z: -.585456371, w: .536756396} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: Right_Upper_Arm_Joint_01 + position: {x: .0635855645, y: 2.84217088e-16, z: -3.92599446e-08} + rotation: {x: -.0620069057, y: .0971060172, z: .0206019096, w: .993126929} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: Right_Forearm_Joint_01 + position: {x: .240620226, y: .00514373928, z: -.012117967} + rotation: {x: .78327322, y: .0116710188, z: .00326981535, w: .62155956} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: Right_Wrist_Joint_01 + position: {x: .305883735, y: -.0331729203, z: .00706654601} + rotation: {x: -.7051211, y: -.00824209582, z: .0129015539, w: .708921611} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: Right_Index_Finger_Joint_01a + position: {x: .0694020092, y: -.0138474749, z: -.0267640352} + rotation: {x: .0103117013, y: .0158601645, z: -.0186141189, w: .999647796} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: Right_Index_Finger_Joint_01b + position: {x: .0405342206, y: -9.35433206e-07, z: 2.2560922e-08} + rotation: {x: .000711358734, y: .000479860872, z: .011196685, w: .999936938} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: Right_Index_Finger_Joint_01c + position: {x: .0229448024, y: -7.9775738e-08, z: -7.1668687e-08} + rotation: {x: -.0110166054, y: -.000252159196, z: -.0228816289, w: .999677479} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: Right_Middle_Finger_Joint_01a + position: {x: .0714474693, y: -.0138888024, z: -.00634721341} + rotation: {x: .0103175482, y: .0156253483, z: -.0186699741, w: .999650359} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: Right_Middle_Finger_Joint_01b + position: {x: .0440530181, y: 6.33701404e-07, z: -1.95757313e-08} + rotation: {x: .000649813446, y: .000440957752, z: .0103045162, w: .999946594} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: Right_Middle_Finger_Joint_01c + position: {x: .0249327328, y: -3.78608348e-07, z: 6.71087363e-08} + rotation: {x: -.0109563544, y: -.00023076385, z: -.0210561678, w: .999718249} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: Right_Pinky_Finger_Joint_01a + position: {x: .0724464282, y: -.0139078433, z: .0319320038} + rotation: {x: .0102807963, y: .0168105923, z: -.0184925273, w: .999634802} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: Right_Pinky_Finger_Joint_01b + position: {x: .0305161439, y: -4.78116e-08, z: 6.06602839e-08} + rotation: {x: .000973835588, y: .000640973856, z: .0148621332, w: .999888897} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: Right_Pinky_Finger_Joint_01c + position: {x: .0172829479, y: -1.95356151e-07, z: 1.46504391e-08} + rotation: {x: -.0112725943, y: -.000342671672, z: -.0303826835, w: .999474704} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: Right_Ring_Finger_Joint_01a + position: {x: .0722524822, y: -.0139042325, z: .0135582108} + rotation: {x: .0103066219, y: .016033005, z: -.0185990017, w: .999645412} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: Right_Ring_Finger_Joint_01b + position: {x: .0383345708, y: -1.48944338e-07, z: 2.93836546e-08} + rotation: {x: .000756177469, y: .000507914403, z: .0118389875, w: .999929488} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: Right_Ring_Finger_Joint_01c + position: {x: .0217003096, y: 2.02178668e-07, z: -9.37706375e-08} + rotation: {x: -.0110604241, y: -.000267697003, z: -.024194574, w: .999646068} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: Right_Thumb_Joint_01a + position: {x: .0461209379, y: .00395598775, z: -.0478250794} + rotation: {x: .383606344, y: .384773076, z: -.209182531, w: .81304276} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + - name: Right_Thumb_Joint_01b + position: {x: .0287784021, y: .00164802861, z: .00240408769} + rotation: {x: .122744381, y: -.0850149319, z: .318449587, w: .93610692} + scale: {x: 1, y: 1, z: 1} + transformModified: 1 + armTwist: .5 + foreArmTwist: .5 + upperLegTwist: .5 + legTwist: .5 + armStretch: .0500000007 + legStretch: .0500000007 + feetSpacing: 0 + rootMotionBoneName: + lastHumanDescriptionAvatarSource: {instanceID: 0} + animationType: 3 + additionalBone: 0 + userData: diff --git a/Assets/Photon Unity Networking/Demos/Shared Assets/PhotonGUISkin.guiskin b/Assets/Photon Unity Networking/Demos/Shared Assets/PhotonGUISkin.guiskin new file mode 100644 index 0000000..28638a1 Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/Shared Assets/PhotonGUISkin.guiskin differ diff --git a/Assets/Photon Unity Networking/Demos/Shared Assets/PhotonGUISkin.guiskin.meta b/Assets/Photon Unity Networking/Demos/Shared Assets/PhotonGUISkin.guiskin.meta new file mode 100644 index 0000000..ed74dc0 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/Shared Assets/PhotonGUISkin.guiskin.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: 0a36872c871b46d4ea5e4e064f3bf975 +NativeFormatImporter: + userData: diff --git a/Assets/Photon Unity Networking/Demos/Shared Assets/PhotonLeanGUISkin.guiskin b/Assets/Photon Unity Networking/Demos/Shared Assets/PhotonLeanGUISkin.guiskin new file mode 100644 index 0000000..18d3d4d Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/Shared Assets/PhotonLeanGUISkin.guiskin differ diff --git a/Assets/Photon Unity Networking/Demos/Shared Assets/PhotonLeanGUISkin.guiskin.meta b/Assets/Photon Unity Networking/Demos/Shared Assets/PhotonLeanGUISkin.guiskin.meta new file mode 100644 index 0000000..dabafcf --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/Shared Assets/PhotonLeanGUISkin.guiskin.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: 798b8fafc1a9fe74cae8837a57ccae37 +NativeFormatImporter: + userData: diff --git a/Assets/Photon Unity Networking/Demos/Shared Assets/Prefabs.meta b/Assets/Photon Unity Networking/Demos/Shared Assets/Prefabs.meta new file mode 100644 index 0000000..7fd8a85 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/Shared Assets/Prefabs.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: d9c7b3e71e0f848c99a709a66ae65a96 +folderAsset: yes +timeCreated: 1501014812 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Photon Unity Networking/Demos/Shared Assets/Prefabs/Level.prefab b/Assets/Photon Unity Networking/Demos/Shared Assets/Prefabs/Level.prefab new file mode 100644 index 0000000..649dc8a Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/Shared Assets/Prefabs/Level.prefab differ diff --git a/Assets/Photon Unity Networking/Demos/Shared Assets/Prefabs/Level.prefab.meta b/Assets/Photon Unity Networking/Demos/Shared Assets/Prefabs/Level.prefab.meta new file mode 100644 index 0000000..3f8e3c6 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/Shared Assets/Prefabs/Level.prefab.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: b144107d6cef9c84d95ee085de8f9c11 +NativeFormatImporter: + userData: diff --git a/Assets/Photon Unity Networking/Demos/Shared Assets/Prefabs/Player Diamond.prefab b/Assets/Photon Unity Networking/Demos/Shared Assets/Prefabs/Player Diamond.prefab new file mode 100644 index 0000000..f5c8f91 Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/Shared Assets/Prefabs/Player Diamond.prefab differ diff --git a/Assets/Photon Unity Networking/Demos/Shared Assets/Prefabs/Player Diamond.prefab.meta b/Assets/Photon Unity Networking/Demos/Shared Assets/Prefabs/Player Diamond.prefab.meta new file mode 100644 index 0000000..75bc0ed --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/Shared Assets/Prefabs/Player Diamond.prefab.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: e4158f2dc7e4b1748ae8e21a3937fb02 +NativeFormatImporter: + userData: diff --git a/Assets/Photon Unity Networking/Demos/Shared Assets/Prefabs/PointerPrefab.prefab b/Assets/Photon Unity Networking/Demos/Shared Assets/Prefabs/PointerPrefab.prefab new file mode 100644 index 0000000..1d6ec2d Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/Shared Assets/Prefabs/PointerPrefab.prefab differ diff --git a/Assets/Photon Unity Networking/Demos/Shared Assets/Prefabs/PointerPrefab.prefab.meta b/Assets/Photon Unity Networking/Demos/Shared Assets/Prefabs/PointerPrefab.prefab.meta new file mode 100644 index 0000000..91a4e26 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/Shared Assets/Prefabs/PointerPrefab.prefab.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: 9c6977a9ecda14e4e96ea3a71c749c2c +NativeFormatImporter: + userData: diff --git a/Assets/Photon Unity Networking/Demos/Shared Assets/Prefabs/UI.meta b/Assets/Photon Unity Networking/Demos/Shared Assets/Prefabs/UI.meta new file mode 100644 index 0000000..ce09892 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/Shared Assets/Prefabs/UI.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 88c42305bf30c478a8b823e72d155e6c +folderAsset: yes +timeCreated: 1501014812 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Photon Unity Networking/Demos/Shared Assets/Prefabs/UI/Button Regular.prefab b/Assets/Photon Unity Networking/Demos/Shared Assets/Prefabs/UI/Button Regular.prefab new file mode 100644 index 0000000..ae05c27 Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/Shared Assets/Prefabs/UI/Button Regular.prefab differ diff --git a/Assets/Photon Unity Networking/Demos/Shared Assets/Prefabs/UI/Button Regular.prefab.meta b/Assets/Photon Unity Networking/Demos/Shared Assets/Prefabs/UI/Button Regular.prefab.meta new file mode 100644 index 0000000..5c67f15 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/Shared Assets/Prefabs/UI/Button Regular.prefab.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: 4f826638dd73749d88747935ea56c522 +NativeFormatImporter: + userData: diff --git a/Assets/Photon Unity Networking/Demos/Shared Assets/Prefabs/UI/Toggle Regular.prefab b/Assets/Photon Unity Networking/Demos/Shared Assets/Prefabs/UI/Toggle Regular.prefab new file mode 100644 index 0000000..42900ef Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/Shared Assets/Prefabs/UI/Toggle Regular.prefab differ diff --git a/Assets/Photon Unity Networking/Demos/Shared Assets/Prefabs/UI/Toggle Regular.prefab.meta b/Assets/Photon Unity Networking/Demos/Shared Assets/Prefabs/UI/Toggle Regular.prefab.meta new file mode 100644 index 0000000..f9cc02d --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/Shared Assets/Prefabs/UI/Toggle Regular.prefab.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: 5d91df74039db4d67a68595d5b9bbf4f +NativeFormatImporter: + userData: diff --git a/Assets/Photon Unity Networking/Demos/Shared Assets/Scripts.meta b/Assets/Photon Unity Networking/Demos/Shared Assets/Scripts.meta new file mode 100644 index 0000000..90d88bb --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/Shared Assets/Scripts.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 4c9ea07ab00eb4828a1991c9d7a5f300 +folderAsset: yes +timeCreated: 1501014811 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Photon Unity Networking/Demos/Shared Assets/Scripts/IdleRunJump.cs b/Assets/Photon Unity Networking/Demos/Shared Assets/Scripts/IdleRunJump.cs new file mode 100644 index 0000000..176eb51 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/Shared Assets/Scripts/IdleRunJump.cs @@ -0,0 +1,99 @@ +using UnityEngine; +using System.Collections; + +public class IdleRunJump : MonoBehaviour +{ + protected Animator animator; + public float DirectionDampTime = .25f; + public bool ApplyGravity = true; + public float SynchronizedMaxSpeed; + public float TurnSpeedModifier; + public float SynchronizedTurnSpeed; + public float SynchronizedSpeedAcceleration; + + protected PhotonView m_PhotonView; + + PhotonTransformView m_TransformView; + + //Vector3 m_LastPosition; + float m_SpeedModifier; + + // Use this for initialization + void Start () + { + animator = GetComponent(); + m_PhotonView = GetComponent(); + m_TransformView = GetComponent(); + + if(animator.layerCount >= 2) + animator.SetLayerWeight(1, 1); + } + + // Update is called once per frame + void Update () + { + if( m_PhotonView.isMine == false && PhotonNetwork.connected == true ) + { + return; + } + + if (animator) + { + AnimatorStateInfo stateInfo = animator.GetCurrentAnimatorStateInfo(0); + + if (stateInfo.IsName("Base Layer.Run")) + { + if (Input.GetButton("Fire1")) animator.SetBool("Jump", true); + } + else + { + animator.SetBool("Jump", false); + } + + if(Input.GetButtonDown("Fire2") && animator.layerCount >= 2) + { + animator.SetBool("Hi", !animator.GetBool("Hi")); + } + + + float h = Input.GetAxis("Horizontal"); + float v = Input.GetAxis("Vertical"); + + if( v < 0 ) + { + v = 0; + } + + animator.SetFloat( "Speed", h*h+v*v ); + animator.SetFloat( "Direction", h, DirectionDampTime, Time.deltaTime ); + + float direction = animator.GetFloat( "Direction" ); + + float targetSpeedModifier = Mathf.Abs( v ); + + if( Mathf.Abs( direction ) > 0.2f ) + { + targetSpeedModifier = TurnSpeedModifier; + } + + m_SpeedModifier = Mathf.MoveTowards( m_SpeedModifier, targetSpeedModifier, Time.deltaTime * 25f ); + + Vector3 speed = transform.forward * SynchronizedMaxSpeed * m_SpeedModifier; + float turnSpeed = direction * SynchronizedTurnSpeed; + + /*float moveDistance = Vector3.Distance( transform.position, m_LastPosition ) / Time.deltaTime; + + if( moveDistance < 4f && turnSpeed == 0f ) + { + speed = transform.forward * moveDistance; + }*/ + + //Debug.Log( moveDistance ); + //Debug.Log( speed + " - " + speed.magnitude + " - " + speedModifier + " - " + h + " - " + v ); + + m_TransformView.SetSynchronizedValues( speed, turnSpeed ); + + //m_LastPosition = transform.position; + } + } +} \ No newline at end of file diff --git a/Assets/Photon Unity Networking/Demos/Shared Assets/Scripts/IdleRunJump.cs.meta b/Assets/Photon Unity Networking/Demos/Shared Assets/Scripts/IdleRunJump.cs.meta new file mode 100644 index 0000000..32e3c30 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/Shared Assets/Scripts/IdleRunJump.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: c026a26bfd98f3e4fa9c736a173aaa79 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Photon Unity Networking/Demos/Shared Assets/Scripts/PlayerDiamond.cs b/Assets/Photon Unity Networking/Demos/Shared Assets/Scripts/PlayerDiamond.cs new file mode 100644 index 0000000..cfd97e1 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/Shared Assets/Scripts/PlayerDiamond.cs @@ -0,0 +1,97 @@ +using UnityEngine; +using System.Collections; + +public class PlayerDiamond : MonoBehaviour +{ + #region Properties + public Transform HeadTransform; + public float HeightOffset = 0.5f; + #endregion + + #region Members + PhotonView m_PhotonView; + PhotonView PhotonView + { + get + { + if( m_PhotonView == null ) + { + m_PhotonView = transform.parent.GetComponent(); + } + + return m_PhotonView; + } + } + + Renderer m_DiamondRenderer; + Renderer DiamondRenderer + { + get + { + if( m_DiamondRenderer == null ) + { + m_DiamondRenderer = GetComponentInChildren(); + } + + return m_DiamondRenderer; + } + } + + float m_Rotation; + float m_Height; + #endregion + + #region Update + void Start() + { + m_Height = HeightOffset; + + if( HeadTransform != null ) + { + m_Height += HeadTransform.position.y; + } + } + + void Update() + { + UpdateDiamondPosition(); + UpdateDiamondRotation(); + UpdateDiamondVisibility(); + } + + void UpdateDiamondPosition() + { + Vector3 targetPosition = Vector3.zero; + + if( HeadTransform != null ) + { + targetPosition = HeadTransform.position; + } + + targetPosition.y = m_Height; + + if( float.IsNaN( targetPosition.x ) == false && float.IsNaN( targetPosition.z ) == false ) + { + transform.position = Vector3.Lerp( transform.position, targetPosition, Time.deltaTime * 10f ); + } + } + + void UpdateDiamondRotation() + { + m_Rotation += Time.deltaTime * 180f; + m_Rotation = m_Rotation % 360; + + transform.rotation = Quaternion.Euler( 0, m_Rotation, 0 ); + } + + void UpdateDiamondVisibility() + { + DiamondRenderer.enabled = true; + + if( PhotonView == null || PhotonView.isMine == false ) + { + DiamondRenderer.enabled = false; + } + } + #endregion +} diff --git a/Assets/Photon Unity Networking/Demos/Shared Assets/Scripts/PlayerDiamond.cs.meta b/Assets/Photon Unity Networking/Demos/Shared Assets/Scripts/PlayerDiamond.cs.meta new file mode 100644 index 0000000..fa2f011 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/Shared Assets/Scripts/PlayerDiamond.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 2c4b3c14e128722448adb60485e29098 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Photon Unity Networking/Demos/Shared Assets/Scripts/PlayerVariables.cs b/Assets/Photon Unity Networking/Demos/Shared Assets/Scripts/PlayerVariables.cs new file mode 100644 index 0000000..d88f0bb --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/Shared Assets/Scripts/PlayerVariables.cs @@ -0,0 +1 @@ + // This file is deprecated and now empty. It can be removed safely. \ No newline at end of file diff --git a/Assets/Photon Unity Networking/Demos/Shared Assets/Scripts/PlayerVariables.cs.meta b/Assets/Photon Unity Networking/Demos/Shared Assets/Scripts/PlayerVariables.cs.meta new file mode 100644 index 0000000..cf123e2 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/Shared Assets/Scripts/PlayerVariables.cs.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 219bc3607c906b14da59b07981e0a793 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} diff --git a/Assets/Photon Unity Networking/Demos/Shared Assets/Skin.meta b/Assets/Photon Unity Networking/Demos/Shared Assets/Skin.meta new file mode 100644 index 0000000..0dfb418 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/Shared Assets/Skin.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: b7ade7deb12634f3688f984eb84c452a +folderAsset: yes +timeCreated: 1501014811 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Photon Unity Networking/Demos/Shared Assets/Skin/3dText.shader b/Assets/Photon Unity Networking/Demos/Shared Assets/Skin/3dText.shader new file mode 100644 index 0000000..551b0bd --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/Shared Assets/Skin/3dText.shader @@ -0,0 +1,18 @@ +Shader "GUI/3D Text Shader" { + Properties { + _MainTex ("Font Texture", 2D) = "white" {} + _Color ("Text Color", Color) = (1,1,1,1) + } + + SubShader { + Tags { "Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent" } + Lighting Off Cull Off ZWrite Off Fog { Mode Off } + Blend SrcAlpha OneMinusSrcAlpha + Pass { + Color [_Color] + SetTexture [_MainTex] { + combine primary, texture * primary + } + } + } +} \ No newline at end of file diff --git a/Assets/Photon Unity Networking/Demos/Shared Assets/Skin/3dText.shader.meta b/Assets/Photon Unity Networking/Demos/Shared Assets/Skin/3dText.shader.meta new file mode 100644 index 0000000..0d5ce81 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/Shared Assets/Skin/3dText.shader.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 953d6c4c7f7ec324d860efb0db9c68ff diff --git a/Assets/Photon Unity Networking/Demos/Shared Assets/Skin/BoxBright.png b/Assets/Photon Unity Networking/Demos/Shared Assets/Skin/BoxBright.png new file mode 100644 index 0000000..657b578 Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/Shared Assets/Skin/BoxBright.png differ diff --git a/Assets/Photon Unity Networking/Demos/Shared Assets/Skin/BoxBright.png.meta b/Assets/Photon Unity Networking/Demos/Shared Assets/Skin/BoxBright.png.meta new file mode 100644 index 0000000..a1d9c94 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/Shared Assets/Skin/BoxBright.png.meta @@ -0,0 +1,45 @@ +fileFormatVersion: 2 +guid: ab6d288fac925ae48bbeb5e02d83dce3 +TextureImporter: + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + linearTexture: 1 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -1 + maxTextureSize: 1024 + textureSettings: + filterMode: -1 + aniso: 1 + mipBias: -1 + wrapMode: 1 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spritePixelsToUnits: 100 + alphaIsTransparency: 1 + textureType: 2 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/Assets/Photon Unity Networking/Demos/Shared Assets/Skin/BoxOrange.png b/Assets/Photon Unity Networking/Demos/Shared Assets/Skin/BoxOrange.png new file mode 100644 index 0000000..3ec03a1 Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/Shared Assets/Skin/BoxOrange.png differ diff --git a/Assets/Photon Unity Networking/Demos/Shared Assets/Skin/BoxOrange.png.meta b/Assets/Photon Unity Networking/Demos/Shared Assets/Skin/BoxOrange.png.meta new file mode 100644 index 0000000..47c6c93 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/Shared Assets/Skin/BoxOrange.png.meta @@ -0,0 +1,45 @@ +fileFormatVersion: 2 +guid: 13548d8d0fcb5c44b8044ce08a99c697 +TextureImporter: + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + linearTexture: 1 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -1 + maxTextureSize: 1024 + textureSettings: + filterMode: -1 + aniso: 1 + mipBias: -1 + wrapMode: 1 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spritePixelsToUnits: 100 + alphaIsTransparency: 1 + textureType: 2 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/Assets/Photon Unity Networking/Demos/Shared Assets/Skin/BoxOrangeRed.png b/Assets/Photon Unity Networking/Demos/Shared Assets/Skin/BoxOrangeRed.png new file mode 100644 index 0000000..21e241f Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/Shared Assets/Skin/BoxOrangeRed.png differ diff --git a/Assets/Photon Unity Networking/Demos/Shared Assets/Skin/BoxOrangeRed.png.meta b/Assets/Photon Unity Networking/Demos/Shared Assets/Skin/BoxOrangeRed.png.meta new file mode 100644 index 0000000..3059504 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/Shared Assets/Skin/BoxOrangeRed.png.meta @@ -0,0 +1,45 @@ +fileFormatVersion: 2 +guid: 72708a25103c3fe4f9074f7296e86b7a +TextureImporter: + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + linearTexture: 1 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -1 + maxTextureSize: 1024 + textureSettings: + filterMode: -1 + aniso: 1 + mipBias: -1 + wrapMode: 1 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spritePixelsToUnits: 100 + alphaIsTransparency: 1 + textureType: 2 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/Assets/Photon Unity Networking/Demos/Shared Assets/Skin/BoxText.png b/Assets/Photon Unity Networking/Demos/Shared Assets/Skin/BoxText.png new file mode 100644 index 0000000..0cc87c6 Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/Shared Assets/Skin/BoxText.png differ diff --git a/Assets/Photon Unity Networking/Demos/Shared Assets/Skin/BoxText.png.meta b/Assets/Photon Unity Networking/Demos/Shared Assets/Skin/BoxText.png.meta new file mode 100644 index 0000000..ac89b1e --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/Shared Assets/Skin/BoxText.png.meta @@ -0,0 +1,45 @@ +fileFormatVersion: 2 +guid: 761ff1491b1f86c4d924261c553ac9cc +TextureImporter: + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + linearTexture: 1 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -1 + maxTextureSize: 1024 + textureSettings: + filterMode: -1 + aniso: 1 + mipBias: -1 + wrapMode: 1 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spritePixelsToUnits: 100 + alphaIsTransparency: 1 + textureType: 2 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/Assets/Photon Unity Networking/Demos/Shared Assets/Skin/BoxTextHover.png b/Assets/Photon Unity Networking/Demos/Shared Assets/Skin/BoxTextHover.png new file mode 100644 index 0000000..088d4d6 Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/Shared Assets/Skin/BoxTextHover.png differ diff --git a/Assets/Photon Unity Networking/Demos/Shared Assets/Skin/BoxTextHover.png.meta b/Assets/Photon Unity Networking/Demos/Shared Assets/Skin/BoxTextHover.png.meta new file mode 100644 index 0000000..fcc9fc6 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/Shared Assets/Skin/BoxTextHover.png.meta @@ -0,0 +1,45 @@ +fileFormatVersion: 2 +guid: 13154691f37c1884c865b54d8bd29d6e +TextureImporter: + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + linearTexture: 1 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -1 + maxTextureSize: 1024 + textureSettings: + filterMode: -1 + aniso: 1 + mipBias: -1 + wrapMode: 1 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spritePixelsToUnits: 100 + alphaIsTransparency: 1 + textureType: 2 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/Assets/Photon Unity Networking/Demos/Shared Assets/Skin/Jura-Flat-Material.mat b/Assets/Photon Unity Networking/Demos/Shared Assets/Skin/Jura-Flat-Material.mat new file mode 100644 index 0000000..f51d4c3 Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/Shared Assets/Skin/Jura-Flat-Material.mat differ diff --git a/Assets/Photon Unity Networking/Demos/Shared Assets/Skin/Jura-Flat-Material.mat.meta b/Assets/Photon Unity Networking/Demos/Shared Assets/Skin/Jura-Flat-Material.mat.meta new file mode 100644 index 0000000..237cb3f --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/Shared Assets/Skin/Jura-Flat-Material.mat.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: c190da5d14d0e904ba512abe82018576 +NativeFormatImporter: + userData: diff --git a/Assets/Photon Unity Networking/Demos/Shared Assets/Skin/Jura-Medium.ttf b/Assets/Photon Unity Networking/Demos/Shared Assets/Skin/Jura-Medium.ttf new file mode 100644 index 0000000..acaa33e Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/Shared Assets/Skin/Jura-Medium.ttf differ diff --git a/Assets/Photon Unity Networking/Demos/Shared Assets/Skin/Jura-Medium.ttf.meta b/Assets/Photon Unity Networking/Demos/Shared Assets/Skin/Jura-Medium.ttf.meta new file mode 100644 index 0000000..1c19eed --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/Shared Assets/Skin/Jura-Medium.ttf.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: e00995507c2406448b4c8429136104dd +TrueTypeFontImporter: + serializedVersion: 2 + fontSize: 16 + forceTextureCase: -2 + characterSpacing: 1 + characterPadding: 0 + includeFontData: 1 + use2xBehaviour: 0 + fontNames: [] + customCharacters: + fontRenderingMode: 0 + userData: diff --git a/Assets/Photon Unity Networking/Demos/Shared Assets/Skin/Orbitron Black.ttf b/Assets/Photon Unity Networking/Demos/Shared Assets/Skin/Orbitron Black.ttf new file mode 100644 index 0000000..aa17eda Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/Shared Assets/Skin/Orbitron Black.ttf differ diff --git a/Assets/Photon Unity Networking/Demos/Shared Assets/Skin/Orbitron Black.ttf.meta b/Assets/Photon Unity Networking/Demos/Shared Assets/Skin/Orbitron Black.ttf.meta new file mode 100644 index 0000000..85b9962 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/Shared Assets/Skin/Orbitron Black.ttf.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: 495c9e2a934bcc640a8d7427b13cb680 +TrueTypeFontImporter: + serializedVersion: 2 + fontSize: 16 + forceTextureCase: -2 + characterSpacing: 1 + characterPadding: 0 + includeFontData: 1 + use2xBehaviour: 0 + fontNames: [] + customCharacters: + fontRenderingMode: 0 + userData: diff --git a/Assets/Photon Unity Networking/Demos/Shared Assets/Skin/RoundedBox.png b/Assets/Photon Unity Networking/Demos/Shared Assets/Skin/RoundedBox.png new file mode 100644 index 0000000..181c88d Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/Shared Assets/Skin/RoundedBox.png differ diff --git a/Assets/Photon Unity Networking/Demos/Shared Assets/Skin/RoundedBox.png.meta b/Assets/Photon Unity Networking/Demos/Shared Assets/Skin/RoundedBox.png.meta new file mode 100644 index 0000000..7fc2671 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/Shared Assets/Skin/RoundedBox.png.meta @@ -0,0 +1,45 @@ +fileFormatVersion: 2 +guid: 9b2eedba1e3057e4b998cdef3d448105 +TextureImporter: + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + linearTexture: 1 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -1 + maxTextureSize: 1024 + textureSettings: + filterMode: -1 + aniso: 1 + mipBias: -1 + wrapMode: 1 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spritePixelsToUnits: 100 + alphaIsTransparency: 1 + textureType: 2 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/Assets/Photon Unity Networking/Demos/Shared Assets/Skin/Toggle.png b/Assets/Photon Unity Networking/Demos/Shared Assets/Skin/Toggle.png new file mode 100644 index 0000000..8c718e7 Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/Shared Assets/Skin/Toggle.png differ diff --git a/Assets/Photon Unity Networking/Demos/Shared Assets/Skin/Toggle.png.meta b/Assets/Photon Unity Networking/Demos/Shared Assets/Skin/Toggle.png.meta new file mode 100644 index 0000000..6e6d293 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/Shared Assets/Skin/Toggle.png.meta @@ -0,0 +1,45 @@ +fileFormatVersion: 2 +guid: b213d4a4b20760f49a105e29da3e4a9a +TextureImporter: + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + linearTexture: 1 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -1 + maxTextureSize: 1024 + textureSettings: + filterMode: -1 + aniso: 1 + mipBias: -1 + wrapMode: 1 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spritePixelsToUnits: 100 + alphaIsTransparency: 1 + textureType: 2 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/Assets/Photon Unity Networking/Demos/Shared Assets/Skin/ToggleHover.png b/Assets/Photon Unity Networking/Demos/Shared Assets/Skin/ToggleHover.png new file mode 100644 index 0000000..71eadd2 Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/Shared Assets/Skin/ToggleHover.png differ diff --git a/Assets/Photon Unity Networking/Demos/Shared Assets/Skin/ToggleHover.png.meta b/Assets/Photon Unity Networking/Demos/Shared Assets/Skin/ToggleHover.png.meta new file mode 100644 index 0000000..4e973d0 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/Shared Assets/Skin/ToggleHover.png.meta @@ -0,0 +1,45 @@ +fileFormatVersion: 2 +guid: b5771695f174e1143b3090393989b688 +TextureImporter: + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + linearTexture: 1 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -1 + maxTextureSize: 1024 + textureSettings: + filterMode: -1 + aniso: 1 + mipBias: -1 + wrapMode: 1 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spritePixelsToUnits: 100 + alphaIsTransparency: 1 + textureType: 2 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/Assets/Photon Unity Networking/Demos/Shared Assets/Skin/ToggleOn.png b/Assets/Photon Unity Networking/Demos/Shared Assets/Skin/ToggleOn.png new file mode 100644 index 0000000..40e69f8 Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/Shared Assets/Skin/ToggleOn.png differ diff --git a/Assets/Photon Unity Networking/Demos/Shared Assets/Skin/ToggleOn.png.meta b/Assets/Photon Unity Networking/Demos/Shared Assets/Skin/ToggleOn.png.meta new file mode 100644 index 0000000..2d683b7 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/Shared Assets/Skin/ToggleOn.png.meta @@ -0,0 +1,45 @@ +fileFormatVersion: 2 +guid: 0520b1e88ad26ae4bb758a35cdf13a64 +TextureImporter: + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + linearTexture: 1 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -1 + maxTextureSize: 1024 + textureSettings: + filterMode: -1 + aniso: 1 + mipBias: -1 + wrapMode: 1 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spritePixelsToUnits: 100 + alphaIsTransparency: 1 + textureType: 2 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/Assets/Photon Unity Networking/Demos/Shared Assets/Skin/ToggleOnHover.png b/Assets/Photon Unity Networking/Demos/Shared Assets/Skin/ToggleOnHover.png new file mode 100644 index 0000000..5a68194 Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/Shared Assets/Skin/ToggleOnHover.png differ diff --git a/Assets/Photon Unity Networking/Demos/Shared Assets/Skin/ToggleOnHover.png.meta b/Assets/Photon Unity Networking/Demos/Shared Assets/Skin/ToggleOnHover.png.meta new file mode 100644 index 0000000..cdd8432 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/Shared Assets/Skin/ToggleOnHover.png.meta @@ -0,0 +1,45 @@ +fileFormatVersion: 2 +guid: e10a16d9e8c6b844db2d3c1c5e4f231e +TextureImporter: + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + linearTexture: 1 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -1 + maxTextureSize: 1024 + textureSettings: + filterMode: -1 + aniso: 1 + mipBias: -1 + wrapMode: 1 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spritePixelsToUnits: 100 + alphaIsTransparency: 1 + textureType: 2 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/Assets/Photon Unity Networking/Demos/Shared Assets/Textures.meta b/Assets/Photon Unity Networking/Demos/Shared Assets/Textures.meta new file mode 100644 index 0000000..6f4ab53 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/Shared Assets/Textures.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 5712818b282c7478b8b86d7b5bd542c0 +folderAsset: yes +timeCreated: 1501014811 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Photon Unity Networking/Demos/Shared Assets/Textures/Gradient.png b/Assets/Photon Unity Networking/Demos/Shared Assets/Textures/Gradient.png new file mode 100644 index 0000000..67e1ce2 Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/Shared Assets/Textures/Gradient.png differ diff --git a/Assets/Photon Unity Networking/Demos/Shared Assets/Textures/Gradient.png.meta b/Assets/Photon Unity Networking/Demos/Shared Assets/Textures/Gradient.png.meta new file mode 100644 index 0000000..39f335f --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/Shared Assets/Textures/Gradient.png.meta @@ -0,0 +1,45 @@ +fileFormatVersion: 2 +guid: 4ca1824a2e144f043b9eb7d6e3777659 +TextureImporter: + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + linearTexture: 0 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -1 + maxTextureSize: 256 + textureSettings: + filterMode: 1 + aniso: 1 + mipBias: -1 + wrapMode: 1 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spritePixelsToUnits: 100 + alphaIsTransparency: 0 + textureType: 0 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/Assets/Photon Unity Networking/Demos/Shared Assets/Textures/Robot_Color.jpg b/Assets/Photon Unity Networking/Demos/Shared Assets/Textures/Robot_Color.jpg new file mode 100644 index 0000000..2746d8c Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/Shared Assets/Textures/Robot_Color.jpg differ diff --git a/Assets/Photon Unity Networking/Demos/Shared Assets/Textures/Robot_Color.jpg.meta b/Assets/Photon Unity Networking/Demos/Shared Assets/Textures/Robot_Color.jpg.meta new file mode 100644 index 0000000..b5fe37d --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/Shared Assets/Textures/Robot_Color.jpg.meta @@ -0,0 +1,45 @@ +fileFormatVersion: 2 +guid: 1fbb41709a1d9334696860db720026e5 +TextureImporter: + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + linearTexture: 0 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -1 + maxTextureSize: 1024 + textureSettings: + filterMode: -1 + aniso: -1 + mipBias: -1 + wrapMode: -1 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spritePixelsToUnits: 100 + alphaIsTransparency: 0 + textureType: -1 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/Assets/Photon Unity Networking/Demos/Shared Assets/Textures/Robot_Normal.jpg b/Assets/Photon Unity Networking/Demos/Shared Assets/Textures/Robot_Normal.jpg new file mode 100644 index 0000000..c9729be Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/Shared Assets/Textures/Robot_Normal.jpg differ diff --git a/Assets/Photon Unity Networking/Demos/Shared Assets/Textures/Robot_Normal.jpg.meta b/Assets/Photon Unity Networking/Demos/Shared Assets/Textures/Robot_Normal.jpg.meta new file mode 100644 index 0000000..bdb4e4c --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/Shared Assets/Textures/Robot_Normal.jpg.meta @@ -0,0 +1,45 @@ +fileFormatVersion: 2 +guid: a1454d7237641fa49a7f66d6bee624ad +TextureImporter: + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + linearTexture: 1 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 1 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -1 + maxTextureSize: 1024 + textureSettings: + filterMode: -1 + aniso: -1 + mipBias: -1 + wrapMode: -1 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spritePixelsToUnits: 100 + alphaIsTransparency: 0 + textureType: 1 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/Assets/Photon Unity Networking/Demos/Shared Assets/Textures/UnitCircleTexture.png b/Assets/Photon Unity Networking/Demos/Shared Assets/Textures/UnitCircleTexture.png new file mode 100644 index 0000000..42158d1 Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/Shared Assets/Textures/UnitCircleTexture.png differ diff --git a/Assets/Photon Unity Networking/Demos/Shared Assets/Textures/UnitCircleTexture.png.meta b/Assets/Photon Unity Networking/Demos/Shared Assets/Textures/UnitCircleTexture.png.meta new file mode 100644 index 0000000..b10229d --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/Shared Assets/Textures/UnitCircleTexture.png.meta @@ -0,0 +1,45 @@ +fileFormatVersion: 2 +guid: 875557e634eec5c42a4681b331501c01 +TextureImporter: + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + linearTexture: 0 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -1 + maxTextureSize: 128 + textureSettings: + filterMode: -1 + aniso: -1 + mipBias: -1 + wrapMode: -1 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spritePixelsToUnits: 100 + alphaIsTransparency: 1 + textureType: -1 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/Assets/Photon Unity Networking/Demos/Shared Assets/Textures/UnitTexture.png b/Assets/Photon Unity Networking/Demos/Shared Assets/Textures/UnitTexture.png new file mode 100644 index 0000000..f6dc13f Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/Shared Assets/Textures/UnitTexture.png differ diff --git a/Assets/Photon Unity Networking/Demos/Shared Assets/Textures/UnitTexture.png.meta b/Assets/Photon Unity Networking/Demos/Shared Assets/Textures/UnitTexture.png.meta new file mode 100644 index 0000000..eb85ffd --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/Shared Assets/Textures/UnitTexture.png.meta @@ -0,0 +1,45 @@ +fileFormatVersion: 2 +guid: df33d7843e7ff98489b55381f6cdd866 +TextureImporter: + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + linearTexture: 0 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -3 + maxTextureSize: 1024 + textureSettings: + filterMode: 2 + aniso: 9 + mipBias: -1 + wrapMode: -1 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spritePixelsToUnits: 100 + alphaIsTransparency: 0 + textureType: 5 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/Assets/Photon Unity Networking/Demos/Shared Assets/Textures/UnitTextureBlue.png b/Assets/Photon Unity Networking/Demos/Shared Assets/Textures/UnitTextureBlue.png new file mode 100644 index 0000000..2c54956 Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/Shared Assets/Textures/UnitTextureBlue.png differ diff --git a/Assets/Photon Unity Networking/Demos/Shared Assets/Textures/UnitTextureBlue.png.meta b/Assets/Photon Unity Networking/Demos/Shared Assets/Textures/UnitTextureBlue.png.meta new file mode 100644 index 0000000..e69f1b3 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/Shared Assets/Textures/UnitTextureBlue.png.meta @@ -0,0 +1,45 @@ +fileFormatVersion: 2 +guid: bf44fd0b5bb0c4142b16ba9db02789fc +TextureImporter: + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + linearTexture: 0 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -3 + maxTextureSize: 1024 + textureSettings: + filterMode: 2 + aniso: 9 + mipBias: -1 + wrapMode: -1 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spritePixelsToUnits: 100 + alphaIsTransparency: 0 + textureType: 5 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/Assets/Photon Unity Networking/Demos/Shared Assets/Textures/UnitTextureRed.png b/Assets/Photon Unity Networking/Demos/Shared Assets/Textures/UnitTextureRed.png new file mode 100644 index 0000000..886bd67 Binary files /dev/null and b/Assets/Photon Unity Networking/Demos/Shared Assets/Textures/UnitTextureRed.png differ diff --git a/Assets/Photon Unity Networking/Demos/Shared Assets/Textures/UnitTextureRed.png.meta b/Assets/Photon Unity Networking/Demos/Shared Assets/Textures/UnitTextureRed.png.meta new file mode 100644 index 0000000..fa47989 --- /dev/null +++ b/Assets/Photon Unity Networking/Demos/Shared Assets/Textures/UnitTextureRed.png.meta @@ -0,0 +1,45 @@ +fileFormatVersion: 2 +guid: 9349ff1a2d6d7804486fef5d7c3a67de +TextureImporter: + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + linearTexture: 0 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -3 + maxTextureSize: 1024 + textureSettings: + filterMode: 2 + aniso: 9 + mipBias: -1 + wrapMode: -1 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spritePixelsToUnits: 100 + alphaIsTransparency: 0 + textureType: 5 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/Assets/Photon Unity Networking/Editor.meta b/Assets/Photon Unity Networking/Editor.meta new file mode 100644 index 0000000..9a02c04 --- /dev/null +++ b/Assets/Photon Unity Networking/Editor.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: b2e209ff8ee264c40b95c04f425fd80c +folderAsset: yes +timeCreated: 1501014811 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Photon Unity Networking/Editor/PhotonNetwork.meta b/Assets/Photon Unity Networking/Editor/PhotonNetwork.meta new file mode 100644 index 0000000..a3d6a03 --- /dev/null +++ b/Assets/Photon Unity Networking/Editor/PhotonNetwork.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: caea577c0b6a0439b8836ca617895789 +folderAsset: yes +timeCreated: 1501014811 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Photon Unity Networking/Editor/PhotonNetwork/AccountService.cs b/Assets/Photon Unity Networking/Editor/PhotonNetwork/AccountService.cs new file mode 100644 index 0000000..2f97be4 --- /dev/null +++ b/Assets/Photon Unity Networking/Editor/PhotonNetwork/AccountService.cs @@ -0,0 +1,235 @@ +// ---------------------------------------------------------------------------- +// +// Photon Cloud Account Service - Copyright (C) 2012 Exit Games GmbH +// +// +// Provides methods to register a new user-account for the Photon Cloud and +// get the resulting appId. +// +// developer@exitgames.com +// ---------------------------------------------------------------------------- + +#if UNITY_EDITOR + +using System.Net.Security; +using System.Security.Cryptography.X509Certificates; + +using System; +using System.Collections.Generic; +using System.IO; +using System.Net; +using ExitGames.Client.Photon; +using Newtonsoft.Json; + + +public class AccountService +{ + private const string ServiceUrl = "https://service.exitgames.com/AccountExt/AccountServiceExt.aspx"; + + private Action registrationCallback; // optional (when using async reg) + + public string Message { get; private set; } // msg from server (in case of success, this is the appid) + + protected internal Exception Exception { get; set; } // exceptions in account-server communication + + public string AppId { get; private set; } + + public string AppId2 { get; private set; } + + public int ReturnCode { get; private set; } // 0 = OK. anything else is a error with Message + + public enum Origin : byte { ServerWeb = 1, CloudWeb = 2, Pun = 3, Playmaker = 4 }; + + /// + /// Creates a instance of the Account Service to register Photon Cloud accounts. + /// + public AccountService() + { + WebRequest.DefaultWebProxy = null; + ServicePointManager.ServerCertificateValidationCallback = Validator; + } + + public static bool Validator(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors policyErrors) + { + return true; // any certificate is ok in this case + } + + /// + /// Attempts to create a Photon Cloud Account. + /// Check ReturnCode, Message and AppId to get the result of this attempt. + /// + /// Email of the account. + /// Marks which channel created the new account (if it's new). + /// Defines which type of Photon-service is being requested. + public void RegisterByEmail(string email, Origin origin, string serviceType = null) + { + this.registrationCallback = null; + this.AppId = string.Empty; + this.AppId2 = string.Empty; + this.Message = string.Empty; + this.ReturnCode = -1; + + string result; + try + { + WebRequest req = HttpWebRequest.Create(this.RegistrationUri(email, (byte)origin, serviceType)); + HttpWebResponse resp = req.GetResponse() as HttpWebResponse; + + // now read result + StreamReader reader = new StreamReader(resp.GetResponseStream()); + result = reader.ReadToEnd(); + } + catch (Exception ex) + { + this.Message = "Failed to connect to Cloud Account Service. Please register via account website."; + this.Exception = ex; + return; + } + + this.ParseResult(result); + } + + /// + /// Attempts to create a Photon Cloud Account asynchronously. + /// Once your callback is called, check ReturnCode, Message and AppId to get the result of this attempt. + /// + /// Email of the account. + /// Marks which channel created the new account (if it's new). + /// Defines which type of Photon-service is being requested. + /// Called when the result is available. + public void RegisterByEmailAsync(string email, Origin origin, string serviceType, Action callback = null) + { + this.registrationCallback = callback; + this.AppId = string.Empty; + this.AppId2 = string.Empty; + this.Message = string.Empty; + this.ReturnCode = -1; + + try + { + HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create(this.RegistrationUri(email, (byte)origin, serviceType)); + req.Timeout = 5000; + req.BeginGetResponse(this.OnRegisterByEmailCompleted, req); + } + catch (Exception ex) + { + this.Message = "Failed to connect to Cloud Account Service. Please register via account website."; + this.Exception = ex; + if (this.registrationCallback != null) + { + this.registrationCallback(this); + } + } + } + + /// + /// Internal callback with result of async HttpWebRequest (in RegisterByEmailAsync). + /// + /// + private void OnRegisterByEmailCompleted(IAsyncResult ar) + { + try + { + HttpWebRequest request = (HttpWebRequest)ar.AsyncState; + HttpWebResponse response = request.EndGetResponse(ar) as HttpWebResponse; + + if (response != null && response.StatusCode == HttpStatusCode.OK) + { + // no error. use the result + StreamReader reader = new StreamReader(response.GetResponseStream()); + string result = reader.ReadToEnd(); + + this.ParseResult(result); + } + else + { + // a response but some error on server. show message + this.Message = "Failed to connect to Cloud Account Service. Please register via account website."; + } + } + catch (Exception ex) + { + // not even a response. show message + this.Message = "Failed to connect to Cloud Account Service. Please register via account website."; + this.Exception = ex; + } + + if (this.registrationCallback != null) + { + this.registrationCallback(this); + } + } + + /// + /// Creates the service-call Uri, escaping the email for security reasons. + /// + /// Email of the account. + /// 1 = server-web, 2 = cloud-web, 3 = PUN, 4 = playmaker + /// Defines which type of Photon-service is being requested. Options: "", "voice", "chat" + /// Uri to call. + private Uri RegistrationUri(string email, byte origin, string serviceType) + { + if (serviceType == null) + { + serviceType = string.Empty; + } + + string emailEncoded = Uri.EscapeDataString(email); + string uriString = string.Format("{0}?email={1}&origin={2}&serviceType={3}", ServiceUrl, emailEncoded, origin, serviceType); + + return new Uri(uriString); + } + + /// + /// Reads the Json response and applies it to local properties. + /// + /// + private void ParseResult(string result) + { + if (string.IsNullOrEmpty(result)) + { + this.Message = "Server's response was empty. Please register through account website during this service interruption."; + return; + } + + Dictionary values = JsonConvert.DeserializeObject>(result); + if (values == null) + { + this.Message = "Service temporarily unavailable. Please register through account website."; + return; + } + + int returnCodeInt = -1; + string returnCodeString = string.Empty; + string message; + string messageDetailed; + + values.TryGetValue("ReturnCode", out returnCodeString); + values.TryGetValue("Message", out message); + values.TryGetValue("MessageDetailed", out messageDetailed); + + int.TryParse(returnCodeString, out returnCodeInt); + + this.ReturnCode = returnCodeInt; + if (returnCodeInt == 0) + { + // returnCode == 0 means: all ok. message is new AppId + this.AppId = message; + if (PhotonEditorUtils.HasVoice) + { + this.AppId2 = messageDetailed; + } + } + else + { + // any error gives returnCode != 0 + this.AppId = string.Empty; + if (PhotonEditorUtils.HasVoice) + { + this.AppId2 = string.Empty; + } + this.Message = message; + } + } +} +#endif \ No newline at end of file diff --git a/Assets/Photon Unity Networking/Editor/PhotonNetwork/AccountService.cs.meta b/Assets/Photon Unity Networking/Editor/PhotonNetwork/AccountService.cs.meta new file mode 100644 index 0000000..a070b17 --- /dev/null +++ b/Assets/Photon Unity Networking/Editor/PhotonNetwork/AccountService.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 166dfe22956ef0341b28e18d0499e363 +labels: +- ExitGames +- PUN +- Photon +- Networking +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} diff --git a/Assets/Photon Unity Networking/Editor/PhotonNetwork/CullAreaEditor.cs b/Assets/Photon Unity Networking/Editor/PhotonNetwork/CullAreaEditor.cs new file mode 100644 index 0000000..a06865e --- /dev/null +++ b/Assets/Photon Unity Networking/Editor/PhotonNetwork/CullAreaEditor.cs @@ -0,0 +1,232 @@ +using UnityEditor; +using UnityEngine; + +[CanEditMultipleObjects] +[CustomEditor(typeof(CullArea))] +public class CullAreaEditor : Editor +{ + private bool alignEditorCamera; + + private CullArea cullArea; + + private enum UP_AXIS_OPTIONS + { + SideScrollerMode = 0, + TopDownOr3DMode = 1 + } + + private UP_AXIS_OPTIONS upAxisOptions; + + public void OnEnable() + { + cullArea = (CullArea) target; + + // Destroying the newly created cull area if there is already one existing + if (FindObjectsOfType().Length > 1) + { + Debug.LogWarning("Destroying newly created cull area because there is already one existing in the scene."); + + DestroyImmediate(cullArea); + + return; + } + + // Prevents the dropdown from resetting + if (cullArea != null) + { + upAxisOptions = cullArea.YIsUpAxis ? UP_AXIS_OPTIONS.SideScrollerMode : UP_AXIS_OPTIONS.TopDownOr3DMode; + } + } + + public override void OnInspectorGUI() + { + EditorGUILayout.BeginVertical(); + + if (Application.isEditor && !Application.isPlaying) + { + OnInspectorGUIEditMode(); + } + else + { + OnInspectorGUIPlayMode(); + } + + EditorGUILayout.EndVertical(); + } + + /// + /// Represents the inspector GUI when edit mode is active. + /// + private void OnInspectorGUIEditMode() + { + EditorGUI.BeginChangeCheck(); + + #region DEFINE_UP_AXIS + + { + EditorGUILayout.BeginVertical(); + EditorGUILayout.LabelField("Select game type", EditorStyles.boldLabel); + upAxisOptions = (UP_AXIS_OPTIONS) EditorGUILayout.EnumPopup("Game type", upAxisOptions); + cullArea.YIsUpAxis = (upAxisOptions == UP_AXIS_OPTIONS.SideScrollerMode); + EditorGUILayout.EndVertical(); + } + + #endregion + + EditorGUILayout.Space(); + + #region SUBDIVISION + + { + EditorGUILayout.BeginVertical(); + EditorGUILayout.LabelField("Set the number of subdivisions", EditorStyles.boldLabel); + cullArea.NumberOfSubdivisions = EditorGUILayout.IntSlider("Number of subdivisions", cullArea.NumberOfSubdivisions, 0, CullArea.MAX_NUMBER_OF_SUBDIVISIONS); + EditorGUILayout.EndVertical(); + + EditorGUILayout.Space(); + + if (cullArea.NumberOfSubdivisions != 0) + { + for (int index = 0; index < cullArea.Subdivisions.Length; ++index) + { + if ((index + 1) <= cullArea.NumberOfSubdivisions) + { + string countMessage = (index + 1) + ". Subdivision: row / column count"; + + EditorGUILayout.BeginVertical(); + cullArea.Subdivisions[index] = EditorGUILayout.Vector2Field(countMessage, cullArea.Subdivisions[index]); + EditorGUILayout.EndVertical(); + + EditorGUILayout.Space(); + } + else + { + cullArea.Subdivisions[index] = new UnityEngine.Vector2(1, 1); + } + } + } + } + + #endregion + + EditorGUILayout.Space(); + + #region UPDATING_MAIN_CAMERA + + { + EditorGUILayout.BeginVertical(); + + EditorGUILayout.LabelField("View and camera options", EditorStyles.boldLabel); + alignEditorCamera = EditorGUILayout.Toggle("Automatically align editor view with grid", alignEditorCamera); + + if (Camera.main != null) + { + if (GUILayout.Button("Align main camera with grid")) + { + Undo.RecordObject(Camera.main.transform, "Align main camera with grid."); + + float yCoord = cullArea.YIsUpAxis ? cullArea.Center.y : Mathf.Max(cullArea.Size.x, cullArea.Size.y); + float zCoord = cullArea.YIsUpAxis ? -Mathf.Max(cullArea.Size.x, cullArea.Size.y) : cullArea.Center.y; + + Camera.main.transform.position = new Vector3(cullArea.Center.x, yCoord, zCoord); + Camera.main.transform.LookAt(cullArea.transform.position); + } + + EditorGUILayout.LabelField("Current main camera position is " + Camera.main.transform.position.ToString()); + } + + EditorGUILayout.EndVertical(); + } + + #endregion + + if (EditorGUI.EndChangeCheck()) + { + cullArea.RecreateCellHierarchy = true; + + AlignEditorView(); + } + } + + /// + /// Represents the inspector GUI when play mode is active. + /// + private void OnInspectorGUIPlayMode() + { + EditorGUILayout.LabelField("No changes allowed when game is running. Please exit play mode first.", EditorStyles.boldLabel); + } + + public void OnSceneGUI() + { + Handles.BeginGUI(); + GUILayout.BeginArea(new Rect(Screen.width - 110, Screen.height - 90, 100, 60)); + + if (GUILayout.Button("Reset position")) + { + cullArea.transform.position = Vector3.zero; + } + + if (GUILayout.Button("Reset scaling")) + { + cullArea.transform.localScale = new Vector3(25.0f, 25.0f, 25.0f); + } + + GUILayout.EndArea(); + Handles.EndGUI(); + + // Checking for changes of the transform + if (cullArea.transform.hasChanged) + { + // Resetting position + float posX = cullArea.transform.position.x; + float posY = cullArea.YIsUpAxis ? cullArea.transform.position.y : 0.0f; + float posZ = !cullArea.YIsUpAxis ? cullArea.transform.position.z : 0.0f; + + cullArea.transform.position = new Vector3(posX, posY, posZ); + + // Resetting scaling + if (cullArea.Size.x < 1.0f || cullArea.Size.y < 1.0f) + { + float scaleX = (cullArea.transform.localScale.x < 1.0f) ? 1.0f : cullArea.transform.localScale.x; + float scaleY = (cullArea.transform.localScale.y < 1.0f) ? 1.0f : cullArea.transform.localScale.y; + float scaleZ = (cullArea.transform.localScale.z < 1.0f) ? 1.0f : cullArea.transform.localScale.z; + + cullArea.transform.localScale = new Vector3(scaleX, scaleY, scaleZ); + + Debug.LogWarning("Scaling on a single axis can not be lower than 1. Resetting..."); + } + + cullArea.RecreateCellHierarchy = true; + + AlignEditorView(); + } + } + + /// + /// Aligns the editor view with the created grid. + /// + private void AlignEditorView() + { + if (!alignEditorCamera) + { + return; + } + + // This creates a temporary game object in order to align the editor view. + // The created game object is destroyed afterwards. + GameObject tmpGo = new GameObject(); + + float yCoord = cullArea.YIsUpAxis ? cullArea.Center.y : Mathf.Max(cullArea.Size.x, cullArea.Size.y); + float zCoord = cullArea.YIsUpAxis ? -Mathf.Max(cullArea.Size.x, cullArea.Size.y) : cullArea.Center.y; + + tmpGo.transform.position = new Vector3(cullArea.Center.x, yCoord, zCoord); + tmpGo.transform.LookAt(cullArea.transform.position); + + if (SceneView.lastActiveSceneView != null) + { + SceneView.lastActiveSceneView.AlignViewToObject(tmpGo.transform); + } + + DestroyImmediate(tmpGo); + } +} \ No newline at end of file diff --git a/Assets/Photon Unity Networking/Editor/PhotonNetwork/CullAreaEditor.cs.meta b/Assets/Photon Unity Networking/Editor/PhotonNetwork/CullAreaEditor.cs.meta new file mode 100644 index 0000000..7d72143 --- /dev/null +++ b/Assets/Photon Unity Networking/Editor/PhotonNetwork/CullAreaEditor.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: abadaa451a7bff0489078ed9eec61133 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Photon Unity Networking/Editor/PhotonNetwork/Newtonsoft.Json.dll b/Assets/Photon Unity Networking/Editor/PhotonNetwork/Newtonsoft.Json.dll new file mode 100644 index 0000000..664b5b5 Binary files /dev/null and b/Assets/Photon Unity Networking/Editor/PhotonNetwork/Newtonsoft.Json.dll differ diff --git a/Assets/Photon Unity Networking/Editor/PhotonNetwork/Newtonsoft.Json.dll.meta b/Assets/Photon Unity Networking/Editor/PhotonNetwork/Newtonsoft.Json.dll.meta new file mode 100644 index 0000000..735d8de --- /dev/null +++ b/Assets/Photon Unity Networking/Editor/PhotonNetwork/Newtonsoft.Json.dll.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0268f98d7c649564a818b0768fc68d4b +labels: +- ExitGames +- PUN +- Photon +- Networking +MonoAssemblyImporter: + serializedVersion: 1 + iconMap: {} + executionOrder: {} diff --git a/Assets/Photon Unity Networking/Editor/PhotonNetwork/PhotonConverter.cs b/Assets/Photon Unity Networking/Editor/PhotonNetwork/PhotonConverter.cs new file mode 100644 index 0000000..9787185 --- /dev/null +++ b/Assets/Photon Unity Networking/Editor/PhotonNetwork/PhotonConverter.cs @@ -0,0 +1,68 @@ +// ---------------------------------------------------------------------------- +// +// PhotonNetwork Framework for Unity - Copyright (C) 2011 Exit Games GmbH +// +// +// Script to convert old RPC attributes into new RPC attributes. +// +// developer@exitgames.com +// ---------------------------------------------------------------------------- + +#if UNITY_5 && !UNITY_5_0 && !UNITY_5_1 && !UNITY_5_2 +#define UNITY_MIN_5_3 +#endif + + +using UnityEngine; +using System.Collections.Generic; +using System.IO; + +public class PhotonConverter : Photon.MonoBehaviour +{ + public static List GetScriptsInFolder(string folder) + { + List scripts = new List(); + + try + { + scripts.AddRange(Directory.GetFiles(folder, "*.cs", SearchOption.AllDirectories)); + scripts.AddRange(Directory.GetFiles(folder, "*.js", SearchOption.AllDirectories)); + scripts.AddRange(Directory.GetFiles(folder, "*.boo", SearchOption.AllDirectories)); + } + catch (System.Exception ex) + { + Debug.Log("Getting script list from folder " + folder + " failed. Exception:\n" + ex.ToString()); + } + + return scripts; + } + + /// default path: "Assets" + public static void ConvertRpcAttribute(string path) + { + if (string.IsNullOrEmpty(path)) + { + path = "Assets"; + } + + List scripts = GetScriptsInFolder(path); + foreach (string file in scripts) + { + string text = File.ReadAllText(file); + string textCopy = text; + if (file.EndsWith("PhotonConverter.cs")) + { + continue; + } + + text = text.Replace("[RPC]", "[PunRPC]"); + text = text.Replace("@RPC", "@PunRPC"); + + if (!text.Equals(textCopy)) + { + File.WriteAllText(file, text); + Debug.Log("Converted RPC to PunRPC in: " + file); + } + } + } +} \ No newline at end of file diff --git a/Assets/Photon Unity Networking/Editor/PhotonNetwork/PhotonConverter.cs.meta b/Assets/Photon Unity Networking/Editor/PhotonNetwork/PhotonConverter.cs.meta new file mode 100644 index 0000000..dc6b834 --- /dev/null +++ b/Assets/Photon Unity Networking/Editor/PhotonNetwork/PhotonConverter.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 15757b26cd9b53247be86da9e8da19dd +labels: +- ExitGames +- PUN +- Photon +- Networking +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} diff --git a/Assets/Photon Unity Networking/Editor/PhotonNetwork/PhotonEditor.cs b/Assets/Photon Unity Networking/Editor/PhotonNetwork/PhotonEditor.cs new file mode 100644 index 0000000..6aba09c --- /dev/null +++ b/Assets/Photon Unity Networking/Editor/PhotonNetwork/PhotonEditor.cs @@ -0,0 +1,759 @@ +// ---------------------------------------------------------------------------- +// +// PhotonNetwork Framework for Unity - Copyright (C) 2011 Exit Games GmbH +// +// +// MenuItems and in-Editor scripts for PhotonNetwork. +// +// developer@exitgames.com +// ---------------------------------------------------------------------------- + +using System; +using System.Collections.Generic; +using System.IO; +using System.Reflection; +using ExitGames.Client.Photon; +using UnityEditor; +using UnityEditorInternal; +using UnityEngine; + + +public class PunWizardText +{ + public string WindowTitle = "PUN Wizard"; + public string SetupWizardWarningTitle = "Warning"; + public string SetupWizardWarningMessage = "You have not yet run the Photon setup wizard! Your game won't be able to connect. See Windows -> Photon Unity Networking."; + public string MainMenuButton = "Main Menu"; + public string SetupWizardTitle = "PUN Setup"; + public string SetupWizardInfo = "Thanks for importing Photon Unity Networking.\nThis window should set you up.\n\n- To use an existing Photon Cloud App, enter your AppId.\n- To register an account or access an existing one, enter the account's mail address.\n- To use Photon OnPremise, skip this step."; + public string EmailOrAppIdLabel = "AppId or Email"; + public string AlreadyRegisteredInfo = "The email is registered so we can't fetch your AppId (without password).\n\nPlease login online to get your AppId and paste it above."; + public string SkipRegistrationInfo = "Skipping? No problem:\nEdit your server settings in the PhotonServerSettings file."; + public string RegisteredNewAccountInfo = "We created a (free) account and fetched you an AppId.\nWelcome. Your PUN project is setup."; + public string AppliedToSettingsInfo = "Your AppId is now applied to this project."; + public string SetupCompleteInfo = "Done!\nAll connection settings can be edited in the PhotonServerSettings now.\nHave a look."; + public string CloseWindowButton = "Close"; + public string SkipButton = "Skip"; + public string SetupButton = "Setup Project"; + public string MobileExportNoteLabel = "Build for mobiles impossible. Get PUN+ or Unity Pro for mobile or use Unity 5."; + public string MobilePunPlusExportNoteLabel = "PUN+ available. Using native sockets for iOS/Android."; + public string CancelButton = "Cancel"; + public string PUNWizardLabel = "PUN Wizard"; + public string SettingsButton = "Settings"; + public string SetupServerCloudLabel = "Setup wizard for setting up your own server or the cloud."; + public string WarningPhotonDisconnect = ""; + public string StartButton = "Start"; + public string LocateSettingsButton = "Locate PhotonServerSettings"; + public string SettingsHighlightLabel = "Highlights the used photon settings file in the project."; + public string DocumentationLabel = "Documentation"; + public string OpenPDFText = "Reference PDF"; + public string OpenPDFTooltip = "Opens the local documentation pdf."; + public string OpenDevNetText = "DevNet / Manual"; + public string OpenDevNetTooltip = "Online documentation for Photon."; + public string OpenCloudDashboardText = "Cloud Dashboard Login"; + public string OpenCloudDashboardTooltip = "Review Cloud App information and statistics."; + public string OpenForumText = "Open Forum"; + public string OpenForumTooltip = "Online support for Photon."; + public string OkButton = "Ok"; + public string OwnHostCloudCompareLabel = "I am not quite sure how 'my own host' compares to 'cloud'."; + public string ComparisonPageButton = "Cloud versus OnPremise"; + public string ConnectionTitle = "Connecting"; + public string ConnectionInfo = "Connecting to the account service..."; + public string ErrorTextTitle = "Error"; + public string IncorrectRPCListTitle = "Warning: RPC-list becoming incompatible!"; + public string IncorrectRPCListLabel = "Your project's RPC-list is full, so we can't add some RPCs just compiled.\n\nBy removing outdated RPCs, the list will be long enough but incompatible with older client builds!\n\nMake sure you change the game version where you use PhotonNetwork.ConnectUsingSettings()."; + public string RemoveOutdatedRPCsLabel = "Remove outdated RPCs"; + public string FullRPCListTitle = "Warning: RPC-list is full!"; + public string FullRPCListLabel = "Your project's RPC-list is too long for PUN.\n\nYou can change PUN's source to use short-typed RPC index. Look for comments 'LIMITS RPC COUNT'\n\nAlternatively, remove some RPC methods (use more parameters per RPC maybe).\n\nAfter a RPC-list refresh, make sure you change the game version where you use PhotonNetwork.ConnectUsingSettings()."; + public string SkipRPCListUpdateLabel = "Skip RPC-list update"; + public string PUNNameReplaceTitle = "Warning: RPC-list Compatibility"; + public string PUNNameReplaceLabel = "PUN replaces RPC names with numbers by using the RPC-list. All clients must use the same list for that.\n\nClearing it most likely makes your client incompatible with previous versions! Change your game version or make sure the RPC-list matches other clients."; + public string RPCListCleared = "Clear RPC-list"; + public string ServerSettingsCleanedWarning = "Cleared the PhotonServerSettings.RpcList! This makes new builds incompatible with older ones. Better change game version in PhotonNetwork.ConnectUsingSettings()."; + public string RpcFoundMessage = "Some code uses the obsolete RPC attribute. PUN now requires the PunRPC attribute to mark remote-callable methods.\nThe Editor can search and replace that code which will modify your source."; + public string RpcFoundDialogTitle = "RPC Attribute Outdated"; + public string RpcReplaceButton = "Replace. I got a backup."; + public string RpcSkipReplace = "Not now."; + public string WizardMainWindowInfo = "This window should help you find important settings for PUN, as well as documentation."; +} + + +[InitializeOnLoad] +public class PhotonEditor : EditorWindow +{ + protected static Type WindowType = typeof (PhotonEditor); + + protected Vector2 scrollPos = Vector2.zero; + + private readonly Vector2 preferredSize = new Vector2(350, 400); + + private static Texture2D BackgroundImage; + + public static PunWizardText CurrentLang = new PunWizardText(); + + + protected static AccountService.Origin RegisterOrigin = AccountService.Origin.Pun; + + protected static string DocumentationLocation = "Assets/Photon Unity Networking/PhotonNetwork-Documentation.pdf"; + + protected static string UrlFreeLicense = "https://www.photonengine.com/dashboard/OnPremise"; + + protected static string UrlDevNet = "http://doc.photonengine.com/en/pun/current"; + + protected static string UrlForum = "http://forum.exitgames.com"; + + protected static string UrlCompare = "http://doc.photonengine.com/en/realtime/current/getting-started/onpremise-or-saas"; + + protected static string UrlHowToSetup = "http://doc.photonengine.com/en/onpremise/current/getting-started/photon-server-in-5min"; + + protected static string UrlAppIDExplained = "http://doc.photonengine.com/en/realtime/current/getting-started/obtain-your-app-id"; + + protected static string UrlAccountPage = "https://www.photonengine.com/Account/SignIn?email="; // opened in browser + + protected static string UrlCloudDashboard = "https://www.photonengine.com/dashboard?email="; + + + private enum PhotonSetupStates + { + MainUi, + + RegisterForPhotonCloud, + + EmailAlreadyRegistered, + + GoEditPhotonServerSettings + } + + private bool isSetupWizard = false; + + private PhotonSetupStates photonSetupState = PhotonSetupStates.RegisterForPhotonCloud; + + + private bool minimumInput = false; + private bool useMail = false; + private bool useAppId = false; + private bool useSkip = false; + private bool highlightedSettings = false; + private bool close = false; + private string mailOrAppId = string.Empty; + + + private static double lastWarning = 0; + private static bool postCompileActionsDone; + + private static bool isPunPlus; + private static bool androidLibExists; + private static bool iphoneLibExists; + + + // setup once on load + static PhotonEditor() + { + EditorApplication.projectWindowChanged += EditorUpdate; + EditorApplication.hierarchyWindowChanged += EditorUpdate; + EditorApplication.playmodeStateChanged += PlaymodeStateChanged; + EditorApplication.update += OnUpdate; + + // detect optional packages + PhotonEditor.CheckPunPlus(); + } + + // setup per window + public PhotonEditor() + { + minSize = this.preferredSize; + } + + [MenuItem("Window/Photon Unity Networking/PUN Wizard &p", false, 0)] + protected static void MenuItemOpenWizard() + { + PhotonEditor win = GetWindow(WindowType, false, CurrentLang.WindowTitle, true) as PhotonEditor; + win.photonSetupState = PhotonSetupStates.MainUi; + win.isSetupWizard = false; + } + + [MenuItem("Window/Photon Unity Networking/Highlight Server Settings %#&p", false, 1)] + protected static void MenuItemHighlightSettings() + { + HighlightSettings(); + } + + /// Creates an Editor window, showing the cloud-registration wizard for Photon (entry point to setup PUN). + protected static void ShowRegistrationWizard() + { + PhotonEditor win = GetWindow(WindowType, false, CurrentLang.WindowTitle, true) as PhotonEditor; + win.photonSetupState = PhotonSetupStates.RegisterForPhotonCloud; + win.isSetupWizard = true; + } + + + // called 100 times / sec + private static void OnUpdate() + { + // after a compile, check RPCs to create a cache-list + if (!postCompileActionsDone && !EditorApplication.isCompiling && !EditorApplication.isPlayingOrWillChangePlaymode && PhotonNetwork.PhotonServerSettings != null) + { + #if UNITY_4_2 || UNITY_4_3 || UNITY_4_4 || UNITY_4_5 || UNITY_4_6 || UNITY_4_7 || UNITY_5 || UNITY_5_0 + if (EditorApplication.isUpdating) + { + return; + } + #endif + + PhotonEditor.UpdateRpcList(); + postCompileActionsDone = true; // on compile, this falls back to false (without actively doing anything) + + #if UNITY_4_2 || UNITY_4_3 || UNITY_4_4 || UNITY_4_5 || UNITY_4_6 || UNITY_4_7 || UNITY_5 || UNITY_5_0 + PhotonEditor.ImportWin8Support(); + #endif + } + } + + + // called in editor, opens wizard for initial setup, keeps scene PhotonViews up to date and closes connections when compiling (to avoid issues) + private static void EditorUpdate() + { + if (PhotonNetwork.PhotonServerSettings == null) + { + PhotonNetwork.CreateSettings(); + } + if (PhotonNetwork.PhotonServerSettings == null) + { + return; + } + + // serverSetting is null when the file gets deleted. otherwise, the wizard should only run once and only if hosting option is not (yet) set + if (!PhotonNetwork.PhotonServerSettings.DisableAutoOpenWizard && PhotonNetwork.PhotonServerSettings.HostType == ServerSettings.HostingOption.NotSet) + { + ShowRegistrationWizard(); + PhotonNetwork.PhotonServerSettings.DisableAutoOpenWizard = true; + PhotonEditor.SaveSettings(); + } + + // Workaround for TCP crash. Plus this surpresses any other recompile errors. + if (EditorApplication.isCompiling) + { + if (PhotonNetwork.connected) + { + if (lastWarning > EditorApplication.timeSinceStartup - 3) + { + // Prevent error spam + Debug.LogWarning(CurrentLang.WarningPhotonDisconnect); + lastWarning = EditorApplication.timeSinceStartup; + } + + PhotonNetwork.Disconnect(); + } + } + } + + + // called in editor on change of play-mode (used to show a message popup that connection settings are incomplete) + private static void PlaymodeStateChanged() + { + if (EditorApplication.isPlaying || !EditorApplication.isPlayingOrWillChangePlaymode) + { + return; + } + + if (PhotonNetwork.PhotonServerSettings.HostType == ServerSettings.HostingOption.NotSet) + { + EditorUtility.DisplayDialog(CurrentLang.SetupWizardWarningTitle, CurrentLang.SetupWizardWarningMessage, CurrentLang.OkButton); + } + } + + + #region GUI and Wizard + + // Window Update() callback. On-demand, when Window is open + protected void Update() + { + if (this.close) + { + Close(); + } + } + + protected virtual void OnGUI() + { + if (BackgroundImage == null) + { + BackgroundImage = AssetDatabase.LoadAssetAtPath("Assets/Photon Unity Networking/Editor/PhotonNetwork/background.jpg", typeof(Texture2D)) as Texture2D; + } + + PhotonSetupStates oldGuiState = this.photonSetupState; // used to fix an annoying Editor input field issue: wont refresh until focus is changed. + + GUI.SetNextControlName(""); + this.scrollPos = GUILayout.BeginScrollView(this.scrollPos); + + + if (this.photonSetupState == PhotonSetupStates.MainUi) + { + UiMainWizard(); + } + else + { + UiSetupApp(); + } + + + GUILayout.EndScrollView(); + + if (oldGuiState != this.photonSetupState) + { + GUI.FocusControl(""); + } + } + + + protected virtual void UiSetupApp() + { + GUI.skin.label.wordWrap = true; + if (!this.isSetupWizard) + { + GUILayout.BeginHorizontal(); + GUILayout.FlexibleSpace(); + if (GUILayout.Button(CurrentLang.MainMenuButton, GUILayout.ExpandWidth(false))) + { + this.photonSetupState = PhotonSetupStates.MainUi; + } + + GUILayout.EndHorizontal(); + } + + + // setup header + UiTitleBox(CurrentLang.SetupWizardTitle, BackgroundImage); + + // setup info text + GUI.skin.label.richText = true; + GUILayout.Label(CurrentLang.SetupWizardInfo); + + // input of appid or mail + EditorGUILayout.Separator(); + GUILayout.Label(CurrentLang.EmailOrAppIdLabel); + this.mailOrAppId = EditorGUILayout.TextField(this.mailOrAppId).Trim(); // note: we trim all input + + if (this.mailOrAppId.Contains("@")) + { + // this should be a mail address + this.minimumInput = (this.mailOrAppId.Length >= 5 && this.mailOrAppId.Contains(".")); + this.useMail = this.minimumInput; + this.useAppId = false; + } + else + { + // this should be an appId + this.minimumInput = ServerSettings.IsAppId(this.mailOrAppId); + this.useMail = false; + this.useAppId = this.minimumInput; + } + + // button to skip setup + GUILayout.BeginHorizontal(); + GUILayout.FlexibleSpace(); + if (GUILayout.Button(CurrentLang.SkipButton, GUILayout.Width(100))) + { + this.photonSetupState = PhotonSetupStates.GoEditPhotonServerSettings; + this.useSkip = true; + this.useMail = false; + this.useAppId = false; + } + + // SETUP button + EditorGUI.BeginDisabledGroup(!this.minimumInput); + if (GUILayout.Button(CurrentLang.SetupButton, GUILayout.Width(100))) + { + this.useSkip = false; + GUIUtility.keyboardControl = 0; + if (this.useMail) + { + RegisterWithEmail(this.mailOrAppId); // sets state + } + if (this.useAppId) + { + this.photonSetupState = PhotonSetupStates.GoEditPhotonServerSettings; + Undo.RecordObject(PhotonNetwork.PhotonServerSettings, "Update PhotonServerSettings for PUN"); + PhotonNetwork.PhotonServerSettings.UseCloud(this.mailOrAppId); + PhotonEditor.SaveSettings(); + } + } + EditorGUI.EndDisabledGroup(); + GUILayout.FlexibleSpace(); + GUILayout.EndHorizontal(); + + + // existing account needs to fetch AppId online + if (this.photonSetupState == PhotonSetupStates.EmailAlreadyRegistered) + { + // button to open dashboard and get the AppId + GUILayout.Space(15); + GUILayout.Label(CurrentLang.AlreadyRegisteredInfo); + + + GUILayout.BeginHorizontal(); + GUILayout.FlexibleSpace(); + if (GUILayout.Button(new GUIContent(CurrentLang.OpenCloudDashboardText, CurrentLang.OpenCloudDashboardTooltip), GUILayout.Width(205))) + { + Application.OpenURL(UrlCloudDashboard + Uri.EscapeUriString(this.mailOrAppId)); + this.mailOrAppId = ""; + } + GUILayout.FlexibleSpace(); + GUILayout.EndHorizontal(); + } + + + if (this.photonSetupState == PhotonSetupStates.GoEditPhotonServerSettings) + { + if (!this.highlightedSettings) + { + this.highlightedSettings = true; + HighlightSettings(); + } + + GUILayout.Space(15); + if (this.useSkip) + { + GUILayout.Label(CurrentLang.SkipRegistrationInfo); + } + else if (this.useMail) + { + GUILayout.Label(CurrentLang.RegisteredNewAccountInfo); + } + else if (this.useAppId) + { + GUILayout.Label(CurrentLang.AppliedToSettingsInfo); + } + + + // setup-complete info + GUILayout.Space(15); + GUILayout.Label(CurrentLang.SetupCompleteInfo); + + + // close window (done) + GUILayout.BeginHorizontal(); + GUILayout.FlexibleSpace(); + if (GUILayout.Button(CurrentLang.CloseWindowButton, GUILayout.Width(205))) + { + this.close = true; + } + GUILayout.FlexibleSpace(); + GUILayout.EndHorizontal(); + } + GUI.skin.label.richText = false; + } + + private void UiTitleBox(string title, Texture2D bgIcon) + { + GUIStyle bgStyle = new GUIStyle(GUI.skin.GetStyle("Label")); + bgStyle.normal.background = bgIcon; + bgStyle.fontSize = 22; + bgStyle.fontStyle = FontStyle.Bold; + + EditorGUILayout.BeginHorizontal(); + GUILayout.FlexibleSpace(); + EditorGUILayout.EndHorizontal(); + Rect scale = GUILayoutUtility.GetLastRect(); + scale.height = 30; + + GUI.Label(scale, title, bgStyle); + GUILayout.Space(scale.height+5); + } + + protected virtual void UiMainWizard() + { + GUILayout.Space(15); + + // title + UiTitleBox(CurrentLang.PUNWizardLabel, BackgroundImage); + + // wizard info text + GUILayout.Label(CurrentLang.WizardMainWindowInfo); + GUILayout.Space(15); + + + // pun+ info + if (isPunPlus) + { + GUILayout.Label(CurrentLang.MobilePunPlusExportNoteLabel); + GUILayout.Space(15); + } +#if !(UNITY_5_0 || UNITY_5) + else if (!InternalEditorUtility.HasAdvancedLicenseOnBuildTarget(BuildTarget.Android) || !InternalEditorUtility.HasAdvancedLicenseOnBuildTarget(BuildTarget.iPhone)) + { + GUILayout.Label(CurrentLang.MobileExportNoteLabel); + GUILayout.Space(15); + } +#endif + + // settings button + GUILayout.BeginHorizontal(); + GUILayout.Label(CurrentLang.SettingsButton, EditorStyles.boldLabel, GUILayout.Width(100)); + GUILayout.BeginVertical(); + if (GUILayout.Button(new GUIContent(CurrentLang.LocateSettingsButton, CurrentLang.SettingsHighlightLabel))) + { + HighlightSettings(); + } + if (GUILayout.Button(new GUIContent(CurrentLang.OpenCloudDashboardText, CurrentLang.OpenCloudDashboardTooltip))) + { + Application.OpenURL(UrlCloudDashboard + Uri.EscapeUriString(this.mailOrAppId)); + } + if (GUILayout.Button(new GUIContent(CurrentLang.SetupButton, CurrentLang.SetupServerCloudLabel))) + { + this.photonSetupState = PhotonSetupStates.RegisterForPhotonCloud; + } + GUILayout.EndVertical(); + GUILayout.EndHorizontal(); + GUILayout.Space(15); + + + EditorGUILayout.Separator(); + + + // documentation + GUILayout.BeginHorizontal(); + GUILayout.Label(CurrentLang.DocumentationLabel, EditorStyles.boldLabel, GUILayout.Width(100)); + GUILayout.BeginVertical(); + if (GUILayout.Button(new GUIContent(CurrentLang.OpenPDFText, CurrentLang.OpenPDFTooltip))) + { + EditorUtility.OpenWithDefaultApp(DocumentationLocation); + } + + if (GUILayout.Button(new GUIContent(CurrentLang.OpenDevNetText, CurrentLang.OpenDevNetTooltip))) + { + Application.OpenURL(UrlDevNet); + } + + GUI.skin.label.wordWrap = true; + GUILayout.Label(CurrentLang.OwnHostCloudCompareLabel); + if (GUILayout.Button(CurrentLang.ComparisonPageButton)) + { + Application.OpenURL(UrlCompare); + } + + + if (GUILayout.Button(new GUIContent(CurrentLang.OpenForumText, CurrentLang.OpenForumTooltip))) + { + Application.OpenURL(UrlForum); + } + + GUILayout.EndVertical(); + GUILayout.EndHorizontal(); + } + + #endregion + + + protected virtual void RegisterWithEmail(string email) + { + EditorUtility.DisplayProgressBar(CurrentLang.ConnectionTitle, CurrentLang.ConnectionInfo, 0.5f); + + string accountServiceType = string.Empty; + if (PhotonEditorUtils.HasVoice) + { + accountServiceType = "voice"; + } + + + AccountService client = new AccountService(); + client.RegisterByEmail(email, RegisterOrigin, accountServiceType); // this is the synchronous variant using the static RegisterOrigin. "result" is in the client + + EditorUtility.ClearProgressBar(); + if (client.ReturnCode == 0) + { + this.mailOrAppId = client.AppId; + PhotonNetwork.PhotonServerSettings.UseCloud(this.mailOrAppId, 0); + if (PhotonEditorUtils.HasVoice) + { + PhotonNetwork.PhotonServerSettings.VoiceAppID = client.AppId2; + } + PhotonEditor.SaveSettings(); + + this.photonSetupState = PhotonSetupStates.GoEditPhotonServerSettings; + } + else + { + PhotonNetwork.PhotonServerSettings.HostType = ServerSettings.HostingOption.PhotonCloud; + PhotonEditor.SaveSettings(); + + Debug.LogWarning(client.Message + " ReturnCode: " + client.ReturnCode); + if (client.Message.Contains("registered")) + { + this.photonSetupState = PhotonSetupStates.EmailAlreadyRegistered; + } + else + { + EditorUtility.DisplayDialog(CurrentLang.ErrorTextTitle, client.Message, CurrentLang.OkButton); + this.photonSetupState = PhotonSetupStates.RegisterForPhotonCloud; + } + } + } + + + protected internal static bool CheckPunPlus() + { + androidLibExists = File.Exists("Assets/Plugins/Android/armeabi-v7a/libPhotonSocketPlugin.so") && + File.Exists("Assets/Plugins/Android/x86/libPhotonSocketPlugin.so"); + + + iphoneLibExists = File.Exists("Assets/Plugins/IOS/libPhotonSocketPlugin.a"); + + isPunPlus = androidLibExists || iphoneLibExists; + return isPunPlus; + } + + + private static void ImportWin8Support() + { + if (EditorApplication.isCompiling || EditorApplication.isPlayingOrWillChangePlaymode) + { + return; // don't import while compiling + } + + #if UNITY_4_2 || UNITY_4_3 || UNITY_4_4 || UNITY_4_5 || UNITY_4_6 || UNITY_4_7 || UNITY_5 || UNITY_5_0 + const string win8Package = "Assets/Plugins/Photon3Unity3D-Win8.unitypackage"; + + bool win8LibsExist = File.Exists("Assets/Plugins/WP8/Photon3Unity3D.dll") && File.Exists("Assets/Plugins/Metro/Photon3Unity3D.dll"); + if (!win8LibsExist && File.Exists(win8Package)) + { + AssetDatabase.ImportPackage(win8Package, false); + } + #endif + } + + + // Pings PhotonServerSettings and makes it selected (show in Inspector) + private static void HighlightSettings() + { + Selection.objects = new UnityEngine.Object[] { PhotonNetwork.PhotonServerSettings }; + EditorGUIUtility.PingObject(PhotonNetwork.PhotonServerSettings); + } + + + // Marks settings object as dirty, so it gets saved. + // unity 5.3 changes the usecase for SetDirty(). but here we don't modify a scene object! so it's ok to use + private static void SaveSettings() + { + EditorUtility.SetDirty(PhotonNetwork.PhotonServerSettings); + } + + + #region RPC List Handling + + public static void UpdateRpcList() + { + List additionalRpcs = new List(); + HashSet currentRpcs = new HashSet(); + + var types = GetAllSubTypesInScripts(typeof(MonoBehaviour)); + + int countOldRpcs = 0; + foreach (var mono in types) + { + MethodInfo[] methods = mono.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); + + foreach (MethodInfo method in methods) + { + bool isOldRpc = false; + #pragma warning disable 618 + // we let the Editor check for outdated RPC attributes in code. that should not cause a compile warning + if (method.IsDefined(typeof (RPC), false)) + { + countOldRpcs++; + isOldRpc = true; + } + #pragma warning restore 618 + + if (isOldRpc || method.IsDefined(typeof(PunRPC), false)) + { + currentRpcs.Add(method.Name); + + if (!additionalRpcs.Contains(method.Name) && !PhotonNetwork.PhotonServerSettings.RpcList.Contains(method.Name)) + { + additionalRpcs.Add(method.Name); + } + } + } + } + + if (additionalRpcs.Count > 0) + { + // LIMITS RPC COUNT + if (additionalRpcs.Count + PhotonNetwork.PhotonServerSettings.RpcList.Count >= byte.MaxValue) + { + if (currentRpcs.Count <= byte.MaxValue) + { + bool clearList = EditorUtility.DisplayDialog(CurrentLang.IncorrectRPCListTitle, CurrentLang.IncorrectRPCListLabel, CurrentLang.RemoveOutdatedRPCsLabel, CurrentLang.CancelButton); + if (clearList) + { + PhotonNetwork.PhotonServerSettings.RpcList.Clear(); + PhotonNetwork.PhotonServerSettings.RpcList.AddRange(currentRpcs); + } + else + { + return; + } + } + else + { + EditorUtility.DisplayDialog(CurrentLang.FullRPCListTitle, CurrentLang.FullRPCListLabel, CurrentLang.SkipRPCListUpdateLabel); + return; + } + } + + additionalRpcs.Sort(); + Undo.RecordObject(PhotonNetwork.PhotonServerSettings, "Update PUN RPC-list"); + PhotonNetwork.PhotonServerSettings.RpcList.AddRange(additionalRpcs); + PhotonEditor.SaveSettings(); + } + + if (countOldRpcs > 0) + { + bool convertRPCs = EditorUtility.DisplayDialog(CurrentLang.RpcFoundDialogTitle, CurrentLang.RpcFoundMessage, CurrentLang.RpcReplaceButton, CurrentLang.RpcSkipReplace); + if (convertRPCs) + { + PhotonConverter.ConvertRpcAttribute(""); + } + } + } + + public static void ClearRpcList() + { + bool clearList = EditorUtility.DisplayDialog(CurrentLang.PUNNameReplaceTitle, CurrentLang.PUNNameReplaceLabel, CurrentLang.RPCListCleared, CurrentLang.CancelButton); + if (clearList) + { + PhotonNetwork.PhotonServerSettings.RpcList.Clear(); + Debug.LogWarning(CurrentLang.ServerSettingsCleanedWarning); + } + } + + public static System.Type[] GetAllSubTypesInScripts(System.Type aBaseClass) + { + var result = new System.Collections.Generic.List(); + System.Reflection.Assembly[] AS = System.AppDomain.CurrentDomain.GetAssemblies(); + foreach (var A in AS) + { + // this skips all but the Unity-scripted assemblies for RPC-list creation. You could remove this to search all assemblies in project + if (!A.FullName.StartsWith("Assembly-")) + { + // Debug.Log("Skipping Assembly: " + A); + continue; + } + + //Debug.Log("Assembly: " + A.FullName); + System.Type[] types = A.GetTypes(); + foreach (var T in types) + { + if (T.IsSubclassOf(aBaseClass)) + { + result.Add(T); + } + } + } + return result.ToArray(); + } + + #endregion + +} \ No newline at end of file diff --git a/Assets/Photon Unity Networking/Editor/PhotonNetwork/PhotonEditor.cs.meta b/Assets/Photon Unity Networking/Editor/PhotonNetwork/PhotonEditor.cs.meta new file mode 100644 index 0000000..beda65a --- /dev/null +++ b/Assets/Photon Unity Networking/Editor/PhotonNetwork/PhotonEditor.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: dabbbed2a74eac44dac281f20d706ba8 +labels: +- ExitGames +- PUN +- Photon +- Networking +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} diff --git a/Assets/Photon Unity Networking/Editor/PhotonNetwork/PhotonEditorUtils.cs b/Assets/Photon Unity Networking/Editor/PhotonNetwork/PhotonEditorUtils.cs new file mode 100644 index 0000000..17e85f1 --- /dev/null +++ b/Assets/Photon Unity Networking/Editor/PhotonNetwork/PhotonEditorUtils.cs @@ -0,0 +1,70 @@ +// ---------------------------------------------------------------------------- +// +// PhotonNetwork Framework for Unity - Copyright (C) 2011 Exit Games GmbH +// +// +// Unity Editor Utils +// +// developer@exitgames.com +// ---------------------------------------------------------------------------- + +using System; +using System.Collections.Generic; +using System.Linq; +using UnityEditor; + + +namespace ExitGames.Client.Photon +{ + [InitializeOnLoad] + public class PhotonEditorUtils + { + /// True if the ChatClient of the Photon Chat API is available. If so, the editor may (e.g.) show additional options in settings. + public static bool HasChat; + /// True if the VoiceClient of the Photon Voice API is available. If so, the editor may (e.g.) show additional options in settings. + public static bool HasVoice; + /// True if the PhotonEditorUtils checked the available products / APIs. If so, the editor may (e.g.) show additional options in settings. + public static bool HasCheckedProducts; + + static PhotonEditorUtils() + { + HasVoice = Type.GetType("ExitGames.Client.Photon.Voice.VoiceClient, Assembly-CSharp") != null || Type.GetType("ExitGames.Client.Photon.Voice.VoiceClient, Assembly-CSharp-firstpass") != null; + HasChat = Type.GetType("ExitGames.Client.Photon.Chat.ChatClient, Assembly-CSharp") != null || Type.GetType("ExitGames.Client.Photon.Chat.ChatClient, Assembly-CSharp-firstpass") != null; + PhotonEditorUtils.HasCheckedProducts = true; + } + + + public static void MountScriptingDefineSymbolToAllTargets(string defineSymbol) + { + foreach (BuildTargetGroup _group in Enum.GetValues(typeof(BuildTargetGroup))) + { + if (_group == BuildTargetGroup.Unknown) continue; + + List _defineSymbols = PlayerSettings.GetScriptingDefineSymbolsForGroup(_group).Split(';').Select(d => d.Trim()).ToList(); + + if (!_defineSymbols.Contains(defineSymbol)) + { + _defineSymbols.Add(defineSymbol); + PlayerSettings.SetScriptingDefineSymbolsForGroup(_group, string.Join(";", _defineSymbols.ToArray())); + } + } + } + + public static void UnMountScriptingDefineSymbolToAllTargets(string defineSymbol) + { + foreach (BuildTargetGroup _group in Enum.GetValues(typeof(BuildTargetGroup))) + { + if (_group == BuildTargetGroup.Unknown) continue; + + List _defineSymbols = PlayerSettings.GetScriptingDefineSymbolsForGroup(_group).Split(';').Select(d => d.Trim()).ToList(); + + if (_defineSymbols.Contains(defineSymbol)) + { + _defineSymbols.Remove(defineSymbol); + PlayerSettings.SetScriptingDefineSymbolsForGroup(_group, string.Join(";", _defineSymbols.ToArray())); + } + } + } + + } +} diff --git a/Assets/Photon Unity Networking/Editor/PhotonNetwork/PhotonEditorUtils.cs.meta b/Assets/Photon Unity Networking/Editor/PhotonNetwork/PhotonEditorUtils.cs.meta new file mode 100644 index 0000000..130b4d0 --- /dev/null +++ b/Assets/Photon Unity Networking/Editor/PhotonNetwork/PhotonEditorUtils.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 42183086715e14a19a573546af09b321 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Photon Unity Networking/Editor/PhotonNetwork/PhotonGUI.cs b/Assets/Photon Unity Networking/Editor/PhotonNetwork/PhotonGUI.cs new file mode 100644 index 0000000..e236915 --- /dev/null +++ b/Assets/Photon Unity Networking/Editor/PhotonNetwork/PhotonGUI.cs @@ -0,0 +1,281 @@ +using UnityEngine; +using UnityEditor; +using System.Collections; + +using Photon.Pun; + +public class PhotonGUI +{ + #region Styles + static GUIStyle m_DefaultTitleStyle; + public static GUIStyle DefaultTitleStyle + { + get + { + if( m_DefaultTitleStyle == null ) + { + m_DefaultTitleStyle = new GUIStyle(); + m_DefaultTitleStyle.border = new RectOffset( 2, 2, 2, 1 ); + m_DefaultTitleStyle.margin = new RectOffset( 5, 5, 5, 0 ); + m_DefaultTitleStyle.padding = new RectOffset( 5, 5, 0, 0 ); + m_DefaultTitleStyle.alignment = TextAnchor.MiddleLeft; + m_DefaultTitleStyle.normal.background = ReorderableListResources.texTitleBackground; + m_DefaultTitleStyle.normal.textColor = EditorGUIUtility.isProSkin + ? new Color( 0.8f, 0.8f, 0.8f ) + : new Color( 0.2f, 0.2f, 0.2f ); + } + + return m_DefaultTitleStyle; + } + } + + static GUIStyle m_DefaultContainerStyle; + public static GUIStyle DefaultContainerStyle + { + get + { + if( m_DefaultContainerStyle == null ) + { + m_DefaultContainerStyle = new GUIStyle(); + m_DefaultContainerStyle.border = new RectOffset( 2, 2, 1, 2 ); + m_DefaultContainerStyle.margin = new RectOffset( 5, 5, 5, 5 ); + m_DefaultContainerStyle.padding = new RectOffset( 1, 1, 2, 2 ); + m_DefaultContainerStyle.normal.background = ReorderableListResources.texContainerBackground; + } + + return m_DefaultContainerStyle; + } + } + + static GUIStyle m_DefaultAddButtonStyle; + public static GUIStyle DefaultAddButtonStyle + { + get + { + if( m_DefaultAddButtonStyle == null ) + { + m_DefaultAddButtonStyle = new GUIStyle(); + m_DefaultAddButtonStyle.fixedWidth = 30; + m_DefaultAddButtonStyle.fixedHeight = 16; + m_DefaultAddButtonStyle.normal.background = ReorderableListResources.texAddButton; + m_DefaultAddButtonStyle.active.background = ReorderableListResources.texAddButtonActive; + } + + return m_DefaultAddButtonStyle; + } + } + + static GUIStyle m_DefaultRemoveButtonStyle; + public static GUIStyle DefaultRemoveButtonStyle + { + get + { + if( m_DefaultRemoveButtonStyle == null ) + { + m_DefaultRemoveButtonStyle = new GUIStyle(); + m_DefaultRemoveButtonStyle.fixedWidth = 30; + m_DefaultRemoveButtonStyle.fixedHeight = 20; + m_DefaultRemoveButtonStyle.active.background = ReorderableListResources.CreatePixelTexture( "Dark Pixel (List GUI)", new Color32( 18, 18, 18, 255 ) ); + m_DefaultRemoveButtonStyle.imagePosition = ImagePosition.ImageOnly; + m_DefaultRemoveButtonStyle.alignment = TextAnchor.MiddleCenter; + } + + return m_DefaultRemoveButtonStyle; + } + } + + static GUIStyle m_DefaultContainerRowStyle; + public static GUIStyle DefaultContainerRowStyle + { + get + { + if( m_DefaultContainerRowStyle == null ) + { + m_DefaultContainerRowStyle = new GUIStyle(); + m_DefaultContainerRowStyle.border = new RectOffset( 2, 2, 2, 2 ); + + m_DefaultContainerRowStyle.margin = new RectOffset( 5, 5, 5, 5 ); + m_DefaultContainerRowStyle.padding = new RectOffset( 1, 1, 2, 2 ); + m_DefaultContainerRowStyle.normal.background = ReorderableListResources.texContainerBackground; + } + + return m_DefaultContainerRowStyle; + } + } + + static GUIStyle m_FoldoutBold; + public static GUIStyle FoldoutBold + { + get + { + if( m_FoldoutBold == null ) + { + m_FoldoutBold = new GUIStyle( EditorStyles.foldout ); + m_FoldoutBold.fontStyle = FontStyle.Bold; + } + + return m_FoldoutBold; + } + } + + static GUIStyle m_RichLabel; + public static GUIStyle RichLabel + { + get + { + if( m_RichLabel == null ) + { + m_RichLabel = new GUIStyle( GUI.skin.label ); + m_RichLabel.richText = true; + m_RichLabel.wordWrap = true; + } + + return m_RichLabel; + } + } + #endregion + + static Texture2D m_HelpIcon; + public static Texture2D HelpIcon + { + get + { + if( m_HelpIcon == null ) + { + m_HelpIcon = AssetDatabase.LoadAssetAtPath( "Assets/Photon Unity Networking/Editor/PhotonNetwork/help.png", typeof( Texture2D ) ) as Texture2D; + } + + return m_HelpIcon; + } + } + + #region Interface + public static void ContainerHeader( string headline ) + { + DoContainerHeader( headline, 27, 0 ); + } + + public static bool ContainerHeaderToggle( string headline, bool toggle ) + { + return DoContainerHeaderToggle( headline, toggle ); + } + + public static bool ContainerHeaderFoldout( string headline, bool foldout ) + { + return DoContainerHeaderFoldout( headline, foldout ); + } + + public static Rect ContainerBody( float height ) + { + return DoContainerBody( height ); + } + + public static bool AddButton() + { + Rect controlRect = EditorGUILayout.GetControlRect( false, DefaultAddButtonStyle.fixedHeight - 5 ); + controlRect.yMin -= 5; + controlRect.yMax -= 5; + + Rect addButtonRect = new Rect( controlRect.xMax - DefaultAddButtonStyle.fixedWidth, + controlRect.yMin, + DefaultAddButtonStyle.fixedWidth, + DefaultAddButtonStyle.fixedHeight ); + + return GUI.Button( addButtonRect, "", DefaultAddButtonStyle ); + } + + public static void DrawSplitter( Rect position ) + { + ReorderableListResources.DrawTexture( position, ReorderableListResources.texItemSplitter ); + } + + public static void DrawGizmoOptions( + Rect position, + string label, + SerializedProperty gizmoEnabledProperty, + SerializedProperty gizmoColorProperty, + SerializedProperty gizmoTypeProperty, + SerializedProperty gizmoSizeProperty ) + { + float height = EditorGUIUtility.singleLineHeight; + float flexibleWidth = Mathf.Max( 40, position.width - EditorGUIUtility.labelWidth - 20 - 75 - 5 - 40 - 5 ); + + Rect labelRect = new Rect( position.xMin, position.yMin, EditorGUIUtility.labelWidth, height ); + GUI.Label( labelRect, label ); + + Rect enabledRect = new Rect( labelRect.xMax, labelRect.yMin, 20, height ); + EditorGUI.PropertyField( enabledRect, gizmoEnabledProperty, GUIContent.none ); + + bool oldGUIEnabled = GUI.enabled; + GUI.enabled = gizmoEnabledProperty.boolValue; + + Rect colorRect = new Rect( enabledRect.xMax + 5, labelRect.yMin, 70, height ); + EditorGUI.PropertyField( colorRect, gizmoColorProperty, GUIContent.none ); + + Rect typeRect = new Rect( colorRect.xMax + 5, labelRect.yMin, flexibleWidth * 0.7f, height ); + EditorGUI.PropertyField( typeRect, gizmoTypeProperty, GUIContent.none ); + + Rect sizeLabelRect = new Rect( typeRect.xMax + 10, labelRect.yMin, 30, height ); + GUI.Label( sizeLabelRect, "Size" ); + + Rect sizeRect = new Rect( sizeLabelRect.xMax + 5, labelRect.yMin, flexibleWidth * 0.3f, height ); + EditorGUI.PropertyField( sizeRect, gizmoSizeProperty, GUIContent.none ); + + GUI.enabled = oldGUIEnabled; + } + + #endregion + + #region Implementation + static Rect DoContainerBody( float height ) + { + Rect controlRect = EditorGUILayout.GetControlRect( false, height ); + controlRect.yMin -= 3; + controlRect.yMax -= 2; + + int controlID = GUIUtility.GetControlID( FocusType.Passive, controlRect ); + + if( Event.current.type == EventType.Repaint ) + { + PhotonGUI.DefaultContainerStyle.Draw( controlRect, GUIContent.none, controlID ); + } + + return controlRect; + } + + static bool DoContainerHeaderToggle( string headline, bool toggle ) + { + Rect rect = DoContainerHeader( headline, 27, 15 ); + Rect toggleRect = new Rect( rect.xMin + 5, rect.yMin + 5, EditorGUIUtility.labelWidth, rect.height ); + + return EditorGUI.Toggle( toggleRect, toggle ); + } + + + static bool DoContainerHeaderFoldout( string headline, bool foldout ) + { + Rect rect = DoContainerHeader( "", 27, 0f ); + Rect foldoutRect = new Rect( rect.xMin + 15, rect.yMin + 5, rect.width, rect.height ); + + return EditorGUI.Foldout( foldoutRect, foldout, headline, FoldoutBold ); + } + + static Rect DoContainerHeader( string headline, float height, float contentOffset ) + { + GUILayout.Space( 5 ); + Rect controlRect = EditorGUILayout.GetControlRect( false, height ); + + int controlID = GUIUtility.GetControlID( FocusType.Passive, controlRect ); + + if( Event.current.type == EventType.Repaint ) + { + PhotonGUI.DefaultTitleStyle.Draw( controlRect, GUIContent.none, controlID ); + + Rect labelRect = new Rect( controlRect.xMin + 5 + contentOffset, controlRect.yMin + 5, controlRect.width, controlRect.height ); + GUI.Label( labelRect, headline, EditorStyles.boldLabel ); + } + + return controlRect; + } + #endregion +} diff --git a/Assets/Photon Unity Networking/Editor/PhotonNetwork/PhotonGUI.cs.meta b/Assets/Photon Unity Networking/Editor/PhotonNetwork/PhotonGUI.cs.meta new file mode 100644 index 0000000..247a4eb --- /dev/null +++ b/Assets/Photon Unity Networking/Editor/PhotonNetwork/PhotonGUI.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 3d2cadb1ccf05074e8ce96b1393846cf +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Photon Unity Networking/Editor/PhotonNetwork/PhotonViewHandler.cs b/Assets/Photon Unity Networking/Editor/PhotonNetwork/PhotonViewHandler.cs new file mode 100644 index 0000000..0fa60b3 --- /dev/null +++ b/Assets/Photon Unity Networking/Editor/PhotonNetwork/PhotonViewHandler.cs @@ -0,0 +1,193 @@ +#if UNITY_5 && !UNITY_5_0 && !UNITY_5_1 && !UNITY_5_2 +#define UNITY_MIN_5_3 +#endif + +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using UnityEditor; +using UnityEngine; +using System.Collections; +using Debug = UnityEngine.Debug; +using UnityEditor.SceneManagement; + +[InitializeOnLoad] +public class PhotonViewHandler : EditorWindow +{ + private static bool CheckSceneForStuckHandlers = true; + + static PhotonViewHandler() + { + // hierarchyWindowChanged is called on hierarchy changed and on save. It's even called when hierarchy-window is closed and if a prefab with instances is changed. + // this is not called when you edit a instance's value but: on save + EditorApplication.hierarchyWindowChanged += HierarchyChange; + } + + // this method corrects the IDs for photonviews in the scene and in prefabs + // make sure prefabs always use viewID 0 + // make sure instances never use a owner + // this is a editor class that should only run if not playing + internal static void HierarchyChange() + { + if (Application.isPlaying) + { + //Debug.Log("HierarchyChange ignored, while running."); + CheckSceneForStuckHandlers = true; // done once AFTER play mode. + return; + } + + if (CheckSceneForStuckHandlers) + { + CheckSceneForStuckHandlers = false; + PhotonNetwork.InternalCleanPhotonMonoFromSceneIfStuck(); + } + + HashSet pvInstances = new HashSet(); + HashSet usedInstanceViewNumbers = new HashSet(); + bool fixedSomeId = false; + + //// the following code would be an option if we only checked scene objects (but we can check all PVs) + //PhotonView[] pvObjects = GameObject.FindSceneObjectsOfType(typeof(PhotonView)) as PhotonView[]; + //Debug.Log("HierarchyChange. PV Count: " + pvObjects.Length); + + string levelName = SceneManagerHelper.ActiveSceneName; + #if UNITY_EDITOR + levelName = SceneManagerHelper.EditorActiveSceneName; + #endif + int minViewIdInThisScene = PunSceneSettings.MinViewIdForScene(levelName); + //Debug.Log("Level '" + Application.loadedLevelName + "' has a minimum ViewId of: " + minViewIdInThisScene); + + PhotonView[] pvObjects = Resources.FindObjectsOfTypeAll(typeof(PhotonView)) as PhotonView[]; + + foreach (PhotonView view in pvObjects) + { + // first pass: fix prefabs to viewID 0 if they got a view number assigned (cause they should not have one!) + if (EditorUtility.IsPersistent(view.gameObject)) + { + if (view.viewID != 0 || view.prefixBackup != -1 || view.instantiationId != -1) + { + Debug.LogWarning("PhotonView on persistent object being fixed (id and prefix must be 0). Was: " + view); + view.viewID = 0; + view.prefixBackup = -1; + view.instantiationId = -1; + EditorUtility.SetDirty(view); // even in Unity 5.3+ it's OK to SetDirty() for non-scene objects. + fixedSomeId = true; + } + } + else + { + // keep all scene-instanced PVs for later re-check + pvInstances.Add(view); + } + } + + Dictionary idPerObject = new Dictionary(); + + // second pass: check all used-in-scene viewIDs for duplicate viewIDs (only checking anything non-prefab) + // scene-PVs must have user == 0 (scene/room) and a subId != 0 + foreach (PhotonView view in pvInstances) + { + if (view.ownerId > 0) + { + Debug.Log("Re-Setting Owner ID of: " + view); + } + view.ownerId = 0; // simply make sure no owner is set (cause room always uses 0) + view.prefix = -1; // TODO: prefix could be settable via inspector per scene?! + + if (view.viewID != 0) + { + if (view.viewID < minViewIdInThisScene || usedInstanceViewNumbers.Contains(view.viewID)) + { + view.viewID = 0; // avoid duplicates and negative values by assigning 0 as (temporary) number to be fixed in next pass + } + else + { + usedInstanceViewNumbers.Add(view.viewID); // builds a list of currently used viewIDs + + int instId = 0; + if (idPerObject.TryGetValue(view.gameObject, out instId)) + { + view.instantiationId = instId; + } + else + { + view.instantiationId = view.viewID; + idPerObject[view.gameObject] = view.instantiationId; + } + } + } + + } + + // third pass: anything that's now 0 must get a new (not yet used) ID (starting at 0) + int lastUsedId = (minViewIdInThisScene > 0) ? minViewIdInThisScene - 1 : 0; + + foreach (PhotonView view in pvInstances) + { + if (view.viewID == 0) + { + Undo.RecordObject(view, "Automatic viewID change for: "+view.gameObject.name); + + // Debug.LogWarning("setting scene ID: " + view.gameObject.name + " ID: " + view.subId.ID + " scene ID: " + view.GetSceneID() + " IsPersistent: " + EditorUtility.IsPersistent(view.gameObject) + " IsSceneViewIDFree: " + IsSceneViewIDFree(view.subId.ID, view)); + int nextViewId = PhotonViewHandler.GetID(lastUsedId, usedInstanceViewNumbers); + + view.viewID = nextViewId; + + int instId = 0; + if (idPerObject.TryGetValue(view.gameObject, out instId)) + { + view.instantiationId = instId; + } + else + { + view.instantiationId = view.viewID; + idPerObject[view.gameObject] = nextViewId; + } + + lastUsedId = nextViewId; + fixedSomeId = true; + + #if !UNITY_MIN_5_3 + EditorUtility.SetDirty(view); + #endif + } + } + + + if (fixedSomeId) + { + //Debug.LogWarning("Some subId was adjusted."); // this log is only interesting for Exit Games + } + } + + // TODO fail if no ID was available anymore + // TODO look up lower numbers if offset hits max?! + public static int GetID(int idOffset, HashSet usedInstanceViewNumbers) + { + while (idOffset < PhotonNetwork.MAX_VIEW_IDS) + { + idOffset++; + if (!usedInstanceViewNumbers.Contains(idOffset)) + { + break; + } + } + + return idOffset; + } + + //TODO: check if this can be internal protected (as source in editor AND as dll) + public static void LoadAllScenesToFix() + { + string[] scenes = System.IO.Directory.GetFiles(".", "*.unity", SearchOption.AllDirectories); + + foreach (string scene in scenes) + { + EditorSceneManager.OpenScene(scene); + PhotonViewHandler.HierarchyChange();//NOTE: most likely on load also triggers a hierarchy change + EditorSceneManager.SaveOpenScenes(); + } + + Debug.Log("Corrected scene views where needed."); + } +} diff --git a/Assets/Photon Unity Networking/Editor/PhotonNetwork/PhotonViewHandler.cs.meta b/Assets/Photon Unity Networking/Editor/PhotonNetwork/PhotonViewHandler.cs.meta new file mode 100644 index 0000000..74dfe3f --- /dev/null +++ b/Assets/Photon Unity Networking/Editor/PhotonNetwork/PhotonViewHandler.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 57b538e62a0ca6248bfd354def935e57 +labels: +- ExitGames +- PUN +- Photon +- Networking +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} diff --git a/Assets/Photon Unity Networking/Editor/PhotonNetwork/PhotonViewInspector.cs b/Assets/Photon Unity Networking/Editor/PhotonNetwork/PhotonViewInspector.cs new file mode 100644 index 0000000..a8eb3aa --- /dev/null +++ b/Assets/Photon Unity Networking/Editor/PhotonNetwork/PhotonViewInspector.cs @@ -0,0 +1,276 @@ +// ---------------------------------------------------------------------------- +// +// PhotonNetwork Framework for Unity - Copyright (C) 2011 Exit Games GmbH +// +// +// Custom inspector for the PhotonView component. +// +// developer@exitgames.com +// ---------------------------------------------------------------------------- + +#if UNITY_5 && !UNITY_5_0 && !UNITY_5_1 && !UNITY_5_2 +#define UNITY_MIN_5_3 +#endif + + +using System; +using UnityEditor; +using UnityEngine; + +using Photon.Pun; + + +[CustomEditor(typeof (PhotonView))] +public class PhotonViewInspector : Editor +{ + private PhotonView m_Target; + + public override void OnInspectorGUI() + { + this.m_Target = (PhotonView)target; + bool isProjectPrefab = EditorUtility.IsPersistent(this.m_Target.gameObject); + + if (this.m_Target.ObservedComponents == null) + { + this.m_Target.ObservedComponents = new System.Collections.Generic.List(); + } + + if (this.m_Target.ObservedComponents.Count == 0) + { + this.m_Target.ObservedComponents.Add(null); + } + + EditorGUILayout.BeginHorizontal(); + // Owner + if (isProjectPrefab) + { + EditorGUILayout.LabelField("Owner:", "Set at runtime"); + } + else if (!this.m_Target.isOwnerActive) + { + EditorGUILayout.LabelField("Owner", "Scene"); + } + else + { + PhotonPlayer owner = this.m_Target.owner; + string ownerInfo = (owner != null) ? owner.NickName : ""; + + if (string.IsNullOrEmpty(ownerInfo)) + { + ownerInfo = ""; + } + + EditorGUILayout.LabelField("Owner", "[" + this.m_Target.ownerId + "] " + ownerInfo); + } + + // ownership requests + EditorGUI.BeginDisabledGroup(Application.isPlaying); + OwnershipOption own = (OwnershipOption)EditorGUILayout.EnumPopup(this.m_Target.ownershipTransfer, GUILayout.Width(100)); + if (own != this.m_Target.ownershipTransfer) + { + // jf: fixed 5 and up prefab not accepting changes if you quit Unity straight after change. + // not touching the define nor the rest of the code to avoid bringing more problem than solving. + EditorUtility.SetDirty(this.m_Target); + + Undo.RecordObject(this.m_Target, "Change PhotonView Ownership Transfer"); + this.m_Target.ownershipTransfer = own; + } + EditorGUI.EndDisabledGroup(); + + EditorGUILayout.EndHorizontal(); + + + // View ID + if (isProjectPrefab) + { + EditorGUILayout.LabelField("View ID", "Set at runtime"); + } + else if (EditorApplication.isPlaying) + { + EditorGUILayout.LabelField("View ID", this.m_Target.viewID.ToString()); + } + else + { + int idValue = EditorGUILayout.IntField("View ID [1.." + (PhotonNetwork.MAX_VIEW_IDS - 1) + "]", this.m_Target.viewID); + if (this.m_Target.viewID != idValue) + { + Undo.RecordObject(this.m_Target, "Change PhotonView viewID"); + this.m_Target.viewID = idValue; + } + } + + // Locally Controlled + if (EditorApplication.isPlaying) + { + string masterClientHint = PhotonNetwork.isMasterClient ? "(master)" : ""; + EditorGUILayout.Toggle("Controlled locally: " + masterClientHint, this.m_Target.isMine); + } + + // ViewSynchronization (reliability) + if (this.m_Target.synchronization == ViewSynchronization.Off) + { + GUI.color = Color.grey; + } + + EditorGUILayout.PropertyField(serializedObject.FindProperty("synchronization"), new GUIContent("Observe option:")); + + if (this.m_Target.synchronization != ViewSynchronization.Off && this.m_Target.ObservedComponents.FindAll(item => item != null).Count == 0) + { + GUILayout.BeginVertical(GUI.skin.box); + GUILayout.Label("Warning", EditorStyles.boldLabel); + GUILayout.Label("Setting the synchronization option only makes sense if you observe something."); + GUILayout.EndVertical(); + } + + DrawSpecificTypeSerializationOptions(); + + GUI.color = Color.white; + DrawObservedComponentsList(); + + // Cleanup: save and fix look + if (GUI.changed) + { + #if !UNITY_MIN_5_3 + EditorUtility.SetDirty(this.m_Target); + #endif + PhotonViewHandler.HierarchyChange(); // TODO: check if needed + } + + GUI.color = Color.white; + #if !UNITY_MIN_5_3 + EditorGUIUtility.LookLikeControls(); + #endif + } + + private void DrawSpecificTypeSerializationOptions() + { + if (this.m_Target.ObservedComponents.FindAll(item => item != null && item.GetType() == typeof (Transform)).Count > 0) + { + this.m_Target.onSerializeTransformOption = (OnSerializeTransform)EditorGUILayout.EnumPopup("Transform Serialization:", this.m_Target.onSerializeTransformOption); + } + else if (this.m_Target.ObservedComponents.FindAll(item => item != null && item.GetType() == typeof (Rigidbody)).Count > 0 || + this.m_Target.ObservedComponents.FindAll(item => item != null && item.GetType() == typeof (Rigidbody2D)).Count > 0) + { + this.m_Target.onSerializeRigidBodyOption = (OnSerializeRigidBody)EditorGUILayout.EnumPopup("Rigidbody Serialization:", this.m_Target.onSerializeRigidBodyOption); + } + } + + + private int GetObservedComponentsCount() + { + int count = 0; + + for (int i = 0; i < this.m_Target.ObservedComponents.Count; ++i) + { + if (this.m_Target.ObservedComponents[i] != null) + { + count++; + } + } + + return count; + } + + private void DrawObservedComponentsList() + { + GUILayout.Space(5); + SerializedProperty listProperty = serializedObject.FindProperty("ObservedComponents"); + + if (listProperty == null) + { + return; + } + + float containerElementHeight = 22; + float containerHeight = listProperty.arraySize*containerElementHeight; + + bool isOpen = PhotonGUI.ContainerHeaderFoldout("Observed Components (" + GetObservedComponentsCount() + ")", serializedObject.FindProperty("ObservedComponentsFoldoutOpen").boolValue); + serializedObject.FindProperty("ObservedComponentsFoldoutOpen").boolValue = isOpen; + + if (isOpen == false) + { + containerHeight = 0; + } + + //Texture2D statsIcon = AssetDatabase.LoadAssetAtPath( "Assets/Photon Unity Networking/Editor/PhotonNetwork/PhotonViewStats.png", typeof( Texture2D ) ) as Texture2D; + + Rect containerRect = PhotonGUI.ContainerBody(containerHeight); + bool wasObservedComponentsEmpty = this.m_Target.ObservedComponents.FindAll(item => item != null).Count == 0; + if (isOpen == true) + { + for (int i = 0; i < listProperty.arraySize; ++i) + { + Rect elementRect = new Rect(containerRect.xMin, containerRect.yMin + containerElementHeight*i, containerRect.width, containerElementHeight); + { + Rect texturePosition = new Rect(elementRect.xMin + 6, elementRect.yMin + elementRect.height/2f - 1, 9, 5); + ReorderableListResources.DrawTexture(texturePosition, ReorderableListResources.texGrabHandle); + + Rect propertyPosition = new Rect(elementRect.xMin + 20, elementRect.yMin + 3, elementRect.width - 45, 16); + EditorGUI.PropertyField(propertyPosition, listProperty.GetArrayElementAtIndex(i), new GUIContent()); + + //Debug.Log( listProperty.GetArrayElementAtIndex( i ).objectReferenceValue.GetType() ); + //Rect statsPosition = new Rect( propertyPosition.xMax + 7, propertyPosition.yMin, statsIcon.width, statsIcon.height ); + //ReorderableListResources.DrawTexture( statsPosition, statsIcon ); + + Rect removeButtonRect = new Rect(elementRect.xMax - PhotonGUI.DefaultRemoveButtonStyle.fixedWidth, + elementRect.yMin + 2, + PhotonGUI.DefaultRemoveButtonStyle.fixedWidth, + PhotonGUI.DefaultRemoveButtonStyle.fixedHeight); + + GUI.enabled = listProperty.arraySize > 1; + if (GUI.Button(removeButtonRect, new GUIContent(ReorderableListResources.texRemoveButton), PhotonGUI.DefaultRemoveButtonStyle)) + { + listProperty.DeleteArrayElementAtIndex(i); + } + GUI.enabled = true; + + if (i < listProperty.arraySize - 1) + { + texturePosition = new Rect(elementRect.xMin + 2, elementRect.yMax, elementRect.width - 4, 1); + PhotonGUI.DrawSplitter(texturePosition); + } + } + } + } + + if (PhotonGUI.AddButton()) + { + listProperty.InsertArrayElementAtIndex(Mathf.Max(0, listProperty.arraySize - 1)); + } + + serializedObject.ApplyModifiedProperties(); + + bool isObservedComponentsEmpty = this.m_Target.ObservedComponents.FindAll(item => item != null).Count == 0; + + if (wasObservedComponentsEmpty == true && isObservedComponentsEmpty == false && this.m_Target.synchronization == ViewSynchronization.Off) + { + Undo.RecordObject(this.m_Target, "Change PhotonView"); + this.m_Target.synchronization = ViewSynchronization.UnreliableOnChange; + #if !UNITY_MIN_5_3 + EditorUtility.SetDirty(this.m_Target); + #endif + serializedObject.Update(); + } + + if (wasObservedComponentsEmpty == false && isObservedComponentsEmpty == true) + { + Undo.RecordObject(this.m_Target, "Change PhotonView"); + this.m_Target.synchronization = ViewSynchronization.Off; + #if !UNITY_MIN_5_3 + EditorUtility.SetDirty(this.m_Target); + #endif + serializedObject.Update(); + } + } + + private static GameObject GetPrefabParent(GameObject mp) + { + #if UNITY_2_6_1 || UNITY_2_6 || UNITY_3_0 || UNITY_3_0_0 || UNITY_3_1 || UNITY_3_2 || UNITY_3_3 || UNITY_3_4 + // Unity 3.4 and older use EditorUtility + return (EditorUtility.GetPrefabParent(mp) as GameObject); + #else + // Unity 3.5 uses PrefabUtility + return PrefabUtility.GetPrefabParent(mp) as GameObject; + #endif + } +} \ No newline at end of file diff --git a/Assets/Photon Unity Networking/Editor/PhotonNetwork/PhotonViewInspector.cs.meta b/Assets/Photon Unity Networking/Editor/PhotonNetwork/PhotonViewInspector.cs.meta new file mode 100644 index 0000000..200b1ee --- /dev/null +++ b/Assets/Photon Unity Networking/Editor/PhotonNetwork/PhotonViewInspector.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: e73a30c46df19194f873ea7a9ce12753 +labels: +- ExitGames +- PUN +- Photon +- Networking +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} diff --git a/Assets/Photon Unity Networking/Editor/PhotonNetwork/PunSceneSettings.cs b/Assets/Photon Unity Networking/Editor/PhotonNetwork/PunSceneSettings.cs new file mode 100644 index 0000000..4a67fae --- /dev/null +++ b/Assets/Photon Unity Networking/Editor/PhotonNetwork/PunSceneSettings.cs @@ -0,0 +1,93 @@ +using System; +using System.Collections.Generic; +using System.IO; +using UnityEditor; +using UnityEngine; + +[Serializable] +public class SceneSetting +{ + public string sceneName; + public int minViewId; +} + +public class PunSceneSettings : ScriptableObject +{ + [SerializeField] public List MinViewIdPerScene = new List(); + + private const string SceneSettingsFileName = "PunSceneSettingsFile.asset"; + + // we use the path to PunSceneSettings.cs as path to create a scene settings file + private static string punSceneSettingsCsPath; + public static string PunSceneSettingsCsPath + { + get + { + if (!string.IsNullOrEmpty(punSceneSettingsCsPath)) + { + return punSceneSettingsCsPath; + } + + // Unity 4.3.4 does not yet have AssetDatabase.FindAssets(). Would be easier. + var result = Directory.GetFiles(Application.dataPath, "PunSceneSettings.cs", SearchOption.AllDirectories); + if (result.Length >= 1) + { + punSceneSettingsCsPath = Path.GetDirectoryName(result[0]); + punSceneSettingsCsPath = punSceneSettingsCsPath.Replace('\\', '/'); + punSceneSettingsCsPath = punSceneSettingsCsPath.Replace(Application.dataPath, "Assets"); + + // AssetDatabase paths have to use '/' and are relative to the project's folder. Always. + punSceneSettingsCsPath = punSceneSettingsCsPath + "/" + SceneSettingsFileName; + } + + return punSceneSettingsCsPath; + } + } + + + private static PunSceneSettings instanceField; + public static PunSceneSettings Instance + { + get + { + if (instanceField != null) + { + return instanceField; + } + + instanceField = (PunSceneSettings)AssetDatabase.LoadAssetAtPath(PunSceneSettingsCsPath, typeof(PunSceneSettings)); + if (instanceField == null) + { + instanceField = ScriptableObject.CreateInstance(); + AssetDatabase.CreateAsset(instanceField, PunSceneSettingsCsPath); + } + + return instanceField; + } + } + + + public static int MinViewIdForScene(string scene) + { + if (string.IsNullOrEmpty(scene)) + { + return 0; + } + + PunSceneSettings pss = Instance; + if (pss == null) + { + Debug.LogError("pss cant be null"); + return 0; + } + + foreach (SceneSetting setting in pss.MinViewIdPerScene) + { + if (setting.sceneName.Equals(scene)) + { + return setting.minViewId; + } + } + return 0; + } +} \ No newline at end of file diff --git a/Assets/Photon Unity Networking/Editor/PhotonNetwork/PunSceneSettings.cs.meta b/Assets/Photon Unity Networking/Editor/PhotonNetwork/PunSceneSettings.cs.meta new file mode 100644 index 0000000..065e2d8 --- /dev/null +++ b/Assets/Photon Unity Networking/Editor/PhotonNetwork/PunSceneSettings.cs.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: fc3284eace5a64d4bb516df7d7effdb9 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} diff --git a/Assets/Photon Unity Networking/Editor/PhotonNetwork/PunSceneSettingsFile.asset b/Assets/Photon Unity Networking/Editor/PhotonNetwork/PunSceneSettingsFile.asset new file mode 100644 index 0000000..075cd61 Binary files /dev/null and b/Assets/Photon Unity Networking/Editor/PhotonNetwork/PunSceneSettingsFile.asset differ diff --git a/Assets/Photon Unity Networking/Editor/PhotonNetwork/PunSceneSettingsFile.asset.meta b/Assets/Photon Unity Networking/Editor/PhotonNetwork/PunSceneSettingsFile.asset.meta new file mode 100644 index 0000000..5125fa9 --- /dev/null +++ b/Assets/Photon Unity Networking/Editor/PhotonNetwork/PunSceneSettingsFile.asset.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: d0aacb83307022d449e90a09d28222ae diff --git a/Assets/Photon Unity Networking/Editor/PhotonNetwork/ReorderableListResources.cs b/Assets/Photon Unity Networking/Editor/PhotonNetwork/ReorderableListResources.cs new file mode 100644 index 0000000..72b9d7d --- /dev/null +++ b/Assets/Photon Unity Networking/Editor/PhotonNetwork/ReorderableListResources.cs @@ -0,0 +1,237 @@ +// Copyright (c) 2012-2013 Rotorz Limited. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +using UnityEngine; +using UnityEditor; + +using System; + +namespace Photon.Pun +{ + + /// + /// Resources to assist with reorderable list control. + /// + internal static class ReorderableListResources + { + + static ReorderableListResources() + { + GenerateSpecialTextures(); + LoadResourceAssets(); + } + + #region Texture Resources + + private enum ResourceName + { + add_button = 0, + add_button_active, + container_background, + grab_handle, + remove_button, + remove_button_active, + title_background, + } + + /// + /// Resource assets for light skin. + /// + /// + /// Resource assets are PNG images which have been encoded using a base-64 + /// string so that actual asset files are not necessary. + /// + private static string[] s_LightSkin = { + "iVBORw0KGgoAAAANSUhEUgAAAB4AAAAQCAYAAAABOs/SAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAZdEVYdFNvZnR3YXJlAEFkb2JlIEltYWdlUmVhZHlxyWU8AAAAW0lEQVRIS+3NywnAQAhF0anI4mzVCmzBBl7QEBgGE5JFhBAXd+OHM5gZZgYRKcktNxu+HRFF2e6qhtOjtQM7K/tZ+xY89wSbazg9eqOfw6oag4rcChjY8coAjA2l1RxFDY8IFAAAAABJRU5ErkJggg==", + "iVBORw0KGgoAAAANSUhEUgAAAB4AAAAQCAYAAAABOs/SAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAGlJREFUeNpiFBER+f/jxw8GNjY2BnqAX79+MXBwcDAwMQwQGHoWnzp1CoxHjo8pBSykBi8+MTMzs2HmY2QfwXxKii9HExdZgNwgHuFB/efPH7pZCLOL8f///wyioqL/6enbL1++MAIEGABvGSLA+9GPZwAAAABJRU5ErkJggg==", + "iVBORw0KGgoAAAANSUhEUgAAAAUAAAAECAYAAABGM/VAAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAZdEVYdFNvZnR3YXJlAEFkb2JlIEltYWdlUmVhZHlxyWU8AAAAMElEQVQYV2P4//8/Q1FR0X8YBvHBAp8+ffp/+fJlMA3igwUfPnwIFgDRYEFM7f8ZAG1EOYL9INrfAAAAAElFTkSuQmCC", + "iVBORw0KGgoAAAANSUhEUgAAAAkAAAAFCAYAAACXU8ZrAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAZdEVYdFNvZnR3YXJlAEFkb2JlIEltYWdlUmVhZHlxyWU8AAAAIElEQVQYV2P49OnTf0KYobCw8D8hzPD/P2FMLesK/wMAs5yJpK+6aN4AAAAASUVORK5CYII=", + "iVBORw0KGgoAAAANSUhEUgAAAAgAAAACCAIAAADq9gq6AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAABVJREFUeNpiVFZWZsAGmBhwAIAAAwAURgBt4C03ZwAAAABJRU5ErkJggg==", + "iVBORw0KGgoAAAANSUhEUgAAAAgAAAACCAIAAADq9gq6AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAABVJREFUeNpivHPnDgM2wMSAAwAEGAB8VgKYlvqkBwAAAABJRU5ErkJggg==", + "iVBORw0KGgoAAAANSUhEUgAAAAUAAAAECAYAAABGM/VAAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAEFJREFUeNpi/P//P0NxcfF/BgRgZP78+fN/VVVVhpCQEAZjY2OGs2fPNrCApBwdHRkePHgAVwoWnDVrFgMyAAgwAAt4E1dCq1obAAAAAElFTkSuQmCC" + }; + /// + /// Resource assets for dark skin. + /// + /// + /// Resource assets are PNG images which have been encoded using a base-64 + /// string so that actual asset files are not necessary. + /// + private static string[] s_DarkSkin = { + "iVBORw0KGgoAAAANSUhEUgAAAB4AAAAQCAYAAAABOs/SAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAIBJREFUeNpiVFZW/u/i4sLw4sULBnoACQkJhj179jAwMQwQGHoWl5aWgvHI8TGlgIXU4MUn1t3dPcx8HB8fD2cvXLgQQ0xHR4c2FmMzmBTLhl5QYwt2cn1MtsXkWjg4gvrt27fgWoMeAGQXCDD+//+fQUVF5T89fXvnzh1GgAADAFmSI1Ed3FqgAAAAAElFTkSuQmCC", + "iVBORw0KGgoAAAANSUhEUgAAAB4AAAAQCAYAAAABOs/SAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAHlJREFUeNpiFBER+f/jxw8GNjY2BnqAX79+MXBwcDAwMQwQGHoWv3nzBoxHjo8pBSykBi8+MWAOGWY+5uLigrO/ffuGIYbMppnF5Fg2tFM1yKfk+pbkoKZGEA+OVP3nzx+6WQizi/H///8MoqKi/+np2y9fvjACBBgAoTYjgvihfz0AAAAASUVORK5CYII=", + "iVBORw0KGgoAAAANSUhEUgAAAAUAAAAECAYAAABGM/VAAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAD1JREFUeNpi/P//P4OKisp/Bii4c+cOIwtIwMXFheHFixcMEhISYAVMINm3b9+CBUA0CDCiazc0NGQECDAAdH0YelA27kgAAAAASUVORK5CYII=", + "iVBORw0KGgoAAAANSUhEUgAAAAkAAAAFCAYAAACXU8ZrAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAACRJREFUeNpizM3N/c9AADAqKysTVMTi5eXFSFAREFPHOoAAAwBCfwcAO8g48QAAAABJRU5ErkJggg==", + "iVBORw0KGgoAAAANSUhEUgAAAAgAAAAECAYAAACzzX7wAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAACJJREFUeNpi/P//PwM+wHL06FG8KpgYCABGZWVlvCYABBgA7/sHvGw+cz8AAAAASUVORK5CYII=", + "iVBORw0KGgoAAAANSUhEUgAAAAgAAAAECAYAAACzzX7wAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAACBJREFUeNpi/P//PwM+wPKfgAomBgKAhYuLC68CgAADAAxjByOjCHIRAAAAAElFTkSuQmCC", + "iVBORw0KGgoAAAANSUhEUgAAAAUAAAAECAYAAABGM/VAAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAADtJREFUeNpi/P//P4OKisp/Bii4c+cOIwtIQE9Pj+HLly9gQRCfBcQACbx69QqmmAEseO/ePQZkABBgAD04FXsmmijSAAAAAElFTkSuQmCC" + }; + + /// + /// Gets light or dark texture "add_button.png". + /// + public static Texture2D texAddButton + { + get { return s_Cached[ (int)ResourceName.add_button ]; } + } + /// + /// Gets light or dark texture "add_button_active.png". + /// + public static Texture2D texAddButtonActive + { + get { return s_Cached[ (int)ResourceName.add_button_active ]; } + } + /// + /// Gets light or dark texture "container_background.png". + /// + public static Texture2D texContainerBackground + { + get { return s_Cached[ (int)ResourceName.container_background ]; } + } + /// + /// Gets light or dark texture "grab_handle.png". + /// + public static Texture2D texGrabHandle + { + get { return s_Cached[ (int)ResourceName.grab_handle ]; } + } + /// + /// Gets light or dark texture "remove_button.png". + /// + public static Texture2D texRemoveButton + { + get { return s_Cached[ (int)ResourceName.remove_button ]; } + } + /// + /// Gets light or dark texture "remove_button_active.png". + /// + public static Texture2D texRemoveButtonActive + { + get { return s_Cached[ (int)ResourceName.remove_button_active ]; } + } + /// + /// Gets light or dark texture "title_background.png". + /// + public static Texture2D texTitleBackground + { + get { return s_Cached[ (int)ResourceName.title_background ]; } + } + + #endregion + + #region Generated Resources + + public static Texture2D texItemSplitter { get; private set; } + + /// + /// Generate special textures. + /// + private static void GenerateSpecialTextures() + { + var splitterColor = EditorGUIUtility.isProSkin + ? new Color( 1f, 1f, 1f, 0.14f ) + : new Color( 0.59f, 0.59f, 0.59f, 0.55f ) + ; + texItemSplitter = CreatePixelTexture( "(Generated) Item Splitter", splitterColor ); + } + + /// + /// Create 1x1 pixel texture of specified color. + /// + /// Name for texture object. + /// Pixel color. + /// + /// The new Texture2D instance. + /// + public static Texture2D CreatePixelTexture( string name, Color color ) + { + var tex = new Texture2D( 1, 1, TextureFormat.ARGB32, false, true ); + tex.name = name; + tex.hideFlags = HideFlags.HideAndDontSave; + tex.filterMode = FilterMode.Point; + tex.SetPixel( 0, 0, color ); + tex.Apply(); + return tex; + } + + #endregion + + #region Load PNG from Base-64 Encoded String + + private static Texture2D[] s_Cached; + + /// + /// Read textures from base-64 encoded strings. Automatically selects assets based + /// upon whether the light or dark (pro) skin is active. + /// + private static void LoadResourceAssets() + { + var skin = EditorGUIUtility.isProSkin ? s_DarkSkin : s_LightSkin; + s_Cached = new Texture2D[ skin.Length ]; + + for( int i = 0; i < s_Cached.Length; ++i ) + { + // Get image data (PNG) from base64 encoded strings. + byte[] imageData = Convert.FromBase64String( skin[ i ] ); + + // Gather image size from image data. + int texWidth, texHeight; + GetImageSize( imageData, out texWidth, out texHeight ); + + // Generate texture asset. + var tex = new Texture2D( texWidth, texHeight, TextureFormat.ARGB32, false, true ); + tex.hideFlags = HideFlags.HideAndDontSave; + tex.name = "(Generated) ReorderableList:" + i; + tex.filterMode = FilterMode.Point; + tex.LoadImage( imageData ); + + s_Cached[ i ] = tex; + } + + s_LightSkin = null; + s_DarkSkin = null; + } + + /// + /// Read width and height if PNG file in pixels. + /// + /// PNG image data. + /// Width of image in pixels. + /// Height of image in pixels. + private static void GetImageSize( byte[] imageData, out int width, out int height ) + { + width = ReadInt( imageData, 3 + 15 ); + height = ReadInt( imageData, 3 + 15 + 2 + 2 ); + } + + private static int ReadInt( byte[] imageData, int offset ) + { + return ( imageData[ offset ] << 8 ) | imageData[ offset + 1 ]; + } + + #endregion + + #region GUI Helper + private static GUIStyle s_TempStyle = new GUIStyle(); + + /// + /// Draw texture using to workaround bug in Unity where + /// flickers when embedded inside a property drawer. + /// + /// Position of which to draw texture in space of GUI. + /// Texture. + public static void DrawTexture( Rect position, Texture2D texture ) + { + if( Event.current.type != EventType.Repaint ) + return; + + s_TempStyle.normal.background = texture; + + s_TempStyle.Draw( position, GUIContent.none, false, false, false, false ); + } + #endregion + + } + +} \ No newline at end of file diff --git a/Assets/Photon Unity Networking/Editor/PhotonNetwork/ReorderableListResources.cs.meta b/Assets/Photon Unity Networking/Editor/PhotonNetwork/ReorderableListResources.cs.meta new file mode 100644 index 0000000..7f43a21 --- /dev/null +++ b/Assets/Photon Unity Networking/Editor/PhotonNetwork/ReorderableListResources.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 60c609ded101b0a468fb5cf27b31cf27 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Photon Unity Networking/Editor/PhotonNetwork/ServerSettingsInspector.cs b/Assets/Photon Unity Networking/Editor/PhotonNetwork/ServerSettingsInspector.cs new file mode 100644 index 0000000..84378e7 --- /dev/null +++ b/Assets/Photon Unity Networking/Editor/PhotonNetwork/ServerSettingsInspector.cs @@ -0,0 +1,358 @@ +// ---------------------------------------------------------------------------- +// +// PhotonNetwork Framework for Unity - Copyright (C) 2016 Exit Games GmbH +// +// +// This is a custom editor for the ServerSettings scriptable object. +// +// developer@exitgames.com +// ---------------------------------------------------------------------------- + +using System; +using ExitGames.Client.Photon; +using UnityEditor; +using UnityEngine; + + +[CustomEditor(typeof (ServerSettings))] +public class ServerSettingsInspector : Editor +{ + // has to be extended when rHTTP becomes available + public enum ProtocolChoices + { + Udp = ConnectionProtocol.Udp, + Tcp = ConnectionProtocol.Tcp + } + + + private bool showMustHaveRegion; + private CloudRegionCode lastUsedRegion; + private ServerConnection lastServer; + + + [ExecuteInEditMode] + public void OnEnable() + { + this.lastUsedRegion = ServerSettings.BestRegionCodeInPreferences; + EditorApplication.update += this.OnUpdate; + } + + + public void OnDisable() + { + EditorApplication.update -= this.OnUpdate; + } + + + private void OnUpdate() + { + if (this.lastUsedRegion != ServerSettings.BestRegionCodeInPreferences) + { + this.lastUsedRegion = ServerSettings.BestRegionCodeInPreferences; + Repaint(); + } + // this won't repaint when we disconnect but it's "good enough" to update when we connect and switch servers. + if (Application.isPlaying && this.lastServer != PhotonNetwork.Server) + { + this.lastServer = PhotonNetwork.Server; + Repaint(); + } + } + + + public override void OnInspectorGUI() + { + ServerSettings settings = (ServerSettings) target; + Undo.RecordObject(settings, "Edit PhotonServerSettings"); + settings.HostType = (ServerSettings.HostingOption) EditorGUILayout.EnumPopup("Hosting", settings.HostType); + EditorGUI.indentLevel = 1; + + switch (settings.HostType) + { + case ServerSettings.HostingOption.BestRegion: + case ServerSettings.HostingOption.PhotonCloud: + // region selection + if (settings.HostType == ServerSettings.HostingOption.PhotonCloud) + { + settings.PreferredRegion = (CloudRegionCode)EditorGUILayout.EnumPopup("Region", settings.PreferredRegion); + } + else + { + string _regionFeedback = "Prefs:"+ServerSettings.BestRegionCodeInPreferences.ToString(); + + // the NameServer does not have a region itself. it's global (although it has regional instances) + if (PhotonNetwork.connected && PhotonNetwork.Server != ServerConnection.NameServer) + { + _regionFeedback = "Current:" + PhotonNetwork.CloudRegion + " " + _regionFeedback; + } + + EditorGUILayout.BeginHorizontal (); + EditorGUILayout.PrefixLabel (" "); + Rect rect = GUILayoutUtility.GetRect(new GUIContent("_regionFeedback"),"Label"); + int indentLevel = EditorGUI.indentLevel; + EditorGUI.indentLevel = 0; + EditorGUI.LabelField (rect, _regionFeedback); + EditorGUI.indentLevel = indentLevel; + + rect.x += rect.width-39; + rect.width = 39; + + rect.height -=2; + if (GUI.Button(rect,"Reset",EditorStyles.miniButton)) + { + ServerSettings.ResetBestRegionCodeInPreferences(); + } + EditorGUILayout.EndHorizontal (); + + + + CloudRegionFlag valRegions = (CloudRegionFlag)EditorGUILayout.EnumMaskField("Enabled Regions", settings.EnabledRegions); + + if (valRegions != settings.EnabledRegions) + { + settings.EnabledRegions = valRegions; + this.showMustHaveRegion = valRegions == 0; + } + if (this.showMustHaveRegion) + { + EditorGUILayout.HelpBox("You should enable at least two regions for 'Best Region' hosting.", MessageType.Warning); + } + + + + + } + + // appid + string valAppId = EditorGUILayout.TextField("AppId", settings.AppID); + if (valAppId != settings.AppID) + { + settings.AppID = valAppId.Trim(); + } + if (!ServerSettings.IsAppId(settings.AppID)) + { + EditorGUILayout.HelpBox("PUN needs an AppId (GUID).\nFind it online in the Dashboard.", MessageType.Warning); + } + + // protocol + ProtocolChoices valProtocol = settings.Protocol == ConnectionProtocol.Tcp ? ProtocolChoices.Tcp : ProtocolChoices.Udp; + valProtocol = (ProtocolChoices) EditorGUILayout.EnumPopup("Protocol", valProtocol); + settings.Protocol = (ConnectionProtocol) valProtocol; + #if UNITY_WEBGL + EditorGUILayout.HelpBox("WebGL always use Secure WebSockets as protocol.\nThis setting gets ignored in current export.", MessageType.Warning); + #endif + break; + + case ServerSettings.HostingOption.SelfHosted: + // address and port (depends on protocol below) + bool hidePort = false; + if (settings.Protocol == ConnectionProtocol.Udp && (settings.ServerPort == 4530 || settings.ServerPort == 0)) + { + settings.ServerPort = 5055; + } + else if (settings.Protocol == ConnectionProtocol.Tcp && (settings.ServerPort == 5055 || settings.ServerPort == 0)) + { + settings.ServerPort = 4530; + } + #if RHTTP + if (settings.Protocol == ConnectionProtocol.RHttp) + { + settings.ServerPort = 0; + hidePort = true; + } + #endif + settings.ServerAddress = EditorGUILayout.TextField("Server Address", settings.ServerAddress); + settings.ServerAddress = settings.ServerAddress.Trim(); + if (!hidePort) + { + settings.ServerPort = EditorGUILayout.IntField("Server Port", settings.ServerPort); + } + // protocol + valProtocol = settings.Protocol == ConnectionProtocol.Tcp ? ProtocolChoices.Tcp : ProtocolChoices.Udp; + valProtocol = (ProtocolChoices) EditorGUILayout.EnumPopup("Protocol", valProtocol); + settings.Protocol = (ConnectionProtocol) valProtocol; + #if UNITY_WEBGL + EditorGUILayout.HelpBox("WebGL always use Secure WebSockets as protocol.\nThis setting gets ignored in current export.", MessageType.Warning); + #endif + + // appid + settings.AppID = EditorGUILayout.TextField("AppId", settings.AppID); + settings.AppID = settings.AppID.Trim(); + break; + + case ServerSettings.HostingOption.OfflineMode: + EditorGUI.indentLevel = 0; + EditorGUILayout.HelpBox("In 'Offline Mode', the client does not communicate with a server.\nAll settings are hidden currently.", MessageType.Info); + break; + + case ServerSettings.HostingOption.NotSet: + EditorGUI.indentLevel = 0; + EditorGUILayout.HelpBox("Hosting is 'Not Set'.\nConnectUsingSettings() will not be able to connect.\nSelect another option or run the PUN Wizard.", MessageType.Info); + break; + + default: + DrawDefaultInspector(); + break; + } + + if (PhotonEditor.CheckPunPlus()) + { + settings.Protocol = ConnectionProtocol.Udp; + EditorGUILayout.HelpBox("You seem to use PUN+.\nPUN+ only supports reliable UDP so the protocol is locked.", MessageType.Info); + } + + + + // CHAT SETTINGS + if (PhotonEditorUtils.HasChat) + { + GUILayout.Space(5); + EditorGUI.indentLevel = 0; + EditorGUILayout.LabelField("Photon Chat Settings"); + EditorGUI.indentLevel = 1; + string valChatAppid = EditorGUILayout.TextField("Chat AppId", settings.ChatAppID); + if (valChatAppid != settings.ChatAppID) + { + settings.ChatAppID = valChatAppid.Trim(); + } + if (!ServerSettings.IsAppId(settings.ChatAppID)) + { + EditorGUILayout.HelpBox("Photon Chat needs an AppId (GUID).\nFind it online in the Dashboard.", MessageType.Warning); + } + + EditorGUI.indentLevel = 0; + } + + + + // VOICE SETTINGS + if (PhotonEditorUtils.HasVoice) + { + GUILayout.Space(5); + EditorGUI.indentLevel = 0; + EditorGUILayout.LabelField("Photon Voice Settings"); + EditorGUI.indentLevel = 1; + switch (settings.HostType) + { + case ServerSettings.HostingOption.BestRegion: + case ServerSettings.HostingOption.PhotonCloud: + // voice appid + string valVoiceAppId = EditorGUILayout.TextField("Voice AppId", settings.VoiceAppID); + if (valVoiceAppId != settings.VoiceAppID) + { + settings.VoiceAppID = valVoiceAppId.Trim(); + } + if (!ServerSettings.IsAppId(settings.VoiceAppID)) + { + EditorGUILayout.HelpBox("Photon Voice needs an AppId (GUID).\nFind it online in the Dashboard.", MessageType.Warning); + } + break; + case ServerSettings.HostingOption.SelfHosted: + if (settings.VoiceServerPort == 0) + { + settings.VoiceServerPort = 5055; + } + settings.VoiceServerPort = EditorGUILayout.IntField("Server Port UDP", settings.VoiceServerPort); + break; + case ServerSettings.HostingOption.OfflineMode: + case ServerSettings.HostingOption.NotSet: + break; + } + EditorGUI.indentLevel = 0; + } + + + + // PUN Client Settings + GUILayout.Space(5); + EditorGUI.indentLevel = 0; + EditorGUILayout.LabelField("Client Settings"); + EditorGUI.indentLevel = 1; + //EditorGUILayout.LabelField("game version"); + settings.JoinLobby = EditorGUILayout.Toggle("Auto-Join Lobby", settings.JoinLobby); + settings.EnableLobbyStatistics = EditorGUILayout.Toggle("Enable Lobby Stats", settings.EnableLobbyStatistics); + + // Pun Logging Level + PhotonLogLevel _PunLogging = (PhotonLogLevel)EditorGUILayout.EnumPopup("Pun Logging", settings.PunLogging); + if (EditorApplication.isPlaying && PhotonNetwork.logLevel!=_PunLogging) + { + PhotonNetwork.logLevel = _PunLogging; + } + settings.PunLogging = _PunLogging; + + // Network Logging Level + DebugLevel _DebugLevel = (DebugLevel)EditorGUILayout.EnumPopup("Network Logging", settings.NetworkLogging); + if (EditorApplication.isPlaying && settings.NetworkLogging!=_DebugLevel) + { + settings.NetworkLogging = _DebugLevel; + } + settings.NetworkLogging = _DebugLevel; + + + //EditorGUILayout.LabelField("automaticallySyncScene"); + //EditorGUILayout.LabelField("autoCleanUpPlayerObjects"); + //EditorGUILayout.LabelField("lobby stats"); + //EditorGUILayout.LabelField("sendrate / serialize rate"); + //EditorGUILayout.LabelField("quick resends"); + //EditorGUILayout.LabelField("max resends"); + //EditorGUILayout.LabelField("enable crc checking"); + + + // Application settings + GUILayout.Space(5); + EditorGUI.indentLevel = 0; + EditorGUILayout.LabelField("Build Settings"); + EditorGUI.indentLevel = 1; + + settings.RunInBackground = EditorGUILayout.Toggle("Run In Background", settings.RunInBackground); + + + // RPC-shortcut list + GUILayout.Space(5); + EditorGUI.indentLevel = 0; + SerializedObject sObj = new SerializedObject(target); + SerializedProperty sRpcs = sObj.FindProperty("RpcList"); + EditorGUILayout.PropertyField(sRpcs, true); + sObj.ApplyModifiedProperties(); + + GUILayout.BeginHorizontal(); + GUILayout.Space(20); + if (GUILayout.Button("Refresh RPCs")) + { + PhotonEditor.UpdateRpcList(); + Repaint(); + } + if (GUILayout.Button("Clear RPCs")) + { + PhotonEditor.ClearRpcList(); + } + if (GUILayout.Button("Log HashCode")) + { + Debug.Log("RPC-List HashCode: " + RpcListHashCode() + ". Make sure clients that send each other RPCs have the same RPC-List."); + } + GUILayout.Space(20); + GUILayout.EndHorizontal(); + + + //SerializedProperty sp = serializedObject.FindProperty("RpcList"); + //EditorGUILayout.PropertyField(sp, true); + + if (GUI.changed) + { + EditorUtility.SetDirty(target); // even in Unity 5.3+ it's OK to SetDirty() for non-scene objects. + } + } + + private int RpcListHashCode() + { + // this is a hashcode generated to (more) easily compare this Editor's RPC List with some other + int hashCode = PhotonNetwork.PhotonServerSettings.RpcList.Count + 1; + foreach (string s in PhotonNetwork.PhotonServerSettings.RpcList) + { + int h1 = s.GetHashCode(); + hashCode = ((h1 << 5) + h1) ^ hashCode; + } + + return hashCode; + } +} \ No newline at end of file diff --git a/Assets/Photon Unity Networking/Editor/PhotonNetwork/ServerSettingsInspector.cs.meta b/Assets/Photon Unity Networking/Editor/PhotonNetwork/ServerSettingsInspector.cs.meta new file mode 100644 index 0000000..d9f769d --- /dev/null +++ b/Assets/Photon Unity Networking/Editor/PhotonNetwork/ServerSettingsInspector.cs.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 21239ba77ac4b534f958e8617ef13ede +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} diff --git a/Assets/Photon Unity Networking/Editor/PhotonNetwork/Views.meta b/Assets/Photon Unity Networking/Editor/PhotonNetwork/Views.meta new file mode 100644 index 0000000..39971e2 --- /dev/null +++ b/Assets/Photon Unity Networking/Editor/PhotonNetwork/Views.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: d8d209f4e3be44a2283f92e39173b833 +folderAsset: yes +timeCreated: 1501014812 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Photon Unity Networking/Editor/PhotonNetwork/Views/PhotonAnimatorViewEditor.cs b/Assets/Photon Unity Networking/Editor/PhotonNetwork/Views/PhotonAnimatorViewEditor.cs new file mode 100644 index 0000000..1a0c6a9 --- /dev/null +++ b/Assets/Photon Unity Networking/Editor/PhotonNetwork/Views/PhotonAnimatorViewEditor.cs @@ -0,0 +1,349 @@ +// ---------------------------------------------------------------------------- +// +// PhotonNetwork Framework for Unity - Copyright (C) 2016 Exit Games GmbH +// +// +// This is a custom editor for the AnimatorView component. +// +// developer@exitgames.com +// ---------------------------------------------------------------------------- + + +#if UNITY_5 && !UNITY_5_0 && !UNITY_5_1 && !UNITY_5_2 +#define UNITY_MIN_5_3 +#endif + + +using UnityEditor; +using UnityEngine; +using System.Collections.Generic; + +#if UNITY_4_0 || UNITY_4_0_1 || UNITY_4_1 || UNITY_4_2 || UNITY_4_3 || UNITY_4_5 || UNITY_4_6 || UNITY_4_7 +using UnityEditorInternal; +#elif UNITY_5 || UNITY_5_0 || UNITY_2017 +using UnityEditor.Animations; +#endif + +[CustomEditor(typeof (PhotonAnimatorView))] +public class PhotonAnimatorViewEditor : Editor +{ + private Animator m_Animator; + private PhotonAnimatorView m_Target; + + #if UNITY_4_0 || UNITY_4_0_1 || UNITY_4_1 || UNITY_4_2 || UNITY_4_3 || UNITY_4_5 || UNITY_4_6 || UNITY_4_7 || UNITY_5 || UNITY_5_0 || UNITY_2017 + private AnimatorController m_Controller; +#endif + + private const string TRIGGER_HELP_URL = "https://doc.photonengine.com/en-us/pun/current/manuals-and-demos/animatorviewtriggerhelp/"; + + public override void OnInspectorGUI() + { + //base.OnInspectorGUI(); + + if (this.m_Animator == null) + { + GUILayout.BeginVertical(GUI.skin.box); + GUILayout.Label("GameObject doesn't have an Animator component to synchronize"); + GUILayout.EndVertical(); + return; + } + + DrawWeightInspector(); + + if (GetLayerCount() == 0) + { + GUILayout.BeginVertical(GUI.skin.box); + GUILayout.Label("Animator doesn't have any layers setup to synchronize"); + GUILayout.EndVertical(); + } + + DrawParameterInspector(); + + if (GetParameterCount() == 0) + { + GUILayout.BeginVertical(GUI.skin.box); + GUILayout.Label("Animator doesn't have any parameters setup to synchronize"); + GUILayout.EndVertical(); + } + + serializedObject.ApplyModifiedProperties(); + + //GUILayout.Label( "m_SynchronizeLayers " + serializedObject.FindProperty( "m_SynchronizeLayers" ).arraySize ); + //GUILayout.Label( "m_SynchronizeParameters " + serializedObject.FindProperty( "m_SynchronizeParameters" ).arraySize ); + } + + + private int GetLayerCount() + { + #if UNITY_5 || UNITY_5_0 || UNITY_2017 + return (this.m_Controller == null) ? 0 : this.m_Controller.layers.Length; + #else + return (this.m_Controller == null) ? 0 : this.m_Controller.layerCount; + #endif + } + + + #if UNITY_5 || UNITY_5_0 || UNITY_2017 + private RuntimeAnimatorController GetEffectiveController(Animator animator) + { + RuntimeAnimatorController controller = animator.runtimeAnimatorController; + + AnimatorOverrideController overrideController = controller as AnimatorOverrideController; + while (overrideController != null) + { + controller = overrideController.runtimeAnimatorController; + overrideController = controller as AnimatorOverrideController; + } + + return controller; + } +#endif + + + private void OnEnable() + { + this.m_Target = (PhotonAnimatorView) target; + this.m_Animator = this.m_Target.GetComponent(); + +#if UNITY_4_0 || UNITY_4_0_1 || UNITY_4_1 || UNITY_4_2 || UNITY_4_3 || UNITY_4_5 || UNITY_4_6 || UNITY_4_7 + this.m_Controller = AnimatorController.GetEffectiveAnimatorController(this.m_Animator); +#elif UNITY_5 || UNITY_5_0 || UNITY_2017 + this.m_Controller = this.GetEffectiveController(this.m_Animator) as AnimatorController; +#endif + + CheckIfStoredParametersExist(); + } + + private void DrawWeightInspector() + { + SerializedProperty foldoutProperty = serializedObject.FindProperty("ShowLayerWeightsInspector"); + foldoutProperty.boolValue = PhotonGUI.ContainerHeaderFoldout("Synchronize Layer Weights", foldoutProperty.boolValue); + + if (foldoutProperty.boolValue == false) + { + return; + } + + float lineHeight = 20; + Rect containerRect = PhotonGUI.ContainerBody(this.GetLayerCount()*lineHeight); + + for (int i = 0; i < this.GetLayerCount(); ++i) + { + if (this.m_Target.DoesLayerSynchronizeTypeExist(i) == false) + { + this.m_Target.SetLayerSynchronized(i, PhotonAnimatorView.SynchronizeType.Disabled); + + #if !UNITY_MIN_5_3 + EditorUtility.SetDirty(this.m_Target); + #endif + } + + PhotonAnimatorView.SynchronizeType syncType = this.m_Target.GetLayerSynchronizeType(i); + + Rect elementRect = new Rect(containerRect.xMin, containerRect.yMin + i*lineHeight, containerRect.width, lineHeight); + + Rect labelRect = new Rect(elementRect.xMin + 5, elementRect.yMin + 2, EditorGUIUtility.labelWidth - 5, elementRect.height); + GUI.Label(labelRect, "Layer " + i); + + Rect popupRect = new Rect(elementRect.xMin + EditorGUIUtility.labelWidth, elementRect.yMin + 2, elementRect.width - EditorGUIUtility.labelWidth - 5, EditorGUIUtility.singleLineHeight); + syncType = (PhotonAnimatorView.SynchronizeType) EditorGUI.EnumPopup(popupRect, syncType); + + if (i < this.GetLayerCount() - 1) + { + Rect splitterRect = new Rect(elementRect.xMin + 2, elementRect.yMax, elementRect.width - 4, 1); + PhotonGUI.DrawSplitter(splitterRect); + } + + if (syncType != this.m_Target.GetLayerSynchronizeType(i)) + { + Undo.RecordObject(target, "Modify Synchronize Layer Weights"); + this.m_Target.SetLayerSynchronized(i, syncType); + + #if !UNITY_MIN_5_3 + EditorUtility.SetDirty(this.m_Target); + #endif + } + } + } + + private int GetParameterCount() + { + #if UNITY_4_0 || UNITY_4_0_1 || UNITY_4_1 || UNITY_4_2 || UNITY_4_3 || UNITY_4_5 || UNITY_4_6 || UNITY_4_7 + return (this.m_Controller == null) ? 0 : this.m_Controller.parameterCount; + #elif UNITY_5 || UNITY_5_0 || UNITY_2017 + return (this.m_Controller == null) ? 0 : this.m_Controller.parameters.Length; + #else + return (m_Animator == null) ? 0 : m_Animator.parameters.Length; + #endif + } + + private AnimatorControllerParameter GetAnimatorControllerParameter(int i) + { + #if UNITY_4_0 || UNITY_4_0_1 || UNITY_4_1 || UNITY_4_2 || UNITY_4_3 || UNITY_4_5 || UNITY_4_6 || UNITY_4_7 + return this.m_Controller.GetParameter(i); + #elif UNITY_5 || UNITY_5_0 || UNITY_2017 + return this.m_Controller.parameters[i]; + #else + return m_Animator.parameters[i]; + #endif + } + + private bool DoesParameterExist(string name) + { + for (int i = 0; i < this.GetParameterCount(); ++i) + { + if (GetAnimatorControllerParameter(i).name == name) + { + return true; + } + } + + return false; + } + + private void CheckIfStoredParametersExist() + { + var syncedParams = this.m_Target.GetSynchronizedParameters(); + List paramsToRemove = new List(); + + for (int i = 0; i < syncedParams.Count; ++i) + { + string parameterName = syncedParams[i].Name; + if (DoesParameterExist(parameterName) == false) + { + Debug.LogWarning("Parameter '" + this.m_Target.GetSynchronizedParameters()[i].Name + "' doesn't exist anymore. Removing it from the list of synchronized parameters"); + paramsToRemove.Add(parameterName); + } + } + if (paramsToRemove.Count > 0) + { + foreach (string param in paramsToRemove) + { + this.m_Target.GetSynchronizedParameters().RemoveAll(item => item.Name == param); + } + + #if !UNITY_MIN_5_3 + EditorUtility.SetDirty(this.m_Target); + #endif + } + } + + + private void DrawParameterInspector() + { + // flag to expose a note in Interface if one or more trigger(s) are synchronized + bool isUsingTriggers = false; + + SerializedProperty foldoutProperty = serializedObject.FindProperty("ShowParameterInspector"); + foldoutProperty.boolValue = PhotonGUI.ContainerHeaderFoldout("Synchronize Parameters", foldoutProperty.boolValue); + + if (foldoutProperty.boolValue == false) + { + return; + } + + float lineHeight = 20; + Rect containerRect = PhotonGUI.ContainerBody(GetParameterCount()*lineHeight); + + for (int i = 0; i < GetParameterCount(); i++) + { + AnimatorControllerParameter parameter = null; + parameter = GetAnimatorControllerParameter(i); + + string defaultValue = ""; + + if (parameter.type == AnimatorControllerParameterType.Bool) + { + if (Application.isPlaying && m_Animator.gameObject.activeInHierarchy) + { + defaultValue += m_Animator.GetBool(parameter.name); + }else{ + defaultValue += parameter.defaultBool.ToString(); + } + } + else if (parameter.type == AnimatorControllerParameterType.Float) + { + if (Application.isPlaying && m_Animator.gameObject.activeInHierarchy) + { + defaultValue += m_Animator.GetFloat(parameter.name).ToString("0.00"); + }else{ + defaultValue += parameter.defaultFloat.ToString(); + } + } + else if (parameter.type == AnimatorControllerParameterType.Int) + { + if (Application.isPlaying && m_Animator.gameObject.activeInHierarchy) + { + defaultValue += m_Animator.GetInteger(parameter.name); + }else{ + defaultValue += parameter.defaultInt.ToString(); + } + } + else if (parameter.type == AnimatorControllerParameterType.Trigger) + { + if (Application.isPlaying && m_Animator.gameObject.activeInHierarchy) + { + defaultValue += m_Animator.GetBool(parameter.name); + }else{ + defaultValue += parameter.defaultBool.ToString(); + } + } + + if (this.m_Target.DoesParameterSynchronizeTypeExist(parameter.name) == false) + { + this.m_Target.SetParameterSynchronized(parameter.name, (PhotonAnimatorView.ParameterType) parameter.type, PhotonAnimatorView.SynchronizeType.Disabled); + + #if !UNITY_MIN_5_3 + EditorUtility.SetDirty(this.m_Target); + #endif + } + + PhotonAnimatorView.SynchronizeType value = this.m_Target.GetParameterSynchronizeType(parameter.name); + + // check if using trigger and actually synchronizing it + if (value!=PhotonAnimatorView.SynchronizeType.Disabled &¶meter.type == AnimatorControllerParameterType.Trigger) + { + isUsingTriggers = true; + } + + Rect elementRect = new Rect(containerRect.xMin, containerRect.yMin + i*lineHeight, containerRect.width, lineHeight); + + Rect labelRect = new Rect(elementRect.xMin + 5, elementRect.yMin + 2, EditorGUIUtility.labelWidth - 5, elementRect.height); + GUI.Label(labelRect, parameter.name + " (" + defaultValue + ")"); + + Rect popupRect = new Rect(elementRect.xMin + EditorGUIUtility.labelWidth, elementRect.yMin + 2, elementRect.width - EditorGUIUtility.labelWidth - 5, EditorGUIUtility.singleLineHeight); + value = (PhotonAnimatorView.SynchronizeType) EditorGUI.EnumPopup(popupRect, value); + + if (i < GetParameterCount() - 1) + { + Rect splitterRect = new Rect(elementRect.xMin + 2, elementRect.yMax, elementRect.width - 4, 1); + PhotonGUI.DrawSplitter(splitterRect); + } + + + + if (value != this.m_Target.GetParameterSynchronizeType(parameter.name)) + { + Undo.RecordObject(target, "Modify Synchronize Parameter " + parameter.name); + this.m_Target.SetParameterSynchronized(parameter.name, (PhotonAnimatorView.ParameterType) parameter.type, value); + + #if !UNITY_MIN_5_3 + EditorUtility.SetDirty(this.m_Target); + #endif + } + } + + // display note when synchronized triggers are detected. + if (isUsingTriggers) + { + GUILayout.BeginHorizontal(GUI.skin.box); + GUILayout.Label("When using triggers, make sure this component is last in the stack"); + if (GUILayout.Button(PhotonGUI.HelpIcon,GUIStyle.none,GUILayout.Width(16)) ) + { + Application.OpenURL(TRIGGER_HELP_URL); + } + GUILayout.EndHorizontal(); + } + + } +} \ No newline at end of file diff --git a/Assets/Photon Unity Networking/Editor/PhotonNetwork/Views/PhotonAnimatorViewEditor.cs.meta b/Assets/Photon Unity Networking/Editor/PhotonNetwork/Views/PhotonAnimatorViewEditor.cs.meta new file mode 100644 index 0000000..c6e48af --- /dev/null +++ b/Assets/Photon Unity Networking/Editor/PhotonNetwork/Views/PhotonAnimatorViewEditor.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: a3f61bade114730459f7ad45f5f292c1 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Photon Unity Networking/Editor/PhotonNetwork/Views/PhotonRigidbody2DViewEditor.cs b/Assets/Photon Unity Networking/Editor/PhotonNetwork/Views/PhotonRigidbody2DViewEditor.cs new file mode 100644 index 0000000..82411d7 --- /dev/null +++ b/Assets/Photon Unity Networking/Editor/PhotonNetwork/Views/PhotonRigidbody2DViewEditor.cs @@ -0,0 +1,19 @@ +using UnityEditor; +using UnityEngine; + +[CustomEditor(typeof (PhotonRigidbody2DView))] +public class PhotonRigidbody2DViewEditor : Editor +{ + public override void OnInspectorGUI() + { + PhotonGUI.ContainerHeader("Options"); + + Rect containerRect = PhotonGUI.ContainerBody(EditorGUIUtility.singleLineHeight*2 + 10); + + Rect propertyRect = new Rect(containerRect.xMin + 5, containerRect.yMin + 5, containerRect.width, EditorGUIUtility.singleLineHeight); + EditorGUI.PropertyField(propertyRect, serializedObject.FindProperty("m_SynchronizeVelocity"), new GUIContent("Synchronize Velocity")); + + propertyRect.y += EditorGUIUtility.singleLineHeight; + EditorGUI.PropertyField(propertyRect, serializedObject.FindProperty("m_SynchronizeAngularVelocity"), new GUIContent("Synchronize Angular Velocity")); + } +} \ No newline at end of file diff --git a/Assets/Photon Unity Networking/Editor/PhotonNetwork/Views/PhotonRigidbody2DViewEditor.cs.meta b/Assets/Photon Unity Networking/Editor/PhotonNetwork/Views/PhotonRigidbody2DViewEditor.cs.meta new file mode 100644 index 0000000..9e50961 --- /dev/null +++ b/Assets/Photon Unity Networking/Editor/PhotonNetwork/Views/PhotonRigidbody2DViewEditor.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 3a82e8e86b9eecb40ac3f6ebc949f6ef +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Photon Unity Networking/Editor/PhotonNetwork/Views/PhotonRigidbodyViewEditor.cs b/Assets/Photon Unity Networking/Editor/PhotonNetwork/Views/PhotonRigidbodyViewEditor.cs new file mode 100644 index 0000000..be835e5 --- /dev/null +++ b/Assets/Photon Unity Networking/Editor/PhotonNetwork/Views/PhotonRigidbodyViewEditor.cs @@ -0,0 +1,19 @@ +using UnityEditor; +using UnityEngine; + +[CustomEditor(typeof (PhotonRigidbodyView))] +public class PhotonRigidbodyViewEditor : Editor +{ + public override void OnInspectorGUI() + { + PhotonGUI.ContainerHeader("Options"); + + Rect containerRect = PhotonGUI.ContainerBody(EditorGUIUtility.singleLineHeight*2 + 10); + + Rect propertyRect = new Rect(containerRect.xMin + 5, containerRect.yMin + 5, containerRect.width, EditorGUIUtility.singleLineHeight); + EditorGUI.PropertyField(propertyRect, serializedObject.FindProperty("m_SynchronizeVelocity"), new GUIContent("Synchronize Velocity")); + + propertyRect.y += EditorGUIUtility.singleLineHeight; + EditorGUI.PropertyField(propertyRect, serializedObject.FindProperty("m_SynchronizeAngularVelocity"), new GUIContent("Synchronize Angular Velocity")); + } +} \ No newline at end of file diff --git a/Assets/Photon Unity Networking/Editor/PhotonNetwork/Views/PhotonRigidbodyViewEditor.cs.meta b/Assets/Photon Unity Networking/Editor/PhotonNetwork/Views/PhotonRigidbodyViewEditor.cs.meta new file mode 100644 index 0000000..b4fa5b9 --- /dev/null +++ b/Assets/Photon Unity Networking/Editor/PhotonNetwork/Views/PhotonRigidbodyViewEditor.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 4bcfebc9a2f1074488adedd1fe84e6c9 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Photon Unity Networking/Editor/PhotonNetwork/Views/PhotonTransformViewEditor.cs b/Assets/Photon Unity Networking/Editor/PhotonNetwork/Views/PhotonTransformViewEditor.cs new file mode 100644 index 0000000..d94e27a --- /dev/null +++ b/Assets/Photon Unity Networking/Editor/PhotonNetwork/Views/PhotonTransformViewEditor.cs @@ -0,0 +1,434 @@ +// ---------------------------------------------------------------------------- +// +// PhotonNetwork Framework for Unity - Copyright (C) 2016 Exit Games GmbH +// +// +// This is a custom editor for the TransformView component. +// +// developer@exitgames.com +// ---------------------------------------------------------------------------- + + +#if UNITY_5 && !UNITY_5_0 && !UNITY_5_1 && !UNITY_5_2 +#define UNITY_MIN_5_3 +#endif + + +using UnityEditor; +using UnityEngine; + +[CustomEditor(typeof (PhotonTransformView))] +public class PhotonTransformViewEditor : Editor +{ + //private PhotonTransformView m_Target; + + private SerializedProperty m_SynchronizePositionProperty; + private SerializedProperty m_SynchronizeRotationProperty; + private SerializedProperty m_SynchronizeScaleProperty; + + private bool m_InterpolateHelpOpen; + private bool m_ExtrapolateHelpOpen; + private bool m_InterpolateRotationHelpOpen; + private bool m_InterpolateScaleHelpOpen; + + private const int EDITOR_LINE_HEIGHT = 20; + + private const string INTERPOLATE_TOOLTIP = + "Choose between synchronizing the value directly (by disabling interpolation) or smoothly move it towards the newest update."; + + private const string INTERPOLATE_HELP = + "You can use interpolation to smoothly move your GameObject towards a new position that is received via the network. " + + "This helps to reduce the stuttering movement that results because the network updates only arrive 10 times per second.\n" + + "As a side effect, the GameObject is always lagging behind the actual position a little bit. This can be addressed with extrapolation."; + + private const string EXTRAPOLATE_TOOLTIP = "Extrapolation is used to predict where the GameObject actually is"; + + private const string EXTRAPOLATE_HELP = + "Whenever you deal with network values, all values you receive will be a little bit out of date since that data needs " + + "to reach you first. You can use extrapolation to try to predict where the player actually is, based on the movement data you have received.\n" + + + "This has to be tweaked carefully for each specific game in order to insure the optimal prediction. Sometimes it is very easy to extrapolate states, because " + + + "the GameObject behaves very predictable (for example for vehicles). Other times it can be very hard because the user input is translated directly to the game " + + "and you cannot really predict what the user is going to do (for example in fighting games)"; + + private const string INTERPOLATE_HELP_URL = "http://doc.exitgames.com/en/pun/current/tutorials/rpg-movement"; + private const string EXTRAPOLATE_HELP_URL = "http://doc.exitgames.com/en/pun/current/tutorials/rpg-movement"; + + public void OnEnable() + { + SetupSerializedProperties(); + } + + public override void OnInspectorGUI() + { + serializedObject.Update (); + + //this.m_Target = (PhotonTransformView) target; + + DrawIsPlayingWarning(); + GUI.enabled = !Application.isPlaying; + + DrawSynchronizePositionHeader(); + DrawSynchronizePositionData(); + + GUI.enabled = !Application.isPlaying; + DrawSynchronizeRotationHeader(); + DrawSynchronizeRotationData(); + + GUI.enabled = !Application.isPlaying; + DrawSynchronizeScaleHeader(); + DrawSynchronizeScaleData(); + + serializedObject.ApplyModifiedProperties(); + + GUI.enabled = true; + } + + private void DrawIsPlayingWarning() + { + if (Application.isPlaying == false) + { + return; + } + + GUILayout.BeginVertical(GUI.skin.box); + { + GUILayout.Label("Editing is disabled in play mode so the two objects don't go out of sync"); + } + GUILayout.EndVertical(); + } + + private void SetupSerializedProperties() + { + this.m_SynchronizePositionProperty = serializedObject.FindProperty("m_PositionModel.SynchronizeEnabled"); + this.m_SynchronizeRotationProperty = serializedObject.FindProperty("m_RotationModel.SynchronizeEnabled"); + this.m_SynchronizeScaleProperty = serializedObject.FindProperty("m_ScaleModel.SynchronizeEnabled"); + } + + private void DrawSynchronizePositionHeader() + { + DrawHeader("Synchronize Position", this.m_SynchronizePositionProperty); + } + + private void DrawSynchronizePositionData() + { + if (this.m_SynchronizePositionProperty == null || this.m_SynchronizePositionProperty.boolValue == false) + { + return; + } + + SerializedProperty interpolatePositionProperty = serializedObject.FindProperty("m_PositionModel.InterpolateOption"); + PhotonTransformViewPositionModel.InterpolateOptions interpolateOption = (PhotonTransformViewPositionModel.InterpolateOptions)interpolatePositionProperty.enumValueIndex; + + SerializedProperty extrapolatePositionProperty = serializedObject.FindProperty("m_PositionModel.ExtrapolateOption"); + PhotonTransformViewPositionModel.ExtrapolateOptions extrapolateOption = (PhotonTransformViewPositionModel.ExtrapolateOptions)extrapolatePositionProperty.enumValueIndex; + + float containerHeight = 155; + + switch (interpolateOption) + { + case PhotonTransformViewPositionModel.InterpolateOptions.FixedSpeed: + case PhotonTransformViewPositionModel.InterpolateOptions.Lerp: + containerHeight += EDITOR_LINE_HEIGHT; + break; + /*case PhotonTransformViewPositionModel.InterpolateOptions.MoveTowardsComplex: + containerHeight += EDITOR_LINE_HEIGHT*3; + break;*/ + } + + if (extrapolateOption != PhotonTransformViewPositionModel.ExtrapolateOptions.Disabled) + { + containerHeight += EDITOR_LINE_HEIGHT; + } + + switch (extrapolateOption) + { + case PhotonTransformViewPositionModel.ExtrapolateOptions.FixedSpeed: + containerHeight += EDITOR_LINE_HEIGHT; + break; + } + + if (this.m_InterpolateHelpOpen == true) + { + containerHeight += GetInterpolateHelpBoxHeight(); + } + + if (this.m_ExtrapolateHelpOpen == true) + { + containerHeight += GetExtrapolateHelpBoxHeight(); + } + + // removed Gizmo Options. -3 lines, -1 splitter + containerHeight -= EDITOR_LINE_HEIGHT * 2; + + Rect rect = PhotonGUI.ContainerBody(containerHeight); + + Rect propertyRect = new Rect(rect.xMin + 5, rect.yMin + 2, rect.width - 10, EditorGUIUtility.singleLineHeight); + + DrawTeleport(ref propertyRect); + DrawSplitter(ref propertyRect); + + DrawSynchronizePositionDataInterpolation(ref propertyRect, interpolatePositionProperty, interpolateOption); + DrawSplitter(ref propertyRect); + + DrawSynchronizePositionDataExtrapolation(ref propertyRect, extrapolatePositionProperty, extrapolateOption); + DrawSplitter(ref propertyRect); + + DrawSynchronizePositionDataGizmos(ref propertyRect); + } + + private float GetInterpolateHelpBoxHeight() + { + return PhotonGUI.RichLabel.CalcHeight(new GUIContent(INTERPOLATE_HELP), Screen.width - 54) + 35; + } + + private float GetExtrapolateHelpBoxHeight() + { + return PhotonGUI.RichLabel.CalcHeight(new GUIContent(EXTRAPOLATE_HELP), Screen.width - 54) + 35; + } + + private void DrawSplitter(ref Rect propertyRect) + { + Rect splitterRect = new Rect(propertyRect.xMin - 3, propertyRect.yMin, propertyRect.width + 6, 1); + PhotonGUI.DrawSplitter(splitterRect); + + propertyRect.y += 5; + } + + private void DrawSynchronizePositionDataGizmos(ref Rect propertyRect) + { + GUI.enabled = true; + /*PhotonGUI.DrawGizmoOptions(propertyRect, "Synchronized Position Gizmo", + serializedObject.FindProperty("m_PositionModel.DrawNetworkGizmo"), + serializedObject.FindProperty("m_PositionModel.NetworkGizmoColor"), + serializedObject.FindProperty("m_PositionModel.NetworkGizmoType"), + serializedObject.FindProperty("m_PositionModel.NetworkGizmoSize")); + propertyRect.y += EDITOR_LINE_HEIGHT; + + PhotonGUI.DrawGizmoOptions(propertyRect, "Extrapolated Position Gizmo", + serializedObject.FindProperty("m_PositionModel.DrawExtrapolatedGizmo"), + serializedObject.FindProperty("m_PositionModel.ExtrapolatedGizmoColor"), + serializedObject.FindProperty("m_PositionModel.ExtrapolatedGizmoType"), + serializedObject.FindProperty("m_PositionModel.ExtrapolatedGizmoSize")); + propertyRect.y += EDITOR_LINE_HEIGHT;*/ + + EditorGUI.PropertyField(propertyRect, serializedObject.FindProperty("m_PositionModel.DrawErrorGizmo"), + new GUIContent("Draw synchronized position error")); + propertyRect.y += EDITOR_LINE_HEIGHT; + } + + private void DrawHelpBox(ref Rect propertyRect, bool isOpen, float height, string helpText, string url) + { + if (isOpen == true) + { + Rect helpRect = new Rect(propertyRect.xMin, propertyRect.yMin, propertyRect.width, height - 5); + GUI.BeginGroup(helpRect, GUI.skin.box); + GUI.Label(new Rect(5, 5, propertyRect.width - 10, height - 30), helpText, PhotonGUI.RichLabel); + if (GUI.Button(new Rect(5, height - 30, propertyRect.width - 10, 20), "Read more in our documentation")) + { + Application.OpenURL(url); + } + GUI.EndGroup(); + + propertyRect.y += height; + } + } + + private void DrawPropertyWithHelpIcon(ref Rect propertyRect, ref bool isHelpOpen, SerializedProperty property, string tooltip) + { + Rect propertyFieldRect = new Rect(propertyRect.xMin, propertyRect.yMin, propertyRect.width - 20, propertyRect.height); + string propertyName = ObjectNames.NicifyVariableName(property.name); + EditorGUI.PropertyField(propertyFieldRect, property, new GUIContent(propertyName, tooltip)); + + Rect helpIconRect = new Rect(propertyFieldRect.xMax + 5, propertyFieldRect.yMin, 20, propertyFieldRect.height); + isHelpOpen = GUI.Toggle(helpIconRect, isHelpOpen, PhotonGUI.HelpIcon, GUIStyle.none); + + propertyRect.y += EDITOR_LINE_HEIGHT; + } + + private void DrawSynchronizePositionDataExtrapolation(ref Rect propertyRect, SerializedProperty extrapolatePositionProperty, PhotonTransformViewPositionModel.ExtrapolateOptions extrapolateOption) + { + DrawPropertyWithHelpIcon(ref propertyRect, ref this.m_ExtrapolateHelpOpen, extrapolatePositionProperty, EXTRAPOLATE_TOOLTIP); + DrawHelpBox(ref propertyRect, this.m_ExtrapolateHelpOpen, GetExtrapolateHelpBoxHeight(), EXTRAPOLATE_HELP, EXTRAPOLATE_HELP_URL); + + if (extrapolateOption != PhotonTransformViewPositionModel.ExtrapolateOptions.Disabled) + { + EditorGUI.PropertyField(propertyRect, serializedObject.FindProperty("m_PositionModel.ExtrapolateIncludingRoundTripTime")); + propertyRect.y += EDITOR_LINE_HEIGHT; + } + + switch (extrapolateOption) + { + case PhotonTransformViewPositionModel.ExtrapolateOptions.FixedSpeed: + EditorGUI.PropertyField(propertyRect, serializedObject.FindProperty("m_PositionModel.ExtrapolateSpeed")); + propertyRect.y += EDITOR_LINE_HEIGHT; + break; + } + } + + private void DrawTeleport(ref Rect propertyRect) + { + EditorGUI.PropertyField(propertyRect, serializedObject.FindProperty("m_PositionModel.TeleportEnabled"), + new GUIContent("Enable teleport for great distances")); + propertyRect.y += EDITOR_LINE_HEIGHT; + + EditorGUI.PropertyField(propertyRect, serializedObject.FindProperty("m_PositionModel.TeleportIfDistanceGreaterThan"), + new GUIContent("Teleport if distance greater than")); + propertyRect.y += EDITOR_LINE_HEIGHT; + } + + private void DrawSynchronizePositionDataInterpolation(ref Rect propertyRect, SerializedProperty interpolatePositionProperty, + PhotonTransformViewPositionModel.InterpolateOptions interpolateOption) + { + DrawPropertyWithHelpIcon(ref propertyRect, ref this.m_InterpolateHelpOpen, interpolatePositionProperty, INTERPOLATE_TOOLTIP); + DrawHelpBox(ref propertyRect, this.m_InterpolateHelpOpen, GetInterpolateHelpBoxHeight(), INTERPOLATE_HELP, INTERPOLATE_HELP_URL); + + switch (interpolateOption) + { + case PhotonTransformViewPositionModel.InterpolateOptions.FixedSpeed: + EditorGUI.PropertyField(propertyRect, serializedObject.FindProperty("m_PositionModel.InterpolateMoveTowardsSpeed"), + new GUIContent("MoveTowards Speed")); + propertyRect.y += EDITOR_LINE_HEIGHT; + break; + + case PhotonTransformViewPositionModel.InterpolateOptions.Lerp: + EditorGUI.PropertyField(propertyRect, serializedObject.FindProperty("m_PositionModel.InterpolateLerpSpeed"), new GUIContent("Lerp Speed")); + propertyRect.y += EDITOR_LINE_HEIGHT; + break; + + /*case PhotonTransformViewPositionModel.InterpolateOptions.MoveTowardsComplex: + Rect curveRect = new Rect(propertyRect.xMin, propertyRect.yMin, propertyRect.width - 100, propertyRect.height); + EditorGUI.PropertyField(curveRect, serializedObject.FindProperty("m_PositionModel.InterpolateSpeedCurve"), new GUIContent("MoveTowards Speed Curve")); + + Rect labelRect = new Rect(propertyRect.xMax - 95, propertyRect.yMin, 10, propertyRect.height); + GUI.Label(labelRect, "x"); + + Rect multiplierRect = new Rect(propertyRect.xMax - 80, propertyRect.yMin, 80, propertyRect.height); + EditorGUI.PropertyField(multiplierRect, serializedObject.FindProperty("m_PositionModel.InterpolateMoveTowardsSpeed"), GUIContent.none); + propertyRect.y += EDITOR_LINE_HEIGHT; + + EditorGUI.PropertyField(propertyRect, serializedObject.FindProperty("m_PositionModel.InterpolateMoveTowardsAcceleration"), + new GUIContent("Acceleration")); + propertyRect.y += EDITOR_LINE_HEIGHT; + + EditorGUI.PropertyField(propertyRect, serializedObject.FindProperty("m_PositionModel.InterpolateMoveTowardsDeceleration"), + new GUIContent("Deceleration")); + propertyRect.y += EDITOR_LINE_HEIGHT; + break;*/ + } + } + + private void DrawSynchronizeRotationHeader() + { + DrawHeader("Synchronize Rotation", this.m_SynchronizeRotationProperty); + } + + private void DrawSynchronizeRotationData() + { + if (this.m_SynchronizeRotationProperty == null || this.m_SynchronizeRotationProperty.boolValue == false) + { + return; + } + + SerializedProperty interpolateRotationProperty = serializedObject.FindProperty("m_RotationModel.InterpolateOption"); + PhotonTransformViewRotationModel.InterpolateOptions interpolateOption = + (PhotonTransformViewRotationModel.InterpolateOptions) interpolateRotationProperty.enumValueIndex; + + float containerHeight = 20; + + switch (interpolateOption) + { + case PhotonTransformViewRotationModel.InterpolateOptions.RotateTowards: + case PhotonTransformViewRotationModel.InterpolateOptions.Lerp: + containerHeight += EDITOR_LINE_HEIGHT; + break; + } + + if (this.m_InterpolateRotationHelpOpen == true) + { + containerHeight += GetInterpolateHelpBoxHeight(); + } + + Rect rect = PhotonGUI.ContainerBody(containerHeight); + Rect propertyRect = new Rect(rect.xMin + 5, rect.yMin + 2, rect.width - 10, EditorGUIUtility.singleLineHeight); + + DrawPropertyWithHelpIcon(ref propertyRect, ref this.m_InterpolateRotationHelpOpen, interpolateRotationProperty, INTERPOLATE_TOOLTIP); + DrawHelpBox(ref propertyRect, this.m_InterpolateRotationHelpOpen, GetInterpolateHelpBoxHeight(), INTERPOLATE_HELP, INTERPOLATE_HELP_URL); + + switch (interpolateOption) + { + case PhotonTransformViewRotationModel.InterpolateOptions.RotateTowards: + EditorGUI.PropertyField(propertyRect, serializedObject.FindProperty("m_RotationModel.InterpolateRotateTowardsSpeed"), + new GUIContent("RotateTowards Speed")); + break; + case PhotonTransformViewRotationModel.InterpolateOptions.Lerp: + EditorGUI.PropertyField(propertyRect, serializedObject.FindProperty("m_RotationModel.InterpolateLerpSpeed"), new GUIContent("Lerp Speed")); + break; + } + } + + private void DrawSynchronizeScaleHeader() + { + DrawHeader("Synchronize Scale", this.m_SynchronizeScaleProperty); + } + + private void DrawSynchronizeScaleData() + { + if (this.m_SynchronizeScaleProperty == null || this.m_SynchronizeScaleProperty.boolValue == false) + { + return; + } + + SerializedProperty interpolateScaleProperty = serializedObject.FindProperty("m_ScaleModel.InterpolateOption"); + PhotonTransformViewScaleModel.InterpolateOptions interpolateOption = (PhotonTransformViewScaleModel.InterpolateOptions) interpolateScaleProperty.enumValueIndex; + + float containerHeight = EDITOR_LINE_HEIGHT; + + switch (interpolateOption) + { + case PhotonTransformViewScaleModel.InterpolateOptions.MoveTowards: + case PhotonTransformViewScaleModel.InterpolateOptions.Lerp: + containerHeight += EDITOR_LINE_HEIGHT; + break; + } + + if (this.m_InterpolateScaleHelpOpen == true) + { + containerHeight += GetInterpolateHelpBoxHeight(); + } + + Rect rect = PhotonGUI.ContainerBody(containerHeight); + Rect propertyRect = new Rect(rect.xMin + 5, rect.yMin + 2, rect.width - 10, EditorGUIUtility.singleLineHeight); + + DrawPropertyWithHelpIcon(ref propertyRect, ref this.m_InterpolateScaleHelpOpen, interpolateScaleProperty, INTERPOLATE_TOOLTIP); + DrawHelpBox(ref propertyRect, this.m_InterpolateScaleHelpOpen, GetInterpolateHelpBoxHeight(), INTERPOLATE_HELP, INTERPOLATE_HELP_URL); + + switch (interpolateOption) + { + case PhotonTransformViewScaleModel.InterpolateOptions.MoveTowards: + EditorGUI.PropertyField(propertyRect, serializedObject.FindProperty("m_ScaleModel.InterpolateMoveTowardsSpeed"), + new GUIContent("MoveTowards Speed")); + break; + case PhotonTransformViewScaleModel.InterpolateOptions.Lerp: + EditorGUI.PropertyField(propertyRect, serializedObject.FindProperty("m_ScaleModel.InterpolateLerpSpeed"), new GUIContent("Lerp Speed")); + break; + } + } + + private void DrawHeader(string label, SerializedProperty property) + { + if (property == null) + { + return; + } + + bool newValue = PhotonGUI.ContainerHeaderToggle(label, property.boolValue); + + if (newValue != property.boolValue) + { + property.boolValue = newValue; + property.serializedObject.ApplyModifiedProperties(); + } + } +} \ No newline at end of file diff --git a/Assets/Photon Unity Networking/Editor/PhotonNetwork/Views/PhotonTransformViewEditor.cs.meta b/Assets/Photon Unity Networking/Editor/PhotonNetwork/Views/PhotonTransformViewEditor.cs.meta new file mode 100644 index 0000000..58d59ef --- /dev/null +++ b/Assets/Photon Unity Networking/Editor/PhotonNetwork/Views/PhotonTransformViewEditor.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 22292ca8ffb574945bedfaf49266672e +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Photon Unity Networking/Editor/PhotonNetwork/background.jpg b/Assets/Photon Unity Networking/Editor/PhotonNetwork/background.jpg new file mode 100644 index 0000000..74d3ce8 Binary files /dev/null and b/Assets/Photon Unity Networking/Editor/PhotonNetwork/background.jpg differ diff --git a/Assets/Photon Unity Networking/Editor/PhotonNetwork/background.jpg.meta b/Assets/Photon Unity Networking/Editor/PhotonNetwork/background.jpg.meta new file mode 100644 index 0000000..48f073e --- /dev/null +++ b/Assets/Photon Unity Networking/Editor/PhotonNetwork/background.jpg.meta @@ -0,0 +1,45 @@ +fileFormatVersion: 2 +guid: 1faa1cf0448470c4ebbb23b97759ab50 +TextureImporter: + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + linearTexture: 1 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -1 + maxTextureSize: 256 + textureSettings: + filterMode: 0 + aniso: 1 + mipBias: -1 + wrapMode: 1 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spritePixelsToUnits: 100 + alphaIsTransparency: 1 + textureType: 2 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/Assets/Photon Unity Networking/Editor/PhotonNetwork/help.png b/Assets/Photon Unity Networking/Editor/PhotonNetwork/help.png new file mode 100644 index 0000000..a421667 Binary files /dev/null and b/Assets/Photon Unity Networking/Editor/PhotonNetwork/help.png differ diff --git a/Assets/Photon Unity Networking/Editor/PhotonNetwork/help.png.meta b/Assets/Photon Unity Networking/Editor/PhotonNetwork/help.png.meta new file mode 100644 index 0000000..cb312ac --- /dev/null +++ b/Assets/Photon Unity Networking/Editor/PhotonNetwork/help.png.meta @@ -0,0 +1,45 @@ +fileFormatVersion: 2 +guid: 9f1212502533cb34188dd6ef094188cb +TextureImporter: + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + linearTexture: 1 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -3 + maxTextureSize: 1024 + textureSettings: + filterMode: -1 + aniso: 1 + mipBias: -1 + wrapMode: 1 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spritePixelsToUnits: 100 + alphaIsTransparency: 1 + textureType: 2 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/Assets/Photon Unity Networking/PhotonCloud-icon.png b/Assets/Photon Unity Networking/PhotonCloud-icon.png new file mode 100644 index 0000000..aff02a4 Binary files /dev/null and b/Assets/Photon Unity Networking/PhotonCloud-icon.png differ diff --git a/Assets/Photon Unity Networking/PhotonCloud-icon.png.meta b/Assets/Photon Unity Networking/PhotonCloud-icon.png.meta new file mode 100644 index 0000000..173f520 --- /dev/null +++ b/Assets/Photon Unity Networking/PhotonCloud-icon.png.meta @@ -0,0 +1,38 @@ +fileFormatVersion: 2 +guid: 8425b95fef16c3f4194e3a20e245cb67 +labels: +- ExitGames +- PUN +- Photon +- Networking +TextureImporter: + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + linearTexture: 1 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + textureFormat: -1 + maxTextureSize: 128 + textureSettings: + filterMode: 0 + aniso: 1 + mipBias: -1 + wrapMode: 1 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + textureType: 2 + buildTargetSettings: [] diff --git a/Assets/Photon Unity Networking/PhotonNetwork-Documentation.chm b/Assets/Photon Unity Networking/PhotonNetwork-Documentation.chm new file mode 100644 index 0000000..cc35d28 Binary files /dev/null and b/Assets/Photon Unity Networking/PhotonNetwork-Documentation.chm differ diff --git a/Assets/Photon Unity Networking/PhotonNetwork-Documentation.chm.meta b/Assets/Photon Unity Networking/PhotonNetwork-Documentation.chm.meta new file mode 100644 index 0000000..1e4153f --- /dev/null +++ b/Assets/Photon Unity Networking/PhotonNetwork-Documentation.chm.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: d93cfd57d52f80543b09a3f2ce724f84 diff --git a/Assets/Photon Unity Networking/PhotonNetwork-Documentation.pdf b/Assets/Photon Unity Networking/PhotonNetwork-Documentation.pdf new file mode 100644 index 0000000..1570969 Binary files /dev/null and b/Assets/Photon Unity Networking/PhotonNetwork-Documentation.pdf differ diff --git a/Assets/Photon Unity Networking/PhotonNetwork-Documentation.pdf.meta b/Assets/Photon Unity Networking/PhotonNetwork-Documentation.pdf.meta new file mode 100644 index 0000000..187227e --- /dev/null +++ b/Assets/Photon Unity Networking/PhotonNetwork-Documentation.pdf.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: f226ce9e7a33bc24c95f34dd9f583516 +labels: +- ExitGames +- PUN +- Photon +- Networking diff --git a/Assets/Photon Unity Networking/Plugins.meta b/Assets/Photon Unity Networking/Plugins.meta new file mode 100644 index 0000000..121101f --- /dev/null +++ b/Assets/Photon Unity Networking/Plugins.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 1fb01432962be447c9a717b61302dae1 +folderAsset: yes +timeCreated: 1501014811 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Photon Unity Networking/Plugins/PhotonNetwork.meta b/Assets/Photon Unity Networking/Plugins/PhotonNetwork.meta new file mode 100644 index 0000000..80a0b4b --- /dev/null +++ b/Assets/Photon Unity Networking/Plugins/PhotonNetwork.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: b3ddd5089024d44a180d4285502ae8f1 +folderAsset: yes +timeCreated: 1501014811 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Photon Unity Networking/Plugins/PhotonNetwork/CustomTypes.cs b/Assets/Photon Unity Networking/Plugins/PhotonNetwork/CustomTypes.cs new file mode 100644 index 0000000..077a6b4 --- /dev/null +++ b/Assets/Photon Unity Networking/Plugins/PhotonNetwork/CustomTypes.cs @@ -0,0 +1,177 @@ +// ---------------------------------------------------------------------------- +// +// PhotonNetwork Framework for Unity - Copyright (C) 2011 Exit Games GmbH +// +// +// +// +// developer@exitgames.com +// ---------------------------------------------------------------------------- + +#pragma warning disable 1587 +/// \file +/// Sets up support for Unity-specific types. Can be a blueprint how to register your own Custom Types for sending. +#pragma warning restore 1587 + + +using ExitGames.Client.Photon; +using UnityEngine; + + +/// +/// Internally used class, containing de/serialization methods for various Unity-specific classes. +/// Adding those to the Photon serialization protocol allows you to send them in events, etc. +/// +internal static class CustomTypes +{ + /// Register + internal static void Register() + { + PhotonPeer.RegisterType(typeof(Vector2), (byte)'W', SerializeVector2, DeserializeVector2); + PhotonPeer.RegisterType(typeof(Vector3), (byte)'V', SerializeVector3, DeserializeVector3); + PhotonPeer.RegisterType(typeof(Quaternion), (byte)'Q', SerializeQuaternion, DeserializeQuaternion); + PhotonPeer.RegisterType(typeof(PhotonPlayer), (byte)'P', SerializePhotonPlayer, DeserializePhotonPlayer); + } + + + #region Custom De/Serializer Methods + + + public static readonly byte[] memVector3 = new byte[3 * 4]; + private static short SerializeVector3(StreamBuffer outStream, object customobject) + { + Vector3 vo = (Vector3)customobject; + + int index = 0; + lock (memVector3) + { + byte[] bytes = memVector3; + Protocol.Serialize(vo.x, bytes, ref index); + Protocol.Serialize(vo.y, bytes, ref index); + Protocol.Serialize(vo.z, bytes, ref index); + outStream.Write(bytes, 0, 3 * 4); + } + + return 3 * 4; + } + + private static object DeserializeVector3(StreamBuffer inStream, short length) + { + Vector3 vo = new Vector3(); + lock (memVector3) + { + inStream.Read(memVector3, 0, 3 * 4); + int index = 0; + Protocol.Deserialize(out vo.x, memVector3, ref index); + Protocol.Deserialize(out vo.y, memVector3, ref index); + Protocol.Deserialize(out vo.z, memVector3, ref index); + } + + return vo; + } + + + public static readonly byte[] memVector2 = new byte[2 * 4]; + private static short SerializeVector2(StreamBuffer outStream, object customobject) + { + Vector2 vo = (Vector2)customobject; + lock (memVector2) + { + byte[] bytes = memVector2; + int index = 0; + Protocol.Serialize(vo.x, bytes, ref index); + Protocol.Serialize(vo.y, bytes, ref index); + outStream.Write(bytes, 0, 2 * 4); + } + + return 2 * 4; + } + + private static object DeserializeVector2(StreamBuffer inStream, short length) + { + Vector2 vo = new Vector2(); + lock (memVector2) + { + inStream.Read(memVector2, 0, 2 * 4); + int index = 0; + Protocol.Deserialize(out vo.x, memVector2, ref index); + Protocol.Deserialize(out vo.y, memVector2, ref index); + } + + return vo; + } + + + public static readonly byte[] memQuarternion = new byte[4 * 4]; + private static short SerializeQuaternion(StreamBuffer outStream, object customobject) + { + Quaternion o = (Quaternion)customobject; + + lock (memQuarternion) + { + byte[] bytes = memQuarternion; + int index = 0; + Protocol.Serialize(o.w, bytes, ref index); + Protocol.Serialize(o.x, bytes, ref index); + Protocol.Serialize(o.y, bytes, ref index); + Protocol.Serialize(o.z, bytes, ref index); + outStream.Write(bytes, 0, 4 * 4); + } + + return 4 * 4; + } + + private static object DeserializeQuaternion(StreamBuffer inStream, short length) + { + Quaternion o = new Quaternion(); + + lock (memQuarternion) + { + inStream.Read(memQuarternion, 0, 4 * 4); + int index = 0; + Protocol.Deserialize(out o.w, memQuarternion, ref index); + Protocol.Deserialize(out o.x, memQuarternion, ref index); + Protocol.Deserialize(out o.y, memQuarternion, ref index); + Protocol.Deserialize(out o.z, memQuarternion, ref index); + } + + return o; + } + + public static readonly byte[] memPlayer = new byte[4]; + private static short SerializePhotonPlayer(StreamBuffer outStream, object customobject) + { + int ID = ((PhotonPlayer)customobject).ID; + + lock (memPlayer) + { + byte[] bytes = memPlayer; + int off = 0; + Protocol.Serialize(ID, bytes, ref off); + outStream.Write(bytes, 0, 4); + return 4; + } + } + + private static object DeserializePhotonPlayer(StreamBuffer inStream, short length) + { + int ID; + lock (memPlayer) + { + inStream.Read(memPlayer, 0, length); + int off = 0; + Protocol.Deserialize(out ID, memPlayer, ref off); + } + + if (PhotonNetwork.networkingPeer.mActors.ContainsKey(ID)) + { + return PhotonNetwork.networkingPeer.mActors[ID]; + } + else + { + return null; + } + } + + #endregion +} diff --git a/Assets/Photon Unity Networking/Plugins/PhotonNetwork/CustomTypes.cs.meta b/Assets/Photon Unity Networking/Plugins/PhotonNetwork/CustomTypes.cs.meta new file mode 100644 index 0000000..82e3a5c --- /dev/null +++ b/Assets/Photon Unity Networking/Plugins/PhotonNetwork/CustomTypes.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: ab517bd36a2b2504b83979fcad45d4a2 +labels: +- ExitGames +- PUN +- Photon +- Networking +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} diff --git a/Assets/Photon Unity Networking/Plugins/PhotonNetwork/Enums.cs b/Assets/Photon Unity Networking/Plugins/PhotonNetwork/Enums.cs new file mode 100644 index 0000000..3439dfb --- /dev/null +++ b/Assets/Photon Unity Networking/Plugins/PhotonNetwork/Enums.cs @@ -0,0 +1,591 @@ +// ---------------------------------------------------------------------------- +// +// PhotonNetwork Framework for Unity - Copyright (C) 2011 Exit Games GmbH +// +// +// +// +// developer@exitgames.com +// ---------------------------------------------------------------------------- + +#pragma warning disable 1587 +/// \file +/// Wraps up several of the commonly used enumerations. +#pragma warning restore 1587 + + +using System; +using ExitGames.Client.Photon; + + +/// +/// This enum defines the set of MonoMessages Photon Unity Networking is using as callbacks. Implemented by PunBehaviour. +/// +/// +/// Much like "Update()" in Unity, PUN will call methods in specific situations. +/// Often, these methods are triggered when network operations complete (example: when joining a room). +/// +/// All those methods are defined and described in this enum and implemented by PunBehaviour +/// (which makes it easy to implement them as override). +/// +/// Each entry is the name of such a method and the description tells you when it gets used by PUN. +/// +/// Make sure to read the remarks per entry as some methods have optional parameters. +/// +/// \ingroup publicApi +public enum PhotonNetworkingMessage +{ + /// + /// Called when the initial connection got established but before you can use the server. OnJoinedLobby() or OnConnectedToMaster() are called when PUN is ready. + /// + /// + /// This callback is only useful to detect if the server can be reached at all (technically). + /// Most often, it's enough to implement OnFailedToConnectToPhoton() and OnDisconnectedFromPhoton(). + /// + /// OnJoinedLobby() or OnConnectedToMaster() are called when PUN is ready. + /// + /// When this is called, the low level connection is established and PUN will send your AppId, the user, etc in the background. + /// This is not called for transitions from the masterserver to game servers. + /// + /// Example: void OnConnectedToPhoton() { ... } + /// + OnConnectedToPhoton, + + /// + /// Called when the local user/client left a room. + /// + /// + /// When leaving a room, PUN brings you back to the Master Server. + /// Before you can use lobbies and join or create rooms, OnJoinedLobby() or OnConnectedToMaster() will get called again. + /// + /// Example: void OnLeftRoom() { ... } + /// + OnLeftRoom, + + /// + /// Called after switching to a new MasterClient when the current one leaves. + /// + /// + /// This is not called when this client enters a room. + /// The former MasterClient is still in the player list when this method get called. + /// + /// Example: void OnMasterClientSwitched(PhotonPlayer newMasterClient) { ... } + /// + OnMasterClientSwitched, + + /// + /// Called when a CreateRoom() call failed. Optional parameters provide ErrorCode and message. + /// + /// + /// Most likely because the room name is already in use (some other client was faster than you). + /// PUN logs some info if the PhotonNetwork.logLevel is >= PhotonLogLevel.Informational. + /// + /// Example: void OnPhotonCreateRoomFailed() { ... } + /// + /// Example: void OnPhotonCreateRoomFailed(object[] codeAndMsg) { // codeAndMsg[0] is short ErrorCode. codeAndMsg[1] is string debug msg. } + /// + OnPhotonCreateRoomFailed, + + /// + /// Called when a JoinRoom() call failed. Optional parameters provide ErrorCode and message. + /// + /// + /// Most likely error is that the room does not exist or the room is full (some other client was faster than you). + /// PUN logs some info if the PhotonNetwork.logLevel is >= PhotonLogLevel.Informational. + /// + /// Example: void OnPhotonJoinRoomFailed() { ... } + /// + /// Example: void OnPhotonJoinRoomFailed(object[] codeAndMsg) { // codeAndMsg[0] is short ErrorCode. codeAndMsg[1] is string debug msg. } + /// + OnPhotonJoinRoomFailed, + + /// + /// Called when this client created a room and entered it. OnJoinedRoom() will be called as well. + /// + /// + /// This callback is only called on the client which created a room (see PhotonNetwork.CreateRoom). + /// + /// As any client might close (or drop connection) anytime, there is a chance that the + /// creator of a room does not execute OnCreatedRoom. + /// + /// If you need specific room properties or a "start signal", it is safer to implement + /// OnMasterClientSwitched() and to make the new MasterClient check the room's state. + /// + /// Example: void OnCreatedRoom() { ... } + /// + OnCreatedRoom, + + /// + /// Called on entering a lobby on the Master Server. The actual room-list updates will call OnReceivedRoomListUpdate(). + /// + /// + /// Note: When PhotonNetwork.autoJoinLobby is false, OnConnectedToMaster() will be called and the room list won't become available. + /// + /// While in the lobby, the roomlist is automatically updated in fixed intervals (which you can't modify). + /// The room list gets available when OnReceivedRoomListUpdate() gets called after OnJoinedLobby(). + /// + /// Example: void OnJoinedLobby() { ... } + /// + OnJoinedLobby, + + /// + /// Called after leaving a lobby. + /// + /// + /// When you leave a lobby, [CreateRoom](@ref PhotonNetwork.CreateRoom) and [JoinRandomRoom](@ref PhotonNetwork.JoinRandomRoom) + /// automatically refer to the default lobby. + /// + /// Example: void OnLeftLobby() { ... } + /// + OnLeftLobby, + + /// + /// Called after disconnecting from the Photon server. + /// + /// + /// In some cases, other callbacks are called before OnDisconnectedFromPhoton is called. + /// Examples: OnConnectionFail() and OnFailedToConnectToPhoton(). + /// + /// Example: void OnDisconnectedFromPhoton() { ... } + /// + OnDisconnectedFromPhoton, + + /// + /// Called when something causes the connection to fail (after it was established), followed by a call to OnDisconnectedFromPhoton(). + /// + /// + /// If the server could not be reached in the first place, OnFailedToConnectToPhoton is called instead. + /// The reason for the error is provided as StatusCode. + /// + /// Example: void OnConnectionFail(DisconnectCause cause) { ... } + /// + OnConnectionFail, + + /// + /// Called if a connect call to the Photon server failed before the connection was established, followed by a call to OnDisconnectedFromPhoton(). + /// + /// + /// OnConnectionFail only gets called when a connection to a Photon server was established in the first place. + /// + /// Example: void OnFailedToConnectToPhoton(DisconnectCause cause) { ... } + /// + OnFailedToConnectToPhoton, + + /// + /// Called for any update of the room-listing while in a lobby (PhotonNetwork.insideLobby) on the Master Server. + /// + /// + /// PUN provides the list of rooms by PhotonNetwork.GetRoomList().
+ /// Each item is a RoomInfo which might include custom properties (provided you defined those as lobby-listed when creating a room). + /// + /// Not all types of lobbies provide a listing of rooms to the client. Some are silent and specialized for server-side matchmaking. + /// + /// Example: void OnReceivedRoomListUpdate() { ... } + ///
+ OnReceivedRoomListUpdate, + + /// + /// Called when entering a room (by creating or joining it). Called on all clients (including the Master Client). + /// + /// + /// This method is commonly used to instantiate player characters. + /// If a match has to be started "actively", you can instead call an [PunRPC](@ref PhotonView.RPC) triggered by a user's button-press or a timer. + /// + /// When this is called, you can usually already access the existing players in the room via PhotonNetwork.playerList. + /// Also, all custom properties should be already available as Room.customProperties. Check Room.playerCount to find out if + /// enough players are in the room to start playing. + /// + /// Example: void OnJoinedRoom() { ... } + /// + OnJoinedRoom, + + /// + /// Called when a remote player entered the room. This PhotonPlayer is already added to the playerlist at this time. + /// + /// + /// If your game starts with a certain number of players, this callback can be useful to check the + /// Room.playerCount and find out if you can start. + /// + /// Example: void OnPhotonPlayerConnected(PhotonPlayer newPlayer) { ... } + /// + OnPhotonPlayerConnected, + + /// + /// Called when a remote player left the room. This PhotonPlayer is already removed from the playerlist at this time. + /// + /// + /// When your client calls PhotonNetwork.leaveRoom, PUN will call this method on the remaining clients. + /// When a remote client drops connection or gets closed, this callback gets executed. after a timeout + /// of several seconds. + /// + /// Example: void OnPhotonPlayerDisconnected(PhotonPlayer otherPlayer) { ... } + /// + OnPhotonPlayerDisconnected, + + /// + /// Called after a JoinRandom() call failed. Optional parameters provide ErrorCode and message. + /// + /// + /// Most likely all rooms are full or no rooms are available. + /// When using multiple lobbies (via JoinLobby or TypedLobby), another lobby might have more/fitting rooms. + /// PUN logs some info if the PhotonNetwork.logLevel is >= PhotonLogLevel.Informational. + /// + /// Example: void OnPhotonRandomJoinFailed() { ... } + /// + /// Example: void OnPhotonRandomJoinFailed(object[] codeAndMsg) { // codeAndMsg[0] is short ErrorCode. codeAndMsg[1] is string debug msg. } + /// + OnPhotonRandomJoinFailed, + + /// + /// Called after the connection to the master is established and authenticated but only when PhotonNetwork.autoJoinLobby is false. + /// + /// + /// If you set PhotonNetwork.autoJoinLobby to true, OnJoinedLobby() will be called instead of this. + /// + /// You can join rooms and create them even without being in a lobby. The default lobby is used in that case. + /// The list of available rooms won't become available unless you join a lobby via PhotonNetwork.joinLobby. + /// + /// Example: void OnConnectedToMaster() { ... } + /// + OnConnectedToMaster, + + /// + /// Implement to customize the data a PhotonView regularly synchronizes. Called every 'network-update' when observed by PhotonView. + /// + /// + /// This method will be called in scripts that are assigned as Observed component of a PhotonView. + /// PhotonNetwork.sendRateOnSerialize affects how often this method is called. + /// PhotonNetwork.sendRate affects how often packages are sent by this client. + /// + /// Implementing this method, you can customize which data a PhotonView regularly synchronizes. + /// Your code defines what is being sent (content) and how your data is used by receiving clients. + /// + /// Unlike other callbacks, OnPhotonSerializeView only gets called when it is assigned + /// to a PhotonView as PhotonView.observed script. + /// + /// To make use of this method, the PhotonStream is essential. It will be in "writing" mode" on the + /// client that controls a PhotonView (PhotonStream.isWriting == true) and in "reading mode" on the + /// remote clients that just receive that the controlling client sends. + /// + /// If you skip writing any value into the stream, PUN will skip the update. Used carefully, this can + /// conserve bandwidth and messages (which have a limit per room/second). + /// + /// Note that OnPhotonSerializeView is not called on remote clients when the sender does not send + /// any update. This can't be used as "x-times per second Update()". + /// + /// Example: void OnPhotonSerializeView(PhotonStream stream, PhotonMessageInfo info) { ... } + /// + OnPhotonSerializeView, + + /// + /// Called on all scripts on a GameObject (and children) that have been Instantiated using PhotonNetwork.Instantiate. + /// + /// + /// PhotonMessageInfo parameter provides info about who created the object and when (based off PhotonNetworking.time). + /// + /// Example: void OnPhotonInstantiate(PhotonMessageInfo info) { ... } + /// + OnPhotonInstantiate, + + /// + /// Because the concurrent user limit was (temporarily) reached, this client is rejected by the server and disconnecting. + /// + /// + /// When this happens, the user might try again later. You can't create or join rooms in OnPhotonMaxCcuReached(), cause the client will be disconnecting. + /// You can raise the CCU limits with a new license (when you host yourself) or extended subscription (when using the Photon Cloud). + /// The Photon Cloud will mail you when the CCU limit was reached. This is also visible in the Dashboard (webpage). + /// + /// Example: void OnPhotonMaxCccuReached() { ... } + /// + OnPhotonMaxCccuReached, + + /// + /// Called when a room's custom properties changed. The propertiesThatChanged contains all that was set via Room.SetCustomProperties. + /// + /// + /// Since v1.25 this method has one parameter: Hashtable propertiesThatChanged. + /// Changing properties must be done by Room.SetCustomProperties, which causes this callback locally, too. + /// + /// Example: void OnPhotonCustomRoomPropertiesChanged(Hashtable propertiesThatChanged) { ... } + /// + OnPhotonCustomRoomPropertiesChanged, + + /// + /// Called when custom player-properties are changed. Player and the changed properties are passed as object[]. + /// + /// + /// Since v1.25 this method has one parameter: object[] playerAndUpdatedProps, which contains two entries.
+ /// [0] is the affected PhotonPlayer.
+ /// [1] is the Hashtable of properties that changed.
+ /// + /// We are using a object[] due to limitations of Unity's GameObject.SendMessage (which has only one optional parameter). + /// + /// Changing properties must be done by PhotonPlayer.SetCustomProperties, which causes this callback locally, too. + /// + /// Example:
+    /// void OnPhotonPlayerPropertiesChanged(object[] playerAndUpdatedProps) {
+    ///     PhotonPlayer player = playerAndUpdatedProps[0] as PhotonPlayer;
+    ///     Hashtable props = playerAndUpdatedProps[1] as Hashtable;
+    ///     //...
+    /// }
+ ///
+ OnPhotonPlayerPropertiesChanged, + + /// + /// Called when the server sent the response to a FindFriends request and updated PhotonNetwork.Friends. + /// + /// + /// The friends list is available as PhotonNetwork.Friends, listing name, online state and + /// the room a user is in (if any). + /// + /// Example: void OnUpdatedFriendList() { ... } + /// + OnUpdatedFriendList, + + /// + /// Called when the custom authentication failed. Followed by disconnect! + /// + /// + /// Custom Authentication can fail due to user-input, bad tokens/secrets. + /// If authentication is successful, this method is not called. Implement OnJoinedLobby() or OnConnectedToMaster() (as usual). + /// + /// During development of a game, it might also fail due to wrong configuration on the server side. + /// In those cases, logging the debugMessage is very important. + /// + /// Unless you setup a custom authentication service for your app (in the [Dashboard](https://www.photonengine.com/dashboard)), + /// this won't be called! + /// + /// Example: void OnCustomAuthenticationFailed(string debugMessage) { ... } + /// + OnCustomAuthenticationFailed, + + /// + /// Called when your Custom Authentication service responds with additional data. + /// + /// + /// Custom Authentication services can include some custom data in their response. + /// When present, that data is made available in this callback as Dictionary. + /// While the keys of your data have to be strings, the values can be either string or a number (in Json). + /// You need to make extra sure, that the value type is the one you expect. Numbers become (currently) int64. + /// + /// Example: void OnCustomAuthenticationResponse(Dictionary<string, object> data) { ... } + /// + /// + OnCustomAuthenticationResponse, + + /// + /// Called by PUN when the response to a WebRPC is available. See PhotonNetwork.WebRPC. + /// + /// + /// Important: The response.ReturnCode is 0 if Photon was able to reach your web-service. + /// The content of the response is what your web-service sent. You can create a WebResponse instance from it. + /// Example: WebRpcResponse webResponse = new WebRpcResponse(operationResponse); + /// + /// Please note: Class OperationResponse is in a namespace which needs to be "used": + /// using ExitGames.Client.Photon; // includes OperationResponse (and other classes) + /// + /// The OperationResponse.ReturnCode by Photon is: + /// 0 for "OK" + /// -3 for "Web-Service not configured" (see Dashboard / WebHooks) + /// -5 for "Web-Service does now have RPC path/name" (at least for Azure) + /// + /// Example: void OnWebRpcResponse(OperationResponse response) { ... } + /// + OnWebRpcResponse, + + /// + /// Called when another player requests ownership of a PhotonView from you (the current owner). + /// + /// + /// The parameter viewAndPlayer contains: + /// + /// PhotonView view = viewAndPlayer[0] as PhotonView; + /// + /// PhotonPlayer requestingPlayer = viewAndPlayer[1] as PhotonPlayer; + /// + /// void OnOwnershipRequest(object[] viewAndPlayer) {} // + OnOwnershipRequest, + + /// + /// Called when the Master Server sent an update for the Lobby Statistics, updating PhotonNetwork.LobbyStatistics. + /// + /// + /// This callback has two preconditions: + /// EnableLobbyStatistics must be set to true, before this client connects. + /// And the client has to be connected to the Master Server, which is providing the info about lobbies. + /// + OnLobbyStatisticsUpdate, + + + /// + /// Called when a remote Photon Player activity changed. This will be called ONLY is PlayerTtl is greater then 0. + /// + /// Use PhotonPlayer.IsInactive to check the current activity state + /// + /// Example: void OnPhotonPlayerActivityChanged(PhotonPlayer otherPlayer) {...} + /// + /// + /// This callback has precondition: + /// PlayerTtl must be greater then 0 + /// + OnPhotonPlayerActivityChanged, + + + /// + /// Called when a PhotonView Owner is transfered to a Player. + /// + /// + /// The parameter viewAndPlayers contains: + /// + /// PhotonView view = viewAndPlayers[0] as PhotonView; + /// + /// PhotonPlayer newOwner = viewAndPlayers[1] as PhotonPlayer; + /// + /// PhotonPlayer oldOwner = viewAndPlayers[2] as PhotonPlayer; + /// + /// void OnOwnershipTransfered(object[] viewAndPlayers) {} // + OnOwnershipTransfered, +} + + +/// Used to define the level of logging output created by the PUN classes. Either log errors, info (some more) or full. +/// \ingroup publicApi +public enum PhotonLogLevel +{ + /// Show only errors. Minimal output. Note: Some might be "runtime errors" which you have to expect. + ErrorsOnly, + /// Logs some of the workflow, calls and results. + Informational, + /// Every available log call gets into the console/log. Only use for debugging. + Full +} + + +/// Enum of "target" options for RPCs. These define which remote clients get your RPC call. +/// \ingroup publicApi +public enum PhotonTargets +{ + /// Sends the RPC to everyone else and executes it immediately on this client. Player who join later will not execute this RPC. + All, + /// Sends the RPC to everyone else. This client does not execute the RPC. Player who join later will not execute this RPC. + Others, + /// Sends the RPC to MasterClient only. Careful: The MasterClient might disconnect before it executes the RPC and that might cause dropped RPCs. + MasterClient, + /// Sends the RPC to everyone else and executes it immediately on this client. New players get the RPC when they join as it's buffered (until this client leaves). + AllBuffered, + /// Sends the RPC to everyone. This client does not execute the RPC. New players get the RPC when they join as it's buffered (until this client leaves). + OthersBuffered, + /// Sends the RPC to everyone (including this client) through the server. + /// + /// This client executes the RPC like any other when it received it from the server. + /// Benefit: The server's order of sending the RPCs is the same on all clients. + /// + AllViaServer, + /// Sends the RPC to everyone (including this client) through the server and buffers it for players joining later. + /// + /// This client executes the RPC like any other when it received it from the server. + /// Benefit: The server's order of sending the RPCs is the same on all clients. + /// + AllBufferedViaServer +} + + +/// Currently available Photon Cloud regions as enum. +/// +/// This is used in PhotonNetwork.ConnectToRegion. +/// +public enum CloudRegionCode +{ + /// European servers in Amsterdam. + eu = 0, + /// US servers (East Coast). + us = 1, + /// Asian servers in Singapore. + asia = 2, + /// Japanese servers in Tokyo. + jp = 3, + /// Australian servers in Melbourne. + au = 5, + ///USA West, San José, usw + usw = 6, + ///South America, Sao Paulo, sa + sa = 7, + ///Canada East, Montreal, cae + cae = 8, + ///South Korea, Seoul, kr + kr = 9, + ///India, Chennai, in + @in = 10, + + /// No region selected. + none = 4 +}; + + +/// +/// Available regions as enum of flags. To be used as "enabled" flags for Best Region pinging. +/// +/// Note that these enum values skip CloudRegionCode.none and their values are in strict order (power of 2). +[Flags] +public enum CloudRegionFlag +{ + eu = 1 << 0, + us = 1 << 1, + asia = 1 << 2, + jp = 1 << 3, + au = 1 << 4, + usw = 1 << 5, + sa = 1 << 6, + cae = 1 << 7, + kr = 1 << 8, + @in = 1 << 9, +}; + + +/// +/// High level connection state of the client. Better use the more detailed . +/// +public enum ConnectionState +{ + Disconnected, + Connecting, + Connected, + Disconnecting, + InitializingApplication +} + + +/// +/// Defines how the communication gets encrypted. +/// +public enum EncryptionMode +{ + /// + /// This is the default encryption mode: Messages get encrypted only on demand (when you send operations with the "encrypt" parameter set to true). + /// + PayloadEncryption, + /// + /// With this encryption mode for UDP, the connection gets setup and all further datagrams get encrypted almost entirely. On-demand message encryption (like in PayloadEncryption) is skipped. + /// + /// + /// This mode requires AuthOnce or AuthOnceWss as AuthMode! + /// + DatagramEncryption = 10, +} + + +public static class EncryptionDataParameters +{ + /// + /// Key for encryption mode + /// + public const byte Mode = 0; + /// + /// Key for first secret + /// + public const byte Secret1 = 1; + /// + /// Key for second secret + /// + public const byte Secret2 = 2; +} \ No newline at end of file diff --git a/Assets/Photon Unity Networking/Plugins/PhotonNetwork/Enums.cs.meta b/Assets/Photon Unity Networking/Plugins/PhotonNetwork/Enums.cs.meta new file mode 100644 index 0000000..d612c91 --- /dev/null +++ b/Assets/Photon Unity Networking/Plugins/PhotonNetwork/Enums.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: b7962bbdaba2a4940b1341d755abd40d +labels: +- ExitGames +- PUN +- Photon +- Networking +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} diff --git a/Assets/Photon Unity Networking/Plugins/PhotonNetwork/Extensions.cs b/Assets/Photon Unity Networking/Plugins/PhotonNetwork/Extensions.cs new file mode 100644 index 0000000..6359599 --- /dev/null +++ b/Assets/Photon Unity Networking/Plugins/PhotonNetwork/Extensions.cs @@ -0,0 +1,246 @@ +// ---------------------------------------------------------------------------- +// +// PhotonNetwork Framework for Unity - Copyright (C) 2011 Exit Games GmbH +// +// +// Provides some helpful methods and extensions for Hashtables, etc. +// +// developer@exitgames.com +// ---------------------------------------------------------------------------- + +using System.Collections; +using System.Collections.Generic; +using System.Reflection; +using UnityEngine; +using Hashtable = ExitGames.Client.Photon.Hashtable; +using SupportClassPun = ExitGames.Client.Photon.SupportClass; + + +/// +/// This static class defines some useful extension methods for several existing classes (e.g. Vector3, float and others). +/// +public static class Extensions +{ + + public static Dictionary ParametersOfMethods = new Dictionary(); + public static ParameterInfo[] GetCachedParemeters(this MethodInfo mo) + { + ParameterInfo[] result; + bool cached= ParametersOfMethods.TryGetValue(mo, out result); + + if (!cached) + { + result = mo.GetParameters(); + ParametersOfMethods[mo] = result; + } + + return result; + } + + public static PhotonView[] GetPhotonViewsInChildren(this UnityEngine.GameObject go) + { + return go.GetComponentsInChildren(true) as PhotonView[]; + } + + public static PhotonView GetPhotonView(this UnityEngine.GameObject go) + { + return go.GetComponent() as PhotonView; + } + + /// compares the squared magnitude of target - second to given float value + public static bool AlmostEquals(this Vector3 target, Vector3 second, float sqrMagnitudePrecision) + { + return (target - second).sqrMagnitude < sqrMagnitudePrecision; // TODO: inline vector methods to optimize? + } + + /// compares the squared magnitude of target - second to given float value + public static bool AlmostEquals(this Vector2 target, Vector2 second, float sqrMagnitudePrecision) + { + return (target - second).sqrMagnitude < sqrMagnitudePrecision; // TODO: inline vector methods to optimize? + } + + /// compares the angle between target and second to given float value + public static bool AlmostEquals(this Quaternion target, Quaternion second, float maxAngle) + { + return Quaternion.Angle(target, second) < maxAngle; + } + + /// compares two floats and returns true of their difference is less than floatDiff + public static bool AlmostEquals(this float target, float second, float floatDiff) + { + return Mathf.Abs(target - second) < floatDiff; + } + + /// + /// Merges all keys from addHash into the target. Adds new keys and updates the values of existing keys in target. + /// + /// The IDictionary to update. + /// The IDictionary containing data to merge into target. + public static void Merge(this IDictionary target, IDictionary addHash) + { + if (addHash == null || target.Equals(addHash)) + { + return; + } + + foreach (object key in addHash.Keys) + { + target[key] = addHash[key]; + } + } + + /// + /// Merges keys of type string to target Hashtable. + /// + /// + /// Does not remove keys from target (so non-string keys CAN be in target if they were before). + /// + /// The target IDicitionary passed in plus all string-typed keys from the addHash. + /// A IDictionary that should be merged partly into target to update it. + public static void MergeStringKeys(this IDictionary target, IDictionary addHash) + { + if (addHash == null || target.Equals(addHash)) + { + return; + } + + foreach (object key in addHash.Keys) + { + // only merge keys of type string + if (key is string) + { + target[key] = addHash[key]; + } + } + } + + /// Helper method for debugging of IDictionary content, inlcuding type-information. Using this is not performant. + /// Should only be used for debugging as necessary. + /// Some Dictionary or Hashtable. + /// String of the content of the IDictionary. + public static string ToStringFull(this IDictionary origin) + { + return SupportClassPun.DictionaryToString(origin, false); + } + + + /// Helper method for debugging of object[] content. Using this is not performant. + /// Should only be used for debugging as necessary. + /// Any object[]. + /// A comma-separated string containing each value's ToString(). + public static string ToStringFull(this object[] data) + { + if (data == null) return "null"; + + string[] sb = new string[data.Length]; + for (int i = 0; i < data.Length; i++) + { + object o = data[i]; + sb[i] = (o != null) ? o.ToString() : "null"; + } + + return string.Join(", ", sb); + } + + + /// + /// This method copies all string-typed keys of the original into a new Hashtable. + /// + /// + /// Does not recurse (!) into hashes that might be values in the root-hash. + /// This does not modify the original. + /// + /// The original IDictonary to get string-typed keys from. + /// New Hashtable containing only string-typed keys of the original. + public static Hashtable StripToStringKeys(this IDictionary original) + { + Hashtable target = new Hashtable(); + if (original != null) + { + foreach (object key in original.Keys) + { + if (key is string) + { + target[key] = original[key]; + } + } + } + + return target; + } + + /// + /// This removes all key-value pairs that have a null-reference as value. + /// Photon properties are removed by setting their value to null. + /// Changes the original passed IDictionary! + /// + /// The IDictionary to strip of keys with null-values. + public static void StripKeysWithNullValues(this IDictionary original) + { + object[] keys = new object[original.Count]; + //original.Keys.CopyTo(keys, 0); // todo: figure out which platform didn't support this + int i = 0; + foreach (object k in original.Keys) + { + keys[i++] = k; + } + + for (int index = 0; index < keys.Length; index++) + { + var key = keys[index]; + if (original[key] == null) + { + original.Remove(key); + } + } + } + + /// + /// Checks if a particular integer value is in an int-array. + /// + /// This might be useful to look up if a particular actorNumber is in the list of players of a room. + /// The array of ints to check. + /// The number to lookup in target. + /// True if nr was found in target. + public static bool Contains(this int[] target, int nr) + { + if (target == null) + { + return false; + } + + for (int index = 0; index < target.Length; index++) + { + if (target[index] == nr) + { + return true; + } + } + + return false; + } +} + + +/// Small number of extension methods that make it easier for PUN to work cross-Unity-versions. +public static class GameObjectExtensions +{ + /// Unity-version-independent replacement for active GO property. + /// Unity 3.5: active. Any newer Unity: activeInHierarchy. + public static bool GetActive(this GameObject target) + { + #if UNITY_3_5 + return target.active; + #else + return target.activeInHierarchy; + #endif + } + + #if UNITY_3_5 + /// Unity-version-independent setter for active and SetActive(). + public static void SetActive(this GameObject target, bool value) + { + target.active = value; + } + #endif +} diff --git a/Assets/Photon Unity Networking/Plugins/PhotonNetwork/Extensions.cs.meta b/Assets/Photon Unity Networking/Plugins/PhotonNetwork/Extensions.cs.meta new file mode 100644 index 0000000..2025f00 --- /dev/null +++ b/Assets/Photon Unity Networking/Plugins/PhotonNetwork/Extensions.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 3c0464991e33a70498abdd85c150cc59 +labels: +- ExitGames +- PUN +- Photon +- Networking +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} diff --git a/Assets/Photon Unity Networking/Plugins/PhotonNetwork/FriendInfo.cs b/Assets/Photon Unity Networking/Plugins/PhotonNetwork/FriendInfo.cs new file mode 100644 index 0000000..112cad5 --- /dev/null +++ b/Assets/Photon Unity Networking/Plugins/PhotonNetwork/FriendInfo.cs @@ -0,0 +1,26 @@ +// ---------------------------------------------------------------------------- +// +// Loadbalancing Framework for Photon - Copyright (C) 2013 Exit Games GmbH +// +// +// Collection of values related to a user / friend. +// +// developer@photonengine.com +// ---------------------------------------------------------------------------- + + +/// +/// Used to store info about a friend's online state and in which room he/she is. +/// +public class FriendInfo +{ + public string Name { get; internal protected set; } + public bool IsOnline { get; internal protected set; } + public string Room { get; internal protected set; } + public bool IsInRoom { get { return IsOnline && !string.IsNullOrEmpty(this.Room); } } + + public override string ToString() + { + return string.Format("{0}\t is: {1}", this.Name, (!this.IsOnline) ? "offline" : this.IsInRoom ? "playing" : "on master"); + } +} diff --git a/Assets/Photon Unity Networking/Plugins/PhotonNetwork/FriendInfo.cs.meta b/Assets/Photon Unity Networking/Plugins/PhotonNetwork/FriendInfo.cs.meta new file mode 100644 index 0000000..b810efc --- /dev/null +++ b/Assets/Photon Unity Networking/Plugins/PhotonNetwork/FriendInfo.cs.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 94ba1138c322ea04c8c37cfbcf87f468 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} diff --git a/Assets/Photon Unity Networking/Plugins/PhotonNetwork/GizmoType.cs b/Assets/Photon Unity Networking/Plugins/PhotonNetwork/GizmoType.cs new file mode 100644 index 0000000..0cf7cee --- /dev/null +++ b/Assets/Photon Unity Networking/Plugins/PhotonNetwork/GizmoType.cs @@ -0,0 +1,36 @@ +using UnityEngine; + +namespace ExitGames.Client.GUI +{ + public enum GizmoType + { + WireSphere, + Sphere, + WireCube, + Cube, + } + + public class GizmoTypeDrawer + { + public static void Draw( Vector3 center, GizmoType type, Color color, float size ) + { + Gizmos.color = color; + + switch( type ) + { + case GizmoType.Cube: + Gizmos.DrawCube( center, Vector3.one * size ); + break; + case GizmoType.Sphere: + Gizmos.DrawSphere( center, size * 0.5f ); + break; + case GizmoType.WireCube: + Gizmos.DrawWireCube( center, Vector3.one * size ); + break; + case GizmoType.WireSphere: + Gizmos.DrawWireSphere( center, size * 0.5f ); + break; + } + } + } +} \ No newline at end of file diff --git a/Assets/Photon Unity Networking/Plugins/PhotonNetwork/GizmoType.cs.meta b/Assets/Photon Unity Networking/Plugins/PhotonNetwork/GizmoType.cs.meta new file mode 100644 index 0000000..a96a3c7 --- /dev/null +++ b/Assets/Photon Unity Networking/Plugins/PhotonNetwork/GizmoType.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: a744e8c91e32ce742b8f79e048a8714a +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Photon Unity Networking/Plugins/PhotonNetwork/LoadbalancingPeer.cs b/Assets/Photon Unity Networking/Plugins/PhotonNetwork/LoadbalancingPeer.cs new file mode 100644 index 0000000..8582f76 --- /dev/null +++ b/Assets/Photon Unity Networking/Plugins/PhotonNetwork/LoadbalancingPeer.cs @@ -0,0 +1,1873 @@ +// ---------------------------------------------------------------------------- +// +// Loadbalancing Framework for Photon - Copyright (C) 2016 Exit Games GmbH +// +// +// Provides operations to use the LoadBalancing and Cloud photon servers. +// No logic is implemented here. +// +// developer@photonengine.com +// ---------------------------------------------------------------------------- + +using System; +using System.Collections; +using System.Collections.Generic; +using ExitGames.Client.Photon; + +#if UNITY_4_0 || UNITY_4_1 || UNITY_4_2 || UNITY_4_3 || UNITY_4_4 || UNITY_4_5 || UNITY_4_6 || UNITY_4_7 || UNITY_5 || UNITY_5_0 || UNITY_5_1 || UNITY_2017 + using UnityEngine; + using Hashtable = ExitGames.Client.Photon.Hashtable; + using SupportClassPun = ExitGames.Client.Photon.SupportClass; +#endif + + + /// + /// A LoadbalancingPeer provides the operations and enum definitions needed to use the loadbalancing server application which is also used in Photon Cloud. + /// + /// + /// Internally used by PUN. + /// The LoadBalancingPeer does not keep a state, instead this is done by a LoadBalancingClient. + /// + internal class LoadBalancingPeer : PhotonPeer + { + + internal bool IsProtocolSecure + { + get { return this.UsedProtocol == ConnectionProtocol.WebSocketSecure; } + } + + private readonly Dictionary opParameters = new Dictionary(); // used in OpRaiseEvent() (avoids lots of new Dictionary() calls) + + + /// + /// Creates a Peer with specified connection protocol. You need to set the Listener before using the peer. + /// + /// Each connection protocol has it's own default networking ports for Photon. + /// The preferred option is UDP. + public LoadBalancingPeer(ConnectionProtocol protocolType) : base(protocolType) + { + // this does not require a Listener, so: + // make sure to set this.Listener before using a peer! + } + + /// + /// Creates a Peer with specified connection protocol and a Listener for callbacks. + /// + public LoadBalancingPeer(IPhotonPeerListener listener, ConnectionProtocol protocolType) : this(protocolType) + { + this.Listener = listener; + } + + public virtual bool OpGetRegions(string appId) + { + Dictionary parameters = new Dictionary(); + parameters[(byte)ParameterCode.ApplicationId] = appId; + + return this.OpCustom(OperationCode.GetRegions, parameters, true, 0, true); + } + + /// + /// Joins the lobby on the Master Server, where you get a list of RoomInfos of currently open rooms. + /// This is an async request which triggers a OnOperationResponse() call. + /// + /// The lobby join to. + /// If the operation could be sent (has to be connected). + public virtual bool OpJoinLobby(TypedLobby lobby = null) + { + if (this.DebugOut >= DebugLevel.INFO) + { + this.Listener.DebugReturn(DebugLevel.INFO, "OpJoinLobby()"); + } + + Dictionary parameters = null; + if (lobby != null && !lobby.IsDefault) + { + parameters = new Dictionary(); + parameters[(byte)ParameterCode.LobbyName] = lobby.Name; + parameters[(byte)ParameterCode.LobbyType] = (byte)lobby.Type; + } + + return this.OpCustom(OperationCode.JoinLobby, parameters, true); + } + + + /// + /// Leaves the lobby on the Master Server. + /// This is an async request which triggers a OnOperationResponse() call. + /// + /// If the operation could be sent (requires connection). + public virtual bool OpLeaveLobby() + { + if (this.DebugOut >= DebugLevel.INFO) + { + this.Listener.DebugReturn(DebugLevel.INFO, "OpLeaveLobby()"); + } + + return this.OpCustom(OperationCode.LeaveLobby, null, true); + } + + + /// Used in the RoomOptionFlags parameter, this bitmask toggles options in the room. + enum RoomOptionBit : int + { + CheckUserOnJoin = 0x01, // toggles a check of the UserId when joining (enabling returning to a game) + DeleteCacheOnLeave = 0x02, // deletes cache on leave + SuppressRoomEvents = 0x04, // suppresses all room events + PublishUserId = 0x08, // signals that we should publish userId + DeleteNullProps = 0x10, // signals that we should remove property if its value was set to null. see RoomOption to Delete Null Properties + BroadcastPropsChangeToAll = 0x20, // signals that we should send PropertyChanged event to all room players including initiator + } + + private void RoomOptionsToOpParameters(Dictionary op, RoomOptions roomOptions) + { + if (roomOptions == null) + { + roomOptions = new RoomOptions(); + } + + Hashtable gameProperties = new Hashtable(); + gameProperties[GamePropertyKey.IsOpen] = roomOptions.IsOpen; + gameProperties[GamePropertyKey.IsVisible] = roomOptions.IsVisible; + gameProperties[GamePropertyKey.PropsListedInLobby] = (roomOptions.CustomRoomPropertiesForLobby == null) ? new string[0] : roomOptions.CustomRoomPropertiesForLobby; + gameProperties.MergeStringKeys(roomOptions.CustomRoomProperties); + if (roomOptions.MaxPlayers > 0) + { + gameProperties[GamePropertyKey.MaxPlayers] = roomOptions.MaxPlayers; + } + op[ParameterCode.GameProperties] = gameProperties; + + + int flags = 0; // a new way to send the room options as bitwise-flags + op[ParameterCode.CleanupCacheOnLeave] = roomOptions.CleanupCacheOnLeave; // this is actually setting the room's config + if (roomOptions.CleanupCacheOnLeave) + { + flags = flags | (int)RoomOptionBit.DeleteCacheOnLeave; + gameProperties[GamePropertyKey.CleanupCacheOnLeave] = true; // this is only informational for the clients which join + } + + if (roomOptions.PlayerTtl > 0 || roomOptions.PlayerTtl == -1) + { + flags = flags | (int)RoomOptionBit.CheckUserOnJoin; + op[ParameterCode.CheckUserOnJoin] = true; // this affects rejoining a room. requires a userId to be used. added in v1.67 + op[ParameterCode.PlayerTTL] = roomOptions.PlayerTtl; // TURNBASED + } + + if (roomOptions.EmptyRoomTtl > 0) + { + op[ParameterCode.EmptyRoomTTL] = roomOptions.EmptyRoomTtl; //TURNBASED + } + + if (roomOptions.SuppressRoomEvents) + { + flags = flags | (int)RoomOptionBit.SuppressRoomEvents; + op[ParameterCode.SuppressRoomEvents] = true; + } + if (roomOptions.Plugins != null) + { + op[ParameterCode.Plugins] = roomOptions.Plugins; + } + if (roomOptions.PublishUserId) + { + flags = flags | (int)RoomOptionBit.PublishUserId; + op[ParameterCode.PublishUserId] = true; + } + if (roomOptions.DeleteNullProperties) + { + flags = flags | (int)RoomOptionBit.DeleteNullProps; // this is only settable as flag + } + + op[ParameterCode.RoomOptionFlags] = flags; + } + + + /// + /// Creates a room (on either Master or Game Server). + /// The OperationResponse depends on the server the peer is connected to: + /// Master will return a Game Server to connect to. + /// Game Server will return the joined Room's data. + /// This is an async request which triggers a OnOperationResponse() call. + /// + /// + /// If the room is already existing, the OperationResponse will have a returnCode of ErrorCode.GameAlreadyExists. + /// + public virtual bool OpCreateRoom(EnterRoomParams opParams) + { + if (this.DebugOut >= DebugLevel.INFO) + { + this.Listener.DebugReturn(DebugLevel.INFO, "OpCreateRoom()"); + } + + Dictionary op = new Dictionary(); + + if (!string.IsNullOrEmpty(opParams.RoomName)) + { + op[ParameterCode.RoomName] = opParams.RoomName; + } + if (opParams.Lobby != null && !string.IsNullOrEmpty(opParams.Lobby.Name)) + { + op[ParameterCode.LobbyName] = opParams.Lobby.Name; + op[ParameterCode.LobbyType] = (byte)opParams.Lobby.Type; + } + + if (opParams.ExpectedUsers != null && opParams.ExpectedUsers.Length > 0) + { + op[ParameterCode.Add] = opParams.ExpectedUsers; + } + if (opParams.OnGameServer) + { + if (opParams.PlayerProperties != null && opParams.PlayerProperties.Count > 0) + { + op[ParameterCode.PlayerProperties] = opParams.PlayerProperties; + op[ParameterCode.Broadcast] = true; // TODO: check if this also makes sense when creating a room?! // broadcast actor properties + } + + this.RoomOptionsToOpParameters(op, opParams.RoomOptions); + } + + //UnityEngine.Debug.Log("CreateRoom: " + SupportClassPun.DictionaryToString(op)); + return this.OpCustom(OperationCode.CreateGame, op, true); + } + + /// + /// Joins a room by name or creates new room if room with given name not exists. + /// The OperationResponse depends on the server the peer is connected to: + /// Master will return a Game Server to connect to. + /// Game Server will return the joined Room's data. + /// This is an async request which triggers a OnOperationResponse() call. + /// + /// + /// If the room is not existing (anymore), the OperationResponse will have a returnCode of ErrorCode.GameDoesNotExist. + /// Other possible ErrorCodes are: GameClosed, GameFull. + /// + /// If the operation could be sent (requires connection). + public virtual bool OpJoinRoom(EnterRoomParams opParams) + { + if (this.DebugOut >= DebugLevel.INFO) + { + this.Listener.DebugReturn(DebugLevel.INFO, "OpJoinRoom()"); + } + Dictionary op = new Dictionary(); + + if (!string.IsNullOrEmpty(opParams.RoomName)) + { + op[ParameterCode.RoomName] = opParams.RoomName; + } + + if (opParams.CreateIfNotExists) + { + op[ParameterCode.JoinMode] = (byte)JoinMode.CreateIfNotExists; + if (opParams.Lobby != null) + { + op[ParameterCode.LobbyName] = opParams.Lobby.Name; + op[ParameterCode.LobbyType] = (byte)opParams.Lobby.Type; + } + } + + if (opParams.RejoinOnly) + { + op[ParameterCode.JoinMode] = (byte)JoinMode.RejoinOnly; // changed from JoinMode.JoinOrRejoin + } + + if (opParams.ExpectedUsers != null && opParams.ExpectedUsers.Length > 0) + { + op[ParameterCode.Add] = opParams.ExpectedUsers; + } + + if (opParams.OnGameServer) + { + if (opParams.PlayerProperties != null && opParams.PlayerProperties.Count > 0) + { + op[ParameterCode.PlayerProperties] = opParams.PlayerProperties; + op[ParameterCode.Broadcast] = true; // broadcast actor properties + } + + if (opParams.CreateIfNotExists) + { + this.RoomOptionsToOpParameters(op, opParams.RoomOptions); + } + } + + // UnityEngine.Debug.Log("JoinRoom: " + SupportClassPun.DictionaryToString(op)); + return this.OpCustom(OperationCode.JoinGame, op, true); + } + + + /// + /// Operation to join a random, available room. Overloads take additional player properties. + /// This is an async request which triggers a OnOperationResponse() call. + /// If all rooms are closed or full, the OperationResponse will have a returnCode of ErrorCode.NoRandomMatchFound. + /// If successful, the OperationResponse contains a gameserver address and the name of some room. + /// + /// If the operation could be sent currently (requires connection). + public virtual bool OpJoinRandomRoom(OpJoinRandomRoomParams opJoinRandomRoomParams) + { + if (this.DebugOut >= DebugLevel.INFO) + { + this.Listener.DebugReturn(DebugLevel.INFO, "OpJoinRandomRoom()"); + } + + Hashtable expectedRoomProperties = new Hashtable(); + expectedRoomProperties.MergeStringKeys(opJoinRandomRoomParams.ExpectedCustomRoomProperties); + if (opJoinRandomRoomParams.ExpectedMaxPlayers > 0) + { + expectedRoomProperties[GamePropertyKey.MaxPlayers] = opJoinRandomRoomParams.ExpectedMaxPlayers; + } + + Dictionary opParameters = new Dictionary(); + if (expectedRoomProperties.Count > 0) + { + opParameters[ParameterCode.GameProperties] = expectedRoomProperties; + } + + if (opJoinRandomRoomParams.MatchingType != MatchmakingMode.FillRoom) + { + opParameters[ParameterCode.MatchMakingType] = (byte)opJoinRandomRoomParams.MatchingType; + } + + if (opJoinRandomRoomParams.TypedLobby != null && !string.IsNullOrEmpty(opJoinRandomRoomParams.TypedLobby.Name)) + { + opParameters[ParameterCode.LobbyName] = opJoinRandomRoomParams.TypedLobby.Name; + opParameters[ParameterCode.LobbyType] = (byte)opJoinRandomRoomParams.TypedLobby.Type; + } + + if (!string.IsNullOrEmpty(opJoinRandomRoomParams.SqlLobbyFilter)) + { + opParameters[ParameterCode.Data] = opJoinRandomRoomParams.SqlLobbyFilter; + } + + if (opJoinRandomRoomParams.ExpectedUsers != null && opJoinRandomRoomParams.ExpectedUsers.Length > 0) + { + opParameters[ParameterCode.Add] = opJoinRandomRoomParams.ExpectedUsers; + } + + // UnityEngine.Debug.LogWarning("OpJoinRandom: " + opParameters.ToStringFull()); + return this.OpCustom(OperationCode.JoinRandomGame, opParameters, true); + } + + + /// + /// Leaves a room with option to come back later or "for good". + /// + /// Async games can be re-joined (loaded) later on. Set to false, if you want to abandon a game entirely. + /// If the opteration can be send currently. + public virtual bool OpLeaveRoom(bool becomeInactive) + { + Dictionary opParameters = new Dictionary(); + if (becomeInactive) + { + opParameters[ParameterCode.IsInactive] = becomeInactive; + } + return this.OpCustom(OperationCode.Leave, opParameters, true); + } + + /// Gets a list of games matching a SQL-like where clause. + /// + /// Operation is only available in lobbies of type SqlLobby. + /// This is an async request which triggers a OnOperationResponse() call. + /// Returned game list is stored in RoomInfoList. + /// + /// + /// The lobby to query. Has to be of type SqlLobby. + /// The sql query statement. + /// If the operation could be sent (has to be connected). + public virtual bool OpGetGameList(TypedLobby lobby, string queryData) + { + if (this.DebugOut >= DebugLevel.INFO) + { + this.Listener.DebugReturn(DebugLevel.INFO, "OpGetGameList()"); + } + + if (lobby == null) + { + if (this.DebugOut >= DebugLevel.INFO) + { + this.Listener.DebugReturn(DebugLevel.INFO, "OpGetGameList not sent. Lobby cannot be null."); + } + return false; + } + + if (lobby.Type != LobbyType.SqlLobby) + { + if (this.DebugOut >= DebugLevel.INFO) + { + this.Listener.DebugReturn(DebugLevel.INFO, "OpGetGameList not sent. LobbyType must be SqlLobby."); + } + return false; + } + + Dictionary opParameters = new Dictionary(); + opParameters[(byte)ParameterCode.LobbyName] = lobby.Name; + opParameters[(byte)ParameterCode.LobbyType] = (byte)lobby.Type; + opParameters[(byte)ParameterCode.Data] = queryData; + + return this.OpCustom(OperationCode.GetGameList, opParameters, true); + } + + /// + /// Request the rooms and online status for a list of friends (each client must set a unique username via OpAuthenticate). + /// + /// + /// Used on Master Server to find the rooms played by a selected list of users. + /// Users identify themselves by using OpAuthenticate with a unique username. + /// The list of usernames must be fetched from some other source (not provided by Photon). + /// + /// The server response includes 2 arrays of info (each index matching a friend from the request): + /// ParameterCode.FindFriendsResponseOnlineList = bool[] of online states + /// ParameterCode.FindFriendsResponseRoomIdList = string[] of room names (empty string if not in a room) + /// + /// Array of friend's names (make sure they are unique). + /// If the operation could be sent (requires connection). + public virtual bool OpFindFriends(string[] friendsToFind) + { + Dictionary opParameters = new Dictionary(); + if (friendsToFind != null && friendsToFind.Length > 0) + { + opParameters[ParameterCode.FindFriendsRequestList] = friendsToFind; + } + + return this.OpCustom(OperationCode.FindFriends, opParameters, true); + } + + public bool OpSetCustomPropertiesOfActor(int actorNr, Hashtable actorProperties) + { + return this.OpSetPropertiesOfActor(actorNr, actorProperties.StripToStringKeys(), null); + } + + /// + /// Sets properties of a player / actor. + /// Internally this uses OpSetProperties, which can be used to either set room or player properties. + /// + /// The payer ID (a.k.a. actorNumber) of the player to attach these properties to. + /// The properties to add or update. + /// If set, these must be in the current properties-set (on the server) to set actorProperties: CAS. + /// Set to true, to forward the set properties to a WebHook, defined for this app (in Dashboard). + /// If the operation could be sent (requires connection). + protected internal bool OpSetPropertiesOfActor(int actorNr, Hashtable actorProperties, Hashtable expectedProperties = null, bool webForward = false) + { + if (this.DebugOut >= DebugLevel.INFO) + { + this.Listener.DebugReturn(DebugLevel.INFO, "OpSetPropertiesOfActor()"); + } + + if (actorNr <= 0 || actorProperties == null) + { + if (this.DebugOut >= DebugLevel.INFO) + { + this.Listener.DebugReturn(DebugLevel.INFO, "OpSetPropertiesOfActor not sent. ActorNr must be > 0 and actorProperties != null."); + } + return false; + } + + Dictionary opParameters = new Dictionary(); + opParameters.Add(ParameterCode.Properties, actorProperties); + opParameters.Add(ParameterCode.ActorNr, actorNr); + opParameters.Add(ParameterCode.Broadcast, true); + if (expectedProperties != null && expectedProperties.Count != 0) + { + opParameters.Add(ParameterCode.ExpectedValues, expectedProperties); + } + + if (webForward) + { + opParameters[ParameterCode.EventForward] = true; + } + + return this.OpCustom((byte)OperationCode.SetProperties, opParameters, true, 0, false); + } + + + protected void OpSetPropertyOfRoom(byte propCode, object value) + { + Hashtable properties = new Hashtable(); + properties[propCode] = value; + this.OpSetPropertiesOfRoom(properties, expectedProperties: null, webForward: false); + } + + public bool OpSetCustomPropertiesOfRoom(Hashtable gameProperties, bool broadcast, byte channelId) + { + return this.OpSetPropertiesOfRoom(gameProperties.StripToStringKeys(), expectedProperties: null, webForward: false); + } + + /// + /// Sets properties of a room. + /// Internally this uses OpSetProperties, which can be used to either set room or player properties. + /// + /// The properties to add or update. + /// The properties expected when update occurs. (CAS : "Check And Swap") + /// "WebFlag" to indicate if request should be forwarded as "PathProperties" webhook or not. + /// If the operation could be sent (has to be connected). + protected internal bool OpSetPropertiesOfRoom(Hashtable gameProperties, Hashtable expectedProperties = null, bool webForward = false) + { + if (this.DebugOut >= DebugLevel.INFO) + { + this.Listener.DebugReturn(DebugLevel.INFO, "OpSetPropertiesOfRoom()"); + } + + Dictionary opParameters = new Dictionary(); + opParameters.Add(ParameterCode.Properties, gameProperties); + opParameters.Add(ParameterCode.Broadcast, true); + if (expectedProperties != null && expectedProperties.Count != 0) + { + opParameters.Add(ParameterCode.ExpectedValues, expectedProperties); + } + + if (webForward) + { + opParameters[ParameterCode.EventForward] = true; + } + + return this.OpCustom((byte)OperationCode.SetProperties, opParameters, true, 0, false); + } + + /// + /// Sends this app's appId and appVersion to identify this application server side. + /// This is an async request which triggers a OnOperationResponse() call. + /// + /// + /// This operation makes use of encryption, if that is established before. + /// See: EstablishEncryption(). Check encryption with IsEncryptionAvailable. + /// This operation is allowed only once per connection (multiple calls will have ErrorCode != Ok). + /// + /// Your application's name or ID to authenticate. This is assigned by Photon Cloud (webpage). + /// The client's version (clients with differing client appVersions are separated and players don't meet). + /// Contains all values relevant for authentication. Even without account system (external Custom Auth), the clients are allowed to identify themselves. + /// Optional region code, if the client should connect to a specific Photon Cloud Region. + /// Set to true on Master Server to receive "Lobby Statistics" events. + /// If the operation could be sent (has to be connected). + public virtual bool OpAuthenticate(string appId, string appVersion, AuthenticationValues authValues, string regionCode, bool getLobbyStatistics) + { + if (this.DebugOut >= DebugLevel.INFO) + { + this.Listener.DebugReturn(DebugLevel.INFO, "OpAuthenticate()"); + } + + Dictionary opParameters = new Dictionary(); + if (getLobbyStatistics) + { + // must be sent in operation, even if a Token is available + opParameters[ParameterCode.LobbyStats] = true; + } + + // shortcut, if we have a Token + if (authValues != null && authValues.Token != null) + { + opParameters[ParameterCode.Secret] = authValues.Token; + return this.OpCustom(OperationCode.Authenticate, opParameters, true, (byte)0, false); // we don't have to encrypt, when we have a token (which is encrypted) + } + + + // without a token, we send a complete op auth + + opParameters[ParameterCode.AppVersion] = appVersion; + opParameters[ParameterCode.ApplicationId] = appId; + + if (!string.IsNullOrEmpty(regionCode)) + { + opParameters[ParameterCode.Region] = regionCode; + } + + if (authValues != null) + { + + if (!string.IsNullOrEmpty(authValues.UserId)) + { + opParameters[ParameterCode.UserId] = authValues.UserId; + } + + if (authValues.AuthType != CustomAuthenticationType.None) + { + if (!this.IsProtocolSecure && !this.IsEncryptionAvailable) + { + this.Listener.DebugReturn(DebugLevel.ERROR, "OpAuthenticate() failed. When you want Custom Authentication encryption is mandatory."); + return false; + } + + opParameters[ParameterCode.ClientAuthenticationType] = (byte) authValues.AuthType; + if (!string.IsNullOrEmpty(authValues.Token)) + { + opParameters[ParameterCode.Secret] = authValues.Token; + } + else + { + if (!string.IsNullOrEmpty(authValues.AuthGetParameters)) + { + opParameters[ParameterCode.ClientAuthenticationParams] = authValues.AuthGetParameters; + } + if (authValues.AuthPostData != null) + { + opParameters[ParameterCode.ClientAuthenticationData] = authValues.AuthPostData; + } + } + } + } + + bool sent = this.OpCustom(OperationCode.Authenticate, opParameters, true, (byte) 0, this.IsEncryptionAvailable); + if (!sent) + { + this.Listener.DebugReturn(DebugLevel.ERROR, "Error calling OpAuthenticate! Did not work. Check log output, AuthValues and if you're connected."); + } + return sent; + } + + + /// + /// Sends this app's appId and appVersion to identify this application server side. + /// This is an async request which triggers a OnOperationResponse() call. + /// + /// + /// This operation makes use of encryption, if that is established before. + /// See: EstablishEncryption(). Check encryption with IsEncryptionAvailable. + /// This operation is allowed only once per connection (multiple calls will have ErrorCode != Ok). + /// + /// Your application's name or ID to authenticate. This is assigned by Photon Cloud (webpage). + /// The client's version (clients with differing client appVersions are separated and players don't meet). + /// Optional authentication values. The client can set no values or a UserId or some parameters for Custom Authentication by a server. + /// Optional region code, if the client should connect to a specific Photon Cloud Region. + /// + /// + /// If the operation could be sent (has to be connected). + public virtual bool OpAuthenticateOnce(string appId, string appVersion, AuthenticationValues authValues, string regionCode, EncryptionMode encryptionMode, ConnectionProtocol expectedProtocol) + { + if (this.DebugOut >= DebugLevel.INFO) + { + this.Listener.DebugReturn(DebugLevel.INFO, "OpAuthenticate()"); + } + + + var opParameters = new Dictionary(); + + // shortcut, if we have a Token + if (authValues != null && authValues.Token != null) + { + opParameters[ParameterCode.Secret] = authValues.Token; + return this.OpCustom(OperationCode.AuthenticateOnce, opParameters, true, (byte)0, false); // we don't have to encrypt, when we have a token (which is encrypted) + } + + if (encryptionMode == EncryptionMode.DatagramEncryption && expectedProtocol != ConnectionProtocol.Udp) + { + Debug.LogWarning("Expected protocol set to UDP, due to encryption mode DatagramEncryption. Changing protocol in PhotonServerSettings from: " + PhotonNetwork.PhotonServerSettings.Protocol); + PhotonNetwork.PhotonServerSettings.Protocol = ConnectionProtocol.Udp; + expectedProtocol = ConnectionProtocol.Udp; + } + + opParameters[ParameterCode.ExpectedProtocol] = (byte)expectedProtocol; + opParameters[ParameterCode.EncryptionMode] = (byte)encryptionMode; + + opParameters[ParameterCode.AppVersion] = appVersion; + opParameters[ParameterCode.ApplicationId] = appId; + + if (!string.IsNullOrEmpty(regionCode)) + { + opParameters[ParameterCode.Region] = regionCode; + } + + if (authValues != null) + { + if (!string.IsNullOrEmpty(authValues.UserId)) + { + opParameters[ParameterCode.UserId] = authValues.UserId; + } + + if (authValues.AuthType != CustomAuthenticationType.None) + { + opParameters[ParameterCode.ClientAuthenticationType] = (byte)authValues.AuthType; + if (!string.IsNullOrEmpty(authValues.Token)) + { + opParameters[ParameterCode.Secret] = authValues.Token; + } + else + { + if (!string.IsNullOrEmpty(authValues.AuthGetParameters)) + { + opParameters[ParameterCode.ClientAuthenticationParams] = authValues.AuthGetParameters; + } + if (authValues.AuthPostData != null) + { + opParameters[ParameterCode.ClientAuthenticationData] = authValues.AuthPostData; + } + } + } + } + + return this.OpCustom(OperationCode.AuthenticateOnce, opParameters, true, (byte)0, this.IsEncryptionAvailable); + } + + /// + /// Operation to handle this client's interest groups (for events in room). + /// + /// + /// Note the difference between passing null and byte[0]: + /// null won't add/remove any groups. + /// byte[0] will add/remove all (existing) groups. + /// First, removing groups is executed. This way, you could leave all groups and join only the ones provided. + /// + /// Changes become active not immediately but when the server executes this operation (approximately RTT/2). + /// + /// Groups to remove from interest. Null will not remove any. A byte[0] will remove all. + /// Groups to add to interest. Null will not add any. A byte[0] will add all current. + /// If operation could be enqueued for sending. Sent when calling: Service or SendOutgoingCommands. + public virtual bool OpChangeGroups(byte[] groupsToRemove, byte[] groupsToAdd) + { + if (this.DebugOut >= DebugLevel.ALL) + { + this.Listener.DebugReturn(DebugLevel.ALL, "OpChangeGroups()"); + } + + Dictionary opParameters = new Dictionary(); + if (groupsToRemove != null) + { + opParameters[(byte)ParameterCode.Remove] = groupsToRemove; + } + if (groupsToAdd != null) + { + opParameters[(byte)ParameterCode.Add] = groupsToAdd; + } + + return this.OpCustom((byte)OperationCode.ChangeGroups, opParameters, true, 0); + } + + + /// + /// Send an event with custom code/type and any content to the other players in the same room. + /// + /// This override explicitly uses another parameter order to not mix it up with the implementation for Hashtable only. + /// Identifies this type of event (and the content). Your game's event codes can start with 0. + /// Any serializable datatype (including Hashtable like the other OpRaiseEvent overloads). + /// If this event has to arrive reliably (potentially repeated if it's lost). + /// Contains (slightly) less often used options. If you pass null, the default options will be used. + /// If operation could be enqueued for sending. Sent when calling: Service or SendOutgoingCommands. + public virtual bool OpRaiseEvent(byte eventCode, object customEventContent, bool sendReliable, RaiseEventOptions raiseEventOptions) + { + this.opParameters.Clear(); // re-used private variable to avoid many new Dictionary() calls (garbage collection) + this.opParameters[(byte)ParameterCode.Code] = (byte)eventCode; + if (customEventContent != null) + { + this.opParameters[(byte) ParameterCode.Data] = customEventContent; + } + + if (raiseEventOptions == null) + { + raiseEventOptions = RaiseEventOptions.Default; + } + else + { + if (raiseEventOptions.CachingOption != EventCaching.DoNotCache) + { + this.opParameters[(byte) ParameterCode.Cache] = (byte) raiseEventOptions.CachingOption; + } + if (raiseEventOptions.Receivers != ReceiverGroup.Others) + { + this.opParameters[(byte) ParameterCode.ReceiverGroup] = (byte) raiseEventOptions.Receivers; + } + if (raiseEventOptions.InterestGroup != 0) + { + this.opParameters[(byte) ParameterCode.Group] = (byte) raiseEventOptions.InterestGroup; + } + if (raiseEventOptions.TargetActors != null) + { + this.opParameters[(byte) ParameterCode.ActorList] = raiseEventOptions.TargetActors; + } + if (raiseEventOptions.ForwardToWebhook) + { + this.opParameters[(byte) ParameterCode.EventForward] = true; //TURNBASED + } + } + + return this.OpCustom((byte) OperationCode.RaiseEvent, this.opParameters, sendReliable, raiseEventOptions.SequenceChannel, raiseEventOptions.Encrypt); + } + + + /// + /// Internally used operation to set some "per server" settings. This is for the Master Server. + /// + /// Set to true, to get Lobby Statistics (lists of existing lobbies). + /// False if the operation could not be sent. + public virtual bool OpSettings(bool receiveLobbyStats) + { + if (this.DebugOut >= DebugLevel.ALL) + { + this.Listener.DebugReturn(DebugLevel.ALL, "OpSettings()"); + } + + // re-used private variable to avoid many new Dictionary() calls (garbage collection) + this.opParameters.Clear(); + + // implementation for Master Server: + if (receiveLobbyStats) + { + this.opParameters[(byte)0] = receiveLobbyStats; + } + + if (this.opParameters.Count == 0) + { + // no need to send op in case we set the default values + return true; + } + return this.OpCustom((byte)OperationCode.ServerSettings, this.opParameters, true); + } + } + + + + internal class OpJoinRandomRoomParams + { + public Hashtable ExpectedCustomRoomProperties; + public byte ExpectedMaxPlayers; + public MatchmakingMode MatchingType; + public TypedLobby TypedLobby; + public string SqlLobbyFilter; + public string[] ExpectedUsers; + } + + internal class EnterRoomParams + { + public string RoomName; + public RoomOptions RoomOptions; + public TypedLobby Lobby; + public Hashtable PlayerProperties; + public bool OnGameServer = true; // defaults to true! better send more parameter than too few (GS needs all) + public bool CreateIfNotExists; + public bool RejoinOnly; + public string[] ExpectedUsers; + } + + + /// + /// ErrorCode defines the default codes associated with Photon client/server communication. + /// + public class ErrorCode + { + /// (0) is always "OK", anything else an error or specific situation. + public const int Ok = 0; + + // server - Photon low(er) level: <= 0 + + /// + /// (-3) Operation can't be executed yet (e.g. OpJoin can't be called before being authenticated, RaiseEvent cant be used before getting into a room). + /// + /// + /// Before you call any operations on the Cloud servers, the automated client workflow must complete its authorization. + /// In PUN, wait until State is: JoinedLobby (with AutoJoinLobby = true) or ConnectedToMaster (AutoJoinLobby = false) + /// + public const int OperationNotAllowedInCurrentState = -3; + + /// (-2) The operation you called is not implemented on the server (application) you connect to. Make sure you run the fitting applications. + [Obsolete("Use InvalidOperation.")] + public const int InvalidOperationCode = -2; + + /// (-2) The operation you called could not be executed on the server. + /// + /// Make sure you are connected to the server you expect. + /// + /// This code is used in several cases: + /// The arguments/parameters of the operation might be out of range, missing entirely or conflicting. + /// The operation you called is not implemented on the server (application). Server-side plugins affect the available operations. + /// + public const int InvalidOperation = -2; + + /// (-1) Something went wrong in the server. Try to reproduce and contact Exit Games. + public const int InternalServerError = -1; + + // server - PhotonNetwork: 0x7FFF and down + // logic-level error codes start with short.max + + /// (32767) Authentication failed. Possible cause: AppId is unknown to Photon (in cloud service). + public const int InvalidAuthentication = 0x7FFF; + + /// (32766) GameId (name) already in use (can't create another). Change name. + public const int GameIdAlreadyExists = 0x7FFF - 1; + + /// (32765) Game is full. This rarely happens when some player joined the room before your join completed. + public const int GameFull = 0x7FFF - 2; + + /// (32764) Game is closed and can't be joined. Join another game. + public const int GameClosed = 0x7FFF - 3; + + [Obsolete("No longer used, cause random matchmaking is no longer a process.")] + public const int AlreadyMatched = 0x7FFF - 4; + + /// (32762) Not in use currently. + public const int ServerFull = 0x7FFF - 5; + + /// (32761) Not in use currently. + public const int UserBlocked = 0x7FFF - 6; + + /// (32760) Random matchmaking only succeeds if a room exists thats neither closed nor full. Repeat in a few seconds or create a new room. + public const int NoRandomMatchFound = 0x7FFF - 7; + + /// (32758) Join can fail if the room (name) is not existing (anymore). This can happen when players leave while you join. + public const int GameDoesNotExist = 0x7FFF - 9; + + /// (32757) Authorization on the Photon Cloud failed becaus the concurrent users (CCU) limit of the app's subscription is reached. + /// + /// Unless you have a plan with "CCU Burst", clients might fail the authentication step during connect. + /// Affected client are unable to call operations. Please note that players who end a game and return + /// to the master server will disconnect and re-connect, which means that they just played and are rejected + /// in the next minute / re-connect. + /// This is a temporary measure. Once the CCU is below the limit, players will be able to connect an play again. + /// + /// OpAuthorize is part of connection workflow but only on the Photon Cloud, this error can happen. + /// Self-hosted Photon servers with a CCU limited license won't let a client connect at all. + /// + public const int MaxCcuReached = 0x7FFF - 10; + + /// (32756) Authorization on the Photon Cloud failed because the app's subscription does not allow to use a particular region's server. + /// + /// Some subscription plans for the Photon Cloud are region-bound. Servers of other regions can't be used then. + /// Check your master server address and compare it with your Photon Cloud Dashboard's info. + /// https://www.photonengine.com/dashboard + /// + /// OpAuthorize is part of connection workflow but only on the Photon Cloud, this error can happen. + /// Self-hosted Photon servers with a CCU limited license won't let a client connect at all. + /// + public const int InvalidRegion = 0x7FFF - 11; + + /// + /// (32755) Custom Authentication of the user failed due to setup reasons (see Cloud Dashboard) or the provided user data (like username or token). Check error message for details. + /// + public const int CustomAuthenticationFailed = 0x7FFF - 12; + + /// (32753) The Authentication ticket expired. Usually, this is refreshed behind the scenes. Connect (and authorize) again. + public const int AuthenticationTicketExpired = 0x7FF1; + + /// + /// (32752) A server-side plugin (or webhook) failed to execute and reported an error. Check the OperationResponse.DebugMessage. + /// + public const int PluginReportedError = 0x7FFF - 15; + + /// + /// (32751) CreateRoom/JoinRoom/Join operation fails if expected plugin does not correspond to loaded one. + /// + public const int PluginMismatch = 0x7FFF - 16; + + /// + /// (32750) for join requests. Indicates the current peer already called join and is joined to the room. + /// + public const int JoinFailedPeerAlreadyJoined = 32750; // 0x7FFF - 17, + + /// + /// (32749) for join requests. Indicates the list of InactiveActors already contains an actor with the requested ActorNr or UserId. + /// + public const int JoinFailedFoundInactiveJoiner = 32749; // 0x7FFF - 18, + + /// + /// (32748) for join requests. Indicates the list of Actors (active and inactive) did not contain an actor with the requested ActorNr or UserId. + /// + public const int JoinFailedWithRejoinerNotFound = 32748; // 0x7FFF - 19, + + /// + /// (32747) for join requests. Note: for future use - Indicates the requested UserId was found in the ExcludedList. + /// + public const int JoinFailedFoundExcludedUserId = 32747; // 0x7FFF - 20, + + /// + /// (32746) for join requests. Indicates the list of ActiveActors already contains an actor with the requested ActorNr or UserId. + /// + public const int JoinFailedFoundActiveJoiner = 32746; // 0x7FFF - 21, + + /// + /// (32745) for SetProerties and Raisevent (if flag HttpForward is true) requests. Indicates the maximum allowd http requests per minute was reached. + /// + public const int HttpLimitReached = 32745; // 0x7FFF - 22, + + /// + /// (32744) for WebRpc requests. Indicates the the call to the external service failed. + /// + public const int ExternalHttpCallFailed = 32744; // 0x7FFF - 23, + + /// + /// (32742) Server error during matchmaking with slot reservation. E.g. the reserved slots can not exceed MaxPlayers. + /// + public const int SlotError = 32742; // 0x7FFF - 25, + + /// + /// (32741) Server will react with this error if invalid encryption parameters provided by token + /// + public const int InvalidEncryptionParameters = 32741; // 0x7FFF - 24, + +} + + + /// + /// Class for constants. These (byte) values define "well known" properties for an Actor / Player. + /// + /// + /// Pun uses these constants internally. + /// "Custom properties" have to use a string-type as key. They can be assigned at will. + /// + public class ActorProperties + { + /// (255) Name of a player/actor. + public const byte PlayerName = 255; // was: 1 + + /// (254) Tells you if the player is currently in this game (getting events live). + /// A server-set value for async games, where players can leave the game and return later. + public const byte IsInactive = 254; + + /// (253) UserId of the player. Sent when room gets created with RoomOptions.PublishUserId = true. + public const byte UserId = 253; + } + + + /// + /// Class for constants. These (byte) values are for "well known" room/game properties used in Photon Loadbalancing. + /// + /// + /// Pun uses these constants internally. + /// "Custom properties" have to use a string-type as key. They can be assigned at will. + /// + public class GamePropertyKey + { + /// (255) Max number of players that "fit" into this room. 0 is for "unlimited". + public const byte MaxPlayers = 255; + + /// (254) Makes this room listed or not in the lobby on master. + public const byte IsVisible = 254; + + /// (253) Allows more players to join a room (or not). + public const byte IsOpen = 253; + + /// (252) Current count of players in the room. Used only in the lobby on master. + public const byte PlayerCount = 252; + + /// (251) True if the room is to be removed from room listing (used in update to room list in lobby on master) + public const byte Removed = 251; + + /// (250) A list of the room properties to pass to the RoomInfo list in a lobby. This is used in CreateRoom, which defines this list once per room. + public const byte PropsListedInLobby = 250; + + /// (249) Equivalent of Operation Join parameter CleanupCacheOnLeave. + public const byte CleanupCacheOnLeave = 249; + + /// (248) Code for MasterClientId, which is synced by server. When sent as op-parameter this is (byte)203. As room property this is (byte)248. + /// Tightly related to ParameterCode.MasterClientId. + public const byte MasterClientId = (byte)248; + + /// (247) Code for ExpectedUsers in a room. Matchmaking keeps a slot open for the players with these userIDs. + public const byte ExpectedUsers = (byte)247; + } + + + /// + /// Class for constants. These values are for events defined by Photon Loadbalancing. + /// + /// They start at 255 and go DOWN. Your own in-game events can start at 0. Pun uses these constants internally. + public class EventCode + { + /// (230) Initial list of RoomInfos (in lobby on Master) + public const byte GameList = 230; + + /// (229) Update of RoomInfos to be merged into "initial" list (in lobby on Master) + public const byte GameListUpdate = 229; + + /// (228) Currently not used. State of queueing in case of server-full + public const byte QueueState = 228; + + /// (227) Currently not used. Event for matchmaking + public const byte Match = 227; + + /// (226) Event with stats about this application (players, rooms, etc) + public const byte AppStats = 226; + + /// (224) This event provides a list of lobbies with their player and game counts. + public const byte LobbyStats = 224; + + /// (210) Internally used in case of hosting by Azure + [Obsolete("TCP routing was removed after becoming obsolete.")] + public const byte AzureNodeInfo = 210; + + /// (255) Event Join: someone joined the game. The new actorNumber is provided as well as the properties of that actor (if set in OpJoin). + public const byte Join = (byte)255; + + /// (254) Event Leave: The player who left the game can be identified by the actorNumber. + public const byte Leave = (byte)254; + + /// (253) When you call OpSetProperties with the broadcast option "on", this event is fired. It contains the properties being set. + public const byte PropertiesChanged = (byte)253; + + /// (253) When you call OpSetProperties with the broadcast option "on", this event is fired. It contains the properties being set. + [Obsolete("Use PropertiesChanged now.")] + public const byte SetProperties = (byte)253; + + /// (252) When player left game unexpected and the room has a playerTtl > 0, this event is fired to let everyone know about the timeout. + /// Obsolete. Replaced by Leave. public const byte Disconnect = LiteEventCode.Disconnect; + + /// (251) Sent by Photon Cloud when a plugin-call or webhook-call failed. Usually, the execution on the server continues, despite the issue. Contains: ParameterCode.Info. + /// + public const byte ErrorInfo = 251; + + /// (250) Sent by Photon whent he event cache slice was changed. Done by OpRaiseEvent. + public const byte CacheSliceChanged = 250; + + /// (223) Sent by Photon to update a token before it times out. + public const byte AuthEvent = 223; + } + + + /// Class for constants. Codes for parameters of Operations and Events. + /// Pun uses these constants internally. + public class ParameterCode + { + /// (237) A bool parameter for creating games. If set to true, no room events are sent to the clients on join and leave. Default: false (and not sent). + public const byte SuppressRoomEvents = 237; + + /// (236) Time To Live (TTL) for a room when the last player leaves. Keeps room in memory for case a player re-joins soon. In milliseconds. + public const byte EmptyRoomTTL = 236; + + /// (235) Time To Live (TTL) for an 'actor' in a room. If a client disconnects, this actor is inactive first and removed after this timeout. In milliseconds. + public const byte PlayerTTL = 235; + + /// (234) Optional parameter of OpRaiseEvent and OpSetCustomProperties to forward the event/operation to a web-service. + public const byte EventForward = 234; + + /// (233) Optional parameter of OpLeave in async games. If false, the player does abandons the game (forever). By default players become inactive and can re-join. + [Obsolete("Use: IsInactive")] + public const byte IsComingBack = (byte)233; + + /// (233) Used in EvLeave to describe if a user is inactive (and might come back) or not. In rooms with PlayerTTL, becoming inactive is the default case. + public const byte IsInactive = (byte)233; + + /// (232) Used when creating rooms to define if any userid can join the room only once. + public const byte CheckUserOnJoin = (byte)232; + + /// (231) Code for "Check And Swap" (CAS) when changing properties. + public const byte ExpectedValues = (byte)231; + + /// (230) Address of a (game) server to use. + public const byte Address = 230; + + /// (229) Count of players in this application in a rooms (used in stats event) + public const byte PeerCount = 229; + + /// (228) Count of games in this application (used in stats event) + public const byte GameCount = 228; + + /// (227) Count of players on the master server (in this app, looking for rooms) + public const byte MasterPeerCount = 227; + + /// (225) User's ID + public const byte UserId = 225; + + /// (224) Your application's ID: a name on your own Photon or a GUID on the Photon Cloud + public const byte ApplicationId = 224; + + /// (223) Not used currently (as "Position"). If you get queued before connect, this is your position + public const byte Position = 223; + + /// (223) Modifies the matchmaking algorithm used for OpJoinRandom. Allowed parameter values are defined in enum MatchmakingMode. + public const byte MatchMakingType = 223; + + /// (222) List of RoomInfos about open / listed rooms + public const byte GameList = 222; + + /// (221) Internally used to establish encryption + public const byte Secret = 221; + + /// (220) Version of your application + public const byte AppVersion = 220; + + /// (210) Internally used in case of hosting by Azure + [Obsolete("TCP routing was removed after becoming obsolete.")] + public const byte AzureNodeInfo = 210; // only used within events, so use: EventCode.AzureNodeInfo + + /// (209) Internally used in case of hosting by Azure + [Obsolete("TCP routing was removed after becoming obsolete.")] + public const byte AzureLocalNodeId = 209; + + /// (208) Internally used in case of hosting by Azure + [Obsolete("TCP routing was removed after becoming obsolete.")] + public const byte AzureMasterNodeId = 208; + + /// (255) Code for the gameId/roomName (a unique name per room). Used in OpJoin and similar. + public const byte RoomName = (byte)255; + + /// (250) Code for broadcast parameter of OpSetProperties method. + public const byte Broadcast = (byte)250; + + /// (252) Code for list of players in a room. Currently not used. + public const byte ActorList = (byte)252; + + /// (254) Code of the Actor of an operation. Used for property get and set. + public const byte ActorNr = (byte)254; + + /// (249) Code for property set (Hashtable). + public const byte PlayerProperties = (byte)249; + + /// (245) Code of data/custom content of an event. Used in OpRaiseEvent. + public const byte CustomEventContent = (byte)245; + + /// (245) Code of data of an event. Used in OpRaiseEvent. + public const byte Data = (byte)245; + + /// (244) Code used when sending some code-related parameter, like OpRaiseEvent's event-code. + /// This is not the same as the Operation's code, which is no longer sent as part of the parameter Dictionary in Photon 3. + public const byte Code = (byte)244; + + /// (248) Code for property set (Hashtable). + public const byte GameProperties = (byte)248; + + /// + /// (251) Code for property-set (Hashtable). This key is used when sending only one set of properties. + /// If either ActorProperties or GameProperties are used (or both), check those keys. + /// + public const byte Properties = (byte)251; + + /// (253) Code of the target Actor of an operation. Used for property set. Is 0 for game + public const byte TargetActorNr = (byte)253; + + /// (246) Code to select the receivers of events (used in Lite, Operation RaiseEvent). + public const byte ReceiverGroup = (byte)246; + + /// (247) Code for caching events while raising them. + public const byte Cache = (byte)247; + + /// (241) Bool parameter of CreateRoom Operation. If true, server cleans up roomcache of leaving players (their cached events get removed). + public const byte CleanupCacheOnLeave = (byte)241; + + /// (240) Code for "group" operation-parameter (as used in Op RaiseEvent). + public const byte Group = 240; + + /// (239) The "Remove" operation-parameter can be used to remove something from a list. E.g. remove groups from player's interest groups. + public const byte Remove = 239; + + /// (239) Used in Op Join to define if UserIds of the players are broadcast in the room. Useful for FindFriends and reserving slots for expected users. + public const byte PublishUserId = 239; + + /// (238) The "Add" operation-parameter can be used to add something to some list or set. E.g. add groups to player's interest groups. + public const byte Add = 238; + + /// (218) Content for EventCode.ErrorInfo and internal debug operations. + public const byte Info = 218; + + /// (217) This key's (byte) value defines the target custom authentication type/service the client connects with. Used in OpAuthenticate + public const byte ClientAuthenticationType = 217; + + /// (216) This key's (string) value provides parameters sent to the custom authentication type/service the client connects with. Used in OpAuthenticate + public const byte ClientAuthenticationParams = 216; + + /// (215) Makes the server create a room if it doesn't exist. OpJoin uses this to always enter a room, unless it exists and is full/closed. + // public const byte CreateIfNotExists = 215; + + /// (215) The JoinMode enum defines which variant of joining a room will be executed: Join only if available, create if not exists or re-join. + /// Replaces CreateIfNotExists which was only a bool-value. + public const byte JoinMode = 215; + + /// (214) This key's (string or byte[]) value provides parameters sent to the custom authentication service setup in Photon Dashboard. Used in OpAuthenticate + public const byte ClientAuthenticationData = 214; + + /// (203) Code for MasterClientId, which is synced by server. When sent as op-parameter this is code 203. + /// Tightly related to GamePropertyKey.MasterClientId. + public const byte MasterClientId = (byte)203; + + /// (1) Used in Op FindFriends request. Value must be string[] of friends to look up. + public const byte FindFriendsRequestList = (byte)1; + + /// (1) Used in Op FindFriends response. Contains bool[] list of online states (false if not online). + public const byte FindFriendsResponseOnlineList = (byte)1; + + /// (2) Used in Op FindFriends response. Contains string[] of room names ("" where not known or no room joined). + public const byte FindFriendsResponseRoomIdList = (byte)2; + + /// (213) Used in matchmaking-related methods and when creating a room to name a lobby (to join or to attach a room to). + public const byte LobbyName = (byte)213; + + /// (212) Used in matchmaking-related methods and when creating a room to define the type of a lobby. Combined with the lobby name this identifies the lobby. + public const byte LobbyType = (byte)212; + + /// (211) This (optional) parameter can be sent in Op Authenticate to turn on Lobby Stats (info about lobby names and their user- and game-counts). See: PhotonNetwork.Lobbies + public const byte LobbyStats = (byte)211; + + /// (210) Used for region values in OpAuth and OpGetRegions. + public const byte Region = (byte)210; + + /// (209) Path of the WebRPC that got called. Also known as "WebRpc Name". Type: string. + public const byte UriPath = 209; + + /// (208) Parameters for a WebRPC as: Dictionary<string, object>. This will get serialized to JSon. + public const byte WebRpcParameters = 208; + + /// (207) ReturnCode for the WebRPC, as sent by the web service (not by Photon, which uses ErrorCode). Type: byte. + public const byte WebRpcReturnCode = 207; + + /// (206) Message returned by WebRPC server. Analog to Photon's debug message. Type: string. + public const byte WebRpcReturnMessage = 206; + + /// (205) Used to define a "slice" for cached events. Slices can easily be removed from cache. Type: int. + public const byte CacheSliceIndex = 205; + + /// (204) Informs the server of the expected plugin setup. + /// + /// The operation will fail in case of a plugin mismatch returning error code PluginMismatch 32751(0x7FFF - 16). + /// Setting string[]{} means the client expects no plugin to be setup. + /// Note: for backwards compatibility null omits any check. + /// + public const byte Plugins = 204; + + /// (202) Used by the server in Operation Responses, when it sends the nickname of the client (the user's nickname). + public const byte NickName = 202; + + /// (201) Informs user about name of plugin load to game + public const byte PluginName = 201; + + /// (200) Informs user about version of plugin load to game + public const byte PluginVersion = 200; + + /// (195) Protocol which will be used by client to connect master/game servers. Used for nameserver. + public const byte ExpectedProtocol = 195; + + /// (194) Set of custom parameters which are sent in auth request. + public const byte CustomInitData = 194; + + /// (193) How are we going to encrypt data. + public const byte EncryptionMode = 193; + + /// (192) Parameter of Authentication, which contains encryption keys (depends on AuthMode and EncryptionMode). + public const byte EncryptionData = 192; + + /// (191) An int parameter summarizing several boolean room-options with bit-flags. + public const byte RoomOptionFlags = 191; + } + + + /// + /// Class for constants. Contains operation codes. + /// Pun uses these constants internally. + /// + public class OperationCode + { + [Obsolete("Exchanging encrpytion keys is done internally in the lib now. Don't expect this operation-result.")] + public const byte ExchangeKeysForEncryption = 250; + + /// (255) Code for OpJoin, to get into a room. + public const byte Join = 255; + + /// (231) Authenticates this peer and connects to a virtual application + public const byte AuthenticateOnce = 231; + + /// (230) Authenticates this peer and connects to a virtual application + public const byte Authenticate = 230; + + /// (229) Joins lobby (on master) + public const byte JoinLobby = 229; + + /// (228) Leaves lobby (on master) + public const byte LeaveLobby = 228; + + /// (227) Creates a game (or fails if name exists) + public const byte CreateGame = 227; + + /// (226) Join game (by name) + public const byte JoinGame = 226; + + /// (225) Joins random game (on master) + public const byte JoinRandomGame = 225; + + // public const byte CancelJoinRandom = 224; // obsolete, cause JoinRandom no longer is a "process". now provides result immediately + + /// (254) Code for OpLeave, to get out of a room. + public const byte Leave = (byte)254; + + /// (253) Raise event (in a room, for other actors/players) + public const byte RaiseEvent = (byte)253; + + /// (252) Set Properties (of room or actor/player) + public const byte SetProperties = (byte)252; + + /// (251) Get Properties + public const byte GetProperties = (byte)251; + + /// (248) Operation code to change interest groups in Rooms (Lite application and extending ones). + public const byte ChangeGroups = (byte)248; + + /// (222) Request the rooms and online status for a list of friends (by name, which should be unique). + public const byte FindFriends = 222; + + /// (221) Request statistics about a specific list of lobbies (their user and game count). + public const byte GetLobbyStats = 221; + + /// (220) Get list of regional servers from a NameServer. + public const byte GetRegions = 220; + + /// (219) WebRpc Operation. + public const byte WebRpc = 219; + + /// (218) Operation to set some server settings. Used with different parameters on various servers. + public const byte ServerSettings = 218; + + /// (217) Get the game list matching a supplied sql filter (SqlListLobby only) + public const byte GetGameList = 217; + } + + /// Defines possible values for OpJoinRoom and OpJoinOrCreate. It tells the server if the room can be only be joined normally, created implicitly or found on a web-service for Turnbased games. + /// These values are not directly used by a game but implicitly set. + public enum JoinMode : byte + { + /// Regular join. The room must exist. + Default = 0, + + /// Join or create the room if it's not existing. Used for OpJoinOrCreate for example. + CreateIfNotExists = 1, + + /// The room might be out of memory and should be loaded (if possible) from a Turnbased web-service. + JoinOrRejoin = 2, + + /// Only re-join will be allowed. If the user is not yet in the room, this will fail. + RejoinOnly = 3, + } + + /// + /// Options for matchmaking rules for OpJoinRandom. + /// + public enum MatchmakingMode : byte + { + /// Fills up rooms (oldest first) to get players together as fast as possible. Default. + /// Makes most sense with MaxPlayers > 0 and games that can only start with more players. + FillRoom = 0, + + /// Distributes players across available rooms sequentially but takes filter into account. Without filter, rooms get players evenly distributed. + SerialMatching = 1, + + /// Joins a (fully) random room. Expected properties must match but aside from this, any available room might be selected. + RandomMatching = 2 + } + + + /// + /// Lite - OpRaiseEvent lets you chose which actors in the room should receive events. + /// By default, events are sent to "Others" but you can overrule this. + /// + public enum ReceiverGroup : byte + { + /// Default value (not sent). Anyone else gets my event. + Others = 0, + + /// Everyone in the current room (including this peer) will get this event. + All = 1, + + /// The server sends this event only to the actor with the lowest actorNumber. + /// The "master client" does not have special rights but is the one who is in this room the longest time. + MasterClient = 2, + } + + /// + /// Lite - OpRaiseEvent allows you to cache events and automatically send them to joining players in a room. + /// Events are cached per event code and player: Event 100 (example!) can be stored once per player. + /// Cached events can be modified, replaced and removed. + /// + /// + /// Caching works only combination with ReceiverGroup options Others and All. + /// + public enum EventCaching : byte + { + /// Default value (not sent). + DoNotCache = 0, + + /// Will merge this event's keys with those already cached. + [Obsolete] + MergeCache = 1, + + /// Replaces the event cache for this eventCode with this event's content. + [Obsolete] + ReplaceCache = 2, + + /// Removes this event (by eventCode) from the cache. + [Obsolete] + RemoveCache = 3, + + /// Adds an event to the room's cache + AddToRoomCache = 4, + + /// Adds this event to the cache for actor 0 (becoming a "globally owned" event in the cache). + AddToRoomCacheGlobal = 5, + + /// Remove fitting event from the room's cache. + RemoveFromRoomCache = 6, + + /// Removes events of players who already left the room (cleaning up). + RemoveFromRoomCacheForActorsLeft = 7, + + /// Increase the index of the sliced cache. + SliceIncreaseIndex = 10, + + /// Set the index of the sliced cache. You must set RaiseEventOptions.CacheSliceIndex for this. + SliceSetIndex = 11, + + /// Purge cache slice with index. Exactly one slice is removed from cache. You must set RaiseEventOptions.CacheSliceIndex for this. + SlicePurgeIndex = 12, + + /// Purge cache slices with specified index and anything lower than that. You must set RaiseEventOptions.CacheSliceIndex for this. + SlicePurgeUpToIndex = 13, + } + + /// + /// Flags for "types of properties", being used as filter in OpGetProperties. + /// + [Flags] + public enum PropertyTypeFlag : byte + { + /// (0x00) Flag type for no property type. + None = 0x00, + + /// (0x01) Flag type for game-attached properties. + Game = 0x01, + + /// (0x02) Flag type for actor related propeties. + Actor = 0x02, + + /// (0x01) Flag type for game AND actor properties. Equal to 'Game' + GameAndActor = Game | Actor + } + + + /// Wraps up common room properties needed when you create rooms. Read the individual entries for more details. + /// This directly maps to the fields in the Room class. + public class RoomOptions + { + /// Defines if this room is listed in the lobby. If not, it also is not joined randomly. + /// + /// A room that is not visible will be excluded from the room lists that are sent to the clients in lobbies. + /// An invisible room can be joined by name but is excluded from random matchmaking. + /// + /// Use this to "hide" a room and simulate "private rooms". Players can exchange a roomname and create it + /// invisble to avoid anyone else joining it. + /// + public bool IsVisible { get { return this.isVisibleField; } set { this.isVisibleField = value; } } + private bool isVisibleField = true; + + /// Defines if this room can be joined at all. + /// + /// If a room is closed, no player can join this. As example this makes sense when 3 of 4 possible players + /// start their gameplay early and don't want anyone to join during the game. + /// The room can still be listed in the lobby (set IsVisible to control lobby-visibility). + /// + public bool IsOpen { get { return this.isOpenField; } set { this.isOpenField = value; } } + private bool isOpenField = true; + + /// Max number of players that can be in the room at any time. 0 means "no limit". + public byte MaxPlayers; + + + /// Time To Live (TTL) for an 'actor' in a room. If a client disconnects, this actor is inactive first and removed after this timeout. In milliseconds. + public int PlayerTtl; + + + /// Time To Live (TTL) for a room when the last player leaves. Keeps room in memory for case a player re-joins soon. In milliseconds. + public int EmptyRoomTtl; + + ///// Activates UserId checks on joining - allowing a users to be only once in the room. + ///// + ///// Turnbased rooms should be created with this check turned on! They should also use custom authentication. + ///// Disabled by default for backwards-compatibility. + ///// + //public bool CheckUserOnJoin { get { return this.checkUserOnJoinField; } set { this.checkUserOnJoinField = value; } } + //private bool checkUserOnJoinField = false; + + /// Removes a user's events and properties from the room when a user leaves. + /// + /// This makes sense when in rooms where players can't place items in the room and just vanish entirely. + /// When you disable this, the event history can become too long to load if the room stays in use indefinitely. + /// Default: true. Cleans up the cache and props of leaving users. + /// + public bool CleanupCacheOnLeave { get { return this.cleanupCacheOnLeaveField; } set { this.cleanupCacheOnLeaveField = value; } } + private bool cleanupCacheOnLeaveField = PhotonNetwork.autoCleanUpPlayerObjects; + + /// The room's custom properties to set. Use string keys! + /// + /// Custom room properties are any key-values you need to define the game's setup. + /// The shorter your keys are, the better. + /// Example: Map, Mode (could be "m" when used with "Map"), TileSet (could be "t"). + /// + public Hashtable CustomRoomProperties; + + /// Defines the custom room properties that get listed in the lobby. + /// + /// Name the custom room properties that should be available to clients that are in a lobby. + /// Use with care. Unless a custom property is essential for matchmaking or user info, it should + /// not be sent to the lobby, which causes traffic and delays for clients in the lobby. + /// + /// Default: No custom properties are sent to the lobby. + /// + public string[] CustomRoomPropertiesForLobby = new string[0]; + + /// Informs the server of the expected plugin setup. + /// + /// The operation will fail in case of a plugin missmatch returning error code PluginMismatch 32757(0x7FFF - 10). + /// Setting string[]{} means the client expects no plugin to be setup. + /// Note: for backwards compatibility null omits any check. + /// + public string[] Plugins; + + /// + /// Tells the server to skip room events for joining and leaving players. + /// + /// + /// Using this makes the client unaware of the other players in a room. + /// That can save some traffic if you have some server logic that updates players + /// but it can also limit the client's usability. + /// + /// PUN will break if you use this, so it's not settable. + /// + public bool SuppressRoomEvents { get { return this.suppressRoomEventsField; } /*set { this.suppressRoomEventsField = value; }*/ } + private bool suppressRoomEventsField = false; + + /// + /// Defines if the UserIds of players get "published" in the room. Useful for FindFriends, if players want to play another game together. + /// + /// + /// When you set this to true, Photon will publish the UserIds of the players in that room. + /// In that case, you can use PhotonPlayer.UserId, to access any player's userID. + /// This is useful for FindFriends and to set "expected users" to reserve slots in a room (see PhotonNetwork.JoinRoom e.g.). + /// + public bool PublishUserId { get { return this.publishUserIdField; } set { this.publishUserIdField = value; } } + private bool publishUserIdField = false; + + /// Optionally, properties get deleted, when null gets assigned as value. Defaults to off / false. + /// + /// When Op SetProperties is setting a key's value to null, the server and clients should remove the key/value from the Custom Properties. + /// By default, the server keeps the keys (and null values) and sends them to joining players. + /// + /// Important: Only when SetProperties does a "broadcast", the change (key, value = null) is sent to clients to update accordingly. + /// This applies to Custom Properties for rooms and actors/players. + /// + public bool DeleteNullProperties { get { return this.deleteNullPropertiesField; } set { this.deleteNullPropertiesField = value; } } + private bool deleteNullPropertiesField = false; + + #region Obsoleted Naming + + [Obsolete("Use property with uppercase naming instead.")] + public bool isVisible { get { return this.isVisibleField; } set { this.isVisibleField = value; } } + [Obsolete("Use property with uppercase naming instead.")] + public bool isOpen { get { return this.isOpenField; } set { this.isOpenField = value; } } + [Obsolete("Use property with uppercase naming instead.")] + public byte maxPlayers { get { return this.MaxPlayers; } set { this.MaxPlayers = value; } } + [Obsolete("Use property with uppercase naming instead.")] + public bool cleanupCacheOnLeave { get { return this.cleanupCacheOnLeaveField; } set { this.cleanupCacheOnLeaveField = value; } } + [Obsolete("Use property with uppercase naming instead.")] + public Hashtable customRoomProperties { get { return this.CustomRoomProperties; } set { this.CustomRoomProperties = value; } } + [Obsolete("Use property with uppercase naming instead.")] + public string[] customRoomPropertiesForLobby { get { return this.CustomRoomPropertiesForLobby; } set { this.CustomRoomPropertiesForLobby = value; } } + [Obsolete("Use property with uppercase naming instead.")] + public string[] plugins { get { return this.Plugins; } set { this.Plugins = value; } } + [Obsolete("Use property with uppercase naming instead.")] + public bool suppressRoomEvents { get { return this.suppressRoomEventsField; } } + [Obsolete("Use property with uppercase naming instead.")] + public bool publishUserId { get { return this.publishUserIdField; } set { this.publishUserIdField = value; } } + + #endregion +} + + + /// Aggregates several less-often used options for operation RaiseEvent. See field descriptions for usage details. + public class RaiseEventOptions + { + /// Default options: CachingOption: DoNotCache, InterestGroup: 0, targetActors: null, receivers: Others, sequenceChannel: 0. + public readonly static RaiseEventOptions Default = new RaiseEventOptions(); + + /// Defines if the server should simply send the event, put it in the cache or remove events that are like this one. + /// + /// When using option: SliceSetIndex, SlicePurgeIndex or SlicePurgeUpToIndex, set a CacheSliceIndex. All other options except SequenceChannel get ignored. + /// + public EventCaching CachingOption; + + /// The number of the Interest Group to send this to. 0 goes to all users but to get 1 and up, clients must subscribe to the group first. + public byte InterestGroup; + + /// A list of PhotonPlayer.IDs to send this event to. You can implement events that just go to specific users this way. + public int[] TargetActors; + + /// Sends the event to All, MasterClient or Others (default). Be careful with MasterClient, as the client might disconnect before it got the event and it gets lost. + public ReceiverGroup Receivers; + + /// Events are ordered per "channel". If you have events that are independent of others, they can go into another sequence or channel. + public byte SequenceChannel; + + /// Events can be forwarded to Webhooks, which can evaluate and use the events to follow the game's state. + public bool ForwardToWebhook; + + ///// Used along with CachingOption SliceSetIndex, SlicePurgeIndex or SlicePurgeUpToIndex if you want to set or purge a specific cache-slice. + //public int CacheSliceIndex; + + public bool Encrypt; + } + + /// + /// Options of lobby types available. Lobby types might be implemented in certain Photon versions and won't be available on older servers. + /// + public enum LobbyType :byte + { + /// This lobby is used unless another is defined by game or JoinRandom. Room-lists will be sent and JoinRandomRoom can filter by matching properties. + Default = 0, + /// This lobby type lists rooms like Default but JoinRandom has a parameter for SQL-like "where" clauses for filtering. This allows bigger, less, or and and combinations. + SqlLobby = 2, + /// This lobby does not send lists of games. It is only used for OpJoinRandomRoom. It keeps rooms available for a while when there are only inactive users left. + AsyncRandomLobby = 3 + } + + /// Refers to a specific lobby (and type) on the server. + /// + /// The name and type are the unique identifier for a lobby.
+ /// Join a lobby via PhotonNetwork.JoinLobby(TypedLobby lobby).
+ /// The current lobby is stored in PhotonNetwork.lobby. + ///
+ public class TypedLobby + { + /// Name of the lobby this game gets added to. Default: null, attached to default lobby. Lobbies are unique per lobbyName plus lobbyType, so the same name can be used when several types are existing. + public string Name; + /// Type of the (named)lobby this game gets added to + public LobbyType Type; + + public static readonly TypedLobby Default = new TypedLobby(); + public bool IsDefault { get { return this.Type == LobbyType.Default && string.IsNullOrEmpty(this.Name); } } + + public TypedLobby() + { + this.Name = string.Empty; + this.Type = LobbyType.Default; + } + + public TypedLobby(string name, LobbyType type) + { + this.Name = name; + this.Type = type; + } + + public override string ToString() + { + return String.Format((string) "lobby '{0}'[{1}]", (object) this.Name, (object) this.Type); + } + } + + public class TypedLobbyInfo : TypedLobby + { + public int PlayerCount; + public int RoomCount; + + public override string ToString() + { + return string.Format("TypedLobbyInfo '{0}'[{1}] rooms: {2} players: {3}", this.Name, this.Type, this.RoomCount, this.PlayerCount); + } + } + + + /// + /// Options for authentication modes. From "classic" auth on each server to AuthOnce (on NameServer). + /// + public enum AuthModeOption { Auth, AuthOnce, AuthOnceWss } + + + /// + /// Options for optional "Custom Authentication" services used with Photon. Used by OpAuthenticate after connecting to Photon. + /// + public enum CustomAuthenticationType : byte + { + /// Use a custom authentification service. Currently the only implemented option. + Custom = 0, + + /// Authenticates users by their Steam Account. Set auth values accordingly! + Steam = 1, + + /// Authenticates users by their Facebook Account. Set auth values accordingly! + Facebook = 2, + + /// Authenticates users by their Oculus Account and token. + Oculus = 3, + + /// Authenticates users by their PSN Account and token. + PlayStation = 4, + + /// Authenticates users by their Xbox Account and XSTS token. + Xbox = 5, + + /// Disables custom authentification. Same as not providing any AuthenticationValues for connect (more precisely for: OpAuthenticate). + None = byte.MaxValue + } + + + /// + /// Container for user authentication in Photon. Set AuthValues before you connect - all else is handled. + /// + /// + /// On Photon, user authentication is optional but can be useful in many cases. + /// If you want to FindFriends, a unique ID per user is very practical. + /// + /// There are basically three options for user authentification: None at all, the client sets some UserId + /// or you can use some account web-service to authenticate a user (and set the UserId server-side). + /// + /// Custom Authentication lets you verify end-users by some kind of login or token. It sends those + /// values to Photon which will verify them before granting access or disconnecting the client. + /// + /// The AuthValues are sent in OpAuthenticate when you connect, so they must be set before you connect. + /// Should you not set any AuthValues, PUN will create them and set the playerName as userId in them. + /// If the AuthValues.userId is null or empty when it's sent to the server, then the Photon Server assigns a userId! + /// + /// The Photon Cloud Dashboard will let you enable this feature and set important server values for it. + /// https://www.photonengine.com/dashboard + /// + public class AuthenticationValues + { + /// See AuthType. + private CustomAuthenticationType authType = CustomAuthenticationType.None; + + /// The type of custom authentication provider that should be used. Currently only "Custom" or "None" (turns this off). + public CustomAuthenticationType AuthType + { + get { return authType; } + set { authType = value; } + } + + /// This string must contain any (http get) parameters expected by the used authentication service. By default, username and token. + /// Standard http get parameters are used here and passed on to the service that's defined in the server (Photon Cloud Dashboard). + public string AuthGetParameters { get; set; } + + /// Data to be passed-on to the auth service via POST. Default: null (not sent). Either string or byte[] (see setters). + public object AuthPostData { get; private set; } + + /// After initial authentication, Photon provides a token for this client / user, which is subsequently used as (cached) validation. + public string Token { get; set; } + + /// The UserId should be a unique identifier per user. This is for finding friends, etc.. + /// See remarks of AuthValues for info about how this is set and used. + public string UserId { get; set; } + + + /// Creates empty auth values without any info. + public AuthenticationValues() + { + } + + /// Creates minimal info about the user. If this is authenticated or not, depends on the set AuthType. + /// Some UserId to set in Photon. + public AuthenticationValues(string userId) + { + this.UserId = userId; + } + + /// Sets the data to be passed-on to the auth service via POST. + /// String data to be used in the body of the POST request. Null or empty string will set AuthPostData to null. + public virtual void SetAuthPostData(string stringData) + { + this.AuthPostData = (string.IsNullOrEmpty(stringData)) ? null : stringData; + } + + /// Sets the data to be passed-on to the auth service via POST. + /// Binary token / auth-data to pass on. + public virtual void SetAuthPostData(byte[] byteData) + { + this.AuthPostData = byteData; + } + + /// Adds a key-value pair to the get-parameters used for Custom Auth. + /// This method does uri-encoding for you. + /// Key for the value to set. + /// Some value relevant for Custom Authentication. + public virtual void AddAuthParameter(string key, string value) + { + string ampersand = string.IsNullOrEmpty(this.AuthGetParameters) ? "" : "&"; + this.AuthGetParameters = string.Format("{0}{1}{2}={3}", this.AuthGetParameters, ampersand, System.Uri.EscapeDataString(key), System.Uri.EscapeDataString(value)); + } + + public override string ToString() + { + return string.Format("AuthenticationValues UserId: {0}, GetParameters: {1} Token available: {2}", this.UserId, this.AuthGetParameters, this.Token != null); + } + } diff --git a/Assets/Photon Unity Networking/Plugins/PhotonNetwork/LoadbalancingPeer.cs.meta b/Assets/Photon Unity Networking/Plugins/PhotonNetwork/LoadbalancingPeer.cs.meta new file mode 100644 index 0000000..989f399 --- /dev/null +++ b/Assets/Photon Unity Networking/Plugins/PhotonNetwork/LoadbalancingPeer.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 35c989013c977244186e524a4c90dcee +labels: +- ExitGames +- PUN +- Photon +- Networking +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} diff --git a/Assets/Photon Unity Networking/Plugins/PhotonNetwork/NetworkingPeer.cs b/Assets/Photon Unity Networking/Plugins/PhotonNetwork/NetworkingPeer.cs new file mode 100644 index 0000000..c18bf2b --- /dev/null +++ b/Assets/Photon Unity Networking/Plugins/PhotonNetwork/NetworkingPeer.cs @@ -0,0 +1,4525 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Part of: Photon Unity Networking (PUN) +// +// -------------------------------------------------------------------------------------------------------------------- + +using ExitGames.Client.Photon; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Reflection; +using UnityEngine; +using Hashtable = ExitGames.Client.Photon.Hashtable; +using SupportClassPun = ExitGames.Client.Photon.SupportClass; + + + +#region Enums + +/// +/// Detailed connection / networking peer state. +/// PUN implements a loadbalancing and authentication workflow "behind the scenes", so +/// some states will automatically advance to some follow up state. Those states are +/// commented with "(will-change)". +/// +/// \ingroup publicApi +public enum ClientState +{ + /// Not running. Only set before initialization and first use. + Uninitialized, + + /// Created and available to connect. + PeerCreated, + + /// Not used at the moment. + Queued, + + /// The application is authenticated. PUN usually joins the lobby now. + /// (will-change) Unless AutoJoinLobby is false. + Authenticated, + + /// Client is in the lobby of the Master Server and gets room listings. + /// Use Join, Create or JoinRandom to get into a room to play. + JoinedLobby, + + /// Disconnecting. + /// (will-change) + DisconnectingFromMasterserver, + + /// Connecting to game server (to join/create a room and play). + /// (will-change) + ConnectingToGameserver, + + /// Similar to Connected state but on game server. Still in process to join/create room. + /// (will-change) + ConnectedToGameserver, + + /// In process to join/create room (on game server). + /// (will-change) + Joining, + + /// Final state of a room join/create sequence. This client can now exchange events / call RPCs with other clients. + Joined, + + /// Leaving a room. + /// (will-change) + Leaving, + + /// Workflow is leaving the game server and will re-connect to the master server. + /// (will-change) + DisconnectingFromGameserver, + + /// Workflow is connected to master server and will establish encryption and authenticate your app. + /// (will-change) + ConnectingToMasterserver, + + /// Same Queued but coming from game server. + /// (will-change) + QueuedComingFromGameserver, + + /// PUN is disconnecting. This leads to Disconnected. + /// (will-change) + Disconnecting, + + /// No connection is setup, ready to connect. Similar to PeerCreated. + Disconnected, + + /// Final state for connecting to master without joining the lobby (AutoJoinLobby is false). + ConnectedToMaster, + + /// Client connects to the NameServer. This process includes low level connecting and setting up encryption. When done, state becomes ConnectedToNameServer. + ConnectingToNameServer, + + /// Client is connected to the NameServer and established enctryption already. You should call OpGetRegions or ConnectToRegionMaster. + ConnectedToNameServer, + + /// When disconnecting from a Photon NameServer. + /// (will-change) + DisconnectingFromNameServer, + + /// When connecting to a Photon Server, this state is intermediate before you can call any operations. + /// (will-change) + Authenticating +} + + + /// + /// Internal state, how this peer gets into a particular room (joining it or creating it). + /// + internal enum JoinType + { + /// This client creates a room, gets into it (no need to join) and can set room properties. + CreateRoom, + /// The room existed already and we join into it (not setting room properties). + JoinRoom, + /// Done on Master Server and (if successful) followed by a Join on Game Server. + JoinRandomRoom, + /// Client is either joining or creating a room. On Master- and Game-Server. + JoinOrCreateRoom + } + + +/// +/// Summarizes the cause for a disconnect. Used in: OnConnectionFail and OnFailedToConnectToPhoton. +/// +/// Extracted from the status codes from ExitGames.Client.Photon.StatusCode. +/// +/// \ingroup publicApi +public enum DisconnectCause +{ + /// Server actively disconnected this client. + /// Possible cause: The server's user limit was hit and client was forced to disconnect (on connect). + DisconnectByServerUserLimit = StatusCode.DisconnectByServerUserLimit, + + /// Connection could not be established. + /// Possible cause: Local server not running. + ExceptionOnConnect = StatusCode.ExceptionOnConnect, + + /// Timeout disconnect by server (which decided an ACK was missing for too long). + DisconnectByServerTimeout = StatusCode.DisconnectByServer, + + /// Server actively disconnected this client. + /// Possible cause: Server's send buffer full (too much data for client). + DisconnectByServerLogic = StatusCode.DisconnectByServerLogic, + + /// Some exception caused the connection to close. + Exception = StatusCode.Exception, + + /// (32767) The Photon Cloud rejected the sent AppId. Check your Dashboard and make sure the AppId you use is complete and correct. + InvalidAuthentication = ErrorCode.InvalidAuthentication, + + /// (32757) Authorization on the Photon Cloud failed because the concurrent users (CCU) limit of the app's subscription is reached. + MaxCcuReached = ErrorCode.MaxCcuReached, + + /// (32756) Authorization on the Photon Cloud failed because the app's subscription does not allow to use a particular region's server. + InvalidRegion = ErrorCode.InvalidRegion, + + /// The security settings for client or server don't allow a connection (see remarks). + /// + /// A common cause for this is that browser clients read a "crossdomain" file from the server. + /// If that file is unavailable or not configured to let the client connect, this exception is thrown. + /// Photon usually provides this crossdomain file for Unity. + /// If it fails, read: + /// http://doc.exitgames.com/photon-server/PolicyApp + /// + SecurityExceptionOnConnect = StatusCode.SecurityExceptionOnConnect, + + /// Timeout disconnect by client (which decided an ACK was missing for too long). + DisconnectByClientTimeout = StatusCode.TimeoutDisconnect, + + /// Exception in the receive-loop. + /// Possible cause: Socket failure. + InternalReceiveException = StatusCode.ExceptionOnReceive, + + /// (32753) The Authentication ticket expired. Handle this by connecting again (which includes an authenticate to get a fresh ticket). + AuthenticationTicketExpired = 32753, +} + +/// Available server (types) for internally used field: server. +/// Photon uses 3 different roles of servers: Name Server, Master Server and Game Server. +public enum ServerConnection +{ + /// This server is where matchmaking gets done and where clients can get lists of rooms in lobbies. + MasterServer, + /// This server handles a number of rooms to execute and relay the messages between players (in a room). + GameServer, + /// This server is used initially to get the address (IP) of a Master Server for a specific region. Not used for Photon OnPremise (self hosted). + NameServer +} + +#endregion + +/// +/// Implements Photon LoadBalancing used in PUN. +/// This class is used internally by PhotonNetwork and not intended as public API. +/// +internal class NetworkingPeer : LoadBalancingPeer, IPhotonPeerListener +{ + /// Combination of GameVersion+"_"+PunVersion. Separates players per app by version. + protected internal string AppVersion + { + get { return string.Format("{0}_{1}", PhotonNetwork.gameVersion, PhotonNetwork.versionPUN); } + } + + /// Contains the AppId for the Photon Cloud (ignored by Photon Servers). + protected internal string AppId; + + /// + /// A user's authentication values used during connect for Custom Authentication with Photon (and a custom service/community). + /// Set these before calling Connect if you want custom authentication. + /// + public AuthenticationValues AuthValues { get; set; } + + /// Internally used cache for the server's token. Identifies a user/session and can be used to rejoin. + private string tokenCache; + + + /// Enables the new Authentication workflow + public AuthModeOption AuthMode = AuthModeOption.Auth; + + /// Defines how the communication gets encrypted. + public EncryptionMode EncryptionMode = EncryptionMode.PayloadEncryption; + + + ///Simplifies getting the token for connect/init requests, if this feature is enabled. + private string TokenForInit + { + get + { + if (this.AuthMode == AuthModeOption.Auth) + { + return null; + } + return (this.AuthValues != null) ? this.AuthValues.Token : null; + } + } + + /// True if this client uses a NameServer to get the Master Server address. + public bool IsUsingNameServer { get; protected internal set; } + + /// Name Server Host Name for Photon Cloud. Without port and without any prefix. + #if !UNITY_EDITOR && UNITY_SWITCH + public const string NameServerHost = "nameserver-eu.cloudapp.net";//set to "ns.exitgames.com" after Nintendo has fixed the traffic manager bug in their dns-resolver for which this is a workaround + #else + public const string NameServerHost = "ns.exitgames.com"; + #endif + + /// Name Server for HTTP connections to the Photon Cloud. Includes prefix and port. + public const string NameServerHttp = "http://ns.exitgamescloud.com:80/photon/n"; + + /// Name Server port per protocol (the UDP port is different than TCP, etc). + private static readonly Dictionary ProtocolToNameServerPort = new Dictionary() { { ConnectionProtocol.Udp, 5058 }, { ConnectionProtocol.Tcp, 4533 }, { ConnectionProtocol.WebSocket, 9093 }, { ConnectionProtocol.WebSocketSecure, 19093 } }; //, { ConnectionProtocol.RHttp, 6063 } }; + + /// Name Server Address for Photon Cloud (based on current protocol). You can use the default values and usually won't have to set this value. + public string NameServerAddress { get { return this.GetNameServerAddress(); } } + + /// Your Master Server address. In PhotonCloud, call ConnectToRegionMaster() to find your Master Server. + /// + /// In the Photon Cloud, explicit definition of a Master Server Address is not best practice. + /// The Photon Cloud has a "Name Server" which redirects clients to a specific Master Server (per Region and AppId). + /// + public string MasterServerAddress { get; protected internal set; } + + /// The game server's address for a particular room. In use temporarily, as assigned by master. + public string GameServerAddress { get; protected internal set; } + + /// The server this client is currently connected or connecting to. + /// + /// Each server (NameServer, MasterServer, GameServer) allow some operations and reject others. + /// + protected internal ServerConnection Server { get; private set; } + + public ClientState State { get; internal set; } + + public bool IsInitialConnect = false; + + + public bool insideLobby = false; + public TypedLobby lobby { get; set; } + + + private bool requestLobbyStatistics + { + get { return PhotonNetwork.EnableLobbyStatistics && this.Server == ServerConnection.MasterServer; } + } + + protected internal List LobbyStatistics = new List(); + + + public Dictionary mGameList = new Dictionary(); + public RoomInfo[] mGameListCopy = new RoomInfo[0]; + + private string playername = ""; + + public string PlayerName + { + get + { + return this.playername; + } + + set + { + if (string.IsNullOrEmpty(value) || value.Equals(this.playername)) + { + return; + } + + if (this.LocalPlayer != null) + { + this.LocalPlayer.NickName = value; + } + + this.playername = value; + if (this.CurrentRoom != null) + { + // Only when in a room + this.SendPlayerName(); + } + } + } + + // "public" access to the current game - is null unless a room is joined on a gameserver + // isLocalClientInside becomes true when op join result is positive on GameServer + private bool mPlayernameHasToBeUpdated; + + + public Room CurrentRoom + { + get + { + if (this.currentRoom != null && this.currentRoom.IsLocalClientInside) + { + return this.currentRoom; + } + + return null; + } + + private set { this.currentRoom = value; } + } + + private Room currentRoom; + + public PhotonPlayer LocalPlayer { get; internal set; } + + /// Statistic value available on master server: Players on master (looking for games). + public int PlayersOnMasterCount { get; internal set; } + + /// Statistic value available on master server: Players in rooms (playing). + public int PlayersInRoomsCount { get; internal set; } + + /// Statistic value available on master server: Rooms currently created. + public int RoomsCount { get; internal set; } + + /// Internally used to decide if a room must be created or joined on game server. + private JoinType lastJoinType; + + protected internal EnterRoomParams enterRoomParamsCache; + + + /// Internally used to trigger OpAuthenticate when encryption was established after a connect. + private bool didAuthenticate; + + + + /// Contains the list of names of friends to look up their state on the server. + private string[] friendListRequested; + + /// + /// Age of friend list info (in milliseconds). It's 0 until a friend list is fetched. + /// + protected internal int FriendListAge { get { return (this.isFetchingFriendList || this.friendListTimestamp == 0) ? 0 : Environment.TickCount - this.friendListTimestamp; } } + + private int friendListTimestamp; + + /// Internal flag to know if the client currently fetches a friend list. + private bool isFetchingFriendList; + + /// Internally used to check if a "Secret" is available to use. Sent by Photon Cloud servers, it simplifies authentication when switching servers. + public bool IsAuthorizeSecretAvailable + { + get + { + return this.AuthValues != null && !String.IsNullOrEmpty(this.AuthValues.Token); + } + } + + /// A list of region names for the Photon Cloud. Set by the result of OpGetRegions(). + /// Put a "case OperationCode.GetRegions:" into your OnOperationResponse method to notice when the result is available. + public List AvailableRegions { get; protected internal set; } + + /// The cloud region this client connects to. Set by ConnectToRegionMaster(). + public CloudRegionCode CloudRegion { get; protected internal set; } + + + + public Dictionary mActors = new Dictionary(); + + public PhotonPlayer[] mOtherPlayerListCopy = new PhotonPlayer[0]; + public PhotonPlayer[] mPlayerListCopy = new PhotonPlayer[0]; + + + public int mMasterClientId + { + get + { + if (PhotonNetwork.offlineMode) return this.LocalPlayer.ID; + return (this.CurrentRoom == null) ? 0 : this.CurrentRoom.MasterClientId; + } + private set + { + if (this.CurrentRoom != null) + { + this.CurrentRoom.MasterClientId = value; + } + } + } + + public bool hasSwitchedMC = false; + + private HashSet allowedReceivingGroups = new HashSet(); + + private HashSet blockSendingGroups = new HashSet(); + + protected internal Dictionary photonViewList = new Dictionary(); //TODO: make private again + + private readonly PhotonStream readStream = new PhotonStream(false, null); // only used in OnSerializeRead() + private readonly PhotonStream pStream = new PhotonStream(true, null); // only used in OnSerializeWrite() + private readonly Dictionary dataPerGroupReliable = new Dictionary(); // only used in RunViewUpdate() + private readonly Dictionary dataPerGroupUnreliable = new Dictionary(); // only used in RunViewUpdate() + + protected internal short currentLevelPrefix = 0; + + /// Internally used to flag if the message queue was disabled by a "scene sync" situation (to re-enable it). + protected internal bool loadingLevelAndPausedNetwork = false; + + /// For automatic scene syncing, the loaded scene is put into a room property. This is the name of said prop. + protected internal const string CurrentSceneProperty = "curScn"; + + public static bool UsePrefabCache = true; + + internal IPunPrefabPool ObjectPool; + + public static Dictionary PrefabCache = new Dictionary(); + + private Dictionary> monoRPCMethodsCache = new Dictionary>(); + + private readonly Dictionary rpcShortcuts; // lookup "table" for the index (shortcut) of an RPC name + + /// Caches PhotonNetworkingMessage.OnPhotonInstantiate.ToString(), because DoInstantiate calls it often (and ToString() on the enum is astonishingly expensive). + private static readonly string OnPhotonInstantiateString = PhotonNetworkingMessage.OnPhotonInstantiate.ToString(); + + + // TODO: CAS must be implemented for OfflineMode + + public NetworkingPeer(string playername, ConnectionProtocol connectionProtocol) : base(connectionProtocol) + { + this.Listener = this; + this.LimitOfUnreliableCommands = 40; + + this.lobby = TypedLobby.Default; + this.PlayerName = playername; + this.LocalPlayer = new PhotonPlayer(true, -1, this.playername); + this.AddNewPlayer(this.LocalPlayer.ID, this.LocalPlayer); + + // RPC shortcut lookup creation (from list of RPCs, which is updated by Editor scripts) + rpcShortcuts = new Dictionary(PhotonNetwork.PhotonServerSettings.RpcList.Count); + for (int index = 0; index < PhotonNetwork.PhotonServerSettings.RpcList.Count; index++) + { + var name = PhotonNetwork.PhotonServerSettings.RpcList[index]; + rpcShortcuts[name] = index; + } + + this.State = ClientState.PeerCreated; + } + + /// + /// Gets the NameServer Address (with prefix and port), based on the set protocol (this.UsedProtocol). + /// + /// NameServer Address (with prefix and port). + private string GetNameServerAddress() + { + #if RHTTP + if (currentProtocol == ConnectionProtocol.RHttp) + { + return NameServerHttp; + } + #endif + + ConnectionProtocol currentProtocol = this.TransportProtocol; + int protocolPort = 0; + ProtocolToNameServerPort.TryGetValue(currentProtocol, out protocolPort); + + string protocolPrefix = string.Empty; + if (currentProtocol == ConnectionProtocol.WebSocket) + { + protocolPrefix = "ws://"; + } + else if (currentProtocol == ConnectionProtocol.WebSocketSecure) + { + protocolPrefix = "wss://"; + } + + string result = string.Format("{0}{1}:{2}", protocolPrefix, NameServerHost, protocolPort); + //Debug.Log("NameServer: " + result); + return result; + } + +#region Operations and Connection Methods + + + public override bool Connect(string serverAddress, string applicationName) + { + Debug.LogError("Avoid using this directly. Thanks."); + return false; + } + + /// Can be used to reconnect to the master server after a disconnect. + /// Common use case: Press the Lock Button on a iOS device and you get disconnected immediately. + public bool ReconnectToMaster() + { + if (this.AuthValues == null) + { + Debug.LogWarning("ReconnectToMaster() with AuthValues == null is not correct!"); + this.AuthValues = new AuthenticationValues(); + } + this.AuthValues.Token = this.tokenCache; + + return this.Connect(this.MasterServerAddress, ServerConnection.MasterServer); + } + + /// + /// Can be used to return to a room quickly, by directly reconnecting to a game server to rejoin a room. + /// + /// False, if the conditions are not met. Then, this client does not attempt the ReconnectAndRejoin. + public bool ReconnectAndRejoin() + { + if (this.AuthValues == null) + { + Debug.LogWarning("ReconnectAndRejoin() with AuthValues == null is not correct!"); + this.AuthValues = new AuthenticationValues(); + } + this.AuthValues.Token = this.tokenCache; + + if (!string.IsNullOrEmpty(this.GameServerAddress) && this.enterRoomParamsCache != null) + { + this.lastJoinType = JoinType.JoinRoom; + this.enterRoomParamsCache.RejoinOnly = true; + return this.Connect(this.GameServerAddress, ServerConnection.GameServer); + } + + return false; + } + + + public bool Connect(string serverAddress, ServerConnection type) + { + if (PhotonHandler.AppQuits) + { + Debug.LogWarning("Ignoring Connect() because app gets closed. If this is an error, check PhotonHandler.AppQuits."); + return false; + } + + if (this.State == ClientState.Disconnecting) + { + Debug.LogError("Connect() failed. Can't connect while disconnecting (still). Current state: " + PhotonNetwork.connectionStateDetailed); + return false; + } + + this.SetupProtocol(type); + + // connect might fail, if the DNS name can't be resolved or if no network connection is available + bool connecting = base.Connect(serverAddress, "", this.TokenForInit); + + if (connecting) + { + switch (type) + { + case ServerConnection.NameServer: + State = ClientState.ConnectingToNameServer; + break; + case ServerConnection.MasterServer: + State = ClientState.ConnectingToMasterserver; + break; + case ServerConnection.GameServer: + State = ClientState.ConnectingToGameserver; + break; + } + } + + return connecting; + } + + + /// + /// Connects to the NameServer for Photon Cloud, where a region-list can be fetched. + /// + /// + /// If the workflow was started or failed right away. + public bool ConnectToNameServer() + { + if (PhotonHandler.AppQuits) + { + Debug.LogWarning("Ignoring Connect() because app gets closed. If this is an error, check PhotonHandler.AppQuits."); + return false; + } + + this.IsUsingNameServer = true; + this.CloudRegion = CloudRegionCode.none; + + if (this.State == ClientState.ConnectedToNameServer) + { + return true; + } + + this.SetupProtocol(ServerConnection.NameServer); + if (!base.Connect(this.NameServerAddress, "ns", this.TokenForInit)) + { + return false; + } + + this.State = ClientState.ConnectingToNameServer; + return true; + } + + /// + /// Connects you to a specific region's Master Server, using the Name Server to find the IP. + /// + /// If the operation could be sent. If false, no operation was sent. + public bool ConnectToRegionMaster(CloudRegionCode region) + { + if (PhotonHandler.AppQuits) + { + Debug.LogWarning("Ignoring Connect() because app gets closed. If this is an error, check PhotonHandler.AppQuits."); + return false; + } + + this.IsUsingNameServer = true; + this.CloudRegion = region; + + if (this.State == ClientState.ConnectedToNameServer) + { + return this.CallAuthenticate(); + } + + this.SetupProtocol(ServerConnection.NameServer); + if (!base.Connect(this.NameServerAddress, "ns", this.TokenForInit)) + { + return false; + } + + this.State = ClientState.ConnectingToNameServer; + return true; + } + + // this sets up the protocol to us, depending on auth-mode and or export. + protected internal void SetupProtocol(ServerConnection serverType) + { + ConnectionProtocol protocolOverride = this.TransportProtocol; + + #if UNITY_XBOXONE + if (this.AuthMode != AuthModeOption.AuthOnceWss) + { + UnityEngine.Debug.LogWarning("UNITY_XBOXONE builds must use AuthMode \"AuthOnceWss\". The default setting was changed. Resetting it now."); + } + if (this.EncryptionMode != EncryptionMode.DatagramEncryption) + { + UnityEngine.Debug.LogWarning("UNITY_XBOXONE builds must use EncryptionMode \"DatagramEncryption\". The default setting was changed. Resetting it now."); + } + if (this.AuthValues == null || this.AuthValues.AuthType != CustomAuthenticationType.Xbox) + { + UnityEngine.Debug.LogError("UNITY_XBOXONE builds must use AuthValues.AuthType \"CustomAuthenticationType.XboxCheck\". Set this before calling any Connect method."); + if (this.AuthValues == null) + { + this.AuthValues = new AuthenticationValues(); + } + this.AuthValues.AuthType = CustomAuthenticationType.Xbox; + } + if (!PhotonPeer.NativeDatagramEncrypt) + { + throw new NotSupportedException("UNITY_XBOXONE builds have to use a special Photon library with Native Datagram Encryption. This is missing. Check your build setup!"); + } + + this.AuthMode = AuthModeOption.AuthOnceWss; + this.EncryptionMode = EncryptionMode.DatagramEncryption; + #endif + + if (this.AuthMode == AuthModeOption.AuthOnceWss) + { + if (serverType != ServerConnection.NameServer) + { + if (PhotonNetwork.logLevel >= PhotonLogLevel.ErrorsOnly) + { + Debug.LogWarning("Using PhotonServerSettings.Protocol when leaving the NameServer (AuthMode is AuthOnceWss): " + PhotonNetwork.PhotonServerSettings.Protocol); + } + protocolOverride = PhotonNetwork.PhotonServerSettings.Protocol; + } + else + { + if (PhotonNetwork.logLevel >= PhotonLogLevel.ErrorsOnly) + { + Debug.LogWarning("Using WebSocket to connect NameServer (AuthMode is AuthOnceWss)."); + } + protocolOverride = ConnectionProtocol.WebSocketSecure; + } + } + + // to support WebGL export in Unity, we find and assign the SocketWebTcp class (if it's in the project). + // alternatively class SocketWebTcp might be in the Photon3Unity3D.dll + Type socketTcp = Type.GetType("ExitGames.Client.Photon.SocketWebTcp, Assembly-CSharp", false); + if (socketTcp == null) + { + socketTcp = Type.GetType("ExitGames.Client.Photon.SocketWebTcp, Assembly-CSharp-firstpass", false); + } + if (socketTcp != null) + { + this.SocketImplementationConfig[ConnectionProtocol.WebSocket] = socketTcp; + this.SocketImplementationConfig[ConnectionProtocol.WebSocketSecure] = socketTcp; + } + + + #if UNITY_WEBGL + if (this.TransportProtocol != ConnectionProtocol.WebSocket && this.TransportProtocol != ConnectionProtocol.WebSocketSecure) + { + Debug.Log("WebGL only supports WebSocket protocol. Overriding PhotonServerSettings."); + protocolOverride = ConnectionProtocol.WebSocketSecure; + } + PhotonHandler.PingImplementation = typeof(PingHttp); + #endif + + + #if !UNITY_EDITOR && (UNITY_WINRT) + // this automatically uses a separate assembly-file with Win8-style Socket usage (not possible in Editor) + Debug.LogWarning("Using PingWindowsStore"); + PhotonHandler.PingImplementation = typeof(PingWindowsStore); // but for ping, we have to set the implementation explicitly to Win 8 Store/Phone + #endif + + + #pragma warning disable 0162 // the library variant defines if we should use PUN's SocketUdp variant (at all) + if (PhotonPeer.NoSocket) + { + if (this.AuthMode != AuthModeOption.AuthOnceWss || serverType != ServerConnection.NameServer) + { + if (this.TransportProtocol != ConnectionProtocol.Udp) + { + Debug.Log("This Photon3Unity3d.dll only allows UDP. TransportProtocol was: " + this.TransportProtocol + ". SocketImplementation: " + this.SocketImplementation); + } + protocolOverride = ConnectionProtocol.Udp; + } + + #if !UNITY_EDITOR && (UNITY_PS3 || UNITY_ANDROID) + this.SocketImplementationConfig[ConnectionProtocol.Udp] = typeof(SocketUdpNativeDynamic); + PhotonHandler.PingImplementation = typeof(PingNativeDynamic); + #elif !UNITY_EDITOR && (UNITY_IPHONE || UNITY_SWITCH) + this.SocketImplementationConfig[ConnectionProtocol.Udp] = typeof(SocketUdpNativeStatic); + PhotonHandler.PingImplementation = typeof(PingNativeStatic); + #elif !UNITY_EDITOR && UNITY_WINRT + // this automatically uses a separate assembly-file with Win8-style Socket usage (not possible in Editor) + #else + this.SocketImplementationConfig[ConnectionProtocol.Udp] = typeof(SocketUdp); + PhotonHandler.PingImplementation = typeof(PingMonoEditor); + #endif + + if (this.SocketImplementationConfig[ConnectionProtocol.Udp] == null) + { + Debug.Log("No socket implementation set for 'NoSocket' assembly. Please check your settings."); + } + } + #pragma warning restore 0162 + + if (PhotonHandler.PingImplementation == null) + { + PhotonHandler.PingImplementation = typeof(PingMono); + } + + + if (this.TransportProtocol == protocolOverride) + { + return; + } + + + if (PhotonNetwork.logLevel >= PhotonLogLevel.ErrorsOnly) + { + Debug.LogWarning("Protocol switch from: " + this.TransportProtocol + " to: " + protocolOverride + "."); + } + + this.TransportProtocol = protocolOverride; + } + + /// + /// Complete disconnect from photon (and the open master OR game server) + /// + public override void Disconnect() + { + if (this.PeerState == PeerStateValue.Disconnected) + { + if (!PhotonHandler.AppQuits) + { + Debug.LogWarning(string.Format("Can't execute Disconnect() while not connected. Nothing changed. State: {0}", this.State)); + } + return; + } + + this.State = ClientState.Disconnecting; + base.Disconnect(); + + //this.LeftRoomCleanup(); + //this.LeftLobbyCleanup(); + } + + private bool CallAuthenticate() + { + // once encryption is availble, the client should send one (secure) authenticate. it includes the AppId (which identifies your app on the Photon Cloud) + AuthenticationValues auth = this.AuthValues ?? new AuthenticationValues() { UserId = this.PlayerName }; + if (this.AuthMode == AuthModeOption.Auth) + { + return this.OpAuthenticate(this.AppId, this.AppVersion, auth, this.CloudRegion.ToString(), this.requestLobbyStatistics); + } + else + { + return this.OpAuthenticateOnce(this.AppId, this.AppVersion, auth, this.CloudRegion.ToString(), this.EncryptionMode, PhotonNetwork.PhotonServerSettings.Protocol); + } + } + + + + /// + /// Internally used only. Triggers OnStateChange with "Disconnect" in next dispatch which is the signal to re-connect (if at all). + /// + private void DisconnectToReconnect() + { + switch (this.Server) + { + case ServerConnection.NameServer: + this.State = ClientState.DisconnectingFromNameServer; + base.Disconnect(); + break; + case ServerConnection.MasterServer: + this.State = ClientState.DisconnectingFromMasterserver; + base.Disconnect(); + //LeftLobbyCleanup(); + break; + case ServerConnection.GameServer: + this.State = ClientState.DisconnectingFromGameserver; + base.Disconnect(); + //this.LeftRoomCleanup(); + break; + } + } + + /// + /// While on the NameServer, this gets you the list of regional servers (short names and their IPs to ping them). + /// + /// If the operation could be sent. If false, no operation was sent (e.g. while not connected to the NameServer). + public bool GetRegions() + { + if (this.Server != ServerConnection.NameServer) + { + return false; + } + + bool sent = this.OpGetRegions(this.AppId); + if (sent) + { + this.AvailableRegions = null; + } + + return sent; + } + + /// + /// Request the rooms and online status for a list of friends. All client must set a unique username via PlayerName property. The result is available in this.Friends. + /// + /// + /// Used on Master Server to find the rooms played by a selected list of users. + /// The result will be mapped to LoadBalancingClient.Friends when available. + /// The list is initialized by OpFindFriends on first use (before that, it is null). + /// + /// Users identify themselves by setting a PlayerName in the LoadBalancingClient instance. + /// This in turn will send the name in OpAuthenticate after each connect (to master and game servers). + /// Note: Changing a player's name doesn't make sense when using a friend list. + /// + /// The list of usernames must be fetched from some other source (not provided by Photon). + /// + /// + /// Internal: + /// The server response includes 2 arrays of info (each index matching a friend from the request): + /// ParameterCode.FindFriendsResponseOnlineList = bool[] of online states + /// ParameterCode.FindFriendsResponseRoomIdList = string[] of room names (empty string if not in a room) + /// + /// Array of friend's names (make sure they are unique). + /// If the operation could be sent (requires connection, only one request is allowed at any time). Always false in offline mode. + public override bool OpFindFriends(string[] friendsToFind) + { + if (this.isFetchingFriendList) + { + return false; // fetching friends currently, so don't do it again (avoid changing the list while fetching friends) + } + + this.friendListRequested = friendsToFind; + this.isFetchingFriendList = true; + + return base.OpFindFriends(friendsToFind); + } + + /// NetworkingPeer.OpCreateGame + public bool OpCreateGame(EnterRoomParams enterRoomParams) + { + bool onGameServer = this.Server == ServerConnection.GameServer; + enterRoomParams.OnGameServer = onGameServer; + enterRoomParams.PlayerProperties = GetLocalActorProperties(); + if (!onGameServer) + { + enterRoomParamsCache = enterRoomParams; + } + + this.lastJoinType = JoinType.CreateRoom; + return base.OpCreateRoom(enterRoomParams); + } + + /// NetworkingPeer.OpJoinRoom + public override bool OpJoinRoom(EnterRoomParams opParams) + { + bool onGameServer = this.Server == ServerConnection.GameServer; + opParams.OnGameServer = onGameServer; + if (!onGameServer) + { + this.enterRoomParamsCache = opParams; + } + + this.lastJoinType = (opParams.CreateIfNotExists) ? JoinType.JoinOrCreateRoom : JoinType.JoinRoom; + return base.OpJoinRoom(opParams); + } + + /// NetworkingPeer.OpJoinRandomRoom + /// this override just makes sure we have a mRoomToGetInto, even if it's blank (the properties provided in this method are filters. they are not set when we join the game) + public override bool OpJoinRandomRoom(OpJoinRandomRoomParams opJoinRandomRoomParams) + { + enterRoomParamsCache = new EnterRoomParams(); // this is used when the client arrives on the GS and joins the room + enterRoomParamsCache.Lobby = opJoinRandomRoomParams.TypedLobby; + this.enterRoomParamsCache.ExpectedUsers = opJoinRandomRoomParams.ExpectedUsers; + + this.lastJoinType = JoinType.JoinRandomRoom; + return base.OpJoinRandomRoom(opJoinRandomRoomParams); + } + + /// + /// Operation Leave will exit any current room. + /// + /// + /// This also happens when you disconnect from the server. + /// Disconnect might be a step less if you don't want to create a new room on the same server. + /// + /// + public virtual bool OpLeave() + { + if (this.State != ClientState.Joined) + { + Debug.LogWarning("Not sending leave operation. State is not 'Joined': " + this.State); + return false; + } + + return this.OpCustom((byte)OperationCode.Leave, null, true, 0); + } + + public override bool OpRaiseEvent(byte eventCode, object customEventContent, bool sendReliable, RaiseEventOptions raiseEventOptions) + { + if (PhotonNetwork.offlineMode) + { + return false; + } + + return base.OpRaiseEvent(eventCode, customEventContent, sendReliable, raiseEventOptions); + } + + #endregion + + #region Helpers + + private void ReadoutProperties(Hashtable gameProperties, Hashtable pActorProperties, int targetActorNr) + { + // Debug.LogWarning("ReadoutProperties gameProperties: " + gameProperties.ToStringFull() + " pActorProperties: " + pActorProperties.ToStringFull() + " targetActorNr: " + targetActorNr); + + // read per-player properties (or those of one target player) and cache those locally + if (pActorProperties != null && pActorProperties.Count > 0) + { + if (targetActorNr > 0) + { + // we have a single entry in the pActorProperties with one + // user's name + // targets MUST exist before you set properties + PhotonPlayer target = this.GetPlayerWithId(targetActorNr); + if (target != null) + { + Hashtable props = this.ReadoutPropertiesForActorNr(pActorProperties, targetActorNr); + target.InternalCacheProperties(props); + SendMonoMessage(PhotonNetworkingMessage.OnPhotonPlayerPropertiesChanged, target, props); + } + } + else + { + // in this case, we've got a key-value pair per actor (each + // value is a hashtable with the actor's properties then) + int actorNr; + Hashtable props; + string newName; + PhotonPlayer target; + + foreach (object key in pActorProperties.Keys) + { + actorNr = (int)key; + props = (Hashtable)pActorProperties[key]; + newName = (string)props[ActorProperties.PlayerName]; + + target = this.GetPlayerWithId(actorNr); + if (target == null) + { + target = new PhotonPlayer(false, actorNr, newName); + this.AddNewPlayer(actorNr, target); + } + + target.InternalCacheProperties(props); + SendMonoMessage(PhotonNetworkingMessage.OnPhotonPlayerPropertiesChanged, target, props); + } + } + } + + // read game properties and cache them locally + if (this.CurrentRoom != null && gameProperties != null) + { + this.CurrentRoom.InternalCacheProperties(gameProperties); + SendMonoMessage(PhotonNetworkingMessage.OnPhotonCustomRoomPropertiesChanged, gameProperties); + if (PhotonNetwork.automaticallySyncScene) + { + this.LoadLevelIfSynced(); // will load new scene if sceneName was changed + } + } + } + + private Hashtable ReadoutPropertiesForActorNr(Hashtable actorProperties, int actorNr) + { + if (actorProperties.ContainsKey(actorNr)) + { + return (Hashtable)actorProperties[actorNr]; + } + + return actorProperties; + } + + public void ChangeLocalID(int newID) + { + if (this.LocalPlayer == null) + { + Debug.LogWarning(string.Format("LocalPlayer is null or not in mActors! LocalPlayer: {0} mActors==null: {1} newID: {2}",this.LocalPlayer,this.mActors == null,newID)); + } + + if (this.mActors.ContainsKey(this.LocalPlayer.ID)) + { + this.mActors.Remove(this.LocalPlayer.ID); + } + + this.LocalPlayer.InternalChangeLocalID(newID); + this.mActors[this.LocalPlayer.ID] = this.LocalPlayer; + this.RebuildPlayerListCopies(); + } + + /// + /// Called at disconnect/leavelobby etc. This CAN also be called when we are not in a lobby (e.g. disconnect from room) + /// + /// Calls callback method OnLeftLobby if this client was in a lobby initially. Clears the lobby's game lists. + private void LeftLobbyCleanup() + { + this.mGameList = new Dictionary(); + this.mGameListCopy = new RoomInfo[0]; + + if (this.insideLobby) + { + this.insideLobby = false; + SendMonoMessage(PhotonNetworkingMessage.OnLeftLobby); + } + } + + /// + /// Called when "this client" left a room to clean up. + /// + private void LeftRoomCleanup() + { + bool wasInRoom = this.CurrentRoom != null; + // when leaving a room, we clean up depending on that room's settings. + bool autoCleanupSettingOfRoom = (this.CurrentRoom != null) ? this.CurrentRoom.AutoCleanUp : PhotonNetwork.autoCleanUpPlayerObjects; + + this.hasSwitchedMC = false; + this.CurrentRoom = null; + this.mActors = new Dictionary(); + this.mPlayerListCopy = new PhotonPlayer[0]; + this.mOtherPlayerListCopy = new PhotonPlayer[0]; + this.allowedReceivingGroups = new HashSet(); + this.blockSendingGroups = new HashSet(); + this.mGameList = new Dictionary(); + this.mGameListCopy = new RoomInfo[0]; + this.isFetchingFriendList = false; + + this.ChangeLocalID(-1); + + // Cleanup all network objects (all spawned PhotonViews, local and remote) + if (autoCleanupSettingOfRoom) + { + this.LocalCleanupAnythingInstantiated(true); + PhotonNetwork.manuallyAllocatedViewIds = new List(); // filled and easier to replace completely + } + + if (wasInRoom) + { + SendMonoMessage(PhotonNetworkingMessage.OnLeftRoom); + } + } + + /// + /// Cleans up anything that was instantiated in-game (not loaded with the scene). + /// + protected internal void LocalCleanupAnythingInstantiated(bool destroyInstantiatedGameObjects) + { + if (this.tempInstantiationData.Count > 0) + { + Debug.LogWarning("It seems some instantiation is not completed, as instantiation data is used. You should make sure instantiations are paused when calling this method. Cleaning now, despite this."); + } + + // Destroy GO's (if we should) + if (destroyInstantiatedGameObjects) + { + // Fill list with Instantiated objects + HashSet instantiatedGos = new HashSet(); + foreach (PhotonView view in this.photonViewList.Values) + { + if (view.isRuntimeInstantiated) + { + instantiatedGos.Add(view.gameObject); // HashSet keeps each object only once + } + } + + foreach (GameObject go in instantiatedGos) + { + this.RemoveInstantiatedGO(go, true); + } + } + + // photonViewList is cleared of anything instantiated (so scene items are left inside) + // any other lists can be + this.tempInstantiationData.Clear(); // should be empty but to be safe we clear (no new list needed) + PhotonNetwork.lastUsedViewSubId = 0; + PhotonNetwork.lastUsedViewSubIdStatic = 0; + } + + + private void GameEnteredOnGameServer(OperationResponse operationResponse) + { + if (operationResponse.ReturnCode != 0) + { + switch (operationResponse.OperationCode) + { + case OperationCode.CreateGame: + if (PhotonNetwork.logLevel >= PhotonLogLevel.Informational) + { + Debug.Log("Create failed on GameServer. Changing back to MasterServer. Msg: " + operationResponse.DebugMessage); + } + SendMonoMessage(PhotonNetworkingMessage.OnPhotonCreateRoomFailed, operationResponse.ReturnCode, operationResponse.DebugMessage); + break; + case OperationCode.JoinGame: + if (PhotonNetwork.logLevel >= PhotonLogLevel.Informational) + { + Debug.Log("Join failed on GameServer. Changing back to MasterServer. Msg: " + operationResponse.DebugMessage); + if (operationResponse.ReturnCode == ErrorCode.GameDoesNotExist) + { + Debug.Log("Most likely the game became empty during the switch to GameServer."); + } + } + SendMonoMessage(PhotonNetworkingMessage.OnPhotonJoinRoomFailed, operationResponse.ReturnCode, operationResponse.DebugMessage); + break; + case OperationCode.JoinRandomGame: + if (PhotonNetwork.logLevel >= PhotonLogLevel.Informational) + { + Debug.Log("Join failed on GameServer. Changing back to MasterServer. Msg: " + operationResponse.DebugMessage); + if (operationResponse.ReturnCode == ErrorCode.GameDoesNotExist) + { + Debug.Log("Most likely the game became empty during the switch to GameServer."); + } + } + SendMonoMessage(PhotonNetworkingMessage.OnPhotonRandomJoinFailed, operationResponse.ReturnCode, operationResponse.DebugMessage); + break; + } + + this.DisconnectToReconnect(); + return; + } + + Room current = new Room(this.enterRoomParamsCache.RoomName, null); + current.IsLocalClientInside = true; + this.CurrentRoom = current; + + this.State = ClientState.Joined; + + if (operationResponse.Parameters.ContainsKey(ParameterCode.ActorList)) + { + int[] actorsInRoom = (int[])operationResponse.Parameters[ParameterCode.ActorList]; + this.UpdatedActorList(actorsInRoom); + } + + // the local player's actor-properties are not returned in join-result. add this player to the list + int localActorNr = (int)operationResponse[ParameterCode.ActorNr]; + this.ChangeLocalID(localActorNr); + + + Hashtable actorProperties = (Hashtable)operationResponse[ParameterCode.PlayerProperties]; + Hashtable gameProperties = (Hashtable)operationResponse[ParameterCode.GameProperties]; + this.ReadoutProperties(gameProperties, actorProperties, 0); + + if (!this.CurrentRoom.serverSideMasterClient) this.CheckMasterClient(-1); + + if (this.mPlayernameHasToBeUpdated) + { + this.SendPlayerName(); + } + + switch (operationResponse.OperationCode) + { + case OperationCode.CreateGame: + SendMonoMessage(PhotonNetworkingMessage.OnCreatedRoom); + break; + case OperationCode.JoinGame: + case OperationCode.JoinRandomGame: + // the mono message for this is sent at another place + break; + } + } + + private void AddNewPlayer(int ID, PhotonPlayer player) + { + if (!this.mActors.ContainsKey(ID)) + { + this.mActors[ID] = player; + RebuildPlayerListCopies(); + } + else + { + Debug.LogError("Adding player twice: " + ID); + } + } + + void RemovePlayer(int ID, PhotonPlayer player) + { + this.mActors.Remove(ID); + if (!player.IsLocal) + { + RebuildPlayerListCopies(); + } + } + + void RebuildPlayerListCopies() + { + this.mPlayerListCopy = new PhotonPlayer[this.mActors.Count]; + this.mActors.Values.CopyTo(this.mPlayerListCopy, 0); + + List otherP = new List(); + for (int i = 0; i < this.mPlayerListCopy.Length; i++) + { + PhotonPlayer player = this.mPlayerListCopy[i]; + if (!player.IsLocal) + { + otherP.Add(player); + } + } + + this.mOtherPlayerListCopy = otherP.ToArray(); + } + + /// + /// Resets the PhotonView "lastOnSerializeDataSent" so that "OnReliable" synched PhotonViews send a complete state to new clients (if the state doesnt change, no messages would be send otherwise!). + /// Note that due to this reset, ALL other players will receive the full OnSerialize. + /// + private void ResetPhotonViewsOnSerialize() + { + foreach (PhotonView photonView in this.photonViewList.Values) + { + photonView.lastOnSerializeDataSent = null; + } + } + + /// + /// Called when the event Leave (of some other player) arrived. + /// Cleans game objects, views locally. The master will also clean the + /// + /// ID of player who left. + private void HandleEventLeave(int actorID, EventData evLeave) + { + if (PhotonNetwork.logLevel >= PhotonLogLevel.Informational) + Debug.Log("HandleEventLeave for player ID: " + actorID + " evLeave: " + evLeave.ToStringFull()); + + + // actorNr is fetched out of event + PhotonPlayer player = this.GetPlayerWithId(actorID); + if (player == null) + { + Debug.LogError(String.Format("Received event Leave for unknown player ID: {0}", actorID)); + return; + } + + bool _isAlreadyInactive = player.IsInactive; + + if (evLeave.Parameters.ContainsKey(ParameterCode.IsInactive)) + { + // player becomes inactive (but might return / is not gone for good) + player.IsInactive = (bool)evLeave.Parameters[ParameterCode.IsInactive]; + + + if (player.IsInactive != _isAlreadyInactive) + { + SendMonoMessage(PhotonNetworkingMessage.OnPhotonPlayerActivityChanged, player); + } + + if (player.IsInactive && _isAlreadyInactive) + { + Debug.LogWarning("HandleEventLeave for player ID: " + actorID + " isInactive: " + player.IsInactive + ". Stopping handling if inactive."); + return; + } + } + + // having a new master before calling destroy for the leaving player is important! + // so we elect a new masterclient and ignore the leaving player (who is still in playerlists). + // note: there is/was a server-side-error which sent 0 as new master instead of skipping the key/value. below is a check for 0 due to that + if (evLeave.Parameters.ContainsKey(ParameterCode.MasterClientId)) + { + int newMaster = (int) evLeave[ParameterCode.MasterClientId]; + if (newMaster != 0) + { + this.mMasterClientId = (int)evLeave[ParameterCode.MasterClientId]; + this.UpdateMasterClient(); + } + } + else if (!this.CurrentRoom.serverSideMasterClient) + { + this.CheckMasterClient(actorID); + } + + + // we let the player up if inactive but if we were already inactive, then we have to actually remove the player properly. + if (player.IsInactive && !_isAlreadyInactive) + { + return; + } + + // destroy objects & buffered messages + if (this.CurrentRoom != null && this.CurrentRoom.AutoCleanUp) + { + this.DestroyPlayerObjects(actorID, true); + } + + RemovePlayer(actorID, player); + + // finally, send notification (the playerList and masterclient are now updated) + SendMonoMessage(PhotonNetworkingMessage.OnPhotonPlayerDisconnected, player); + } + + /// Picks the new master client from player list, if the current Master is leaving (leavingPlayerId) or if no master was assigned so far. + /// + /// The ignored player is the one who's leaving and should not become master (again). Pass -1 to select any player from the list. + /// + private void CheckMasterClient(int leavingPlayerId) + { + bool currentMasterIsLeaving = this.mMasterClientId == leavingPlayerId; + bool someoneIsLeaving = leavingPlayerId > 0; + + // return early if SOME player (leavingId > 0) is leaving AND it's NOT the current master + if (someoneIsLeaving && !currentMasterIsLeaving) + { + return; + } + + // picking the player with lowest ID (longest in game). + int lowestActorNumber; + if (this.mActors.Count <= 1) + { + lowestActorNumber = this.LocalPlayer.ID; + } + else + { + // keys in mActors are their actorNumbers + lowestActorNumber = Int32.MaxValue; + foreach (int key in this.mActors.Keys) + { + if (key < lowestActorNumber && key != leavingPlayerId) + { + lowestActorNumber = key; + } + } + } + this.mMasterClientId = lowestActorNumber; + + // callback ONLY when the current master left + if (someoneIsLeaving) + { + SendMonoMessage(PhotonNetworkingMessage.OnMasterClientSwitched, this.GetPlayerWithId(lowestActorNumber)); + } + } + + /// Call when the server provides a MasterClientId (due to joining or the current MC leaving, etc). + internal protected void UpdateMasterClient() + { + SendMonoMessage(PhotonNetworkingMessage.OnMasterClientSwitched, PhotonNetwork.masterClient); + } + + private static int ReturnLowestPlayerId(PhotonPlayer[] players, int playerIdToIgnore) + { + if (players == null || players.Length == 0) + { + return -1; + } + + int lowestActorNumber = Int32.MaxValue; + for (int i = 0; i < players.Length; i++) + { + PhotonPlayer photonPlayer = players[i]; + if (photonPlayer.ID == playerIdToIgnore) + { + continue; + } + + if (photonPlayer.ID < lowestActorNumber) + { + lowestActorNumber = photonPlayer.ID; + } + } + + return lowestActorNumber; + } + + /// Fake-sets a new Master Client for this room via RaiseEvent. + /// Does not affect RaiseEvent with target MasterClient but RPC(). + internal protected bool SetMasterClient(int playerId, bool sync) + { + bool masterReplaced = this.mMasterClientId != playerId; + if (!masterReplaced || !this.mActors.ContainsKey(playerId)) + { + return false; + } + + if (sync) + { + bool sent = this.OpRaiseEvent(PunEvent.AssignMaster, new Hashtable() { { (byte)1, playerId } }, true, null); + if (!sent) + { + return false; + } + } + + this.hasSwitchedMC = true; + this.CurrentRoom.MasterClientId = playerId; + SendMonoMessage(PhotonNetworkingMessage.OnMasterClientSwitched, this.GetPlayerWithId(playerId)); // we only callback when an actual change is done + return true; + } + + /// Uses a well-known property to set someone new as Master Client in room (requires "Server Side Master Client" feature). + public bool SetMasterClient(int nextMasterId) + { + Hashtable newProps = new Hashtable() { { GamePropertyKey.MasterClientId, nextMasterId } }; + Hashtable prevProps = new Hashtable() { { GamePropertyKey.MasterClientId, this.mMasterClientId } }; + return this.OpSetPropertiesOfRoom(newProps, expectedProperties: prevProps, webForward: false); + } + + protected internal PhotonPlayer GetPlayerWithId(int number) + { + if (this.mActors == null) return null; + + PhotonPlayer player = null; + this.mActors.TryGetValue(number, out player); + return player; + } + + private void SendPlayerName() + { + if (this.State == ClientState.Joining) + { + // this means, the join on the gameServer is sent (with an outdated name). send the new when in game + this.mPlayernameHasToBeUpdated = true; + return; + } + + if (this.LocalPlayer != null) + { + this.LocalPlayer.NickName = this.PlayerName; + Hashtable properties = new Hashtable(); + properties[ActorProperties.PlayerName] = this.PlayerName; + if (this.LocalPlayer.ID > 0) + { + this.OpSetPropertiesOfActor(this.LocalPlayer.ID, properties, null); + this.mPlayernameHasToBeUpdated = false; + } + } + } + + private Hashtable GetLocalActorProperties() + { + if (PhotonNetwork.player != null) + { + return PhotonNetwork.player.AllProperties; + } + + Hashtable actorProperties = new Hashtable(); + actorProperties[ActorProperties.PlayerName] = this.PlayerName; + return actorProperties; + } + + #endregion + + #region Implementation of IPhotonPeerListener + + public void DebugReturn(DebugLevel level, string message) + { + if (level == DebugLevel.ERROR) + { + Debug.LogError(message); + } + else if (level == DebugLevel.WARNING) + { + Debug.LogWarning(message); + } + else if (level == DebugLevel.INFO && PhotonNetwork.logLevel >= PhotonLogLevel.Informational) + { + Debug.Log(message); + } + else if (level == DebugLevel.ALL && PhotonNetwork.logLevel == PhotonLogLevel.Full) + { + Debug.Log(message); + } + } + + public void OnOperationResponse(OperationResponse operationResponse) + { + if (PhotonNetwork.networkingPeer.State == ClientState.Disconnecting) + { + if (PhotonNetwork.logLevel >= PhotonLogLevel.Informational) + { + Debug.Log("OperationResponse ignored while disconnecting. Code: " + operationResponse.OperationCode); + } + return; + } + + // extra logging for error debugging (helping developers with a bit of automated analysis) + if (operationResponse.ReturnCode == 0) + { + if (PhotonNetwork.logLevel >= PhotonLogLevel.Informational) + Debug.Log(operationResponse.ToString()); + } + else + { + if (operationResponse.ReturnCode == ErrorCode.OperationNotAllowedInCurrentState) + { + Debug.LogError("Operation " + operationResponse.OperationCode + " could not be executed (yet). Wait for state JoinedLobby or ConnectedToMaster and their callbacks before calling operations. WebRPCs need a server-side configuration. Enum OperationCode helps identify the operation."); + } + else if (operationResponse.ReturnCode == ErrorCode.PluginReportedError) + { + Debug.LogError("Operation " + operationResponse.OperationCode + " failed in a server-side plugin. Check the configuration in the Dashboard. Message from server-plugin: " + operationResponse.DebugMessage); + } + else if (operationResponse.ReturnCode == ErrorCode.NoRandomMatchFound) + { + Debug.LogWarning("Operation failed: " + operationResponse.ToStringFull()); + } + else + { + Debug.LogError("Operation failed: " + operationResponse.ToStringFull() + " Server: " + this.Server); + } + } + + // use the "secret" or "token" whenever we get it. doesn't really matter if it's in AuthResponse. + if (operationResponse.Parameters.ContainsKey(ParameterCode.Secret)) + { + if (this.AuthValues == null) + { + this.AuthValues = new AuthenticationValues(); + // this.DebugReturn(DebugLevel.ERROR, "Server returned secret. Created AuthValues."); + } + + this.AuthValues.Token = operationResponse[ParameterCode.Secret] as string; + this.tokenCache = this.AuthValues.Token; + } + + switch (operationResponse.OperationCode) + { + case OperationCode.Authenticate: + case OperationCode.AuthenticateOnce: + { + // ClientState oldState = this.State; + + if (operationResponse.ReturnCode != 0) + { + if (operationResponse.ReturnCode == ErrorCode.InvalidOperation) + { + Debug.LogError(string.Format("If you host Photon yourself, make sure to start the 'Instance LoadBalancing' "+ this.ServerAddress)); + } + else if (operationResponse.ReturnCode == ErrorCode.InvalidAuthentication) + { + Debug.LogError(string.Format("The appId this client sent is unknown on the server (Cloud). Check settings. If using the Cloud, check account.")); + SendMonoMessage(PhotonNetworkingMessage.OnFailedToConnectToPhoton, DisconnectCause.InvalidAuthentication); + } + else if (operationResponse.ReturnCode == ErrorCode.CustomAuthenticationFailed) + { + Debug.LogError(string.Format("Custom Authentication failed (either due to user-input or configuration or AuthParameter string format). Calling: OnCustomAuthenticationFailed()")); + SendMonoMessage(PhotonNetworkingMessage.OnCustomAuthenticationFailed, operationResponse.DebugMessage); + } + else + { + Debug.LogError(string.Format("Authentication failed: '{0}' Code: {1}", operationResponse.DebugMessage, operationResponse.ReturnCode)); + } + + this.State = ClientState.Disconnecting; + this.Disconnect(); + + if (operationResponse.ReturnCode == ErrorCode.MaxCcuReached) + { + if (PhotonNetwork.logLevel >= PhotonLogLevel.Informational) + Debug.LogWarning(string.Format("Currently, the limit of users is reached for this title. Try again later. Disconnecting")); + SendMonoMessage(PhotonNetworkingMessage.OnPhotonMaxCccuReached); + SendMonoMessage(PhotonNetworkingMessage.OnConnectionFail, DisconnectCause.MaxCcuReached); + } + else if (operationResponse.ReturnCode == ErrorCode.InvalidRegion) + { + if (PhotonNetwork.logLevel >= PhotonLogLevel.Informational) + Debug.LogError(string.Format("The used master server address is not available with the subscription currently used. Got to Photon Cloud Dashboard or change URL. Disconnecting.")); + SendMonoMessage(PhotonNetworkingMessage.OnConnectionFail, DisconnectCause.InvalidRegion); + } + else if (operationResponse.ReturnCode == ErrorCode.AuthenticationTicketExpired) + { + if (PhotonNetwork.logLevel >= PhotonLogLevel.Informational) + Debug.LogError(string.Format("The authentication ticket expired. You need to connect (and authenticate) again. Disconnecting.")); + SendMonoMessage(PhotonNetworkingMessage.OnConnectionFail, DisconnectCause.AuthenticationTicketExpired); + } + break; + } + else + { + // successful connect/auth. depending on the used server, do next steps: + + if (this.Server == ServerConnection.NameServer || this.Server == ServerConnection.MasterServer) + { + if (operationResponse.Parameters.ContainsKey(ParameterCode.UserId)) + { + string incomingId = (string)operationResponse.Parameters[ParameterCode.UserId]; + if (!string.IsNullOrEmpty(incomingId)) + { + if (this.AuthValues == null) + { + this.AuthValues = new AuthenticationValues(); + } + this.AuthValues.UserId = incomingId; + PhotonNetwork.player.UserId = incomingId; + + if (PhotonNetwork.logLevel >= PhotonLogLevel.Informational) + { + this.DebugReturn(DebugLevel.INFO, string.Format("Received your UserID from server. Updating local value to: {0}", incomingId)); + } + } + } + if (operationResponse.Parameters.ContainsKey(ParameterCode.NickName)) + { + this.playername = (string)operationResponse.Parameters[ParameterCode.NickName]; + if (PhotonNetwork.logLevel >= PhotonLogLevel.Informational) + { + this.DebugReturn(DebugLevel.INFO, string.Format("Received your NickName from server. Updating local value to: {0}", this.playername)); + } + } + + if (operationResponse.Parameters.ContainsKey(ParameterCode.EncryptionData)) + { + this.SetupEncryption((Dictionary)operationResponse.Parameters[ParameterCode.EncryptionData]); + } + } + + if (this.Server == ServerConnection.NameServer) + { + // on the NameServer, authenticate returns the MasterServer address for a region and we hop off to there + this.MasterServerAddress = operationResponse[ParameterCode.Address] as string; + this.DisconnectToReconnect(); + } + else if (this.Server == ServerConnection.MasterServer) + { + if (this.AuthMode != AuthModeOption.Auth) + { + this.OpSettings(this.requestLobbyStatistics); + } + if (PhotonNetwork.autoJoinLobby) + { + this.State = ClientState.Authenticated; + this.OpJoinLobby(this.lobby); + } + else + { + this.State = ClientState.ConnectedToMaster; + SendMonoMessage(PhotonNetworkingMessage.OnConnectedToMaster); + } + } + else if (this.Server == ServerConnection.GameServer) + { + this.State = ClientState.Joining; + this.enterRoomParamsCache.PlayerProperties = GetLocalActorProperties(); + this.enterRoomParamsCache.OnGameServer = true; + + if (this.lastJoinType == JoinType.JoinRoom || this.lastJoinType == JoinType.JoinRandomRoom || this.lastJoinType == JoinType.JoinOrCreateRoom) + { + // if we just "join" the game, do so. if we wanted to "create the room on demand", we have to send this to the game server as well. + this.OpJoinRoom(this.enterRoomParamsCache); + } + else if (this.lastJoinType == JoinType.CreateRoom) + { + this.OpCreateGame(this.enterRoomParamsCache); + } + } + + if (operationResponse.Parameters.ContainsKey(ParameterCode.Data)) + { + // optionally, OpAuth may return some data for the client to use. if it's available, call OnCustomAuthenticationResponse + Dictionary data = (Dictionary)operationResponse.Parameters[ParameterCode.Data]; + if (data != null) + { + SendMonoMessage(PhotonNetworkingMessage.OnCustomAuthenticationResponse, data); + } + } + } + break; + } + + case OperationCode.GetRegions: + // Debug.Log("GetRegions returned: " + operationResponse.ToStringFull()); + + if (operationResponse.ReturnCode == ErrorCode.InvalidAuthentication) + { + Debug.LogError(string.Format("The appId this client sent is unknown on the server (Cloud). Check settings. If using the Cloud, check account.")); + SendMonoMessage(PhotonNetworkingMessage.OnFailedToConnectToPhoton, DisconnectCause.InvalidAuthentication); + + this.State = ClientState.Disconnecting; + this.Disconnect(); + break; + } + if (operationResponse.ReturnCode != ErrorCode.Ok) + { + Debug.LogError("GetRegions failed. Can't provide regions list. Error: " + operationResponse.ReturnCode + ": " + operationResponse.DebugMessage); + break; + } + + string[] regions = operationResponse[ParameterCode.Region] as string[]; + string[] servers = operationResponse[ParameterCode.Address] as string[]; + if (regions == null || servers == null || regions.Length != servers.Length) + { + Debug.LogError("The region arrays from Name Server are not ok. Must be non-null and same length. " + (regions ==null)+ " " + (servers==null) + "\n"+operationResponse.ToStringFull()); + break; + } + + this.AvailableRegions = new List(regions.Length); + for (int i = 0; i < regions.Length; i++) + { + string regionCodeString = regions[i]; + if (string.IsNullOrEmpty(regionCodeString)) + { + continue; + } + regionCodeString = regionCodeString.ToLower(); + CloudRegionCode code = Region.Parse(regionCodeString); + + // check if enabled (or ignored by PhotonServerSettings.EnabledRegions) + bool enabledRegion = true; + if (PhotonNetwork.PhotonServerSettings.HostType == ServerSettings.HostingOption.BestRegion && PhotonNetwork.PhotonServerSettings.EnabledRegions != 0) + { + CloudRegionFlag flag = Region.ParseFlag(code); + enabledRegion = ((PhotonNetwork.PhotonServerSettings.EnabledRegions & flag) != 0); + if (!enabledRegion && PhotonNetwork.logLevel >= PhotonLogLevel.Informational) + { + Debug.Log("Skipping region because it's not in PhotonServerSettings.EnabledRegions: " + code); + } + } + if (enabledRegion) + { + this.AvailableRegions.Add(new Region(code, regionCodeString, servers[i])); + } + } + + // PUN assumes you fetch the name-server's list of regions to ping them + if (PhotonNetwork.PhotonServerSettings.HostType == ServerSettings.HostingOption.BestRegion) + { + PhotonHandler.PingAvailableRegionsAndConnectToBest(); + } + break; + + case OperationCode.CreateGame: + { + if (this.Server == ServerConnection.GameServer) + { + this.GameEnteredOnGameServer(operationResponse); + } + else + { + if (operationResponse.ReturnCode != 0) + { + if (PhotonNetwork.logLevel >= PhotonLogLevel.Informational) + Debug.LogWarning(string.Format("CreateRoom failed, client stays on masterserver: {0}.", operationResponse.ToStringFull())); + + this.State = (this.insideLobby) ? ClientState.JoinedLobby : ClientState.ConnectedToMaster; + SendMonoMessage(PhotonNetworkingMessage.OnPhotonCreateRoomFailed, operationResponse.ReturnCode, operationResponse.DebugMessage); + break; + } + + string gameID = (string) operationResponse[ParameterCode.RoomName]; + if (!string.IsNullOrEmpty(gameID)) + { + // is only sent by the server's response, if it has not been + // sent with the client's request before! + this.enterRoomParamsCache.RoomName = gameID; + } + + this.GameServerAddress = (string)operationResponse[ParameterCode.Address]; + this.DisconnectToReconnect(); + } + + break; + } + + case OperationCode.JoinGame: + { + if (this.Server != ServerConnection.GameServer) + { + if (operationResponse.ReturnCode != 0) + { + if (PhotonNetwork.logLevel >= PhotonLogLevel.Informational) + Debug.Log(string.Format("JoinRoom failed (room maybe closed by now). Client stays on masterserver: {0}. State: {1}", operationResponse.ToStringFull(), this.State)); + + SendMonoMessage(PhotonNetworkingMessage.OnPhotonJoinRoomFailed, operationResponse.ReturnCode, operationResponse.DebugMessage); + break; + } + + this.GameServerAddress = (string)operationResponse[ParameterCode.Address]; + this.DisconnectToReconnect(); + } + else + { + this.GameEnteredOnGameServer(operationResponse); + } + + break; + } + + case OperationCode.JoinRandomGame: + { + // happens only on master. on gameserver, this is a regular join (we don't need to find a random game again) + // the operation OpJoinRandom either fails (with returncode 8) or returns game-to-join information + if (operationResponse.ReturnCode != 0) + { + if (operationResponse.ReturnCode == ErrorCode.NoRandomMatchFound) + { + if (PhotonNetwork.logLevel >= PhotonLogLevel.Full) + Debug.Log("JoinRandom failed: No open game. Calling: OnPhotonRandomJoinFailed() and staying on master server."); + } + else if (PhotonNetwork.logLevel >= PhotonLogLevel.Informational) + { + Debug.LogWarning(string.Format("JoinRandom failed: {0}.", operationResponse.ToStringFull())); + } + + SendMonoMessage(PhotonNetworkingMessage.OnPhotonRandomJoinFailed, operationResponse.ReturnCode, operationResponse.DebugMessage); + break; + } + + string roomName = (string)operationResponse[ParameterCode.RoomName]; + this.enterRoomParamsCache.RoomName = roomName; + this.GameServerAddress = (string)operationResponse[ParameterCode.Address]; + this.DisconnectToReconnect(); + break; + } + + case OperationCode.GetGameList: + if (operationResponse.ReturnCode != 0) + { + this.DebugReturn(DebugLevel.ERROR, "GetGameList failed: " + operationResponse.ToStringFull()); + break; + } + + this.mGameList = new Dictionary(); + Hashtable games = (Hashtable)operationResponse[ParameterCode.GameList]; + foreach (var gameKey in games.Keys) + { + string gameName = (string)gameKey; + this.mGameList[gameName] = new RoomInfo(gameName, (Hashtable)games[gameKey]); + } + mGameListCopy = new RoomInfo[mGameList.Count]; + mGameList.Values.CopyTo(mGameListCopy, 0); + SendMonoMessage(PhotonNetworkingMessage.OnReceivedRoomListUpdate); + break; + + case OperationCode.JoinLobby: + this.State = ClientState.JoinedLobby; + this.insideLobby = true; + SendMonoMessage(PhotonNetworkingMessage.OnJoinedLobby); + + // this.mListener.joinLobbyReturn(); + break; + case OperationCode.LeaveLobby: + this.State = ClientState.Authenticated; + this.LeftLobbyCleanup(); // will set insideLobby = false + break; + + case OperationCode.Leave: + this.DisconnectToReconnect(); + break; + + case OperationCode.SetProperties: + // this.mListener.setPropertiesReturn(returnCode, debugMsg); + break; + + case OperationCode.GetProperties: + { + Hashtable actorProperties = (Hashtable)operationResponse[ParameterCode.PlayerProperties]; + Hashtable gameProperties = (Hashtable)operationResponse[ParameterCode.GameProperties]; + this.ReadoutProperties(gameProperties, actorProperties, 0); + + // RemoveByteTypedPropertyKeys(actorProperties, false); + // RemoveByteTypedPropertyKeys(gameProperties, false); + // this.mListener.getPropertiesReturn(gameProperties, actorProperties, returnCode, debugMsg); + break; + } + + case OperationCode.RaiseEvent: + // this usually doesn't give us a result. only if the caching is affected the server will send one. + break; + + case OperationCode.FindFriends: + bool[] onlineList = operationResponse[ParameterCode.FindFriendsResponseOnlineList] as bool[]; + string[] roomList = operationResponse[ParameterCode.FindFriendsResponseRoomIdList] as string[]; + + if (onlineList != null && roomList != null && this.friendListRequested != null && onlineList.Length == this.friendListRequested.Length) + { + List friendList = new List(this.friendListRequested.Length); + for (int index = 0; index < this.friendListRequested.Length; index++) + { + FriendInfo friend = new FriendInfo(); + friend.Name = this.friendListRequested[index]; + friend.Room = roomList[index]; + friend.IsOnline = onlineList[index]; + friendList.Insert(index, friend); + } + PhotonNetwork.Friends = friendList; + } + else + { + // any of the lists is null and shouldn't. print a error + Debug.LogError("FindFriends failed to apply the result, as a required value wasn't provided or the friend list length differed from result."); + } + + this.friendListRequested = null; + this.isFetchingFriendList = false; + this.friendListTimestamp = Environment.TickCount; + if (this.friendListTimestamp == 0) + { + this.friendListTimestamp = 1; // makes sure the timestamp is not accidentally 0 + } + + SendMonoMessage(PhotonNetworkingMessage.OnUpdatedFriendList); + break; + + case OperationCode.WebRpc: + SendMonoMessage(PhotonNetworkingMessage.OnWebRpcResponse, operationResponse); + break; + + default: + Debug.LogWarning(string.Format("OperationResponse unhandled: {0}", operationResponse.ToString())); + break; + } + + //this.externalListener.OnOperationResponse(operationResponse); + } + + public void OnStatusChanged(StatusCode statusCode) + { + if (PhotonNetwork.logLevel >= PhotonLogLevel.Informational) + Debug.Log(string.Format("OnStatusChanged: {0} current State: {1}", statusCode.ToString(), this.State)); + + switch (statusCode) + { + case StatusCode.Connect: + if (this.State == ClientState.ConnectingToNameServer) + { + if (PhotonNetwork.logLevel >= PhotonLogLevel.Full) + Debug.Log("Connected to NameServer."); + + this.Server = ServerConnection.NameServer; + if (this.AuthValues != null) + { + this.AuthValues.Token = null; // when connecting to NameServer, invalidate any auth values + } + } + + if (this.State == ClientState.ConnectingToGameserver) + { + if (PhotonNetwork.logLevel >= PhotonLogLevel.Full) + Debug.Log("Connected to gameserver."); + + this.Server = ServerConnection.GameServer; + this.State = ClientState.ConnectedToGameserver; + } + + if (this.State == ClientState.ConnectingToMasterserver) + { + if (PhotonNetwork.logLevel >= PhotonLogLevel.Full) + Debug.Log("Connected to masterserver."); + + this.Server = ServerConnection.MasterServer; + this.State = ClientState.Authenticating; // photon v4 always requires OpAuthenticate. even self-hosted Photon Server + + if (this.IsInitialConnect) + { + this.IsInitialConnect = false; // after handling potential initial-connect issues with special messages, we are now sure we can reach a server + SendMonoMessage(PhotonNetworkingMessage.OnConnectedToPhoton); + } + } + + + if (this.TransportProtocol != ConnectionProtocol.WebSocketSecure) + { + if (this.Server == ServerConnection.NameServer || this.AuthMode == AuthModeOption.Auth) + { + this.EstablishEncryption(); + } + } + else + { + if (DebugOut == DebugLevel.INFO) + { + Debug.Log("Skipping EstablishEncryption. Protocol is secure."); + } + + goto case StatusCode.EncryptionEstablished; + } + break; + + case StatusCode.EncryptionEstablished: + // on nameserver, the "process" is stopped here, so the developer/game can either get regions or authenticate with a specific region + if (this.Server == ServerConnection.NameServer) + { + this.State = ClientState.ConnectedToNameServer; + + if (!this.didAuthenticate && this.CloudRegion == CloudRegionCode.none) + { + // this client is not setup to connect to a default region. find out which regions there are! + this.OpGetRegions(this.AppId); + } + } + + if (this.Server != ServerConnection.NameServer && (this.AuthMode == AuthModeOption.AuthOnce || this.AuthMode == AuthModeOption.AuthOnceWss)) + { + // AuthMode "Once" means we only authenticate on the NameServer + break; + } + + + // we might need to authenticate automatically now, so the client can do anything at all + if (!this.didAuthenticate && (!this.IsUsingNameServer || this.CloudRegion != CloudRegionCode.none)) + { + this.didAuthenticate = this.CallAuthenticate(); + + if (this.didAuthenticate) + { + this.State = ClientState.Authenticating; + } + } + break; + + case StatusCode.EncryptionFailedToEstablish: + Debug.LogError("Encryption wasn't established: " + statusCode + ". Going to authenticate anyways."); + AuthenticationValues authV = this.AuthValues ?? new AuthenticationValues() { UserId = this.PlayerName }; + this.OpAuthenticate(this.AppId, this.AppVersion, authV, this.CloudRegion.ToString(), this.requestLobbyStatistics); // TODO: check if there are alternatives + break; + + case StatusCode.Disconnect: + this.didAuthenticate = false; + this.isFetchingFriendList = false; + if (this.Server == ServerConnection.GameServer) this.LeftRoomCleanup(); + if (this.Server == ServerConnection.MasterServer) this.LeftLobbyCleanup(); + + if (this.State == ClientState.DisconnectingFromMasterserver) + { + if (this.Connect(this.GameServerAddress, ServerConnection.GameServer)) + { + this.State = ClientState.ConnectingToGameserver; + } + } + else if (this.State == ClientState.DisconnectingFromGameserver || this.State == ClientState.DisconnectingFromNameServer) + { + this.SetupProtocol(ServerConnection.MasterServer); + if (this.Connect(this.MasterServerAddress, ServerConnection.MasterServer)) + { + this.State = ClientState.ConnectingToMasterserver; + } + } + else + { + if (this.AuthValues != null) + { + this.AuthValues.Token = null; // invalidate any custom auth secrets + } + + this.IsInitialConnect = false; // not "connecting" anymore + this.State = ClientState.PeerCreated; // if we set another state here, we could keep clients from connecting in OnDisconnectedFromPhoton right here. + SendMonoMessage(PhotonNetworkingMessage.OnDisconnectedFromPhoton); + } + break; + + case StatusCode.ExceptionOnConnect: + case StatusCode.SecurityExceptionOnConnect: + + this.IsInitialConnect = false; + + this.State = ClientState.PeerCreated; + if (this.AuthValues != null) + { + this.AuthValues.Token = null; // invalidate any custom auth secrets + } + + DisconnectCause cause = (DisconnectCause)statusCode; + SendMonoMessage(PhotonNetworkingMessage.OnFailedToConnectToPhoton, cause); + break; + + case StatusCode.Exception: + if (this.IsInitialConnect) + { + Debug.LogError("Exception while connecting to: " + this.ServerAddress + ". Check if the server is available."); + if (this.ServerAddress == null || this.ServerAddress.StartsWith("127.0.0.1")) + { + Debug.LogWarning("The server address is 127.0.0.1 (localhost): Make sure the server is running on this machine. Android and iOS emulators have their own localhost."); + if (this.ServerAddress == this.GameServerAddress) + { + Debug.LogWarning("This might be a misconfiguration in the game server config. You need to edit it to a (public) address."); + } + } + + this.State = ClientState.PeerCreated; + cause = (DisconnectCause)statusCode; + this.IsInitialConnect = false; + SendMonoMessage(PhotonNetworkingMessage.OnFailedToConnectToPhoton, cause); + } + else + { + this.State = ClientState.PeerCreated; + + cause = (DisconnectCause)statusCode; + SendMonoMessage(PhotonNetworkingMessage.OnConnectionFail, cause); + } + + this.Disconnect(); + break; + + case StatusCode.TimeoutDisconnect: + if (this.IsInitialConnect) + { + Debug.LogWarning(statusCode + " while connecting to: " + this.ServerAddress + ". Check if the server is available."); + + this.IsInitialConnect = false; + cause = (DisconnectCause)statusCode; + SendMonoMessage(PhotonNetworkingMessage.OnFailedToConnectToPhoton, cause); + } + else + { + cause = (DisconnectCause)statusCode; + SendMonoMessage(PhotonNetworkingMessage.OnConnectionFail, cause); + } + if (this.AuthValues != null) + { + this.AuthValues.Token = null; // invalidate any custom auth secrets + } + + /* JF: we need this when reconnecting and joining. + if (this.ServerAddress.Equals(this.GameServerAddress)) + { + this.GameServerAddress = null; + } + if (this.ServerAddress.Equals(this.MasterServerAddress)) + { + this.ServerAddress = null; + } + */ + + this.Disconnect(); + break; + + case StatusCode.ExceptionOnReceive: + case StatusCode.DisconnectByServer: + case StatusCode.DisconnectByServerLogic: + case StatusCode.DisconnectByServerUserLimit: + if (this.IsInitialConnect) + { + Debug.LogWarning(statusCode + " while connecting to: " + this.ServerAddress + ". Check if the server is available."); + + this.IsInitialConnect = false; + cause = (DisconnectCause)statusCode; + SendMonoMessage(PhotonNetworkingMessage.OnFailedToConnectToPhoton, cause); + } + else + { + cause = (DisconnectCause)statusCode; + SendMonoMessage(PhotonNetworkingMessage.OnConnectionFail, cause); + } + if (this.AuthValues != null) + { + this.AuthValues.Token = null; // invalidate any custom auth secrets + } + + this.Disconnect(); + break; + + case StatusCode.SendError: + // this.mListener.clientErrorReturn(statusCode); + break; + + //case StatusCode.QueueOutgoingReliableWarning: + //case StatusCode.QueueOutgoingUnreliableWarning: + //case StatusCode.QueueOutgoingAcksWarning: + //case StatusCode.QueueSentWarning: + // // this.mListener.warningReturn(statusCode); + // break; + + //case StatusCode.QueueIncomingReliableWarning: + //case StatusCode.QueueIncomingUnreliableWarning: + // Debug.Log(statusCode + ". This client buffers many incoming messages. This is OK temporarily. With lots of these warnings, check if you send too much or execute messages too slow. " + (PhotonNetwork.isMessageQueueRunning? "":"Your isMessageQueueRunning is false. This can cause the issue temporarily.") ); + // break; + + // // TCP "routing" is an option of Photon that's not currently needed (or supported) by PUN + //case StatusCode.TcpRouterResponseOk: + // break; + //case StatusCode.TcpRouterResponseEndpointUnknown: + //case StatusCode.TcpRouterResponseNodeIdUnknown: + //case StatusCode.TcpRouterResponseNodeNotReady: + + // this.DebugReturn(DebugLevel.ERROR, "Unexpected router response: " + statusCode); + // break; + + default: + + // this.mListener.serverErrorReturn(statusCode.value()); + Debug.LogError("Received unknown status code: " + statusCode); + break; + } + + //this.externalListener.OnStatusChanged(statusCode); + } + + + public void OnEvent(EventData photonEvent) + { + if (PhotonNetwork.logLevel >= PhotonLogLevel.Informational) + Debug.Log(string.Format("OnEvent: {0}", photonEvent.ToString())); + + int actorNr = -1; + PhotonPlayer originatingPlayer = null; + + if (photonEvent.Parameters.ContainsKey(ParameterCode.ActorNr)) + { + actorNr = (int)photonEvent[ParameterCode.ActorNr]; + originatingPlayer = this.GetPlayerWithId(actorNr); + + //else + //{ + // // the actor sending this event is not in actorlist. this is usually no problem + // if (photonEvent.Code != (byte)LiteOpCode.Join) + // { + // Debug.LogWarning("Received event, but we do not have this actor: " + actorNr); + // } + //} + } + + switch (photonEvent.Code) + { + case PunEvent.OwnershipRequest: + { + int[] requestValues = (int[]) photonEvent.Parameters[ParameterCode.CustomEventContent]; + int requestedViewId = requestValues[0]; + int currentOwner = requestValues[1]; + + + PhotonView requestedView = PhotonView.Find(requestedViewId); + if (requestedView == null) + { + Debug.LogWarning("Can't find PhotonView of incoming OwnershipRequest. ViewId not found: " + requestedViewId); + break; + } + + if (PhotonNetwork.logLevel == PhotonLogLevel.Informational) + Debug.Log("Ev OwnershipRequest " + requestedView.ownershipTransfer + ". ActorNr: " + actorNr + " takes from: " + currentOwner + ". local RequestedView.ownerId: " + requestedView.ownerId + " isOwnerActive: " + requestedView.isOwnerActive + ". MasterClient: " + this.mMasterClientId + ". This client's player: " + PhotonNetwork.player.ToStringFull()); + + switch (requestedView.ownershipTransfer) + { + case OwnershipOption.Fixed: + Debug.LogWarning("Ownership mode == fixed. Ignoring request."); + break; + case OwnershipOption.Takeover: + if (currentOwner == requestedView.ownerId || (currentOwner == 0 && requestedView.ownerId == this.mMasterClientId) || requestedView.ownerId == 0) + { + // a takeover is successful automatically, if taken from current owner + requestedView.OwnerShipWasTransfered = true; + int _oldOwnerId = requestedView.ownerId; + PhotonPlayer _oldOwner = this.GetPlayerWithId(_oldOwnerId); + + requestedView.ownerId = actorNr; + + + if (PhotonNetwork.logLevel >= PhotonLogLevel.Informational) + { + Debug.LogWarning(requestedView + " ownership transfered to: "+ actorNr); + } + + SendMonoMessage(PhotonNetworkingMessage.OnOwnershipTransfered, new object[] {requestedView, originatingPlayer,_oldOwner}); + + } + break; + case OwnershipOption.Request: + if (currentOwner == PhotonNetwork.player.ID || PhotonNetwork.player.IsMasterClient) + { + if ((requestedView.ownerId == PhotonNetwork.player.ID) || (PhotonNetwork.player.IsMasterClient && !requestedView.isOwnerActive)) + { + SendMonoMessage(PhotonNetworkingMessage.OnOwnershipRequest, new object[] {requestedView, originatingPlayer}); + } + } + break; + default: + break; + } + } + break; + + case PunEvent.OwnershipTransfer: + { + int[] transferViewToUserID = (int[]) photonEvent.Parameters[ParameterCode.CustomEventContent]; + + if (PhotonNetwork.logLevel >= PhotonLogLevel.Informational) + { + Debug.Log("Ev OwnershipTransfer. ViewID " + transferViewToUserID[0] + " to: " + transferViewToUserID[1] + " Time: " + Environment.TickCount%1000); + } + + + + int requestedViewId = transferViewToUserID[0]; + int newOwnerId = transferViewToUserID[1]; + + PhotonView pv = PhotonView.Find(requestedViewId); + if (pv != null) + { + int _oldOwnerID = pv.ownerId; + pv.OwnerShipWasTransfered = true; + pv.ownerId = newOwnerId; + + SendMonoMessage(PhotonNetworkingMessage.OnOwnershipTransfered, new object[] {pv, PhotonPlayer.Find(newOwnerId),PhotonPlayer.Find(_oldOwnerID)}); + } + + + break; + } + case EventCode.GameList: + { + this.mGameList = new Dictionary(); + Hashtable games = (Hashtable)photonEvent[ParameterCode.GameList]; + foreach (var gameKey in games.Keys) + { + string gameName = (string)gameKey; + this.mGameList[gameName] = new RoomInfo(gameName, (Hashtable)games[gameKey]); + } + mGameListCopy = new RoomInfo[mGameList.Count]; + mGameList.Values.CopyTo(mGameListCopy, 0); + SendMonoMessage(PhotonNetworkingMessage.OnReceivedRoomListUpdate); + break; + } + + case EventCode.GameListUpdate: + { + Hashtable games = (Hashtable)photonEvent[ParameterCode.GameList]; + foreach (var roomKey in games.Keys) + { + string gameName = (string)roomKey; + RoomInfo game = new RoomInfo(gameName, (Hashtable)games[roomKey]); + if (game.removedFromList) + { + this.mGameList.Remove(gameName); + } + else + { + this.mGameList[gameName] = game; + } + } + this.mGameListCopy = new RoomInfo[this.mGameList.Count]; + this.mGameList.Values.CopyTo(this.mGameListCopy, 0); + SendMonoMessage(PhotonNetworkingMessage.OnReceivedRoomListUpdate); + break; + } + + case EventCode.AppStats: + // Debug.LogInfo("Received stats!"); + this.PlayersInRoomsCount = (int)photonEvent[ParameterCode.PeerCount]; + this.PlayersOnMasterCount = (int)photonEvent[ParameterCode.MasterPeerCount]; + this.RoomsCount = (int)photonEvent[ParameterCode.GameCount]; + break; + + case EventCode.Join: + + // save the IsInactive Property to be able to detect if activity state changed + bool wasInactive = false; + + // actorNr is fetched out of event above + Hashtable actorProperties = (Hashtable)photonEvent[ParameterCode.PlayerProperties]; + if (originatingPlayer == null) + { + bool isLocal = this.LocalPlayer.ID == actorNr; + this.AddNewPlayer(actorNr, new PhotonPlayer(isLocal, actorNr, actorProperties)); + this.ResetPhotonViewsOnSerialize(); // This sets the correct OnSerializeState for Reliable OnSerialize + } + else + { + wasInactive = originatingPlayer.IsInactive; + + originatingPlayer.InternalCacheProperties(actorProperties); + originatingPlayer.IsInactive = false; + } + + if (actorNr == this.LocalPlayer.ID) + { + // in this player's 'own' join event, we get a complete list of players in the room, so check if we know all players + int[] actorsInRoom = (int[])photonEvent[ParameterCode.ActorList]; + this.UpdatedActorList(actorsInRoom); + + // joinWithCreateOnDemand can turn an OpJoin into creating the room. Then actorNumber is 1 and callback: OnCreatedRoom() + if (this.lastJoinType == JoinType.JoinOrCreateRoom && this.LocalPlayer.ID == 1) + { + SendMonoMessage(PhotonNetworkingMessage.OnCreatedRoom); + } + SendMonoMessage(PhotonNetworkingMessage.OnJoinedRoom); //Always send OnJoinedRoom + + } + else + { + SendMonoMessage(PhotonNetworkingMessage.OnPhotonPlayerConnected, this.mActors[actorNr]); + + if (wasInactive) + { + SendMonoMessage(PhotonNetworkingMessage.OnPhotonPlayerActivityChanged, this.mActors[actorNr]); + } + + } + break; + + case EventCode.Leave: + this.HandleEventLeave(actorNr, photonEvent); + break; + + case EventCode.PropertiesChanged: + int targetActorNr = (int)photonEvent[ParameterCode.TargetActorNr]; + Hashtable gameProperties = null; + Hashtable actorProps = null; + if (targetActorNr == 0) + { + gameProperties = (Hashtable)photonEvent[ParameterCode.Properties]; + } + else + { + actorProps = (Hashtable)photonEvent[ParameterCode.Properties]; + } + + this.ReadoutProperties(gameProperties, actorProps, targetActorNr); + break; + + case PunEvent.RPC: + //ts: each event now contains a single RPC. execute this + // Debug.Log("Ev RPC from: " + originatingPlayer); + this.ExecuteRpc(photonEvent[ParameterCode.Data] as Hashtable, originatingPlayer); + break; + + case PunEvent.SendSerialize: + case PunEvent.SendSerializeReliable: + Hashtable serializeData = (Hashtable)photonEvent[ParameterCode.Data]; + //Debug.Log(serializeData.ToStringFull()); + + int remoteUpdateServerTimestamp = (int)serializeData[(byte)0]; + short remoteLevelPrefix = -1; + byte initialDataIndex = 10; + int headerLength = 1; + if (serializeData.ContainsKey((byte)1)) + { + remoteLevelPrefix = (short)serializeData[(byte)1]; + headerLength = 2; + } + + for (byte s = initialDataIndex; s - initialDataIndex < serializeData.Count - headerLength; s++) + { + this.OnSerializeRead(serializeData[s] as object[], originatingPlayer, remoteUpdateServerTimestamp, remoteLevelPrefix); + } + break; + + case PunEvent.Instantiation: + this.DoInstantiate((Hashtable)photonEvent[ParameterCode.Data], originatingPlayer, null); + break; + + case PunEvent.CloseConnection: + // MasterClient "requests" a disconnection from us + if (originatingPlayer == null || !originatingPlayer.IsMasterClient) + { + Debug.LogError("Error: Someone else(" + originatingPlayer + ") then the masterserver requests a disconnect!"); + } + else + { + PhotonNetwork.LeaveRoom(); + } + + break; + + case PunEvent.DestroyPlayer: + Hashtable evData = (Hashtable)photonEvent[ParameterCode.Data]; + int targetPlayerId = (int)evData[(byte)0]; + if (targetPlayerId >= 0) + { + this.DestroyPlayerObjects(targetPlayerId, true); + } + else + { + if (this.DebugOut >= DebugLevel.INFO) Debug.Log("Ev DestroyAll! By PlayerId: " + actorNr); + this.DestroyAll(true); + } + break; + + case PunEvent.Destroy: + evData = (Hashtable)photonEvent[ParameterCode.Data]; + int instantiationId = (int)evData[(byte)0]; + // Debug.Log("Ev Destroy for viewId: " + instantiationId + " sent by owner: " + (instantiationId / PhotonNetwork.MAX_VIEW_IDS == actorNr) + " this client is owner: " + (instantiationId / PhotonNetwork.MAX_VIEW_IDS == this.LocalPlayer.ID)); + + + PhotonView pvToDestroy = null; + if (this.photonViewList.TryGetValue(instantiationId, out pvToDestroy)) + { + this.RemoveInstantiatedGO(pvToDestroy.gameObject, true); + } + else + { + if (this.DebugOut >= DebugLevel.ERROR) Debug.LogError("Ev Destroy Failed. Could not find PhotonView with instantiationId " + instantiationId + ". Sent by actorNr: " + actorNr); + } + + break; + + case PunEvent.AssignMaster: + evData = (Hashtable)photonEvent[ParameterCode.Data]; + int newMaster = (int)evData[(byte)1]; + this.SetMasterClient(newMaster, false); + break; + + case EventCode.LobbyStats: + //Debug.Log("LobbyStats EV: " + photonEvent.ToStringFull()); + + string[] names = photonEvent[ParameterCode.LobbyName] as string[]; + byte[] types = photonEvent[ParameterCode.LobbyType] as byte[]; + int[] peers = photonEvent[ParameterCode.PeerCount] as int[]; + int[] rooms = photonEvent[ParameterCode.GameCount] as int[]; + + this.LobbyStatistics.Clear(); + for (int i = 0; i < names.Length; i++) + { + TypedLobbyInfo info = new TypedLobbyInfo(); + info.Name = names[i]; + info.Type = (LobbyType)types[i]; + info.PlayerCount = peers[i]; + info.RoomCount = rooms[i]; + + this.LobbyStatistics.Add(info); + } + + SendMonoMessage(PhotonNetworkingMessage.OnLobbyStatisticsUpdate); + break; + + case EventCode.ErrorInfo: + if (PhotonNetwork.OnEventCall != null) + { + object content = photonEvent[ParameterCode.Data]; + PhotonNetwork.OnEventCall(photonEvent.Code, content, actorNr); + } + else + { + Debug.LogWarning("Warning: Unhandled Event ErrorInfo (251). Set PhotonNetwork.OnEventCall to the method PUN should call for this event."); + } + break; + + case EventCode.AuthEvent: + if (this.AuthValues == null) + { + this.AuthValues = new AuthenticationValues(); + } + + this.AuthValues.Token = photonEvent[ParameterCode.Secret] as string; + this.tokenCache = this.AuthValues.Token; + break; + + + default: + if (photonEvent.Code < 200) + { + if (PhotonNetwork.OnEventCall != null) + { + object content = photonEvent[ParameterCode.Data]; + PhotonNetwork.OnEventCall(photonEvent.Code, content, actorNr); + } + else + { + Debug.LogWarning("Warning: Unhandled event " + photonEvent + ". Set PhotonNetwork.OnEventCall."); + } + } + break; + } + + //this.externalListener.OnEvent(photonEvent); + } + + public void OnMessage(object messages) + { + // not used here + } + + #endregion + + + private void SetupEncryption(Dictionary encryptionData) + { + // this should not be called when authentication is done per server. this mode does not support the required "key-exchange via token" + if (this.AuthMode == AuthModeOption.Auth) + { + if (DebugOut == DebugLevel.ERROR) + { + UnityEngine.Debug.LogWarning("SetupEncryption() called but ignored. Not XB1 compiled. EncryptionData: " + encryptionData.ToStringFull()); + return; + } + } + + + // for AuthOnce and AuthOnceWss, we can keep the same secret across machines (for the session, basically) + if (DebugOut == DebugLevel.INFO) + { + UnityEngine.Debug.Log("SetupEncryption() got called. "+encryptionData.ToStringFull()); + } + + var mode = (EncryptionMode)(byte)encryptionData[EncryptionDataParameters.Mode]; + switch (mode) + { + case EncryptionMode.PayloadEncryption: + byte[] secret = (byte[])encryptionData[EncryptionDataParameters.Secret1]; + this.InitPayloadEncryption(secret); + break; + case EncryptionMode.DatagramEncryption: + { + byte[] secret1 = (byte[])encryptionData[EncryptionDataParameters.Secret1]; + byte[] secret2 = (byte[])encryptionData[EncryptionDataParameters.Secret2]; + this.InitDatagramEncryption(secret1, secret2); + } + break; + default: + throw new ArgumentOutOfRangeException(); + } + } + + + protected internal void UpdatedActorList(int[] actorsInRoom) + { + for (int i = 0; i < actorsInRoom.Length; i++) + { + int actorNrToCheck = actorsInRoom[i]; + if (this.LocalPlayer.ID != actorNrToCheck && !this.mActors.ContainsKey(actorNrToCheck)) + { + this.AddNewPlayer(actorNrToCheck, new PhotonPlayer(false, actorNrToCheck, string.Empty)); + } + } + } + + private void SendVacantViewIds() + { + Debug.Log("SendVacantViewIds()"); + List vacantViews = new List(); + foreach (PhotonView view in this.photonViewList.Values) + { + if (!view.isOwnerActive) + { + vacantViews.Add(view.viewID); + } + } + + Debug.Log("Sending vacant view IDs. Length: " + vacantViews.Count); + //this.OpRaiseEvent(PunEvent.VacantViewIds, true, vacantViews.ToArray()); + this.OpRaiseEvent(PunEvent.VacantViewIds, vacantViews.ToArray(), true, null); + } + + public static void SendMonoMessage(PhotonNetworkingMessage methodString, params object[] parameters) + { + HashSet objectsToCall; + if (PhotonNetwork.SendMonoMessageTargets != null) + { + objectsToCall = PhotonNetwork.SendMonoMessageTargets; + } + else + { + objectsToCall = PhotonNetwork.FindGameObjectsWithComponent(PhotonNetwork.SendMonoMessageTargetType); + } + + string methodName = methodString.ToString(); + object callParameter = (parameters != null && parameters.Length == 1) ? parameters[0] : parameters; + foreach (GameObject gameObject in objectsToCall) + { + if (gameObject!=null) + { + gameObject.SendMessage(methodName, callParameter, SendMessageOptions.DontRequireReceiver); + } + } + } + + // PHOTONVIEW/RPC related + + /// + /// Executes a received RPC event + /// + protected internal void ExecuteRpc(Hashtable rpcData, PhotonPlayer sender) + { + if (rpcData == null || !rpcData.ContainsKey((byte)0)) + { + Debug.LogError("Malformed RPC; this should never occur. Content: " + SupportClassPun.DictionaryToString(rpcData)); + return; + } + + // ts: updated with "flat" event data + int netViewID = (int)rpcData[(byte)0]; // LIMITS PHOTONVIEWS&PLAYERS + int otherSidePrefix = 0; // by default, the prefix is 0 (and this is not being sent) + if (rpcData.ContainsKey((byte)1)) + { + otherSidePrefix = (short)rpcData[(byte)1]; + } + + + string inMethodName; + if (rpcData.ContainsKey((byte)5)) + { + int rpcIndex = (byte)rpcData[(byte)5]; // LIMITS RPC COUNT + if (rpcIndex > PhotonNetwork.PhotonServerSettings.RpcList.Count - 1) + { + Debug.LogError("Could not find RPC with index: " + rpcIndex + ". Going to ignore! Check PhotonServerSettings.RpcList"); + return; + } + else + { + inMethodName = PhotonNetwork.PhotonServerSettings.RpcList[rpcIndex]; + } + } + else + { + inMethodName = (string)rpcData[(byte)3]; + } + + object[] inMethodParameters = null; + if (rpcData.ContainsKey((byte)4)) + { + inMethodParameters = (object[])rpcData[(byte)4]; + } + + if (inMethodParameters == null) + { + inMethodParameters = new object[0]; + } + + PhotonView photonNetview = this.GetPhotonView(netViewID); + if (photonNetview == null) + { + int viewOwnerId = netViewID/PhotonNetwork.MAX_VIEW_IDS; + bool owningPv = (viewOwnerId == this.LocalPlayer.ID); + bool ownerSent = (viewOwnerId == sender.ID); + + if (owningPv) + { + Debug.LogWarning("Received RPC \"" + inMethodName + "\" for viewID " + netViewID + " but this PhotonView does not exist! View was/is ours." + (ownerSent ? " Owner called." : " Remote called.") + " By: " + sender.ID); + } + else + { + Debug.LogWarning("Received RPC \"" + inMethodName + "\" for viewID " + netViewID + " but this PhotonView does not exist! Was remote PV." + (ownerSent ? " Owner called." : " Remote called.") + " By: " + sender.ID + " Maybe GO was destroyed but RPC not cleaned up."); + } + return; + } + + if (photonNetview.prefix != otherSidePrefix) + { + Debug.LogError("Received RPC \"" + inMethodName + "\" on viewID " + netViewID + " with a prefix of " + otherSidePrefix + ", our prefix is " + photonNetview.prefix + ". The RPC has been ignored."); + return; + } + + // Get method name + if (string.IsNullOrEmpty(inMethodName)) + { + Debug.LogError("Malformed RPC; this should never occur. Content: " + SupportClassPun.DictionaryToString(rpcData)); + return; + } + + if (PhotonNetwork.logLevel >= PhotonLogLevel.Full) + Debug.Log("Received RPC: " + inMethodName); + + + // SetReceiving filtering + if (photonNetview.group != 0 && !allowedReceivingGroups.Contains(photonNetview.group)) + { + return; // Ignore group + } + + Type[] argTypes = new Type[0]; + if (inMethodParameters.Length > 0) + { + argTypes = new Type[inMethodParameters.Length]; + int i = 0; + for (int index = 0; index < inMethodParameters.Length; index++) + { + object objX = inMethodParameters[index]; + if (objX == null) + { + argTypes[i] = null; + } + else + { + argTypes[i] = objX.GetType(); + } + + i++; + } + } + + int receivers = 0; + int foundMethods = 0; + if (!PhotonNetwork.UseRpcMonoBehaviourCache || photonNetview.RpcMonoBehaviours == null || photonNetview.RpcMonoBehaviours.Length == 0) + { + photonNetview.RefreshRpcMonoBehaviourCache(); + } + + for (int componentsIndex = 0; componentsIndex < photonNetview.RpcMonoBehaviours.Length; componentsIndex++) + { + MonoBehaviour monob = photonNetview.RpcMonoBehaviours[componentsIndex]; + if (monob == null) + { + Debug.LogError("ERROR You have missing MonoBehaviours on your gameobjects!"); + continue; + } + + Type type = monob.GetType(); + + // Get [PunRPC] methods from cache + List cachedRPCMethods = null; + bool methodsOfTypeInCache = this.monoRPCMethodsCache.TryGetValue(type, out cachedRPCMethods); + + if (!methodsOfTypeInCache) + { + List entries = SupportClassPun.GetMethods(type, typeof(PunRPC)); + + this.monoRPCMethodsCache[type] = entries; + cachedRPCMethods = entries; + } + + if (cachedRPCMethods == null) + { + continue; + } + + // Check cache for valid methodname+arguments + for (int index = 0; index < cachedRPCMethods.Count; index++) + { + MethodInfo mInfo = cachedRPCMethods[index]; + if (mInfo.Name.Equals(inMethodName)) + { + foundMethods++; + ParameterInfo[] pArray = mInfo.GetCachedParemeters(); + + if (pArray.Length == argTypes.Length) + { + // Normal, PhotonNetworkMessage left out + if (this.CheckTypeMatch(pArray, argTypes)) + { + receivers++; + object result = mInfo.Invoke((object)monob, inMethodParameters); + if (PhotonNetwork.StartRpcsAsCoroutine && mInfo.ReturnType == typeof(IEnumerator)) + { + monob.StartCoroutine((IEnumerator)result); + } + } + } + else if ((pArray.Length - 1) == argTypes.Length) + { + // Check for PhotonNetworkMessage being the last + if (this.CheckTypeMatch(pArray, argTypes)) + { + if (pArray[pArray.Length - 1].ParameterType == typeof(PhotonMessageInfo)) + { + receivers++; + + int sendTime = (int)rpcData[(byte)2]; + object[] deParamsWithInfo = new object[inMethodParameters.Length + 1]; + inMethodParameters.CopyTo(deParamsWithInfo, 0); + deParamsWithInfo[deParamsWithInfo.Length - 1] = new PhotonMessageInfo(sender, sendTime, photonNetview); + + object result = mInfo.Invoke((object)monob, deParamsWithInfo); + if (PhotonNetwork.StartRpcsAsCoroutine && mInfo.ReturnType == typeof(IEnumerator)) + { + monob.StartCoroutine((IEnumerator)result); + } + } + } + } + else if (pArray.Length == 1 && pArray[0].ParameterType.IsArray) + { + receivers++; + object result = mInfo.Invoke((object)monob, new object[] { inMethodParameters }); + if (PhotonNetwork.StartRpcsAsCoroutine && mInfo.ReturnType == typeof(IEnumerator)) + { + monob.StartCoroutine((IEnumerator)result); + } + } + } + } + } + + // Error handling + if (receivers != 1) + { + string argsString = string.Empty; + for (int index = 0; index < argTypes.Length; index++) + { + Type ty = argTypes[index]; + if (argsString != string.Empty) + { + argsString += ", "; + } + + if (ty == null) + { + argsString += "null"; + } + else + { + argsString += ty.Name; + } + } + + if (receivers == 0) + { + if (foundMethods == 0) + { + Debug.LogError("PhotonView with ID " + netViewID + " has no method \"" + inMethodName + "\" marked with the [PunRPC](C#) or @PunRPC(JS) property! Args: " + argsString); + } + else + { + Debug.LogError("PhotonView with ID " + netViewID + " has no method \"" + inMethodName + "\" that takes " + argTypes.Length + " argument(s): " + argsString); + } + } + else + { + Debug.LogError("PhotonView with ID " + netViewID + " has " + receivers + " methods \"" + inMethodName + "\" that takes " + argTypes.Length + " argument(s): " + argsString + ". Should be just one?"); + } + } + } + + /// + /// Check if all types match with parameters. We can have more paramters then types (allow last RPC type to be different). + /// + /// + /// + /// If the types-array has matching parameters (of method) in the parameters array (which may be longer). + private bool CheckTypeMatch(ParameterInfo[] methodParameters, Type[] callParameterTypes) + { + if (methodParameters.Length < callParameterTypes.Length) + { + return false; + } + + for (int index = 0; index < callParameterTypes.Length; index++) + { + #if NETFX_CORE + TypeInfo methodParamTI = methodParameters[index].ParameterType.GetTypeInfo(); + TypeInfo callParamTI = callParameterTypes[index].GetTypeInfo(); + + if (callParameterTypes[index] != null && !methodParamTI.IsAssignableFrom(callParamTI) && !(callParamTI.IsEnum && System.Enum.GetUnderlyingType(methodParamTI.AsType()).GetTypeInfo().IsAssignableFrom(callParamTI))) + { + return false; + } + #else + Type type = methodParameters[index].ParameterType; + if (callParameterTypes[index] != null && !type.IsAssignableFrom(callParameterTypes[index]) && !(type.IsEnum && System.Enum.GetUnderlyingType(type).IsAssignableFrom(callParameterTypes[index]))) + { + return false; + } + #endif + } + + return true; + } + + internal Hashtable SendInstantiate(string prefabName, Vector3 position, Quaternion rotation, byte group, int[] viewIDs, object[] data, bool isGlobalObject) + { + // first viewID is now also the gameobject's instantiateId + int instantiateId = viewIDs[0]; // LIMITS PHOTONVIEWS&PLAYERS + + //TODO: reduce hashtable key usage by using a parameter array for the various values + Hashtable instantiateEvent = new Hashtable(); // This players info is sent via ActorID + instantiateEvent[(byte)0] = prefabName; + + if (position != Vector3.zero) + { + instantiateEvent[(byte)1] = position; + } + + if (rotation != Quaternion.identity) + { + instantiateEvent[(byte)2] = rotation; + } + + if (group != 0) + { + instantiateEvent[(byte)3] = group; + } + + // send the list of viewIDs only if there are more than one. else the instantiateId is the viewID + if (viewIDs.Length > 1) + { + instantiateEvent[(byte)4] = viewIDs; // LIMITS PHOTONVIEWS&PLAYERS + } + + if (data != null) + { + instantiateEvent[(byte)5] = data; + } + + if (this.currentLevelPrefix > 0) + { + instantiateEvent[(byte)8] = this.currentLevelPrefix; // photonview's / object's level prefix + } + + instantiateEvent[(byte)6] = PhotonNetwork.ServerTimestamp; + instantiateEvent[(byte)7] = instantiateId; + + + RaiseEventOptions options = new RaiseEventOptions(); + options.CachingOption = (isGlobalObject) ? EventCaching.AddToRoomCacheGlobal : EventCaching.AddToRoomCache; + + this.OpRaiseEvent(PunEvent.Instantiation, instantiateEvent, true, options); + return instantiateEvent; + } + + internal GameObject DoInstantiate(Hashtable evData, PhotonPlayer photonPlayer, GameObject resourceGameObject) + { + // some values always present: + string prefabName = (string)evData[(byte)0]; + int serverTime = (int)evData[(byte)6]; + int instantiationId = (int)evData[(byte)7]; + + Vector3 position; + if (evData.ContainsKey((byte)1)) + { + position = (Vector3)evData[(byte)1]; + } + else + { + position = Vector3.zero; + } + + Quaternion rotation = Quaternion.identity; + if (evData.ContainsKey((byte)2)) + { + rotation = (Quaternion)evData[(byte)2]; + } + + byte group = 0; + if (evData.ContainsKey((byte)3)) + { + group = (byte)evData[(byte)3]; + } + + short objLevelPrefix = 0; + if (evData.ContainsKey((byte)8)) + { + objLevelPrefix = (short)evData[(byte)8]; + } + + int[] viewsIDs; + if (evData.ContainsKey((byte)4)) + { + viewsIDs = (int[])evData[(byte)4]; + } + else + { + viewsIDs = new int[1] { instantiationId }; + } + + object[] incomingInstantiationData; + if (evData.ContainsKey((byte)5)) + { + incomingInstantiationData = (object[])evData[(byte)5]; + } + else + { + incomingInstantiationData = null; + } + + // SetReceiving filtering + if (group != 0 && !this.allowedReceivingGroups.Contains(group)) + { + return null; // Ignore group + } + + if (ObjectPool != null) + { + GameObject go = ObjectPool.Instantiate(prefabName, position, rotation); + + PhotonView[] photonViews = go.GetPhotonViewsInChildren(); + if (photonViews.Length != viewsIDs.Length) + { + throw new Exception("Error in Instantiation! The resource's PhotonView count is not the same as in incoming data."); + } + for (int i = 0; i < photonViews.Length; i++) + { + photonViews[i].didAwake = false; + photonViews[i].viewID = 0; + + photonViews[i].prefix = objLevelPrefix; + photonViews[i].instantiationId = instantiationId; + photonViews[i].isRuntimeInstantiated = true; + photonViews[i].instantiationDataField = incomingInstantiationData; + + photonViews[i].didAwake = true; + photonViews[i].viewID = viewsIDs[i]; // with didAwake true and viewID == 0, this will also register the view + } + + // Send OnPhotonInstantiate callback to newly created GO. + // GO will be enabled when instantiated from Prefab and it does not matter if the script is enabled or disabled. + go.SendMessage(OnPhotonInstantiateString, new PhotonMessageInfo(photonPlayer, serverTime, null), SendMessageOptions.DontRequireReceiver); + return go; + } + else + { + // load prefab, if it wasn't loaded before (calling methods might do this) + if (resourceGameObject == null) + { + if (!NetworkingPeer.UsePrefabCache || !NetworkingPeer.PrefabCache.TryGetValue(prefabName, out resourceGameObject)) + { + resourceGameObject = (GameObject)Resources.Load(prefabName, typeof (GameObject)); + if (NetworkingPeer.UsePrefabCache) + { + NetworkingPeer.PrefabCache.Add(prefabName, resourceGameObject); + } + } + + if (resourceGameObject == null) + { + Debug.LogError("PhotonNetwork error: Could not Instantiate the prefab [" + prefabName + "]. Please verify you have this gameobject in a Resources folder."); + return null; + } + } + + // now modify the loaded "blueprint" object before it becomes a part of the scene (by instantiating it) + PhotonView[] resourcePVs = resourceGameObject.GetPhotonViewsInChildren(); + if (resourcePVs.Length != viewsIDs.Length) + { + throw new Exception("Error in Instantiation! The resource's PhotonView count is not the same as in incoming data."); + } + + for (int i = 0; i < viewsIDs.Length; i++) + { + // NOTE instantiating the loaded resource will keep the viewID but would not copy instantiation data, so it's set below + // so we only set the viewID and instantiationId now. the instantiationData can be fetched + resourcePVs[i].viewID = viewsIDs[i]; + resourcePVs[i].prefix = objLevelPrefix; + resourcePVs[i].instantiationId = instantiationId; + resourcePVs[i].isRuntimeInstantiated = true; + } + + this.StoreInstantiationData(instantiationId, incomingInstantiationData); + + // load the resource and set it's values before instantiating it: + GameObject go = (GameObject)GameObject.Instantiate(resourceGameObject, position, rotation); + + for (int i = 0; i < viewsIDs.Length; i++) + { + // NOTE instantiating the loaded resource will keep the viewID but would not copy instantiation data, so it's set below + // so we only set the viewID and instantiationId now. the instantiationData can be fetched + resourcePVs[i].viewID = 0; + resourcePVs[i].prefix = -1; + resourcePVs[i].prefixBackup = -1; + resourcePVs[i].instantiationId = -1; + resourcePVs[i].isRuntimeInstantiated = false; + } + + this.RemoveInstantiationData(instantiationId); + + // Send OnPhotonInstantiate callback to newly created GO. + // GO will be enabled when instantiated from Prefab and it does not matter if the script is enabled or disabled. + go.SendMessage(OnPhotonInstantiateString, new PhotonMessageInfo(photonPlayer, serverTime, null), SendMessageOptions.DontRequireReceiver); + return go; + } + } + + private Dictionary tempInstantiationData = new Dictionary(); + + private void StoreInstantiationData(int instantiationId, object[] instantiationData) + { + // Debug.Log("StoreInstantiationData() instantiationId: " + instantiationId + " tempInstantiationData.Count: " + tempInstantiationData.Count); + tempInstantiationData[instantiationId] = instantiationData; + } + + public object[] FetchInstantiationData(int instantiationId) + { + object[] data = null; + if (instantiationId == 0) + { + return null; + } + + tempInstantiationData.TryGetValue(instantiationId, out data); + // Debug.Log("FetchInstantiationData() instantiationId: " + instantiationId + " tempInstantiationData.Count: " + tempInstantiationData.Count); + return data; + } + + private void RemoveInstantiationData(int instantiationId) + { + tempInstantiationData.Remove(instantiationId); + } + + + /// + /// Destroys all Instantiates and RPCs locally and (if not localOnly) sends EvDestroy(player) and clears related events in the server buffer. + /// + public void DestroyPlayerObjects(int playerId, bool localOnly) + { + if (playerId <= 0) + { + Debug.LogError("Failed to Destroy objects of playerId: " + playerId); + return; + } + + if (!localOnly) + { + // clean server's Instantiate and RPC buffers + this.OpRemoveFromServerInstantiationsOfPlayer(playerId); + this.OpCleanRpcBuffer(playerId); + + // send Destroy(player) to anyone else + this.SendDestroyOfPlayer(playerId); + } + + // locally cleaning up that player's objects + HashSet playersGameObjects = new HashSet(); + foreach (PhotonView view in this.photonViewList.Values) + { + if (view!=null && view.CreatorActorNr == playerId) + { + playersGameObjects.Add(view.gameObject); + } + } + + // any non-local work is already done, so with the list of that player's objects, we can clean up (locally only) + foreach (GameObject gameObject in playersGameObjects) + { + this.RemoveInstantiatedGO(gameObject, true); + } + + // with ownership transfer, some objects might lose their owner. + // in that case, the creator becomes the owner again. every client can apply this. done below. + foreach (PhotonView view in this.photonViewList.Values) + { + if (view.ownerId == playerId) + { + view.ownerId = view.CreatorActorNr; + //Debug.Log("Creator is: " + view.ownerId); + } + } + } + + public void DestroyAll(bool localOnly) + { + if (!localOnly) + { + this.OpRemoveCompleteCache(); + this.SendDestroyOfAll(); + } + + this.LocalCleanupAnythingInstantiated(true); + } + + /// Removes GameObject and the PhotonViews on it from local lists and optionally updates remotes. GameObject gets destroyed at end. + /// + /// This method might fail and quit early due to several tests. + /// + /// GameObject to cleanup. + /// For localOnly, tests of control are skipped and the server is not updated. + protected internal void RemoveInstantiatedGO(GameObject go, bool localOnly) + { + if (go == null) + { + Debug.LogError("Failed to 'network-remove' GameObject because it's null."); + return; + } + + // Don't remove the GO if it doesn't have any PhotonView + PhotonView[] views = go.GetComponentsInChildren(true); + if (views == null || views.Length <= 0) + { + Debug.LogError("Failed to 'network-remove' GameObject because has no PhotonView components: " + go); + return; + } + + PhotonView viewZero = views[0]; + int creatorId = viewZero.CreatorActorNr; // creatorId of obj is needed to delete EvInstantiate (only if it's from that user) + int instantiationId = viewZero.instantiationId; // actual, live InstantiationIds start with 1 and go up + + // Don't remove GOs that are owned by others (unless this is the master and the remote player left) + if (!localOnly) + { + if (!viewZero.isMine) + { + Debug.LogError("Failed to 'network-remove' GameObject. Client is neither owner nor masterClient taking over for owner who left: " + viewZero); + return; + } + + // Don't remove the Instantiation from the server, if it doesn't have a proper ID + if (instantiationId < 1) + { + Debug.LogError("Failed to 'network-remove' GameObject because it is missing a valid InstantiationId on view: " + viewZero + ". Not Destroying GameObject or PhotonViews!"); + return; + } + } + + + // cleanup instantiation (event and local list) + if (!localOnly) + { + this.ServerCleanInstantiateAndDestroy(instantiationId, creatorId, viewZero.isRuntimeInstantiated); // server cleaning + } + + + // cleanup PhotonViews and their RPCs events (if not localOnly) + for (int j = views.Length - 1; j >= 0; j--) + { + PhotonView view = views[j]; + if (view == null) + { + continue; + } + + // we only destroy/clean PhotonViews that were created by PhotonNetwork.Instantiate (and those have an instantiationId!) + if (view.instantiationId >= 1) + { + this.LocalCleanPhotonView(view); + } + if (!localOnly) + { + this.OpCleanRpcBuffer(view); + } + } + + if (PhotonNetwork.logLevel >= PhotonLogLevel.Full) + { + Debug.Log("Network destroy Instantiated GO: " + go.name); + } + + + if (this.ObjectPool != null) + { + PhotonView[] photonViews = go.GetPhotonViewsInChildren(); + for (int i = 0; i < photonViews.Length; i++) + { + photonViews[i].viewID = 0; // marks the PV as not being in use currently. + } + this.ObjectPool.Destroy(go); + } + else + { + GameObject.Destroy(go); + } + } + + /// + /// Removes an instantiation event from the server's cache. Needs id and actorNr of player who instantiated. + /// + private void ServerCleanInstantiateAndDestroy(int instantiateId, int creatorId, bool isRuntimeInstantiated) + { + Hashtable removeFilter = new Hashtable(); + removeFilter[(byte)7] = instantiateId; + + RaiseEventOptions options = new RaiseEventOptions() { CachingOption = EventCaching.RemoveFromRoomCache, TargetActors = new int[] { creatorId } }; + this.OpRaiseEvent(PunEvent.Instantiation, removeFilter, true, options); + //this.OpRaiseEvent(PunEvent.Instantiation, removeFilter, true, 0, new int[] { actorNr }, EventCaching.RemoveFromRoomCache); + + Hashtable evData = new Hashtable(); + evData[(byte)0] = instantiateId; + options = null; + if (!isRuntimeInstantiated) + { + // if the view got loaded with the scene, the EvDestroy must be cached (there is no Instantiate-msg which we can remove) + // reason: joining players will load the obj and have to destroy it (too) + options = new RaiseEventOptions(); + options.CachingOption = EventCaching.AddToRoomCacheGlobal; + Debug.Log("Destroying GO as global. ID: " + instantiateId); + } + this.OpRaiseEvent(PunEvent.Destroy, evData, true, options); + } + + private void SendDestroyOfPlayer(int actorNr) + { + Hashtable evData = new Hashtable(); + evData[(byte)0] = actorNr; + + this.OpRaiseEvent(PunEvent.DestroyPlayer, evData, true, null); + //this.OpRaiseEvent(PunEvent.DestroyPlayer, evData, true, 0, EventCaching.DoNotCache, ReceiverGroup.Others); + } + + private void SendDestroyOfAll() + { + Hashtable evData = new Hashtable(); + evData[(byte)0] = -1; + + + this.OpRaiseEvent(PunEvent.DestroyPlayer, evData, true, null); + //this.OpRaiseEvent(PunEvent.DestroyPlayer, evData, true, 0, EventCaching.DoNotCache, ReceiverGroup.Others); + } + + private void OpRemoveFromServerInstantiationsOfPlayer(int actorNr) + { + // removes all "Instantiation" events of player actorNr. this is not an event for anyone else + RaiseEventOptions options = new RaiseEventOptions() { CachingOption = EventCaching.RemoveFromRoomCache, TargetActors = new int[] { actorNr } }; + this.OpRaiseEvent(PunEvent.Instantiation, null, true, options); + //this.OpRaiseEvent(PunEvent.Instantiation, null, true, 0, new int[] { actorNr }, EventCaching.RemoveFromRoomCache); + } + + internal protected void RequestOwnership(int viewID, int fromOwner) + { + Debug.Log("RequestOwnership(): " + viewID + " from: " + fromOwner + " Time: " + Environment.TickCount % 1000); + //PhotonNetwork.networkingPeer.OpRaiseEvent(PunEvent.OwnershipRequest, true, new int[] { viewID, fromOwner }, 0, EventCaching.DoNotCache, null, ReceiverGroup.All, 0); + this.OpRaiseEvent(PunEvent.OwnershipRequest, new int[] {viewID, fromOwner}, true, new RaiseEventOptions() { Receivers = ReceiverGroup.All }); // All sends to all via server (including self) + } + + internal protected void TransferOwnership(int viewID, int playerID) + { + Debug.Log("TransferOwnership() view " + viewID + " to: " + playerID + " Time: " + Environment.TickCount % 1000); + //PhotonNetwork.networkingPeer.OpRaiseEvent(PunEvent.OwnershipTransfer, true, new int[] {viewID, playerID}, 0, EventCaching.DoNotCache, null, ReceiverGroup.All, 0); + this.OpRaiseEvent(PunEvent.OwnershipTransfer, new int[] { viewID, playerID }, true, new RaiseEventOptions() { Receivers = ReceiverGroup.All }); // All sends to all via server (including self) + } + + public bool LocalCleanPhotonView(PhotonView view) + { + view.removedFromLocalViewList = true; + return this.photonViewList.Remove(view.viewID); + } + + public PhotonView GetPhotonView(int viewID) + { + PhotonView result = null; + this.photonViewList.TryGetValue(viewID, out result); + + if (result == null) + { + PhotonView[] views = GameObject.FindObjectsOfType(typeof(PhotonView)) as PhotonView[]; + + for (int i = 0; i < views.Length; i++) + { + PhotonView view = views[i]; + if (view.viewID == viewID) + { + if (view.didAwake) + { + Debug.LogWarning("Had to lookup view that wasn't in photonViewList: " + view); + } + return view; + } + } + } + + return result; + } + + public void RegisterPhotonView(PhotonView netView) + { + if (!Application.isPlaying) + { + this.photonViewList = new Dictionary(); + return; + } + + if (netView.viewID == 0) + { + // don't register views with ID 0 (not initialized). they register when a ID is assigned later on + Debug.Log("PhotonView register is ignored, because viewID is 0. No id assigned yet to: " + netView); + return; + } + + PhotonView listedView = null; + bool isViewListed = this.photonViewList.TryGetValue(netView.viewID, out listedView); + if (isViewListed) + { + // if some other view is in the list already, we got a problem. it might be undestructible. print out error + if (netView != listedView) + { + Debug.LogError(string.Format("PhotonView ID duplicate found: {0}. New: {1} old: {2}. Maybe one wasn't destroyed on scene load?! Check for 'DontDestroyOnLoad'. Destroying old entry, adding new.", netView.viewID, netView, listedView)); + } + else + { + return; + } + + this.RemoveInstantiatedGO(listedView.gameObject, true); + } + + // Debug.Log("adding view to known list: " + netView); + this.photonViewList.Add(netView.viewID, netView); + //Debug.LogError("view being added. " + netView); // Exit Games internal log + + if (PhotonNetwork.logLevel >= PhotonLogLevel.Full) + { + Debug.Log("Registered PhotonView: " + netView.viewID); + } + } + + ///// + ///// Will remove the view from list of views (by its ID). + ///// + //public void RemovePhotonView(PhotonView netView) + //{ + // if (!Application.isPlaying) + // { + // this.photonViewList = new Dictionary(); + // return; + // } + + // //PhotonView removedView = null; + // //this.photonViewList.TryGetValue(netView.viewID, out removedView); + // //if (removedView != netView) + // //{ + // // Debug.LogError("Detected two differing PhotonViews with same viewID: " + netView.viewID); + // //} + + // this.photonViewList.Remove(netView.viewID); + + // //if (this.DebugOut >= DebugLevel.ALL) + // //{ + // // this.DebugReturn(DebugLevel.ALL, "Removed PhotonView: " + netView.viewID); + // //} + //} + + /// + /// Removes the RPCs of someone else (to be used as master). + /// This won't clean any local caches. It just tells the server to forget a player's RPCs and instantiates. + /// + /// + public void OpCleanRpcBuffer(int actorNumber) + { + RaiseEventOptions options = new RaiseEventOptions() { CachingOption = EventCaching.RemoveFromRoomCache, TargetActors = new int[] { actorNumber } }; + this.OpRaiseEvent(PunEvent.RPC, null, true, options); + //this.OpRaiseEvent(PunEvent.RPC, null, true, 0, new int[] { actorNumber }, EventCaching.RemoveFromRoomCache); + } + + /// + /// Instead removing RPCs or Instantiates, this removed everything cached by the actor. + /// + /// + public void OpRemoveCompleteCacheOfPlayer(int actorNumber) + { + RaiseEventOptions options = new RaiseEventOptions() { CachingOption = EventCaching.RemoveFromRoomCache, TargetActors = new int[] { actorNumber } }; + this.OpRaiseEvent(0, null, true, options); + //this.OpRaiseEvent(0, null, true, 0, new int[] { actorNumber }, EventCaching.RemoveFromRoomCache); + } + + + public void OpRemoveCompleteCache() + { + RaiseEventOptions options = new RaiseEventOptions() { CachingOption = EventCaching.RemoveFromRoomCache, Receivers = ReceiverGroup.MasterClient }; + this.OpRaiseEvent(0, null, true, options); + //this.OpRaiseEvent(0, null, true, 0, EventCaching.RemoveFromRoomCache, ReceiverGroup.MasterClient); // TODO: check who gets this event? + } + + /// This clears the cache of any player/actor who's no longer in the room (making it a simple clean-up option for a new master) + private void RemoveCacheOfLeftPlayers() + { + Dictionary opParameters = new Dictionary(); + opParameters[ParameterCode.Code] = (byte)0; // any event + opParameters[ParameterCode.Cache] = (byte)EventCaching.RemoveFromRoomCacheForActorsLeft; // option to clear the room cache of all events of players who left + + this.OpCustom((byte)OperationCode.RaiseEvent, opParameters, true, 0); + } + + // Remove RPCs of view (if they are local player's RPCs) + public void CleanRpcBufferIfMine(PhotonView view) + { + if (view.ownerId != this.LocalPlayer.ID && !LocalPlayer.IsMasterClient) + { + Debug.LogError("Cannot remove cached RPCs on a PhotonView thats not ours! " + view.owner + " scene: " + view.isSceneView); + return; + } + + this.OpCleanRpcBuffer(view); + } + + /// Cleans server RPCs for PhotonView (without any further checks). + public void OpCleanRpcBuffer(PhotonView view) + { + Hashtable rpcFilterByViewId = new Hashtable(); + rpcFilterByViewId[(byte)0] = view.viewID; + + RaiseEventOptions options = new RaiseEventOptions() { CachingOption = EventCaching.RemoveFromRoomCache }; + this.OpRaiseEvent(PunEvent.RPC, rpcFilterByViewId, true, options); + //this.OpRaiseEvent(PunEvent.RPC, rpcFilterByViewId, true, 0, EventCaching.RemoveFromRoomCache, ReceiverGroup.Others); + } + + public void RemoveRPCsInGroup(int group) + { + foreach (PhotonView view in this.photonViewList.Values) + { + if (view.group == group) + { + this.CleanRpcBufferIfMine(view); + } + } + } + + public void SetLevelPrefix(short prefix) + { + this.currentLevelPrefix = prefix; + // TODO: should we really change the prefix for existing PVs?! better keep it! + //foreach (PhotonView view in this.photonViewList.Values) + //{ + // view.prefix = prefix; + //} + } + + + /// RPC Hashtable Structure + /// (byte)0 -> (int) ViewId (combined from actorNr and actor-unique-id) + /// (byte)1 -> (short) prefix (level) + /// (byte)2 -> (int) server timestamp + /// (byte)3 -> (string) methodname + /// (byte)4 -> (object[]) parameters + /// (byte)5 -> (byte) method shortcut (alternative to name) + /// + /// This is sent as event (code: 200) which will contain a sender (origin of this RPC). + + internal void RPC(PhotonView view, string methodName, PhotonTargets target, PhotonPlayer player, bool encrypt, params object[] parameters) + { + if (this.blockSendingGroups.Contains(view.group)) + { + return; // Block sending on this group + } + + if (view.viewID < 1) + { + Debug.LogError("Illegal view ID:" + view.viewID + " method: " + methodName + " GO:" + view.gameObject.name); + } + + if (PhotonNetwork.logLevel >= PhotonLogLevel.Full) + { + Debug.Log("Sending RPC \"" + methodName + "\" to target: " + target + " or player:" + player + "."); + } + + + //ts: changed RPCs to a one-level hashtable as described in internal.txt + Hashtable rpcEvent = new Hashtable(); + rpcEvent[(byte)0] = (int)view.viewID; // LIMITS NETWORKVIEWS&PLAYERS + if (view.prefix > 0) + { + rpcEvent[(byte)1] = (short)view.prefix; + } + rpcEvent[(byte)2] = PhotonNetwork.ServerTimestamp; + + + // send name or shortcut (if available) + int shortcut = 0; + if (rpcShortcuts.TryGetValue(methodName, out shortcut)) + { + rpcEvent[(byte)5] = (byte)shortcut; // LIMITS RPC COUNT + } + else + { + rpcEvent[(byte)3] = methodName; + } + + if (parameters != null && parameters.Length > 0) + { + rpcEvent[(byte)4] = (object[])parameters; + } + + + // if sent to target player, this overrides the target + if (player != null) + { + if (this.LocalPlayer.ID == player.ID) + { + this.ExecuteRpc(rpcEvent, player); + } + else + { + RaiseEventOptions options = new RaiseEventOptions() { TargetActors = new int[] { player.ID }, Encrypt = encrypt }; + this.OpRaiseEvent(PunEvent.RPC, rpcEvent, true, options); + } + + return; + } + + // send to a specific set of players + if (target == PhotonTargets.All) + { + RaiseEventOptions options = new RaiseEventOptions() { InterestGroup = (byte)view.group, Encrypt = encrypt }; + this.OpRaiseEvent(PunEvent.RPC, rpcEvent, true, options); + + // Execute local + this.ExecuteRpc(rpcEvent, this.LocalPlayer); + } + else if (target == PhotonTargets.Others) + { + RaiseEventOptions options = new RaiseEventOptions() { InterestGroup = (byte)view.group, Encrypt = encrypt }; + this.OpRaiseEvent(PunEvent.RPC, rpcEvent, true, options); + } + else if (target == PhotonTargets.AllBuffered) + { + RaiseEventOptions options = new RaiseEventOptions() { CachingOption = EventCaching.AddToRoomCache, Encrypt = encrypt }; + this.OpRaiseEvent(PunEvent.RPC, rpcEvent, true, options); + + // Execute local + this.ExecuteRpc(rpcEvent, this.LocalPlayer); + } + else if (target == PhotonTargets.OthersBuffered) + { + RaiseEventOptions options = new RaiseEventOptions() { CachingOption = EventCaching.AddToRoomCache, Encrypt = encrypt }; + this.OpRaiseEvent(PunEvent.RPC, rpcEvent, true, options); + } + else if (target == PhotonTargets.MasterClient) + { + if (this.mMasterClientId == this.LocalPlayer.ID) + { + this.ExecuteRpc(rpcEvent, this.LocalPlayer); + } + else + { + RaiseEventOptions options = new RaiseEventOptions() { Receivers = ReceiverGroup.MasterClient, Encrypt = encrypt }; + this.OpRaiseEvent(PunEvent.RPC, rpcEvent, true, options); + } + } + else if (target == PhotonTargets.AllViaServer) + { + RaiseEventOptions options = new RaiseEventOptions() { InterestGroup = (byte)view.group, Receivers = ReceiverGroup.All, Encrypt = encrypt }; + this.OpRaiseEvent(PunEvent.RPC, rpcEvent, true, options); + if (PhotonNetwork.offlineMode) + { + this.ExecuteRpc(rpcEvent, this.LocalPlayer); + } + } + else if (target == PhotonTargets.AllBufferedViaServer) + { + RaiseEventOptions options = new RaiseEventOptions() { InterestGroup = (byte)view.group, Receivers = ReceiverGroup.All, CachingOption = EventCaching.AddToRoomCache, Encrypt = encrypt }; + this.OpRaiseEvent(PunEvent.RPC, rpcEvent, true, options); + if (PhotonNetwork.offlineMode) + { + this.ExecuteRpc(rpcEvent, this.LocalPlayer); + } + } + else + { + Debug.LogError("Unsupported target enum: " + target); + } + } + + + public void SetInterestGroups(byte[] disableGroups, byte[] enableGroups) + { + if (disableGroups != null) + { + if (disableGroups.Length == 0) + { + // a byte[0] should disable ALL groups in one step and before any groups are enabled. we do this locally, too. + this.allowedReceivingGroups.Clear(); + } + else + { + for (int index = 0; index < disableGroups.Length; index++) + { + byte g = disableGroups[index]; + if (g <= 0) + { + Debug.LogError("Error: PhotonNetwork.SetInterestGroups was called with an illegal group number: " + g + ". The group number should be at least 1."); + continue; + } + + if (this.allowedReceivingGroups.Contains(g)) + { + this.allowedReceivingGroups.Remove(g); + } + } + } + } + + if (enableGroups != null) + { + if (enableGroups.Length == 0) + { + // a byte[0] should enable ALL groups in one step. we do this locally, too. + for (byte index = 0; index <= byte.MaxValue; index++) + { + this.allowedReceivingGroups.Add(index); + } + } + else + { + for (int index = 0; index < enableGroups.Length; index++) + { + byte g = enableGroups[index]; + if (g <= 0) + { + Debug.LogError("Error: PhotonNetwork.SetInterestGroups was called with an illegal group number: " + g + ". The group number should be at least 1."); + continue; + } + + this.allowedReceivingGroups.Add(g); + } + } + } + + this.OpChangeGroups(disableGroups, enableGroups); + } + + + // SetSending + public void SetSendingEnabled(byte group, bool enabled) + { + if (!enabled) + { + this.blockSendingGroups.Add(group); // can be added to HashSet no matter if already in it + } + else + { + this.blockSendingGroups.Remove(group); + } + } + + + public void SetSendingEnabled(byte[] disableGroups, byte[] enableGroups) + { + if (disableGroups != null) + { + for (int index = 0; index < disableGroups.Length; index++) + { + byte g = disableGroups[index]; + this.blockSendingGroups.Add(g); + } + } + + if (enableGroups != null) + { + for (int index = 0; index < enableGroups.Length; index++) + { + byte g = enableGroups[index]; + this.blockSendingGroups.Remove(g); + } + } + } + + + public void NewSceneLoaded() + { + if (this.loadingLevelAndPausedNetwork) + { + this.loadingLevelAndPausedNetwork = false; + PhotonNetwork.isMessageQueueRunning = true; + } + // Debug.Log("OnLevelWasLoaded photonViewList.Count: " + photonViewList.Count); // Exit Games internal log + + List removeKeys = new List(); + foreach (KeyValuePair kvp in this.photonViewList) + { + PhotonView view = kvp.Value; + if (view == null) + { + removeKeys.Add(kvp.Key); + } + } + + for (int index = 0; index < removeKeys.Count; index++) + { + int key = removeKeys[index]; + this.photonViewList.Remove(key); + } + + if (removeKeys.Count > 0) + { + if (PhotonNetwork.logLevel >= PhotonLogLevel.Informational) + Debug.Log("New level loaded. Removed " + removeKeys.Count + " scene view IDs from last level."); + } + } + + /// + /// Defines how many OnPhotonSerialize()-calls might get summarized in one message. + /// + /// + /// A low number increases overhead, a high number might mean fragmentation. + /// + public static int ObjectsInOneUpdate = 10; + + // cache the RaiseEventOptions to prevent redundant Memory Allocation + RaiseEventOptions options = new RaiseEventOptions(); + + // this is called by Update() and in Unity that means it's single threaded. + public void RunViewUpdate() + { + if (!PhotonNetwork.connected || PhotonNetwork.offlineMode || this.mActors == null) + { + return; + } + + // no need to send OnSerialize messages while being alone (these are not buffered anyway) + if (this.mActors.Count <= 1) + { + #if !PHOTON_DEVELOP + return; + #endif + } + + + /* Format of the data hashtable: + * Hasthable dataPergroup* + * [(byte)0] = PhotonNetwork.ServerTimestamp; + * [(byte)1] = currentLevelPrefix; OPTIONAL! + * + * [(byte)10] = data 1 + * [(byte)11] = data 2 ... + * + * We only combine updates for XY objects into one RaiseEvent to avoid fragmentation + */ + + int countOfUpdatesToSend = 0; + + + // we got updates to send. every group is send it's own message and unreliable and reliable are split as well + options.InterestGroup = 0; + + #if PHOTON_DEVELOP + options.Receivers = ReceiverGroup.All; + #endif + + var enumerator = this.photonViewList.GetEnumerator(); // replacing foreach (PhotonView view in this.photonViewList.Values) for memory allocation improvement + while (enumerator.MoveNext()) + { + PhotonView view = enumerator.Current.Value; + + // a client only sends updates for active, synchronized PhotonViews that are under it's control (isMine) + if (view.synchronization == ViewSynchronization.Off || view.isMine == false || view.gameObject.activeInHierarchy == false) + { + continue; + } + + if (this.blockSendingGroups.Contains(view.group)) + { + continue; // Block sending on this group + } + + + // call the PhotonView's serialize method(s) + object[] evData = this.OnSerializeWrite(view); + if (evData == null) + { + continue; + } + + if (view.synchronization == ViewSynchronization.ReliableDeltaCompressed || view.mixedModeIsReliable) + { + Hashtable groupHashtable = null; + bool found = this.dataPerGroupReliable.TryGetValue(view.group, out groupHashtable); + if (!found) + { + groupHashtable = new Hashtable(NetworkingPeer.ObjectsInOneUpdate); + this.dataPerGroupReliable[view.group] = groupHashtable; + } + + groupHashtable.Add((byte)(groupHashtable.Count+10), evData); + countOfUpdatesToSend++; + + // if any group has XY elements, we should send it right away (to avoid bigger messages which need fragmentation and reliable transfer). + if (groupHashtable.Count >= NetworkingPeer.ObjectsInOneUpdate) + { + countOfUpdatesToSend -= groupHashtable.Count; + + options.InterestGroup = (byte)view.group; + groupHashtable[(byte)0] = PhotonNetwork.ServerTimestamp; + if (this.currentLevelPrefix >= 0) + { + groupHashtable[(byte)1] = this.currentLevelPrefix; + } + + this.OpRaiseEvent(PunEvent.SendSerializeReliable, groupHashtable, true, options); + //Debug.Log("SendSerializeReliable (10) " + PhotonNetwork.networkingPeer.ByteCountLastOperation); + groupHashtable.Clear(); + } + } + else + { + Hashtable groupHashtable = null; + bool found = this.dataPerGroupUnreliable.TryGetValue(view.group, out groupHashtable); + if (!found) + { + groupHashtable = new Hashtable(NetworkingPeer.ObjectsInOneUpdate); + this.dataPerGroupUnreliable[view.group] = groupHashtable; + } + + groupHashtable.Add((byte)(groupHashtable.Count+10), evData); + countOfUpdatesToSend++; + + // if any group has XY elements, we should send it right away (to avoid bigger messages which need fragmentation and reliable transfer). + if (groupHashtable.Count >= NetworkingPeer.ObjectsInOneUpdate) + { + countOfUpdatesToSend -= groupHashtable.Count; + + options.InterestGroup = (byte)view.group; + groupHashtable[(byte)0] = PhotonNetwork.ServerTimestamp; + if (this.currentLevelPrefix >= 0) + { + groupHashtable[(byte)1] = this.currentLevelPrefix; + } + + this.OpRaiseEvent(PunEvent.SendSerialize, groupHashtable, false, options); + groupHashtable.Clear(); + //Debug.Log("SendSerializeUnreliable (10) " + PhotonNetwork.networkingPeer.ByteCountLastOperation); + } + } + } // all views serialized + + + // if we didn't produce anything to send, don't do it + if (countOfUpdatesToSend == 0) + { + return; + } + + + foreach (int groupId in this.dataPerGroupReliable.Keys) + { + options.InterestGroup = (byte)groupId; + Hashtable groupHashtable = this.dataPerGroupReliable[groupId]; + if (groupHashtable.Count == 0) + { + continue; + } + + groupHashtable[(byte)0] = PhotonNetwork.ServerTimestamp; + if (this.currentLevelPrefix >= 0) + { + groupHashtable[(byte)1] = this.currentLevelPrefix; + } + + this.OpRaiseEvent(PunEvent.SendSerializeReliable, groupHashtable, true, options); + groupHashtable.Clear(); + } + foreach (int groupId in this.dataPerGroupUnreliable.Keys) + { + options.InterestGroup = (byte)groupId; + Hashtable groupHashtable = this.dataPerGroupUnreliable[groupId]; + if (groupHashtable.Count == 0) + { + continue; + } + + groupHashtable[(byte)0] = PhotonNetwork.ServerTimestamp; + if (this.currentLevelPrefix >= 0) + { + groupHashtable[(byte)1] = this.currentLevelPrefix; + } + + this.OpRaiseEvent(PunEvent.SendSerialize, groupHashtable, false, options); + groupHashtable.Clear(); + } + } + + + // calls OnPhotonSerializeView (through ExecuteOnSerialize) + // the content created here is consumed by receivers in: ReadOnSerialize + private object[] OnSerializeWrite(PhotonView view) + { + if (view.synchronization == ViewSynchronization.Off) + { + return null; + } + + + // each view creates a list of values that should be sent + PhotonMessageInfo info = new PhotonMessageInfo(this.LocalPlayer, PhotonNetwork.ServerTimestamp, view); + this.pStream.ResetWriteStream(); + this.pStream.SendNext(null); + this.pStream.SendNext(null); + this.pStream.SendNext(null); + view.SerializeView(this.pStream, info); + + // check if there are actual values to be sent (after the "header" of viewId, (bool)compressed and (int[])nullValues) + if (this.pStream.Count <= SyncFirstValue) + { + return null; + } + + + object[] currentValues = this.pStream.ToArray(); + currentValues[0] = view.viewID; + currentValues[1] = false; + currentValues[2] = null; + + if (view.synchronization == ViewSynchronization.Unreliable) + { + return currentValues; + } + + + // ViewSynchronization: Off, Unreliable, UnreliableOnChange, ReliableDeltaCompressed + if (view.synchronization == ViewSynchronization.UnreliableOnChange) + { + if (AlmostEquals(currentValues, view.lastOnSerializeDataSent)) + { + if (view.mixedModeIsReliable) + { + return null; + } + + view.mixedModeIsReliable = true; + view.lastOnSerializeDataSent = currentValues; + } + else + { + view.mixedModeIsReliable = false; + view.lastOnSerializeDataSent = currentValues; + } + + return currentValues; + } + + if (view.synchronization == ViewSynchronization.ReliableDeltaCompressed) + { + // compress content of data set (by comparing to view.lastOnSerializeDataSent) + // the "original" dataArray is NOT modified by DeltaCompressionWrite + object[] dataToSend = this.DeltaCompressionWrite(view.lastOnSerializeDataSent, currentValues); + + // cache the values that were written this time (not the compressed values) + view.lastOnSerializeDataSent = currentValues; + + return dataToSend; + } + + return null; + } + + /// + /// Reads updates created by OnSerializeWrite + /// + private void OnSerializeRead(object[] data, PhotonPlayer sender, int networkTime, short correctPrefix) + { + // read view ID from key (byte)0: a int-array (PUN 1.17++) + int viewID = (int)data[SyncViewId]; + + + // debug: + //LogObjectArray(data); + + PhotonView view = this.GetPhotonView(viewID); + if (view == null) + { + Debug.LogWarning("Received OnSerialization for view ID " + viewID + ". We have no such PhotonView! Ignored this if you're leaving a room. State: " + this.State); + return; + } + + if (view.prefix > 0 && correctPrefix != view.prefix) + { + Debug.LogError("Received OnSerialization for view ID " + viewID + " with prefix " + correctPrefix + ". Our prefix is " + view.prefix); + return; + } + + // SetReceiving filtering + if (view.group != 0 && !this.allowedReceivingGroups.Contains(view.group)) + { + return; // Ignore group + } + + + + + if (view.synchronization == ViewSynchronization.ReliableDeltaCompressed) + { + object[] uncompressed = this.DeltaCompressionRead(view.lastOnSerializeDataReceived, data); + //LogObjectArray(uncompressed,"uncompressed "); + if (uncompressed == null) + { + // Skip this packet as we haven't got received complete-copy of this view yet. + if (PhotonNetwork.logLevel >= PhotonLogLevel.Informational) + { + Debug.Log("Skipping packet for " + view.name + " [" + view.viewID + "] as we haven't received a full packet for delta compression yet. This is OK if it happens for the first few frames after joining a game."); + } + return; + } + + // store last received values (uncompressed) for delta-compression usage + view.lastOnSerializeDataReceived = uncompressed; + data = uncompressed; + } + + // This is when joining late to assign ownership to the sender + // this has nothing to do with reading the actual synchronization update. + // We don't do anything is OwnerShip Was Touched, which means we got the infos already. We only possibly act if ownership was never transfered. + // We do override OwnerShipWasTransfered if owner is the masterClient. + if (sender.ID != view.ownerId && (!view.OwnerShipWasTransfered || view.ownerId == 0) && view.currentMasterID == -1 ) + { + // obviously the owner changed and we didn't yet notice. + //Debug.Log("Adjusting owner to sender of updates. From: " + view.ownerId + " to: " + sender.ID); + view.ownerId = sender.ID; + } + + this.readStream.SetReadStream(data, 3); + PhotonMessageInfo info = new PhotonMessageInfo(sender, networkTime, view); + + view.DeserializeView(this.readStream, info); + } + + + // compresses currentContent by using NULL as value if currentContent equals previousContent + // skips initial indexes, as defined by SyncFirstValue + // to conserve memory, the previousContent is re-used as buffer for the result! duplicate the values before using this, if needed + // returns null, if nothing must be sent (current content might be null, which also returns null) + // SyncFirstValue should be the index of the first actual data-value (3 in PUN's case, as 0=viewId, 1=(bool)compressed, 2=(int[])values that are now null) + public const int SyncViewId = 0; + public const int SyncCompressed = 1; + public const int SyncNullValues = 2; + public const int SyncFirstValue = 3; + + private object[] DeltaCompressionWrite(object[] previousContent, object[] currentContent) + { + if (currentContent == null || previousContent == null || previousContent.Length != currentContent.Length) + { + return currentContent; // the current data needs to be sent (which might be null) + } + + if (currentContent.Length <= SyncFirstValue) + { + return null; // this send doesn't contain values (except the "headers"), so it's not being sent + } + + + object[] compressedContent = previousContent; // the previous content is no longer needed, once we compared the values! + compressedContent[SyncCompressed] = false; + int compressedValues = 0; + + Queue valuesThatAreChangedToNull = null; + for (int index = SyncFirstValue; index < currentContent.Length; index++) + { + object newObj = currentContent[index]; + object oldObj = previousContent[index]; + if (this.AlmostEquals(newObj, oldObj)) + { + // compress (by using null, instead of value, which is same as before) + compressedValues++; + compressedContent[index] = null; + } + else + { + compressedContent[index] = newObj; + + // value changed, we don't replace it with null + // new value is null (like a compressed value): we have to mark it so it STAYS null instead of being replaced with previous value + if (newObj == null) + { + if (valuesThatAreChangedToNull == null) + { + valuesThatAreChangedToNull = new Queue(currentContent.Length); + } + valuesThatAreChangedToNull.Enqueue(index); + } + } + } + + // Only send the list of compressed fields if we actually compressed 1 or more fields. + if (compressedValues > 0) + { + if (compressedValues == currentContent.Length - SyncFirstValue) + { + // all values are compressed to null, we have nothing to send + return null; + } + + compressedContent[SyncCompressed] = true; + if (valuesThatAreChangedToNull != null) + { + compressedContent[SyncNullValues] = valuesThatAreChangedToNull.ToArray(); // data that is actually null (not just cause we didn't want to send it) + } + } + + compressedContent[SyncViewId] = currentContent[SyncViewId]; + return compressedContent; // some data was compressed but we need to send something + } + + private object[] DeltaCompressionRead(object[] lastOnSerializeDataReceived, object[] incomingData) + { + if ((bool)incomingData[SyncCompressed] == false) + { + // index 1 marks "compressed" as being true. + return incomingData; + } + + // Compression was applied (as data[1] == true) + // we need a previous "full" list of values to restore values that are null in this msg. else, ignore this + if (lastOnSerializeDataReceived == null) + { + return null; + } + + + int[] indexesThatAreChangedToNull = incomingData[(byte)2] as int[]; + for (int index = SyncFirstValue; index < incomingData.Length; index++) + { + if (indexesThatAreChangedToNull != null && indexesThatAreChangedToNull.Contains(index)) + { + continue; // if a value was set to null in this update, we don't need to fetch it from an earlier update + } + if (incomingData[index] == null) + { + // we replace null values in this received msg unless a index is in the "changed to null" list + object lastValue = lastOnSerializeDataReceived[index]; + incomingData[index] = lastValue; + } + } + + return incomingData; + } + + + // startIndex should be the index of the first actual data-value (3 in PUN's case, as 0=viewId, 1=(bool)compressed, 2=(int[])values that are now null) + // returns the incomingData with modified content. any object being null (means: value unchanged) gets replaced with a previously sent value. incomingData is being modified + + + private bool AlmostEquals(object[] lastData, object[] currentContent) + { + if (lastData == null && currentContent == null) + { + return true; + } + + if (lastData == null || currentContent == null || (lastData.Length != currentContent.Length)) + { + return false; + } + + for (int index = 0; index < currentContent.Length; index++) + { + object newObj = currentContent[index]; + object oldObj = lastData[index]; + if (!this.AlmostEquals(newObj, oldObj)) + { + return false; + } + } + + return true; + } + + /// + /// Returns true if both objects are almost identical. + /// Used to check whether two objects are similar enough to skip an update. + /// + bool AlmostEquals(object one, object two) + { + if (one == null || two == null) + { + return one == null && two == null; + } + + if (!one.Equals(two)) + { + // if A is not B, lets check if A is almost B + if (one is Vector3) + { + Vector3 a = (Vector3)one; + Vector3 b = (Vector3)two; + if (a.AlmostEquals(b, PhotonNetwork.precisionForVectorSynchronization)) + { + return true; + } + } + else if (one is Vector2) + { + Vector2 a = (Vector2)one; + Vector2 b = (Vector2)two; + if (a.AlmostEquals(b, PhotonNetwork.precisionForVectorSynchronization)) + { + return true; + } + } + else if (one is Quaternion) + { + Quaternion a = (Quaternion)one; + Quaternion b = (Quaternion)two; + if (a.AlmostEquals(b, PhotonNetwork.precisionForQuaternionSynchronization)) + { + return true; + } + } + else if (one is float) + { + float a = (float)one; + float b = (float)two; + if (a.AlmostEquals(b, PhotonNetwork.precisionForFloatSynchronization)) + { + return true; + } + } + + // one does not equal two + return false; + } + + return true; + } + + internal protected static bool GetMethod(MonoBehaviour monob, string methodType, out MethodInfo mi) + { + mi = null; + + if (monob == null || string.IsNullOrEmpty(methodType)) + { + return false; + } + + List methods = SupportClassPun.GetMethods(monob.GetType(), null); + for (int index = 0; index < methods.Count; index++) + { + MethodInfo methodInfo = methods[index]; + if (methodInfo.Name.Equals(methodType)) + { + mi = methodInfo; + return true; + } + } + + return false; + } + + /// Internally used to detect the current scene and load it if PhotonNetwork.automaticallySyncScene is enabled. + internal protected void LoadLevelIfSynced() + { + if (!PhotonNetwork.automaticallySyncScene || PhotonNetwork.isMasterClient || PhotonNetwork.room == null) + { + return; + } + + // check if "current level" is set in props + if (!PhotonNetwork.room.CustomProperties.ContainsKey(NetworkingPeer.CurrentSceneProperty)) + { + return; + } + + // if loaded level is not the one defined my master in props, load that level + object sceneId = PhotonNetwork.room.CustomProperties[NetworkingPeer.CurrentSceneProperty]; + if (sceneId is int) + { + if (SceneManagerHelper.ActiveSceneBuildIndex != (int)sceneId) + PhotonNetwork.LoadLevel((int)sceneId); + } + else if (sceneId is string) + { + if (SceneManagerHelper.ActiveSceneName != (string)sceneId) + PhotonNetwork.LoadLevel((string)sceneId); + } + } + + protected internal void SetLevelInPropsIfSynced(object levelId) + { + if (!PhotonNetwork.automaticallySyncScene || !PhotonNetwork.isMasterClient || PhotonNetwork.room == null) + { + return; + } + if (levelId == null) + { + Debug.LogError("Parameter levelId can't be null!"); + return; + } + + // check if "current level" is already set in props + if (PhotonNetwork.room.CustomProperties.ContainsKey(NetworkingPeer.CurrentSceneProperty)) + { + object levelIdInProps = PhotonNetwork.room.CustomProperties[NetworkingPeer.CurrentSceneProperty]; + if (levelIdInProps is int && SceneManagerHelper.ActiveSceneBuildIndex == (int)levelIdInProps) + { + return; + } + if (levelIdInProps is string && SceneManagerHelper.ActiveSceneName != null && SceneManagerHelper.ActiveSceneName.Equals((string)levelIdInProps)) + { + return; + } + } + + // current level is not yet in props, so this client has to set it + Hashtable setScene = new Hashtable(); + if (levelId is int) setScene[NetworkingPeer.CurrentSceneProperty] = (int)levelId; + else if (levelId is string) setScene[NetworkingPeer.CurrentSceneProperty] = (string)levelId; + else Debug.LogError("Parameter levelId must be int or string!"); + + PhotonNetwork.room.SetCustomProperties(setScene); + this.SendOutgoingCommands(); // send immediately! because: in most cases the client will begin to load and not send for a while + } + + public void SetApp(string appId, string gameVersion) + { + this.AppId = appId.Trim(); + + if (!string.IsNullOrEmpty(gameVersion)) + { + PhotonNetwork.gameVersion = gameVersion.Trim(); + } + } + + + public bool WebRpc(string uriPath, object parameters) + { + Dictionary opParameters = new Dictionary(); + opParameters.Add(ParameterCode.UriPath, uriPath); + opParameters.Add(ParameterCode.WebRpcParameters, parameters); + + return this.OpCustom(OperationCode.WebRpc, opParameters, true); + + } +} diff --git a/Assets/Photon Unity Networking/Plugins/PhotonNetwork/NetworkingPeer.cs.meta b/Assets/Photon Unity Networking/Plugins/PhotonNetwork/NetworkingPeer.cs.meta new file mode 100644 index 0000000..266e935 --- /dev/null +++ b/Assets/Photon Unity Networking/Plugins/PhotonNetwork/NetworkingPeer.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 6389c32085f1ef04f88e046b96ab6fc6 +labels: +- ExitGames +- PUN +- Photon +- Networking +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} diff --git a/Assets/Photon Unity Networking/Plugins/PhotonNetwork/PhotonClasses.cs b/Assets/Photon Unity Networking/Plugins/PhotonNetwork/PhotonClasses.cs new file mode 100644 index 0000000..0ecd5b3 --- /dev/null +++ b/Assets/Photon Unity Networking/Plugins/PhotonNetwork/PhotonClasses.cs @@ -0,0 +1,1542 @@ +// ---------------------------------------------------------------------------- +// +// PhotonNetwork Framework for Unity - Copyright (C) 2011 Exit Games GmbH +// +// +// +// +// developer@exitgames.com +// ---------------------------------------------------------------------------- + +#pragma warning disable 1587 +/// \file +/// Wraps up smaller classes that don't need their own file. +/// +/// +/// \defgroup publicApi Public API +/// \brief Groups the most important classes that you need to understand early on. +/// +/// \defgroup optionalGui Optional Gui Elements +/// \brief Useful GUI elements for PUN. +#pragma warning restore 1587 + +#if UNITY_5 && !UNITY_5_0 && !UNITY_5_1 && !UNITY_5_2 +#define UNITY_MIN_5_3 +#endif + +using System; +using System.Collections.Generic; +using ExitGames.Client.Photon; +using UnityEngine; + +using Hashtable = ExitGames.Client.Photon.Hashtable; +using SupportClassPun = ExitGames.Client.Photon.SupportClass; + + +/// Defines the OnPhotonSerializeView method to make it easy to implement correctly for observable scripts. +/// \ingroup publicApi +public interface IPunObservable +{ + /// + /// Called by PUN several times per second, so that your script can write and read synchronization data for the PhotonView. + /// + /// + /// This method will be called in scripts that are assigned as Observed component of a PhotonView.
+ /// PhotonNetwork.sendRateOnSerialize affects how often this method is called.
+ /// PhotonNetwork.sendRate affects how often packages are sent by this client.
+ /// + /// Implementing this method, you can customize which data a PhotonView regularly synchronizes. + /// Your code defines what is being sent (content) and how your data is used by receiving clients. + /// + /// Unlike other callbacks, OnPhotonSerializeView only gets called when it is assigned + /// to a PhotonView as PhotonView.observed script. + /// + /// To make use of this method, the PhotonStream is essential. It will be in "writing" mode" on the + /// client that controls a PhotonView (PhotonStream.isWriting == true) and in "reading mode" on the + /// remote clients that just receive that the controlling client sends. + /// + /// If you skip writing any value into the stream, PUN will skip the update. Used carefully, this can + /// conserve bandwidth and messages (which have a limit per room/second). + /// + /// Note that OnPhotonSerializeView is not called on remote clients when the sender does not send + /// any update. This can't be used as "x-times per second Update()". + ///
+ /// \ingroup publicApi + void OnPhotonSerializeView(PhotonStream stream, PhotonMessageInfo info); +} + +/// +/// This interface is used as definition of all callback methods of PUN, except OnPhotonSerializeView. Preferably, implement them individually. +/// +/// +/// This interface is available for completeness, more than for actually implementing it in a game. +/// You can implement each method individually in any MonoMehaviour, without implementing IPunCallbacks. +/// +/// PUN calls all callbacks by name. Don't use implement callbacks with fully qualified name. +/// Example: IPunCallbacks.OnConnectedToPhoton won't get called by Unity's SendMessage(). +/// +/// PUN will call these methods on any script that implements them, analog to Unity's events and callbacks. +/// The situation that triggers the call is described per method. +/// +/// OnPhotonSerializeView is NOT called like these callbacks! It's usage frequency is much higher and it is implemented in: IPunObservable. +/// +/// \ingroup publicApi +public interface IPunCallbacks +{ + /// + /// Called when the initial connection got established but before you can use the server. OnJoinedLobby() or OnConnectedToMaster() are called when PUN is ready. + /// + /// + /// This callback is only useful to detect if the server can be reached at all (technically). + /// Most often, it's enough to implement OnFailedToConnectToPhoton() and OnDisconnectedFromPhoton(). + /// + /// OnJoinedLobby() or OnConnectedToMaster() are called when PUN is ready. + /// + /// When this is called, the low level connection is established and PUN will send your AppId, the user, etc in the background. + /// This is not called for transitions from the masterserver to game servers. + /// + void OnConnectedToPhoton(); + + /// + /// Called when the local user/client left a room. + /// + /// + /// When leaving a room, PUN brings you back to the Master Server. + /// Before you can use lobbies and join or create rooms, OnJoinedLobby() or OnConnectedToMaster() will get called again. + /// + void OnLeftRoom(); + + /// + /// Called after switching to a new MasterClient when the current one leaves. + /// + /// + /// This is not called when this client enters a room. + /// The former MasterClient is still in the player list when this method get called. + /// + void OnMasterClientSwitched(PhotonPlayer newMasterClient); + + /// + /// Called when a CreateRoom() call failed. The parameter provides ErrorCode and message (as array). + /// + /// + /// Most likely because the room name is already in use (some other client was faster than you). + /// PUN logs some info if the PhotonNetwork.logLevel is >= PhotonLogLevel.Informational. + /// + /// codeAndMsg[0] is short ErrorCode and codeAndMsg[1] is a string debug msg. + void OnPhotonCreateRoomFailed(object[] codeAndMsg); + + /// + /// Called when a JoinRoom() call failed. The parameter provides ErrorCode and message (as array). + /// + /// + /// Most likely error is that the room does not exist or the room is full (some other client was faster than you). + /// PUN logs some info if the PhotonNetwork.logLevel is >= PhotonLogLevel.Informational. + /// + /// codeAndMsg[0] is short ErrorCode and codeAndMsg[1] is string debug msg. + void OnPhotonJoinRoomFailed(object[] codeAndMsg); + + /// + /// Called when this client created a room and entered it. OnJoinedRoom() will be called as well. + /// + /// + /// This callback is only called on the client which created a room (see PhotonNetwork.CreateRoom). + /// + /// As any client might close (or drop connection) anytime, there is a chance that the + /// creator of a room does not execute OnCreatedRoom. + /// + /// If you need specific room properties or a "start signal", it is safer to implement + /// OnMasterClientSwitched() and to make the new MasterClient check the room's state. + /// + void OnCreatedRoom(); + + /// + /// Called on entering a lobby on the Master Server. The actual room-list updates will call OnReceivedRoomListUpdate(). + /// + /// + /// Note: When PhotonNetwork.autoJoinLobby is false, OnConnectedToMaster() will be called and the room list won't become available. + /// + /// While in the lobby, the roomlist is automatically updated in fixed intervals (which you can't modify). + /// The room list gets available when OnReceivedRoomListUpdate() gets called after OnJoinedLobby(). + /// + void OnJoinedLobby(); + + /// + /// Called after leaving a lobby. + /// + /// + /// When you leave a lobby, [CreateRoom](@ref PhotonNetwork.CreateRoom) and [JoinRandomRoom](@ref PhotonNetwork.JoinRandomRoom) + /// automatically refer to the default lobby. + /// + void OnLeftLobby(); + + /// + /// Called if a connect call to the Photon server failed before the connection was established, followed by a call to OnDisconnectedFromPhoton(). + /// + /// + /// This is called when no connection could be established at all. + /// It differs from OnConnectionFail, which is called when an existing connection fails. + /// + void OnFailedToConnectToPhoton(DisconnectCause cause); + + /// + /// Called when something causes the connection to fail (after it was established), followed by a call to OnDisconnectedFromPhoton(). + /// + /// + /// If the server could not be reached in the first place, OnFailedToConnectToPhoton is called instead. + /// The reason for the error is provided as DisconnectCause. + /// + void OnConnectionFail(DisconnectCause cause); + + /// + /// Called after disconnecting from the Photon server. + /// + /// + /// In some cases, other callbacks are called before OnDisconnectedFromPhoton is called. + /// Examples: OnConnectionFail() and OnFailedToConnectToPhoton(). + /// + void OnDisconnectedFromPhoton(); + + /// + /// Called on all scripts on a GameObject (and children) that have been Instantiated using PhotonNetwork.Instantiate. + /// + /// + /// PhotonMessageInfo parameter provides info about who created the object and when (based off PhotonNetworking.time). + /// + void OnPhotonInstantiate(PhotonMessageInfo info); + + /// + /// Called for any update of the room-listing while in a lobby (PhotonNetwork.insideLobby) on the Master Server. + /// + /// + /// PUN provides the list of rooms by PhotonNetwork.GetRoomList().
+ /// Each item is a RoomInfo which might include custom properties (provided you defined those as lobby-listed when creating a room). + /// + /// Not all types of lobbies provide a listing of rooms to the client. Some are silent and specialized for server-side matchmaking. + ///
+ void OnReceivedRoomListUpdate(); + + /// + /// Called when entering a room (by creating or joining it). Called on all clients (including the Master Client). + /// + /// + /// This method is commonly used to instantiate player characters. + /// If a match has to be started "actively", you can call an [PunRPC](@ref PhotonView.RPC) triggered by a user's button-press or a timer. + /// + /// When this is called, you can usually already access the existing players in the room via PhotonNetwork.playerList. + /// Also, all custom properties should be already available as Room.customProperties. Check Room.playerCount to find out if + /// enough players are in the room to start playing. + /// + void OnJoinedRoom(); + + /// + /// Called when a remote player entered the room. This PhotonPlayer is already added to the playerlist at this time. + /// + /// + /// If your game starts with a certain number of players, this callback can be useful to check the + /// Room.playerCount and find out if you can start. + /// + void OnPhotonPlayerConnected(PhotonPlayer newPlayer); + + /// + /// Called when a remote player left the room. This PhotonPlayer is already removed from the playerlist at this time. + /// + /// + /// When your client calls PhotonNetwork.leaveRoom, PUN will call this method on the remaining clients. + /// When a remote client drops connection or gets closed, this callback gets executed. after a timeout + /// of several seconds. + /// + void OnPhotonPlayerDisconnected(PhotonPlayer otherPlayer); + + /// + /// Called when a JoinRandom() call failed. The parameter provides ErrorCode and message. + /// + /// + /// Most likely all rooms are full or no rooms are available.
+ /// When using multiple lobbies (via JoinLobby or TypedLobby), another lobby might have more/fitting rooms.
+ /// PUN logs some info if the PhotonNetwork.logLevel is >= PhotonLogLevel.Informational. + ///
+ /// codeAndMsg[0] is short ErrorCode. codeAndMsg[1] is string debug msg. + void OnPhotonRandomJoinFailed(object[] codeAndMsg); + + /// + /// Called after the connection to the master is established and authenticated but only when PhotonNetwork.autoJoinLobby is false. + /// + /// + /// If you set PhotonNetwork.autoJoinLobby to true, OnJoinedLobby() will be called instead of this. + /// + /// You can join rooms and create them even without being in a lobby. The default lobby is used in that case. + /// The list of available rooms won't become available unless you join a lobby via PhotonNetwork.joinLobby. + /// + void OnConnectedToMaster(); + + /// + /// Because the concurrent user limit was (temporarily) reached, this client is rejected by the server and disconnecting. + /// + /// + /// When this happens, the user might try again later. You can't create or join rooms in OnPhotonMaxCcuReached(), cause the client will be disconnecting. + /// You can raise the CCU limits with a new license (when you host yourself) or extended subscription (when using the Photon Cloud). + /// The Photon Cloud will mail you when the CCU limit was reached. This is also visible in the Dashboard (webpage). + /// + void OnPhotonMaxCccuReached(); + + /// + /// Called when a room's custom properties changed. The propertiesThatChanged contains all that was set via Room.SetCustomProperties. + /// + /// + /// Since v1.25 this method has one parameter: Hashtable propertiesThatChanged.
+ /// Changing properties must be done by Room.SetCustomProperties, which causes this callback locally, too. + ///
+ /// + void OnPhotonCustomRoomPropertiesChanged(Hashtable propertiesThatChanged); + + /// + /// Called when custom player-properties are changed. Player and the changed properties are passed as object[]. + /// + /// + /// Since v1.25 this method has one parameter: object[] playerAndUpdatedProps, which contains two entries.
+ /// [0] is the affected PhotonPlayer.
+ /// [1] is the Hashtable of properties that changed.
+ /// + /// We are using a object[] due to limitations of Unity's GameObject.SendMessage (which has only one optional parameter). + /// + /// Changing properties must be done by PhotonPlayer.SetCustomProperties, which causes this callback locally, too. + /// + /// Example:
+    /// void OnPhotonPlayerPropertiesChanged(object[] playerAndUpdatedProps) {
+    ///     PhotonPlayer player = playerAndUpdatedProps[0] as PhotonPlayer;
+    ///     Hashtable props = playerAndUpdatedProps[1] as Hashtable;
+    ///     //...
+    /// }
+ ///
+ /// Contains PhotonPlayer and the properties that changed See remarks. + void OnPhotonPlayerPropertiesChanged(object[] playerAndUpdatedProps); + + /// + /// Called when the server sent the response to a FindFriends request and updated PhotonNetwork.Friends. + /// + /// + /// The friends list is available as PhotonNetwork.Friends, listing name, online state and + /// the room a user is in (if any). + /// + void OnUpdatedFriendList(); + + /// + /// Called when the custom authentication failed. Followed by disconnect! + /// + /// + /// Custom Authentication can fail due to user-input, bad tokens/secrets. + /// If authentication is successful, this method is not called. Implement OnJoinedLobby() or OnConnectedToMaster() (as usual). + /// + /// During development of a game, it might also fail due to wrong configuration on the server side. + /// In those cases, logging the debugMessage is very important. + /// + /// Unless you setup a custom authentication service for your app (in the [Dashboard](https://www.photonengine.com/dashboard)), + /// this won't be called! + /// + /// Contains a debug message why authentication failed. This has to be fixed during development time. + void OnCustomAuthenticationFailed(string debugMessage); + + /// + /// Called when your Custom Authentication service responds with additional data. + /// + /// + /// Custom Authentication services can include some custom data in their response. + /// When present, that data is made available in this callback as Dictionary. + /// While the keys of your data have to be strings, the values can be either string or a number (in Json). + /// You need to make extra sure, that the value type is the one you expect. Numbers become (currently) int64. + /// + /// Example: void OnCustomAuthenticationResponse(Dictionary<string, object> data) { ... } + /// + /// + void OnCustomAuthenticationResponse(Dictionary data); + + /// + /// Called by PUN when the response to a WebRPC is available. See PhotonNetwork.WebRPC. + /// + /// + /// Important: The response.ReturnCode is 0 if Photon was able to reach your web-service.
+ /// The content of the response is what your web-service sent. You can create a WebRpcResponse from it.
+ /// Example: WebRpcResponse webResponse = new WebRpcResponse(operationResponse);
+ /// + /// Please note: Class OperationResponse is in a namespace which needs to be "used":
+ /// using ExitGames.Client.Photon; // includes OperationResponse (and other classes) + /// + /// The OperationResponse.ReturnCode by Photon is:
+    ///  0 for "OK"
+    /// -3 for "Web-Service not configured" (see Dashboard / WebHooks)
+    /// -5 for "Web-Service does now have RPC path/name" (at least for Azure)
+ ///
+ void OnWebRpcResponse(OperationResponse response); + + /// + /// Called when another player requests ownership of a PhotonView from you (the current owner). + /// + /// + /// The parameter viewAndPlayer contains: + /// + /// PhotonView view = viewAndPlayer[0] as PhotonView; + /// + /// PhotonPlayer requestingPlayer = viewAndPlayer[1] as PhotonPlayer; + /// + /// The PhotonView is viewAndPlayer[0] and the requesting player is viewAndPlayer[1]. + void OnOwnershipRequest(object[] viewAndPlayer); + + /// + /// Called when the Master Server sent an update for the Lobby Statistics, updating PhotonNetwork.LobbyStatistics. + /// + /// + /// This callback has two preconditions: + /// EnableLobbyStatistics must be set to true, before this client connects. + /// And the client has to be connected to the Master Server, which is providing the info about lobbies. + /// + void OnLobbyStatisticsUpdate(); + + /// + /// Called when a remote Photon Player activity changed. This will be called ONLY if PlayerTtl is greater than 0. + /// + /// + /// Use PhotonPlayer.IsInactive to check a player's current activity state. + /// + /// Example: void OnPhotonPlayerActivityChanged(PhotonPlayer otherPlayer) {...} + /// + /// This callback has precondition: + /// PlayerTtl must be greater than 0. + /// + void OnPhotonPlayerActivityChanged(PhotonPlayer otherPlayer); + + /// + /// Called when ownership of a PhotonView is transfered to another player. + /// + /// + /// The parameter viewAndPlayers contains: + /// + /// PhotonView view = viewAndPlayers[0] as PhotonView; + /// + /// PhotonPlayer newOwner = viewAndPlayers[1] as PhotonPlayer; + /// + /// PhotonPlayer oldOwner = viewAndPlayers[2] as PhotonPlayer; + /// + /// void OnOwnershipTransfered(object[] viewAndPlayers) {} // + void OnOwnershipTransfered(object[] viewAndPlayers); +} + +/// +/// Defines all the methods that a Object Pool must implement, so that PUN can use it. +/// +/// +/// To use a Object Pool for instantiation, you can set PhotonNetwork.ObjectPool. +/// That is used for all objects, as long as ObjectPool is not null. +/// The pool has to return a valid non-null GameObject when PUN calls Instantiate. +/// Also, the position and rotation must be applied. +/// +/// Please note that pooled GameObjects don't get the usual Awake and Start calls. +/// OnEnable will be called (by your pool) but the networking values are not updated yet +/// when that happens. OnEnable will have outdated values for PhotonView (isMine, etc.). +/// You might have to adjust scripts. +/// +/// PUN will call OnPhotonInstantiate (see IPunCallbacks). This should be used to +/// setup the re-used object with regards to networking values / ownership. +/// +public interface IPunPrefabPool +{ + /// + /// This is called when PUN wants to create a new instance of an entity prefab. Must return valid GameObject with PhotonView. + /// + /// The id of this prefab. + /// The position we want the instance instantiated at. + /// The rotation we want the instance to take. + /// The newly instantiated object, or null if a prefab with was not found. + GameObject Instantiate(string prefabId, Vector3 position, Quaternion rotation); + + /// + /// This is called when PUN wants to destroy the instance of an entity prefab. + /// + /// + /// A pool needs some way to find out which type of GameObject got returned via Destroy(). + /// It could be a tag or name or anything similar. + /// + /// The instance to destroy. + void Destroy(GameObject gameObject); +} + + +namespace Photon +{ + using Hashtable = ExitGames.Client.Photon.Hashtable; + + /// + /// This class adds the property photonView, while logging a warning when your game still uses the networkView. + /// + public class MonoBehaviour : UnityEngine.MonoBehaviour + { + /// Cache field for the PhotonView on this GameObject. + private PhotonView pvCache = null; + + /// A cached reference to a PhotonView on this GameObject. + /// + /// If you intend to work with a PhotonView in a script, it's usually easier to write this.photonView. + /// + /// If you intend to remove the PhotonView component from the GameObject but keep this Photon.MonoBehaviour, + /// avoid this reference or modify this code to use PhotonView.Get(obj) instead. + /// + public PhotonView photonView + { + get + { + if (pvCache == null) + { + pvCache = PhotonView.Get(this); + } + return pvCache; + } + } + + #if !UNITY_MIN_5_3 + /// + /// This property is only here to notify developers when they use the outdated value. + /// + /// + /// If Unity 5.x logs a compiler warning "Use the new keyword if hiding was intended" or + /// "The new keyword is not required", you may suffer from an Editor issue. + /// Try to modify networkView with a if-def condition: + /// + /// #if UNITY_EDITOR + /// new + /// #endif + /// public PhotonView networkView + /// + [Obsolete("Use a photonView")] + public new PhotonView networkView + { + get + { + Debug.LogWarning("Why are you still using networkView? should be PhotonView?"); + return PhotonView.Get(this); + } + } + #endif + } + + + /// + /// This class provides a .photonView and all callbacks/events that PUN can call. Override the events/methods you want to use. + /// + /// + /// By extending this class, you can implement individual methods as override. + /// + /// Visual Studio and MonoDevelop should provide the list of methods when you begin typing "override". + /// Your implementation does not have to call "base.method()". + /// + /// This class implements IPunCallbacks, which is used as definition of all PUN callbacks. + /// Don't implement IPunCallbacks in your classes. Instead, implent PunBehaviour or individual methods. + /// + /// \ingroup publicApi + // the documentation for the interface methods becomes inherited when Doxygen builds it. + public class PunBehaviour : Photon.MonoBehaviour, IPunCallbacks + { + /// + /// Called when the initial connection got established but before you can use the server. OnJoinedLobby() or OnConnectedToMaster() are called when PUN is ready. + /// + /// + /// This callback is only useful to detect if the server can be reached at all (technically). + /// Most often, it's enough to implement OnFailedToConnectToPhoton() and OnDisconnectedFromPhoton(). + /// + /// OnJoinedLobby() or OnConnectedToMaster() are called when PUN is ready. + /// + /// When this is called, the low level connection is established and PUN will send your AppId, the user, etc in the background. + /// This is not called for transitions from the masterserver to game servers. + /// + public virtual void OnConnectedToPhoton() + { + } + + /// + /// Called when the local user/client left a room. + /// + /// + /// When leaving a room, PUN brings you back to the Master Server. + /// Before you can use lobbies and join or create rooms, OnJoinedLobby() or OnConnectedToMaster() will get called again. + /// + public virtual void OnLeftRoom() + { + } + + /// + /// Called after switching to a new MasterClient when the current one leaves. + /// + /// + /// This is not called when this client enters a room. + /// The former MasterClient is still in the player list when this method get called. + /// + public virtual void OnMasterClientSwitched(PhotonPlayer newMasterClient) + { + } + + /// + /// Called when a CreateRoom() call failed. The parameter provides ErrorCode and message (as array). + /// + /// + /// Most likely because the room name is already in use (some other client was faster than you). + /// PUN logs some info if the PhotonNetwork.logLevel is >= PhotonLogLevel.Informational. + /// + /// codeAndMsg[0] is a short ErrorCode and codeAndMsg[1] is a string debug msg. + public virtual void OnPhotonCreateRoomFailed(object[] codeAndMsg) + { + } + + /// + /// Called when a JoinRoom() call failed. The parameter provides ErrorCode and message (as array). + /// + /// + /// Most likely error is that the room does not exist or the room is full (some other client was faster than you). + /// PUN logs some info if the PhotonNetwork.logLevel is >= PhotonLogLevel.Informational. + /// + /// codeAndMsg[0] is short ErrorCode. codeAndMsg[1] is string debug msg. + public virtual void OnPhotonJoinRoomFailed(object[] codeAndMsg) + { + } + + /// + /// Called when this client created a room and entered it. OnJoinedRoom() will be called as well. + /// + /// + /// This callback is only called on the client which created a room (see PhotonNetwork.CreateRoom). + /// + /// As any client might close (or drop connection) anytime, there is a chance that the + /// creator of a room does not execute OnCreatedRoom. + /// + /// If you need specific room properties or a "start signal", it is safer to implement + /// OnMasterClientSwitched() and to make the new MasterClient check the room's state. + /// + public virtual void OnCreatedRoom() + { + } + + /// + /// Called on entering a lobby on the Master Server. The actual room-list updates will call OnReceivedRoomListUpdate(). + /// + /// + /// Note: When PhotonNetwork.autoJoinLobby is false, OnConnectedToMaster() will be called and the room list won't become available. + /// + /// While in the lobby, the roomlist is automatically updated in fixed intervals (which you can't modify). + /// The room list gets available when OnReceivedRoomListUpdate() gets called after OnJoinedLobby(). + /// + public virtual void OnJoinedLobby() + { + } + + /// + /// Called after leaving a lobby. + /// + /// + /// When you leave a lobby, [CreateRoom](@ref PhotonNetwork.CreateRoom) and [JoinRandomRoom](@ref PhotonNetwork.JoinRandomRoom) + /// automatically refer to the default lobby. + /// + public virtual void OnLeftLobby() + { + } + + /// + /// Called if a connect call to the Photon server failed before the connection was established, followed by a call to OnDisconnectedFromPhoton(). + /// + /// + /// This is called when no connection could be established at all. + /// It differs from OnConnectionFail, which is called when an existing connection fails. + /// + public virtual void OnFailedToConnectToPhoton(DisconnectCause cause) + { + } + + /// + /// Called after disconnecting from the Photon server. + /// + /// + /// In some cases, other callbacks are called before OnDisconnectedFromPhoton is called. + /// Examples: OnConnectionFail() and OnFailedToConnectToPhoton(). + /// + public virtual void OnDisconnectedFromPhoton() + { + } + + /// + /// Called when something causes the connection to fail (after it was established), followed by a call to OnDisconnectedFromPhoton(). + /// + /// + /// If the server could not be reached in the first place, OnFailedToConnectToPhoton is called instead. + /// The reason for the error is provided as DisconnectCause. + /// + public virtual void OnConnectionFail(DisconnectCause cause) + { + } + + /// + /// Called on all scripts on a GameObject (and children) that have been Instantiated using PhotonNetwork.Instantiate. + /// + /// + /// PhotonMessageInfo parameter provides info about who created the object and when (based off PhotonNetworking.time). + /// + public virtual void OnPhotonInstantiate(PhotonMessageInfo info) + { + } + + /// + /// Called for any update of the room-listing while in a lobby (PhotonNetwork.insideLobby) on the Master Server. + /// + /// + /// PUN provides the list of rooms by PhotonNetwork.GetRoomList().
+ /// Each item is a RoomInfo which might include custom properties (provided you defined those as lobby-listed when creating a room). + /// + /// Not all types of lobbies provide a listing of rooms to the client. Some are silent and specialized for server-side matchmaking. + ///
+ public virtual void OnReceivedRoomListUpdate() + { + } + + /// + /// Called when entering a room (by creating or joining it). Called on all clients (including the Master Client). + /// + /// + /// This method is commonly used to instantiate player characters. + /// If a match has to be started "actively", you can call an [PunRPC](@ref PhotonView.RPC) triggered by a user's button-press or a timer. + /// + /// When this is called, you can usually already access the existing players in the room via PhotonNetwork.playerList. + /// Also, all custom properties should be already available as Room.customProperties. Check Room.playerCount to find out if + /// enough players are in the room to start playing. + /// + public virtual void OnJoinedRoom() + { + } + + /// + /// Called when a remote player entered the room. This PhotonPlayer is already added to the playerlist at this time. + /// + /// + /// If your game starts with a certain number of players, this callback can be useful to check the + /// Room.playerCount and find out if you can start. + /// + public virtual void OnPhotonPlayerConnected(PhotonPlayer newPlayer) + { + } + + /// + /// Called when a remote player left the room. This PhotonPlayer is already removed from the playerlist at this time. + /// + /// + /// When your client calls PhotonNetwork.leaveRoom, PUN will call this method on the remaining clients. + /// When a remote client drops connection or gets closed, this callback gets executed. after a timeout + /// of several seconds. + /// + public virtual void OnPhotonPlayerDisconnected(PhotonPlayer otherPlayer) + { + } + + /// + /// Called when a JoinRandom() call failed. The parameter provides ErrorCode and message. + /// + /// + /// Most likely all rooms are full or no rooms are available.
+ /// When using multiple lobbies (via JoinLobby or TypedLobby), another lobby might have more/fitting rooms.
+ /// PUN logs some info if the PhotonNetwork.logLevel is >= PhotonLogLevel.Informational. + ///
+ /// codeAndMsg[0] is short ErrorCode. codeAndMsg[1] is string debug msg. + public virtual void OnPhotonRandomJoinFailed(object[] codeAndMsg) + { + } + + /// + /// Called after the connection to the master is established and authenticated but only when PhotonNetwork.autoJoinLobby is false. + /// + /// + /// If you set PhotonNetwork.autoJoinLobby to true, OnJoinedLobby() will be called instead of this. + /// + /// You can join rooms and create them even without being in a lobby. The default lobby is used in that case. + /// The list of available rooms won't become available unless you join a lobby via PhotonNetwork.joinLobby. + /// + public virtual void OnConnectedToMaster() + { + } + + /// + /// Because the concurrent user limit was (temporarily) reached, this client is rejected by the server and disconnecting. + /// + /// + /// When this happens, the user might try again later. You can't create or join rooms in OnPhotonMaxCcuReached(), cause the client will be disconnecting. + /// You can raise the CCU limits with a new license (when you host yourself) or extended subscription (when using the Photon Cloud). + /// The Photon Cloud will mail you when the CCU limit was reached. This is also visible in the Dashboard (webpage). + /// + public virtual void OnPhotonMaxCccuReached() + { + } + + /// + /// Called when a room's custom properties changed. The propertiesThatChanged contains all that was set via Room.SetCustomProperties. + /// + /// + /// Since v1.25 this method has one parameter: Hashtable propertiesThatChanged.
+ /// Changing properties must be done by Room.SetCustomProperties, which causes this callback locally, too. + ///
+ /// + public virtual void OnPhotonCustomRoomPropertiesChanged(Hashtable propertiesThatChanged) + { + } + + /// + /// Called when custom player-properties are changed. Player and the changed properties are passed as object[]. + /// + /// + /// Since v1.25 this method has one parameter: object[] playerAndUpdatedProps, which contains two entries.
+ /// [0] is the affected PhotonPlayer.
+ /// [1] is the Hashtable of properties that changed.
+ /// + /// We are using a object[] due to limitations of Unity's GameObject.SendMessage (which has only one optional parameter). + /// + /// Changing properties must be done by PhotonPlayer.SetCustomProperties, which causes this callback locally, too. + /// + /// Example:
+        /// void OnPhotonPlayerPropertiesChanged(object[] playerAndUpdatedProps) {
+        ///     PhotonPlayer player = playerAndUpdatedProps[0] as PhotonPlayer;
+        ///     Hashtable props = playerAndUpdatedProps[1] as Hashtable;
+        ///     //...
+        /// }
+ ///
+ /// Contains PhotonPlayer and the properties that changed See remarks. + public virtual void OnPhotonPlayerPropertiesChanged(object[] playerAndUpdatedProps) + { + } + + /// + /// Called when the server sent the response to a FindFriends request and updated PhotonNetwork.Friends. + /// + /// + /// The friends list is available as PhotonNetwork.Friends, listing name, online state and + /// the room a user is in (if any). + /// + public virtual void OnUpdatedFriendList() + { + } + + /// + /// Called when the custom authentication failed. Followed by disconnect! + /// + /// + /// Custom Authentication can fail due to user-input, bad tokens/secrets. + /// If authentication is successful, this method is not called. Implement OnJoinedLobby() or OnConnectedToMaster() (as usual). + /// + /// During development of a game, it might also fail due to wrong configuration on the server side. + /// In those cases, logging the debugMessage is very important. + /// + /// Unless you setup a custom authentication service for your app (in the [Dashboard](https://www.photonengine.com/dashboard)), + /// this won't be called! + /// + /// Contains a debug message why authentication failed. This has to be fixed during development time. + public virtual void OnCustomAuthenticationFailed(string debugMessage) + { + } + + /// + /// Called when your Custom Authentication service responds with additional data. + /// + /// + /// Custom Authentication services can include some custom data in their response. + /// When present, that data is made available in this callback as Dictionary. + /// While the keys of your data have to be strings, the values can be either string or a number (in Json). + /// You need to make extra sure, that the value type is the one you expect. Numbers become (currently) int64. + /// + /// Example: void OnCustomAuthenticationResponse(Dictionary<string, object> data) { ... } + /// + /// + public virtual void OnCustomAuthenticationResponse(Dictionary data) + { + } + + /// + /// Called by PUN when the response to a WebRPC is available. See PhotonNetwork.WebRPC. + /// + /// + /// Important: The response.ReturnCode is 0 if Photon was able to reach your web-service. + /// The content of the response is what your web-service sent. You can create a WebResponse instance from it. + /// Example: WebRpcResponse webResponse = new WebRpcResponse(operationResponse); + /// + /// Please note: Class OperationResponse is in a namespace which needs to be "used": + /// using ExitGames.Client.Photon; // includes OperationResponse (and other classes) + /// + /// The OperationResponse.ReturnCode by Photon is:
+        ///  0 for "OK"
+        /// -3 for "Web-Service not configured" (see Dashboard / WebHooks)
+        /// -5 for "Web-Service does now have RPC path/name" (at least for Azure)
+ ///
+ public virtual void OnWebRpcResponse(OperationResponse response) + { + } + + /// + /// Called when another player requests ownership of a PhotonView from you (the current owner). + /// + /// + /// The parameter viewAndPlayer contains: + /// + /// PhotonView view = viewAndPlayer[0] as PhotonView; + /// + /// PhotonPlayer requestingPlayer = viewAndPlayer[1] as PhotonPlayer; + /// + /// The PhotonView is viewAndPlayer[0] and the requesting player is viewAndPlayer[1]. + public virtual void OnOwnershipRequest(object[] viewAndPlayer) + { + } + + /// + /// Called when the Master Server sent an update for the Lobby Statistics, updating PhotonNetwork.LobbyStatistics. + /// + /// + /// This callback has two preconditions: + /// EnableLobbyStatistics must be set to true, before this client connects. + /// And the client has to be connected to the Master Server, which is providing the info about lobbies. + /// + public virtual void OnLobbyStatisticsUpdate() + { + } + + /// + /// Called when a remote Photon Player activity changed. This will be called ONLY if PlayerTtl is greater than 0. + /// + /// + /// Use PhotonPlayer.IsInactive to check a player's current activity state. + /// + /// Example: void OnPhotonPlayerActivityChanged(PhotonPlayer otherPlayer) {...} + /// + /// This callback has precondition: + /// PlayerTtl must be greater than 0. + /// + public virtual void OnPhotonPlayerActivityChanged(PhotonPlayer otherPlayer) + { + } + + /// + /// Called when ownership of a PhotonView is transfered to another player. + /// + /// + /// The parameter viewAndPlayers contains: + /// + /// PhotonView view = viewAndPlayers[0] as PhotonView; + /// + /// PhotonPlayer newOwner = viewAndPlayers[1] as PhotonPlayer; + /// + /// PhotonPlayer oldOwner = viewAndPlayers[2] as PhotonPlayer; + /// + /// void OnOwnershipTransfered(object[] viewAndPlayers) {} // + public virtual void OnOwnershipTransfered(object[] viewAndPlayers) + { + } + } +} + + +/// +/// Container class for info about a particular message, RPC or update. +/// +/// \ingroup publicApi +public struct PhotonMessageInfo +{ + private readonly int timeInt; + public readonly PhotonPlayer sender; + public readonly PhotonView photonView; + + public PhotonMessageInfo(PhotonPlayer player, int timestamp, PhotonView view) + { + this.sender = player; + this.timeInt = timestamp; + this.photonView = view; + } + + public double timestamp + { + get + { + uint u = (uint)this.timeInt; + double t = u; + return t / 1000; + } + } + + public override string ToString() + { + return string.Format("[PhotonMessageInfo: Sender='{1}' Senttime={0}]", this.timestamp, this.sender); + } +} + + + +/// Defines Photon event-codes as used by PUN. +internal class PunEvent +{ + public const byte RPC = 200; + public const byte SendSerialize = 201; + public const byte Instantiation = 202; + public const byte CloseConnection = 203; + public const byte Destroy = 204; + public const byte RemoveCachedRPCs = 205; + public const byte SendSerializeReliable = 206; // TS: added this but it's not really needed anymore + public const byte DestroyPlayer = 207; // TS: added to make others remove all GOs of a player + public const byte AssignMaster = 208; // TS: added to assign someone master client (overriding the current) + public const byte OwnershipRequest = 209; + public const byte OwnershipTransfer = 210; + public const byte VacantViewIds = 211; +} + +/// +/// This container is used in OnPhotonSerializeView() to either provide incoming data of a PhotonView or for you to provide it. +/// +/// +/// The isWriting property will be true if this client is the "owner" of the PhotonView (and thus the GameObject). +/// Add data to the stream and it's sent via the server to the other players in a room. +/// On the receiving side, isWriting is false and the data should be read. +/// +/// Send as few data as possible to keep connection quality up. An empty PhotonStream will not be sent. +/// +/// Use either Serialize() for reading and writing or SendNext() and ReceiveNext(). The latter two are just explicit read and +/// write methods but do about the same work as Serialize(). It's a matter of preference which methods you use. +/// +/// +/// \ingroup publicApi +public class PhotonStream +{ + bool write = false; + private Queue writeData; + private object[] readData; + internal byte currentItem = 0; //Used to track the next item to receive. + + /// + /// Creates a stream and initializes it. Used by PUN internally. + /// + public PhotonStream(bool write, object[] incomingData) + { + this.write = write; + if (incomingData == null) + { + this.writeData = new Queue(10); + } + else + { + this.readData = incomingData; + } + } + + public void SetReadStream(object[] incomingData, byte pos = 0) + { + this.readData = incomingData; + this.currentItem = pos; + this.write = false; + } + + internal void ResetWriteStream() + { + writeData.Clear(); + } + + /// If true, this client should add data to the stream to send it. + public bool isWriting + { + get { return this.write; } + } + + /// If true, this client should read data send by another client. + public bool isReading + { + get { return !this.write; } + } + + /// Count of items in the stream. + public int Count + { + get + { + return (this.isWriting) ? this.writeData.Count : this.readData.Length; + } + } + + /// Read next piece of data from the stream when isReading is true. + public object ReceiveNext() + { + if (this.write) + { + Debug.LogError("Error: you cannot read this stream that you are writing!"); + return null; + } + + object obj = this.readData[this.currentItem]; + this.currentItem++; + return obj; + } + + /// Read next piece of data from the stream without advancing the "current" item. + public object PeekNext() + { + if (this.write) + { + Debug.LogError("Error: you cannot read this stream that you are writing!"); + return null; + } + + object obj = this.readData[this.currentItem]; + //this.currentItem++; + return obj; + } + + /// Add another piece of data to send it when isWriting is true. + public void SendNext(object obj) + { + if (!this.write) + { + Debug.LogError("Error: you cannot write/send to this stream that you are reading!"); + return; + } + + this.writeData.Enqueue(obj); + } + + /// Turns the stream into a new object[]. + public object[] ToArray() + { + return this.isWriting ? this.writeData.ToArray() : this.readData; + } + + /// + /// Will read or write the value, depending on the stream's isWriting value. + /// + public void Serialize(ref bool myBool) + { + if (this.write) + { + this.writeData.Enqueue(myBool); + } + else + { + if (this.readData.Length > currentItem) + { + myBool = (bool)this.readData[currentItem]; + this.currentItem++; + } + } + } + + /// + /// Will read or write the value, depending on the stream's isWriting value. + /// + public void Serialize(ref int myInt) + { + if (write) + { + this.writeData.Enqueue(myInt); + } + else + { + if (this.readData.Length > currentItem) + { + myInt = (int)this.readData[currentItem]; + currentItem++; + } + } + } + + /// + /// Will read or write the value, depending on the stream's isWriting value. + /// + public void Serialize(ref string value) + { + if (write) + { + this.writeData.Enqueue(value); + } + else + { + if (this.readData.Length > currentItem) + { + value = (string)this.readData[currentItem]; + currentItem++; + } + } + } + + /// + /// Will read or write the value, depending on the stream's isWriting value. + /// + public void Serialize(ref char value) + { + if (write) + { + this.writeData.Enqueue(value); + } + else + { + if (this.readData.Length > currentItem) + { + value = (char)this.readData[currentItem]; + currentItem++; + } + } + } + + /// + /// Will read or write the value, depending on the stream's isWriting value. + /// + public void Serialize(ref short value) + { + if (write) + { + this.writeData.Enqueue(value); + } + else + { + if (this.readData.Length > currentItem) + { + value = (short)this.readData[currentItem]; + currentItem++; + } + } + } + + /// + /// Will read or write the value, depending on the stream's isWriting value. + /// + public void Serialize(ref float obj) + { + if (write) + { + this.writeData.Enqueue(obj); + } + else + { + if (this.readData.Length > currentItem) + { + obj = (float)this.readData[currentItem]; + currentItem++; + } + } + } + + /// + /// Will read or write the value, depending on the stream's isWriting value. + /// + public void Serialize(ref PhotonPlayer obj) + { + if (write) + { + this.writeData.Enqueue(obj); + } + else + { + if (this.readData.Length > currentItem) + { + obj = (PhotonPlayer)this.readData[currentItem]; + currentItem++; + } + } + } + + /// + /// Will read or write the value, depending on the stream's isWriting value. + /// + public void Serialize(ref Vector3 obj) + { + if (write) + { + this.writeData.Enqueue(obj); + } + else + { + if (this.readData.Length > currentItem) + { + obj = (Vector3)this.readData[currentItem]; + currentItem++; + } + } + } + + /// + /// Will read or write the value, depending on the stream's isWriting value. + /// + public void Serialize(ref Vector2 obj) + { + if (write) + { + this.writeData.Enqueue(obj); + } + else + { + if (this.readData.Length > currentItem) + { + obj = (Vector2)this.readData[currentItem]; + currentItem++; + } + } + } + + /// + /// Will read or write the value, depending on the stream's isWriting value. + /// + public void Serialize(ref Quaternion obj) + { + if (write) + { + this.writeData.Enqueue(obj); + } + else + { + if (this.readData.Length > currentItem) + { + obj = (Quaternion)this.readData[currentItem]; + currentItem++; + } + } + } +} + + +#if UNITY_5_0 || !UNITY_5 +/// Empty implementation of the upcoming HelpURL of Unity 5.1. This one is only for compatibility of attributes. +/// http://feedback.unity3d.com/suggestions/override-component-documentation-slash-help-link +public class HelpURL : Attribute +{ + public HelpURL(string url) + { + } +} +#endif + + +#if !UNITY_MIN_5_3 && ! UNITY_2017 +// in Unity 5.3 and up, we have to use a SceneManager. This section re-implements it for older Unity versions + +#if UNITY_EDITOR +namespace UnityEditor.SceneManagement +{ + /// Minimal implementation of the EditorSceneManager for older Unity, up to v5.2. + public class EditorSceneManager + { + public static int loadedSceneCount + { + get { return string.IsNullOrEmpty(UnityEditor.EditorApplication.currentScene) ? -1 : 1; } + } + + public static void OpenScene(string name) + { + UnityEditor.EditorApplication.OpenScene(name); + } + + public static void SaveOpenScenes() + { + UnityEditor.EditorApplication.SaveScene(); + } + + public static void SaveCurrentModifiedScenesIfUserWantsTo() + { + UnityEditor.EditorApplication.SaveCurrentSceneIfUserWantsTo(); + } + } +} +#endif + +namespace UnityEngine.SceneManagement +{ + /// Minimal implementation of the SceneManager for older Unity, up to v5.2. + public class SceneManager + { + public static void LoadScene(string name) + { + Application.LoadLevel(name); + } + + public static void LoadScene(int buildIndex) + { + Application.LoadLevel(buildIndex); + } + } +} + +#endif + + +public class SceneManagerHelper +{ + public static string ActiveSceneName + { + get + { + #if UNITY_MIN_5_3 + UnityEngine.SceneManagement.Scene s = UnityEngine.SceneManagement.SceneManager.GetActiveScene(); + return s.name; + #else + return Application.loadedLevelName; + #endif + } + } + + public static int ActiveSceneBuildIndex + { + get + { + #if UNITY_MIN_5_3 + return UnityEngine.SceneManagement.SceneManager.GetActiveScene().buildIndex; + #else + return Application.loadedLevel; + #endif + } + } + + +#if UNITY_EDITOR + public static string EditorActiveSceneName + { + get + { + #if UNITY_MIN_5_3 + return UnityEditor.SceneManagement.EditorSceneManager.GetActiveScene().name; + #else + return System.IO.Path.GetFileNameWithoutExtension(UnityEditor.EditorApplication.currentScene); + #endif + } + } +#endif +} + + +/// Reads an operation response of a WebRpc and provides convenient access to most common values. +/// +/// See method PhotonNetwork.WebRpc.
+/// Create a WebRpcResponse to access common result values.
+/// The operationResponse.OperationCode should be: OperationCode.WebRpc.
+///
+public class WebRpcResponse +{ + /// Name of the WebRpc that was called. + public string Name { get; private set; } + /// ReturnCode of the WebService that answered the WebRpc. + /// + /// 0 is commonly used to signal success.
+ /// -1 tells you: Got no ReturnCode from WebRpc service.
+ /// Other ReturnCodes are defined by the individual WebRpc and service. + ///
+ public int ReturnCode { get; private set; } + /// Might be empty or null. + public string DebugMessage { get; private set; } + /// Other key/values returned by the webservice that answered the WebRpc. + public Dictionary Parameters { get; private set; } + + /// An OperationResponse for a WebRpc is needed to read it's values. + public WebRpcResponse(OperationResponse response) + { + object value; + response.Parameters.TryGetValue(ParameterCode.UriPath, out value); + this.Name = value as string; + + response.Parameters.TryGetValue(ParameterCode.WebRpcReturnCode, out value); + this.ReturnCode = (value != null) ? (byte)value : -1; + + response.Parameters.TryGetValue(ParameterCode.WebRpcParameters, out value); + this.Parameters = value as Dictionary; + + response.Parameters.TryGetValue(ParameterCode.WebRpcReturnMessage, out value); + this.DebugMessage = value as string; + } + + /// Turns the response into an easier to read string. + /// String resembling the result. + public string ToStringFull() + { + return string.Format("{0}={2}: {1} \"{3}\"", Name, SupportClassPun.DictionaryToString(Parameters), ReturnCode, DebugMessage); + } +} + +/** +public class PBitStream +{ + List streamBytes; + private int currentByte; + private int totalBits = 0; + + public int ByteCount + { + get { return BytesForBits(this.totalBits); } + } + + public int BitCount + { + get { return this.totalBits; } + private set { this.totalBits = value; } + } + + public PBitStream() + { + this.streamBytes = new List(1); + } + + public PBitStream(int bitCount) + { + this.streamBytes = new List(BytesForBits(bitCount)); + } + + public PBitStream(IEnumerable bytes, int bitCount) + { + this.streamBytes = new List(bytes); + this.BitCount = bitCount; + } + + public static int BytesForBits(int bitCount) + { + if (bitCount <= 0) + { + return 0; + } + + return ((bitCount - 1) / 8) + 1; + } + + public void Add(bool val) + { + int bytePos = this.totalBits / 8; + if (bytePos > this.streamBytes.Count-1 || this.totalBits == 0) + { + this.streamBytes.Add(0); + } + + if (val) + { + int currentByteBit = 7 - (this.totalBits % 8); + this.streamBytes[bytePos] |= (byte)(1 << currentByteBit); + } + + this.totalBits++; + } + + public byte[] ToBytes() + { + return this.streamBytes.ToArray(); + } + + public int Position { get; set; } + + public bool GetNext() + { + if (this.Position > this.totalBits) + { + throw new Exception("End of PBitStream reached. Can't read more."); + } + + return Get(this.Position++); + } + + public bool Get(int bitIndex) + { + int byteIndex = bitIndex / 8; + int bitInByIndex = 7 - (bitIndex % 8); + return ((this.streamBytes[byteIndex] & (byte)(1 << bitInByIndex)) > 0); + } + + public void Set(int bitIndex, bool value) + { + int byteIndex = bitIndex / 8; + int bitInByIndex = 7 - (bitIndex % 8); + this.streamBytes[byteIndex] |= (byte)(1 << bitInByIndex); + } +} +**/ diff --git a/Assets/Photon Unity Networking/Plugins/PhotonNetwork/PhotonClasses.cs.meta b/Assets/Photon Unity Networking/Plugins/PhotonNetwork/PhotonClasses.cs.meta new file mode 100644 index 0000000..94dc773 --- /dev/null +++ b/Assets/Photon Unity Networking/Plugins/PhotonNetwork/PhotonClasses.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: f40f16a0227e5c14293e269c875c0f9b +labels: +- ExitGames +- PUN +- Photon +- Networking +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} diff --git a/Assets/Photon Unity Networking/Plugins/PhotonNetwork/PhotonHandler.cs b/Assets/Photon Unity Networking/Plugins/PhotonNetwork/PhotonHandler.cs new file mode 100644 index 0000000..24d8f07 --- /dev/null +++ b/Assets/Photon Unity Networking/Plugins/PhotonNetwork/PhotonHandler.cs @@ -0,0 +1,330 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Part of: Photon Unity Networking +// +// -------------------------------------------------------------------------------------------------------------------- + +#if UNITY_5 && (!UNITY_5_0 && !UNITY_5_1 && !UNITY_5_2 && !UNITY_5_3) || UNITY_6 +#define UNITY_MIN_5_4 +#endif + +using System; +using System.Collections; +using System.Diagnostics; +using ExitGames.Client.Photon; +using UnityEngine; +using Debug = UnityEngine.Debug; +using Hashtable = ExitGames.Client.Photon.Hashtable; +using SupportClassPun = ExitGames.Client.Photon.SupportClass; + +#if UNITY_5_5_OR_NEWER +using UnityEngine.Profiling; +#endif + +/// +/// Internal Monobehaviour that allows Photon to run an Update loop. +/// +internal class PhotonHandler : MonoBehaviour +{ + public static PhotonHandler SP; + + public int updateInterval; // time [ms] between consecutive SendOutgoingCommands calls + + public int updateIntervalOnSerialize; // time [ms] between consecutive RunViewUpdate calls (sending syncs, etc) + + private int nextSendTickCount = 0; + + private int nextSendTickCountOnSerialize = 0; + + private static bool sendThreadShouldRun; + + private static Stopwatch timerToStopConnectionInBackground; + + protected internal static bool AppQuits; + + protected internal static Type PingImplementation = null; + + protected void Awake() + { + if (SP != null && SP != this && SP.gameObject != null) + { + GameObject.DestroyImmediate(SP.gameObject); + } + + SP = this; + DontDestroyOnLoad(this.gameObject); + + this.updateInterval = 1000 / PhotonNetwork.sendRate; + this.updateIntervalOnSerialize = 1000 / PhotonNetwork.sendRateOnSerialize; + + PhotonHandler.StartFallbackSendAckThread(); + } + + + #if UNITY_MIN_5_4 + + protected void Start() + { + UnityEngine.SceneManagement.SceneManager.sceneLoaded += (scene, loadingMode) => + { + PhotonNetwork.networkingPeer.NewSceneLoaded(); + PhotonNetwork.networkingPeer.SetLevelInPropsIfSynced(SceneManagerHelper.ActiveSceneName); + }; + } + + #else + + /// Called by Unity after a new level was loaded. + protected void OnLevelWasLoaded(int level) + { + PhotonNetwork.networkingPeer.NewSceneLoaded(); + PhotonNetwork.networkingPeer.SetLevelInPropsIfSynced(SceneManagerHelper.ActiveSceneName); + } + + #endif + + + /// Called by Unity when the application is closed. Disconnects. + protected void OnApplicationQuit() + { + PhotonHandler.AppQuits = true; + PhotonHandler.StopFallbackSendAckThread(); + PhotonNetwork.Disconnect(); + } + + /// + /// Called by Unity when the application gets paused (e.g. on Android when in background). + /// + /// + /// Sets a disconnect timer when PhotonNetwork.BackgroundTimeout > 0.1f. See PhotonNetwork.BackgroundTimeout. + /// + /// Some versions of Unity will give false values for pause on Android (and possibly on other platforms). + /// + /// If the app pauses. + protected void OnApplicationPause(bool pause) + { + if (PhotonNetwork.BackgroundTimeout > 0.1f) + { + if (timerToStopConnectionInBackground == null) + { + timerToStopConnectionInBackground = new Stopwatch(); + } + timerToStopConnectionInBackground.Reset(); + + if (pause) + { + timerToStopConnectionInBackground.Start(); + } + else + { + timerToStopConnectionInBackground.Stop(); + } + } + } + + /// Called by Unity when the play mode ends. Used to cleanup. + protected void OnDestroy() + { + //Debug.Log("OnDestroy on PhotonHandler."); + PhotonHandler.StopFallbackSendAckThread(); + //PhotonNetwork.Disconnect(); + } + + protected void Update() + { + if (PhotonNetwork.networkingPeer == null) + { + Debug.LogError("NetworkPeer broke!"); + return; + } + + if (PhotonNetwork.connectionStateDetailed == ClientState.PeerCreated || PhotonNetwork.connectionStateDetailed == ClientState.Disconnected || PhotonNetwork.offlineMode) + { + return; + } + + // the messageQueue might be paused. in that case a thread will send acknowledgements only. nothing else to do here. + if (!PhotonNetwork.isMessageQueueRunning) + { + return; + } + + bool doDispatch = true; + while (PhotonNetwork.isMessageQueueRunning && doDispatch) + { + // DispatchIncomingCommands() returns true of it found any command to dispatch (event, result or state change) + Profiler.BeginSample("DispatchIncomingCommands"); + doDispatch = PhotonNetwork.networkingPeer.DispatchIncomingCommands(); + Profiler.EndSample(); + } + + int currentMsSinceStart = (int)(Time.realtimeSinceStartup * 1000); // avoiding Environment.TickCount, which could be negative on long-running platforms + if (PhotonNetwork.isMessageQueueRunning && currentMsSinceStart > this.nextSendTickCountOnSerialize) + { + PhotonNetwork.networkingPeer.RunViewUpdate(); + this.nextSendTickCountOnSerialize = currentMsSinceStart + this.updateIntervalOnSerialize; + this.nextSendTickCount = 0; // immediately send when synchronization code was running + } + + currentMsSinceStart = (int)(Time.realtimeSinceStartup * 1000); + if (currentMsSinceStart > this.nextSendTickCount) + { + bool doSend = true; + while (PhotonNetwork.isMessageQueueRunning && doSend) + { + // Send all outgoing commands + Profiler.BeginSample("SendOutgoingCommands"); + doSend = PhotonNetwork.networkingPeer.SendOutgoingCommands(); + Profiler.EndSample(); + } + + this.nextSendTickCount = currentMsSinceStart + this.updateInterval; + } + } + + protected void OnJoinedRoom() + { + PhotonNetwork.networkingPeer.LoadLevelIfSynced(); + } + + protected void OnCreatedRoom() + { + PhotonNetwork.networkingPeer.SetLevelInPropsIfSynced(SceneManagerHelper.ActiveSceneName); + } + + public static void StartFallbackSendAckThread() + { + #if !UNITY_WEBGL + if (sendThreadShouldRun) + { + return; + } + + sendThreadShouldRun = true; + SupportClassPun.StartBackgroundCalls(FallbackSendAckThread); // thread will call this every 100ms until method returns false + #endif + } + + public static void StopFallbackSendAckThread() + { + #if !UNITY_WEBGL + sendThreadShouldRun = false; + #endif + } + + /// A thread which runs independent from the Update() calls. Keeps connections online while loading or in background. See PhotonNetwork.BackgroundTimeout. + public static bool FallbackSendAckThread() + { + if (sendThreadShouldRun && !PhotonNetwork.offlineMode && PhotonNetwork.networkingPeer != null) + { + // check if the client should disconnect after some seconds in background + if (timerToStopConnectionInBackground != null && PhotonNetwork.BackgroundTimeout > 0.1f) + { + if (timerToStopConnectionInBackground.ElapsedMilliseconds > PhotonNetwork.BackgroundTimeout * 1000) + { + if (PhotonNetwork.connected) + { + PhotonNetwork.Disconnect(); + } + timerToStopConnectionInBackground.Stop(); + timerToStopConnectionInBackground.Reset(); + return sendThreadShouldRun; + } + } + + if (PhotonNetwork.networkingPeer.ConnectionTime - PhotonNetwork.networkingPeer.LastSendOutgoingTime > 200) + { + PhotonNetwork.networkingPeer.SendAcksOnly(); + } + } + + return sendThreadShouldRun; + } + + + #region Photon Cloud Ping Evaluation + + + private const string PlayerPrefsKey = "PUNCloudBestRegion"; + + internal static CloudRegionCode BestRegionCodeInPreferences + { + get + { + string prefsRegionCode = PlayerPrefs.GetString(PlayerPrefsKey, ""); + if (!string.IsNullOrEmpty(prefsRegionCode)) + { + CloudRegionCode loadedRegion = Region.Parse(prefsRegionCode); + return loadedRegion; + } + + return CloudRegionCode.none; + } + set + { + if (value == CloudRegionCode.none) + { + PlayerPrefs.DeleteKey(PlayerPrefsKey); + } + else + { + PlayerPrefs.SetString(PlayerPrefsKey, value.ToString()); + } + } + } + + + internal protected static void PingAvailableRegionsAndConnectToBest() + { + SP.StartCoroutine(SP.PingAvailableRegionsCoroutine(true)); + } + + + internal IEnumerator PingAvailableRegionsCoroutine(bool connectToBest) + { + while (PhotonNetwork.networkingPeer.AvailableRegions == null) + { + if (PhotonNetwork.connectionStateDetailed != ClientState.ConnectingToNameServer && PhotonNetwork.connectionStateDetailed != ClientState.ConnectedToNameServer) + { + Debug.LogError("Call ConnectToNameServer to ping available regions."); + yield break; // break if we don't connect to the nameserver at all + } + + Debug.Log("Waiting for AvailableRegions. State: " + PhotonNetwork.connectionStateDetailed + " Server: " + PhotonNetwork.Server + " PhotonNetwork.networkingPeer.AvailableRegions " + (PhotonNetwork.networkingPeer.AvailableRegions != null)); + yield return new WaitForSeconds(0.25f); // wait until pinging finished (offline mode won't ping) + } + + if (PhotonNetwork.networkingPeer.AvailableRegions == null || PhotonNetwork.networkingPeer.AvailableRegions.Count == 0) + { + Debug.LogError("No regions available. Are you sure your appid is valid and setup?"); + yield break; // break if we don't get regions at all + } + + PhotonPingManager pingManager = new PhotonPingManager(); + foreach (Region region in PhotonNetwork.networkingPeer.AvailableRegions) + { + SP.StartCoroutine(pingManager.PingSocket(region)); + } + + while (!pingManager.Done) + { + yield return new WaitForSeconds(0.1f); // wait until pinging finished (offline mode won't ping) + } + + + Region best = pingManager.BestRegion; + PhotonHandler.BestRegionCodeInPreferences = best.Code; + + Debug.Log("Found best region: '" + best.Code + "' ping: " + best.Ping + ". Calling ConnectToRegionMaster() is: " + connectToBest); + + if (connectToBest) + { + PhotonNetwork.networkingPeer.ConnectToRegionMaster(best.Code); + } + } + + + + #endregion + +} diff --git a/Assets/Photon Unity Networking/Plugins/PhotonNetwork/PhotonHandler.cs.meta b/Assets/Photon Unity Networking/Plugins/PhotonNetwork/PhotonHandler.cs.meta new file mode 100644 index 0000000..97b4d82 --- /dev/null +++ b/Assets/Photon Unity Networking/Plugins/PhotonNetwork/PhotonHandler.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 177bddf229f8d8445a70c0652f03b7df +labels: +- ExitGames +- PUN +- Photon +- Networking +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} diff --git a/Assets/Photon Unity Networking/Plugins/PhotonNetwork/PhotonLagSimulationGui.cs b/Assets/Photon Unity Networking/Plugins/PhotonNetwork/PhotonLagSimulationGui.cs new file mode 100644 index 0000000..0a15b0a --- /dev/null +++ b/Assets/Photon Unity Networking/Plugins/PhotonNetwork/PhotonLagSimulationGui.cs @@ -0,0 +1,97 @@ +#pragma warning disable 1587 +/// \file +/// Part of the [Optional GUI](@ref optionalGui). +#pragma warning restore 1587 + + +using ExitGames.Client.Photon; +using UnityEngine; + + +/// +/// This MonoBehaviour is a basic GUI for the Photon client's network-simulation feature. +/// It can modify lag (fixed delay), jitter (random lag) and packet loss. +/// +/// \ingroup optionalGui +public class PhotonLagSimulationGui : MonoBehaviour +{ + /// Positioning rect for window. + public Rect WindowRect = new Rect(0, 100, 120, 100); + + /// Unity GUI Window ID (must be unique or will cause issues). + public int WindowId = 101; + + /// Shows or hides GUI (does not affect settings). + public bool Visible = true; + + /// The peer currently in use (to set the network simulation). + public PhotonPeer Peer { get; set; } + + public void Start() + { + this.Peer = PhotonNetwork.networkingPeer; + } + + public void OnGUI() + { + if (!this.Visible) + { + return; + } + + if (this.Peer == null) + { + this.WindowRect = GUILayout.Window(this.WindowId, this.WindowRect, this.NetSimHasNoPeerWindow, "Netw. Sim."); + } + else + { + this.WindowRect = GUILayout.Window(this.WindowId, this.WindowRect, this.NetSimWindow, "Netw. Sim."); + } + } + + private void NetSimHasNoPeerWindow(int windowId) + { + GUILayout.Label("No peer to communicate with. "); + } + + private void NetSimWindow(int windowId) + { + GUILayout.Label(string.Format("Rtt:{0,4} +/-{1,3}", this.Peer.RoundTripTime, this.Peer.RoundTripTimeVariance)); + + bool simEnabled = this.Peer.IsSimulationEnabled; + bool newSimEnabled = GUILayout.Toggle(simEnabled, "Simulate"); + if (newSimEnabled != simEnabled) + { + this.Peer.IsSimulationEnabled = newSimEnabled; + } + + float inOutLag = this.Peer.NetworkSimulationSettings.IncomingLag; + GUILayout.Label("Lag " + inOutLag); + inOutLag = GUILayout.HorizontalSlider(inOutLag, 0, 500); + + this.Peer.NetworkSimulationSettings.IncomingLag = (int)inOutLag; + this.Peer.NetworkSimulationSettings.OutgoingLag = (int)inOutLag; + + float inOutJitter = this.Peer.NetworkSimulationSettings.IncomingJitter; + GUILayout.Label("Jit " + inOutJitter); + inOutJitter = GUILayout.HorizontalSlider(inOutJitter, 0, 100); + + this.Peer.NetworkSimulationSettings.IncomingJitter = (int)inOutJitter; + this.Peer.NetworkSimulationSettings.OutgoingJitter = (int)inOutJitter; + + float loss = this.Peer.NetworkSimulationSettings.IncomingLossPercentage; + GUILayout.Label("Loss " + loss); + loss = GUILayout.HorizontalSlider(loss, 0, 10); + + this.Peer.NetworkSimulationSettings.IncomingLossPercentage = (int)loss; + this.Peer.NetworkSimulationSettings.OutgoingLossPercentage = (int)loss; + + // if anything was clicked, the height of this window is likely changed. reduce it to be layouted again next frame + if (GUI.changed) + { + this.WindowRect.height = 100; + } + + GUI.DragWindow(); + } +} \ No newline at end of file diff --git a/Assets/Photon Unity Networking/Plugins/PhotonNetwork/PhotonLagSimulationGui.cs.meta b/Assets/Photon Unity Networking/Plugins/PhotonNetwork/PhotonLagSimulationGui.cs.meta new file mode 100644 index 0000000..5a7173b --- /dev/null +++ b/Assets/Photon Unity Networking/Plugins/PhotonNetwork/PhotonLagSimulationGui.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 5867a53c8db0e6745818285bb6b6e1b9 +labels: +- ExitGames +- PUN +- Photon +- Networking +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} diff --git a/Assets/Photon Unity Networking/Plugins/PhotonNetwork/PhotonNetwork.cs b/Assets/Photon Unity Networking/Plugins/PhotonNetwork/PhotonNetwork.cs new file mode 100644 index 0000000..e296913 --- /dev/null +++ b/Assets/Photon Unity Networking/Plugins/PhotonNetwork/PhotonNetwork.cs @@ -0,0 +1,3340 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Part of: Photon Unity Networking +// +// -------------------------------------------------------------------------------------------------------------------- + + +using System.Diagnostics; +using UnityEngine; +using System; +using System.Collections.Generic; +using ExitGames.Client.Photon; +using UnityEngine.SceneManagement; +using Debug = UnityEngine.Debug; +using Hashtable = ExitGames.Client.Photon.Hashtable; + +#if UNITY_EDITOR +using UnityEditor; +using System.IO; +#endif + + +/// +/// The main class to use the PhotonNetwork plugin. +/// This class is static. +/// +/// \ingroup publicApi +public static class PhotonNetwork +{ + /// Version number of PUN. Also used in GameVersion to separate client version from each other. + public const string versionPUN = "1.85"; + + /// Version string for your this build. Can be used to separate incompatible clients. Sent during connect. + /// This is only sent when you connect so that is also the place you set it usually (e.g. in ConnectUsingSettings). + public static string gameVersion { get; set; } + + /// + /// This Monobehaviour allows Photon to run an Update loop. + /// + internal static readonly PhotonHandler photonMono; + + /// + /// Photon peer class that implements LoadBalancing in PUN. + /// Primary use is internal (by PUN itself). + /// + internal static NetworkingPeer networkingPeer; + + /// + /// The maximum number of assigned PhotonViews per player (or scene). See the [General Documentation](@ref general) topic "Limitations" on how to raise this limitation. + /// + public static readonly int MAX_VIEW_IDS = 1000; // VIEW & PLAYER LIMIT CAN BE EASILY CHANGED, SEE DOCS + + + /// Name of the PhotonServerSettings file (used to load and by PhotonEditor to save new files). + internal const string serverSettingsAssetFile = "PhotonServerSettings"; + + /// Path to the PhotonServerSettings file (used by PhotonEditor). + internal const string serverSettingsAssetPath = "Assets/Photon Unity Networking/Resources/" + PhotonNetwork.serverSettingsAssetFile + ".asset"; + + + /// Serialized server settings, written by the Setup Wizard for use in ConnectUsingSettings. + public static ServerSettings PhotonServerSettings = (ServerSettings)Resources.Load(PhotonNetwork.serverSettingsAssetFile, typeof(ServerSettings)); + + /// Currently used server address (no matter if master or game server). + public static string ServerAddress { get { return (networkingPeer != null) ? networkingPeer.ServerAddress : ""; } } + + /// Currently used Cloud Region (if any). As long as the client is not on a Master Server or Game Server, the region is not yet defined. + public static CloudRegionCode CloudRegion { get { return (networkingPeer != null && connected && Server!=ServerConnection.NameServer) ? networkingPeer.CloudRegion : CloudRegionCode.none; } } + + /// + /// False until you connected to Photon initially. True in offline mode, while connected to any server and even while switching servers. + /// + public static bool connected + { + get + { + if (offlineMode) + { + return true; + } + + if (networkingPeer == null) + { + return false; + } + + return !networkingPeer.IsInitialConnect && networkingPeer.State != ClientState.PeerCreated && networkingPeer.State != ClientState.Disconnected && networkingPeer.State != ClientState.Disconnecting && networkingPeer.State != ClientState.ConnectingToNameServer; + } + } + + /// + /// True when you called ConnectUsingSettings (or similar) until the low level connection to Photon gets established. + /// + public static bool connecting + { + get { return networkingPeer.IsInitialConnect && !offlineMode; } + } + + /// + /// A refined version of connected which is true only if your connection to the server is ready to accept operations like join, leave, etc. + /// + public static bool connectedAndReady + { + get + { + // connected property will check offlineMode and networkingPeer being null + if (!connected) + { + return false; + } + + if (offlineMode) + { + return true; + } + + switch (connectionStateDetailed) + { + case ClientState.PeerCreated: + case ClientState.Disconnected: + case ClientState.Disconnecting: + case ClientState.Authenticating: + case ClientState.ConnectingToGameserver: + case ClientState.ConnectingToMasterserver: + case ClientState.ConnectingToNameServer: + case ClientState.Joining: + return false; // we are not ready to execute any operations + } + + return true; + } + } + + /// + /// Simplified connection state + /// + public static ConnectionState connectionState + { + get + { + if (offlineMode) + { + return ConnectionState.Connected; + } + + if (networkingPeer == null) + { + return ConnectionState.Disconnected; + } + + switch (networkingPeer.PeerState) + { + case PeerStateValue.Disconnected: + return ConnectionState.Disconnected; + case PeerStateValue.Connecting: + return ConnectionState.Connecting; + case PeerStateValue.Connected: + return ConnectionState.Connected; + case PeerStateValue.Disconnecting: + return ConnectionState.Disconnecting; + case PeerStateValue.InitializingApplication: + return ConnectionState.InitializingApplication; + } + + return ConnectionState.Disconnected; + } + } + + /// + /// Detailed connection state (ignorant of PUN, so it can be "disconnected" while switching servers). + /// + /// + /// In OfflineMode, this is ClientState.Joined (after create/join) or it is ConnectedToMaster in all other cases. + /// + public static ClientState connectionStateDetailed + { + get + { + if (offlineMode) + { + return (offlineModeRoom != null) ? ClientState.Joined : ClientState.ConnectedToMaster; + } + + if (networkingPeer == null) + { + return ClientState.Disconnected; + } + + return networkingPeer.State; + } + } + + /// The server (type) this client is currently connected or connecting to. + /// Photon uses 3 different roles of servers: Name Server, Master Server and Game Server. + public static ServerConnection Server { get { return (PhotonNetwork.networkingPeer != null) ? PhotonNetwork.networkingPeer.Server : ServerConnection.NameServer; } } + + /// + /// A user's authentication values used during connect. + /// + /// + /// Set these before calling Connect if you want custom authentication. + /// These values set the userId, if and how that userId gets verified (server-side), etc.. + /// + /// If authentication fails for any values, PUN will call your implementation of OnCustomAuthenticationFailed(string debugMsg). + /// See: PhotonNetworkingMessage.OnCustomAuthenticationFailed + /// + public static AuthenticationValues AuthValues + { + get { return (networkingPeer != null) ? networkingPeer.AuthValues : null; } + set { if (networkingPeer != null) networkingPeer.AuthValues = value; } + } + + /// + /// Get the room we're currently in. Null if we aren't in any room. + /// + public static Room room + { + get + { + if (isOfflineMode) + { + return offlineModeRoom; + } + + return networkingPeer.CurrentRoom; + } + } + + /// If true, Instantiate methods will check if you are in a room and fail if you are not. + /// + /// Instantiating anything outside of a specific room is very likely to break things. + /// Turn this off only if you know what you do. + public static bool InstantiateInRoomOnly = true; + + /// + /// Network log level. Controls how verbose PUN is. + /// + public static PhotonLogLevel logLevel = PhotonLogLevel.ErrorsOnly; + + /// + /// The local PhotonPlayer. Always available and represents this player. + /// CustomProperties can be set before entering a room and will be synced as well. + /// + public static PhotonPlayer player + { + get + { + if (networkingPeer == null) + { + return null; // Surpress ExitApplication errors + } + + return networkingPeer.LocalPlayer; + } + } + + /// + /// The Master Client of the current room or null (outside of rooms). + /// + /// + /// Can be used as "authoritative" client/player to make descisions, run AI or other. + /// + /// If the current Master Client leaves the room (leave/disconnect), the server will quickly assign someone else. + /// If the current Master Client times out (closed app, lost connection, etc), messages sent to this client are + /// effectively lost for the others! A timeout can take 10 seconds in which no Master Client is active. + /// + /// Implement the method IPunCallbacks.OnMasterClientSwitched to be called when the Master Client switched. + /// + /// Use PhotonNetwork.SetMasterClient, to switch manually to some other player / client. + /// + /// With offlineMode == true, this always returns the PhotonNetwork.player. + /// + public static PhotonPlayer masterClient + { + get + { + if (offlineMode) + { + return PhotonNetwork.player; + } + + if (networkingPeer == null) + { + return null; + } + + return networkingPeer.GetPlayerWithId(networkingPeer.mMasterClientId); + } + } + + /// + /// Set to synchronize the player's nickname with everyone in the room(s) you enter. This sets PhotonNetwork.player.NickName. + /// + /// + /// The playerName is just a nickname and does not have to be unique or backed up with some account.
+ /// Set the value any time (e.g. before you connect) and it will be available to everyone you play with.
+ /// Access the names of players by: PhotonPlayer.NickName.
+ /// PhotonNetwork.otherPlayers is a list of other players - each contains the playerName the remote player set. + ///
+ public static string playerName + { + get + { + return networkingPeer.PlayerName; + } + + set + { + networkingPeer.PlayerName = value; + } + } + + /// The list of players in the current room, including the local player. + /// + /// This list is only valid, while the client is in a room. + /// It automatically gets updated when someone joins or leaves. + /// + /// This can be used to list all players in a room. + /// Each player's PhotonPlayer.customProperties are accessible (set and synchronized via + /// PhotonPlayer.SetCustomProperties). + /// + /// You can use a PhotonPlayer.TagObject to store an arbitrary object for reference. + /// That is not synchronized via the network. + /// + public static PhotonPlayer[] playerList + { + get + { + if (networkingPeer == null) + return new PhotonPlayer[0]; + + return networkingPeer.mPlayerListCopy; + } + } + + /// The list of players in the current room, excluding the local player. + /// + /// This list is only valid, while the client is in a room. + /// It automatically gets updated when someone joins or leaves. + /// + /// This can be used to list all other players in a room. + /// Each player's PhotonPlayer.customProperties are accessible (set and synchronized via + /// PhotonPlayer.SetCustomProperties). + /// + /// You can use a PhotonPlayer.TagObject to store an arbitrary object for reference. + /// That is not synchronized via the network. + /// + public static PhotonPlayer[] otherPlayers + { + get + { + if (networkingPeer == null) + return new PhotonPlayer[0]; + + return networkingPeer.mOtherPlayerListCopy; + } + } + + /// + /// Read-only list of friends, their online status and the room they are in. Null until initialized by a FindFriends call. + /// + /// + /// Do not modify this list! + /// It is internally handled by FindFriends and only available to read the values. + /// The value of FriendListAge tells you how old the data is in milliseconds. + /// + /// Don't get this list more often than useful (> 10 seconds). In best case, keep the list you fetch really short. + /// You could (e.g.) get the full list only once, then request a few updates only for friends who are online. + /// After a while (e.g. 1 minute), you can get the full list again (to update online states). + /// + public static List Friends { get; internal set; } + + /// + /// Age of friend list info (in milliseconds). It's 0 until a friend list is fetched. + /// + public static int FriendsListAge + { + get { return (networkingPeer != null) ? networkingPeer.FriendListAge : 0; } + } + + /// + /// The minimum difference that a Vector2 or Vector3(e.g. a transforms rotation) needs to change before we send it via a PhotonView's OnSerialize/ObservingComponent. + /// + /// + /// Note that this is the sqrMagnitude. E.g. to send only after a 0.01 change on the Y-axix, we use 0.01f*0.01f=0.0001f. As a remedy against float inaccuracy we use 0.000099f instead of 0.0001f. + /// + public static float precisionForVectorSynchronization = 0.000099f; + + /// + /// The minimum angle that a rotation needs to change before we send it via a PhotonView's OnSerialize/ObservingComponent. + /// + public static float precisionForQuaternionSynchronization = 1.0f; + + /// + /// The minimum difference between floats before we send it via a PhotonView's OnSerialize/ObservingComponent. + /// + public static float precisionForFloatSynchronization = 0.01f; + + /// + /// While enabled, the MonoBehaviours on which we call RPCs are cached, avoiding costly GetComponents() calls. + /// + /// + /// RPCs are called on the MonoBehaviours of a target PhotonView. Those have to be found via GetComponents. + /// + /// When set this to true, the list of MonoBehaviours gets cached in each PhotonView. + /// You can use photonView.RefreshRpcMonoBehaviourCache() to manually refresh a PhotonView's + /// list of MonoBehaviours on demand (when a new MonoBehaviour gets added to a networked GameObject, e.g.). + /// + public static bool UseRpcMonoBehaviourCache; + + /// + /// While enabled (true), Instantiate uses PhotonNetwork.PrefabCache to keep game objects in memory (improving instantiation of the same prefab). + /// + /// + /// Setting UsePrefabCache to false during runtime will not clear PrefabCache but will ignore it right away. + /// You could clean and modify the cache yourself. Read its comments. + /// + public static bool UsePrefabCache = true; + + /// + /// An Object Pool can be used to keep and reuse instantiated object instances. It replaced Unity's default Instantiate and Destroy methods. + /// + /// + /// To use a GameObject pool, implement IPunPrefabPool and assign it here. + /// Prefabs are identified by name. + /// + public static IPunPrefabPool PrefabPool { get { return networkingPeer.ObjectPool; } set { networkingPeer.ObjectPool = value; }} + + /// + /// Keeps references to GameObjects for frequent instantiation (out of memory instead of loading the Resources). + /// + /// + /// You should be able to modify the cache anytime you like, except while Instantiate is used. Best do it only in the main-Thread. + /// + public static Dictionary PrefabCache = new Dictionary(); + + /// + /// If not null, this is the (exclusive) list of GameObjects that get called by PUN SendMonoMessage(). + /// + /// + /// For all callbacks defined in PhotonNetworkingMessage, PUN will use SendMonoMessage and + /// call FindObjectsOfType() to find all scripts and GameObjects that might want a callback by PUN. + /// + /// PUN callbacks are not very frequent (in-game, property updates are most frequent) but + /// FindObjectsOfType is time consuming and with a large number of GameObjects, performance might + /// suffer. + /// + /// Optionally, SendMonoMessageTargets can be used to supply a list of target GameObjects. This + /// skips the FindObjectsOfType() but any GameObject that needs callbacks will have to Add itself + /// to this list. + /// + /// If null, the default behaviour is to do a SendMessage on each GameObject with a MonoBehaviour. + /// + public static HashSet SendMonoMessageTargets; + + + /// + /// Defines which classes can contain PUN Callback implementations. + /// + /// + /// This provides the option to optimize your runtime for speed.
+ /// The more specific this Type is, the fewer classes will be checked with reflection for callback methods. + ///
+ public static Type SendMonoMessageTargetType = typeof(MonoBehaviour); + + /// + /// Can be used to skip starting RPCs as Coroutine, which can be a performance issue. + /// + public static bool StartRpcsAsCoroutine = true; + + /// + /// Offline mode can be set to re-use your multiplayer code in singleplayer game modes. + /// When this is on PhotonNetwork will not create any connections and there is near to + /// no overhead. Mostly usefull for reusing RPC's and PhotonNetwork.Instantiate + /// + public static bool offlineMode + { + get + { + return isOfflineMode; + } + + set + { + if (value == isOfflineMode) + { + return; + } + + if (value && connected) + { + Debug.LogError("Can't start OFFLINE mode while connected!"); + return; + } + + if (networkingPeer.PeerState != PeerStateValue.Disconnected) + { + networkingPeer.Disconnect(); // Cleanup (also calls OnLeftRoom to reset stuff) + } + isOfflineMode = value; + if (isOfflineMode) + { + networkingPeer.ChangeLocalID(-1); + NetworkingPeer.SendMonoMessage(PhotonNetworkingMessage.OnConnectedToMaster); + } + else + { + offlineModeRoom = null; + networkingPeer.ChangeLocalID(-1); + } + } + } + + private static bool isOfflineMode = false; + private static Room offlineModeRoom = null; + + + /// Only used in Unity Networking. In PUN, set the number of players in PhotonNetwork.CreateRoom. + [Obsolete("Used for compatibility with Unity networking only.")] + public static int maxConnections; + + /// Defines if all clients in a room should load the same level as the Master Client (if that used PhotonNetwork.LoadLevel). + /// + /// To synchronize the loaded level, the Master Client should use PhotonNetwork.LoadLevel. + /// All clients will load the new scene when they get the update or when they join. + /// + /// Internally, a Custom Room Property is set for the loaded scene. When a client reads that + /// and is not in the same scene yet, it will immediately pause the Message Queue + /// (PhotonNetwork.isMessageQueueRunning = false) and load. When the scene finished loading, + /// PUN will automatically re-enable the Message Queue. + /// + public static bool automaticallySyncScene + { + get + { + return _mAutomaticallySyncScene; + } + set + { + _mAutomaticallySyncScene = value; + if (_mAutomaticallySyncScene && room != null) + { + networkingPeer.LoadLevelIfSynced(); + } + } + } + + private static bool _mAutomaticallySyncScene = false; + + /// + /// This setting defines per room, if network-instantiated GameObjects (with PhotonView) get cleaned up when the creator of it leaves. + /// + /// + /// This setting is done per room. It can't be changed in the room and it will override the settings of individual clients. + /// + /// If room.AutoCleanUp is enabled in a room, the PUN clients will destroy a player's GameObjects on leave. + /// This includes GameObjects manually instantiated (via RPCs, e.g.). + /// When enabled, the server will clean RPCs, instantiated GameObjects and PhotonViews of the leaving player, too. and + /// Players who join after someone left, won't get the events of that player anymore. + /// + /// Under the hood, this setting is stored as a Custom Room Property. + /// Enabled by default. + /// + public static bool autoCleanUpPlayerObjects + { + get + { + return m_autoCleanUpPlayerObjects; + } + set + { + if (room != null) + Debug.LogError("Setting autoCleanUpPlayerObjects while in a room is not supported."); + else m_autoCleanUpPlayerObjects = value; + } + } + + private static bool m_autoCleanUpPlayerObjects = true; + + /// + /// Set in PhotonServerSettings asset. Defines if the PhotonNetwork should join the "lobby" when connected to the Master server. + /// + /// + /// If this is false, OnConnectedToMaster() will be called when connection to the Master is available. + /// OnJoinedLobby() will NOT be called if this is false. + /// + /// Enabled by default. + /// + /// The room listing will not become available. + /// Rooms can be created and joined (randomly) without joining the lobby (and getting sent the room list). + /// + public static bool autoJoinLobby + { + get + { + return PhotonNetwork.PhotonServerSettings.JoinLobby; + } + set + { + PhotonNetwork.PhotonServerSettings.JoinLobby = value; + } + } + + + /// + /// Set in PhotonServerSettings asset. Enable to get a list of active lobbies from the Master Server. + /// + /// + /// Lobby Statistics can be useful if a game uses multiple lobbies and you want + /// to show activity of each to players. + /// + /// This value is stored in PhotonServerSettings. + /// + /// PhotonNetwork.LobbyStatistics is updated when you connect to the Master Server. + /// There is also a callback PunBehaviour. + /// + public static bool EnableLobbyStatistics + { + get + { + return PhotonNetwork.PhotonServerSettings.EnableLobbyStatistics; + } + set + { + PhotonNetwork.PhotonServerSettings.EnableLobbyStatistics = value; + } + } + + /// + /// If turned on, the Master Server will provide information about active lobbies for this application. + /// + /// + /// Lobby Statistics can be useful if a game uses multiple lobbies and you want + /// to show activity of each to players. Per lobby, you get: name, type, room- and player-count. + /// + /// PhotonNetwork.LobbyStatistics is updated when you connect to the Master Server. + /// There is also a callback PunBehaviour.OnLobbyStatisticsUpdate, which you should implement + /// to update your UI (e.g.). + /// + /// Lobby Statistics are not turned on by default. + /// Enable them in the PhotonServerSettings file of the project. + /// + public static List LobbyStatistics + { + get { return PhotonNetwork.networkingPeer.LobbyStatistics; } + // only available to reset the state conveniently. done by state updates of PUN + private set { PhotonNetwork.networkingPeer.LobbyStatistics = value; } + } + + + /// True while this client is in a lobby. + /// + /// Implement IPunCallbacks.OnReceivedRoomListUpdate() for a notification when the list of rooms + /// becomes available or updated. + /// + /// You are automatically leaving any lobby when you join a room! + /// Lobbies only exist on the Master Server (whereas rooms are handled by Game Servers). + /// + public static bool insideLobby + { + get + { + return networkingPeer.insideLobby; + } + } + + /// + /// The lobby that will be used when PUN joins a lobby or creates a game. + /// + /// + /// The default lobby uses an empty string as name. + /// PUN will enter a lobby on the Master Server if autoJoinLobby is set to true. + /// So when you connect or leave a room, PUN automatically gets you into a lobby again. + /// + /// Check PhotonNetwork.insideLobby if the client is in a lobby. + /// (@ref masterServerAndLobby) + /// + public static TypedLobby lobby + { + get { return networkingPeer.lobby; } + set { networkingPeer.lobby = value; } + } + + /// + /// Defines how many times per second PhotonNetwork should send a package. If you change + /// this, do not forget to also change 'sendRateOnSerialize'. + /// + /// + /// Less packages are less overhead but more delay. + /// Setting the sendRate to 50 will create up to 50 packages per second (which is a lot!). + /// Keep your target platform in mind: mobile networks are slower and less reliable. + /// + public static int sendRate + { + get + { + return 1000 / sendInterval; + } + + set + { + sendInterval = 1000 / value; + if (photonMono != null) + { + photonMono.updateInterval = sendInterval; + } + + if (value < sendRateOnSerialize) + { + // sendRateOnSerialize needs to be <= sendRate + sendRateOnSerialize = value; + } + } + } + + /// + /// Defines how many times per second OnPhotonSerialize should be called on PhotonViews. + /// + /// + /// Choose this value in relation to PhotonNetwork.sendRate. OnPhotonSerialize will create updates and messages to be sent.
+ /// A lower rate takes up less performance but will cause more lag. + ///
+ public static int sendRateOnSerialize + { + get + { + return 1000 / sendIntervalOnSerialize; + } + + set + { + if (value > sendRate) + { + Debug.LogError("Error: Can not set the OnSerialize rate higher than the overall SendRate."); + value = sendRate; + } + + sendIntervalOnSerialize = 1000 / value; + if (photonMono != null) + { + photonMono.updateIntervalOnSerialize = sendIntervalOnSerialize; + } + } + } + + private static int sendInterval = 50; // in miliseconds. + + private static int sendIntervalOnSerialize = 100; // in miliseconds. I.e. 100 = 100ms which makes 10 times/second + + /// + /// Can be used to pause dispatching of incoming evtents (RPCs, Instantiates and anything else incoming). + /// + /// + /// While IsMessageQueueRunning == false, the OnPhotonSerializeView calls are not done and nothing is sent by + /// a client. Also, incoming messages will be queued until you re-activate the message queue. + /// + /// This can be useful if you first want to load a level, then go on receiving data of PhotonViews and RPCs. + /// The client will go on receiving and sending acknowledgements for incoming packages and your RPCs/Events. + /// This adds "lag" and can cause issues when the pause is longer, as all incoming messages are just queued. + /// + public static bool isMessageQueueRunning + { + get + { + return m_isMessageQueueRunning; + } + + set + { + if (value) PhotonHandler.StartFallbackSendAckThread(); + networkingPeer.IsSendingOnlyAcks = !value; + m_isMessageQueueRunning = value; + } + } + + /// Backup for property isMessageQueueRunning. + private static bool m_isMessageQueueRunning = true; + + /// + /// Used once per dispatch to limit unreliable commands per channel (so after a pause, many channels can still cause a lot of unreliable commands) + /// + public static int unreliableCommandsLimit + { + get + { + return networkingPeer.LimitOfUnreliableCommands; + } + + set + { + networkingPeer.LimitOfUnreliableCommands = value; + } + } + + /// + /// Photon network time, synched with the server. + /// + /// + /// v1.55
+ /// This time value depends on the server's Environment.TickCount. It is different per server + /// but inside a Room, all clients should have the same value (Rooms are on one server only).
+ /// This is not a DateTime!
+ /// + /// Use this value with care:
+ /// It can start with any positive value.
+ /// It will "wrap around" from 4294967.295 to 0! + ///
+ public static double time + { + get + { + uint u = (uint)ServerTimestamp; + double t = u; + return t / 1000; + } + } + + /// + /// The current server's millisecond timestamp. + /// + /// + /// This can be useful to sync actions and events on all clients in one room. + /// The timestamp is based on the server's Environment.TickCount. + /// + /// It will overflow from a positive to a negative value every so often, so + /// be careful to use only time-differences to check the time delta when things + /// happen. + /// + /// This is the basis for PhotonNetwork.time. + /// + public static int ServerTimestamp + { + get + { + if (offlineMode) + { + if (UsePreciseTimer && startupStopwatch != null && startupStopwatch.IsRunning) + { + return (int)startupStopwatch.ElapsedMilliseconds; + } + return Environment.TickCount; + } + + return networkingPeer.ServerTimeInMilliSeconds; + } + } + + /// If true, PUN will use a Stopwatch to measure time since start/connect. This is more precise than the Environment.TickCount used by default. + private static bool UsePreciseTimer = false; + static Stopwatch startupStopwatch; + + /// + /// Defines how many seconds PUN keeps the connection, after Unity's OnApplicationPause(true) call. Default: 60 seconds. + /// + /// + /// It's best practice to disconnect inactive apps/connections after a while but to also allow users to take calls, etc.. + /// We think a reasonable backgroung timeout is 60 seconds. + /// + /// To handle the timeout, implement: OnDisconnectedFromPhoton(), as usual. + /// Your application will "notice" the background disconnect when it becomes active again (running the Update() loop). + /// + /// If you need to separate this case from others, you need to track if the app was in the background + /// (there is no special callback by PUN). + /// + /// A value below 0.1 seconds will disable this timeout (careful: connections can be kept indefinitely). + /// + /// + /// Info: + /// PUN is running a "fallback thread" to send ACKs to the server, even when Unity is not calling Update() regularly. + /// This helps keeping the connection while loading scenes and assets and when the app is in the background. + /// + /// Note: + /// Some platforms (e.g. iOS) don't allow to keep a connection while the app is in background. + /// In those cases, this value does not change anything, the app immediately loses connection in background. + /// + /// Unity's OnApplicationPause() callback is broken in some exports (Android) of some Unity versions. + /// Make sure OnApplicationPause() gets the callbacks you'd expect on the platform you target! + /// Check PhotonHandler.OnApplicationPause(bool pause), to see the implementation. + /// + public static float BackgroundTimeout = 60.0f; + + /// + /// Are we the master client? + /// + public static bool isMasterClient + { + get + { + if (offlineMode) + { + return true; + } + else + { + return networkingPeer.mMasterClientId == player.ID; + } + } + } + + /// Is true while being in a room (connectionStateDetailed == ClientState.Joined). + /// + /// Many actions can only be executed in a room, like Instantiate or Leave, etc. + /// You can join a room in offline mode, too. + /// + public static bool inRoom + { + get + { + // in offline mode, you can be in a room too and connectionStateDetailed then returns Joined like on online mode! + return connectionStateDetailed == ClientState.Joined; + } + } + + /// + /// True if we are in a room (client) and NOT the room's masterclient + /// + public static bool isNonMasterClientInRoom + { + get + { + return !isMasterClient && room != null; + } + } + + /// + /// The count of players currently looking for a room (available on MasterServer in 5sec intervals). + /// + public static int countOfPlayersOnMaster + { + get + { + return networkingPeer.PlayersOnMasterCount; + } + } + + /// + /// Count of users currently playing your app in some room (sent every 5sec by Master Server). Use playerList.Count to get the count of players in the room you're in! + /// + public static int countOfPlayersInRooms + { + get + { + return networkingPeer.PlayersInRoomsCount; + } + } + + /// + /// The count of players currently using this application (available on MasterServer in 5sec intervals). + /// + public static int countOfPlayers + { + get + { + return networkingPeer.PlayersInRoomsCount + networkingPeer.PlayersOnMasterCount; + } + } + + /// + /// The count of rooms currently in use (available on MasterServer in 5sec intervals). + /// + /// + /// While inside the lobby you can also check the count of listed rooms as: PhotonNetwork.GetRoomList().Length. + /// Since PUN v1.25 this is only based on the statistic event Photon sends (counting all rooms). + /// + public static int countOfRooms + { + get + { + return networkingPeer.RoomsCount; + } + } + + /// + /// Enables or disables the collection of statistics about this client's traffic. + /// + /// + /// If you encounter issues with clients, the traffic stats are a good starting point to find solutions. + /// Only with enabled stats, you can use GetVitalStats + /// + public static bool NetworkStatisticsEnabled + { + get + { + return networkingPeer.TrafficStatsEnabled; + } + + set + { + networkingPeer.TrafficStatsEnabled = value; + } + } + + /// + /// Count of commands that got repeated (due to local repeat-timing before an ACK was received). + /// + /// + /// If this value increases a lot, there is a good chance that a timeout disconnect will happen due to bad conditions. + /// + public static int ResentReliableCommands + { + get { return networkingPeer.ResentReliableCommands; } + } + + /// Crc checks can be useful to detect and avoid issues with broken datagrams. Can be enabled while not connected. + public static bool CrcCheckEnabled + { + get { return networkingPeer.CrcEnabled; } + set + { + if (!connected && !connecting) + { + networkingPeer.CrcEnabled = value; + } + else + { + Debug.Log("Can't change CrcCheckEnabled while being connected. CrcCheckEnabled stays " + networkingPeer.CrcEnabled); + } + } + } + + /// If CrcCheckEnabled, this counts the incoming packages that don't have a valid CRC checksum and got rejected. + public static int PacketLossByCrcCheck + { + get { return networkingPeer.PacketLossByCrc; } + } + + /// Defines the number of times a reliable message can be resent before not getting an ACK for it will trigger a disconnect. Default: 5. + /// Less resends mean quicker disconnects, while more can lead to much more lag without helping. Min: 3. Max: 10. + public static int MaxResendsBeforeDisconnect + { + get { return networkingPeer.SentCountAllowance; } + set + { + if (value < 3) value = 3; + if (value > 10) value = 10; + networkingPeer.SentCountAllowance = value; + } + } + + /// In case of network loss, reliable messages can be repeated quickly up to 3 times. + /// + /// When reliable messages get lost more than once, subsequent repeats are delayed a bit + /// to allow the network to recover.
+ /// With this option, the repeats 2 and 3 can be sped up. This can help avoid timeouts but + /// also it increases the speed in which gaps are closed.
+ /// When you set this, increase PhotonNetwork.MaxResendsBeforeDisconnect to 6 or 7. + ///
+ public static int QuickResends + { + get { return networkingPeer.QuickResendAttempts; } + set + { + if (value < 0) value = 0; + if (value > 3) value = 3; + networkingPeer.QuickResendAttempts = (byte)value; + } + } + + /// + /// Defines the delegate usable in OnEventCall. + /// + /// Any eventCode < 200 will be forwarded to your delegate(s). + /// The code assigend to the incoming event. + /// The content the sender put into the event. + /// The ID of the player who sent the event. It might be 0, if the "room" sent the event. + public delegate void EventCallback(byte eventCode, object content, int senderId); + + /// Register your RaiseEvent handling methods here by using "+=". + /// Any eventCode < 200 will be forwarded to your delegate(s). + /// + public static EventCallback OnEventCall; + + + internal static int lastUsedViewSubId = 0; // each player only needs to remember it's own (!) last used subId to speed up assignment + internal static int lastUsedViewSubIdStatic = 0; // per room, the master is able to instantiate GOs. the subId for this must be unique too + internal static List manuallyAllocatedViewIds = new List(); + + /// + /// Static constructor used for basic setup. + /// + static PhotonNetwork() + { + #if UNITY_EDITOR + if (PhotonServerSettings == null) + { + // create PhotonServerSettings + CreateSettings(); + } + + if (!EditorApplication.isPlaying && !EditorApplication.isPlayingOrWillChangePlaymode) + { + //Debug.Log(string.Format("PhotonNetwork.ctor() Not playing {0} {1}", UnityEditor.EditorApplication.isPlaying, UnityEditor.EditorApplication.isPlayingOrWillChangePlaymode)); + return; + } + + // This can happen when you recompile a script IN play made + // This helps to surpress some errors, but will not fix breaking + PhotonHandler[] photonHandlers = GameObject.FindObjectsOfType(typeof(PhotonHandler)) as PhotonHandler[]; + if (photonHandlers != null && photonHandlers.Length > 0) + { + Debug.LogWarning("Unity recompiled. Connection gets closed and replaced. You can connect as 'new' client."); + foreach (PhotonHandler photonHandler in photonHandlers) + { + //Debug.Log("Handler: " + photonHandler + " photonHandler.gameObject: " + photonHandler.gameObject); + photonHandler.gameObject.hideFlags = 0; + GameObject.DestroyImmediate(photonHandler.gameObject); + Component.DestroyImmediate(photonHandler); + } + } + #endif + + if (PhotonServerSettings != null) + { + Application.runInBackground = PhotonServerSettings.RunInBackground; + } + + // Set up a MonoBehaviour to run Photon, and hide it + GameObject photonGO = new GameObject(); + photonMono = (PhotonHandler)photonGO.AddComponent(); + photonGO.name = "PhotonMono"; + photonGO.hideFlags = HideFlags.HideInHierarchy; + + + // Set up the NetworkingPeer and use protocol of PhotonServerSettings + ConnectionProtocol protocol = PhotonNetwork.PhotonServerSettings.Protocol; + networkingPeer = new NetworkingPeer(string.Empty, protocol); + networkingPeer.QuickResendAttempts = 2; + networkingPeer.SentCountAllowance = 7; + + + #if UNITY_XBOXONE + networkingPeer.AuthMode = AuthModeOption.AuthOnceWss; + networkingPeer.EncryptionMode = EncryptionMode.DatagramEncryption; + #endif + + if (UsePreciseTimer) + { + Debug.Log("Using Stopwatch as precision timer for PUN."); + startupStopwatch = new Stopwatch(); + startupStopwatch.Start(); + networkingPeer.LocalMsTimestampDelegate = () => (int)startupStopwatch.ElapsedMilliseconds; + } + + // Local player + CustomTypes.Register(); + } + + /// + /// While offline, the network protocol can be switched (which affects the ports you can use to connect). + /// + /// + /// When you switch the protocol, make sure to also switch the port for the master server. Default ports are: + /// TCP: 4530 + /// UDP: 5055 + /// + /// This could look like this:
+ /// Connect(serverAddress, , appID, gameVersion) + /// + /// Or when you use ConnectUsingSettings(), the PORT in the settings can be switched like so:
+ /// PhotonNetwork.PhotonServerSettings.ServerPort = 4530; + /// + /// The current protocol can be read this way:
+ /// PhotonNetwork.networkingPeer.UsedProtocol + /// + /// This does not work with the native socket plugin of PUN+ on mobile! + ///
+ /// Network protocol to use as low level connection. UDP is default. TCP is not available on all platforms (see remarks). + public static void SwitchToProtocol(ConnectionProtocol cp) + { + // Debug.Log("SwitchToProtocol: " + cp + " PhotonNetwork.connected: " + PhotonNetwork.connected); + networkingPeer.TransportProtocol = cp; + } + + + /// Connect to Photon as configured in the editor (saved in PhotonServerSettings file). + /// + /// This method will disable offlineMode (which won't destroy any instantiated GOs) and it + /// will set isMessageQueueRunning to true. + /// + /// Your server configuration is created by the PUN Wizard and contains the AppId and + /// region for Photon Cloud games and the server address if you host Photon yourself. + /// These settings usually don't change often. + /// + /// To ignore the config file and connect anywhere call: PhotonNetwork.ConnectToMaster. + /// + /// To connect to the Photon Cloud, a valid AppId must be in the settings file (shown in the Photon Cloud Dashboard). + /// https://www.photonengine.com/dashboard + /// + /// Connecting to the Photon Cloud might fail due to: + /// - Invalid AppId (calls: OnFailedToConnectToPhoton(). check exact AppId value) + /// - Network issues (calls: OnFailedToConnectToPhoton()) + /// - Invalid region (calls: OnConnectionFail() with DisconnectCause.InvalidRegion) + /// - Subscription CCU limit reached (calls: OnConnectionFail() with DisconnectCause.MaxCcuReached. also calls: OnPhotonMaxCccuReached()) + /// + /// More about the connection limitations: + /// http://doc.exitgames.com/en/pun + /// + /// This client's version number. Users are separated from each other by gameversion (which allows you to make breaking changes). + public static bool ConnectUsingSettings(string gameVersion) + { + if (networkingPeer.PeerState != PeerStateValue.Disconnected) + { + Debug.LogWarning("ConnectUsingSettings() failed. Can only connect while in state 'Disconnected'. Current state: " + networkingPeer.PeerState); + return false; + } + if (PhotonServerSettings == null) + { + Debug.LogError("Can't connect: Loading settings failed. ServerSettings asset must be in any 'Resources' folder as: " + serverSettingsAssetFile); + return false; + } + if (PhotonServerSettings.HostType == ServerSettings.HostingOption.NotSet) + { + Debug.LogError("You did not select a Hosting Type in your PhotonServerSettings. Please set it up or don't use ConnectUsingSettings()."); + return false; + } + + // only apply Settings if logLevel is default ( see ServerSettings.cs), else it means it's been set programmatically + if (PhotonNetwork.logLevel == PhotonLogLevel.ErrorsOnly) + { + PhotonNetwork.logLevel = PhotonServerSettings.PunLogging; + } + + // only apply Settings if logLevel is default ( see ServerSettings.cs), else it means it's been set programmatically + if (PhotonNetwork.networkingPeer.DebugOut == DebugLevel.ERROR) + { + PhotonNetwork.networkingPeer.DebugOut = PhotonServerSettings.NetworkLogging; + } + + + SwitchToProtocol(PhotonServerSettings.Protocol); + networkingPeer.SetApp(PhotonServerSettings.AppID, gameVersion); + + if (PhotonServerSettings.HostType == ServerSettings.HostingOption.OfflineMode) + { + offlineMode = true; + return true; + } + + if (offlineMode) + { + // someone can set offlineMode in code and then call ConnectUsingSettings() with non-offline settings. Warning for that case: + Debug.LogWarning("ConnectUsingSettings() disabled the offline mode. No longer offline."); + } + + offlineMode = false; // Cleanup offline mode + isMessageQueueRunning = true; + networkingPeer.IsInitialConnect = true; + + if (PhotonServerSettings.HostType == ServerSettings.HostingOption.SelfHosted) + { + networkingPeer.IsUsingNameServer = false; + networkingPeer.MasterServerAddress = (PhotonServerSettings.ServerPort == 0) ? PhotonServerSettings.ServerAddress : PhotonServerSettings.ServerAddress + ":" + PhotonServerSettings.ServerPort; + + return networkingPeer.Connect(networkingPeer.MasterServerAddress, ServerConnection.MasterServer); + } + + if (PhotonServerSettings.HostType == ServerSettings.HostingOption.BestRegion) + { + return ConnectToBestCloudServer(gameVersion); + } + + return networkingPeer.ConnectToRegionMaster(PhotonServerSettings.PreferredRegion); + } + + /// Connect to a Photon Master Server by address, port, appID and game(client) version. + /// + /// To connect to the Photon Cloud, a valid AppId must be in the settings file (shown in the Photon Cloud Dashboard). + /// https://www.photonengine.com/dashboard + /// + /// Connecting to the Photon Cloud might fail due to: + /// - Invalid AppId (calls: OnFailedToConnectToPhoton(). check exact AppId value) + /// - Network issues (calls: OnFailedToConnectToPhoton()) + /// - Invalid region (calls: OnConnectionFail() with DisconnectCause.InvalidRegion) + /// - Subscription CCU limit reached (calls: OnConnectionFail() with DisconnectCause.MaxCcuReached. also calls: OnPhotonMaxCccuReached()) + /// + /// More about the connection limitations: + /// http://doc.exitgames.com/en/pun + /// + /// The server's address (either your own or Photon Cloud address). + /// The server's port to connect to. + /// Your application ID (Photon Cloud provides you with a GUID for your game). + /// This client's version number. Users are separated by gameversion (which allows you to make breaking changes). + public static bool ConnectToMaster(string masterServerAddress, int port, string appID, string gameVersion) + { + if (networkingPeer.PeerState != PeerStateValue.Disconnected) + { + Debug.LogWarning("ConnectToMaster() failed. Can only connect while in state 'Disconnected'. Current state: " + networkingPeer.PeerState); + return false; + } + + if (offlineMode) + { + offlineMode = false; // Cleanup offline mode + Debug.LogWarning("ConnectToMaster() disabled the offline mode. No longer offline."); + } + + if (!isMessageQueueRunning) + { + isMessageQueueRunning = true; + Debug.LogWarning("ConnectToMaster() enabled isMessageQueueRunning. Needs to be able to dispatch incoming messages."); + } + + networkingPeer.SetApp(appID, gameVersion); + networkingPeer.IsUsingNameServer = false; + networkingPeer.IsInitialConnect = true; + networkingPeer.MasterServerAddress = (port == 0) ? masterServerAddress : masterServerAddress + ":" + port; + + return networkingPeer.Connect(networkingPeer.MasterServerAddress, ServerConnection.MasterServer); + } + + /// Can be used to reconnect to the master server after a disconnect. + /// + /// After losing connection, you can use this to connect a client to the region Master Server again. + /// Cache the room name you're in and use ReJoin(roomname) to return to a game. + /// Common use case: Press the Lock Button on a iOS device and you get disconnected immediately. + /// + public static bool Reconnect() + { + if (string.IsNullOrEmpty(networkingPeer.MasterServerAddress)) + { + Debug.LogWarning("Reconnect() failed. It seems the client wasn't connected before?! Current state: " + networkingPeer.PeerState); + return false; + } + + if (networkingPeer.PeerState != PeerStateValue.Disconnected) + { + Debug.LogWarning("Reconnect() failed. Can only connect while in state 'Disconnected'. Current state: " + networkingPeer.PeerState); + return false; + } + + if (offlineMode) + { + offlineMode = false; // Cleanup offline mode + Debug.LogWarning("Reconnect() disabled the offline mode. No longer offline."); + } + + if (!isMessageQueueRunning) + { + isMessageQueueRunning = true; + Debug.LogWarning("Reconnect() enabled isMessageQueueRunning. Needs to be able to dispatch incoming messages."); + } + + networkingPeer.IsUsingNameServer = false; + networkingPeer.IsInitialConnect = false; + return networkingPeer.ReconnectToMaster(); + } + + + /// When the client lost connection during gameplay, this method attempts to reconnect and rejoin the room. + /// + /// This method re-connects directly to the game server which was hosting the room PUN was in before. + /// If the room was shut down in the meantime, PUN will call OnPhotonJoinRoomFailed and return this client to the Master Server. + /// + /// Check the return value, if this client will attempt a reconnect and rejoin (if the conditions are met). + /// If ReconnectAndRejoin returns false, you can still attempt a Reconnect and ReJoin. + /// + /// Similar to PhotonNetwork.ReJoin, this requires you to use unique IDs per player (the UserID). + /// + /// False, if there is no known room or game server to return to. Then, this client does not attempt the ReconnectAndRejoin. + public static bool ReconnectAndRejoin() + { + if (networkingPeer.PeerState != PeerStateValue.Disconnected) + { + Debug.LogWarning("ReconnectAndRejoin() failed. Can only connect while in state 'Disconnected'. Current state: " + networkingPeer.PeerState); + return false; + } + if (offlineMode) + { + offlineMode = false; // Cleanup offline mode + Debug.LogWarning("ReconnectAndRejoin() disabled the offline mode. No longer offline."); + } + + if (string.IsNullOrEmpty(networkingPeer.GameServerAddress)) + { + Debug.LogWarning("ReconnectAndRejoin() failed. It seems the client wasn't connected to a game server before (no address)."); + return false; + } + if (networkingPeer.enterRoomParamsCache == null) + { + Debug.LogWarning("ReconnectAndRejoin() failed. It seems the client doesn't have any previous room to re-join."); + return false; + } + + if (!isMessageQueueRunning) + { + isMessageQueueRunning = true; + Debug.LogWarning("ReconnectAndRejoin() enabled isMessageQueueRunning. Needs to be able to dispatch incoming messages."); + } + + networkingPeer.IsUsingNameServer = false; + networkingPeer.IsInitialConnect = false; + return networkingPeer.ReconnectAndRejoin(); + } + + + /// + /// Connect to the Photon Cloud region with the lowest ping (on platforms that support Unity's Ping). + /// + /// + /// Will save the result of pinging all cloud servers in PlayerPrefs. Calling this the first time can take +-2 seconds. + /// The ping result can be overridden via PhotonNetwork.OverrideBestCloudServer(..) + /// This call can take up to 2 seconds if it is the first time you are using this, all cloud servers will be pinged to check for the best region. + /// + /// The PUN Setup Wizard stores your appID in a settings file and applies a server address/port. + /// To connect to the Photon Cloud, a valid AppId must be in the settings file (shown in the Photon Cloud Dashboard). + /// https://www.photonengine.com/dashboard + /// + /// Connecting to the Photon Cloud might fail due to: + /// - Invalid AppId (calls: OnFailedToConnectToPhoton(). check exact AppId value) + /// - Network issues (calls: OnFailedToConnectToPhoton()) + /// - Invalid region (calls: OnConnectionFail() with DisconnectCause.InvalidRegion) + /// - Subscription CCU limit reached (calls: OnConnectionFail() with DisconnectCause.MaxCcuReached. also calls: OnPhotonMaxCccuReached()) + /// + /// More about the connection limitations: + /// http://doc.exitgames.com/en/pun + /// + /// This client's version number. Users are separated from each other by gameversion (which allows you to make breaking changes). + /// If this client is going to connect to cloud server based on ping. Even if true, this does not guarantee a connection but the attempt is being made. + public static bool ConnectToBestCloudServer(string gameVersion) + { + if (networkingPeer.PeerState != PeerStateValue.Disconnected) + { + Debug.LogWarning("ConnectToBestCloudServer() failed. Can only connect while in state 'Disconnected'. Current state: " + networkingPeer.PeerState); + return false; + } + + if (PhotonServerSettings == null) + { + Debug.LogError("Can't connect: Loading settings failed. ServerSettings asset must be in any 'Resources' folder as: " + PhotonNetwork.serverSettingsAssetFile); + return false; + } + + if (PhotonServerSettings.HostType == ServerSettings.HostingOption.OfflineMode) + { + return PhotonNetwork.ConnectUsingSettings(gameVersion); + } + + networkingPeer.IsInitialConnect = true; + networkingPeer.SetApp(PhotonServerSettings.AppID, gameVersion); + + CloudRegionCode bestFromPrefs = PhotonHandler.BestRegionCodeInPreferences; + if (bestFromPrefs != CloudRegionCode.none) + { + Debug.Log("Best region found in PlayerPrefs. Connecting to: " + bestFromPrefs); + return networkingPeer.ConnectToRegionMaster(bestFromPrefs); + } + + bool couldConnect = PhotonNetwork.networkingPeer.ConnectToNameServer(); + return couldConnect; + } + + + /// + /// Connects to the Photon Cloud region of choice. + /// + public static bool ConnectToRegion(CloudRegionCode region, string gameVersion) + { + if (networkingPeer.PeerState != PeerStateValue.Disconnected) + { + Debug.LogWarning("ConnectToRegion() failed. Can only connect while in state 'Disconnected'. Current state: " + networkingPeer.PeerState); + return false; + } + + if (PhotonServerSettings == null) + { + Debug.LogError("Can't connect: ServerSettings asset must be in any 'Resources' folder as: " + PhotonNetwork.serverSettingsAssetFile); + return false; + } + + if (PhotonServerSettings.HostType == ServerSettings.HostingOption.OfflineMode) + { + return PhotonNetwork.ConnectUsingSettings(gameVersion); + } + + networkingPeer.IsInitialConnect = true; + networkingPeer.SetApp(PhotonServerSettings.AppID, gameVersion); + + if (region != CloudRegionCode.none) + { + Debug.Log("ConnectToRegion: " + region); + return networkingPeer.ConnectToRegionMaster(region); + } + + return false; + } + + /// Overwrites the region that is used for ConnectToBestCloudServer(string gameVersion). + /// + /// This will overwrite the result of pinging all cloud servers.
+ /// Use this to allow your users to save a manually selected region in the player preferences.
+ /// Note: You can also use PhotonNetwork.ConnectToRegion to (temporarily) connect to a specific region. + ///
+ public static void OverrideBestCloudServer(CloudRegionCode region) + { + PhotonHandler.BestRegionCodeInPreferences = region; + } + + /// Pings all cloud servers again to find the one with best ping (currently). + public static void RefreshCloudServerRating() + { + throw new NotImplementedException("not available at the moment"); + } + + + /// + /// Resets the traffic stats and re-enables them. + /// + public static void NetworkStatisticsReset() + { + networkingPeer.TrafficStatsReset(); + } + + + /// + /// Only available when NetworkStatisticsEnabled was used to gather some stats. + /// + /// A string with vital networking statistics. + public static string NetworkStatisticsToString() + { + if (networkingPeer == null || offlineMode) + { + return "Offline or in OfflineMode. No VitalStats available."; + } + + return networkingPeer.VitalStatsToString(false); + } + + /// + /// Used for compatibility with Unity networking only. Encryption is automatically initialized while connecting. + /// + [Obsolete("Used for compatibility with Unity networking only. Encryption is automatically initialized while connecting.")] + public static void InitializeSecurity() + { + return; + } + + /// + /// Helper function which is called inside this class to erify if certain functions can be used (e.g. RPC when not connected) + /// + /// + private static bool VerifyCanUseNetwork() + { + if (connected) + { + return true; + } + + Debug.LogError("Cannot send messages when not connected. Either connect to Photon OR use offline mode!"); + return false; + } + + /// + /// Makes this client disconnect from the photon server, a process that leaves any room and calls OnDisconnectedFromPhoton on completion. + /// + /// + /// When you disconnect, the client will send a "disconnecting" message to the server. This speeds up leave/disconnect + /// messages for players in the same room as you (otherwise the server would timeout this client's connection). + /// When used in offlineMode, the state-change and event-call OnDisconnectedFromPhoton are immediate. + /// Offline mode is set to false as well. + /// Once disconnected, the client can connect again. Use ConnectUsingSettings. + /// + public static void Disconnect() + { + if (offlineMode) + { + offlineMode = false; + offlineModeRoom = null; + networkingPeer.State = ClientState.Disconnecting; + networkingPeer.OnStatusChanged(StatusCode.Disconnect); + return; + } + + if (networkingPeer == null) + { + return; // Surpress error when quitting playmode in the editor + } + + networkingPeer.Disconnect(); + } + + /// + /// Requests the rooms and online status for a list of friends and saves the result in PhotonNetwork.Friends. + /// + /// + /// Works only on Master Server to find the rooms played by a selected list of users. + /// + /// The result will be stored in PhotonNetwork.Friends when available. + /// That list is initialized on first use of OpFindFriends (before that, it is null). + /// To refresh the list, call FindFriends again (in 5 seconds or 10 or 20). + /// + /// Users identify themselves by setting a unique userId in the PhotonNetwork.AuthValues. + /// See remarks of AuthenticationValues for info about how this is set and used. + /// + /// The list of friends must be fetched from some other source (not provided by Photon). + /// + /// + /// Internal: + /// The server response includes 2 arrays of info (each index matching a friend from the request): + /// ParameterCode.FindFriendsResponseOnlineList = bool[] of online states + /// ParameterCode.FindFriendsResponseRoomIdList = string[] of room names (empty string if not in a room) + /// + /// Array of friend (make sure to use unique playerName or AuthValues). + /// If the operation could be sent (requires connection, only one request is allowed at any time). Always false in offline mode. + public static bool FindFriends(string[] friendsToFind) + { + if (networkingPeer == null || isOfflineMode) + { + return false; + } + + return networkingPeer.OpFindFriends(friendsToFind); + } + + + /// + /// Creates a room with given name but fails if this room(name) is existing already. Creates random name for roomName null. + /// + /// + /// If you don't want to create a unique room-name, pass null or "" as name and the server will assign a roomName (a GUID as string). + /// + /// The created room is automatically placed in the currently used lobby (if any) or the default-lobby if you didn't explicitly join one. + /// + /// Call this only on the master server. + /// Internally, the master will respond with a server-address (and roomName, if needed). Both are used internally + /// to switch to the assigned game server and roomName. + /// + /// PhotonNetwork.autoCleanUpPlayerObjects will become this room's AutoCleanUp property and that's used by all clients that join this room. + /// + /// Unique name of the room to create. + /// If the operation got queued and will be sent. + public static bool CreateRoom(string roomName) + { + return CreateRoom(roomName, null, null, null); + } + + /// + /// Creates a room but fails if this room is existing already. Can only be called on Master Server. + /// + /// + /// When successful, this calls the callbacks OnCreatedRoom and OnJoinedRoom (the latter, cause you join as first player). + /// If the room can't be created (because it exists already), OnPhotonCreateRoomFailed gets called. + /// + /// If you don't want to create a unique room-name, pass null or "" as name and the server will assign a roomName (a GUID as string). + /// + /// Rooms can be created in any number of lobbies. Those don't have to exist before you create a room in them (they get + /// auto-created on demand). Lobbies can be useful to split room lists on the server-side already. That can help keep the room + /// lists short and manageable. + /// If you set a typedLobby parameter, the room will be created in that lobby (no matter if you are active in any). + /// If you don't set a typedLobby, the room is automatically placed in the currently active lobby (if any) or the + /// default-lobby. + /// + /// Call this only on the master server. + /// Internally, the master will respond with a server-address (and roomName, if needed). Both are used internally + /// to switch to the assigned game server and roomName. + /// + /// PhotonNetwork.autoCleanUpPlayerObjects will become this room's autoCleanUp property and that's used by all clients that join this room. + /// + /// Unique name of the room to create. Pass null or "" to make the server generate a name. + /// Common options for the room like MaxPlayers, initial custom room properties and similar. See RoomOptions type.. + /// If null, the room is automatically created in the currently used lobby (which is "default" when you didn't join one explicitly). + /// If the operation got queued and will be sent. + public static bool CreateRoom(string roomName, RoomOptions roomOptions, TypedLobby typedLobby) + { + return CreateRoom(roomName, roomOptions, typedLobby, null); + } + + /// + /// Creates a room but fails if this room is existing already. Can only be called on Master Server. + /// + /// + /// When successful, this calls the callbacks OnCreatedRoom and OnJoinedRoom (the latter, cause you join as first player). + /// If the room can't be created (because it exists already), OnPhotonCreateRoomFailed gets called. + /// + /// If you don't want to create a unique room-name, pass null or "" as name and the server will assign a roomName (a GUID as string). + /// + /// Rooms can be created in any number of lobbies. Those don't have to exist before you create a room in them (they get + /// auto-created on demand). Lobbies can be useful to split room lists on the server-side already. That can help keep the room + /// lists short and manageable. + /// If you set a typedLobby parameter, the room will be created in that lobby (no matter if you are active in any). + /// If you don't set a typedLobby, the room is automatically placed in the currently active lobby (if any) or the + /// default-lobby. + /// + /// Call this only on the master server. + /// Internally, the master will respond with a server-address (and roomName, if needed). Both are used internally + /// to switch to the assigned game server and roomName. + /// + /// PhotonNetwork.autoCleanUpPlayerObjects will become this room's autoCleanUp property and that's used by all clients that join this room. + /// + /// You can define an array of expectedUsers, to block player slots in the room for these users. + /// The corresponding feature in Photon is called "Slot Reservation" and can be found in the doc pages. + /// + /// Unique name of the room to create. Pass null or "" to make the server generate a name. + /// Common options for the room like MaxPlayers, initial custom room properties and similar. See RoomOptions type.. + /// If null, the room is automatically created in the currently used lobby (which is "default" when you didn't join one explicitly). + /// Optional list of users (by UserId) who are expected to join this game and who you want to block a slot for. + /// If the operation got queued and will be sent. + public static bool CreateRoom(string roomName, RoomOptions roomOptions, TypedLobby typedLobby, string[] expectedUsers) + { + if (offlineMode) + { + if (offlineModeRoom != null) + { + Debug.LogError("CreateRoom failed. In offline mode you still have to leave a room to enter another."); + return false; + } + EnterOfflineRoom(roomName, roomOptions, true); + return true; + } + if (networkingPeer.Server != ServerConnection.MasterServer || !connectedAndReady) + { + Debug.LogError("CreateRoom failed. Client is not on Master Server or not yet ready to call operations. Wait for callback: OnJoinedLobby or OnConnectedToMaster."); + return false; + } + + typedLobby = typedLobby ?? ((networkingPeer.insideLobby) ? networkingPeer.lobby : null); // use given lobby, or active lobby (if any active) or none + + EnterRoomParams opParams = new EnterRoomParams(); + opParams.RoomName = roomName; + opParams.RoomOptions = roomOptions; + opParams.Lobby = typedLobby; + opParams.ExpectedUsers = expectedUsers; + + return networkingPeer.OpCreateGame(opParams); + } + + + /// Join room by roomname and on success calls OnJoinedRoom(). This is not affected by lobbies. + /// + /// On success, the method OnJoinedRoom() is called on any script. You can implement it to react to joining a room. + /// + /// JoinRoom fails if the room is either full or no longer available (it might become empty while you attempt to join). + /// Implement OnPhotonJoinRoomFailed() to get a callback in error case. + /// + /// To join a room from the lobby's listing, use RoomInfo.Name as roomName here. + /// Despite using multiple lobbies, a roomName is always "global" for your application and so you don't + /// have to specify which lobby it's in. The Master Server will find the room. + /// In the Photon Cloud, an application is defined by AppId, Game- and PUN-version. + /// + /// + /// + /// Unique name of the room to join. + /// If the operation got queued and will be sent. + public static bool JoinRoom(string roomName) + { + return JoinRoom(roomName, null); + } + + /// Join room by roomname and on success calls OnJoinedRoom(). This is not affected by lobbies. + /// + /// On success, the method OnJoinedRoom() is called on any script. You can implement it to react to joining a room. + /// + /// JoinRoom fails if the room is either full or no longer available (it might become empty while you attempt to join). + /// Implement OnPhotonJoinRoomFailed() to get a callback in error case. + /// + /// To join a room from the lobby's listing, use RoomInfo.Name as roomName here. + /// Despite using multiple lobbies, a roomName is always "global" for your application and so you don't + /// have to specify which lobby it's in. The Master Server will find the room. + /// In the Photon Cloud, an application is defined by AppId, Game- and PUN-version. + /// + /// You can define an array of expectedUsers, to block player slots in the room for these users. + /// The corresponding feature in Photon is called "Slot Reservation" and can be found in the doc pages. + /// + /// + /// + /// Unique name of the room to join. + /// Optional list of users (by UserId) who are expected to join this game and who you want to block a slot for. + /// If the operation got queued and will be sent. + public static bool JoinRoom(string roomName, string[] expectedUsers) + { + if (offlineMode) + { + if (offlineModeRoom != null) + { + Debug.LogError("JoinRoom failed. In offline mode you still have to leave a room to enter another."); + return false; + } + EnterOfflineRoom(roomName, null, true); + return true; + } + if (networkingPeer.Server != ServerConnection.MasterServer || !connectedAndReady) + { + Debug.LogError("JoinRoom failed. Client is not on Master Server or not yet ready to call operations. Wait for callback: OnJoinedLobby or OnConnectedToMaster."); + return false; + } + if (string.IsNullOrEmpty(roomName)) + { + Debug.LogError("JoinRoom failed. A roomname is required. If you don't know one, how will you join?"); + return false; + } + + + EnterRoomParams opParams = new EnterRoomParams(); + opParams.RoomName = roomName; + opParams.ExpectedUsers = expectedUsers; + + return networkingPeer.OpJoinRoom(opParams); + } + + + /// Lets you either join a named room or create it on the fly - you don't have to know if someone created the room already. + /// + /// This makes it easier for groups of players to get into the same room. Once the group + /// exchanged a roomName, any player can call JoinOrCreateRoom and it doesn't matter who + /// actually joins or creates the room. + /// + /// The parameters roomOptions and typedLobby are only used when the room actually gets created by this client. + /// You know if this client created a room, if you get a callback OnCreatedRoom (before OnJoinedRoom gets called as well). + /// + /// Name of the room to join. Must be non null. + /// Options for the room, in case it does not exist yet. Else these values are ignored. + /// Lobby you want a new room to be listed in. Ignored if the room was existing and got joined. + /// If the operation got queued and will be sent. + public static bool JoinOrCreateRoom(string roomName, RoomOptions roomOptions, TypedLobby typedLobby) + { + return JoinOrCreateRoom(roomName, roomOptions, typedLobby, null); + } + + /// Lets you either join a named room or create it on the fly - you don't have to know if someone created the room already. + /// + /// This makes it easier for groups of players to get into the same room. Once the group + /// exchanged a roomName, any player can call JoinOrCreateRoom and it doesn't matter who + /// actually joins or creates the room. + /// + /// The parameters roomOptions and typedLobby are only used when the room actually gets created by this client. + /// You know if this client created a room, if you get a callback OnCreatedRoom (before OnJoinedRoom gets called as well). + /// + /// You can define an array of expectedUsers, to block player slots in the room for these users. + /// The corresponding feature in Photon is called "Slot Reservation" and can be found in the doc pages. + /// + /// Name of the room to join. Must be non null. + /// Options for the room, in case it does not exist yet. Else these values are ignored. + /// Lobby you want a new room to be listed in. Ignored if the room was existing and got joined. + /// Optional list of users (by UserId) who are expected to join this game and who you want to block a slot for. + /// If the operation got queued and will be sent. + public static bool JoinOrCreateRoom(string roomName, RoomOptions roomOptions, TypedLobby typedLobby, string[] expectedUsers) + { + if (offlineMode) + { + if (offlineModeRoom != null) + { + Debug.LogError("JoinOrCreateRoom failed. In offline mode you still have to leave a room to enter another."); + return false; + } + EnterOfflineRoom(roomName, roomOptions, true); // in offline mode, JoinOrCreateRoom assumes you create the room + return true; + } + if (networkingPeer.Server != ServerConnection.MasterServer || !connectedAndReady) + { + Debug.LogError("JoinOrCreateRoom failed. Client is not on Master Server or not yet ready to call operations. Wait for callback: OnJoinedLobby or OnConnectedToMaster."); + return false; + } + if (string.IsNullOrEmpty(roomName)) + { + Debug.LogError("JoinOrCreateRoom failed. A roomname is required. If you don't know one, how will you join?"); + return false; + } + + typedLobby = typedLobby ?? ((networkingPeer.insideLobby) ? networkingPeer.lobby : null); // use given lobby, or active lobby (if any active) or none + + EnterRoomParams opParams = new EnterRoomParams(); + opParams.RoomName = roomName; + opParams.RoomOptions = roomOptions; + opParams.Lobby = typedLobby; + opParams.CreateIfNotExists = true; + opParams.PlayerProperties = player.CustomProperties; + opParams.ExpectedUsers = expectedUsers; + + return networkingPeer.OpJoinRoom(opParams); + } + + /// + /// Joins any available room of the currently used lobby and fails if none is available. + /// + /// + /// Rooms can be created in arbitrary lobbies which get created on demand. + /// You can join rooms from any lobby without actually joining the lobby. + /// Use the JoinRandomRoom overload with TypedLobby parameter. + /// + /// This method will only match rooms attached to one lobby! If you use many lobbies, you + /// might have to repeat JoinRandomRoom, to find some fitting room. + /// This method looks up a room in the currently active lobby or (if no lobby is joined) + /// in the default lobby. + /// + /// If this fails, you can still create a room (and make this available for the next who uses JoinRandomRoom). + /// Alternatively, try again in a moment. + /// + public static bool JoinRandomRoom() + { + return JoinRandomRoom(null, 0, MatchmakingMode.FillRoom, null, null); + } + + /// + /// Attempts to join an open room with fitting, custom properties but fails if none is currently available. + /// + /// + /// Rooms can be created in arbitrary lobbies which get created on demand. + /// You can join rooms from any lobby without actually joining the lobby. + /// Use the JoinRandomRoom overload with TypedLobby parameter. + /// + /// This method will only match rooms attached to one lobby! If you use many lobbies, you + /// might have to repeat JoinRandomRoom, to find some fitting room. + /// This method looks up a room in the currently active lobby or (if no lobby is joined) + /// in the default lobby. + /// + /// If this fails, you can still create a room (and make this available for the next who uses JoinRandomRoom). + /// Alternatively, try again in a moment. + /// + /// Filters for rooms that match these custom properties (string keys and values). To ignore, pass null. + /// Filters for a particular maxplayer setting. Use 0 to accept any maxPlayer value. + /// If the operation got queued and will be sent. + public static bool JoinRandomRoom(Hashtable expectedCustomRoomProperties, byte expectedMaxPlayers) + { + return JoinRandomRoom(expectedCustomRoomProperties, expectedMaxPlayers, MatchmakingMode.FillRoom, null, null); + } + + /// + /// Attempts to join an open room with fitting, custom properties but fails if none is currently available. + /// + /// + /// Rooms can be created in arbitrary lobbies which get created on demand. + /// You can join rooms from any lobby without actually joining the lobby with this overload. + /// + /// This method will only match rooms attached to one lobby! If you use many lobbies, you + /// might have to repeat JoinRandomRoom, to find some fitting room. + /// This method looks up a room in the specified lobby or the currently active lobby (if none specified) + /// or in the default lobby (if none active). + /// + /// If this fails, you can still create a room (and make this available for the next who uses JoinRandomRoom). + /// Alternatively, try again in a moment. + /// + /// In offlineMode, a room will be created but no properties will be set and all parameters of this + /// JoinRandomRoom call are ignored. The event/callback OnJoinedRoom gets called (see enum PhotonNetworkingMessage). + /// + /// You can define an array of expectedUsers, to block player slots in the room for these users. + /// The corresponding feature in Photon is called "Slot Reservation" and can be found in the doc pages. + /// + /// Filters for rooms that match these custom properties (string keys and values). To ignore, pass null. + /// Filters for a particular maxplayer setting. Use 0 to accept any maxPlayer value. + /// Selects one of the available matchmaking algorithms. See MatchmakingMode enum for options. + /// The lobby in which you want to lookup a room. Pass null, to use the default lobby. This does not join that lobby and neither sets the lobby property. + /// A filter-string for SQL-typed lobbies. + /// Optional list of users (by UserId) who are expected to join this game and who you want to block a slot for. + /// If the operation got queued and will be sent. + public static bool JoinRandomRoom(Hashtable expectedCustomRoomProperties, byte expectedMaxPlayers, MatchmakingMode matchingType, TypedLobby typedLobby, string sqlLobbyFilter, string[] expectedUsers = null) + { + if (offlineMode) + { + if (offlineModeRoom != null) + { + Debug.LogError("JoinRandomRoom failed. In offline mode you still have to leave a room to enter another."); + return false; + } + EnterOfflineRoom("offline room", null, true); + return true; + } + if (networkingPeer.Server != ServerConnection.MasterServer || !connectedAndReady) + { + Debug.LogError("JoinRandomRoom failed. Client is not on Master Server or not yet ready to call operations. Wait for callback: OnJoinedLobby or OnConnectedToMaster."); + return false; + } + + typedLobby = typedLobby ?? ((networkingPeer.insideLobby) ? networkingPeer.lobby : null); // use given lobby, or active lobby (if any active) or none + + OpJoinRandomRoomParams opParams = new OpJoinRandomRoomParams(); + opParams.ExpectedCustomRoomProperties = expectedCustomRoomProperties; + opParams.ExpectedMaxPlayers = expectedMaxPlayers; + opParams.MatchingType = matchingType; + opParams.TypedLobby = typedLobby; + opParams.SqlLobbyFilter = sqlLobbyFilter; + opParams.ExpectedUsers = expectedUsers; + + return networkingPeer.OpJoinRandomRoom(opParams); + } + + + /// Can be used to return to a room after a disconnect and reconnect. + /// + /// After losing connection, you might be able to return to a room and continue playing, + /// if the client is reconnecting fast enough. Use Reconnect() and this method. + /// Cache the room name you're in and use ReJoin(roomname) to return to a game. + /// + /// Note: To be able to ReJoin any room, you need to use UserIDs! + /// You also need to set RoomOptions.PlayerTtl. + /// + /// Important: Instantiate() and use of RPCs is not yet supported. + /// The ownership rules of PhotonViews prevent a seamless return to a game. + /// Use Custom Properties and RaiseEvent with event caching instead. + /// + /// Common use case: Press the Lock Button on a iOS device and you get disconnected immediately. + /// + public static bool ReJoinRoom(string roomName) + { + if (offlineMode) + { + Debug.LogError("ReJoinRoom failed due to offline mode."); + return false; + } + if (networkingPeer.Server != ServerConnection.MasterServer || !connectedAndReady) + { + Debug.LogError("ReJoinRoom failed. Client is not on Master Server or not yet ready to call operations. Wait for callback: OnJoinedLobby or OnConnectedToMaster."); + return false; + } + if (string.IsNullOrEmpty(roomName)) + { + Debug.LogError("ReJoinRoom failed. A roomname is required. If you don't know one, how will you join?"); + return false; + } + + EnterRoomParams opParams = new EnterRoomParams(); + opParams.RoomName = roomName; + opParams.RejoinOnly = true; + opParams.PlayerProperties = player.CustomProperties; + + return networkingPeer.OpJoinRoom(opParams); + } + + + /// + /// Internally used helper-method to setup an offline room, the numbers for actor and master-client and to do the callbacks. + /// + private static void EnterOfflineRoom(string roomName, RoomOptions roomOptions, bool createdRoom) + { + offlineModeRoom = new Room(roomName, roomOptions); + networkingPeer.ChangeLocalID(1); + offlineModeRoom.MasterClientId = 1; + + if (createdRoom) + { + NetworkingPeer.SendMonoMessage(PhotonNetworkingMessage.OnCreatedRoom); + } + NetworkingPeer.SendMonoMessage(PhotonNetworkingMessage.OnJoinedRoom); + } + + /// On MasterServer this joins the default lobby which list rooms currently in use. + /// + /// The room list is sent and refreshed by the server. You can access this cached list by + /// PhotonNetwork.GetRoomList(). + /// + /// Per room you should check if it's full or not before joining. Photon also lists rooms that are + /// full, unless you close and hide them (room.open = false and room.visible = false). + /// + /// In best case, you make your clients join random games, as described here: + /// http://doc.exitgames.com/en/realtime/current/reference/matchmaking-and-lobby + /// + /// + /// You can show your current players and room count without joining a lobby (but you must + /// be on the master server). Use: countOfPlayers, countOfPlayersOnMaster, countOfPlayersInRooms and + /// countOfRooms. + /// + /// You can use more than one lobby to keep the room lists shorter. See JoinLobby(TypedLobby lobby). + /// When creating new rooms, they will be "attached" to the currently used lobby or the default lobby. + /// + /// You can use JoinRandomRoom without being in a lobby! + /// Set autoJoinLobby = false before you connect, to not join a lobby. In that case, the + /// connect-workflow will call OnConnectedToMaster (if you implement it) when it's done. + /// + public static bool JoinLobby() + { + return JoinLobby(null); + } + + /// On a Master Server you can join a lobby to get lists of available rooms. + /// + /// The room list is sent and refreshed by the server. You can access this cached list by + /// PhotonNetwork.GetRoomList(). + /// + /// Any client can "make up" any lobby on the fly. Splitting rooms into multiple lobbies will + /// keep each list shorter. However, having too many lists might ruin the matchmaking experience. + /// + /// In best case, you create a limited number of lobbies. For example, create a lobby per + /// game-mode: "koth" for king of the hill and "ffa" for free for all, etc. + /// + /// There is no listing of lobbies at the moment. + /// + /// Sql-typed lobbies offer a different filtering model for random matchmaking. This might be more + /// suited for skillbased-games. However, you will also need to follow the conventions for naming + /// filterable properties in sql-lobbies! Both is explained in the matchmaking doc linked below. + /// + /// In best case, you make your clients join random games, as described here: + /// http://confluence.exitgames.com/display/PTN/Op+JoinRandomGame + /// + /// + /// Per room you should check if it's full or not before joining. Photon does list rooms that are + /// full, unless you close and hide them (room.open = false and room.visible = false). + /// + /// You can show your games current players and room count without joining a lobby (but you must + /// be on the master server). Use: countOfPlayers, countOfPlayersOnMaster, countOfPlayersInRooms and + /// countOfRooms. + /// + /// When creating new rooms, they will be "attached" to the currently used lobby or the default lobby. + /// + /// You can use JoinRandomRoom without being in a lobby! + /// Set autoJoinLobby = false before you connect, to not join a lobby. In that case, the + /// connect-workflow will call OnConnectedToMaster (if you implement it) when it's done. + /// + /// A typed lobby to join (must have name and type). + public static bool JoinLobby(TypedLobby typedLobby) + { + if (PhotonNetwork.connected && PhotonNetwork.Server == ServerConnection.MasterServer) + { + if (typedLobby == null) + { + typedLobby = TypedLobby.Default; + } + + bool sending = networkingPeer.OpJoinLobby(typedLobby); + if (sending) + { + networkingPeer.lobby = typedLobby; + + } + return sending; + } + + return false; + } + + /// Leave a lobby to stop getting updates about available rooms. + /// + /// This does not reset PhotonNetwork.lobby! This allows you to join this particular lobby later + /// easily. + /// + /// The values countOfPlayers, countOfPlayersOnMaster, countOfPlayersInRooms and countOfRooms + /// are received even without being in a lobby. + /// + /// You can use JoinRandomRoom without being in a lobby. + /// Use autoJoinLobby to not join a lobby when you connect. + /// + public static bool LeaveLobby() + { + if (PhotonNetwork.connected && PhotonNetwork.Server == ServerConnection.MasterServer) + { + return networkingPeer.OpLeaveLobby(); + } + + return false; + } + + /// Leave the current room and return to the Master Server where you can join or create rooms (see remarks). + /// + /// This will clean up all (network) GameObjects with a PhotonView, unless you changed autoCleanUp to false. + /// Returns to the Master Server. + /// + /// In OfflineMode, the local "fake" room gets cleaned up and OnLeftRoom gets called immediately. + /// + public static bool LeaveRoom() + { + if (offlineMode) + { + offlineModeRoom = null; + NetworkingPeer.SendMonoMessage(PhotonNetworkingMessage.OnLeftRoom); + } + else + { + if (room == null) + { + Debug.LogWarning("PhotonNetwork.room is null. You don't have to call LeaveRoom() when you're not in one. State: " + PhotonNetwork.connectionStateDetailed); + } + return networkingPeer.OpLeave(); + } + + return true; + } + + /// Fetches a custom list of games from the server, matching a SQL-like "where" clause, then triggers OnReceivedRoomListUpdate callback. + /// + /// Operation is only available for lobbies of type SqlLobby. Note: You don't have to join that lobby. + /// This is an async request. + /// + /// When done, OnReceivedRoomListUpdate gets called. Use GetRoomList() to access it. + /// + /// + /// The lobby to query. Has to be of type SqlLobby. + /// The sql query statement. + /// If the operation could be sent (has to be connected). + public static bool GetCustomRoomList(TypedLobby typedLobby, string sqlLobbyFilter) + { + return networkingPeer.OpGetGameList(typedLobby, sqlLobbyFilter); + } + + /// + /// Gets currently known rooms as RoomInfo array. This is available and updated while in a lobby (check insideLobby). + /// + /// + /// This list is a cached copy of the internal rooms list so it can be accessed each frame if needed. + /// Per RoomInfo you can check if the room is full by comparing playerCount and MaxPlayers before you allow a join. + /// + /// The name of a room must be used to join it (via JoinRoom). + /// + /// Closed rooms are also listed by lobbies but they can't be joined. While in a room, any player can set + /// Room.visible and Room.open to hide rooms from matchmaking and close them. + /// + /// RoomInfo[] of current rooms in lobby. + public static RoomInfo[] GetRoomList() + { + if (offlineMode || networkingPeer == null) + { + return new RoomInfo[0]; + } + + return networkingPeer.mGameListCopy; + } + + /// + /// Sets this (local) player's properties and synchronizes them to the other players (don't modify them directly). + /// + /// + /// While in a room, your properties are synced with the other players. + /// CreateRoom, JoinRoom and JoinRandomRoom will all apply your player's custom properties when you enter the room. + /// The whole Hashtable will get sent. Minimize the traffic by setting only updated key/values. + /// + /// If the Hashtable is null, the custom properties will be cleared. + /// Custom properties are never cleared automatically, so they carry over to the next room, if you don't change them. + /// + /// Don't set properties by modifying PhotonNetwork.player.customProperties! + /// + /// Only string-typed keys will be used from this hashtable. If null, custom properties are all deleted. + public static void SetPlayerCustomProperties(Hashtable customProperties) + { + if (customProperties == null) + { + customProperties = new Hashtable(); + foreach (object k in player.CustomProperties.Keys) + { + customProperties[(string)k] = null; + } + } + + if (room != null && room.IsLocalClientInside) + { + player.SetCustomProperties(customProperties); + } + else + { + player.InternalCacheProperties(customProperties); + } + } + + /// + /// Locally removes Custom Properties of "this" player. Important: This does not synchronize the change! Useful when you switch rooms. + /// + /// + /// Use this method with care. It can create inconsistencies of state between players! + /// This only changes the player.customProperties locally. This can be useful to clear your + /// Custom Properties between games (let's say they store which turn you made, kills, etc). + /// + /// SetPlayerCustomProperties() syncs and can be used to set values to null while in a room. + /// That can be considered "removed" while in a room. + /// + /// If customPropertiesToDelete is null or has 0 entries, all Custom Properties are deleted (replaced with a new Hashtable). + /// If you specify keys to remove, those will be removed from the Hashtable but other keys are unaffected. + /// + /// List of Custom Property keys to remove. See remarks. + public static void RemovePlayerCustomProperties(string[] customPropertiesToDelete) + { + if (customPropertiesToDelete == null || customPropertiesToDelete.Length == 0 || player.CustomProperties == null) + { + player.CustomProperties = new Hashtable(); + return; + } + + // if a specific list of props should be deleted, we do that here + for (int i = 0; i < customPropertiesToDelete.Length; i++) + { + string key = customPropertiesToDelete[i]; + if (player.CustomProperties.ContainsKey(key)) + { + player.CustomProperties.Remove(key); + } + } + } + + /// + /// Sends fully customizable events in a room. Events consist of at least an EventCode (0..199) and can have content. + /// + /// + /// To receive the events someone sends, register your handling method in PhotonNetwork.OnEventCall. + /// + /// Example: + /// private void OnEventHandler(byte eventCode, object content, int senderId) + /// { Debug.Log("OnEventHandler"); } + /// + /// PhotonNetwork.OnEventCall += this.OnEventHandler; + /// + /// With the senderId, you can look up the PhotonPlayer who sent the event. + /// It is best practice to assign a eventCode for each different type of content and action. You have to cast the content. + /// + /// The eventContent is optional. To be able to send something, it must be a "serializable type", something that + /// the client can turn into a byte[] basically. Most basic types and arrays of them are supported, including + /// Unity's Vector2, Vector3, Quaternion. Transforms or classes some project defines are NOT supported! + /// You can make your own class a "serializable type" by following the example in CustomTypes.cs. + /// + /// + /// The RaiseEventOptions have some (less intuitive) combination rules: + /// If you set targetActors (an array of PhotonPlayer.ID values), the receivers parameter gets ignored. + /// When using event caching, the targetActors, receivers and interestGroup can't be used. Buffered events go to all. + /// When using cachingOption removeFromRoomCache, the eventCode and content are actually not sent but used as filter. + /// + /// A byte identifying the type of event. You might want to use a code per action or to signal which content can be expected. Allowed: 0..199. + /// Some serializable object like string, byte, integer, float (etc) and arrays of those. Hashtables with byte keys are good to send variable content. + /// Makes sure this event reaches all players. It gets acknowledged, which requires bandwidth and it can't be skipped (might add lag in case of loss). + /// Allows more complex usage of events. If null, RaiseEventOptions.Default will be used (which is fine). + /// False if event could not be sent + public static bool RaiseEvent(byte eventCode, object eventContent, bool sendReliable, RaiseEventOptions options) + { + if (!inRoom || eventCode >= 200) + { + Debug.LogWarning("RaiseEvent() failed. Your event is not being sent! Check if your are in a Room and the eventCode must be less than 200 (0..199)."); + return false; + } + + return networkingPeer.OpRaiseEvent(eventCode, eventContent, sendReliable, options); + } + + /// + /// Allocates a viewID that's valid for the current/local player. + /// + /// A viewID that can be used for a new PhotonView. + public static int AllocateViewID() + { + int manualId = AllocateViewID(player.ID); + manuallyAllocatedViewIds.Add(manualId); + return manualId; + } + + + /// + /// Enables the Master Client to allocate a viewID that is valid for scene objects. + /// + /// A viewID that can be used for a new PhotonView or -1 in case of an error. + public static int AllocateSceneViewID() + { + if (!PhotonNetwork.isMasterClient) + { + Debug.LogError("Only the Master Client can AllocateSceneViewID(). Check PhotonNetwork.isMasterClient!"); + return -1; + } + + int manualId = AllocateViewID(0); + manuallyAllocatedViewIds.Add(manualId); + return manualId; + } + + // use 0 for scene-targetPhotonView-ids + // returns viewID (combined owner and sub id) + private static int AllocateViewID(int ownerId) + { + if (ownerId == 0) + { + // we look up a fresh subId for the owner "room" (mind the "sub" in subId) + int newSubId = lastUsedViewSubIdStatic; + int newViewId; + int ownerIdOffset = ownerId * MAX_VIEW_IDS; + for (int i = 1; i < MAX_VIEW_IDS; i++) + { + newSubId = (newSubId + 1) % MAX_VIEW_IDS; + if (newSubId == 0) + { + continue; // avoid using subID 0 + } + + newViewId = newSubId + ownerIdOffset; + if (!networkingPeer.photonViewList.ContainsKey(newViewId)) + { + lastUsedViewSubIdStatic = newSubId; + return newViewId; + } + } + + // this is the error case: we didn't find any (!) free subId for this user + throw new Exception(string.Format("AllocateViewID() failed. Room (user {0}) is out of 'scene' viewIDs. It seems all available are in use.", ownerId)); + } + else + { + // we look up a fresh SUBid for the owner + int newSubId = lastUsedViewSubId; + int newViewId; + int ownerIdOffset = ownerId * MAX_VIEW_IDS; + for (int i = 1; i < MAX_VIEW_IDS; i++) + { + newSubId = (newSubId + 1) % MAX_VIEW_IDS; + if (newSubId == 0) + { + continue; // avoid using subID 0 + } + + newViewId = newSubId + ownerIdOffset; + if (!networkingPeer.photonViewList.ContainsKey(newViewId) && !manuallyAllocatedViewIds.Contains(newViewId)) + { + lastUsedViewSubId = newSubId; + return newViewId; + } + } + + throw new Exception(string.Format("AllocateViewID() failed. User {0} is out of subIds, as all viewIDs are used.", ownerId)); + } + } + + private static int[] AllocateSceneViewIDs(int countOfNewViews) + { + int[] viewIDs = new int[countOfNewViews]; + for (int view = 0; view < countOfNewViews; view++) + { + viewIDs[view] = AllocateViewID(0); + } + + return viewIDs; + } + + /// + /// Unregister a viewID (of manually instantiated and destroyed networked objects). + /// + /// A viewID manually allocated by this player. + public static void UnAllocateViewID(int viewID) + { + manuallyAllocatedViewIds.Remove(viewID); + + if (networkingPeer.photonViewList.ContainsKey(viewID)) + { + Debug.LogWarning(string.Format("UnAllocateViewID() should be called after the PhotonView was destroyed (GameObject.Destroy()). ViewID: {0} still found in: {1}", viewID, networkingPeer.photonViewList[viewID])); + } + } + + /// + /// Instantiate a prefab over the network. This prefab needs to be located in the root of a "Resources" folder. + /// + /// + /// Instead of using prefabs in the Resources folder, you can manually Instantiate and assign PhotonViews. See doc. + /// + /// Name of the prefab to instantiate. + /// Position Vector3 to apply on instantiation. + /// Rotation Quaternion to apply on instantiation. + /// The group for this PhotonView. + /// The new instance of a GameObject with initialized PhotonView. + public static GameObject Instantiate(string prefabName, Vector3 position, Quaternion rotation, byte group) + { + return Instantiate(prefabName, position, rotation, group, null); + } + + /// + /// Instantiate a prefab over the network. This prefab needs to be located in the root of a "Resources" folder. + /// + /// Instead of using prefabs in the Resources folder, you can manually Instantiate and assign PhotonViews. See doc. + /// Name of the prefab to instantiate. + /// Position Vector3 to apply on instantiation. + /// Rotation Quaternion to apply on instantiation. + /// The group for this PhotonView. + /// Optional instantiation data. This will be saved to it's PhotonView.instantiationData. + /// The new instance of a GameObject with initialized PhotonView. + public static GameObject Instantiate(string prefabName, Vector3 position, Quaternion rotation, byte group, object[] data) + { + if (!connected || (InstantiateInRoomOnly && !inRoom)) + { + Debug.LogError("Failed to Instantiate prefab: " + prefabName + ". Client should be in a room. Current connectionStateDetailed: " + PhotonNetwork.connectionStateDetailed); + return null; + } + + GameObject prefabGo; + if (!UsePrefabCache || !PrefabCache.TryGetValue(prefabName, out prefabGo)) + { + prefabGo = (GameObject)Resources.Load(prefabName, typeof(GameObject)); + if (UsePrefabCache) + { + PrefabCache.Add(prefabName, prefabGo); + } + } + + if (prefabGo == null) + { + Debug.LogError("Failed to Instantiate prefab: " + prefabName + ". Verify the Prefab is in a Resources folder (and not in a subfolder)"); + return null; + } + + // a scene object instantiated with network visibility has to contain a PhotonView + if (prefabGo.GetComponent() == null) + { + Debug.LogError("Failed to Instantiate prefab:" + prefabName + ". Prefab must have a PhotonView component."); + return null; + } + + Component[] views = (Component[])prefabGo.GetPhotonViewsInChildren(); + int[] viewIDs = new int[views.Length]; + for (int i = 0; i < viewIDs.Length; i++) + { + //Debug.Log("Instantiate prefabName: " + prefabName + " player.ID: " + player.ID); + viewIDs[i] = AllocateViewID(player.ID); + } + + // Send to others, create info + Hashtable instantiateEvent = networkingPeer.SendInstantiate(prefabName, position, rotation, group, viewIDs, data, false); + + // Instantiate the GO locally (but the same way as if it was done via event). This will also cache the instantiationId + return networkingPeer.DoInstantiate(instantiateEvent, networkingPeer.LocalPlayer, prefabGo); + } + + + /// + /// Instantiate a scene-owned prefab over the network. The PhotonViews will be controllable by the MasterClient. This prefab needs to be located in the root of a "Resources" folder. + /// + /// + /// Only the master client can Instantiate scene objects. + /// Instead of using prefabs in the Resources folder, you can manually Instantiate and assign PhotonViews. See doc. + /// + /// Name of the prefab to instantiate. + /// Position Vector3 to apply on instantiation. + /// Rotation Quaternion to apply on instantiation. + /// The group for this PhotonView. + /// Optional instantiation data. This will be saved to it's PhotonView.instantiationData. + /// The new instance of a GameObject with initialized PhotonView. + public static GameObject InstantiateSceneObject(string prefabName, Vector3 position, Quaternion rotation, byte group, object[] data) + { + if (!connected || (InstantiateInRoomOnly && !inRoom)) + { + Debug.LogError("Failed to InstantiateSceneObject prefab: " + prefabName + ". Client should be in a room. Current connectionStateDetailed: " + PhotonNetwork.connectionStateDetailed); + return null; + } + + if (!isMasterClient) + { + Debug.LogError("Failed to InstantiateSceneObject prefab: " + prefabName + ". Client is not the MasterClient in this room."); + return null; + } + + GameObject prefabGo; + if (!UsePrefabCache || !PrefabCache.TryGetValue(prefabName, out prefabGo)) + { + prefabGo = (GameObject)Resources.Load(prefabName, typeof(GameObject)); + if (UsePrefabCache) + { + PrefabCache.Add(prefabName, prefabGo); + } + } + + if (prefabGo == null) + { + Debug.LogError("Failed to InstantiateSceneObject prefab: " + prefabName + ". Verify the Prefab is in a Resources folder (and not in a subfolder)"); + return null; + } + + // a scene object instantiated with network visibility has to contain a PhotonView + if (prefabGo.GetComponent() == null) + { + Debug.LogError("Failed to InstantiateSceneObject prefab:" + prefabName + ". Prefab must have a PhotonView component."); + return null; + } + + Component[] views = (Component[])prefabGo.GetPhotonViewsInChildren(); + int[] viewIDs = AllocateSceneViewIDs(views.Length); + + if (viewIDs == null) + { + Debug.LogError("Failed to InstantiateSceneObject prefab: " + prefabName + ". No ViewIDs are free to use. Max is: " + MAX_VIEW_IDS); + return null; + } + + // Send to others, create info + Hashtable instantiateEvent = networkingPeer.SendInstantiate(prefabName, position, rotation, group, viewIDs, data, true); + + // Instantiate the GO locally (but the same way as if it was done via event). This will also cache the instantiationId + return networkingPeer.DoInstantiate(instantiateEvent, networkingPeer.LocalPlayer, prefabGo); + } + + /// + /// The current roundtrip time to the photon server. + /// + /// Roundtrip time (to server and back). + public static int GetPing() + { + return networkingPeer.RoundTripTime; + } + + /// Refreshes the server timestamp (async operation, takes a roundtrip). + /// Can be useful if a bad connection made the timestamp unusable or imprecise. + public static void FetchServerTimestamp() + { + if (networkingPeer != null) + { + networkingPeer.FetchServerTimestamp(); + } + } + + /// + /// Can be used to immediately send the RPCs and Instantiates just called, so they are on their way to the other players. + /// + /// + /// This could be useful if you do a RPC to load a level and then load it yourself. + /// While loading, no RPCs are sent to others, so this would delay the "load" RPC. + /// You can send the RPC to "others", use this method, disable the message queue + /// (by isMessageQueueRunning) and then load. + /// + public static void SendOutgoingCommands() + { + if (!VerifyCanUseNetwork()) + { + return; + } + + while (networkingPeer.SendOutgoingCommands()) + { + } + } + + /// Request a client to disconnect (KICK). Only the master client can do this + /// Only the target player gets this event. That player will disconnect automatically, which is what the others will notice, too. + /// The PhotonPlayer to kick. + public static bool CloseConnection(PhotonPlayer kickPlayer) + { + if (!VerifyCanUseNetwork()) + { + return false; + } + + if (!player.IsMasterClient) + { + Debug.LogError("CloseConnection: Only the masterclient can kick another player."); + return false; + } + + if (kickPlayer == null) + { + Debug.LogError("CloseConnection: No such player connected!"); + return false; + } + + RaiseEventOptions options = new RaiseEventOptions() { TargetActors = new int[] { kickPlayer.ID } }; + return networkingPeer.OpRaiseEvent(PunEvent.CloseConnection, null, true, options); + } + + /// + /// Asks the server to assign another player as Master Client of your current room. + /// + /// + /// RPCs and RaiseEvent have the option to send messages only to the Master Client of a room. + /// SetMasterClient affects which client gets those messages. + /// + /// This method calls an operation on the server to set a new Master Client, which takes a roundtrip. + /// In case of success, this client and the others get the new Master Client from the server. + /// + /// SetMasterClient tells the server which current Master Client should be replaced with the new one. + /// It will fail, if anything switches the Master Client moments earlier. There is no callback for this + /// error. All clients should get the new Master Client assigned by the server anyways. + /// + /// See also: PhotonNetwork.masterClient + /// + /// On v3 servers: + /// The ReceiverGroup.MasterClient (usable in RPCs) is not affected by this (still points to lowest player.ID in room). + /// Avoid using this enum value (and send to a specific player instead). + /// + /// If the current Master Client leaves, PUN will detect a new one by "lowest player ID". Implement OnMasterClientSwitched + /// to get a callback in this case. The PUN-selected Master Client might assign a new one. + /// + /// Make sure you don't create an endless loop of Master-assigning! When selecting a custom Master Client, all clients + /// should point to the same player, no matter who actually assigns this player. + /// + /// Locally the Master Client is immediately switched, while remote clients get an event. This means the game + /// is tempoarily without Master Client like when a current Master Client leaves. + /// + /// When switching the Master Client manually, keep in mind that this user might leave and not do it's work, just like + /// any Master Client. + /// + /// + /// The player to become the next Master Client. + /// False when this operation couldn't be done. Must be in a room (not in offlineMode). + public static bool SetMasterClient(PhotonPlayer masterClientPlayer) + { + if (!inRoom || !VerifyCanUseNetwork() || offlineMode) + { + if (logLevel == PhotonLogLevel.Informational) Debug.Log("Can not SetMasterClient(). Not in room or in offlineMode."); + return false; + } + + if (room.serverSideMasterClient) + { + Hashtable newProps = new Hashtable() { { GamePropertyKey.MasterClientId, masterClientPlayer.ID } }; + Hashtable prevProps = new Hashtable() { { GamePropertyKey.MasterClientId, networkingPeer.mMasterClientId } }; + return networkingPeer.OpSetPropertiesOfRoom(newProps, expectedProperties: prevProps, webForward: false); + } + else + { + if (!isMasterClient) + { + return false; + } + return networkingPeer.SetMasterClient(masterClientPlayer.ID, true); + } + } + + /// + /// Network-Destroy the GameObject associated with the PhotonView, unless the PhotonView is static or not under this client's control. + /// + /// + /// Destroying a networked GameObject while in a Room includes: + /// - Removal of the Instantiate call from the server's room buffer. + /// - Removing RPCs buffered for PhotonViews that got created indirectly with the PhotonNetwork.Instantiate call. + /// - Sending a message to other clients to remove the GameObject also (affected by network lag). + /// + /// Usually, when you leave a room, the GOs get destroyed automatically. + /// If you have to destroy a GO while not in a room, the Destroy is only done locally. + /// + /// Destroying networked objects works only if they got created with PhotonNetwork.Instantiate(). + /// Objects loaded with a scene are ignored, no matter if they have PhotonView components. + /// + /// The GameObject must be under this client's control: + /// - Instantiated and owned by this client. + /// - Instantiated objects of players who left the room are controlled by the Master Client. + /// - Scene-owned game objects are controlled by the Master Client. + /// - GameObject can be destroyed while client is not in a room. + /// + /// Nothing. Check error debug log for any issues. + public static void Destroy(PhotonView targetView) + { + if (targetView != null) + { + networkingPeer.RemoveInstantiatedGO(targetView.gameObject, !inRoom); + } + else + { + Debug.LogError("Destroy(targetPhotonView) failed, cause targetPhotonView is null."); + } + } + + /// + /// Network-Destroy the GameObject, unless it is static or not under this client's control. + /// + /// + /// Destroying a networked GameObject includes: + /// - Removal of the Instantiate call from the server's room buffer. + /// - Removing RPCs buffered for PhotonViews that got created indirectly with the PhotonNetwork.Instantiate call. + /// - Sending a message to other clients to remove the GameObject also (affected by network lag). + /// + /// Usually, when you leave a room, the GOs get destroyed automatically. + /// If you have to destroy a GO while not in a room, the Destroy is only done locally. + /// + /// Destroying networked objects works only if they got created with PhotonNetwork.Instantiate(). + /// Objects loaded with a scene are ignored, no matter if they have PhotonView components. + /// + /// The GameObject must be under this client's control: + /// - Instantiated and owned by this client. + /// - Instantiated objects of players who left the room are controlled by the Master Client. + /// - Scene-owned game objects are controlled by the Master Client. + /// - GameObject can be destroyed while client is not in a room. + /// + /// Nothing. Check error debug log for any issues. + public static void Destroy(GameObject targetGo) + { + networkingPeer.RemoveInstantiatedGO(targetGo, !inRoom); + } + + /// + /// Network-Destroy all GameObjects, PhotonViews and their RPCs of targetPlayer. Can only be called on local player (for "self") or Master Client (for anyone). + /// + /// + /// Destroying a networked GameObject includes: + /// - Removal of the Instantiate call from the server's room buffer. + /// - Removing RPCs buffered for PhotonViews that got created indirectly with the PhotonNetwork.Instantiate call. + /// - Sending a message to other clients to remove the GameObject also (affected by network lag). + /// + /// Destroying networked objects works only if they got created with PhotonNetwork.Instantiate(). + /// Objects loaded with a scene are ignored, no matter if they have PhotonView components. + /// + /// Nothing. Check error debug log for any issues. + public static void DestroyPlayerObjects(PhotonPlayer targetPlayer) + { + if (player == null) + { + Debug.LogError("DestroyPlayerObjects() failed, cause parameter 'targetPlayer' was null."); + } + + DestroyPlayerObjects(targetPlayer.ID); + } + + /// + /// Network-Destroy all GameObjects, PhotonViews and their RPCs of this player (by ID). Can only be called on local player (for "self") or Master Client (for anyone). + /// + /// + /// Destroying a networked GameObject includes: + /// - Removal of the Instantiate call from the server's room buffer. + /// - Removing RPCs buffered for PhotonViews that got created indirectly with the PhotonNetwork.Instantiate call. + /// - Sending a message to other clients to remove the GameObject also (affected by network lag). + /// + /// Destroying networked objects works only if they got created with PhotonNetwork.Instantiate(). + /// Objects loaded with a scene are ignored, no matter if they have PhotonView components. + /// + /// Nothing. Check error debug log for any issues. + public static void DestroyPlayerObjects(int targetPlayerId) + { + if (!VerifyCanUseNetwork()) + { + return; + } + if (player.IsMasterClient || targetPlayerId == player.ID) + { + networkingPeer.DestroyPlayerObjects(targetPlayerId, false); + } + else + { + Debug.LogError("DestroyPlayerObjects() failed, cause players can only destroy their own GameObjects. A Master Client can destroy anyone's. This is master: " + PhotonNetwork.isMasterClient); + } + } + + /// + /// Network-Destroy all GameObjects, PhotonViews and their RPCs in the room. Removes anything buffered from the server. Can only be called by Master Client (for anyone). + /// + /// + /// Can only be called by Master Client (for anyone). + /// Unlike the Destroy methods, this will remove anything from the server's room buffer. If your game + /// buffers anything beyond Instantiate and RPC calls, that will be cleaned as well from server. + /// + /// Destroying all includes: + /// - Remove anything from the server's room buffer (Instantiate, RPCs, anything buffered). + /// - Sending a message to other clients to destroy everything locally, too (affected by network lag). + /// + /// Destroying networked objects works only if they got created with PhotonNetwork.Instantiate(). + /// Objects loaded with a scene are ignored, no matter if they have PhotonView components. + /// + /// Nothing. Check error debug log for any issues. + public static void DestroyAll() + { + if (isMasterClient) + { + networkingPeer.DestroyAll(false); + } + else + { + Debug.LogError("Couldn't call DestroyAll() as only the master client is allowed to call this."); + } + } + + /// + /// Remove all buffered RPCs from server that were sent by targetPlayer. Can only be called on local player (for "self") or Master Client (for anyone). + /// + /// + /// This method requires either: + /// - This is the targetPlayer's client. + /// - This client is the Master Client (can remove any PhotonPlayer's RPCs). + /// + /// If the targetPlayer calls RPCs at the same time that this is called, + /// network lag will determine if those get buffered or cleared like the rest. + /// + /// This player's buffered RPCs get removed from server buffer. + public static void RemoveRPCs(PhotonPlayer targetPlayer) + { + if (!VerifyCanUseNetwork()) + { + return; + } + + if (!targetPlayer.IsLocal && !isMasterClient) + { + Debug.LogError("Error; Only the MasterClient can call RemoveRPCs for other players."); + return; + } + + networkingPeer.OpCleanRpcBuffer(targetPlayer.ID); + } + + /// + /// Remove all buffered RPCs from server that were sent via targetPhotonView. The Master Client and the owner of the targetPhotonView may call this. + /// + /// + /// This method requires either: + /// - The targetPhotonView is owned by this client (Instantiated by it). + /// - This client is the Master Client (can remove any PhotonView's RPCs). + /// + /// RPCs buffered for this PhotonView get removed from server buffer. + public static void RemoveRPCs(PhotonView targetPhotonView) + { + if (!VerifyCanUseNetwork()) + { + return; + } + + networkingPeer.CleanRpcBufferIfMine(targetPhotonView); + } + + /// + /// Remove all buffered RPCs from server that were sent in the targetGroup, if this is the Master Client or if this controls the individual PhotonView. + /// + /// + /// This method requires either: + /// - This client is the Master Client (can remove any RPCs per group). + /// - Any other client: each PhotonView is checked if it is under this client's control. Only those RPCs are removed. + /// + /// Interest group that gets all RPCs removed. + public static void RemoveRPCsInGroup(int targetGroup) + { + if (!VerifyCanUseNetwork()) + { + return; + } + + networkingPeer.RemoveRPCsInGroup(targetGroup); + } + + /// + /// Internal to send an RPC on given PhotonView. Do not call this directly but use: PhotonView.RPC! + /// + internal static void RPC(PhotonView view, string methodName, PhotonTargets target, bool encrypt, params object[] parameters) + { + if (!VerifyCanUseNetwork()) + { + return; + } + + if (room == null) + { + Debug.LogWarning("RPCs can only be sent in rooms. Call of \"" + methodName + "\" gets executed locally only, if at all."); + return; + } + + if (networkingPeer != null) + { + if (PhotonNetwork.room.serverSideMasterClient) + { + networkingPeer.RPC(view, methodName, target, null, encrypt, parameters); + } + else + { + if (PhotonNetwork.networkingPeer.hasSwitchedMC && target == PhotonTargets.MasterClient) + { + networkingPeer.RPC(view, methodName, PhotonTargets.Others, PhotonNetwork.masterClient, encrypt, parameters); + } + else + { + networkingPeer.RPC(view, methodName, target, null, encrypt, parameters); + } + } + } + else + { + Debug.LogWarning("Could not execute RPC " + methodName + ". Possible scene loading in progress?"); + } + } + + /// + /// Internal to send an RPC on given PhotonView. Do not call this directly but use: PhotonView.RPC! + /// + internal static void RPC(PhotonView view, string methodName, PhotonPlayer targetPlayer, bool encrpyt, params object[] parameters) + { + if (!VerifyCanUseNetwork()) + { + return; + } + + if (room == null) + { + Debug.LogWarning("RPCs can only be sent in rooms. Call of \"" + methodName + "\" gets executed locally only, if at all."); + return; + } + + if (player == null) + { + Debug.LogError("RPC can't be sent to target PhotonPlayer being null! Did not send \"" + methodName + "\" call."); + } + + if (networkingPeer != null) + { + networkingPeer.RPC(view, methodName, PhotonTargets.Others, targetPlayer, encrpyt, parameters); + } + else + { + Debug.LogWarning("Could not execute RPC " + methodName + ". Possible scene loading in progress?"); + } + } + + /// + /// Populates SendMonoMessageTargets with currently existing GameObjects that have a Component of type. + /// + /// If null, this will use SendMonoMessageTargets as component-type (MonoBehaviour by default). + public static void CacheSendMonoMessageTargets(Type type) + { + if (type == null) type = SendMonoMessageTargetType; + PhotonNetwork.SendMonoMessageTargets = FindGameObjectsWithComponent(type); + } + + /// Finds the GameObjects with Components of a specific type (using FindObjectsOfType). + /// Type must be a Component + /// HashSet with GameObjects that have a specific type of Component. + public static HashSet FindGameObjectsWithComponent(Type type) + { + HashSet objectsWithComponent = new HashSet(); + + Component[] targetComponents = (Component[]) GameObject.FindObjectsOfType(type); + for (int index = 0; index < targetComponents.Length; index++) + { + if (targetComponents[index] != null) + { + objectsWithComponent.Add(targetComponents[index].gameObject); + } + } + + return objectsWithComponent; + } + + + + [Obsolete("Use SetInterestGroups(byte group, bool enabled) instead.")] + public static void SetReceivingEnabled(int group, bool enabled) + { + if (!VerifyCanUseNetwork()) + { + return; + } + + SetInterestGroups((byte)group, enabled); + } + + /// Enable/disable receiving events from a given Interest Group. + /// + /// A client can tell the server which Interest Groups it's interested in. + /// The server will only forward events for those Interest Groups to that client (saving bandwidth and performance). + /// + /// See: https://doc.photonengine.com/en-us/pun/current/manuals-and-demos/interestgroupsinterestgroups + /// + /// See: https://doc.photonengine.com/en-us/pun/current/manuals-and-demos/culling-demo + /// + /// The interest group to affect. + /// Sets if receiving from group to enabled (or not). + public static void SetInterestGroups(byte group, bool enabled) + { + if (!VerifyCanUseNetwork()) + { + return; + } + + if (enabled) + { + byte[] groups = new byte[1] { (byte)group }; + networkingPeer.SetInterestGroups(null, groups); + } + else + { + byte[] groups = new byte[1] { (byte)group }; + networkingPeer.SetInterestGroups(groups, null); + } + } + + + [Obsolete("Use SetInterestGroups(byte[] disableGroups, byte[] enableGroups) instead. Mind the parameter order!")] + public static void SetReceivingEnabled(int[] enableGroups, int[] disableGroups) + { + if (!VerifyCanUseNetwork()) + { + return; + } + + byte[] disableByteGroups = null; + byte[] enableByteGroups = null; + + if (enableGroups != null) + { + enableByteGroups = new byte[enableGroups.Length]; + Array.Copy(enableGroups, enableByteGroups, enableGroups.Length); + } + if (disableGroups != null) + { + disableByteGroups = new byte[disableGroups.Length]; + Array.Copy(disableGroups, disableByteGroups, disableGroups.Length); + } + + networkingPeer.SetInterestGroups(disableByteGroups, enableByteGroups); + } + + /// Enable/disable receiving on given Interest Groups (applied to PhotonViews). + /// + /// A client can tell the server which Interest Groups it's interested in. + /// The server will only forward events for those Interest Groups to that client (saving bandwidth and performance). + /// + /// See: https://doc.photonengine.com/en-us/pun/current/manuals-and-demos/interestgroupsinterestgroups + /// + /// See: https://doc.photonengine.com/en-us/pun/current/manuals-and-demos/culling-demo + /// + /// The interest groups to disable (or null). + /// The interest groups to enable (or null). + public static void SetInterestGroups(byte[] disableGroups, byte[] enableGroups) + { + if (!VerifyCanUseNetwork()) + { + return; + } + networkingPeer.SetInterestGroups(disableGroups, enableGroups); + } + + + + [Obsolete("Use SetSendingEnabled(byte group, bool enabled). Interest Groups have a byte-typed ID. Mind the parameter order.")] + public static void SetSendingEnabled(int group, bool enabled) + { + SetSendingEnabled((byte)group, enabled); + } + + /// Enable/disable sending on given group (applied to PhotonViews) + /// + /// This does not interact with the Photon server-side. + /// It's just a client-side setting to suppress updates, should they be sent to one of the blocked groups. + /// + /// This setting is not particularly useful, as it means that updates literally never reach the server or anyone else. + /// Use with care. + /// + /// The interest group to affect. + /// Sets if sending to group is enabled (or not). + public static void SetSendingEnabled(byte group, bool enabled) + { + if (!VerifyCanUseNetwork()) + { + return; + } + + networkingPeer.SetSendingEnabled(group, enabled); + } + + + [Obsolete("Use SetSendingEnabled(byte group, bool enabled). Interest Groups have a byte-typed ID. Mind the parameter order.")] + public static void SetSendingEnabled(int[] enableGroups, int[] disableGroups) + { + byte[] disableByteGroups = null; + byte[] enableByteGroups = null; + + if (enableGroups != null) + { + enableByteGroups = new byte[enableGroups.Length]; + Array.Copy(enableGroups, enableByteGroups, enableGroups.Length); + } + if (disableGroups != null) + { + disableByteGroups = new byte[disableGroups.Length]; + Array.Copy(disableGroups, disableByteGroups, disableGroups.Length); + } + + SetSendingEnabled(disableByteGroups, enableByteGroups); + } + + /// Enable/disable sending on given groups (applied to PhotonViews) + /// + /// This does not interact with the Photon server-side. + /// It's just a client-side setting to suppress updates, should they be sent to one of the blocked groups. + /// + /// This setting is not particularly useful, as it means that updates literally never reach the server or anyone else. + /// Use with care. + /// The interest groups to enable sending on (or null). + /// The interest groups to disable sending on (or null). + public static void SetSendingEnabled(byte[] disableGroups, byte[] enableGroups) + { + if (!VerifyCanUseNetwork()) + { + return; + } + + networkingPeer.SetSendingEnabled(disableGroups, enableGroups); + } + + + + /// + /// Sets level prefix for PhotonViews instantiated later on. Don't set it if you need only one! + /// + /// + /// Important: If you don't use multiple level prefixes, simply don't set this value. The + /// default value is optimized out of the traffic. + /// + /// This won't affect existing PhotonViews (they can't be changed yet for existing PhotonViews). + /// + /// Messages sent with a different level prefix will be received but not executed. This affects + /// RPCs, Instantiates and synchronization. + /// + /// Be aware that PUN never resets this value, you'll have to do so yourself. + /// + /// Max value is short.MaxValue = 32767 + public static void SetLevelPrefix(short prefix) + { + if (!VerifyCanUseNetwork()) + { + return; + } + + networkingPeer.SetLevelPrefix(prefix); + } + + /// Wraps loading a level to pause the network mesage-queue. Optionally syncs the loaded level in a room. + /// + /// To sync the loaded level in a room, set PhotonNetwork.automaticallySyncScene to true. + /// The Master Client of a room will then sync the loaded level with every other player in the room. + /// + /// While loading levels, it makes sense to not dispatch messages received by other players. + /// This method takes care of that by setting PhotonNetwork.isMessageQueueRunning = false and enabling + /// the queue when the level was loaded. + /// + /// You should make sure you don't fire RPCs before you load another scene (which doesn't contain + /// the same GameObjects and PhotonViews). You can call this in OnJoinedRoom. + /// + /// This uses Application.LoadLevel. + /// + /// + /// Number of the level to load. When using level numbers, make sure they are identical on all clients. + /// + public static void LoadLevel(int levelNumber) + { + networkingPeer.SetLevelInPropsIfSynced(levelNumber); + + PhotonNetwork.isMessageQueueRunning = false; + networkingPeer.loadingLevelAndPausedNetwork = true; + SceneManager.LoadScene(levelNumber); + } + + /// Wraps loading a level to pause the network mesage-queue. Optionally syncs the loaded level in a room. + /// + /// While loading levels, it makes sense to not dispatch messages received by other players. + /// This method takes care of that by setting PhotonNetwork.isMessageQueueRunning = false and enabling + /// the queue when the level was loaded. + /// + /// To sync the loaded level in a room, set PhotonNetwork.automaticallySyncScene to true. + /// The Master Client of a room will then sync the loaded level with every other player in the room. + /// + /// You should make sure you don't fire RPCs before you load another scene (which doesn't contain + /// the same GameObjects and PhotonViews). You can call this in OnJoinedRoom. + /// + /// This uses Application.LoadLevel. + /// + /// + /// Name of the level to load. Make sure it's available to all clients in the same room. + /// + public static void LoadLevel(string levelName) + { + networkingPeer.SetLevelInPropsIfSynced(levelName); + + PhotonNetwork.isMessageQueueRunning = false; + networkingPeer.loadingLevelAndPausedNetwork = true; + SceneManager.LoadScene(levelName); + } + + + /// + /// This operation makes Photon call your custom web-service by name (path) with the given parameters. + /// + /// + /// This is a server-side feature which must be setup in the Photon Cloud Dashboard prior to use.
+ /// See the Turnbased Feature Overview for a short intro.
+ /// http://doc.photonengine.com/en/turnbased/current/getting-started/feature-overview + ///
+ /// The Parameters will be converted into JSon format, so make sure your parameters are compatible. + /// + /// See PhotonNetworkingMessage.OnWebRpcResponse on how to get a response. + /// + /// It's important to understand that the OperationResponse only tells if the WebRPC could be called. + /// The content of the response contains any values your web-service sent and the error/success code. + /// In case the web-service failed, an error code and a debug message are usually inside the + /// OperationResponse. + /// + /// The class WebRpcResponse is a helper-class that extracts the most valuable content from the WebRPC + /// response. + ///
+ /// + /// Example callback implementation:
+    ///
+    /// public void OnWebRpcResponse(OperationResponse response)
+    /// {
+    ///     WebRpcResponse webResponse = new WebRpcResponse(operationResponse);
+    ///     if (webResponse.ReturnCode != 0) { //...
+    ///     }
+    ///
+    ///     switch (webResponse.Name) { //...
+    ///     }
+    ///     // and so on
+    /// }
+ ///
+ public static bool WebRpc(string name, object parameters) + { + return networkingPeer.WebRpc(name, parameters); + } + + +#if UNITY_EDITOR + [Conditional("UNITY_EDITOR")] + public static void CreateSettings() + { + PhotonNetwork.PhotonServerSettings = (ServerSettings)Resources.Load(PhotonNetwork.serverSettingsAssetFile, typeof(ServerSettings)); + if (PhotonNetwork.PhotonServerSettings != null) + { + return; + } + + // find out if ServerSettings can be instantiated (existing script check) + ScriptableObject serverSettingTest = ScriptableObject.CreateInstance("ServerSettings"); + if (serverSettingTest == null) + { + Debug.LogError("missing settings script"); + return; + } + UnityEngine.Object.DestroyImmediate(serverSettingTest); + + + // if still not loaded, create one + if (PhotonNetwork.PhotonServerSettings == null) + { + string settingsPath = Path.GetDirectoryName(PhotonNetwork.serverSettingsAssetPath); + if (!Directory.Exists(settingsPath)) + { + Directory.CreateDirectory(settingsPath); + AssetDatabase.ImportAsset(settingsPath); + } + + PhotonNetwork.PhotonServerSettings = (ServerSettings)ScriptableObject.CreateInstance("ServerSettings"); + if (PhotonNetwork.PhotonServerSettings != null) + { + AssetDatabase.CreateAsset(PhotonNetwork.PhotonServerSettings, PhotonNetwork.serverSettingsAssetPath); + } + else + { + Debug.LogError("PUN failed creating a settings file. ScriptableObject.CreateInstance(\"ServerSettings\") returned null. Will try again later."); + } + } + } + + + /// + /// Internally used by Editor scripts, called on Hierarchy change (includes scene save) to remove surplus hidden PhotonHandlers. + /// + public static void InternalCleanPhotonMonoFromSceneIfStuck() + { + PhotonHandler[] photonHandlers = GameObject.FindObjectsOfType(typeof(PhotonHandler)) as PhotonHandler[]; + if (photonHandlers != null && photonHandlers.Length > 0) + { + Debug.Log("Cleaning up hidden PhotonHandler instances in scene. Please save it. This is not an issue."); + foreach (PhotonHandler photonHandler in photonHandlers) + { + // Debug.Log("Removing Handler: " + photonHandler + " photonHandler.gameObject: " + photonHandler.gameObject); + photonHandler.gameObject.hideFlags = 0; + + if (photonHandler.gameObject != null && photonHandler.gameObject.name == "PhotonMono") + { + GameObject.DestroyImmediate(photonHandler.gameObject); + } + + Component.DestroyImmediate(photonHandler); + } + } + } +#endif + +} diff --git a/Assets/Photon Unity Networking/Plugins/PhotonNetwork/PhotonNetwork.cs.meta b/Assets/Photon Unity Networking/Plugins/PhotonNetwork/PhotonNetwork.cs.meta new file mode 100644 index 0000000..23f48a0 --- /dev/null +++ b/Assets/Photon Unity Networking/Plugins/PhotonNetwork/PhotonNetwork.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 88e11b3353de7e94d84b1ec5adbdd15e +labels: +- ExitGames +- PUN +- Photon +- Networking +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} diff --git a/Assets/Photon Unity Networking/Plugins/PhotonNetwork/PhotonPlayer.cs b/Assets/Photon Unity Networking/Plugins/PhotonNetwork/PhotonPlayer.cs new file mode 100644 index 0000000..6ea4946 --- /dev/null +++ b/Assets/Photon Unity Networking/Plugins/PhotonNetwork/PhotonPlayer.cs @@ -0,0 +1,428 @@ +// ---------------------------------------------------------------------------- +// +// PhotonNetwork Framework for Unity - Copyright (C) 2011 Exit Games GmbH +// +// +// Represents a player, identified by actorID (a.k.a. ActorNumber). +// Caches properties of a player. +// +// developer@exitgames.com +// ---------------------------------------------------------------------------- + +using System; +using System.Collections.Generic; +using ExitGames.Client.Photon; +using UnityEngine; +using Hashtable = ExitGames.Client.Photon.Hashtable; + + +/// +/// Summarizes a "player" within a room, identified (in that room) by actorID. +/// +/// +/// Each player has an actorId (or ID), valid for that room. It's -1 until it's assigned by server. +/// Each client can set it's player's custom properties with SetCustomProperties, even before being in a room. +/// They are synced when joining a room. +/// +/// \ingroup publicApi +public class PhotonPlayer : IComparable, IComparable, IEquatable, IEquatable +{ + /// This player's actorID + public int ID + { + get { return this.actorID; } + } + + /// Identifier of this player in current room. + private int actorID = -1; + + private string nameField = ""; + + /// Nickname of this player. + /// Set the PhotonNetwork.playerName to make the name synchronized in a room. + public string NickName + { + get + { + return this.nameField; + } + set + { + if (!IsLocal) + { + Debug.LogError("Error: Cannot change the name of a remote player!"); + return; + } + if (string.IsNullOrEmpty(value) || value.Equals(this.nameField)) + { + return; + } + + this.nameField = value; + PhotonNetwork.playerName = value; // this will sync the local player's name in a room + } + } + + /// UserId of the player, available when the room got created with RoomOptions.PublishUserId = true. + /// Useful for PhotonNetwork.FindFriends and blocking slots in a room for expected players (e.g. in PhotonNetwork.CreateRoom). + public string UserId { get; internal set; } + + /// Only one player is controlled by each client. Others are not local. + public readonly bool IsLocal = false; + + /// + /// True if this player is the Master Client of the current room. + /// + /// + /// See also: PhotonNetwork.masterClient. + /// + public bool IsMasterClient + { + get { return (PhotonNetwork.networkingPeer.mMasterClientId == this.ID); } + } + + /// Players might be inactive in a room when PlayerTTL for a room is > 0. If true, the player is not getting events from this room (now) but can return later. + public bool IsInactive { get; set; } // needed for rejoins + + /// Read-only cache for custom properties of player. Set via PhotonPlayer.SetCustomProperties. + /// + /// Don't modify the content of this Hashtable. Use SetCustomProperties and the + /// properties of this class to modify values. When you use those, the client will + /// sync values with the server. + /// + /// + public Hashtable CustomProperties { get; internal set; } + + /// Creates a Hashtable with all properties (custom and "well known" ones). + /// If used more often, this should be cached. + public Hashtable AllProperties + { + get + { + Hashtable allProps = new Hashtable(); + allProps.Merge(this.CustomProperties); + allProps[ActorProperties.PlayerName] = this.NickName; + return allProps; + } + } + + /// Can be used to store a reference that's useful to know "by player". + /// Example: Set a player's character as Tag by assigning the GameObject on Instantiate. + public object TagObject; + + + /// + /// Creates a PhotonPlayer instance. + /// + /// If this is the local peer's player (or a remote one). + /// ID or ActorNumber of this player in the current room (a shortcut to identify each player in room) + /// Name of the player (a "well known property"). + public PhotonPlayer(bool isLocal, int actorID, string name) + { + this.CustomProperties = new Hashtable(); + this.IsLocal = isLocal; + this.actorID = actorID; + this.nameField = name; + } + + /// + /// Internally used to create players from event Join + /// + protected internal PhotonPlayer(bool isLocal, int actorID, Hashtable properties) + { + this.CustomProperties = new Hashtable(); + this.IsLocal = isLocal; + this.actorID = actorID; + + this.InternalCacheProperties(properties); + } + + /// + /// Makes PhotonPlayer comparable + /// + public override bool Equals(object p) + { + PhotonPlayer pp = p as PhotonPlayer; + return (pp != null && this.GetHashCode() == pp.GetHashCode()); + } + + public override int GetHashCode() + { + return this.ID; + } + + /// + /// Used internally, to update this client's playerID when assigned. + /// + internal void InternalChangeLocalID(int newID) + { + if (!this.IsLocal) + { + Debug.LogError("ERROR You should never change PhotonPlayer IDs!"); + return; + } + + this.actorID = newID; + } + + /// + /// Caches custom properties for this player. + /// + internal void InternalCacheProperties(Hashtable properties) + { + if (properties == null || properties.Count == 0 || this.CustomProperties.Equals(properties)) + { + return; + } + + if (properties.ContainsKey(ActorProperties.PlayerName)) + { + this.nameField = (string)properties[ActorProperties.PlayerName]; + } + if (properties.ContainsKey(ActorProperties.UserId)) + { + this.UserId = (string)properties[ActorProperties.UserId]; + } + if (properties.ContainsKey(ActorProperties.IsInactive)) + { + this.IsInactive = (bool)properties[ActorProperties.IsInactive]; //TURNBASED new well-known propery for players + } + + this.CustomProperties.MergeStringKeys(properties); + this.CustomProperties.StripKeysWithNullValues(); + } + + + /// + /// Updates the this player's Custom Properties with new/updated key-values. + /// + /// + /// Custom Properties are a key-value set (Hashtable) which is available to all players in a room. + /// They can relate to the room or individual players and are useful when only the current value + /// of something is of interest. For example: The map of a room. + /// All keys must be strings. + /// + /// The Room and the PhotonPlayer class both have SetCustomProperties methods. + /// Also, both classes offer access to current key-values by: customProperties. + /// + /// Always use SetCustomProperties to change values. + /// To reduce network traffic, set only values that actually changed. + /// New properties are added, existing values are updated. + /// Other values will not be changed, so only provide values that changed or are new. + /// + /// To delete a named (custom) property of this room, use null as value. + /// + /// Locally, SetCustomProperties will update it's cache without delay. + /// Other clients are updated through Photon (the server) with a fitting operation. + /// + /// Check and Swap + /// + /// SetCustomProperties have the option to do a server-side Check-And-Swap (CAS): + /// Values only get updated if the expected values are correct. + /// The expectedValues can be different key/values than the propertiesToSet. So you can + /// check some key and set another key's value (if the check succeeds). + /// + /// If the client's knowledge of properties is wrong or outdated, it can't set values with CAS. + /// This can be useful to keep players from concurrently setting values. For example: If all players + /// try to pickup some card or item, only one should get it. With CAS, only the first SetProperties + /// gets executed server-side and any other (sent at the same time) fails. + /// + /// The server will broadcast successfully changed values and the local "cache" of customProperties + /// only gets updated after a roundtrip (if anything changed). + /// + /// You can do a "webForward": Photon will send the changed properties to a WebHook defined + /// for your application. + /// + /// OfflineMode + /// + /// While PhotonNetwork.offlineMode is true, the expectedValues and webForward parameters are ignored. + /// In OfflineMode, the local customProperties values are immediately updated (without the roundtrip). + /// + /// The new properties to be set. + /// At least one property key/value set to check server-side. Key and value must be correct. Ignored in OfflineMode. + /// Set to true, to forward the set properties to a WebHook, defined for this app (in Dashboard). Ignored in OfflineMode. + public void SetCustomProperties(Hashtable propertiesToSet, Hashtable expectedValues = null, bool webForward = false) + { + if (propertiesToSet == null) + { + return; + } + + Hashtable customProps = propertiesToSet.StripToStringKeys() as Hashtable; + Hashtable customPropsToCheck = expectedValues.StripToStringKeys() as Hashtable; + + + // no expected values -> set and callback + bool noCas = customPropsToCheck == null || customPropsToCheck.Count == 0; + bool inOnlineRoom = this.actorID > 0 && !PhotonNetwork.offlineMode; + + if (noCas) + { + this.CustomProperties.Merge(customProps); + this.CustomProperties.StripKeysWithNullValues(); + } + + if (inOnlineRoom) + { + PhotonNetwork.networkingPeer.OpSetPropertiesOfActor(this.actorID, customProps, customPropsToCheck, webForward); + } + + if (!inOnlineRoom || noCas) + { + this.InternalCacheProperties(customProps); + NetworkingPeer.SendMonoMessage(PhotonNetworkingMessage.OnPhotonPlayerPropertiesChanged, this, customProps); + } + } + + /// + /// Try to get a specific player by id. + /// + /// ActorID + /// The player with matching actorID or null, if the actorID is not in use. + public static PhotonPlayer Find(int ID) + { + if (PhotonNetwork.networkingPeer != null) + { + return PhotonNetwork.networkingPeer.GetPlayerWithId(ID); + } + return null; + } + + public PhotonPlayer Get(int id) + { + return PhotonPlayer.Find(id); + } + + public PhotonPlayer GetNext() + { + return GetNextFor(this.ID); + } + + public PhotonPlayer GetNextFor(PhotonPlayer currentPlayer) + { + if (currentPlayer == null) + { + return null; + } + return GetNextFor(currentPlayer.ID); + } + + public PhotonPlayer GetNextFor(int currentPlayerId) + { + if (PhotonNetwork.networkingPeer == null || PhotonNetwork.networkingPeer.mActors == null || PhotonNetwork.networkingPeer.mActors.Count < 2) + { + return null; + } + + Dictionary players = PhotonNetwork.networkingPeer.mActors; + int nextHigherId = int.MaxValue; // we look for the next higher ID + int lowestId = currentPlayerId; // if we are the player with the highest ID, there is no higher and we return to the lowest player's id + + foreach (int playerid in players.Keys) + { + if (playerid < lowestId) + { + lowestId = playerid; // less than any other ID (which must be at least less than this player's id). + } + else if (playerid > currentPlayerId && playerid < nextHigherId) + { + nextHigherId = playerid; // more than our ID and less than those found so far. + } + } + + //UnityEngine.Debug.LogWarning("Debug. " + currentPlayerId + " lower: " + lowestId + " higher: " + nextHigherId + " "); + //UnityEngine.Debug.LogWarning(this.RoomReference.GetPlayer(currentPlayerId)); + //UnityEngine.Debug.LogWarning(this.RoomReference.GetPlayer(lowestId)); + //if (nextHigherId != int.MaxValue) UnityEngine.Debug.LogWarning(this.RoomReference.GetPlayer(nextHigherId)); + return (nextHigherId != int.MaxValue) ? players[nextHigherId] : players[lowestId]; + } + + #region IComparable implementation + + public int CompareTo (PhotonPlayer other) + { + if ( other == null) + { + return 0; + } + + return this.GetHashCode().CompareTo(other.GetHashCode()); + } + + public int CompareTo (int other) + { + return this.GetHashCode().CompareTo(other); + } + + #endregion + + #region IEquatable implementation + + public bool Equals (PhotonPlayer other) + { + if ( other == null) + { + return false; + } + + return this.GetHashCode().Equals(other.GetHashCode()); + } + + public bool Equals (int other) + { + return this.GetHashCode().Equals(other); + } + + #endregion + + /// + /// Brief summary string of the PhotonPlayer. Includes name or player.ID and if it's the Master Client. + /// + public override string ToString() + { + if (string.IsNullOrEmpty(this.NickName)) + { + return string.Format("#{0:00}{1}{2}", this.ID, this.IsInactive ? " (inactive)" : " ", this.IsMasterClient ? "(master)":""); + } + + return string.Format("'{0}'{1}{2}", this.NickName, this.IsInactive ? " (inactive)" : " ", this.IsMasterClient ? "(master)" : ""); + } + + /// + /// String summary of the PhotonPlayer: player.ID, name and all custom properties of this user. + /// + /// + /// Use with care and not every frame! + /// Converts the customProperties to a String on every single call. + /// + public string ToStringFull() + { + return string.Format("#{0:00} '{1}'{2} {3}", this.ID, this.NickName, this.IsInactive ? " (inactive)" : "", this.CustomProperties.ToStringFull()); + } + + + #region Obsoleted variable names + + [Obsolete("Please use NickName (updated case for naming).")] + public string name { get { return this.NickName; } set { this.NickName = value; } } + + [Obsolete("Please use UserId (updated case for naming).")] + public string userId { get { return this.UserId; } internal set { this.UserId = value; } } + + [Obsolete("Please use IsLocal (updated case for naming).")] + public bool isLocal { get { return this.IsLocal; } } + + [Obsolete("Please use IsMasterClient (updated case for naming).")] + public bool isMasterClient { get { return this.IsMasterClient; } } + + [Obsolete("Please use IsInactive (updated case for naming).")] + public bool isInactive { get { return this.IsInactive; } set { this.IsInactive = value; } } + + [Obsolete("Please use CustomProperties (updated case for naming).")] + public Hashtable customProperties { get { return this.CustomProperties; } internal set { this.CustomProperties = value; } } + + [Obsolete("Please use AllProperties (updated case for naming).")] + public Hashtable allProperties { get { return this.AllProperties; } } + + #endregion +} diff --git a/Assets/Photon Unity Networking/Plugins/PhotonNetwork/PhotonPlayer.cs.meta b/Assets/Photon Unity Networking/Plugins/PhotonNetwork/PhotonPlayer.cs.meta new file mode 100644 index 0000000..d494ca7 --- /dev/null +++ b/Assets/Photon Unity Networking/Plugins/PhotonNetwork/PhotonPlayer.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: e3e4b5bebc687044b9c6c2803c36be3d +labels: +- ExitGames +- PUN +- Photon +- Networking +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} diff --git a/Assets/Photon Unity Networking/Plugins/PhotonNetwork/PhotonStatsGui.cs b/Assets/Photon Unity Networking/Plugins/PhotonNetwork/PhotonStatsGui.cs new file mode 100644 index 0000000..2f8a4c2 --- /dev/null +++ b/Assets/Photon Unity Networking/Plugins/PhotonNetwork/PhotonStatsGui.cs @@ -0,0 +1,159 @@ +#pragma warning disable 1587 +/// \file +/// Part of the [Optional GUI](@ref optionalGui). +#pragma warning restore 1587 + + +using ExitGames.Client.Photon; +using UnityEngine; + + +/// +/// Basic GUI to show traffic and health statistics of the connection to Photon, +/// toggled by shift+tab. +/// +/// +/// The shown health values can help identify problems with connection losses or performance. +/// Example: +/// If the time delta between two consecutive SendOutgoingCommands calls is a second or more, +/// chances rise for a disconnect being caused by this (because acknowledgements to the server +/// need to be sent in due time). +/// +/// \ingroup optionalGui +public class PhotonStatsGui : MonoBehaviour +{ + /// Shows or hides GUI (does not affect if stats are collected). + public bool statsWindowOn = true; + + /// Option to turn collecting stats on or off (used in Update()). + public bool statsOn = true; + + /// Shows additional "health" values of connection. + public bool healthStatsVisible; + + /// Shows additional "lower level" traffic stats. + public bool trafficStatsOn; + + /// Show buttons to control stats and reset them. + public bool buttonsOn; + + /// Positioning rect for window. + public Rect statsRect = new Rect(0, 100, 200, 50); + + /// Unity GUI Window ID (must be unique or will cause issues). + public int WindowId = 100; + + + public void Start() + { + if (this.statsRect.x <= 0) + { + this.statsRect.x = Screen.width - this.statsRect.width; + } + } + + /// Checks for shift+tab input combination (to toggle statsOn). + public void Update() + { + if (Input.GetKeyDown(KeyCode.Tab) && Input.GetKey(KeyCode.LeftShift)) + { + this.statsWindowOn = !this.statsWindowOn; + this.statsOn = true; // enable stats when showing the window + } + } + + public void OnGUI() + { + if (PhotonNetwork.networkingPeer.TrafficStatsEnabled != statsOn) + { + PhotonNetwork.networkingPeer.TrafficStatsEnabled = this.statsOn; + } + + if (!this.statsWindowOn) + { + return; + } + + this.statsRect = GUILayout.Window(this.WindowId, this.statsRect, this.TrafficStatsWindow, "Messages (shift+tab)"); + } + + public void TrafficStatsWindow(int windowID) + { + bool statsToLog = false; + TrafficStatsGameLevel gls = PhotonNetwork.networkingPeer.TrafficStatsGameLevel; + long elapsedMs = PhotonNetwork.networkingPeer.TrafficStatsElapsedMs / 1000; + if (elapsedMs == 0) + { + elapsedMs = 1; + } + + GUILayout.BeginHorizontal(); + this.buttonsOn = GUILayout.Toggle(this.buttonsOn, "buttons"); + this.healthStatsVisible = GUILayout.Toggle(this.healthStatsVisible, "health"); + this.trafficStatsOn = GUILayout.Toggle(this.trafficStatsOn, "traffic"); + GUILayout.EndHorizontal(); + + string total = string.Format("Out {0,4} | In {1,4} | Sum {2,4}", gls.TotalOutgoingMessageCount, gls.TotalIncomingMessageCount, gls.TotalMessageCount); + string elapsedTime = string.Format("{0}sec average:", elapsedMs); + string average = string.Format("Out {0,4} | In {1,4} | Sum {2,4}", gls.TotalOutgoingMessageCount / elapsedMs, gls.TotalIncomingMessageCount / elapsedMs, gls.TotalMessageCount / elapsedMs); + GUILayout.Label(total); + GUILayout.Label(elapsedTime); + GUILayout.Label(average); + + if (this.buttonsOn) + { + GUILayout.BeginHorizontal(); + this.statsOn = GUILayout.Toggle(this.statsOn, "stats on"); + if (GUILayout.Button("Reset")) + { + PhotonNetwork.networkingPeer.TrafficStatsReset(); + PhotonNetwork.networkingPeer.TrafficStatsEnabled = true; + } + statsToLog = GUILayout.Button("To Log"); + GUILayout.EndHorizontal(); + } + + string trafficStatsIn = string.Empty; + string trafficStatsOut = string.Empty; + if (this.trafficStatsOn) + { + GUILayout.Box("Traffic Stats"); + trafficStatsIn = "Incoming: \n" + PhotonNetwork.networkingPeer.TrafficStatsIncoming.ToString(); + trafficStatsOut = "Outgoing: \n" + PhotonNetwork.networkingPeer.TrafficStatsOutgoing.ToString(); + GUILayout.Label(trafficStatsIn); + GUILayout.Label(trafficStatsOut); + } + + string healthStats = string.Empty; + if (this.healthStatsVisible) + { + GUILayout.Box("Health Stats"); + healthStats = string.Format( + "ping: {6}[+/-{7}]ms resent:{8} \n\nmax ms between\nsend: {0,4} \ndispatch: {1,4} \n\nlongest dispatch for: \nev({3}):{2,3}ms \nop({5}):{4,3}ms", + gls.LongestDeltaBetweenSending, + gls.LongestDeltaBetweenDispatching, + gls.LongestEventCallback, + gls.LongestEventCallbackCode, + gls.LongestOpResponseCallback, + gls.LongestOpResponseCallbackOpCode, + PhotonNetwork.networkingPeer.RoundTripTime, + PhotonNetwork.networkingPeer.RoundTripTimeVariance, + PhotonNetwork.networkingPeer.ResentReliableCommands); + GUILayout.Label(healthStats); + } + + if (statsToLog) + { + string complete = string.Format("{0}\n{1}\n{2}\n{3}\n{4}\n{5}", total, elapsedTime, average, trafficStatsIn, trafficStatsOut, healthStats); + Debug.Log(complete); + } + + // if anything was clicked, the height of this window is likely changed. reduce it to be layouted again next frame + if (GUI.changed) + { + this.statsRect.height = 100; + } + + GUI.DragWindow(); + } +} diff --git a/Assets/Photon Unity Networking/Plugins/PhotonNetwork/PhotonStatsGui.cs.meta b/Assets/Photon Unity Networking/Plugins/PhotonNetwork/PhotonStatsGui.cs.meta new file mode 100644 index 0000000..dc1049b --- /dev/null +++ b/Assets/Photon Unity Networking/Plugins/PhotonNetwork/PhotonStatsGui.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: d06466c03d263624786afa88b52928b6 +labels: +- ExitGames +- PUN +- Photon +- Networking +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} diff --git a/Assets/Photon Unity Networking/Plugins/PhotonNetwork/PhotonStreamQueue.cs b/Assets/Photon Unity Networking/Plugins/PhotonNetwork/PhotonStreamQueue.cs new file mode 100644 index 0000000..ec3f9c6 --- /dev/null +++ b/Assets/Photon Unity Networking/Plugins/PhotonNetwork/PhotonStreamQueue.cs @@ -0,0 +1,187 @@ +using System.Collections.Generic; +using UnityEngine; + +/// +/// The PhotonStreamQueue helps you poll object states at higher frequencies then what +/// PhotonNetwork.sendRate dictates and then sends all those states at once when +/// Serialize() is called. +/// On the receiving end you can call Deserialize() and then the stream will roll out +/// the received object states in the same order and timeStep they were recorded in. +/// +public class PhotonStreamQueue +{ + #region Members + + private int m_SampleRate; + private int m_SampleCount; + private int m_ObjectsPerSample = -1; + + private float m_LastSampleTime = -Mathf.Infinity; + private int m_LastFrameCount = -1; + private int m_NextObjectIndex = -1; + + private List m_Objects = new List(); + + private bool m_IsWriting; + + #endregion + + /// + /// Initializes a new instance of the class. + /// + /// How many times per second should the object states be sampled + public PhotonStreamQueue(int sampleRate) + { + this.m_SampleRate = sampleRate; + } + + private void BeginWritePackage() + { + //If not enough time has passed since the last sample, we don't want to write anything + if (Time.realtimeSinceStartup < this.m_LastSampleTime + 1f/this.m_SampleRate) + { + this.m_IsWriting = false; + return; + } + + if (this.m_SampleCount == 1) + { + this.m_ObjectsPerSample = this.m_Objects.Count; + //Debug.Log( "Setting m_ObjectsPerSample to " + m_ObjectsPerSample ); + } + else if (this.m_SampleCount > 1) + { + if (this.m_Objects.Count/this.m_SampleCount != this.m_ObjectsPerSample) + { + Debug.LogWarning("The number of objects sent via a PhotonStreamQueue has to be the same each frame"); + Debug.LogWarning("Objects in List: " + this.m_Objects.Count + " / Sample Count: " + this.m_SampleCount + " = " + (this.m_Objects.Count/this.m_SampleCount) + " != " + this.m_ObjectsPerSample); + } + } + + this.m_IsWriting = true; + this.m_SampleCount++; + this.m_LastSampleTime = Time.realtimeSinceStartup; + + /*if( m_SampleCount > 1 ) + { + Debug.Log( "Check: " + m_Objects.Count + " / " + m_SampleCount + " = " + ( m_Objects.Count / m_SampleCount ) + " = " + m_ObjectsPerSample ); + }*/ + } + + /// + /// Resets the PhotonStreamQueue. You need to do this whenever the amount of objects you are observing changes + /// + public void Reset() + { + this.m_SampleCount = 0; + this.m_ObjectsPerSample = -1; + + this.m_LastSampleTime = -Mathf.Infinity; + this.m_LastFrameCount = -1; + + this.m_Objects.Clear(); + } + + /// + /// Adds the next object to the queue. This works just like PhotonStream.SendNext + /// + /// The object you want to add to the queue + public void SendNext(object obj) + { + if (Time.frameCount != this.m_LastFrameCount) + { + BeginWritePackage(); + } + + this.m_LastFrameCount = Time.frameCount; + + if (this.m_IsWriting == false) + { + return; + } + + this.m_Objects.Add(obj); + } + + /// + /// Determines whether the queue has stored any objects + /// + public bool HasQueuedObjects() + { + return this.m_NextObjectIndex != -1; + } + + /// + /// Receives the next object from the queue. This works just like PhotonStream.ReceiveNext + /// + /// + public object ReceiveNext() + { + if (this.m_NextObjectIndex == -1) + { + return null; + } + + if (this.m_NextObjectIndex >= this.m_Objects.Count) + { + this.m_NextObjectIndex -= this.m_ObjectsPerSample; + } + + return this.m_Objects[this.m_NextObjectIndex++]; + } + + /// + /// Serializes the specified stream. Call this in your OnPhotonSerializeView method to send the whole recorded stream. + /// + /// The PhotonStream you receive as a parameter in OnPhotonSerializeView + public void Serialize(PhotonStream stream) + { + // TODO: find a better solution for this: + // the "if" is a workaround for packages which have only 1 sample/frame. in that case, SendNext didn't set the obj per sample. + if (m_Objects.Count > 0 && this.m_ObjectsPerSample < 0) + { + this.m_ObjectsPerSample = m_Objects.Count; + } + + stream.SendNext(this.m_SampleCount); + stream.SendNext(this.m_ObjectsPerSample); + + for (int i = 0; i < this.m_Objects.Count; ++i) + { + stream.SendNext(this.m_Objects[i]); + } + + //Debug.Log( "Serialize " + m_SampleCount + " samples with " + m_ObjectsPerSample + " objects per sample. object count: " + m_Objects.Count + " / " + ( m_SampleCount * m_ObjectsPerSample ) ); + + this.m_Objects.Clear(); + this.m_SampleCount = 0; + } + + /// + /// Deserializes the specified stream. Call this in your OnPhotonSerializeView method to receive the whole recorded stream. + /// + /// The PhotonStream you receive as a parameter in OnPhotonSerializeView + public void Deserialize(PhotonStream stream) + { + this.m_Objects.Clear(); + + this.m_SampleCount = (int)stream.ReceiveNext(); + this.m_ObjectsPerSample = (int)stream.ReceiveNext(); + + for (int i = 0; i < this.m_SampleCount*this.m_ObjectsPerSample; ++i) + { + this.m_Objects.Add(stream.ReceiveNext()); + } + + if (this.m_Objects.Count > 0) + { + this.m_NextObjectIndex = 0; + } + else + { + this.m_NextObjectIndex = -1; + } + + //Debug.Log( "Deserialized " + m_SampleCount + " samples with " + m_ObjectsPerSample + " objects per sample. object count: " + m_Objects.Count + " / " + ( m_SampleCount * m_ObjectsPerSample ) ); + } +} \ No newline at end of file diff --git a/Assets/Photon Unity Networking/Plugins/PhotonNetwork/PhotonStreamQueue.cs.meta b/Assets/Photon Unity Networking/Plugins/PhotonNetwork/PhotonStreamQueue.cs.meta new file mode 100644 index 0000000..b225d0d --- /dev/null +++ b/Assets/Photon Unity Networking/Plugins/PhotonNetwork/PhotonStreamQueue.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 006991e32d9020c4d896f161318a2bc0 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Photon Unity Networking/Plugins/PhotonNetwork/PhotonView.cs b/Assets/Photon Unity Networking/Plugins/PhotonNetwork/PhotonView.cs new file mode 100644 index 0000000..0600a56 --- /dev/null +++ b/Assets/Photon Unity Networking/Plugins/PhotonNetwork/PhotonView.cs @@ -0,0 +1,692 @@ +// ---------------------------------------------------------------------------- +// +// PhotonNetwork Framework for Unity - Copyright (C) 2011 Exit Games GmbH +// +// +// +// +// developer@exitgames.com +// ---------------------------------------------------------------------------- + +using System; +using UnityEngine; +using System.Reflection; +using System.Collections.Generic; +using ExitGames.Client.Photon; + +#if UNITY_EDITOR +using UnityEditor; +#endif + + +public enum ViewSynchronization { Off, ReliableDeltaCompressed, Unreliable, UnreliableOnChange } +public enum OnSerializeTransform { OnlyPosition, OnlyRotation, OnlyScale, PositionAndRotation, All } +public enum OnSerializeRigidBody { OnlyVelocity, OnlyAngularVelocity, All } + +/// +/// Options to define how Ownership Transfer is handled per PhotonView. +/// +/// +/// This setting affects how RequestOwnership and TransferOwnership work at runtime. +/// +public enum OwnershipOption +{ + /// + /// Ownership is fixed. Instantiated objects stick with their creator, scene objects always belong to the Master Client. + /// + Fixed, + /// + /// Ownership can be taken away from the current owner who can't object. + /// + Takeover, + /// + /// Ownership can be requested with PhotonView.RequestOwnership but the current owner has to agree to give up ownership. + /// + /// The current owner has to implement IPunCallbacks.OnOwnershipRequest to react to the ownership request. + Request +} + + +/// +/// PUN's NetworkView replacement class for networking. Use it like a NetworkView. +/// +/// \ingroup publicApi +[AddComponentMenu("Photon Networking/Photon View &v")] +public class PhotonView : Photon.MonoBehaviour +{ + #if UNITY_EDITOR + [ContextMenu("Open PUN Wizard")] + void OpenPunWizard() + { + EditorApplication.ExecuteMenuItem("Window/Photon Unity Networking"); + } + #endif + + public int ownerId; + + public byte group = 0; + + protected internal bool mixedModeIsReliable = false; + + + /// + /// Flag to check if ownership of this photonView was set during the lifecycle. Used for checking when joining late if event with mismatched owner and sender needs addressing. + /// + /// true if owner ship was transfered; otherwise, false. + public bool OwnerShipWasTransfered; + + + // NOTE: this is now an integer because unity won't serialize short (needed for instantiation). we SEND only a short though! + // NOTE: prefabs have a prefixBackup of -1. this is replaced with any currentLevelPrefix that's used at runtime. instantiated GOs get their prefix set pre-instantiation (so those are not -1 anymore) + public int prefix + { + get + { + if (this.prefixBackup == -1 && PhotonNetwork.networkingPeer != null) + { + this.prefixBackup = PhotonNetwork.networkingPeer.currentLevelPrefix; + } + + return this.prefixBackup; + } + set { this.prefixBackup = value; } + } + + // this field is serialized by unity. that means it is copied when instantiating a persistent obj into the scene + public int prefixBackup = -1; + + /// + /// This is the instantiationData that was passed when calling PhotonNetwork.Instantiate* (if that was used to spawn this prefab) + /// + public object[] instantiationData + { + get + { + if (!this.didAwake) + { + // even though viewID and instantiationID are setup before the GO goes live, this data can't be set. as workaround: fetch it if needed + this.instantiationDataField = PhotonNetwork.networkingPeer.FetchInstantiationData(this.instantiationId); + } + return this.instantiationDataField; + } + set { this.instantiationDataField = value; } + } + + internal object[] instantiationDataField; + + /// + /// For internal use only, don't use + /// + protected internal object[] lastOnSerializeDataSent = null; + + /// + /// For internal use only, don't use + /// + protected internal object[] lastOnSerializeDataReceived = null; + + public ViewSynchronization synchronization; + + public OnSerializeTransform onSerializeTransformOption = OnSerializeTransform.PositionAndRotation; + + public OnSerializeRigidBody onSerializeRigidBodyOption = OnSerializeRigidBody.All; + + /// Defines if ownership of this PhotonView is fixed, can be requested or simply taken. + /// + /// Note that you can't edit this value at runtime. + /// The options are described in enum OwnershipOption. + /// The current owner has to implement IPunCallbacks.OnOwnershipRequest to react to the ownership request. + /// + public OwnershipOption ownershipTransfer = OwnershipOption.Fixed; + + public List ObservedComponents; + Dictionary m_OnSerializeMethodInfos = new Dictionary(3); + +#if UNITY_EDITOR + // Suppressing compiler warning "this variable is never used". Only used in the CustomEditor, only in Editor + #pragma warning disable 0414 + [SerializeField] + bool ObservedComponentsFoldoutOpen = true; + #pragma warning restore 0414 +#endif + + [SerializeField] + private int viewIdField = 0; + + /// + /// The ID of the PhotonView. Identifies it in a networked game (per room). + /// + /// See: [Network Instantiation](@ref instantiateManual) + public int viewID + { + get { return this.viewIdField; } + set + { + // if ID was 0 for an awakened PhotonView, the view should add itself into the networkingPeer.photonViewList after setup + bool viewMustRegister = this.didAwake && this.viewIdField == 0; + + // TODO: decide if a viewID can be changed once it wasn't 0. most likely that is not a good idea + // check if this view is in networkingPeer.photonViewList and UPDATE said list (so we don't keep the old viewID with a reference to this object) + // PhotonNetwork.networkingPeer.RemovePhotonView(this, true); + + this.ownerId = value / PhotonNetwork.MAX_VIEW_IDS; + + this.viewIdField = value; + + if (viewMustRegister) + { + PhotonNetwork.networkingPeer.RegisterPhotonView(this); + } + //Debug.Log("Set viewID: " + value + " -> owner: " + this.ownerId + " subId: " + this.subId); + } + } + + public int instantiationId; // if the view was instantiated with a GO, this GO has a instantiationID (first view's viewID) + + /// True if the PhotonView was loaded with the scene (game object) or instantiated with InstantiateSceneObject. + /// + /// Scene objects are not owned by a particular player but belong to the scene. Thus they don't get destroyed when their + /// creator leaves the game and the current Master Client can control them (whoever that is). + /// The ownerId is 0 (player IDs are 1 and up). + /// + public bool isSceneView + { + get { return this.CreatorActorNr == 0; } + } + + /// + /// The owner of a PhotonView is the player who created the GameObject with that view. Objects in the scene don't have an owner. + /// + /// + /// The owner/controller of a PhotonView is also the client which sends position updates of the GameObject. + /// + /// Ownership can be transferred to another player with PhotonView.TransferOwnership or any player can request + /// ownership by calling the PhotonView's RequestOwnership method. + /// The current owner has to implement IPunCallbacks.OnOwnershipRequest to react to the ownership request. + /// + public PhotonPlayer owner + { + get + { + return PhotonPlayer.Find(this.ownerId); + } + } + + public int OwnerActorNr + { + get { return this.ownerId; } + } + + public bool isOwnerActive + { + get { return this.ownerId != 0 && PhotonNetwork.networkingPeer.mActors.ContainsKey(this.ownerId); } + } + + public int CreatorActorNr + { + get { return this.viewIdField / PhotonNetwork.MAX_VIEW_IDS; } + } + + /// + /// True if the PhotonView is "mine" and can be controlled by this client. + /// + /// + /// PUN has an ownership concept that defines who can control and destroy each PhotonView. + /// True in case the owner matches the local PhotonPlayer. + /// True if this is a scene photonview on the Master client. + /// + public bool isMine + { + get + { + return (this.ownerId == PhotonNetwork.player.ID) || (!this.isOwnerActive && PhotonNetwork.isMasterClient); + } + } + + /// + /// The current master ID so that we can compare when we receive OnMasterClientSwitched() callback + /// It's public so that we can check it during ownerId assignments in networkPeer script + /// TODO: Maybe we can have the networkPeer always aware of the previous MasterClient? + /// + public int currentMasterID = -1; + protected internal bool didAwake; + + [SerializeField] + protected internal bool isRuntimeInstantiated; + + protected internal bool removedFromLocalViewList; + + internal MonoBehaviour[] RpcMonoBehaviours; + private MethodInfo OnSerializeMethodInfo; + + private bool failedToFindOnSerialize; + + /// Called by Unity on start of the application and does a setup the PhotonView. + protected internal void Awake() + { + if (this.viewID != 0) + { + // registration might be too late when some script (on this GO) searches this view BUT GetPhotonView() can search ALL in that case + PhotonNetwork.networkingPeer.RegisterPhotonView(this); + this.instantiationDataField = PhotonNetwork.networkingPeer.FetchInstantiationData(this.instantiationId); + } + + this.didAwake = true; + } + + /// + /// Depending on the PhotonView's ownershipTransfer setting, any client can request to become owner of the PhotonView. + /// + /// + /// Requesting ownership can give you control over a PhotonView, if the ownershipTransfer setting allows that. + /// The current owner might have to implement IPunCallbacks.OnOwnershipRequest to react to the ownership request. + /// + /// The owner/controller of a PhotonView is also the client which sends position updates of the GameObject. + /// + public void RequestOwnership() + { + PhotonNetwork.networkingPeer.RequestOwnership(this.viewID, this.ownerId); + } + + /// + /// Transfers the ownership of this PhotonView (and GameObject) to another player. + /// + /// + /// The owner/controller of a PhotonView is also the client which sends position updates of the GameObject. + /// + public void TransferOwnership(PhotonPlayer newOwner) + { + this.TransferOwnership(newOwner.ID); + } + + /// + /// Transfers the ownership of this PhotonView (and GameObject) to another player. + /// + /// + /// The owner/controller of a PhotonView is also the client which sends position updates of the GameObject. + /// + public void TransferOwnership(int newOwnerId) + { + PhotonNetwork.networkingPeer.TransferOwnership(this.viewID, newOwnerId); + this.ownerId = newOwnerId; // immediately switch ownership locally, to avoid more updates sent from this client. + } + + /// + ///Check ownerId assignment for sceneObjects to keep being owned by the MasterClient. + /// + /// New master client. + public void OnMasterClientSwitched(PhotonPlayer newMasterClient) + { + if (this.CreatorActorNr == 0 && !this.OwnerShipWasTransfered && (this.currentMasterID== -1 || this.ownerId==this.currentMasterID)) + { + this.ownerId = newMasterClient.ID; + } + + this.currentMasterID = newMasterClient.ID; + } + + + protected internal void OnDestroy() + { + if (!this.removedFromLocalViewList) + { + bool wasInList = PhotonNetwork.networkingPeer.LocalCleanPhotonView(this); + bool loading = false; + + #if !UNITY_5 || UNITY_5_0 || UNITY_5_1 + loading = Application.isLoadingLevel; + #endif + + if (wasInList && !loading && this.instantiationId > 0 && !PhotonHandler.AppQuits && PhotonNetwork.logLevel >= PhotonLogLevel.Informational) + { + Debug.Log("PUN-instantiated '" + this.gameObject.name + "' got destroyed by engine. This is OK when loading levels. Otherwise use: PhotonNetwork.Destroy()."); + } + } + } + + public void SerializeView(PhotonStream stream, PhotonMessageInfo info) + { + if (this.ObservedComponents != null && this.ObservedComponents.Count > 0) + { + for (int i = 0; i < this.ObservedComponents.Count; ++i) + { + SerializeComponent(this.ObservedComponents[i], stream, info); + } + } + } + + public void DeserializeView(PhotonStream stream, PhotonMessageInfo info) + { + if (this.ObservedComponents != null && this.ObservedComponents.Count > 0) + { + for (int i = 0; i < this.ObservedComponents.Count; ++i) + { + DeserializeComponent(this.ObservedComponents[i], stream, info); + } + } + } + + protected internal void DeserializeComponent(Component component, PhotonStream stream, PhotonMessageInfo info) + { + if (component == null) + { + return; + } + + // Use incoming data according to observed type + if (component is MonoBehaviour) + { + ExecuteComponentOnSerialize(component, stream, info); + } + else if (component is Transform) + { + Transform trans = (Transform) component; + + switch (this.onSerializeTransformOption) + { + case OnSerializeTransform.All: + trans.localPosition = (Vector3) stream.ReceiveNext(); + trans.localRotation = (Quaternion) stream.ReceiveNext(); + trans.localScale = (Vector3) stream.ReceiveNext(); + break; + case OnSerializeTransform.OnlyPosition: + trans.localPosition = (Vector3) stream.ReceiveNext(); + break; + case OnSerializeTransform.OnlyRotation: + trans.localRotation = (Quaternion) stream.ReceiveNext(); + break; + case OnSerializeTransform.OnlyScale: + trans.localScale = (Vector3) stream.ReceiveNext(); + break; + case OnSerializeTransform.PositionAndRotation: + trans.localPosition = (Vector3) stream.ReceiveNext(); + trans.localRotation = (Quaternion) stream.ReceiveNext(); + break; + } + } + else if (component is Rigidbody) + { + Rigidbody rigidB = (Rigidbody) component; + + switch (this.onSerializeRigidBodyOption) + { + case OnSerializeRigidBody.All: + rigidB.velocity = (Vector3) stream.ReceiveNext(); + rigidB.angularVelocity = (Vector3) stream.ReceiveNext(); + break; + case OnSerializeRigidBody.OnlyAngularVelocity: + rigidB.angularVelocity = (Vector3) stream.ReceiveNext(); + break; + case OnSerializeRigidBody.OnlyVelocity: + rigidB.velocity = (Vector3) stream.ReceiveNext(); + break; + } + } + else if (component is Rigidbody2D) + { + Rigidbody2D rigidB = (Rigidbody2D) component; + + switch (this.onSerializeRigidBodyOption) + { + case OnSerializeRigidBody.All: + rigidB.velocity = (Vector2) stream.ReceiveNext(); + rigidB.angularVelocity = (float) stream.ReceiveNext(); + break; + case OnSerializeRigidBody.OnlyAngularVelocity: + rigidB.angularVelocity = (float) stream.ReceiveNext(); + break; + case OnSerializeRigidBody.OnlyVelocity: + rigidB.velocity = (Vector2) stream.ReceiveNext(); + break; + } + } + else + { + Debug.LogError("Type of observed is unknown when receiving."); + } + } + + protected internal void SerializeComponent(Component component, PhotonStream stream, PhotonMessageInfo info) + { + if (component == null) + { + return; + } + + if (component is MonoBehaviour) + { + ExecuteComponentOnSerialize(component, stream, info); + } + else if (component is Transform) + { + Transform trans = (Transform) component; + + switch (this.onSerializeTransformOption) + { + case OnSerializeTransform.All: + stream.SendNext(trans.localPosition); + stream.SendNext(trans.localRotation); + stream.SendNext(trans.localScale); + break; + case OnSerializeTransform.OnlyPosition: + stream.SendNext(trans.localPosition); + break; + case OnSerializeTransform.OnlyRotation: + stream.SendNext(trans.localRotation); + break; + case OnSerializeTransform.OnlyScale: + stream.SendNext(trans.localScale); + break; + case OnSerializeTransform.PositionAndRotation: + stream.SendNext(trans.localPosition); + stream.SendNext(trans.localRotation); + break; + } + } + else if (component is Rigidbody) + { + Rigidbody rigidB = (Rigidbody) component; + + switch (this.onSerializeRigidBodyOption) + { + case OnSerializeRigidBody.All: + stream.SendNext(rigidB.velocity); + stream.SendNext(rigidB.angularVelocity); + break; + case OnSerializeRigidBody.OnlyAngularVelocity: + stream.SendNext(rigidB.angularVelocity); + break; + case OnSerializeRigidBody.OnlyVelocity: + stream.SendNext(rigidB.velocity); + break; + } + } + else if (component is Rigidbody2D) + { + Rigidbody2D rigidB = (Rigidbody2D) component; + + switch (this.onSerializeRigidBodyOption) + { + case OnSerializeRigidBody.All: + stream.SendNext(rigidB.velocity); + stream.SendNext(rigidB.angularVelocity); + break; + case OnSerializeRigidBody.OnlyAngularVelocity: + stream.SendNext(rigidB.angularVelocity); + break; + case OnSerializeRigidBody.OnlyVelocity: + stream.SendNext(rigidB.velocity); + break; + } + } + else + { + Debug.LogError("Observed type is not serializable: " + component.GetType()); + } + } + + protected internal void ExecuteComponentOnSerialize(Component component, PhotonStream stream, PhotonMessageInfo info) + { + IPunObservable observable = component as IPunObservable; + if (observable != null) + { + observable.OnPhotonSerializeView(stream, info); + } + else if (component != null) + { + MethodInfo method = null; + bool found = this.m_OnSerializeMethodInfos.TryGetValue(component, out method); + if (!found) + { + bool foundMethod = NetworkingPeer.GetMethod(component as MonoBehaviour, PhotonNetworkingMessage.OnPhotonSerializeView.ToString(), out method); + + if (foundMethod == false) + { + Debug.LogError("The observed monobehaviour (" + component.name + ") of this PhotonView does not implement OnPhotonSerializeView()!"); + method = null; + } + + this.m_OnSerializeMethodInfos.Add(component, method); + } + + if (method != null) + { + method.Invoke(component, new object[] {stream, info}); + } + } + } + + + /// + /// Can be used to refesh the list of MonoBehaviours on this GameObject while PhotonNetwork.UseRpcMonoBehaviourCache is true. + /// + /// + /// Set PhotonNetwork.UseRpcMonoBehaviourCache to true to enable the caching. + /// Uses this.GetComponents() to get a list of MonoBehaviours to call RPCs on (potentially). + /// + /// While PhotonNetwork.UseRpcMonoBehaviourCache is false, this method has no effect, + /// because the list is refreshed when a RPC gets called. + /// + public void RefreshRpcMonoBehaviourCache() + { + this.RpcMonoBehaviours = this.GetComponents(); + } + + + /// + /// Call a RPC method of this GameObject on remote clients of this room (or on all, inclunding this client). + /// + /// + /// [Remote Procedure Calls](@ref rpcManual) are an essential tool in making multiplayer games with PUN. + /// It enables you to make every client in a room call a specific method. + /// + /// RPC calls can target "All" or the "Others". + /// Usually, the target "All" gets executed locally immediately after sending the RPC. + /// The "*ViaServer" options send the RPC to the server and execute it on this client when it's sent back. + /// Of course, calls are affected by this client's lag and that of remote clients. + /// + /// Each call automatically is routed to the same PhotonView (and GameObject) that was used on the + /// originating client. + /// + /// See: [Remote Procedure Calls](@ref rpcManual). + /// + /// The name of a fitting method that was has the RPC attribute. + /// The group of targets and the way the RPC gets sent. + /// The parameters that the RPC method has (must fit this call!). + public void RPC(string methodName, PhotonTargets target, params object[] parameters) + { + PhotonNetwork.RPC(this, methodName, target, false, parameters); + } + + /// + /// Call a RPC method of this GameObject on remote clients of this room (or on all, inclunding this client). + /// + /// + /// [Remote Procedure Calls](@ref rpcManual) are an essential tool in making multiplayer games with PUN. + /// It enables you to make every client in a room call a specific method. + /// + /// RPC calls can target "All" or the "Others". + /// Usually, the target "All" gets executed locally immediately after sending the RPC. + /// The "*ViaServer" options send the RPC to the server and execute it on this client when it's sent back. + /// Of course, calls are affected by this client's lag and that of remote clients. + /// + /// Each call automatically is routed to the same PhotonView (and GameObject) that was used on the + /// originating client. + /// + /// See: [Remote Procedure Calls](@ref rpcManual). + /// + ///The name of a fitting method that was has the RPC attribute. + ///The group of targets and the way the RPC gets sent. + /// + ///The parameters that the RPC method has (must fit this call!). + public void RpcSecure(string methodName, PhotonTargets target, bool encrypt, params object[] parameters) + { + PhotonNetwork.RPC(this, methodName, target, encrypt, parameters); + } + + /// + /// Call a RPC method of this GameObject on remote clients of this room (or on all, inclunding this client). + /// + /// + /// [Remote Procedure Calls](@ref rpcManual) are an essential tool in making multiplayer games with PUN. + /// It enables you to make every client in a room call a specific method. + /// + /// This method allows you to make an RPC calls on a specific player's client. + /// Of course, calls are affected by this client's lag and that of remote clients. + /// + /// Each call automatically is routed to the same PhotonView (and GameObject) that was used on the + /// originating client. + /// + /// See: [Remote Procedure Calls](@ref rpcManual). + /// + /// The name of a fitting method that was has the RPC attribute. + /// The group of targets and the way the RPC gets sent. + /// The parameters that the RPC method has (must fit this call!). + public void RPC(string methodName, PhotonPlayer targetPlayer, params object[] parameters) + { + PhotonNetwork.RPC(this, methodName, targetPlayer, false, parameters); + } + + /// + /// Call a RPC method of this GameObject on remote clients of this room (or on all, inclunding this client). + /// + /// + /// [Remote Procedure Calls](@ref rpcManual) are an essential tool in making multiplayer games with PUN. + /// It enables you to make every client in a room call a specific method. + /// + /// This method allows you to make an RPC calls on a specific player's client. + /// Of course, calls are affected by this client's lag and that of remote clients. + /// + /// Each call automatically is routed to the same PhotonView (and GameObject) that was used on the + /// originating client. + /// + /// See: [Remote Procedure Calls](@ref rpcManual). + /// + ///The name of a fitting method that was has the RPC attribute. + ///The group of targets and the way the RPC gets sent. + /// + ///The parameters that the RPC method has (must fit this call!). + public void RpcSecure(string methodName, PhotonPlayer targetPlayer, bool encrypt, params object[] parameters) + { + PhotonNetwork.RPC(this, methodName, targetPlayer, encrypt, parameters); + } + + public static PhotonView Get(Component component) + { + return component.GetComponent(); + } + + public static PhotonView Get(GameObject gameObj) + { + return gameObj.GetComponent(); + } + + public static PhotonView Find(int viewID) + { + return PhotonNetwork.networkingPeer.GetPhotonView(viewID); + } + + public override string ToString() + { + return string.Format("View ({3}){0} on {1} {2}", this.viewID, (this.gameObject != null) ? this.gameObject.name : "GO==null", (this.isSceneView) ? "(scene)" : string.Empty, this.prefix); + } +} diff --git a/Assets/Photon Unity Networking/Plugins/PhotonNetwork/PhotonView.cs.meta b/Assets/Photon Unity Networking/Plugins/PhotonNetwork/PhotonView.cs.meta new file mode 100644 index 0000000..b2b8709 --- /dev/null +++ b/Assets/Photon Unity Networking/Plugins/PhotonNetwork/PhotonView.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: aa584fbee541324448dd18d8409c7a41 +labels: +- ExitGames +- PUN +- Photon +- Networking +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} diff --git a/Assets/Photon Unity Networking/Plugins/PhotonNetwork/PingCloudRegions.cs b/Assets/Photon Unity Networking/Plugins/PhotonNetwork/PingCloudRegions.cs new file mode 100644 index 0000000..5dcf83a --- /dev/null +++ b/Assets/Photon Unity Networking/Plugins/PhotonNetwork/PingCloudRegions.cs @@ -0,0 +1,352 @@ +using System; +using System.Net; +using System.Collections; +using System.Diagnostics; +using ExitGames.Client.Photon; +using UnityEngine; +using Debug = UnityEngine.Debug; +using SupportClassPun = ExitGames.Client.Photon.SupportClass; + + +#if UNITY_EDITOR || (!UNITY_ANDROID && !UNITY_IPHONE && !UNITY_PS3 && !UNITY_WINRT) + +using System.Net.Sockets; + + +/// Uses C# Socket class from System.Net.Sockets (as Unity usually does). +/// Incompatible with Windows 8 Store/Phone API. +public class PingMonoEditor : PhotonPing +{ + private Socket sock; + + /// + /// Sends a "Photon Ping" to a server. + /// + /// Address in IPv4 or IPv6 format. An address containing a '.' will be interpretet as IPv4. + /// True if the Photon Ping could be sent. + public override bool StartPing(string ip) + { + base.Init(); + + try + { + if (ip.Contains(".")) + { + this.sock = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); + } + else + { + this.sock = new Socket(AddressFamily.InterNetworkV6, SocketType.Dgram, ProtocolType.Udp); + } + + sock.ReceiveTimeout = 5000; + sock.Connect(ip, 5055); + + PingBytes[PingBytes.Length - 1] = PingId; + sock.Send(PingBytes); + PingBytes[PingBytes.Length - 1] = (byte)(PingId - 1); + } + catch (Exception e) + { + sock = null; + Console.WriteLine(e); + } + + return false; + } + + public override bool Done() + { + if (this.GotResult || sock == null) + { + return true; + } + + if (sock.Available <= 0) + { + return false; + } + + int read = sock.Receive(PingBytes, SocketFlags.None); + //Debug.Log("Got: " + SupportClassPun.ByteArrayToString(PingBytes)); + bool replyMatch = PingBytes[PingBytes.Length - 1] == PingId && read == PingLength; + if (!replyMatch) Debug.Log("ReplyMatch is false! "); + + + this.Successful = read == PingBytes.Length && PingBytes[PingBytes.Length - 1] == PingId; + this.GotResult = true; + return true; + } + + public override void Dispose() + { + try + { + sock.Close(); + } + catch + { + } + sock = null; + } + +} + +#endif + + +#if UNITY_WEBGL + +public class PingHttp : PhotonPing +{ + private WWW webRequest; + + public override bool StartPing(string address) + { + address = "https://" + address + "/photon/m/?ping&r=" + UnityEngine.Random.Range(0, 10000); + Debug.Log("StartPing: " + address); + this.webRequest = new WWW(address); + return true; + } + + public override bool Done() + { + if (this.webRequest.isDone) + { + Successful = true; + return true; + } + + return false; + } + + public override void Dispose() + { + this.webRequest.Dispose(); + } +} + +#endif + + +public class PhotonPingManager +{ + public bool UseNative; + public static int Attempts = 5; + public static bool IgnoreInitialAttempt = true; + public static int MaxMilliseconsPerPing = 800; // enter a value you're sure some server can beat (have a lower rtt) + + private const string wssProtocolString = "wss://"; + + public Region BestRegion + { + get + { + Region result = null; + int bestRtt = Int32.MaxValue; + foreach (Region region in PhotonNetwork.networkingPeer.AvailableRegions) + { + Debug.Log("BestRegion checks region: " + region); + if (region.Ping != 0 && region.Ping < bestRtt) + { + bestRtt = region.Ping; + result = region; + } + } + + return (Region)result; + } + } + + public bool Done + { + get { return this.PingsRunning == 0; } + } + + private int PingsRunning; + + + /// + /// Affected by frame-rate of app, as this Coroutine checks the socket for a result once per frame. + /// + public IEnumerator PingSocket(Region region) + { + region.Ping = Attempts*MaxMilliseconsPerPing; + + this.PingsRunning++; // TODO: Add try-catch to make sure the PingsRunning are reduced at the end and that the lib does not crash the app + PhotonPing ping; + if (PhotonHandler.PingImplementation == typeof(PingNativeDynamic)) + { + Debug.Log("Using constructor for new PingNativeDynamic()"); // it seems on Android, the Activator can't find the default Constructor + ping = new PingNativeDynamic(); + } + else if(PhotonHandler.PingImplementation == typeof(PingNativeStatic)) + { + Debug.Log("Using constructor for new PingNativeStatic()"); // it seems on Switch, the Activator can't find the default Constructor + ping = new PingNativeStatic(); + } + else if (PhotonHandler.PingImplementation == typeof(PingMono)) + { + ping = new PingMono(); // using this type explicitly saves it from IL2CPP bytecode stripping + } + #if UNITY_WEBGL + else if (PhotonHandler.PingImplementation == typeof(PingHttp)) + { + ping = new PingHttp(); + } + #endif + else + { + ping = (PhotonPing)Activator.CreateInstance(PhotonHandler.PingImplementation); + } + + //Debug.Log(region); + + float rttSum = 0.0f; + int replyCount = 0; + + // all addresses for Photon region servers will contain a :port ending. this needs to be removed first. + // PhotonPing.StartPing() requires a plain (IP) address without port or protocol-prefix (on all but Windows 8.1 and WebGL platforms). + + string regionAddress = region.HostAndPort; + int indexOfColon = regionAddress.LastIndexOf(':'); + if (indexOfColon > 1) + { + regionAddress = regionAddress.Substring(0, indexOfColon); + } + + // we also need to remove the protocol or Dns.GetHostAddresses(hostName) will throw an exception + // This is for xBox One for example. + int indexOfProtocol = regionAddress.IndexOf(PhotonPingManager.wssProtocolString); + if (indexOfProtocol > -1) + { + regionAddress = regionAddress.Substring(indexOfProtocol+PhotonPingManager.wssProtocolString.Length); + } + regionAddress = ResolveHost(regionAddress); + + + for (int i = 0; i < Attempts; i++) + { + bool overtime = false; + Stopwatch sw = new Stopwatch(); + sw.Start(); + + try + { + ping.StartPing(regionAddress); + } + catch (Exception e) + { + Debug.Log("catched: " + e); + this.PingsRunning--; + break; + } + + + while (!ping.Done()) + { + if (sw.ElapsedMilliseconds >= MaxMilliseconsPerPing) + { + overtime = true; + break; + } + yield return 0; // keep this loop tight, to avoid adding local lag to rtt. + } + int rtt = (int)sw.ElapsedMilliseconds; + + + if (IgnoreInitialAttempt && i == 0) + { + // do nothing. + } + else if (ping.Successful && !overtime) + { + rttSum += rtt; + replyCount++; + region.Ping = (int)((rttSum) / replyCount); + //Debug.Log("region " + region.Code + " RTT " + region.Ping + " success: " + ping.Successful + " over: " + overtime); + } + + yield return new WaitForSeconds(0.1f); + } + ping.Dispose(); + + this.PingsRunning--; + + //Debug.Log("this.PingsRunning: " + this.PingsRunning + " this debug: " + ping.DebugString); + yield return null; + } + +#if (UNITY_WINRT && !UNITY_EDITOR) || UNITY_WEBGL + + public static string ResolveHost(string hostName) + { + #if UNITY_WEBGL + if (hostName.StartsWith("wss://")) + { + hostName = hostName.Substring(6); + } + if (hostName.StartsWith("ws://")) + { + hostName = hostName.Substring(5); + } + #endif + + return hostName; + } + +#else + + /// + /// Attempts to resolve a hostname into an IP string or returns empty string if that fails. + /// + /// + /// To be compatible with most platforms, the address family is checked like this:
+ /// if (ipAddress.AddressFamily.ToString().Contains("6")) // ipv6... + /// + /// Hostname to resolve. + /// IP string or empty string if resolution fails + public static string ResolveHost(string hostName) + { + string ipv4Address = string.Empty; + + try + { + IPAddress[] address = Dns.GetHostAddresses(hostName); + //foreach (IPAddress adr in address) + //{ + // Debug.Log(hostName + " -> Adress: " + adr + " family: " + adr.AddressFamily.ToString()); + //} + + if (address.Length == 1) + { + return address[0].ToString(); + } + + // if we got more addresses, try to pick a IPv4 one + for (int index = 0; index < address.Length; index++) + { + IPAddress ipAddress = address[index]; + if (ipAddress != null) + { + // checking ipAddress.ToString() means we don't have to import System.Net.Sockets, which is not available on some platforms (Metro) + if (ipAddress.ToString().Contains(":")) + { + return ipAddress.ToString(); + } + if (string.IsNullOrEmpty(ipv4Address)) + { + ipv4Address = address.ToString(); + } + } + } + } + catch (System.Exception e) + { + Debug.Log("Exception caught! " + e.Source + " Message: " + e.Message); + } + + return ipv4Address; + } +#endif +} diff --git a/Assets/Photon Unity Networking/Plugins/PhotonNetwork/PingCloudRegions.cs.meta b/Assets/Photon Unity Networking/Plugins/PhotonNetwork/PingCloudRegions.cs.meta new file mode 100644 index 0000000..2e90001 --- /dev/null +++ b/Assets/Photon Unity Networking/Plugins/PhotonNetwork/PingCloudRegions.cs.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 207807222df026f40ac3688a3a051e38 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} diff --git a/Assets/Photon Unity Networking/Plugins/PhotonNetwork/RPC.cs b/Assets/Photon Unity Networking/Plugins/PhotonNetwork/RPC.cs new file mode 100644 index 0000000..477f44c --- /dev/null +++ b/Assets/Photon Unity Networking/Plugins/PhotonNetwork/RPC.cs @@ -0,0 +1,12 @@ + +#pragma warning disable 1587 +/// \file +/// Reimplements a RPC Attribute, as it's no longer in all versions of the UnityEngine assembly. +#pragma warning restore 1587 + +using System; + +/// Replacement for RPC attribute with different name. Used to flag methods as remote-callable. +public class PunRPC : Attribute +{ +} \ No newline at end of file diff --git a/Assets/Photon Unity Networking/Plugins/PhotonNetwork/RPC.cs.meta b/Assets/Photon Unity Networking/Plugins/PhotonNetwork/RPC.cs.meta new file mode 100644 index 0000000..5b97d85 --- /dev/null +++ b/Assets/Photon Unity Networking/Plugins/PhotonNetwork/RPC.cs.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: c40d255b1edd61842ae10e3346a2251e +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} diff --git a/Assets/Photon Unity Networking/Plugins/PhotonNetwork/Room.cs b/Assets/Photon Unity Networking/Plugins/PhotonNetwork/Room.cs new file mode 100644 index 0000000..475a142 --- /dev/null +++ b/Assets/Photon Unity Networking/Plugins/PhotonNetwork/Room.cs @@ -0,0 +1,366 @@ +// ---------------------------------------------------------------------------- +// +// PhotonNetwork Framework for Unity - Copyright (C) 2011 Exit Games GmbH +// +// +// Represents a room/game on the server and caches the properties of that. +// +// developer@exitgames.com +// ---------------------------------------------------------------------------- + +using System; +using ExitGames.Client.Photon; +using UnityEngine; + + +/// +/// This class resembles a room that PUN joins (or joined). +/// The properties are settable as opposed to those of a RoomInfo and you can close or hide "your" room. +/// +/// \ingroup publicApi +public class Room : RoomInfo +{ + /// The name of a room. Unique identifier (per Loadbalancing group) for a room/match. + public new string Name + { + get + { + return this.nameField; + } + + internal set + { + this.nameField = value; + } + } + + /// + /// Defines if the room can be joined. + /// This does not affect listing in a lobby but joining the room will fail if not open. + /// If not open, the room is excluded from random matchmaking. + /// Due to racing conditions, found matches might become closed before they are joined. + /// Simply re-connect to master and find another. + /// Use property "visible" to not list the room. + /// + public new bool IsOpen + { + get + { + return this.openField; + } + + set + { + if (!this.Equals(PhotonNetwork.room)) + { + UnityEngine.Debug.LogWarning("Can't set open when not in that room."); + } + + if (value != this.openField && !PhotonNetwork.offlineMode) + { + PhotonNetwork.networkingPeer.OpSetPropertiesOfRoom(new Hashtable() { { GamePropertyKey.IsOpen, value } }, expectedProperties: null, webForward: false); + } + + this.openField = value; + } + } + + /// + /// Defines if the room is listed in its lobby. + /// Rooms can be created invisible, or changed to invisible. + /// To change if a room can be joined, use property: open. + /// + public new bool IsVisible + { + get + { + return this.visibleField; + } + + set + { + if (!this.Equals(PhotonNetwork.room)) + { + UnityEngine.Debug.LogWarning("Can't set visible when not in that room."); + } + + if (value != this.visibleField && !PhotonNetwork.offlineMode) + { + PhotonNetwork.networkingPeer.OpSetPropertiesOfRoom(new Hashtable() { { GamePropertyKey.IsVisible, value } }, expectedProperties: null, webForward: false); + } + + this.visibleField = value; + } + } + + /// + /// A list of custom properties that should be forwarded to the lobby and listed there. + /// + public string[] PropertiesListedInLobby { get; private set; } + + /// + /// Gets if this room uses autoCleanUp to remove all (buffered) RPCs and instantiated GameObjects when a player leaves. + /// + public bool AutoCleanUp + { + get + { + return this.autoCleanUpField; + } + } + + /// + /// Sets a limit of players to this room. This property is shown in lobby, too. + /// If the room is full (players count == maxplayers), joining this room will fail. + /// + public new int MaxPlayers + { + get + { + return (int)this.maxPlayersField; + } + + set + { + if (!this.Equals(PhotonNetwork.room)) + { + UnityEngine.Debug.LogWarning("Can't set MaxPlayers when not in that room."); + } + + if (value > 255) + { + UnityEngine.Debug.LogWarning("Can't set Room.MaxPlayers to: " + value + ". Using max value: 255."); + value = 255; + } + + if (value != this.maxPlayersField && !PhotonNetwork.offlineMode) + { + PhotonNetwork.networkingPeer.OpSetPropertiesOfRoom(new Hashtable() { { GamePropertyKey.MaxPlayers, (byte)value } }, expectedProperties: null, webForward: false); + } + + this.maxPlayersField = (byte)value; + } + } + + /// Count of players in this room. + public new int PlayerCount + { + get + { + if (PhotonNetwork.playerList != null) + { + return PhotonNetwork.playerList.Length; + } + else + { + return 0; + } + } + } + + /// + /// List of users who are expected to join this room. In matchmaking, Photon blocks a slot for each of these UserIDs out of the MaxPlayers. + /// + /// + /// The corresponding feature in Photon is called "Slot Reservation" and can be found in the doc pages. + /// Define expected players in the PhotonNetwork methods: CreateRoom, JoinRoom and JoinOrCreateRoom. + /// + public string[] ExpectedUsers + { + get { return this.expectedUsersField; } + } + + /// The ID (actorNumber) of the current Master Client of this room. + /// See also: PhotonNetwork.masterClient. + protected internal int MasterClientId + { + get + { + return this.masterClientIdField; + } + set + { + this.masterClientIdField = value; + } + } + + + internal Room(string roomName, RoomOptions options) : base(roomName, null) + { + if (options == null) + { + options = new RoomOptions(); + } + + this.visibleField = options.IsVisible; + this.openField = options.IsOpen; + this.maxPlayersField = (byte)options.MaxPlayers; + this.autoCleanUpField = false; // defaults to false, unless set to true when room gets created. + + this.InternalCacheProperties(options.CustomRoomProperties); + this.PropertiesListedInLobby = options.CustomRoomPropertiesForLobby; + } + + + /// + /// Updates the current room's Custom Properties with new/updated key-values. + /// + /// + /// Custom Properties are a key-value set (Hashtable) which is available to all players in a room. + /// They can relate to the room or individual players and are useful when only the current value + /// of something is of interest. For example: The map of a room. + /// All keys must be strings. + /// + /// The Room and the PhotonPlayer class both have SetCustomProperties methods. + /// Also, both classes offer access to current key-values by: customProperties. + /// + /// Always use SetCustomProperties to change values. + /// To reduce network traffic, set only values that actually changed. + /// New properties are added, existing values are updated. + /// Other values will not be changed, so only provide values that changed or are new. + /// + /// To delete a named (custom) property of this room, use null as value. + /// + /// Locally, SetCustomProperties will update it's cache without delay. + /// Other clients are updated through Photon (the server) with a fitting operation. + /// + /// Check and Swap + /// + /// SetCustomProperties have the option to do a server-side Check-And-Swap (CAS): + /// Values only get updated if the expected values are correct. + /// The expectedValues can be different key/values than the propertiesToSet. So you can + /// check some key and set another key's value (if the check succeeds). + /// + /// If the client's knowledge of properties is wrong or outdated, it can't set values with CAS. + /// This can be useful to keep players from concurrently setting values. For example: If all players + /// try to pickup some card or item, only one should get it. With CAS, only the first SetProperties + /// gets executed server-side and any other (sent at the same time) fails. + /// + /// The server will broadcast successfully changed values and the local "cache" of customProperties + /// only gets updated after a roundtrip (if anything changed). + /// + /// You can do a "webForward": Photon will send the changed properties to a WebHook defined + /// for your application. + /// + /// OfflineMode + /// + /// While PhotonNetwork.offlineMode is true, the expectedValues and webForward parameters are ignored. + /// In OfflineMode, the local customProperties values are immediately updated (without the roundtrip). + /// + /// The new properties to be set. + /// At least one property key/value set to check server-side. Key and value must be correct. Ignored in OfflineMode. + /// Set to true, to forward the set properties to a WebHook, defined for this app (in Dashboard). Ignored in OfflineMode. + public void SetCustomProperties(Hashtable propertiesToSet, Hashtable expectedValues = null, bool webForward = false) + { + if (propertiesToSet == null) + { + return; + } + + Hashtable customProps = propertiesToSet.StripToStringKeys() as Hashtable; + Hashtable customPropsToCheck = expectedValues.StripToStringKeys() as Hashtable; + + + // no expected values -> set and callback + bool noCas = customPropsToCheck == null || customPropsToCheck.Count == 0; + + if (PhotonNetwork.offlineMode || noCas) + { + this.CustomProperties.Merge(customProps); // the customProps are already stripped to string-keys-only (custom-props keys) + this.CustomProperties.StripKeysWithNullValues(); + } + + if (!PhotonNetwork.offlineMode) + { + PhotonNetwork.networkingPeer.OpSetPropertiesOfRoom(customProps, customPropsToCheck, webForward); // as the customProps are stripped already, this equals OpSetCustomPropertiesOfRoom() + } + + if (PhotonNetwork.offlineMode || noCas) + { + NetworkingPeer.SendMonoMessage(PhotonNetworkingMessage.OnPhotonCustomRoomPropertiesChanged, customProps); + } + } + + /// + /// Enables you to define the properties available in the lobby if not all properties are needed to pick a room. + /// + /// + /// It makes sense to limit the amount of properties sent to users in the lobby as this improves speed and stability. + /// + /// An array of custom room property names to forward to the lobby. + public void SetPropertiesListedInLobby(string[] propsListedInLobby) + { + Hashtable customProps = new Hashtable(); + customProps[GamePropertyKey.PropsListedInLobby] = propsListedInLobby; + PhotonNetwork.networkingPeer.OpSetPropertiesOfRoom(customProps, expectedProperties: null, webForward: false); + + this.PropertiesListedInLobby = propsListedInLobby; + } + + /// + /// Attempts to remove all current expected users from the server's Slot Reservation list. + /// + /// + /// Note that this operation can conflict with new/other users joining. They might be + /// adding users to the list of expected users before or after this client called ClearExpectedUsers. + /// + /// This room's expectedUsers value will update, when the server sends a successful update. + /// + /// Internals: This methods wraps up setting the ExpectedUsers property of a room. + /// + public void ClearExpectedUsers() + { + Hashtable props = new Hashtable(); + props[GamePropertyKey.ExpectedUsers] = new string[0]; + Hashtable expected = new Hashtable(); + expected[GamePropertyKey.ExpectedUsers] = this.ExpectedUsers; + PhotonNetwork.networkingPeer.OpSetPropertiesOfRoom(props, expected, webForward: false); + } + + + /// Returns a summary of this Room instance as string. + /// Summary of this Room instance. + public override string ToString() + { + return string.Format("Room: '{0}' {1},{2} {4}/{3} players.", this.nameField, this.visibleField ? "visible" : "hidden", this.openField ? "open" : "closed", this.maxPlayersField, this.PlayerCount); + } + + /// Returns a summary of this Room instance as longer string, including Custom Properties. + /// Summary of this Room instance. + public new string ToStringFull() + { + return string.Format("Room: '{0}' {1},{2} {4}/{3} players.\ncustomProps: {5}", this.nameField, this.visibleField ? "visible" : "hidden", this.openField ? "open" : "closed", this.maxPlayersField, this.PlayerCount, this.CustomProperties.ToStringFull()); + } + + + #region Obsoleted variable names + + [Obsolete("Please use Name (updated case for naming).")] + public new string name { get { return this.Name; } internal set { this.Name = value; } } + + [Obsolete("Please use IsOpen (updated case for naming).")] + public new bool open { get { return this.IsOpen; } set { this.IsOpen = value; } } + + [Obsolete("Please use IsVisible (updated case for naming).")] + public new bool visible { get { return this.IsVisible; } set { this.IsVisible = value; } } + + [Obsolete("Please use PropertiesListedInLobby (updated case for naming).")] + public string[] propertiesListedInLobby { get { return this.PropertiesListedInLobby; } private set { this.PropertiesListedInLobby = value; } } + + [Obsolete("Please use AutoCleanUp (updated case for naming).")] + public bool autoCleanUp { get { return this.AutoCleanUp; } } + + [Obsolete("Please use MaxPlayers (updated case for naming).")] + public new int maxPlayers { get { return this.MaxPlayers; } set { this.MaxPlayers = value; } } + + [Obsolete("Please use PlayerCount (updated case for naming).")] + public new int playerCount { get { return this.PlayerCount; } } + + [Obsolete("Please use ExpectedUsers (updated case for naming).")] + public string[] expectedUsers { get { return this.ExpectedUsers; } } + + [Obsolete("Please use MasterClientId (updated case for naming).")] + protected internal int masterClientId { get { return this.MasterClientId; } set { this.MasterClientId = value; } } + + #endregion +} diff --git a/Assets/Photon Unity Networking/Plugins/PhotonNetwork/Room.cs.meta b/Assets/Photon Unity Networking/Plugins/PhotonNetwork/Room.cs.meta new file mode 100644 index 0000000..66ccb6c --- /dev/null +++ b/Assets/Photon Unity Networking/Plugins/PhotonNetwork/Room.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 17568a7a5552c09428dd48e73548b8b8 +labels: +- ExitGames +- PUN +- Photon +- Networking +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} diff --git a/Assets/Photon Unity Networking/Plugins/PhotonNetwork/RoomInfo.cs b/Assets/Photon Unity Networking/Plugins/PhotonNetwork/RoomInfo.cs new file mode 100644 index 0000000..a4ed0d6 --- /dev/null +++ b/Assets/Photon Unity Networking/Plugins/PhotonNetwork/RoomInfo.cs @@ -0,0 +1,282 @@ +// ---------------------------------------------------------------------------- +// +// Loadbalancing Framework for Photon - Copyright (C) 2011 Exit Games GmbH +// +// +// This class resembles info about available rooms, as sent by the Master +// server's lobby. Consider all values as readonly. +// +// developer@exitgames.com +// ---------------------------------------------------------------------------- + +using System; +using ExitGames.Client.Photon; + + +/// +/// A simplified room with just the info required to list and join, used for the room listing in the lobby. +/// The properties are not settable (open, MaxPlayers, etc). +/// +/// +/// This class resembles info about available rooms, as sent by the Master server's lobby. +/// Consider all values as readonly. None are synced (only updated by events by server). +/// +/// \ingroup publicApi +public class RoomInfo +{ + /// Used internally in lobby, to mark rooms that are no longer listed. + public bool removedFromList { get; internal set; } + + /// Backing field for property. + private Hashtable customPropertiesField = new Hashtable(); + + /// Backing field for property. + protected byte maxPlayersField = 0; + + /// Backing field for property. + protected string[] expectedUsersField; + + /// Backing field for property. + protected bool openField = true; + + /// Backing field for property. + protected bool visibleField = true; + + /// Backing field for property. False unless the GameProperty is set to true (else it's not sent). + protected bool autoCleanUpField = PhotonNetwork.autoCleanUpPlayerObjects; + + /// Backing field for property. + protected string nameField; + + /// Backing field for master client id (actorNumber). defined by server in room props and ev leave. + protected internal int masterClientIdField; + + protected internal bool serverSideMasterClient { get; private set; } + + /// Read-only "cache" of custom properties of a room. Set via Room.SetCustomProperties (not available for RoomInfo class!). + /// All keys are string-typed and the values depend on the game/application. + /// + public Hashtable CustomProperties + { + get + { + return this.customPropertiesField; + } + } + + /// The name of a room. Unique identifier (per Loadbalancing group) for a room/match. + public string Name + { + get + { + return this.nameField; + } + } + + /// + /// Only used internally in lobby, to display number of players in room (while you're not in). + /// + public int PlayerCount { get; private set; } + + /// + /// State if the local client is already in the game or still going to join it on gameserver (in lobby always false). + /// + public bool IsLocalClientInside { get; set; } + + /// + /// Sets a limit of players to this room. This property is shown in lobby, too. + /// If the room is full (players count == maxplayers), joining this room will fail. + /// + /// + /// As part of RoomInfo this can't be set. + /// As part of a Room (which the player joined), the setter will update the server and all clients. + /// + public byte MaxPlayers + { + get + { + return this.maxPlayersField; + } + } + + /// + /// Defines if the room can be joined. + /// This does not affect listing in a lobby but joining the room will fail if not open. + /// If not open, the room is excluded from random matchmaking. + /// Due to racing conditions, found matches might become closed before they are joined. + /// Simply re-connect to master and find another. + /// Use property "IsVisible" to not list the room. + /// + /// + /// As part of RoomInfo this can't be set. + /// As part of a Room (which the player joined), the setter will update the server and all clients. + /// + public bool IsOpen + { + get + { + return this.openField; + } + } + + /// + /// Defines if the room is listed in its lobby. + /// Rooms can be created invisible, or changed to invisible. + /// To change if a room can be joined, use property: open. + /// + /// + /// As part of RoomInfo this can't be set. + /// As part of a Room (which the player joined), the setter will update the server and all clients. + /// + public bool IsVisible + { + get + { + return this.visibleField; + } + } + + /// + /// Constructs a RoomInfo to be used in room listings in lobby. + /// + /// + /// + protected internal RoomInfo(string roomName, Hashtable properties) + { + this.InternalCacheProperties(properties); + + this.nameField = roomName; + } + + /// + /// Makes RoomInfo comparable (by name). + /// + public override bool Equals(object other) + { + RoomInfo otherRoomInfo = other as RoomInfo; + return (otherRoomInfo != null && this.Name.Equals(otherRoomInfo.nameField)); + } + + /// + /// Accompanies Equals, using the name's HashCode as return. + /// + /// + public override int GetHashCode() + { + return this.nameField.GetHashCode(); + } + + + /// Simple printingin method. + /// Summary of this RoomInfo instance. + public override string ToString() + { + return string.Format("Room: '{0}' {1},{2} {4}/{3} players.", this.nameField, this.visibleField ? "visible" : "hidden", this.openField ? "open" : "closed", this.maxPlayersField, this.PlayerCount); + } + + /// Simple printingin method. + /// Summary of this RoomInfo instance. + public string ToStringFull() + { + return string.Format("Room: '{0}' {1},{2} {4}/{3} players.\ncustomProps: {5}", this.nameField, this.visibleField ? "visible" : "hidden", this.openField ? "open" : "closed", this.maxPlayersField, this.PlayerCount, this.customPropertiesField.ToStringFull()); + } + + /// Copies "well known" properties to fields (IsVisible, etc) and caches the custom properties (string-keys only) in a local hashtable. + /// New or updated properties to store in this RoomInfo. + protected internal void InternalCacheProperties(Hashtable propertiesToCache) + { + if (propertiesToCache == null || propertiesToCache.Count == 0 || this.customPropertiesField.Equals(propertiesToCache)) + { + return; + } + + // check of this game was removed from the list. in that case, we don't + // need to read any further properties + // list updates will remove this game from the game listing + if (propertiesToCache.ContainsKey(GamePropertyKey.Removed)) + { + this.removedFromList = (Boolean)propertiesToCache[GamePropertyKey.Removed]; + if (this.removedFromList) + { + return; + } + } + + // fetch the "well known" properties of the room, if available + if (propertiesToCache.ContainsKey(GamePropertyKey.MaxPlayers)) + { + this.maxPlayersField = (byte)propertiesToCache[GamePropertyKey.MaxPlayers]; + } + + if (propertiesToCache.ContainsKey(GamePropertyKey.IsOpen)) + { + this.openField = (bool)propertiesToCache[GamePropertyKey.IsOpen]; + } + + if (propertiesToCache.ContainsKey(GamePropertyKey.IsVisible)) + { + this.visibleField = (bool)propertiesToCache[GamePropertyKey.IsVisible]; + } + + if (propertiesToCache.ContainsKey(GamePropertyKey.PlayerCount)) + { + this.PlayerCount = (int)((byte)propertiesToCache[GamePropertyKey.PlayerCount]); + } + + if (propertiesToCache.ContainsKey(GamePropertyKey.CleanupCacheOnLeave)) + { + this.autoCleanUpField = (bool)propertiesToCache[GamePropertyKey.CleanupCacheOnLeave]; + } + + if (propertiesToCache.ContainsKey(GamePropertyKey.MasterClientId)) + { + this.serverSideMasterClient = true; + bool isUpdate = this.masterClientIdField != 0; + this.masterClientIdField = (int) propertiesToCache[GamePropertyKey.MasterClientId]; + if (isUpdate) + { + PhotonNetwork.networkingPeer.UpdateMasterClient(); + } + } + + //if (propertiesToCache.ContainsKey(GamePropertyKey.PropsListedInLobby)) + //{ + // // could be cached but isn't useful + //} + + if (propertiesToCache.ContainsKey((byte)GamePropertyKey.ExpectedUsers)) + { + this.expectedUsersField = (string[])propertiesToCache[GamePropertyKey.ExpectedUsers]; + } + + // merge the custom properties (from your application) to the cache (only string-typed keys will be kept) + this.customPropertiesField.MergeStringKeys(propertiesToCache); + this.customPropertiesField.StripKeysWithNullValues(); + } + + + #region Obsoleted variable names + + [Obsolete("Please use CustomProperties (updated case for naming).")] + public Hashtable customProperties { get { return this.CustomProperties; } } + + [Obsolete("Please use Name (updated case for naming).")] + public string name { get { return this.Name; } } + + [Obsolete("Please use PlayerCount (updated case for naming).")] + public int playerCount { get { return this.PlayerCount; } set { this.PlayerCount = value; } } + + [Obsolete("Please use IsLocalClientInside (updated case for naming).")] + public bool isLocalClientInside { get { return this.IsLocalClientInside; } set { this.IsLocalClientInside = value; } } + + [Obsolete("Please use MaxPlayers (updated case for naming).")] + public byte maxPlayers { get { return this.MaxPlayers; } } + + [Obsolete("Please use IsOpen (updated case for naming).")] + public bool open { get { return this.IsOpen; } } + + [Obsolete("Please use IsVisible (updated case for naming).")] + public bool visible { get { return this.IsVisible; } } + + #endregion +} diff --git a/Assets/Photon Unity Networking/Plugins/PhotonNetwork/RoomInfo.cs.meta b/Assets/Photon Unity Networking/Plugins/PhotonNetwork/RoomInfo.cs.meta new file mode 100644 index 0000000..a1188f0 --- /dev/null +++ b/Assets/Photon Unity Networking/Plugins/PhotonNetwork/RoomInfo.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 71760b65ad7d5b842942c797a0366fa7 +labels: +- ExitGames +- PUN +- Photon +- Networking +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} diff --git a/Assets/Photon Unity Networking/Plugins/PhotonNetwork/ServerSettings.cs b/Assets/Photon Unity Networking/Plugins/PhotonNetwork/ServerSettings.cs new file mode 100644 index 0000000..7667eb5 --- /dev/null +++ b/Assets/Photon Unity Networking/Plugins/PhotonNetwork/ServerSettings.cs @@ -0,0 +1,186 @@ +#pragma warning disable 1587 +/// \file +/// ScriptableObject defining a server setup. An instance is created as PhotonServerSettings. +#pragma warning restore 1587 + +using System; +using System.Collections.Generic; +using ExitGames.Client.Photon; +using UnityEngine; + + +public class Region +{ + public CloudRegionCode Code; + /// Unlike the CloudRegionCode, this may contain cluster information. + public string Cluster; + public string HostAndPort; + public int Ping; + + public Region(CloudRegionCode code) + { + this.Code = code; + this.Cluster = code.ToString(); + } + + public Region(CloudRegionCode code, string regionCodeString, string address) + { + this.Code = code; + this.Cluster = regionCodeString; + this.HostAndPort = address; + } + + public static CloudRegionCode Parse(string codeAsString) + { + if (codeAsString == null) + { + return CloudRegionCode.none; + } + + int slash = codeAsString.IndexOf('/'); + if (slash > 0) + { + codeAsString = codeAsString.Substring(0, slash); + } + codeAsString = codeAsString.ToLower(); + + if (Enum.IsDefined(typeof(CloudRegionCode), codeAsString)) + { + return (CloudRegionCode)Enum.Parse(typeof(CloudRegionCode), codeAsString); + } + + return CloudRegionCode.none; + } + + + internal static CloudRegionFlag ParseFlag(CloudRegionCode region) + { + if (Enum.IsDefined(typeof(CloudRegionFlag), region.ToString())) + { + return (CloudRegionFlag)Enum.Parse(typeof(CloudRegionFlag), region.ToString()); + } + + return (CloudRegionFlag)0; + } + + [Obsolete] + internal static CloudRegionFlag ParseFlag(string codeAsString) + { + codeAsString = codeAsString.ToLower(); + + CloudRegionFlag code = 0; + if (Enum.IsDefined(typeof(CloudRegionFlag), codeAsString)) + { + code = (CloudRegionFlag)Enum.Parse(typeof(CloudRegionFlag), codeAsString); + } + + return code; + } + + public override string ToString() + { + return string.Format("'{0}' \t{1}ms \t{2}", this.Cluster, this.Ping, this.HostAndPort); + } +} + + +/// +/// Collection of connection-relevant settings, used internally by PhotonNetwork.ConnectUsingSettings. +/// +[Serializable] +public class ServerSettings : ScriptableObject +{ + public enum HostingOption { NotSet = 0, PhotonCloud = 1, SelfHosted = 2, OfflineMode = 3, BestRegion = 4 } + + public string AppID = ""; + public string VoiceAppID = ""; + public string ChatAppID = ""; + + public HostingOption HostType = HostingOption.NotSet; + + public CloudRegionCode PreferredRegion; + public CloudRegionFlag EnabledRegions = (CloudRegionFlag)(-1); + + public ConnectionProtocol Protocol = ConnectionProtocol.Udp; + public string ServerAddress = ""; + public int ServerPort = 5055; + public int VoiceServerPort = 5055; // Voice only uses UDP + + + public bool JoinLobby; + public bool EnableLobbyStatistics; + public PhotonLogLevel PunLogging = PhotonLogLevel.ErrorsOnly; + public DebugLevel NetworkLogging = DebugLevel.ERROR; + + public bool RunInBackground = true; + + public List RpcList = new List(); // set by scripts and or via Inspector + + [HideInInspector] + public bool DisableAutoOpenWizard; + + + public void UseCloudBestRegion(string cloudAppid) + { + this.HostType = HostingOption.BestRegion; + this.AppID = cloudAppid; + } + + public void UseCloud(string cloudAppid) + { + this.HostType = HostingOption.PhotonCloud; + this.AppID = cloudAppid; + } + + public void UseCloud(string cloudAppid, CloudRegionCode code) + { + this.HostType = HostingOption.PhotonCloud; + this.AppID = cloudAppid; + this.PreferredRegion = code; + } + + public void UseMyServer(string serverAddress, int serverPort, string application) + { + this.HostType = HostingOption.SelfHosted; + this.AppID = (application != null) ? application : "master"; + + this.ServerAddress = serverAddress; + this.ServerPort = serverPort; + } + + /// Checks if a string is a Guid by attempting to create one. + /// The potential guid to check. + /// True if new Guid(val) did not fail. + public static bool IsAppId(string val) + { + try + { + new Guid(val); + } + catch + { + return false; + } + return true; + } + + /// + /// Gets the best region code in preferences. + /// This composes the PhotonHandler, since its Internal and can not be accessed by the custom inspector + /// + /// The best region code in preferences. + public static CloudRegionCode BestRegionCodeInPreferences + { + get { return PhotonHandler.BestRegionCodeInPreferences; } + } + + public static void ResetBestRegionCodeInPreferences() + { + PhotonHandler.BestRegionCodeInPreferences = CloudRegionCode.none; + } + + public override string ToString() + { + return "ServerSettings: " + HostType + " " + ServerAddress; + } +} diff --git a/Assets/Photon Unity Networking/Plugins/PhotonNetwork/ServerSettings.cs.meta b/Assets/Photon Unity Networking/Plugins/PhotonNetwork/ServerSettings.cs.meta new file mode 100644 index 0000000..401bf34 --- /dev/null +++ b/Assets/Photon Unity Networking/Plugins/PhotonNetwork/ServerSettings.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 9f3758f8f58fdef43803eb9be1df0608 +labels: +- ExitGames +- PUN +- Photon +- Networking +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} diff --git a/Assets/Photon Unity Networking/Plugins/PhotonNetwork/SocketUdp.cs b/Assets/Photon Unity Networking/Plugins/PhotonNetwork/SocketUdp.cs new file mode 100644 index 0000000..11851b7 --- /dev/null +++ b/Assets/Photon Unity Networking/Plugins/PhotonNetwork/SocketUdp.cs @@ -0,0 +1,229 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Protocol & Photon Client Lib - Copyright (C) 2013 Exit Games GmbH +// +// +// Uses the UDP socket for a peer to send and receive enet/Photon messages. +// +// developer@exitgames.com +// -------------------------------------------------------------------------------------------------------------------- + +#if UNITY_EDITOR || (!UNITY_ANDROID && !UNITY_IPHONE && !UNITY_PS3 && !UNITY_WINRT && !UNITY_WP8) + +namespace ExitGames.Client.Photon +{ + using System; + using System.Net; + using System.Net.Sockets; + using System.Security; + using System.Threading; + + /// Internal class to encapsulate the network i/o functionality for the realtime libary. + internal class SocketUdp : IPhotonSocket, IDisposable + { + private Socket sock; + + private readonly object syncer = new object(); + + public SocketUdp(PeerBase npeer) : base(npeer) + { + if (this.ReportDebugOfLevel(DebugLevel.ALL)) + { + this.Listener.DebugReturn(DebugLevel.ALL, "CSharpSocket: UDP, Unity3d."); + } + + this.Protocol = ConnectionProtocol.Udp; + this.PollReceive = false; + } + + public void Dispose() + { + this.State = PhotonSocketState.Disconnecting; + + if (this.sock != null) + { + try + { + if (this.sock.Connected) this.sock.Close(); + } + catch (Exception ex) + { + this.EnqueueDebugReturn(DebugLevel.INFO, "Exception in Dispose(): " + ex); + } + } + + this.sock = null; + this.State = PhotonSocketState.Disconnected; + } + + public override bool Connect() + { + lock (this.syncer) + { + bool baseOk = base.Connect(); + if (!baseOk) + { + return false; + } + + this.State = PhotonSocketState.Connecting; + + Thread dns = new Thread(this.DnsAndConnect); + dns.Name = "photon dns thread"; + dns.IsBackground = true; + dns.Start(); + + return true; + } + } + + public override bool Disconnect() + { + if (this.ReportDebugOfLevel(DebugLevel.INFO)) + { + this.EnqueueDebugReturn(DebugLevel.INFO, "CSharpSocket.Disconnect()"); + } + + this.State = PhotonSocketState.Disconnecting; + + lock (this.syncer) + { + if (this.sock != null) + { + try + { + this.sock.Close(); + } + catch (Exception ex) + { + this.EnqueueDebugReturn(DebugLevel.INFO, "Exception in Disconnect(): " + ex); + } + + this.sock = null; + } + } + + this.State = PhotonSocketState.Disconnected; + return true; + } + + /// used by PhotonPeer* + public override PhotonSocketError Send(byte[] data, int length) + { + lock (this.syncer) + { + if (this.sock == null || !this.sock.Connected) + { + return PhotonSocketError.Skipped; + } + + try + { + sock.Send(data, 0, length, SocketFlags.None); + } + catch (Exception e) + { + if (this.ReportDebugOfLevel(DebugLevel.ERROR)) + { + this.EnqueueDebugReturn(DebugLevel.ERROR, "Cannot send to: " + this.ServerAddress + ". " + e.Message); + } + return PhotonSocketError.Exception; + } + } + + return PhotonSocketError.Success; + } + + public override PhotonSocketError Receive(out byte[] data) + { + data = null; + return PhotonSocketError.NoData; + } + + internal void DnsAndConnect() + { + IPAddress ipAddress = null; + try + { + ipAddress = IPhotonSocket.GetIpAddress(this.ServerAddress); + if (ipAddress == null) + { + // this covers cases of failed DNS lookup and bad addresses. + throw new ArgumentException("Invalid IPAddress. Address: " + this.ServerAddress); + } + + lock (this.syncer) + { + if (this.State == PhotonSocketState.Disconnecting || this.State == PhotonSocketState.Disconnected) + { + return; + } + + this.sock = new Socket(ipAddress.AddressFamily, SocketType.Dgram, ProtocolType.Udp); + this.sock.Connect(ipAddress, this.ServerPort); + + this.AddressResolvedAsIpv6 = this.IsIpv6SimpleCheck(ipAddress); + this.State = PhotonSocketState.Connected; + + this.peerBase.OnConnect(); + } + } + catch (SecurityException se) + { + if (this.ReportDebugOfLevel(DebugLevel.ERROR)) + { + this.Listener.DebugReturn(DebugLevel.ERROR, "Connect() to '" + this.ServerAddress + "' (" + ((ipAddress == null ) ? "": ipAddress.AddressFamily.ToString()) + ") failed: " + se.ToString()); + } + + this.HandleException(StatusCode.SecurityExceptionOnConnect); + return; + } + catch (Exception se) + { + if (this.ReportDebugOfLevel(DebugLevel.ERROR)) + { + this.Listener.DebugReturn(DebugLevel.ERROR, "Connect() to '" + this.ServerAddress + "' (" + ((ipAddress == null) ? "" : ipAddress.AddressFamily.ToString()) + ") failed: " + se.ToString()); + } + + this.HandleException(StatusCode.ExceptionOnConnect); + return; + } + + Thread run = new Thread(new ThreadStart(ReceiveLoop)); + run.Name = "photon receive thread"; + run.IsBackground = true; + run.Start(); + } + + /// Endless loop, run in Receive Thread. + public void ReceiveLoop() + { + byte[] inBuffer = new byte[this.MTU]; + while (this.State == PhotonSocketState.Connected) + { + try + { + int read = this.sock.Receive(inBuffer); + this.HandleReceivedDatagram(inBuffer, read, true); + } + catch (Exception e) + { + if (this.State != PhotonSocketState.Disconnecting && this.State != PhotonSocketState.Disconnected) + { + if (this.ReportDebugOfLevel(DebugLevel.ERROR)) + { + this.EnqueueDebugReturn(DebugLevel.ERROR, "Receive issue. State: " + this.State + ". Server: '" + this.ServerAddress + "' Exception: " + e); + } + + this.HandleException(StatusCode.ExceptionOnReceive); + } + } + } //while Connected receive + + // on exit of the receive-loop: disconnect socket + this.Disconnect(); + } + } //class + +} +#endif diff --git a/Assets/Photon Unity Networking/Plugins/PhotonNetwork/SocketUdp.cs.meta b/Assets/Photon Unity Networking/Plugins/PhotonNetwork/SocketUdp.cs.meta new file mode 100644 index 0000000..b51113e --- /dev/null +++ b/Assets/Photon Unity Networking/Plugins/PhotonNetwork/SocketUdp.cs.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: fdcd4031513ba944ba1cc57b3aff328a +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} diff --git a/Assets/Photon Unity Networking/Plugins/PhotonNetwork/SocketWebTcp.cs b/Assets/Photon Unity Networking/Plugins/PhotonNetwork/SocketWebTcp.cs new file mode 100644 index 0000000..67807e3 --- /dev/null +++ b/Assets/Photon Unity Networking/Plugins/PhotonNetwork/SocketWebTcp.cs @@ -0,0 +1,282 @@ +#if UNITY_WEBGL || UNITY_XBOXONE +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) Exit Games GmbH. All rights reserved. +// +// +// Internal class to encapsulate the network i/o functionality for the realtime libary. +// +// developer@exitgames.com +// -------------------------------------------------------------------------------------------------------------------- + +using System; +using System.Collections; +using UnityEngine; +using SupportClassPun = ExitGames.Client.Photon.SupportClass; + + +namespace ExitGames.Client.Photon +{ + #if UNITY_5_3 || UNITY_5_3_OR_NEWER + /// + /// Yield Instruction to Wait for real seconds. Very important to keep connection working if Time.TimeScale is altered, we still want accurate network events + /// + public sealed class WaitForRealSeconds : CustomYieldInstruction + { + private readonly float _endTime; + + public override bool keepWaiting + { + get { return _endTime > Time.realtimeSinceStartup; } + } + + public WaitForRealSeconds(float seconds) + { + _endTime = Time.realtimeSinceStartup + seconds; + } + } + #endif + + /// + /// Internal class to encapsulate the network i/o functionality for the realtime libary. + /// + public class SocketWebTcp : IPhotonSocket, IDisposable + { + private WebSocket sock; + + private readonly object syncer = new object(); + + public SocketWebTcp(PeerBase npeer) : base(npeer) + { + ServerAddress = npeer.ServerAddress; + if (this.ReportDebugOfLevel(DebugLevel.INFO)) + { + Listener.DebugReturn(DebugLevel.INFO, "new SocketWebTcp() for Unity. Server: " + ServerAddress); + } + + this.Protocol = ConnectionProtocol.WebSocket; + this.PollReceive = false; + } + + public void Dispose() + { + this.State = PhotonSocketState.Disconnecting; + + if (this.sock != null) + { + try + { + if (this.sock.Connected) this.sock.Close(); + } + catch (Exception ex) + { + this.EnqueueDebugReturn(DebugLevel.INFO, "Exception in Dispose(): " + ex); + } + } + + this.sock = null; + this.State = PhotonSocketState.Disconnected; + } + + GameObject websocketConnectionObject; + public override bool Connect() + { + //bool baseOk = base.Connect(); + //if (!baseOk) + //{ + // return false; + //} + + + State = PhotonSocketState.Connecting; + + if (this.websocketConnectionObject != null) + { + UnityEngine.Object.Destroy(this.websocketConnectionObject); + } + + this.websocketConnectionObject = new GameObject("websocketConnectionObject"); + MonoBehaviour mb = this.websocketConnectionObject.AddComponent(); + this.websocketConnectionObject.hideFlags = HideFlags.HideInHierarchy; + UnityEngine.Object.DontDestroyOnLoad(this.websocketConnectionObject); + + this.sock = new WebSocket(new Uri(ServerAddress)); + this.sock.Connect(); + + mb.StartCoroutine(this.ReceiveLoop()); + return true; + } + + + public override bool Disconnect() + { + if (ReportDebugOfLevel(DebugLevel.INFO)) + { + this.Listener.DebugReturn(DebugLevel.INFO, "SocketWebTcp.Disconnect()"); + } + + State = PhotonSocketState.Disconnecting; + + lock (this.syncer) + { + if (this.sock != null) + { + try + { + this.sock.Close(); + } + catch (Exception ex) + { + this.Listener.DebugReturn(DebugLevel.ERROR, "Exception in Disconnect(): " + ex); + } + this.sock = null; + } + } + + if (this.websocketConnectionObject != null) + { + UnityEngine.Object.Destroy(this.websocketConnectionObject); + } + + State = PhotonSocketState.Disconnected; + return true; + } + + /// + /// used by TPeer* + /// + public override PhotonSocketError Send(byte[] data, int length) + { + if (this.State != PhotonSocketState.Connected) + { + return PhotonSocketError.Skipped; + } + + try + { + if (this.ReportDebugOfLevel(DebugLevel.ALL)) + { + this.Listener.DebugReturn(DebugLevel.ALL, "Sending: " + SupportClassPun.ByteArrayToString(data)); + } + + if (this.sock != null) + { + this.sock.Send(data); + } + } + catch (Exception e) + { + this.Listener.DebugReturn(DebugLevel.ERROR, "Cannot send to: " + this.ServerAddress + ". " + e.Message); + + HandleException(StatusCode.Exception); + return PhotonSocketError.Exception; + } + + return PhotonSocketError.Success; + } + + public override PhotonSocketError Receive(out byte[] data) + { + data = null; + return PhotonSocketError.NoData; + } + + + internal const int ALL_HEADER_BYTES = 9; + internal const int TCP_HEADER_BYTES = 7; + internal const int MSG_HEADER_BYTES = 2; + + public IEnumerator ReceiveLoop() + { + this.Listener.DebugReturn(DebugLevel.INFO, "ReceiveLoop()"); + if (this.sock != null) + { + while (this.sock != null && !this.sock.Connected && this.sock.Error == null) + { + #if UNITY_5_3 || UNITY_5_3_OR_NEWER + yield return new WaitForRealSeconds(0.1f); + #else + float waittime = Time.realtimeSinceStartup + 0.1f; + while (Time.realtimeSinceStartup < waittime) yield return 0; + #endif + } + + if (this.sock != null) + { + if (this.sock.Error != null) + { + this.Listener.DebugReturn(DebugLevel.ERROR, "Exiting receive thread. Server: " + this.ServerAddress + ":" + this.ServerPort + " Error: " + this.sock.Error); + this.HandleException(StatusCode.ExceptionOnConnect); + } + else + { + // connected + if (this.ReportDebugOfLevel(DebugLevel.ALL)) + { + this.Listener.DebugReturn(DebugLevel.ALL, "Receiving by websocket. this.State: " + State); + } + State = PhotonSocketState.Connected; + while (State == PhotonSocketState.Connected) + { + if (this.sock != null) + { + if (this.sock.Error != null) + { + this.Listener.DebugReturn(DebugLevel.ERROR, "Exiting receive thread (inside loop). Server: " + this.ServerAddress + ":" + this.ServerPort + " Error: " + this.sock.Error); + this.HandleException(StatusCode.ExceptionOnReceive); + break; + } + else + { + byte[] inBuff = this.sock.Recv(); + if (inBuff == null || inBuff.Length == 0) + { + // nothing received. wait a bit, try again + #if UNITY_5_3 || UNITY_5_3_OR_NEWER + yield return new WaitForRealSeconds(0.02f); + #else + float waittime = Time.realtimeSinceStartup + 0.02f; + while (Time.realtimeSinceStartup < waittime) yield return 0; + #endif + continue; + } + + if (this.ReportDebugOfLevel(DebugLevel.ALL)) + { + this.Listener.DebugReturn(DebugLevel.ALL, "TCP << " + inBuff.Length + " = " + SupportClassPun.ByteArrayToString(inBuff)); + } + + if (inBuff.Length > 0) + { + try + { + HandleReceivedDatagram(inBuff, inBuff.Length, false); + } + catch (Exception e) + { + if (this.State != PhotonSocketState.Disconnecting && this.State != PhotonSocketState.Disconnected) + { + if (this.ReportDebugOfLevel(DebugLevel.ERROR)) + { + this.EnqueueDebugReturn(DebugLevel.ERROR, "Receive issue. State: " + this.State + ". Server: '" + this.ServerAddress + "' Exception: " + e); + } + + this.HandleException(StatusCode.ExceptionOnReceive); + } + } + } + } + } + } + } + } + } + + this.Disconnect(); + } + } + + internal class MonoBehaviourExt : MonoBehaviour { } +} + +#endif diff --git a/Assets/Photon Unity Networking/Plugins/PhotonNetwork/SocketWebTcp.cs.meta b/Assets/Photon Unity Networking/Plugins/PhotonNetwork/SocketWebTcp.cs.meta new file mode 100644 index 0000000..7f04d3c --- /dev/null +++ b/Assets/Photon Unity Networking/Plugins/PhotonNetwork/SocketWebTcp.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ac953d6a57a9ea94e96ec689598995d5 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Photon Unity Networking/Plugins/PhotonNetwork/Views.meta b/Assets/Photon Unity Networking/Plugins/PhotonNetwork/Views.meta new file mode 100644 index 0000000..796d374 --- /dev/null +++ b/Assets/Photon Unity Networking/Plugins/PhotonNetwork/Views.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 679a8d2fc554a44dc8fb71550474bfa5 +folderAsset: yes +timeCreated: 1501014811 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Photon Unity Networking/Plugins/PhotonNetwork/Views/PhotonAnimatorView.cs b/Assets/Photon Unity Networking/Plugins/PhotonNetwork/Views/PhotonAnimatorView.cs new file mode 100644 index 0000000..cba9a8b --- /dev/null +++ b/Assets/Photon Unity Networking/Plugins/PhotonNetwork/Views/PhotonAnimatorView.cs @@ -0,0 +1,544 @@ +// ---------------------------------------------------------------------------- +// +// PhotonNetwork Framework for Unity - Copyright (C) 2016 Exit Games GmbH +// +// +// Component to synchronize Mecanim animations via PUN. +// +// developer@exitgames.com +// ---------------------------------------------------------------------------- + +using System.Collections.Generic; +using UnityEngine; + +/// +/// This class helps you to synchronize Mecanim animations +/// Simply add the component to your GameObject and make sure that +/// the PhotonAnimatorView is added to the list of observed components +/// +/// +/// When Using Trigger Parameters, make sure the component that sets the trigger is higher in the stack of Components on the GameObject than 'PhotonAnimatorView' +/// Triggers are raised true during one frame only. +/// +[RequireComponent(typeof(Animator))] +[RequireComponent(typeof(PhotonView))] +[AddComponentMenu("Photon Networking/Photon Animator View")] +public class PhotonAnimatorView : MonoBehaviour, IPunObservable +{ + #region Enums + + public enum ParameterType + { + Float = 1, + Int = 3, + Bool = 4, + Trigger = 9, + } + + public enum SynchronizeType + { + Disabled = 0, + Discrete = 1, + Continuous = 2, + } + + [System.Serializable] + public class SynchronizedParameter + { + public ParameterType Type; + public SynchronizeType SynchronizeType; + public string Name; + } + + [System.Serializable] + public class SynchronizedLayer + { + public SynchronizeType SynchronizeType; + public int LayerIndex; + } + + #endregion + + #region Properties + +#if PHOTON_DEVELOP + public PhotonAnimatorView ReceivingSender; +#endif + + #endregion + + #region Members + + private Animator m_Animator; + + private PhotonStreamQueue m_StreamQueue; + + //These fields are only used in the CustomEditor for this script and would trigger a + //"this variable is never used" warning, which I am suppressing here +#pragma warning disable 0414 + [HideInInspector] + [SerializeField] + private bool ShowLayerWeightsInspector = true; + + [HideInInspector] + [SerializeField] + private bool ShowParameterInspector = true; +#pragma warning restore 0414 + + [HideInInspector] + [SerializeField] + private List m_SynchronizeParameters = new List(); + + [HideInInspector] + [SerializeField] + private List m_SynchronizeLayers = new List(); + + private Vector3 m_ReceiverPosition; + private float m_LastDeserializeTime; + private bool m_WasSynchronizeTypeChanged = true; + private PhotonView m_PhotonView; + + /// + /// Cached raised triggers that are set to be synchronized in discrete mode. since a Trigger only stay up for less than a frame, + /// We need to cache it until the next discrete serialization call. + /// + List m_raisedDiscreteTriggersCache = new List(); + + #endregion + + #region Unity + + private void Awake() + { + this.m_PhotonView = GetComponent(); + this.m_StreamQueue = new PhotonStreamQueue(120); + + this.m_Animator = GetComponent(); + } + + private void Update() + { + if (this.m_Animator.applyRootMotion && this.m_PhotonView.isMine == false && PhotonNetwork.connected == true) + { + this.m_Animator.applyRootMotion = false; + } + + if (PhotonNetwork.inRoom == false || PhotonNetwork.room.PlayerCount <= 1) + { + this.m_StreamQueue.Reset(); + return; + } + + if (this.m_PhotonView.isMine == true) + { + this.SerializeDataContinuously(); + + this.CacheDiscreteTriggers(); + } + else + { + this.DeserializeDataContinuously(); + } + } + + #endregion + + #region Setup Synchronizing Methods + + /// + /// Caches the discrete triggers values for keeping track of raised triggers, and will be reseted after the sync routine got performed + /// + public void CacheDiscreteTriggers() + { + for (int i = 0; i < this.m_SynchronizeParameters.Count; ++i) + { + SynchronizedParameter parameter = this.m_SynchronizeParameters[i]; + + if (parameter.SynchronizeType == SynchronizeType.Discrete && parameter.Type == ParameterType.Trigger && this.m_Animator.GetBool(parameter.Name)) + { + if (parameter.Type == ParameterType.Trigger) + { + this.m_raisedDiscreteTriggersCache.Add(parameter.Name); + break; + } + } + } + } + + /// + /// Check if a specific layer is configured to be synchronize + /// + /// Index of the layer. + /// True if the layer is synchronized + public bool DoesLayerSynchronizeTypeExist(int layerIndex) + { + return this.m_SynchronizeLayers.FindIndex(item => item.LayerIndex == layerIndex) != -1; + } + + /// + /// Check if the specified parameter is configured to be synchronized + /// + /// The name of the parameter. + /// True if the parameter is synchronized + public bool DoesParameterSynchronizeTypeExist(string name) + { + return this.m_SynchronizeParameters.FindIndex(item => item.Name == name) != -1; + } + + /// + /// Get a list of all synchronized layers + /// + /// List of SynchronizedLayer objects + public List GetSynchronizedLayers() + { + return this.m_SynchronizeLayers; + } + + /// + /// Get a list of all synchronized parameters + /// + /// List of SynchronizedParameter objects + public List GetSynchronizedParameters() + { + return this.m_SynchronizeParameters; + } + + /// + /// Gets the type how the layer is synchronized + /// + /// Index of the layer. + /// Disabled/Discrete/Continuous + public SynchronizeType GetLayerSynchronizeType(int layerIndex) + { + int index = this.m_SynchronizeLayers.FindIndex(item => item.LayerIndex == layerIndex); + + if (index == -1) + { + return SynchronizeType.Disabled; + } + + return this.m_SynchronizeLayers[index].SynchronizeType; + } + + /// + /// Gets the type how the parameter is synchronized + /// + /// The name of the parameter. + /// Disabled/Discrete/Continuous + public SynchronizeType GetParameterSynchronizeType(string name) + { + int index = this.m_SynchronizeParameters.FindIndex(item => item.Name == name); + + if (index == -1) + { + return SynchronizeType.Disabled; + } + + return this.m_SynchronizeParameters[index].SynchronizeType; + } + + /// + /// Sets the how a layer should be synchronized + /// + /// Index of the layer. + /// Disabled/Discrete/Continuous + public void SetLayerSynchronized(int layerIndex, SynchronizeType synchronizeType) + { + if (Application.isPlaying == true) + { + this.m_WasSynchronizeTypeChanged = true; + } + + int index = this.m_SynchronizeLayers.FindIndex(item => item.LayerIndex == layerIndex); + + if (index == -1) + { + this.m_SynchronizeLayers.Add(new SynchronizedLayer { LayerIndex = layerIndex, SynchronizeType = synchronizeType }); + } + else + { + this.m_SynchronizeLayers[index].SynchronizeType = synchronizeType; + } + } + + /// + /// Sets the how a parameter should be synchronized + /// + /// The name of the parameter. + /// The type of the parameter. + /// Disabled/Discrete/Continuous + public void SetParameterSynchronized(string name, ParameterType type, SynchronizeType synchronizeType) + { + if (Application.isPlaying == true) + { + this.m_WasSynchronizeTypeChanged = true; + } + + int index = this.m_SynchronizeParameters.FindIndex(item => item.Name == name); + + if (index == -1) + { + this.m_SynchronizeParameters.Add(new SynchronizedParameter { Name = name, Type = type, SynchronizeType = synchronizeType }); + } + else + { + this.m_SynchronizeParameters[index].SynchronizeType = synchronizeType; + } + } + + #endregion + + #region Serialization + + private void SerializeDataContinuously() + { + if (this.m_Animator == null) + { + return; + } + + for (int i = 0; i < this.m_SynchronizeLayers.Count; ++i) + { + if (this.m_SynchronizeLayers[i].SynchronizeType == SynchronizeType.Continuous) + { + this.m_StreamQueue.SendNext(this.m_Animator.GetLayerWeight(this.m_SynchronizeLayers[i].LayerIndex)); + } + } + + for (int i = 0; i < this.m_SynchronizeParameters.Count; ++i) + { + SynchronizedParameter parameter = this.m_SynchronizeParameters[i]; + + if (parameter.SynchronizeType == SynchronizeType.Continuous) + { + switch (parameter.Type) + { + case ParameterType.Bool: + this.m_StreamQueue.SendNext(this.m_Animator.GetBool(parameter.Name)); + break; + case ParameterType.Float: + this.m_StreamQueue.SendNext(this.m_Animator.GetFloat(parameter.Name)); + break; + case ParameterType.Int: + this.m_StreamQueue.SendNext(this.m_Animator.GetInteger(parameter.Name)); + break; + case ParameterType.Trigger: + this.m_StreamQueue.SendNext(this.m_Animator.GetBool(parameter.Name)); + break; + } + } + } + } + + + private void DeserializeDataContinuously() + { + if (this.m_StreamQueue.HasQueuedObjects() == false) + { + return; + } + + for (int i = 0; i < this.m_SynchronizeLayers.Count; ++i) + { + if (this.m_SynchronizeLayers[i].SynchronizeType == SynchronizeType.Continuous) + { + this.m_Animator.SetLayerWeight(this.m_SynchronizeLayers[i].LayerIndex, (float)this.m_StreamQueue.ReceiveNext()); + } + } + + for (int i = 0; i < this.m_SynchronizeParameters.Count; ++i) + { + SynchronizedParameter parameter = this.m_SynchronizeParameters[i]; + + if (parameter.SynchronizeType == SynchronizeType.Continuous) + { + switch (parameter.Type) + { + case ParameterType.Bool: + this.m_Animator.SetBool(parameter.Name, (bool)this.m_StreamQueue.ReceiveNext()); + break; + case ParameterType.Float: + this.m_Animator.SetFloat(parameter.Name, (float)this.m_StreamQueue.ReceiveNext()); + break; + case ParameterType.Int: + this.m_Animator.SetInteger(parameter.Name, (int)this.m_StreamQueue.ReceiveNext()); + break; + case ParameterType.Trigger: + this.m_Animator.SetBool(parameter.Name, (bool)this.m_StreamQueue.ReceiveNext()); + break; + } + } + } + } + + private void SerializeDataDiscretly(PhotonStream stream) + { + for (int i = 0; i < this.m_SynchronizeLayers.Count; ++i) + { + if (this.m_SynchronizeLayers[i].SynchronizeType == SynchronizeType.Discrete) + { + stream.SendNext(this.m_Animator.GetLayerWeight(this.m_SynchronizeLayers[i].LayerIndex)); + } + } + + for (int i = 0; i < this.m_SynchronizeParameters.Count; ++i) + { + SynchronizedParameter parameter = this.m_SynchronizeParameters[i]; + + if (parameter.SynchronizeType == SynchronizeType.Discrete) + { + switch (parameter.Type) + { + case ParameterType.Bool: + stream.SendNext(this.m_Animator.GetBool(parameter.Name)); + break; + case ParameterType.Float: + stream.SendNext(this.m_Animator.GetFloat(parameter.Name)); + break; + case ParameterType.Int: + stream.SendNext(this.m_Animator.GetInteger(parameter.Name)); + break; + case ParameterType.Trigger: + // here we can't rely on the current real state of the trigger, we might have missed its raise + stream.SendNext(this.m_raisedDiscreteTriggersCache.Contains(parameter.Name)); + break; + } + } + } + + // reset the cache, we've synchronized. + this.m_raisedDiscreteTriggersCache.Clear(); + } + + private void DeserializeDataDiscretly(PhotonStream stream) + { + for (int i = 0; i < this.m_SynchronizeLayers.Count; ++i) + { + if (this.m_SynchronizeLayers[i].SynchronizeType == SynchronizeType.Discrete) + { + this.m_Animator.SetLayerWeight(this.m_SynchronizeLayers[i].LayerIndex, (float)stream.ReceiveNext()); + } + } + + for (int i = 0; i < this.m_SynchronizeParameters.Count; ++i) + { + SynchronizedParameter parameter = this.m_SynchronizeParameters[i]; + + if (parameter.SynchronizeType == SynchronizeType.Discrete) + { + switch (parameter.Type) + { + case ParameterType.Bool: + if (stream.PeekNext() is bool == false) + { + return; + } + this.m_Animator.SetBool(parameter.Name, (bool)stream.ReceiveNext()); + break; + case ParameterType.Float: + if (stream.PeekNext() is float == false) + { + return; + } + + this.m_Animator.SetFloat(parameter.Name, (float)stream.ReceiveNext()); + break; + case ParameterType.Int: + if (stream.PeekNext() is int == false) + { + return; + } + + this.m_Animator.SetInteger(parameter.Name, (int)stream.ReceiveNext()); + break; + case ParameterType.Trigger: + if (stream.PeekNext() is bool == false) + { + return; + } + + if ((bool)stream.ReceiveNext()) + { + this.m_Animator.SetTrigger(parameter.Name); + } + break; + } + } + } + } + + private void SerializeSynchronizationTypeState(PhotonStream stream) + { + byte[] states = new byte[this.m_SynchronizeLayers.Count + this.m_SynchronizeParameters.Count]; + + for (int i = 0; i < this.m_SynchronizeLayers.Count; ++i) + { + states[i] = (byte)this.m_SynchronizeLayers[i].SynchronizeType; + } + + for (int i = 0; i < this.m_SynchronizeParameters.Count; ++i) + { + states[this.m_SynchronizeLayers.Count + i] = (byte)this.m_SynchronizeParameters[i].SynchronizeType; + } + + stream.SendNext(states); + } + + private void DeserializeSynchronizationTypeState(PhotonStream stream) + { + byte[] state = (byte[])stream.ReceiveNext(); + + for (int i = 0; i < this.m_SynchronizeLayers.Count; ++i) + { + this.m_SynchronizeLayers[i].SynchronizeType = (SynchronizeType)state[i]; + } + + for (int i = 0; i < this.m_SynchronizeParameters.Count; ++i) + { + this.m_SynchronizeParameters[i].SynchronizeType = (SynchronizeType)state[this.m_SynchronizeLayers.Count + i]; + } + } + + public void OnPhotonSerializeView(PhotonStream stream, PhotonMessageInfo info) + { + if (this.m_Animator == null) + { + return; + } + + if (stream.isWriting == true) + { + if (this.m_WasSynchronizeTypeChanged == true) + { + this.m_StreamQueue.Reset(); + this.SerializeSynchronizationTypeState(stream); + + this.m_WasSynchronizeTypeChanged = false; + } + + this.m_StreamQueue.Serialize(stream); + this.SerializeDataDiscretly(stream); + } + else + { +#if PHOTON_DEVELOP + if( ReceivingSender != null ) + { + ReceivingSender.OnPhotonSerializeView( stream, info ); + } + else +#endif + { + if (stream.PeekNext() is byte[]) + { + this.DeserializeSynchronizationTypeState(stream); + } + + this.m_StreamQueue.Deserialize(stream); + this.DeserializeDataDiscretly(stream); + } + } + } + + #endregion +} \ No newline at end of file diff --git a/Assets/Photon Unity Networking/Plugins/PhotonNetwork/Views/PhotonAnimatorView.cs.meta b/Assets/Photon Unity Networking/Plugins/PhotonNetwork/Views/PhotonAnimatorView.cs.meta new file mode 100644 index 0000000..9232492 --- /dev/null +++ b/Assets/Photon Unity Networking/Plugins/PhotonNetwork/Views/PhotonAnimatorView.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 9b8c4a61274f60b4ea5fb4299cfdbf14 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Photon Unity Networking/Plugins/PhotonNetwork/Views/PhotonRigidbody2DView.cs b/Assets/Photon Unity Networking/Plugins/PhotonNetwork/Views/PhotonRigidbody2DView.cs new file mode 100644 index 0000000..25aaf6b --- /dev/null +++ b/Assets/Photon Unity Networking/Plugins/PhotonNetwork/Views/PhotonRigidbody2DView.cs @@ -0,0 +1,68 @@ +// ---------------------------------------------------------------------------- +// +// PhotonNetwork Framework for Unity - Copyright (C) 2016 Exit Games GmbH +// +// +// Component to synchronize 2d rigidbodies via PUN. +// +// developer@exitgames.com +// ---------------------------------------------------------------------------- + +using UnityEngine; + +/// +/// This class helps you to synchronize the velocities of a 2d physics RigidBody. +/// Note that only the velocities are synchronized and because Unitys physics +/// engine is not deterministic (ie. the results aren't always the same on all +/// computers) - the actual positions of the objects may go out of sync. If you +/// want to have the position of this object the same on all clients, you should +/// also add a PhotonTransformView to synchronize the position. +/// Simply add the component to your GameObject and make sure that +/// the PhotonRigidbody2DView is added to the list of observed components +/// +[RequireComponent(typeof(PhotonView))] +[RequireComponent(typeof(Rigidbody2D))] +[AddComponentMenu("Photon Networking/Photon Rigidbody 2D View")] +public class PhotonRigidbody2DView : MonoBehaviour, IPunObservable +{ + [SerializeField] + bool m_SynchronizeVelocity = true; + + [SerializeField] + bool m_SynchronizeAngularVelocity = true; + + Rigidbody2D m_Body; + + void Awake() + { + this.m_Body = GetComponent(); + } + + public void OnPhotonSerializeView(PhotonStream stream, PhotonMessageInfo info) + { + if (stream.isWriting == true) + { + if (this.m_SynchronizeVelocity == true) + { + stream.SendNext(this.m_Body.velocity); + } + + if (this.m_SynchronizeAngularVelocity == true) + { + stream.SendNext(this.m_Body.angularVelocity); + } + } + else + { + if (this.m_SynchronizeVelocity == true) + { + this.m_Body.velocity = (Vector2)stream.ReceiveNext(); + } + + if (this.m_SynchronizeAngularVelocity == true) + { + this.m_Body.angularVelocity = (float)stream.ReceiveNext(); + } + } + } +} \ No newline at end of file diff --git a/Assets/Photon Unity Networking/Plugins/PhotonNetwork/Views/PhotonRigidbody2DView.cs.meta b/Assets/Photon Unity Networking/Plugins/PhotonNetwork/Views/PhotonRigidbody2DView.cs.meta new file mode 100644 index 0000000..b2e6d08 --- /dev/null +++ b/Assets/Photon Unity Networking/Plugins/PhotonNetwork/Views/PhotonRigidbody2DView.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 0e7cb724808c322458aa4d15f5035fa9 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Photon Unity Networking/Plugins/PhotonNetwork/Views/PhotonRigidbodyView.cs b/Assets/Photon Unity Networking/Plugins/PhotonNetwork/Views/PhotonRigidbodyView.cs new file mode 100644 index 0000000..bec072f --- /dev/null +++ b/Assets/Photon Unity Networking/Plugins/PhotonNetwork/Views/PhotonRigidbodyView.cs @@ -0,0 +1,68 @@ +// ---------------------------------------------------------------------------- +// +// PhotonNetwork Framework for Unity - Copyright (C) 2016 Exit Games GmbH +// +// +// Component to synchronize rigidbodies via PUN. +// +// developer@exitgames.com +// ---------------------------------------------------------------------------- + +using UnityEngine; + +/// +/// This class helps you to synchronize the velocities of a physics RigidBody. +/// Note that only the velocities are synchronized and because Unitys physics +/// engine is not deterministic (ie. the results aren't always the same on all +/// computers) - the actual positions of the objects may go out of sync. If you +/// want to have the position of this object the same on all clients, you should +/// also add a PhotonTransformView to synchronize the position. +/// Simply add the component to your GameObject and make sure that +/// the PhotonRigidbodyView is added to the list of observed components +/// +[RequireComponent(typeof(PhotonView))] +[RequireComponent(typeof(Rigidbody))] +[AddComponentMenu("Photon Networking/Photon Rigidbody View")] +public class PhotonRigidbodyView : MonoBehaviour, IPunObservable +{ + [SerializeField] + bool m_SynchronizeVelocity = true; + + [SerializeField] + bool m_SynchronizeAngularVelocity = true; + + Rigidbody m_Body; + + void Awake() + { + this.m_Body = GetComponent(); + } + + public void OnPhotonSerializeView(PhotonStream stream, PhotonMessageInfo info) + { + if (stream.isWriting == true) + { + if (this.m_SynchronizeVelocity == true) + { + stream.SendNext(this.m_Body.velocity); + } + + if (this.m_SynchronizeAngularVelocity == true) + { + stream.SendNext(this.m_Body.angularVelocity); + } + } + else + { + if (this.m_SynchronizeVelocity == true) + { + this.m_Body.velocity = (Vector3)stream.ReceiveNext(); + } + + if (this.m_SynchronizeAngularVelocity == true) + { + this.m_Body.angularVelocity = (Vector3)stream.ReceiveNext(); + } + } + } +} \ No newline at end of file diff --git a/Assets/Photon Unity Networking/Plugins/PhotonNetwork/Views/PhotonRigidbodyView.cs.meta b/Assets/Photon Unity Networking/Plugins/PhotonNetwork/Views/PhotonRigidbodyView.cs.meta new file mode 100644 index 0000000..e8c398f --- /dev/null +++ b/Assets/Photon Unity Networking/Plugins/PhotonNetwork/Views/PhotonRigidbodyView.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 64179f3720bbfe947b7724caa67b7c1d +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Photon Unity Networking/Plugins/PhotonNetwork/Views/PhotonTransformView.cs b/Assets/Photon Unity Networking/Plugins/PhotonNetwork/Views/PhotonTransformView.cs new file mode 100644 index 0000000..29f576d --- /dev/null +++ b/Assets/Photon Unity Networking/Plugins/PhotonNetwork/Views/PhotonTransformView.cs @@ -0,0 +1,214 @@ + // ---------------------------------------------------------------------------- +// +// PhotonNetwork Framework for Unity - Copyright (C) 2016 Exit Games GmbH +// +// +// Component to synchronize Transforms via PUN PhotonView. +// +// developer@exitgames.com +// ---------------------------------------------------------------------------- + +using UnityEngine; + +/// +/// This class helps you to synchronize position, rotation and scale +/// of a GameObject. It also gives you many different options to make +/// the synchronized values appear smooth, even when the data is only +/// send a couple of times per second. +/// Simply add the component to your GameObject and make sure that +/// the PhotonTransformView is added to the list of observed components +/// +[RequireComponent(typeof(PhotonView))] +[AddComponentMenu("Photon Networking/Photon Transform View")] +public class PhotonTransformView : MonoBehaviour, IPunObservable +{ + //Since this component is very complex, we seperated it into multiple objects. + //The PositionModel, RotationModel and ScaleMode store the data you are able to + //configure in the inspector while the control objects below are actually moving + //the object and calculating all the inter- and extrapolation + + [SerializeField] + PhotonTransformViewPositionModel m_PositionModel = new PhotonTransformViewPositionModel(); + + [SerializeField] + PhotonTransformViewRotationModel m_RotationModel = new PhotonTransformViewRotationModel(); + + [SerializeField] + PhotonTransformViewScaleModel m_ScaleModel = new PhotonTransformViewScaleModel(); + + PhotonTransformViewPositionControl m_PositionControl; + PhotonTransformViewRotationControl m_RotationControl; + PhotonTransformViewScaleControl m_ScaleControl; + + PhotonView m_PhotonView; + + bool m_ReceivedNetworkUpdate = false; + + /// + /// Flag to skip initial data when Object is instantiated and rely on the first deserialized data instead. + /// + bool m_firstTake = false; + + void Awake() + { + this.m_PhotonView = GetComponent(); + + this.m_PositionControl = new PhotonTransformViewPositionControl(this.m_PositionModel); + this.m_RotationControl = new PhotonTransformViewRotationControl(this.m_RotationModel); + this.m_ScaleControl = new PhotonTransformViewScaleControl(this.m_ScaleModel); + } + + void OnEnable() + { + m_firstTake = true; + } + + void Update() + { + if (this.m_PhotonView == null || this.m_PhotonView.isMine == true || PhotonNetwork.connected == false) + { + return; + } + + this.UpdatePosition(); + this.UpdateRotation(); + this.UpdateScale(); + } + + void UpdatePosition() + { + if (this.m_PositionModel.SynchronizeEnabled == false || this.m_ReceivedNetworkUpdate == false) + { + return; + } + + transform.localPosition = this.m_PositionControl.UpdatePosition(transform.localPosition); + } + + void UpdateRotation() + { + if (this.m_RotationModel.SynchronizeEnabled == false || this.m_ReceivedNetworkUpdate == false) + { + return; + } + + transform.localRotation = this.m_RotationControl.GetRotation(transform.localRotation); + } + + void UpdateScale() + { + if (this.m_ScaleModel.SynchronizeEnabled == false || this.m_ReceivedNetworkUpdate == false) + { + return; + } + + transform.localScale = this.m_ScaleControl.GetScale(transform.localScale); + } + + /// + /// These values are synchronized to the remote objects if the interpolation mode + /// or the extrapolation mode SynchronizeValues is used. Your movement script should pass on + /// the current speed (in units/second) and turning speed (in angles/second) so the remote + /// object can use them to predict the objects movement. + /// + /// The current movement vector of the object in units/second. + /// The current turn speed of the object in angles/second. + public void SetSynchronizedValues(Vector3 speed, float turnSpeed) + { + this.m_PositionControl.SetSynchronizedValues(speed, turnSpeed); + } + + public void OnPhotonSerializeView(PhotonStream stream, PhotonMessageInfo info) + { + this.m_PositionControl.OnPhotonSerializeView(transform.localPosition, stream, info); + this.m_RotationControl.OnPhotonSerializeView(transform.localRotation, stream, info); + this.m_ScaleControl.OnPhotonSerializeView(transform.localScale, stream, info); + + if (this.m_PhotonView.isMine == false && this.m_PositionModel.DrawErrorGizmo == true) + { + this.DoDrawEstimatedPositionError(); + } + + if (stream.isReading == true) + { + this.m_ReceivedNetworkUpdate = true; + + // force latest data to avoid initial drifts when player is instantiated. + if (m_firstTake) + { + m_firstTake = false; + + if (this.m_PositionModel.SynchronizeEnabled) + { + this.transform.localPosition = this.m_PositionControl.GetNetworkPosition(); + } + + if (this.m_RotationModel.SynchronizeEnabled) + { + this.transform.localRotation = this.m_RotationControl.GetNetworkRotation(); + } + + if (this.m_ScaleModel.SynchronizeEnabled) + { + this.transform.localScale = this.m_ScaleControl.GetNetworkScale(); + } + + } + + } + } + + //void OnDrawGizmos() + //{ + // if( Application.isPlaying == false || m_PhotonView == null || m_PhotonView.isMine == true || PhotonNetwork.connected == false ) + // { + // return; + // } + + // DoDrawNetworkPositionGizmo(); + // DoDrawExtrapolatedPositionGizmo(); + //} + + void DoDrawEstimatedPositionError() + { + Vector3 targetPosition = this.m_PositionControl.GetNetworkPosition(); + + // we are synchronizing the localPosition, so we need to add the parent position for a proper positioning. + if (transform.parent != null) + { + targetPosition = transform.parent.position + targetPosition ; + } + + Debug.DrawLine(targetPosition, transform.position, Color.red, 2f); + Debug.DrawLine(transform.position, transform.position + Vector3.up, Color.green, 2f); + Debug.DrawLine(targetPosition , targetPosition + Vector3.up, Color.red, 2f); + } + + //void DoDrawNetworkPositionGizmo() + //{ + // if( m_PositionModel.DrawNetworkGizmo == false || m_PositionControl == null ) + // { + // return; + // } + + // ExitGames.Client.GUI.GizmoTypeDrawer.Draw( m_PositionControl.GetNetworkPosition(), + // m_PositionModel.NetworkGizmoType, + // m_PositionModel.NetworkGizmoColor, + // m_PositionModel.NetworkGizmoSize ); + //} + + //void DoDrawExtrapolatedPositionGizmo() + //{ + // if( m_PositionModel.DrawExtrapolatedGizmo == false || + // m_PositionModel.ExtrapolateOption == PhotonTransformViewPositionModel.ExtrapolateOptions.Disabled || + // m_PositionControl == null ) + // { + // return; + // } + + // ExitGames.Client.GUI.GizmoTypeDrawer.Draw( m_PositionControl.GetNetworkPosition() + m_PositionControl.GetExtrapolatedPositionOffset(), + // m_PositionModel.ExtrapolatedGizmoType, + // m_PositionModel.ExtrapolatedGizmoColor, + // m_PositionModel.ExtrapolatedGizmoSize ); + //} +} \ No newline at end of file diff --git a/Assets/Photon Unity Networking/Plugins/PhotonNetwork/Views/PhotonTransformView.cs.meta b/Assets/Photon Unity Networking/Plugins/PhotonNetwork/Views/PhotonTransformView.cs.meta new file mode 100644 index 0000000..963d8ee --- /dev/null +++ b/Assets/Photon Unity Networking/Plugins/PhotonNetwork/Views/PhotonTransformView.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 627855c7f81362d41938ffe0b1475957 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Photon Unity Networking/Plugins/PhotonNetwork/Views/PhotonTransformViewPositionControl.cs b/Assets/Photon Unity Networking/Plugins/PhotonNetwork/Views/PhotonTransformViewPositionControl.cs new file mode 100644 index 0000000..550fd7b --- /dev/null +++ b/Assets/Photon Unity Networking/Plugins/PhotonNetwork/Views/PhotonTransformViewPositionControl.cs @@ -0,0 +1,246 @@ +// ---------------------------------------------------------------------------- +// +// PhotonNetwork Framework for Unity - Copyright (C) 2016 Exit Games GmbH +// +// +// Component to synchronize position via PUN PhotonView. +// +// developer@exitgames.com +// ---------------------------------------------------------------------------- + +using UnityEngine; +using System.Collections; +using System.Collections.Generic; + +public class PhotonTransformViewPositionControl +{ + PhotonTransformViewPositionModel m_Model; + float m_CurrentSpeed; + double m_LastSerializeTime; + Vector3 m_SynchronizedSpeed = Vector3.zero; + float m_SynchronizedTurnSpeed = 0; + + Vector3 m_NetworkPosition; + Queue m_OldNetworkPositions = new Queue(); + + bool m_UpdatedPositionAfterOnSerialize = true; + + public PhotonTransformViewPositionControl( PhotonTransformViewPositionModel model ) + { + m_Model = model; + } + + Vector3 GetOldestStoredNetworkPosition() + { + Vector3 oldPosition = m_NetworkPosition; + + if( m_OldNetworkPositions.Count > 0 ) + { + oldPosition = m_OldNetworkPositions.Peek(); + } + + return oldPosition; + } + + /// + /// These values are synchronized to the remote objects if the interpolation mode + /// or the extrapolation mode SynchronizeValues is used. Your movement script should pass on + /// the current speed (in units/second) and turning speed (in angles/second) so the remote + /// object can use them to predict the objects movement. + /// + /// The current movement vector of the object in units/second. + /// The current turn speed of the object in angles/second. + public void SetSynchronizedValues( Vector3 speed, float turnSpeed ) + { + m_SynchronizedSpeed = speed; + m_SynchronizedTurnSpeed = turnSpeed; + } + + /// + /// Calculates the new position based on the values setup in the inspector + /// + /// The current position. + /// The new position. + public Vector3 UpdatePosition( Vector3 currentPosition ) + { + Vector3 targetPosition = GetNetworkPosition() + GetExtrapolatedPositionOffset(); + + switch( m_Model.InterpolateOption ) + { + case PhotonTransformViewPositionModel.InterpolateOptions.Disabled: + if( m_UpdatedPositionAfterOnSerialize == false ) + { + currentPosition = targetPosition; + m_UpdatedPositionAfterOnSerialize = true; + } + break; + + case PhotonTransformViewPositionModel.InterpolateOptions.FixedSpeed: + currentPosition = Vector3.MoveTowards( currentPosition, targetPosition, Time.deltaTime * m_Model.InterpolateMoveTowardsSpeed ); + break; + + case PhotonTransformViewPositionModel.InterpolateOptions.EstimatedSpeed: + if (m_OldNetworkPositions.Count == 0) + { + // special case: we have no previous updates in memory, so we can't guess a speed! + break; + } + + // knowing the last (incoming) position and the one before, we can guess a speed. + // note that the speed is times sendRateOnSerialize! we send X updates/sec, so our estimate has to factor that in. + float estimatedSpeed = (Vector3.Distance(m_NetworkPosition, GetOldestStoredNetworkPosition()) / m_OldNetworkPositions.Count) * PhotonNetwork.sendRateOnSerialize; + + // move towards the targetPosition (including estimates, if that's active) with the speed calculated from the last updates. + currentPosition = Vector3.MoveTowards(currentPosition, targetPosition, Time.deltaTime * estimatedSpeed ); + break; + + case PhotonTransformViewPositionModel.InterpolateOptions.SynchronizeValues: + if( m_SynchronizedSpeed.magnitude == 0 ) + { + currentPosition = targetPosition; + } + else + { + currentPosition = Vector3.MoveTowards( currentPosition, targetPosition, Time.deltaTime * m_SynchronizedSpeed.magnitude ); + } + break; + + case PhotonTransformViewPositionModel.InterpolateOptions.Lerp: + currentPosition = Vector3.Lerp( currentPosition, targetPosition, Time.deltaTime * m_Model.InterpolateLerpSpeed ); + break; + + /*case PhotonTransformViewPositionModel.InterpolateOptions.MoveTowardsComplex: + float distanceToTarget = Vector3.Distance( currentPosition, targetPosition ); + float targetSpeed = m_Model.InterpolateSpeedCurve.Evaluate( distanceToTarget ) * m_Model.InterpolateMoveTowardsSpeed; + + if( targetSpeed > m_CurrentSpeed ) + { + m_CurrentSpeed = Mathf.MoveTowards( m_CurrentSpeed, targetSpeed, Time.deltaTime * m_Model.InterpolateMoveTowardsAcceleration ); + } + else + { + m_CurrentSpeed = Mathf.MoveTowards( m_CurrentSpeed, targetSpeed, Time.deltaTime * m_Model.InterpolateMoveTowardsDeceleration ); + } + + //Debug.Log( m_CurrentSpeed + " - " + targetSpeed + " - " + transform.localPosition + " - " + targetPosition ); + + currentPosition = Vector3.MoveTowards( currentPosition, targetPosition, Time.deltaTime * m_CurrentSpeed ); + break;*/ + } + + if( m_Model.TeleportEnabled == true ) + { + if( Vector3.Distance( currentPosition, GetNetworkPosition() ) > m_Model.TeleportIfDistanceGreaterThan ) + { + currentPosition = GetNetworkPosition(); + } + } + + return currentPosition; + } + + /// + /// Gets the last position that was received through the network + /// + /// + public Vector3 GetNetworkPosition() + { + return m_NetworkPosition; + } + + /// + /// Calculates an estimated position based on the last synchronized position, + /// the time when the last position was received and the movement speed of the object + /// + /// Estimated position of the remote object + public Vector3 GetExtrapolatedPositionOffset() + { + float timePassed = (float)( PhotonNetwork.time - m_LastSerializeTime ); + + if( m_Model.ExtrapolateIncludingRoundTripTime == true ) + { + timePassed += (float)PhotonNetwork.GetPing() / 1000f; + } + + Vector3 extrapolatePosition = Vector3.zero; + + switch( m_Model.ExtrapolateOption ) + { + case PhotonTransformViewPositionModel.ExtrapolateOptions.SynchronizeValues: + Quaternion turnRotation = Quaternion.Euler( 0, m_SynchronizedTurnSpeed * timePassed, 0 ); + extrapolatePosition = turnRotation * ( m_SynchronizedSpeed * timePassed ); + break; + case PhotonTransformViewPositionModel.ExtrapolateOptions.FixedSpeed: + Vector3 moveDirection = ( m_NetworkPosition - GetOldestStoredNetworkPosition() ).normalized; + + extrapolatePosition = moveDirection * m_Model.ExtrapolateSpeed * timePassed; + break; + case PhotonTransformViewPositionModel.ExtrapolateOptions.EstimateSpeedAndTurn: + Vector3 moveDelta = ( m_NetworkPosition - GetOldestStoredNetworkPosition() ) * PhotonNetwork.sendRateOnSerialize; + extrapolatePosition = moveDelta * timePassed; + break; + } + + return extrapolatePosition; + } + + public void OnPhotonSerializeView( Vector3 currentPosition, PhotonStream stream, PhotonMessageInfo info ) + { + if( m_Model.SynchronizeEnabled == false ) + { + return; + } + + if( stream.isWriting == true ) + { + SerializeData( currentPosition, stream, info ); + } + else + { + DeserializeData( stream, info ); + } + + m_LastSerializeTime = PhotonNetwork.time; + m_UpdatedPositionAfterOnSerialize = false; + } + + void SerializeData( Vector3 currentPosition, PhotonStream stream, PhotonMessageInfo info ) + { + stream.SendNext( currentPosition ); + m_NetworkPosition = currentPosition; + + if( m_Model.ExtrapolateOption == PhotonTransformViewPositionModel.ExtrapolateOptions.SynchronizeValues || + m_Model.InterpolateOption == PhotonTransformViewPositionModel.InterpolateOptions.SynchronizeValues ) + { + stream.SendNext( m_SynchronizedSpeed ); + stream.SendNext( m_SynchronizedTurnSpeed ); + } + } + + void DeserializeData( PhotonStream stream, PhotonMessageInfo info ) + { + Vector3 readPosition = (Vector3)stream.ReceiveNext(); + if( m_Model.ExtrapolateOption == PhotonTransformViewPositionModel.ExtrapolateOptions.SynchronizeValues || + m_Model.InterpolateOption == PhotonTransformViewPositionModel.InterpolateOptions.SynchronizeValues ) + { + m_SynchronizedSpeed = (Vector3)stream.ReceiveNext(); + m_SynchronizedTurnSpeed = (float)stream.ReceiveNext(); + } + + if (m_OldNetworkPositions.Count == 0) + { + // if we don't have old positions yet, this is the very first update this client reads. let's use this as current AND old position. + m_NetworkPosition = readPosition; + } + + // the previously received position becomes the old(er) one and queued. the new one is the m_NetworkPosition + m_OldNetworkPositions.Enqueue( m_NetworkPosition ); + m_NetworkPosition = readPosition; + + // reduce items in queue to defined number of stored positions. + while( m_OldNetworkPositions.Count > m_Model.ExtrapolateNumberOfStoredPositions ) + { + m_OldNetworkPositions.Dequeue(); + } + } +} \ No newline at end of file diff --git a/Assets/Photon Unity Networking/Plugins/PhotonNetwork/Views/PhotonTransformViewPositionControl.cs.meta b/Assets/Photon Unity Networking/Plugins/PhotonNetwork/Views/PhotonTransformViewPositionControl.cs.meta new file mode 100644 index 0000000..003f24d --- /dev/null +++ b/Assets/Photon Unity Networking/Plugins/PhotonNetwork/Views/PhotonTransformViewPositionControl.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 83c7620118e76384db972fbb42e91b20 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Photon Unity Networking/Plugins/PhotonNetwork/Views/PhotonTransformViewPositionModel.cs b/Assets/Photon Unity Networking/Plugins/PhotonNetwork/Views/PhotonTransformViewPositionModel.cs new file mode 100644 index 0000000..f234807 --- /dev/null +++ b/Assets/Photon Unity Networking/Plugins/PhotonNetwork/Views/PhotonTransformViewPositionModel.cs @@ -0,0 +1,67 @@ +// ---------------------------------------------------------------------------- +// +// PhotonNetwork Framework for Unity - Copyright (C) 2016 Exit Games GmbH +// +// +// Model to synchronize position via PUN PhotonView. +// +// developer@exitgames.com +// ---------------------------------------------------------------------------- + +using UnityEngine; +using System.Collections; + +[System.Serializable] +public class PhotonTransformViewPositionModel +{ + public enum InterpolateOptions + { + Disabled, + FixedSpeed, + EstimatedSpeed, + SynchronizeValues, + //MoveTowardsComplex, + Lerp, + } + + public enum ExtrapolateOptions + { + Disabled, + SynchronizeValues, + EstimateSpeedAndTurn, + FixedSpeed, + } + + public bool SynchronizeEnabled; + + public bool TeleportEnabled = true; + public float TeleportIfDistanceGreaterThan = 3f; + + public InterpolateOptions InterpolateOption = InterpolateOptions.EstimatedSpeed; + public float InterpolateMoveTowardsSpeed = 1f; + public float InterpolateLerpSpeed = 1f; + public float InterpolateMoveTowardsAcceleration = 2; + public float InterpolateMoveTowardsDeceleration = 2; + public AnimationCurve InterpolateSpeedCurve = new AnimationCurve( new Keyframe[] { + new Keyframe( -1, 0, 0, Mathf.Infinity ), + new Keyframe( 0, 1, 0, 0 ), + new Keyframe( 1, 1, 0, 1 ), + new Keyframe( 4, 4, 1, 0 ) } ); + + public ExtrapolateOptions ExtrapolateOption = ExtrapolateOptions.Disabled; + public float ExtrapolateSpeed = 1f; + public bool ExtrapolateIncludingRoundTripTime = true; + public int ExtrapolateNumberOfStoredPositions = 1; + + //public bool DrawNetworkGizmo = true; + //public Color NetworkGizmoColor = Color.red; + //public ExitGames.Client.GUI.GizmoType NetworkGizmoType; + //public float NetworkGizmoSize = 1f; + + //public bool DrawExtrapolatedGizmo = true; + //public Color ExtrapolatedGizmoColor = Color.yellow; + //public ExitGames.Client.GUI.GizmoType ExtrapolatedGizmoType; + //public float ExtrapolatedGizmoSize = 1f; + + public bool DrawErrorGizmo = true; +} diff --git a/Assets/Photon Unity Networking/Plugins/PhotonNetwork/Views/PhotonTransformViewPositionModel.cs.meta b/Assets/Photon Unity Networking/Plugins/PhotonNetwork/Views/PhotonTransformViewPositionModel.cs.meta new file mode 100644 index 0000000..58b8945 --- /dev/null +++ b/Assets/Photon Unity Networking/Plugins/PhotonNetwork/Views/PhotonTransformViewPositionModel.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 50a9ddcc59cdf244883cf0ec646cc8c1 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Photon Unity Networking/Plugins/PhotonNetwork/Views/PhotonTransformViewRotationControl.cs b/Assets/Photon Unity Networking/Plugins/PhotonNetwork/Views/PhotonTransformViewRotationControl.cs new file mode 100644 index 0000000..490fda4 --- /dev/null +++ b/Assets/Photon Unity Networking/Plugins/PhotonNetwork/Views/PhotonTransformViewRotationControl.cs @@ -0,0 +1,64 @@ +// ---------------------------------------------------------------------------- +// +// PhotonNetwork Framework for Unity - Copyright (C) 2016 Exit Games GmbH +// +// +// Component to synchronize rotations via PUN PhotonView. +// +// developer@exitgames.com +// ---------------------------------------------------------------------------- + +using UnityEngine; +using System.Collections; + +public class PhotonTransformViewRotationControl +{ + PhotonTransformViewRotationModel m_Model; + Quaternion m_NetworkRotation; + + public PhotonTransformViewRotationControl( PhotonTransformViewRotationModel model ) + { + m_Model = model; + } + + /// + /// Gets the last rotation that was received through the network + /// + /// + public Quaternion GetNetworkRotation() + { + return m_NetworkRotation; + } + + public Quaternion GetRotation( Quaternion currentRotation ) + { + switch( m_Model.InterpolateOption ) + { + default: + case PhotonTransformViewRotationModel.InterpolateOptions.Disabled: + return m_NetworkRotation; + case PhotonTransformViewRotationModel.InterpolateOptions.RotateTowards: + return Quaternion.RotateTowards( currentRotation, m_NetworkRotation, m_Model.InterpolateRotateTowardsSpeed * Time.deltaTime ); + case PhotonTransformViewRotationModel.InterpolateOptions.Lerp: + return Quaternion.Lerp( currentRotation, m_NetworkRotation, m_Model.InterpolateLerpSpeed * Time.deltaTime ); + } + } + + public void OnPhotonSerializeView( Quaternion currentRotation, PhotonStream stream, PhotonMessageInfo info ) + { + if( m_Model.SynchronizeEnabled == false ) + { + return; + } + + if( stream.isWriting == true ) + { + stream.SendNext( currentRotation ); + m_NetworkRotation = currentRotation; + } + else + { + m_NetworkRotation = (Quaternion)stream.ReceiveNext(); + } + } +} \ No newline at end of file diff --git a/Assets/Photon Unity Networking/Plugins/PhotonNetwork/Views/PhotonTransformViewRotationControl.cs.meta b/Assets/Photon Unity Networking/Plugins/PhotonNetwork/Views/PhotonTransformViewRotationControl.cs.meta new file mode 100644 index 0000000..f3520cd --- /dev/null +++ b/Assets/Photon Unity Networking/Plugins/PhotonNetwork/Views/PhotonTransformViewRotationControl.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: c6756f3d99937134d9b25f9573d60f27 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Photon Unity Networking/Plugins/PhotonNetwork/Views/PhotonTransformViewRotationModel.cs b/Assets/Photon Unity Networking/Plugins/PhotonNetwork/Views/PhotonTransformViewRotationModel.cs new file mode 100644 index 0000000..2a81c4f --- /dev/null +++ b/Assets/Photon Unity Networking/Plugins/PhotonNetwork/Views/PhotonTransformViewRotationModel.cs @@ -0,0 +1,29 @@ +// ---------------------------------------------------------------------------- +// +// PhotonNetwork Framework for Unity - Copyright (C) 2016 Exit Games GmbH +// +// +// Model class to synchronize rotations via PUN PhotonView. +// +// developer@exitgames.com +// ---------------------------------------------------------------------------- + +using UnityEngine; +using System.Collections; + +[System.Serializable] +public class PhotonTransformViewRotationModel +{ + public enum InterpolateOptions + { + Disabled, + RotateTowards, + Lerp, + } + + public bool SynchronizeEnabled; + + public InterpolateOptions InterpolateOption = InterpolateOptions.RotateTowards; + public float InterpolateRotateTowardsSpeed = 180; + public float InterpolateLerpSpeed = 5; +} diff --git a/Assets/Photon Unity Networking/Plugins/PhotonNetwork/Views/PhotonTransformViewRotationModel.cs.meta b/Assets/Photon Unity Networking/Plugins/PhotonNetwork/Views/PhotonTransformViewRotationModel.cs.meta new file mode 100644 index 0000000..288faef --- /dev/null +++ b/Assets/Photon Unity Networking/Plugins/PhotonNetwork/Views/PhotonTransformViewRotationModel.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: fc810f3956379f34dae4b1487445d290 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Photon Unity Networking/Plugins/PhotonNetwork/Views/PhotonTransformViewScaleControl.cs b/Assets/Photon Unity Networking/Plugins/PhotonNetwork/Views/PhotonTransformViewScaleControl.cs new file mode 100644 index 0000000..1d2930e --- /dev/null +++ b/Assets/Photon Unity Networking/Plugins/PhotonNetwork/Views/PhotonTransformViewScaleControl.cs @@ -0,0 +1,64 @@ +// ---------------------------------------------------------------------------- +// +// PhotonNetwork Framework for Unity - Copyright (C) 2016 Exit Games GmbH +// +// +// Component to synchronize scale via PUN PhotonView. +// +// developer@exitgames.com +// ---------------------------------------------------------------------------- + +using UnityEngine; +using System.Collections; + +public class PhotonTransformViewScaleControl +{ + PhotonTransformViewScaleModel m_Model; + Vector3 m_NetworkScale = Vector3.one; + + public PhotonTransformViewScaleControl( PhotonTransformViewScaleModel model ) + { + m_Model = model; + } + + /// + /// Gets the last scale that was received through the network + /// + /// + public Vector3 GetNetworkScale() + { + return m_NetworkScale; + } + + public Vector3 GetScale( Vector3 currentScale ) + { + switch( m_Model.InterpolateOption ) + { + default: + case PhotonTransformViewScaleModel.InterpolateOptions.Disabled: + return m_NetworkScale; + case PhotonTransformViewScaleModel.InterpolateOptions.MoveTowards: + return Vector3.MoveTowards( currentScale, m_NetworkScale, m_Model.InterpolateMoveTowardsSpeed * Time.deltaTime ); + case PhotonTransformViewScaleModel.InterpolateOptions.Lerp: + return Vector3.Lerp( currentScale, m_NetworkScale, m_Model.InterpolateLerpSpeed * Time.deltaTime ); + } + } + + public void OnPhotonSerializeView( Vector3 currentScale, PhotonStream stream, PhotonMessageInfo info ) + { + if( m_Model.SynchronizeEnabled == false ) + { + return; + } + + if( stream.isWriting == true ) + { + stream.SendNext( currentScale ); + m_NetworkScale = currentScale; + } + else + { + m_NetworkScale = (Vector3)stream.ReceiveNext(); + } + } +} \ No newline at end of file diff --git a/Assets/Photon Unity Networking/Plugins/PhotonNetwork/Views/PhotonTransformViewScaleControl.cs.meta b/Assets/Photon Unity Networking/Plugins/PhotonNetwork/Views/PhotonTransformViewScaleControl.cs.meta new file mode 100644 index 0000000..b9c242e --- /dev/null +++ b/Assets/Photon Unity Networking/Plugins/PhotonNetwork/Views/PhotonTransformViewScaleControl.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: f8ddd626f728c0c4f9305c4fc472b1a2 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Photon Unity Networking/Plugins/PhotonNetwork/Views/PhotonTransformViewScaleModel.cs b/Assets/Photon Unity Networking/Plugins/PhotonNetwork/Views/PhotonTransformViewScaleModel.cs new file mode 100644 index 0000000..5c5f914 --- /dev/null +++ b/Assets/Photon Unity Networking/Plugins/PhotonNetwork/Views/PhotonTransformViewScaleModel.cs @@ -0,0 +1,29 @@ +// ---------------------------------------------------------------------------- +// +// PhotonNetwork Framework for Unity - Copyright (C) 2016 Exit Games GmbH +// +// +// Model to synchronize scale via PUN PhotonView. +// +// developer@exitgames.com +// ---------------------------------------------------------------------------- + +using UnityEngine; +using System.Collections; + +[System.Serializable] +public class PhotonTransformViewScaleModel +{ + public enum InterpolateOptions + { + Disabled, + MoveTowards, + Lerp, + } + + public bool SynchronizeEnabled; + + public InterpolateOptions InterpolateOption = InterpolateOptions.Disabled; + public float InterpolateMoveTowardsSpeed = 1f; + public float InterpolateLerpSpeed; +} diff --git a/Assets/Photon Unity Networking/Plugins/PhotonNetwork/Views/PhotonTransformViewScaleModel.cs.meta b/Assets/Photon Unity Networking/Plugins/PhotonNetwork/Views/PhotonTransformViewScaleModel.cs.meta new file mode 100644 index 0000000..b4f63a8 --- /dev/null +++ b/Assets/Photon Unity Networking/Plugins/PhotonNetwork/Views/PhotonTransformViewScaleModel.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 7379c1718ac64ca48bdb60b1dd644a5c +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Photon Unity Networking/PunIcon-White-128.png b/Assets/Photon Unity Networking/PunIcon-White-128.png new file mode 100644 index 0000000..885c22f Binary files /dev/null and b/Assets/Photon Unity Networking/PunIcon-White-128.png differ diff --git a/Assets/Photon Unity Networking/PunIcon-White-128.png.meta b/Assets/Photon Unity Networking/PunIcon-White-128.png.meta new file mode 100644 index 0000000..967667e --- /dev/null +++ b/Assets/Photon Unity Networking/PunIcon-White-128.png.meta @@ -0,0 +1,45 @@ +fileFormatVersion: 2 +guid: e1e27211415083e41bd38b51da93f58b +TextureImporter: + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + linearTexture: 1 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -1 + maxTextureSize: 128 + textureSettings: + filterMode: -1 + aniso: 1 + mipBias: -1 + wrapMode: 1 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spritePixelsToUnits: 100 + alphaIsTransparency: 1 + textureType: 2 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/Assets/Photon Unity Networking/Resources.meta b/Assets/Photon Unity Networking/Resources.meta new file mode 100644 index 0000000..1638958 --- /dev/null +++ b/Assets/Photon Unity Networking/Resources.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: c063a6f5f4c7f41ee8ca5f9b44962311 +folderAsset: yes +timeCreated: 1501014865 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Photon Unity Networking/Resources/PhotonServerSettings.asset b/Assets/Photon Unity Networking/Resources/PhotonServerSettings.asset new file mode 100644 index 0000000..5640895 Binary files /dev/null and b/Assets/Photon Unity Networking/Resources/PhotonServerSettings.asset differ diff --git a/Assets/Photon Unity Networking/Resources/PhotonServerSettings.asset.meta b/Assets/Photon Unity Networking/Resources/PhotonServerSettings.asset.meta new file mode 100644 index 0000000..5aadcdf --- /dev/null +++ b/Assets/Photon Unity Networking/Resources/PhotonServerSettings.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: bee9ca287d2e749cab243a127deeb975 +timeCreated: 1501014866 +licenseType: Free +NativeFormatImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Photon Unity Networking/UtilityScripts.meta b/Assets/Photon Unity Networking/UtilityScripts.meta new file mode 100644 index 0000000..1f1ff78 --- /dev/null +++ b/Assets/Photon Unity Networking/UtilityScripts.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: ac7a3822fd702481f8e69c95e53cd814 +folderAsset: yes +timeCreated: 1501014811 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Photon Unity Networking/UtilityScripts/ConnectAndJoinRandom.cs b/Assets/Photon Unity Networking/UtilityScripts/ConnectAndJoinRandom.cs new file mode 100644 index 0000000..1e21e56 --- /dev/null +++ b/Assets/Photon Unity Networking/UtilityScripts/ConnectAndJoinRandom.cs @@ -0,0 +1,70 @@ +using System; +using UnityEngine; +using System.Collections; + +/// +/// This script automatically connects to Photon (using the settings file), +/// tries to join a random room and creates one if none was found (which is ok). +/// +public class ConnectAndJoinRandom : Photon.MonoBehaviour +{ + /// Connect automatically? If false you can set this to true later on or call ConnectUsingSettings in your own scripts. + public bool AutoConnect = true; + + public byte Version = 1; + + /// if we don't want to connect in Start(), we have to "remember" if we called ConnectUsingSettings() + private bool ConnectInUpdate = true; + + + public virtual void Start() + { + PhotonNetwork.autoJoinLobby = false; // we join randomly. always. no need to join a lobby to get the list of rooms. + } + + public virtual void Update() + { + if (ConnectInUpdate && AutoConnect && !PhotonNetwork.connected) + { + Debug.Log("Update() was called by Unity. Scene is loaded. Let's connect to the Photon Master Server. Calling: PhotonNetwork.ConnectUsingSettings();"); + + ConnectInUpdate = false; + PhotonNetwork.ConnectUsingSettings(Version + "." + SceneManagerHelper.ActiveSceneBuildIndex); + } + } + + + // below, we implement some callbacks of PUN + // you can find PUN's callbacks in the class PunBehaviour or in enum PhotonNetworkingMessage + + + public virtual void OnConnectedToMaster() + { + Debug.Log("OnConnectedToMaster() was called by PUN. Now this client is connected and could join a room. Calling: PhotonNetwork.JoinRandomRoom();"); + PhotonNetwork.JoinRandomRoom(); + } + + public virtual void OnJoinedLobby() + { + Debug.Log("OnJoinedLobby(). This client is connected and does get a room-list, which gets stored as PhotonNetwork.GetRoomList(). This script now calls: PhotonNetwork.JoinRandomRoom();"); + PhotonNetwork.JoinRandomRoom(); + } + + public virtual void OnPhotonRandomJoinFailed() + { + Debug.Log("OnPhotonRandomJoinFailed() was called by PUN. No random room available, so we create one. Calling: PhotonNetwork.CreateRoom(null, new RoomOptions() {maxPlayers = 4}, null);"); + PhotonNetwork.CreateRoom(null, new RoomOptions() { MaxPlayers = 4 }, null); + } + + // the following methods are implemented to give you some context. re-implement them as needed. + + public virtual void OnFailedToConnectToPhoton(DisconnectCause cause) + { + Debug.LogError("Cause: " + cause); + } + + public void OnJoinedRoom() + { + Debug.Log("OnJoinedRoom() called by PUN. Now this client is in a room. From here on, your game would be running. For reference, all callbacks are listed in enum: PhotonNetworkingMessage"); + } +} diff --git a/Assets/Photon Unity Networking/UtilityScripts/ConnectAndJoinRandom.cs.meta b/Assets/Photon Unity Networking/UtilityScripts/ConnectAndJoinRandom.cs.meta new file mode 100644 index 0000000..13f1494 --- /dev/null +++ b/Assets/Photon Unity Networking/UtilityScripts/ConnectAndJoinRandom.cs.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 5c1b84a427010e0469ce0df07ab64dbc +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} diff --git a/Assets/Photon Unity Networking/UtilityScripts/CullArea.cs b/Assets/Photon Unity Networking/UtilityScripts/CullArea.cs new file mode 100644 index 0000000..f54c0af --- /dev/null +++ b/Assets/Photon Unity Networking/UtilityScripts/CullArea.cs @@ -0,0 +1,465 @@ +using System.Collections.Generic; +using UnityEngine; + +/// +/// Represents the cull area used for network culling. +/// +public class CullArea : MonoBehaviour +{ + private const int MAX_NUMBER_OF_ALLOWED_CELLS = 250; + + public const int MAX_NUMBER_OF_SUBDIVISIONS = 3; + + /// + /// This represents the first ID which is assigned to the first created cell. + /// If you already have some interest groups blocking this first ID, fell free to change it. + /// However increasing the first group ID decreases the maximum amount of allowed cells. + /// Allowed values are in range from 1 to 250. + /// + public readonly byte FIRST_GROUP_ID = 1; + + /// + /// This represents the order in which updates are sent. + /// The number represents the subdivision of the cell hierarchy: + /// - 0: message is sent to all players + /// - 1: message is sent to players who are interested in the matching cell of the first subdivision + /// If there is only one subdivision we are sending one update to all players + /// before sending three consequent updates only to players who are in the same cell + /// or interested in updates of the current cell. + /// + public readonly int[] SUBDIVISION_FIRST_LEVEL_ORDER = new int[4] { 0, 1, 1, 1 }; + + /// + /// This represents the order in which updates are sent. + /// The number represents the subdivision of the cell hierarchy: + /// - 0: message is sent to all players + /// - 1: message is sent to players who are interested in the matching cell of the first subdivision + /// - 2: message is sent to players who are interested in the matching cell of the second subdivision + /// If there are two subdivisions we are sending every second update only to players + /// who are in the same cell or interested in updates of the current cell. + /// + public readonly int[] SUBDIVISION_SECOND_LEVEL_ORDER = new int[8] { 0, 2, 1, 2, 0, 2, 1, 2 }; + + /// + /// This represents the order in which updates are sent. + /// The number represents the subdivision of the cell hierarchy: + /// - 0: message is sent to all players + /// - 1: message is sent to players who are interested in the matching cell of the first subdivision + /// - 2: message is sent to players who are interested in the matching cell of the second subdivision + /// - 3: message is sent to players who are interested in the matching cell of the third subdivision + /// If there are two subdivisions we are sending every second update only to players + /// who are in the same cell or interested in updates of the current cell. + /// + public readonly int[] SUBDIVISION_THIRD_LEVEL_ORDER = new int[12] { 0, 3, 2, 3, 1, 3, 2, 3, 1, 3, 2, 3 }; + + public Vector2 Center; + public Vector2 Size = new Vector2(25.0f, 25.0f); + + public Vector2[] Subdivisions = new Vector2[MAX_NUMBER_OF_SUBDIVISIONS]; + + public int NumberOfSubdivisions; + + public int CellCount { get; private set; } + + public CellTree CellTree { get; private set; } + + public Dictionary Map { get; private set; } + + public bool YIsUpAxis = true; + public bool RecreateCellHierarchy = false; + + private byte idCounter; + + /// + /// Creates the cell hierarchy at runtime. + /// + private void Awake() + { + this.idCounter = this.FIRST_GROUP_ID; + + this.CreateCellHierarchy(); + } + + /// + /// Creates the cell hierarchy in editor and draws the cell view. + /// + public void OnDrawGizmos() + { + this.idCounter = this.FIRST_GROUP_ID; + + if (this.RecreateCellHierarchy) + { + this.CreateCellHierarchy(); + } + + this.DrawCells(); + } + + /// + /// Creates the cell hierarchy. + /// + private void CreateCellHierarchy() + { + if (!this.IsCellCountAllowed()) + { + if (Debug.isDebugBuild) + { + Debug.LogError("There are too many cells created by your subdivision options. Maximum allowed number of cells is " + (MAX_NUMBER_OF_ALLOWED_CELLS - this.FIRST_GROUP_ID) + + ". Current number of cells is " + this.CellCount + "."); + return; + } + else + { + Application.Quit(); + } + } + + CellTreeNode rootNode = new CellTreeNode(this.idCounter++, CellTreeNode.ENodeType.Root, null); + + if (this.YIsUpAxis) + { + this.Center = new Vector2(transform.position.x, transform.position.y); + this.Size = new Vector2(transform.localScale.x, transform.localScale.y); + + rootNode.Center = new Vector3(this.Center.x, this.Center.y, 0.0f); + rootNode.Size = new Vector3(this.Size.x, this.Size.y, 0.0f); + rootNode.TopLeft = new Vector3((this.Center.x - (this.Size.x/2.0f)), (this.Center.y - (this.Size.y/2.0f)), 0.0f); + rootNode.BottomRight = new Vector3((this.Center.x + (this.Size.x/2.0f)), (this.Center.y + (this.Size.y/2.0f)), 0.0f); + } + else + { + this.Center = new Vector2(transform.position.x, transform.position.z); + this.Size = new Vector2(transform.localScale.x, transform.localScale.z); + + rootNode.Center = new Vector3(this.Center.x, 0.0f, this.Center.y); + rootNode.Size = new Vector3(this.Size.x, 0.0f, this.Size.y); + rootNode.TopLeft = new Vector3((this.Center.x - (this.Size.x/2.0f)), 0.0f, (this.Center.y - (this.Size.y/2.0f))); + rootNode.BottomRight = new Vector3((this.Center.x + (this.Size.x/2.0f)), 0.0f, (this.Center.y + (this.Size.y/2.0f))); + } + + this.CreateChildCells(rootNode, 1); + + this.CellTree = new CellTree(rootNode); + + this.RecreateCellHierarchy = false; + } + + /// + /// Creates all child cells. + /// + /// The current parent node. + /// The cell level within the current hierarchy. + private void CreateChildCells(CellTreeNode parent, int cellLevelInHierarchy) + { + if (cellLevelInHierarchy > this.NumberOfSubdivisions) + { + return; + } + + int rowCount = (int)this.Subdivisions[(cellLevelInHierarchy - 1)].x; + int columnCount = (int)this.Subdivisions[(cellLevelInHierarchy - 1)].y; + + float startX = parent.Center.x - (parent.Size.x/2.0f); + float width = parent.Size.x/rowCount; + + for (int row = 0; row < rowCount; ++row) + { + for (int column = 0; column < columnCount; ++column) + { + float xPos = startX + (row*width) + (width/2.0f); + + CellTreeNode node = new CellTreeNode(this.idCounter++, (this.NumberOfSubdivisions == cellLevelInHierarchy) ? CellTreeNode.ENodeType.Leaf : CellTreeNode.ENodeType.Node, parent); + + if (this.YIsUpAxis) + { + float startY = parent.Center.y - (parent.Size.y/2.0f); + float height = parent.Size.y/columnCount; + float yPos = startY + (column*height) + (height/2.0f); + + node.Center = new Vector3(xPos, yPos, 0.0f); + node.Size = new Vector3(width, height, 0.0f); + node.TopLeft = new Vector3(xPos - (width/2.0f), yPos - (height/2.0f), 0.0f); + node.BottomRight = new Vector3(xPos + (width/2.0f), yPos + (height/2.0f), 0.0f); + } + else + { + float startZ = parent.Center.z - (parent.Size.z/2.0f); + float depth = parent.Size.z/columnCount; + float zPos = startZ + (column*depth) + (depth/2.0f); + + node.Center = new Vector3(xPos, 0.0f, zPos); + node.Size = new Vector3(width, 0.0f, depth); + node.TopLeft = new Vector3(xPos - (width/2.0f), 0.0f, zPos - (depth/2.0f)); + node.BottomRight = new Vector3(xPos + (width/2.0f), 0.0f, zPos + (depth/2.0f)); + } + + parent.AddChild(node); + + this.CreateChildCells(node, (cellLevelInHierarchy + 1)); + } + } + } + + /// + /// Draws the cells. + /// + private void DrawCells() + { + if ((this.CellTree != null) && (this.CellTree.RootNode != null)) + { + this.CellTree.RootNode.Draw(); + } + else + { + this.RecreateCellHierarchy = true; + } + } + + /// + /// Checks if the cell count is allowed. + /// + /// True if the cell count is allowed, false if the cell count is too large. + private bool IsCellCountAllowed() + { + int horizontalCells = 1; + int verticalCells = 1; + + foreach (Vector2 v in this.Subdivisions) + { + horizontalCells *= (int)v.x; + verticalCells *= (int)v.y; + } + + this.CellCount = horizontalCells*verticalCells; + + return (this.CellCount <= (MAX_NUMBER_OF_ALLOWED_CELLS - this.FIRST_GROUP_ID)); + } + + /// + /// Gets a list of all cell IDs the player is currently inside or nearby. + /// + /// The current position of the player. + /// A list containing all cell IDs the player is currently inside or nearby. + public List GetActiveCells(Vector3 position) + { + List activeCells = new List(0); + this.CellTree.RootNode.GetActiveCells(activeCells, this.YIsUpAxis, position); + + return activeCells; + } +} + +/// +/// Represents the tree accessible from its root node. +/// +public class CellTree +{ + /// + /// Represents the root node of the cell tree. + /// + public CellTreeNode RootNode { get; private set; } + + /// + /// Default constructor. + /// + public CellTree() + { + } + + /// + /// Constructor to define the root node. + /// + /// The root node of the tree. + public CellTree(CellTreeNode root) + { + this.RootNode = root; + } +} + +/// +/// Represents a single node of the tree. +/// +public class CellTreeNode +{ + public enum ENodeType + { + Root, + Node, + Leaf + } + + /// + /// Represents the unique ID of the cell. + /// + public byte Id; + + /// + /// Represents the center, top-left or bottom-right position of the cell + /// or the size of the cell. + /// + public Vector3 Center, Size, TopLeft, BottomRight; + + /// + /// Describes the current node type of the cell tree node. + /// + public ENodeType NodeType; + + /// + /// Reference to the parent node. + /// + public CellTreeNode Parent; + + /// + /// A list containing all child nodes. + /// + public List Childs; + + /// + /// The max distance the player can have to the center of the cell for being 'nearby'. + /// This is calculated once at runtime. + /// + private float maxDistance; + + /// + /// Default constructor. + /// + public CellTreeNode() + { + } + + /// + /// Constructor to define the ID and the node type as well as setting a parent node. + /// + /// The ID of the cell is used as the interest group. + /// The node type of the cell tree node. + /// The parent node of the cell tree node. + public CellTreeNode(byte id, ENodeType nodeType, CellTreeNode parent) + { + this.Id = id; + + this.NodeType = nodeType; + + this.Parent = parent; + } + + /// + /// Adds the given child to the node. + /// + /// The child which is added to the node. + public void AddChild(CellTreeNode child) + { + if (this.Childs == null) + { + this.Childs = new List(1); + } + + this.Childs.Add(child); + } + + /// + /// Draws the cell in the editor. + /// + public void Draw() + { +#if UNITY_EDITOR + if (this.Childs != null) + { + foreach (CellTreeNode node in this.Childs) + { + node.Draw(); + } + } + + Gizmos.color = new Color((this.NodeType == ENodeType.Root) ? 1 : 0, (this.NodeType == ENodeType.Node) ? 1 : 0, (this.NodeType == ENodeType.Leaf) ? 1 : 0); + Gizmos.DrawWireCube(this.Center, this.Size); + + UnityEditor.Handles.Label(this.Center, this.Id.ToString(), new GUIStyle() { fontStyle = FontStyle.Bold }); +#endif + } + + /// + /// Gathers all cell IDs the player is currently inside or nearby. + /// + /// The list to add all cell IDs to the player is currently inside or nearby. + /// Describes if the y-axis is used as up-axis. + /// The current position of the player. + public void GetActiveCells(List activeCells, bool yIsUpAxis, Vector3 position) + { + if (this.NodeType != ENodeType.Leaf) + { + foreach (CellTreeNode node in this.Childs) + { + node.GetActiveCells(activeCells, yIsUpAxis, position); + } + } + else + { + if (this.IsPointNearCell(yIsUpAxis, position)) + { + if (this.IsPointInsideCell(yIsUpAxis, position)) + { + activeCells.Insert(0, this.Id); + + CellTreeNode p = this.Parent; + while (p != null) + { + activeCells.Insert(0, p.Id); + + p = p.Parent; + } + } + else + { + activeCells.Add(this.Id); + } + } + } + } + + /// + /// Checks if the given point is inside the cell. + /// + /// Describes if the y-axis is used as up-axis. + /// The point to check. + /// True if the point is inside the cell, false if the point is not inside the cell. + public bool IsPointInsideCell(bool yIsUpAxis, Vector3 point) + { + if ((point.x < this.TopLeft.x) || (point.x > this.BottomRight.x)) + { + return false; + } + + if (yIsUpAxis) + { + if ((point.y >= this.TopLeft.y) && (point.y <= this.BottomRight.y)) + { + return true; + } + } + else + { + if ((point.z >= this.TopLeft.z) && (point.z <= this.BottomRight.z)) + { + return true; + } + } + + return false; + } + + /// + /// Checks if the given point is near the cell. + /// + /// Describes if the y-axis is used as up-axis. + /// The point to check. + /// True if the point is near the cell, false if the point is too far away. + public bool IsPointNearCell(bool yIsUpAxis, Vector3 point) + { + if (this.maxDistance == 0.0f) + { + this.maxDistance = (this.Size.x + this.Size.y + this.Size.z)/2.0f; + } + + return ((point - this.Center).sqrMagnitude <= (this.maxDistance*this.maxDistance)); + } +} \ No newline at end of file diff --git a/Assets/Photon Unity Networking/UtilityScripts/CullArea.cs.meta b/Assets/Photon Unity Networking/UtilityScripts/CullArea.cs.meta new file mode 100644 index 0000000..9f081cd --- /dev/null +++ b/Assets/Photon Unity Networking/UtilityScripts/CullArea.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: dfb1c264fdc576442b2f42c998bed4a2 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Photon Unity Networking/UtilityScripts/InRoomChat.cs b/Assets/Photon Unity Networking/UtilityScripts/InRoomChat.cs new file mode 100644 index 0000000..731de0e --- /dev/null +++ b/Assets/Photon Unity Networking/UtilityScripts/InRoomChat.cs @@ -0,0 +1,95 @@ +using System.Collections.Generic; +using UnityEngine; +using System.Collections; + +[RequireComponent(typeof(PhotonView))] +public class InRoomChat : Photon.MonoBehaviour +{ + public Rect GuiRect = new Rect(0,0, 250,300); + public bool IsVisible = true; + public bool AlignBottom = false; + public List messages = new List(); + private string inputLine = ""; + private Vector2 scrollPos = Vector2.zero; + + public static readonly string ChatRPC = "Chat"; + + public void Start() + { + if (this.AlignBottom) + { + this.GuiRect.y = Screen.height - this.GuiRect.height; + } + } + + public void OnGUI() + { + if (!this.IsVisible || !PhotonNetwork.inRoom) + { + return; + } + + if (Event.current.type == EventType.KeyDown && (Event.current.keyCode == KeyCode.KeypadEnter || Event.current.keyCode == KeyCode.Return)) + { + if (!string.IsNullOrEmpty(this.inputLine)) + { + this.photonView.RPC("Chat", PhotonTargets.All, this.inputLine); + this.inputLine = ""; + GUI.FocusControl(""); + return; // printing the now modified list would result in an error. to avoid this, we just skip this single frame + } + else + { + GUI.FocusControl("ChatInput"); + } + } + + GUI.SetNextControlName(""); + GUILayout.BeginArea(this.GuiRect); + + scrollPos = GUILayout.BeginScrollView(scrollPos); + GUILayout.FlexibleSpace(); + for (int i = messages.Count - 1; i >= 0; i--) + { + GUILayout.Label(messages[i]); + } + GUILayout.EndScrollView(); + + GUILayout.BeginHorizontal(); + GUI.SetNextControlName("ChatInput"); + inputLine = GUILayout.TextField(inputLine); + if (GUILayout.Button("Send", GUILayout.ExpandWidth(false))) + { + this.photonView.RPC("Chat", PhotonTargets.All, this.inputLine); + this.inputLine = ""; + GUI.FocusControl(""); + } + GUILayout.EndHorizontal(); + GUILayout.EndArea(); + } + + [PunRPC] + public void Chat(string newLine, PhotonMessageInfo mi) + { + string senderName = "anonymous"; + + if (mi.sender != null) + { + if (!string.IsNullOrEmpty(mi.sender.NickName)) + { + senderName = mi.sender.NickName; + } + else + { + senderName = "player " + mi.sender.ID; + } + } + + this.messages.Add(senderName +": " + newLine); + } + + public void AddLine(string newLine) + { + this.messages.Add(newLine); + } +} \ No newline at end of file diff --git a/Assets/Photon Unity Networking/UtilityScripts/InRoomChat.cs.meta b/Assets/Photon Unity Networking/UtilityScripts/InRoomChat.cs.meta new file mode 100644 index 0000000..b704ebe --- /dev/null +++ b/Assets/Photon Unity Networking/UtilityScripts/InRoomChat.cs.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 043bd8ce63fde7c41a9ee103809fa981 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} diff --git a/Assets/Photon Unity Networking/UtilityScripts/InputToEvent.cs b/Assets/Photon Unity Networking/UtilityScripts/InputToEvent.cs new file mode 100644 index 0000000..0ef7bd7 --- /dev/null +++ b/Assets/Photon Unity Networking/UtilityScripts/InputToEvent.cs @@ -0,0 +1,118 @@ +using UnityEngine; + +/// +/// Utility component to forward mouse or touch input to clicked gameobjects. +/// Calls OnPress, OnClick and OnRelease methods on "first" game object. +/// +public class InputToEvent : MonoBehaviour +{ + private GameObject lastGo; + public static Vector3 inputHitPos; + public bool DetectPointedAtGameObject; + public static GameObject goPointedAt { get; private set; } + + private Vector2 pressedPosition = Vector2.zero; + private Vector2 currentPos = Vector2.zero; + public bool Dragging; + + private Camera m_Camera; + + public Vector2 DragVector + { + get { return this.Dragging ? this.currentPos - this.pressedPosition : Vector2.zero; } + } + + private void Start() + { + this.m_Camera = GetComponent(); + } + + // Update is called once per frame + private void Update() + { + if (this.DetectPointedAtGameObject) + { + goPointedAt = RaycastObject(Input.mousePosition); + } + + if (Input.touchCount > 0) + { + Touch touch = Input.GetTouch(0); + this.currentPos = touch.position; + + if (touch.phase == TouchPhase.Began) + { + Press(touch.position); + } + else if (touch.phase == TouchPhase.Ended) + { + Release(touch.position); + } + + return; + } + + this.currentPos = Input.mousePosition; + if (Input.GetMouseButtonDown(0)) + { + Press(Input.mousePosition); + } + if (Input.GetMouseButtonUp(0)) + { + Release(Input.mousePosition); + } + + if (Input.GetMouseButtonDown(1)) + { + this.pressedPosition = Input.mousePosition; + this.lastGo = RaycastObject(this.pressedPosition); + if (this.lastGo != null) + { + this.lastGo.SendMessage("OnPressRight", SendMessageOptions.DontRequireReceiver); + } + } + } + + + private void Press(Vector2 screenPos) + { + this.pressedPosition = screenPos; + this.Dragging = true; + + this.lastGo = RaycastObject(screenPos); + if (this.lastGo != null) + { + this.lastGo.SendMessage("OnPress", SendMessageOptions.DontRequireReceiver); + } + } + + private void Release(Vector2 screenPos) + { + if (this.lastGo != null) + { + GameObject currentGo = RaycastObject(screenPos); + if (currentGo == this.lastGo) + { + this.lastGo.SendMessage("OnClick", SendMessageOptions.DontRequireReceiver); + } + + this.lastGo.SendMessage("OnRelease", SendMessageOptions.DontRequireReceiver); + this.lastGo = null; + } + + this.pressedPosition = Vector2.zero; + this.Dragging = false; + } + + private GameObject RaycastObject(Vector2 screenPos) + { + RaycastHit info; + if (Physics.Raycast(this.m_Camera.ScreenPointToRay(screenPos), out info, 200)) + { + inputHitPos = info.point; + return info.collider.gameObject; + } + + return null; + } +} \ No newline at end of file diff --git a/Assets/Photon Unity Networking/UtilityScripts/InputToEvent.cs.meta b/Assets/Photon Unity Networking/UtilityScripts/InputToEvent.cs.meta new file mode 100644 index 0000000..9f0f350 --- /dev/null +++ b/Assets/Photon Unity Networking/UtilityScripts/InputToEvent.cs.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 4fdde8222e647b24b816eec3ad67ff32 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} diff --git a/Assets/Photon Unity Networking/UtilityScripts/ManualPhotonViewAllocator.cs b/Assets/Photon Unity Networking/UtilityScripts/ManualPhotonViewAllocator.cs new file mode 100644 index 0000000..d02e432 --- /dev/null +++ b/Assets/Photon Unity Networking/UtilityScripts/ManualPhotonViewAllocator.cs @@ -0,0 +1,31 @@ +using UnityEngine; +using System.Collections; + +[RequireComponent(typeof(PhotonView))] +public class ManualPhotonViewAllocator : MonoBehaviour +{ + public GameObject Prefab; + + public void AllocateManualPhotonView() + { + PhotonView pv = this.gameObject.GetPhotonView(); + if (pv == null) + { + Debug.LogError("Can't do manual instantiation without PhotonView component."); + return; + } + + int viewID = PhotonNetwork.AllocateViewID(); + pv.RPC("InstantiateRpc", PhotonTargets.AllBuffered, viewID); + } + + [PunRPC] + public void InstantiateRpc(int viewID) + { + GameObject go = GameObject.Instantiate(Prefab, InputToEvent.inputHitPos + new Vector3(0, 5f, 0), Quaternion.identity) as GameObject; + go.GetPhotonView().viewID = viewID; + + OnClickDestroy ocd = go.GetComponent(); + ocd.DestroyByRpc = true; + } +} diff --git a/Assets/Photon Unity Networking/UtilityScripts/ManualPhotonViewAllocator.cs.meta b/Assets/Photon Unity Networking/UtilityScripts/ManualPhotonViewAllocator.cs.meta new file mode 100644 index 0000000..0499fb5 --- /dev/null +++ b/Assets/Photon Unity Networking/UtilityScripts/ManualPhotonViewAllocator.cs.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 2668418d0a8c6804facdeca6e5fc6d98 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} diff --git a/Assets/Photon Unity Networking/UtilityScripts/MoveByKeys.cs b/Assets/Photon Unity Networking/UtilityScripts/MoveByKeys.cs new file mode 100644 index 0000000..551af7c --- /dev/null +++ b/Assets/Photon Unity Networking/UtilityScripts/MoveByKeys.cs @@ -0,0 +1,85 @@ +using UnityEngine; + +/// +/// Very basic component to move a GameObject by WASD and Space. +/// +/// +/// Requires a PhotonView. +/// Disables itself on GameObjects that are not owned on Start. +/// +/// Speed affects movement-speed. +/// JumpForce defines how high the object "jumps". +/// JumpTimeout defines after how many seconds you can jump again. +/// +[RequireComponent(typeof (PhotonView))] +public class MoveByKeys : Photon.MonoBehaviour +{ + public float Speed = 10f; + public float JumpForce = 200f; + public float JumpTimeout = 0.5f; + + private bool isSprite; + private float jumpingTime; + private Rigidbody body; + private Rigidbody2D body2d; + + public void Start() + { + //enabled = photonView.isMine; + this.isSprite = (GetComponent() != null); + + this.body2d = GetComponent(); + this.body = GetComponent(); + } + + + // Update is called once per frame + public void FixedUpdate() + { + if (!photonView.isMine) + { + return; + } + + if ((Input.GetAxisRaw("Horizontal") < -0.1f) || (Input.GetAxisRaw("Horizontal") > 0.1f)) + { + transform.position += Vector3.right * (Speed * Time.deltaTime) * Input.GetAxisRaw("Horizontal"); + } + + // jumping has a simple "cooldown" time but you could also jump in the air + if (this.jumpingTime <= 0.0f) + { + if (this.body != null || this.body2d != null) + { + // obj has a Rigidbody and can jump (AddForce) + if (Input.GetKey(KeyCode.Space)) + { + this.jumpingTime = this.JumpTimeout; + + Vector2 jump = Vector2.up*this.JumpForce; + if (this.body2d != null) + { + this.body2d.AddForce(jump); + } + else if (this.body != null) + { + this.body.AddForce(jump); + } + } + } + } + else + { + this.jumpingTime -= Time.deltaTime; + } + + // 2d objects can't be moved in 3d "forward" + if (!this.isSprite) + { + if ((Input.GetAxisRaw("Vertical") < -0.1f) || (Input.GetAxisRaw("Vertical") > 0.1f)) + { + transform.position += Vector3.forward * (Speed * Time.deltaTime) * Input.GetAxisRaw("Vertical"); + } + } + } +} diff --git a/Assets/Photon Unity Networking/UtilityScripts/MoveByKeys.cs.meta b/Assets/Photon Unity Networking/UtilityScripts/MoveByKeys.cs.meta new file mode 100644 index 0000000..63447da --- /dev/null +++ b/Assets/Photon Unity Networking/UtilityScripts/MoveByKeys.cs.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 99b4daedc5e674a429acdf1e77da6a55 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} diff --git a/Assets/Photon Unity Networking/UtilityScripts/NetworkCullingHandler.cs b/Assets/Photon Unity Networking/UtilityScripts/NetworkCullingHandler.cs new file mode 100644 index 0000000..4413fd2 --- /dev/null +++ b/Assets/Photon Unity Networking/UtilityScripts/NetworkCullingHandler.cs @@ -0,0 +1,220 @@ +using System.Collections.Generic; +using UnityEngine; + +/// +/// Handles the network culling. +/// +[RequireComponent(typeof(PhotonView))] +public class NetworkCullingHandler : MonoBehaviour, IPunObservable +{ + #region VARIABLES + + private int orderIndex; + + private CullArea cullArea; + + private List previousActiveCells, activeCells; + + private PhotonView pView; + + private Vector3 lastPosition, currentPosition; + + #endregion + + #region UNITY_FUNCTIONS + + /// + /// Gets references to the PhotonView component and the cull area game object. + /// + private void OnEnable() + { + if (this.pView == null) + { + this.pView = GetComponent(); + + if (!this.pView.isMine) + { + return; + } + } + + if (this.cullArea == null) + { + this.cullArea = FindObjectOfType(); + } + + this.previousActiveCells = new List(0); + this.activeCells = new List(0); + + this.currentPosition = this.lastPosition = transform.position; + } + + /// + /// Initializes the right interest group or prepares the permanent change of the interest group of the PhotonView component. + /// + private void Start() + { + if (!this.pView.isMine) + { + return; + } + + if (PhotonNetwork.inRoom) + { + if (this.cullArea.NumberOfSubdivisions == 0) + { + this.pView.group = this.cullArea.FIRST_GROUP_ID; + + PhotonNetwork.SetInterestGroups(this.cullArea.FIRST_GROUP_ID, true); + PhotonNetwork.SetSendingEnabled(this.cullArea.FIRST_GROUP_ID, true); + } + else + { + // This is used to continuously update the active group. + this.pView.ObservedComponents.Add(this); + } + } + } + + /// + /// Checks if the player has moved previously and updates the interest groups if necessary. + /// + private void Update() + { + if (!this.pView.isMine) + { + return; + } + + this.lastPosition = this.currentPosition; + this.currentPosition = transform.position; + + // This is a simple position comparison of the current and the previous position. + // When using Network Culling in a bigger project keep in mind that there might + // be more transform-related options, e.g. the rotation, or other options to check. + if (this.currentPosition != this.lastPosition) + { + if (this.HaveActiveCellsChanged()) + { + this.UpdateInterestGroups(); + } + } + } + + /// + /// Drawing informations. + /// + private void OnGUI() + { + if (!this.pView.isMine) + { + return; + } + + string subscribedAndActiveCells = "Inside cells:\n"; + string subscribedCells = "Subscribed cells:\n"; + + for (int index = 0; index < this.activeCells.Count; ++index) + { + if (index <= this.cullArea.NumberOfSubdivisions) + { + subscribedAndActiveCells += this.activeCells[index] + " "; + } + + subscribedCells += this.activeCells[index] + " "; + } + + GUI.Label(new Rect(20.0f, Screen.height - 100.0f, 200.0f, 40.0f), "" + subscribedAndActiveCells + "", new GUIStyle() { alignment = TextAnchor.UpperLeft, fontSize = 16 }); + GUI.Label(new Rect(20.0f, Screen.height - 60.0f, 200.0f, 40.0f), "" + subscribedCells + "", new GUIStyle() { alignment = TextAnchor.UpperLeft, fontSize = 16 }); + } + + #endregion + + /// + /// Checks if the previously active cells have changed. + /// + /// True if the previously active cells have changed and false otherwise. + private bool HaveActiveCellsChanged() + { + if (this.cullArea.NumberOfSubdivisions == 0) + { + return false; + } + + this.previousActiveCells = new List(this.activeCells); + this.activeCells = this.cullArea.GetActiveCells(transform.position); + + // If the player leaves the area we insert the whole area itself as an active cell. + // This can be removed if it is sure that the player is not able to leave the area. + while (this.activeCells.Count <= this.cullArea.NumberOfSubdivisions) + { + this.activeCells.Add(this.cullArea.FIRST_GROUP_ID); + } + + if (this.activeCells.Count != this.previousActiveCells.Count) + { + return true; + } + + if (this.activeCells[this.cullArea.NumberOfSubdivisions] != this.previousActiveCells[this.cullArea.NumberOfSubdivisions]) + { + return true; + } + + return false; + } + + /// + /// Unsubscribes from old and subscribes to new interest groups. + /// + private void UpdateInterestGroups() + { + List disable = new List(0); + + foreach (byte groupId in this.previousActiveCells) + { + if (!this.activeCells.Contains(groupId)) + { + disable.Add(groupId); + } + } + + PhotonNetwork.SetInterestGroups(disable.ToArray(), this.activeCells.ToArray()); + PhotonNetwork.SetSendingEnabled(disable.ToArray(), this.activeCells.ToArray()); + } + + #region IPunObservable implementation + + /// + /// This time OnPhotonSerializeView is not used to send or receive any kind of data. + /// It is used to change the currently active group of the PhotonView component, making it work together with PUN more directly. + /// Keep in mind that this function is only executed, when there is at least one more player in the room. + /// + public void OnPhotonSerializeView(PhotonStream stream, PhotonMessageInfo info) + { + // If the player leaves the area we insert the whole area itself as an active cell. + // This can be removed if it is sure that the player is not able to leave the area. + while (this.activeCells.Count <= this.cullArea.NumberOfSubdivisions) + { + this.activeCells.Add(this.cullArea.FIRST_GROUP_ID); + } + + if (this.cullArea.NumberOfSubdivisions == 1) + { + this.orderIndex = (++this.orderIndex%this.cullArea.SUBDIVISION_FIRST_LEVEL_ORDER.Length); + this.pView.group = this.activeCells[this.cullArea.SUBDIVISION_FIRST_LEVEL_ORDER[this.orderIndex]]; + } + else if (this.cullArea.NumberOfSubdivisions == 2) + { + this.orderIndex = (++this.orderIndex%this.cullArea.SUBDIVISION_SECOND_LEVEL_ORDER.Length); + this.pView.group = this.activeCells[this.cullArea.SUBDIVISION_SECOND_LEVEL_ORDER[this.orderIndex]]; + } + else if (this.cullArea.NumberOfSubdivisions == 3) + { + this.orderIndex = (++this.orderIndex%this.cullArea.SUBDIVISION_THIRD_LEVEL_ORDER.Length); + this.pView.group = this.activeCells[this.cullArea.SUBDIVISION_THIRD_LEVEL_ORDER[this.orderIndex]]; + } + } + + #endregion +} \ No newline at end of file diff --git a/Assets/Photon Unity Networking/UtilityScripts/NetworkCullingHandler.cs.meta b/Assets/Photon Unity Networking/UtilityScripts/NetworkCullingHandler.cs.meta new file mode 100644 index 0000000..74b7441 --- /dev/null +++ b/Assets/Photon Unity Networking/UtilityScripts/NetworkCullingHandler.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 84db789113d4b01418c1becb128c4561 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Photon Unity Networking/UtilityScripts/OnClickDestroy.cs b/Assets/Photon Unity Networking/UtilityScripts/OnClickDestroy.cs new file mode 100644 index 0000000..80153f1 --- /dev/null +++ b/Assets/Photon Unity Networking/UtilityScripts/OnClickDestroy.cs @@ -0,0 +1,45 @@ +using UnityEngine; +using System.Collections; + +/// +/// Implements OnClick to destroy the GameObject it's attached to. Optionally a RPC is sent to do this. +/// +/// +/// Using an RPC to Destroy a GameObject allows any player to Destroy a GameObject. But it might cause errors. +/// RPC and the Instantiated GameObject are not fully linked on the server. One might stick in the server witout +/// the other. +/// +/// A buffered RPC gets cleaned up when the sending player leaves the room. This means, the RPC gets lost. +/// +/// Vice versus, a GameObject Instantiate might get cleaned up when the creating player leaves a room. +/// This way, the GameObject that a RPC targets might become lost. +/// +/// It makes sense to test those cases. Many are not breaking errors and you just have to be aware of them. +/// +/// Gets OnClick() calls by InputToEvent class attached to a camera. +/// +[RequireComponent(typeof(PhotonView))] +public class OnClickDestroy : Photon.MonoBehaviour +{ + public bool DestroyByRpc; + + public void OnClick() + { + if (!DestroyByRpc) + { + PhotonNetwork.Destroy(this.gameObject); + } + else + { + this.photonView.RPC("DestroyRpc", PhotonTargets.AllBuffered); + } + } + + [PunRPC] + public IEnumerator DestroyRpc() + { + GameObject.Destroy(this.gameObject); + yield return 0; // if you allow 1 frame to pass, the object's OnDestroy() method gets called and cleans up references. + PhotonNetwork.UnAllocateViewID(this.photonView.viewID); + } +} diff --git a/Assets/Photon Unity Networking/UtilityScripts/OnClickDestroy.cs.meta b/Assets/Photon Unity Networking/UtilityScripts/OnClickDestroy.cs.meta new file mode 100644 index 0000000..f091f18 --- /dev/null +++ b/Assets/Photon Unity Networking/UtilityScripts/OnClickDestroy.cs.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 9dab7328ba500e944a99d62065fba6c0 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} diff --git a/Assets/Photon Unity Networking/UtilityScripts/OnClickInstantiate.cs b/Assets/Photon Unity Networking/UtilityScripts/OnClickInstantiate.cs new file mode 100644 index 0000000..30f4308 --- /dev/null +++ b/Assets/Photon Unity Networking/UtilityScripts/OnClickInstantiate.cs @@ -0,0 +1,42 @@ +using UnityEngine; +using System.Collections; + +public class OnClickInstantiate : MonoBehaviour +{ + public GameObject Prefab; + public int InstantiateType; + private string[] InstantiateTypeNames = {"Mine", "Scene"}; + + public bool showGui; + + void OnClick() + { + if (!PhotonNetwork.inRoom) + { + // only use PhotonNetwork.Instantiate while in a room. + return; + } + + switch (InstantiateType) + { + case 0: + PhotonNetwork.Instantiate(Prefab.name, InputToEvent.inputHitPos + new Vector3(0, 5f, 0), Quaternion.identity, 0); + break; + case 1: + PhotonNetwork.InstantiateSceneObject(Prefab.name, InputToEvent.inputHitPos + new Vector3(0, 5f, 0), Quaternion.identity, 0, null); + break; + } + } + + void OnGUI() + { + if (showGui) + { + GUILayout.BeginArea(new Rect(Screen.width - 180, 0, 180, 50)); + InstantiateType = GUILayout.Toolbar(InstantiateType, InstantiateTypeNames); + GUILayout.EndArea(); + } + } + + +} diff --git a/Assets/Photon Unity Networking/UtilityScripts/OnClickInstantiate.cs.meta b/Assets/Photon Unity Networking/UtilityScripts/OnClickInstantiate.cs.meta new file mode 100644 index 0000000..1150759 --- /dev/null +++ b/Assets/Photon Unity Networking/UtilityScripts/OnClickInstantiate.cs.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 9b79a9b62449de940a073364858c3f9b +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} diff --git a/Assets/Photon Unity Networking/UtilityScripts/OnClickLoadSomething.cs b/Assets/Photon Unity Networking/UtilityScripts/OnClickLoadSomething.cs new file mode 100644 index 0000000..fdef909 --- /dev/null +++ b/Assets/Photon Unity Networking/UtilityScripts/OnClickLoadSomething.cs @@ -0,0 +1,2 @@ +// this class was moved into the Marco Polo Tutorial folder, as it's only used there +// this file is here to make sure the class is not defined 2 times. \ No newline at end of file diff --git a/Assets/Photon Unity Networking/UtilityScripts/OnClickLoadSomething.cs.meta b/Assets/Photon Unity Networking/UtilityScripts/OnClickLoadSomething.cs.meta new file mode 100644 index 0000000..efc61a8 --- /dev/null +++ b/Assets/Photon Unity Networking/UtilityScripts/OnClickLoadSomething.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 6a05e7e66dac32a46b59f70b5f3da048 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Photon Unity Networking/UtilityScripts/OnJoinedInstantiate.cs b/Assets/Photon Unity Networking/UtilityScripts/OnJoinedInstantiate.cs new file mode 100644 index 0000000..c460354 --- /dev/null +++ b/Assets/Photon Unity Networking/UtilityScripts/OnJoinedInstantiate.cs @@ -0,0 +1,33 @@ +using UnityEngine; +using System.Collections; + +public class OnJoinedInstantiate : MonoBehaviour +{ + public Transform SpawnPosition; + public float PositionOffset = 2.0f; + public GameObject[] PrefabsToInstantiate; // set in inspector + + public void OnJoinedRoom() + { + if (this.PrefabsToInstantiate != null) + { + foreach (GameObject o in this.PrefabsToInstantiate) + { + Debug.Log("Instantiating: " + o.name); + + Vector3 spawnPos = Vector3.up; + if (this.SpawnPosition != null) + { + spawnPos = this.SpawnPosition.position; + } + + Vector3 random = Random.insideUnitSphere; + random.y = 0; + random = random.normalized; + Vector3 itempos = spawnPos + this.PositionOffset * random; + + PhotonNetwork.Instantiate(o.name, itempos, Quaternion.identity, 0); + } + } + } +} diff --git a/Assets/Photon Unity Networking/UtilityScripts/OnJoinedInstantiate.cs.meta b/Assets/Photon Unity Networking/UtilityScripts/OnJoinedInstantiate.cs.meta new file mode 100644 index 0000000..5b4fba0 --- /dev/null +++ b/Assets/Photon Unity Networking/UtilityScripts/OnJoinedInstantiate.cs.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: ed3b5dcba7bf9114cb13fc59e0a71f55 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} diff --git a/Assets/Photon Unity Networking/UtilityScripts/OnStartDelete.cs b/Assets/Photon Unity Networking/UtilityScripts/OnStartDelete.cs new file mode 100644 index 0000000..1ef64de --- /dev/null +++ b/Assets/Photon Unity Networking/UtilityScripts/OnStartDelete.cs @@ -0,0 +1,11 @@ +using UnityEngine; + +/// This component will destroy the GameObject it is attached to (in Start()). +public class OnStartDelete : MonoBehaviour +{ + // Use this for initialization + void Start() + { + Destroy(this.gameObject); + } +} \ No newline at end of file diff --git a/Assets/Photon Unity Networking/UtilityScripts/OnStartDelete.cs.meta b/Assets/Photon Unity Networking/UtilityScripts/OnStartDelete.cs.meta new file mode 100644 index 0000000..4f4d47a --- /dev/null +++ b/Assets/Photon Unity Networking/UtilityScripts/OnStartDelete.cs.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: f8d56a54ae062da4a87516fb994f4e30 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} diff --git a/Assets/Photon Unity Networking/UtilityScripts/PhotonPlayer.meta b/Assets/Photon Unity Networking/UtilityScripts/PhotonPlayer.meta new file mode 100644 index 0000000..459d7e3 --- /dev/null +++ b/Assets/Photon Unity Networking/UtilityScripts/PhotonPlayer.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 17184cdcc5bb84c1c89e0b8ecb79ca1d +folderAsset: yes +timeCreated: 1501014811 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Photon Unity Networking/UtilityScripts/PhotonPlayer/Editor.meta b/Assets/Photon Unity Networking/UtilityScripts/PhotonPlayer/Editor.meta new file mode 100644 index 0000000..1d023a5 --- /dev/null +++ b/Assets/Photon Unity Networking/UtilityScripts/PhotonPlayer/Editor.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: edb0ae7fe268e430ba136ccd2c0075ef +folderAsset: yes +timeCreated: 1501014812 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Photon Unity Networking/UtilityScripts/PhotonPlayer/Editor/PlayerRoomIndexingInspector.cs b/Assets/Photon Unity Networking/UtilityScripts/PhotonPlayer/Editor/PlayerRoomIndexingInspector.cs new file mode 100644 index 0000000..51942a4 --- /dev/null +++ b/Assets/Photon Unity Networking/UtilityScripts/PhotonPlayer/Editor/PlayerRoomIndexingInspector.cs @@ -0,0 +1,73 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Part of: Photon Unity Utilities, +// +// +// Custom inspector for PlayerRoomIndexing +// +// developer@exitgames.com +// -------------------------------------------------------------------------------------------------------------------- + + +using UnityEngine; +using System.Collections; +using System.Collections.Generic; +using UnityEditor; + +namespace ExitGames.UtilityScripts +{ + [CustomEditor(typeof(PlayerRoomIndexing))] + public class PlayerRoomIndexingInspector : Editor { + + PlayerRoomIndexing _target; + int localPlayerIndex; + + void OnEnable () { + _target = (PlayerRoomIndexing)target; + _target.OnRoomIndexingChanged += RefreshData; + } + + void OnDisable () { + _target = (PlayerRoomIndexing)target; + _target.OnRoomIndexingChanged -= RefreshData; + } + + public override void OnInspectorGUI() + { + _target = (PlayerRoomIndexing)target; + + _target.OnRoomIndexingChanged += RefreshData; + + if (PhotonNetwork.inRoom) + { + EditorGUILayout.LabelField("Player Index", "PhotonPlayer ID"); + if (_target.PlayerIds != null) + { + int index = 0; + foreach(int ID in _target.PlayerIds) + { + GUI.enabled = ID!=0; + EditorGUILayout.LabelField("Player " +index + + (PhotonNetwork.player.ID==ID?" - You -":"") + + (PhotonNetwork.masterClient.ID==ID?" Master":"") + , ID==0?"n/a":PhotonPlayer.Find(ID).ToStringFull()); + GUI.enabled = true; + index++; + } + } + }else{ + GUILayout.Label("Room Indexing only works when localPlayer is inside a room"); + } + } + + /// + /// force repaint fo the inspector, else we would not see the new data in the inspector. + /// This is better then doing it in OnInspectorGUI too many times per frame for no need + /// + void RefreshData() + { + Repaint(); + } + + } +} \ No newline at end of file diff --git a/Assets/Photon Unity Networking/UtilityScripts/PhotonPlayer/Editor/PlayerRoomIndexingInspector.cs.meta b/Assets/Photon Unity Networking/UtilityScripts/PhotonPlayer/Editor/PlayerRoomIndexingInspector.cs.meta new file mode 100644 index 0000000..4ed2ee0 --- /dev/null +++ b/Assets/Photon Unity Networking/UtilityScripts/PhotonPlayer/Editor/PlayerRoomIndexingInspector.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d6590f39353bf4efdb3b14691166135f +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Photon Unity Networking/UtilityScripts/PhotonPlayer/Editor/PunTeamsInspector.cs b/Assets/Photon Unity Networking/UtilityScripts/PhotonPlayer/Editor/PunTeamsInspector.cs new file mode 100644 index 0000000..b6baa8a --- /dev/null +++ b/Assets/Photon Unity Networking/UtilityScripts/PhotonPlayer/Editor/PunTeamsInspector.cs @@ -0,0 +1,57 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Part of: Photon Unity Utilities, +// +// +// Custom inspector for PunTeams +// +// developer@exitgames.com +// -------------------------------------------------------------------------------------------------------------------- + +using System; +using UnityEngine; +using System.Collections; +using System.Collections.Generic; +using UnityEditor; + +namespace ExitGames.UtilityScripts +{ + [CustomEditor(typeof(PunTeams))] + public class PunTeamsInspector : Editor { + + + Dictionary _Foldouts ; + + public override void OnInspectorGUI() + { + if (_Foldouts==null) + { + _Foldouts = new Dictionary(); + } + + if (PunTeams.PlayersPerTeam!=null) + { + foreach (KeyValuePair> _pair in PunTeams.PlayersPerTeam) + { + if (!_Foldouts.ContainsKey(_pair.Key)) + { + _Foldouts[_pair.Key] = true; + } + + _Foldouts[_pair.Key] = EditorGUILayout.Foldout(_Foldouts[_pair.Key],"Team "+_pair.Key +" ("+_pair.Value.Count+")"); + + if (_Foldouts[_pair.Key]) + { + EditorGUI.indentLevel++; + foreach(PhotonPlayer _player in _pair.Value) + { + EditorGUILayout.LabelField("",_player.ToString() + (PhotonNetwork.player==_player?" - You -":"")); + } + EditorGUI.indentLevel--; + } + + } + } + } + } +} \ No newline at end of file diff --git a/Assets/Photon Unity Networking/UtilityScripts/PhotonPlayer/Editor/PunTeamsInspector.cs.meta b/Assets/Photon Unity Networking/UtilityScripts/PhotonPlayer/Editor/PunTeamsInspector.cs.meta new file mode 100644 index 0000000..ff6b7e0 --- /dev/null +++ b/Assets/Photon Unity Networking/UtilityScripts/PhotonPlayer/Editor/PunTeamsInspector.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 7dcadaf22424c4f5d82f4d48c3b8097f +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Photon Unity Networking/UtilityScripts/PhotonPlayer/PlayerRoomIndexing.cs b/Assets/Photon Unity Networking/UtilityScripts/PhotonPlayer/PlayerRoomIndexing.cs new file mode 100644 index 0000000..32037c6 --- /dev/null +++ b/Assets/Photon Unity Networking/UtilityScripts/PhotonPlayer/PlayerRoomIndexing.cs @@ -0,0 +1,287 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Part of: Photon Unity Utilities, +// +// +// Assign numbers to Players in a room. Uses Room custom Properties +// +// developer@exitgames.com +// -------------------------------------------------------------------------------------------------------------------- + +using UnityEngine; +using System.Collections; +using System.Collections.Generic; +using System.Linq; + +using Photon; +using ExitGames.Client.Photon; +using Hashtable = ExitGames.Client.Photon.Hashtable; + + + +namespace ExitGames.UtilityScripts +{ + /// + /// Implements consistent indexing in a room/game with help of room properties. Access them by PhotonPlayer.GetRoomIndex() extension. + /// + /// + /// indexing ranges from 0 to the maximum number of Players. + /// indexing remains for the player while in room. + /// If a Player is indexed 2 and player indexes 1 leaves, index 1 become vacant and will assigned to the future player joining (the first available vacant index is assigned when joining) + /// + public class PlayerRoomIndexing : PunBehaviour + { + + #region Public Properties + + /// + /// The instance. EntryPoint to query about Room Indexing. + /// + public static PlayerRoomIndexing instance; + + /// + /// OnRoomIndexingChanged delegate. Use + /// + public delegate void RoomIndexingChanged(); + /// + /// Called everytime the room Indexing was updated. Use this for discrete updates. Always better than brute force calls every frame. + /// + public RoomIndexingChanged OnRoomIndexingChanged; + + /// Defines the room custom property name to use for room player indexing tracking. + public const string RoomPlayerIndexedProp = "PlayerIndexes"; + + /// + /// Cached list of Player indexes. You can use .GetRoomIndex() + /// + /// The player identifiers. + public int[] PlayerIds + { + get { + return _playerIds; + } + } + + #endregion + + + + #region Private Properties + + int[] _playerIds; + object _indexes; + Dictionary _indexesLUT; + List _indexesPool; + PhotonPlayer _p; + + #endregion + + #region MonoBehaviours methods + + public void Awake() + { + if (instance!=null) + { + Debug.LogError("Existing instance of PlayerRoomIndexing found. Only One instance is required at the most. Please correct and have only one at any time."); + } + instance = this; + + // check if we are already in room, likely if component was added at runtime or came late into scene + if (PhotonNetwork.room!=null) + { + SanitizeIndexing(true); + } + } + + #endregion + + + #region PunBehavior Overrides + + public override void OnJoinedRoom() + { + if (PhotonNetwork.isMasterClient) + { + AssignIndex(PhotonNetwork.player); + }else{ + RefreshData(); + } + } + + public override void OnLeftRoom() + { + RefreshData(); + } + + public override void OnPhotonPlayerConnected (PhotonPlayer newPlayer) + { + if (PhotonNetwork.isMasterClient) + { + AssignIndex(newPlayer); + } + + } + + public override void OnPhotonPlayerDisconnected(PhotonPlayer otherPlayer) + { + if (PhotonNetwork.isMasterClient) + { + UnAssignIndex(otherPlayer); + } + } + + public override void OnPhotonCustomRoomPropertiesChanged(Hashtable propertiesThatChanged) + { + if (propertiesThatChanged.ContainsKey(PlayerRoomIndexing.RoomPlayerIndexedProp)) + { + RefreshData(); + } + } + + + public override void OnMasterClientSwitched(PhotonPlayer newMasterClient) + { + if (PhotonNetwork.isMasterClient) + { + SanitizeIndexing(); + } + } + + #endregion + + /// Get the room index of a particular PhotonPlayer. You can also use .GetRoomIndex() + /// persistent index in room. -1 for none + public int GetRoomIndex( PhotonPlayer player) + { + if (_indexesLUT!=null && _indexesLUT.ContainsKey(player.ID)) + { + return _indexesLUT[player.ID]; + } + return -1; + } + + + /// + /// Sanitizes the indexing incase a player join while masterclient was changed and missed it. + /// + void SanitizeIndexing(bool forceIndexing = false) + { + if (!forceIndexing && !PhotonNetwork.isMasterClient) + { + return; + } + + if (PhotonNetwork.room==null) + { + return; + } + + // attempt to access index props. + Dictionary _indexesLUT_local = new Dictionary(); + if(PhotonNetwork.room.CustomProperties.TryGetValue(PlayerRoomIndexing.RoomPlayerIndexedProp, out _indexes)) + { + _indexesLUT_local = _indexes as Dictionary; + } + + // check if we need to assign + if (_indexesLUT_local.Count != PhotonNetwork.room.PlayerCount) + { + foreach(PhotonPlayer _p in PhotonNetwork.playerList) + { + if (!_indexesLUT_local.ContainsKey(_p.ID)) + { + // Debug.Log("Sanitizing Index for "+_p); + AssignIndex(_p); + } + } + + } + + } + + /// + /// Internal call Refresh the cached data and call the OnRoomIndexingChanged delegate. + /// + void RefreshData() + { + if (PhotonNetwork.room!=null) + { + _playerIds = new int[PhotonNetwork.room.MaxPlayers]; + if (PhotonNetwork.room.CustomProperties.TryGetValue(PlayerRoomIndexing.RoomPlayerIndexedProp, out _indexes)) + { + _indexesLUT = _indexes as Dictionary; + + foreach(KeyValuePair _entry in _indexesLUT) + { + //Debug.Log("Entry; "+_entry.Key+":"+_entry.Value); + _p = PhotonPlayer.Find(_entry.Key); + _playerIds[_entry.Value] = _p.ID; + } + } + }else{ + _playerIds = new int[0]; + } + + + if (OnRoomIndexingChanged!=null) OnRoomIndexingChanged(); + } + + + void AssignIndex(PhotonPlayer player) + { + if (PhotonNetwork.room.CustomProperties.TryGetValue(PlayerRoomIndexing.RoomPlayerIndexedProp, out _indexes)) + { + _indexesLUT = _indexes as Dictionary; + + }else{ + _indexesLUT = new Dictionary(); + } + + List _indexesPool = new List( new bool[PhotonNetwork.room.MaxPlayers] ); + foreach(KeyValuePair _entry in _indexesLUT) + { + _indexesPool[_entry.Value] = true; + } + + _indexesLUT[player.ID] = Mathf.Max (0,_indexesPool.IndexOf(false)); + + PhotonNetwork.room.SetCustomProperties(new Hashtable() {{PlayerRoomIndexing.RoomPlayerIndexedProp, _indexesLUT}}); + + RefreshData(); + } + + + void UnAssignIndex(PhotonPlayer player) + { + if (PhotonNetwork.room.CustomProperties.TryGetValue(PlayerRoomIndexing.RoomPlayerIndexedProp, out _indexes)) + { + _indexesLUT = _indexes as Dictionary; + + _indexesLUT.Remove(player.ID); + PhotonNetwork.room.SetCustomProperties(new Hashtable() {{PlayerRoomIndexing.RoomPlayerIndexedProp, _indexesLUT}}); + }else{ + + } + + RefreshData(); + } + + } + + /// Extension used for PlayerRoomIndexing and PhotonPlayer class. + public static class PlayerRoomIndexingExtensions + { + /// Extension for PhotonPlayer class to wrap up access to the player's custom property. + /// persistent index in room. -1 for no indexing + public static int GetRoomIndex(this PhotonPlayer player) + { + if (PlayerRoomIndexing.instance == null) + { + Debug.LogError("Missing PlayerRoomIndexing Component in Scene"); + return -1; + } + return PlayerRoomIndexing.instance.GetRoomIndex(player); + } + + } +} \ No newline at end of file diff --git a/Assets/Photon Unity Networking/UtilityScripts/PhotonPlayer/PlayerRoomIndexing.cs.meta b/Assets/Photon Unity Networking/UtilityScripts/PhotonPlayer/PlayerRoomIndexing.cs.meta new file mode 100644 index 0000000..c860e34 --- /dev/null +++ b/Assets/Photon Unity Networking/UtilityScripts/PhotonPlayer/PlayerRoomIndexing.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: f5a097d1ab84b464395a16e9a7bb35b1 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Photon Unity Networking/UtilityScripts/PickupItem.cs b/Assets/Photon Unity Networking/UtilityScripts/PickupItem.cs new file mode 100644 index 0000000..8413ba1 --- /dev/null +++ b/Assets/Photon Unity Networking/UtilityScripts/PickupItem.cs @@ -0,0 +1,213 @@ +using System.Collections.Generic; +using UnityEngine; +using System.Collections; +using Hashtable = ExitGames.Client.Photon.Hashtable; + +/// +/// Makes a scene object pickup-able. Needs a PhotonView which belongs to the scene. +/// +/// Includes a OnPhotonSerializeView implementation that +[RequireComponent(typeof(PhotonView))] +public class PickupItem : Photon.MonoBehaviour, IPunObservable +{ + ///Enables you to define a timeout when the picked up item should re-spawn at the same place it was before. + /// + /// Set in Inspector per GameObject! The value in code is just the default. + /// + /// If you don't want an item to respawn, set SecondsBeforeRespawn == 0. + /// If an item does not respawn, it could be consumed or carried around and dropped somewhere else. + /// + /// A respawning item should stick to a fixed position. It should not be observed at all (in any PhotonView). + /// It can only be consumed and can't be dropped somewhere else (cause that would double the item). + /// + /// This script uses PunRespawn() as RPC and as method that gets called by Invoke() after a timeout. + /// No matter if the item respawns timed or by Drop, that method makes sure (temporary) owner and other status-values + /// are being re-set. + /// + public float SecondsBeforeRespawn = 2; + + /// The most likely trigger to pick up an item. Set in inspector! + /// Edit the collider and set collision masks to avoid pickups by random objects. + public bool PickupOnTrigger; + + /// If the pickup item is currently yours. Interesting in OnPickedUp(PickupItem item). + public bool PickupIsMine; + + /// GameObject to send an event "OnPickedUp(PickupItem item)" to. + /// + /// Implement OnPickedUp(PickupItem item) {} in some script on the linked game object. + /// The item will be "this" and item.PickupIsMine will help you to find if this pickup was done by "this player". + /// + public MonoBehaviour OnPickedUpCall; + + + // these values are internally used. they are public for debugging only + + /// If this client sent a pickup. To avoid sending multiple pickup requests before reply is there. + public bool SentPickup; + + /// Timestamp when to respawn the item (compared to PhotonNetwork.time). + public double TimeOfRespawn; // needed when we want to update new players when a PickupItem respawns + + /// + public int ViewID { get { return this.photonView.viewID; } } + + public static HashSet DisabledPickupItems = new HashSet(); + + + public void OnTriggerEnter(Collider other) + { + // we only call Pickup() if "our" character collides with this PickupItem. + // note: if you "position" remote characters by setting their translation, triggers won't be hit. + + PhotonView otherpv = other.GetComponent(); + if (this.PickupOnTrigger && otherpv != null && otherpv.isMine) + { + //Debug.Log("OnTriggerEnter() calls Pickup()."); + this.Pickup(); + } + } + + + + public void OnPhotonSerializeView(PhotonStream stream, PhotonMessageInfo info) + { + // read the description in SecondsBeforeRespawn + + if (stream.isWriting && SecondsBeforeRespawn <= 0) + { + stream.SendNext(this.gameObject.transform.position); + } + else + { + // this will directly apply the last received position for this PickupItem. No smoothing. Usually not needed though. + Vector3 lastIncomingPos = (Vector3)stream.ReceiveNext(); + this.gameObject.transform.position = lastIncomingPos; + } + } + + + public void Pickup() + { + if (this.SentPickup) + { + // skip sending more pickups until the original pickup-RPC got back to this client + return; + } + + this.SentPickup = true; + this.photonView.RPC("PunPickup", PhotonTargets.AllViaServer); + } + + + /// Makes use of RPC PunRespawn to drop an item (sent through server for all). + public void Drop() + { + if (this.PickupIsMine) + { + this.photonView.RPC("PunRespawn", PhotonTargets.AllViaServer); + } + } + + /// Makes use of RPC PunRespawn to drop an item (sent through server for all). + public void Drop(Vector3 newPosition) + { + if (this.PickupIsMine) + { + this.photonView.RPC("PunRespawn", PhotonTargets.AllViaServer, newPosition); + } + } + + + [PunRPC] + public void PunPickup(PhotonMessageInfo msgInfo) + { + // when this client's RPC gets executed, this client no longer waits for a sent pickup and can try again + if (msgInfo.sender.IsLocal) this.SentPickup = false; + + + // In this solution, picked up items are disabled. They can't be picked up again this way, etc. + // You could check "active" first, if you're not interested in failed pickup-attempts. + if (!this.gameObject.GetActive()) + { + // optional logging: + Debug.Log("Ignored PU RPC, cause item is inactive. " + this.gameObject + " SecondsBeforeRespawn: " + SecondsBeforeRespawn + " TimeOfRespawn: " + this.TimeOfRespawn + " respawn in future: " + (TimeOfRespawn > PhotonNetwork.time)); + return; // makes this RPC being ignored + } + + + // if the RPC isn't ignored by now, this is a successful pickup. this might be "my" pickup and we should do a callback + this.PickupIsMine = msgInfo.sender.IsLocal; + + // call the method OnPickedUp(PickupItem item) if a GameObject was defined as callback target + if (this.OnPickedUpCall != null) + { + // you could also skip callbacks for items that are not picked up by this client by using: if (this.PickupIsMine) + this.OnPickedUpCall.SendMessage("OnPickedUp", this); + } + + + // setup a respawn (or none, if the item has to be dropped) + if (SecondsBeforeRespawn <= 0) + { + this.PickedUp(0.0f); // item doesn't auto-respawn. must be dropped + } + else + { + // how long it is until this item respanws, depends on the pickup time and the respawn time + double timeSinceRpcCall = (PhotonNetwork.time - msgInfo.timestamp); + double timeUntilRespawn = SecondsBeforeRespawn - timeSinceRpcCall; + + //Debug.Log("msg timestamp: " + msgInfo.timestamp + " time until respawn: " + timeUntilRespawn); + + if (timeUntilRespawn > 0) + { + this.PickedUp((float)timeUntilRespawn); + } + } + } + + internal void PickedUp(float timeUntilRespawn) + { + // this script simply disables the GO for a while until it respawns. + this.gameObject.SetActive(false); + PickupItem.DisabledPickupItems.Add(this); + this.TimeOfRespawn = 0; + + if (timeUntilRespawn > 0) + { + this.TimeOfRespawn = PhotonNetwork.time + timeUntilRespawn; + Invoke("PunRespawn", timeUntilRespawn); + } + } + + + [PunRPC] + internal void PunRespawn(Vector3 pos) + { + Debug.Log("PunRespawn with Position."); + this.PunRespawn(); + this.gameObject.transform.position = pos; + } + + [PunRPC] + internal void PunRespawn() + { + #if DEBUG + // debugging: in some cases, the respawn is "late". it's unclear why! just be aware of this. + double timeDiffToRespawnTime = PhotonNetwork.time - this.TimeOfRespawn; + if (timeDiffToRespawnTime > 0.1f) Debug.LogWarning("Spawn time is wrong by: " + timeDiffToRespawnTime + " (this is not an error. you just need to be aware of this.)"); + #endif + + + // if this is called from another thread, we might want to do this in OnEnable() instead of here (depends on Invoke's implementation) + PickupItem.DisabledPickupItems.Remove(this); + this.TimeOfRespawn = 0; + this.PickupIsMine = false; + + if (this.gameObject != null) + { + this.gameObject.SetActive(true); + } + } +} \ No newline at end of file diff --git a/Assets/Photon Unity Networking/UtilityScripts/PickupItem.cs.meta b/Assets/Photon Unity Networking/UtilityScripts/PickupItem.cs.meta new file mode 100644 index 0000000..a3dbbcb --- /dev/null +++ b/Assets/Photon Unity Networking/UtilityScripts/PickupItem.cs.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 49a81ce8037f41540ac70f51e9a19d7f +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} diff --git a/Assets/Photon Unity Networking/UtilityScripts/PickupItemSimple.cs b/Assets/Photon Unity Networking/UtilityScripts/PickupItemSimple.cs new file mode 100644 index 0000000..a738daf --- /dev/null +++ b/Assets/Photon Unity Networking/UtilityScripts/PickupItemSimple.cs @@ -0,0 +1,85 @@ +using UnityEngine; +using System.Collections; + +/// +/// Makes a scene object pickup-able. Needs a PhotonView which belongs to the scene. +/// +[RequireComponent(typeof(PhotonView))] +public class PickupItemSimple : Photon.MonoBehaviour +{ + public float SecondsBeforeRespawn = 2; + public bool PickupOnCollide; + public bool SentPickup; + + public void OnTriggerEnter(Collider other) + { + // we only call Pickup() if "our" character collides with this PickupItem. + // note: if you "position" remote characters by setting their translation, triggers won't be hit. + + PhotonView otherpv = other.GetComponent(); + if (this.PickupOnCollide && otherpv != null && otherpv.isMine) + { + //Debug.Log("OnTriggerEnter() calls Pickup()."); + this.Pickup(); + } + } + + public void Pickup() + { + if (this.SentPickup) + { + // skip sending more pickups until the original pickup-RPC got back to this client + return; + } + + this.SentPickup = true; + this.photonView.RPC("PunPickupSimple", PhotonTargets.AllViaServer); + } + + [PunRPC] + public void PunPickupSimple(PhotonMessageInfo msgInfo) + { + // one of the messages might be ours + // note: you could check "active" first, if you're not interested in your own, failed pickup-attempts. + if (this.SentPickup && msgInfo.sender.IsLocal) + { + if (this.gameObject.GetActive()) + { + // picked up! yay. + } + else + { + // pickup failed. too late (compared to others) + } + } + + this.SentPickup = false; + + if (!this.gameObject.GetActive()) + { + Debug.Log("Ignored PU RPC, cause item is inactive. " + this.gameObject); + return; + } + + + // how long it is until this item respanws, depends on the pickup time and the respawn time + double timeSinceRpcCall = (PhotonNetwork.time - msgInfo.timestamp); + float timeUntilRespawn = SecondsBeforeRespawn - (float)timeSinceRpcCall; + //Debug.Log("msg timestamp: " + msgInfo.timestamp + " time until respawn: " + timeUntilRespawn); + + if (timeUntilRespawn > 0) + { + // this script simply disables the GO for a while until it respawns. + this.gameObject.SetActive(false); + Invoke("RespawnAfter", timeUntilRespawn); + } + } + + public void RespawnAfter() + { + if (this.gameObject != null) + { + this.gameObject.SetActive(true); + } + } +} \ No newline at end of file diff --git a/Assets/Photon Unity Networking/UtilityScripts/PickupItemSimple.cs.meta b/Assets/Photon Unity Networking/UtilityScripts/PickupItemSimple.cs.meta new file mode 100644 index 0000000..4adcc55 --- /dev/null +++ b/Assets/Photon Unity Networking/UtilityScripts/PickupItemSimple.cs.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 7dcf9a2d8dc276745bb51228cc019f52 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} diff --git a/Assets/Photon Unity Networking/UtilityScripts/PickupItemSyncer.cs b/Assets/Photon Unity Networking/UtilityScripts/PickupItemSyncer.cs new file mode 100644 index 0000000..0723f8a --- /dev/null +++ b/Assets/Photon Unity Networking/UtilityScripts/PickupItemSyncer.cs @@ -0,0 +1,170 @@ +using System.Collections.Generic; +using UnityEngine; +using System.Collections; +using System; +using Hashtable = ExitGames.Client.Photon.Hashtable; + +/// Finds out which PickupItems are not spawned at the moment and send this to new players. +/// Attach this component to a single GameObject in the scene, not to all PickupItems. +[RequireComponent(typeof(PhotonView))] +public class PickupItemSyncer : Photon.MonoBehaviour +{ + public bool IsWaitingForPickupInit; + private const float TimeDeltaToIgnore = 0.2f; + + + public void OnPhotonPlayerConnected(PhotonPlayer newPlayer) + { + if (PhotonNetwork.isMasterClient) + { + this.SendPickedUpItems(newPlayer); + } + } + + public void OnJoinedRoom() + { + Debug.Log("Joined Room. isMasterClient: " + PhotonNetwork.isMasterClient + " id: " + PhotonNetwork.player.ID); + // this client joined the room. let's see if there are players and if someone has to inform us about pickups + this.IsWaitingForPickupInit = !PhotonNetwork.isMasterClient; + + if (PhotonNetwork.playerList.Length >= 2) + { + this.Invoke("AskForPickupItemSpawnTimes", 2.0f); + } + } + + + public void AskForPickupItemSpawnTimes() + { + if (this.IsWaitingForPickupInit) + { + if (PhotonNetwork.playerList.Length < 2) + { + Debug.Log("Cant ask anyone else for PickupItem spawn times."); + this.IsWaitingForPickupInit = false; + return; + } + + + // find a another player (than the master, who likely is gone) to ask for the PickupItem spawn times + PhotonPlayer nextPlayer = PhotonNetwork.masterClient.GetNext(); + if (nextPlayer == null || nextPlayer.Equals(PhotonNetwork.player)) + { + nextPlayer = PhotonNetwork.player.GetNext(); + //Debug.Log("This player is the Master's next. Asking this client's 'next' player: " + ((nextPlayer != null) ? nextPlayer.ToStringFull() : "")); + } + + if (nextPlayer != null && !nextPlayer.Equals(PhotonNetwork.player)) + { + this.photonView.RPC("RequestForPickupItems", nextPlayer); + + // you could restart this invoke and try to find another player after 4 seconds. but after a while it doesnt make a difference anymore + //this.Invoke("AskForPickupItemSpawnTimes", 2.0f); + } + else + { + Debug.Log("No player left to ask"); + this.IsWaitingForPickupInit = false; + } + } + } + + [PunRPC] + [Obsolete("Use RequestForPickupItems(PhotonMessageInfo msgInfo) with corrected typing instead.")] + public void RequestForPickupTimes(PhotonMessageInfo msgInfo) + { + RequestForPickupItems(msgInfo); + } + + [PunRPC] + public void RequestForPickupItems(PhotonMessageInfo msgInfo) + { + if (msgInfo.sender == null) + { + Debug.LogError("Unknown player asked for PickupItems"); + return; + } + + SendPickedUpItems(msgInfo.sender); + } + + /// Summarizes all PickupItem ids and spawn times for new players. Calls RPC "PickupItemInit". + /// The player to send the pickup times to. It's a targetted RPC. + private void SendPickedUpItems(PhotonPlayer targetPlayer) + { + if (targetPlayer == null) + { + Debug.LogWarning("Cant send PickupItem spawn times to unknown targetPlayer."); + return; + } + + double now = PhotonNetwork.time; + double soon = now + TimeDeltaToIgnore; + + + PickupItem[] items = new PickupItem[PickupItem.DisabledPickupItems.Count]; + PickupItem.DisabledPickupItems.CopyTo(items); + + List valuesToSend = new List(items.Length * 2); + for (int i = 0; i < items.Length; i++) + { + PickupItem pi = items[i]; + if (pi.SecondsBeforeRespawn <= 0) + { + valuesToSend.Add(pi.ViewID); + valuesToSend.Add((float)0.0f); + } + else + { + double timeUntilRespawn = pi.TimeOfRespawn - PhotonNetwork.time; + if (pi.TimeOfRespawn > soon) + { + // the respawn of this item is not "immediately", so we include it in the message "these items are not active" for the new player + Debug.Log(pi.ViewID + " respawn: " + pi.TimeOfRespawn + " timeUntilRespawn: " + timeUntilRespawn + " (now: " + PhotonNetwork.time + ")"); + valuesToSend.Add(pi.ViewID); + valuesToSend.Add((float)timeUntilRespawn); + } + } + } + + Debug.Log("Sent count: " + valuesToSend.Count + " now: " + now); + this.photonView.RPC("PickupItemInit", targetPlayer, PhotonNetwork.time, valuesToSend.ToArray()); + } + + + [PunRPC] + public void PickupItemInit(double timeBase, float[] inactivePickupsAndTimes) + { + this.IsWaitingForPickupInit = false; + + // if there are no inactive pickups, the sender will send a list of 0 items. this is not a problem... + for (int i = 0; i < inactivePickupsAndTimes.Length / 2; i++) + { + int arrayIndex = i*2; + int viewIdOfPickup = (int)inactivePickupsAndTimes[arrayIndex]; + float timeUntilRespawnBasedOnTimeBase = inactivePickupsAndTimes[arrayIndex + 1]; + + + PhotonView view = PhotonView.Find(viewIdOfPickup); + PickupItem pi = view.GetComponent(); + + if (timeUntilRespawnBasedOnTimeBase <= 0) + { + pi.PickedUp(0.0f); + } + else + { + double timeOfRespawn = timeUntilRespawnBasedOnTimeBase + timeBase; + + Debug.Log(view.viewID + " respawn: " + timeOfRespawn + " timeUntilRespawnBasedOnTimeBase:" + timeUntilRespawnBasedOnTimeBase + " SecondsBeforeRespawn: " + pi.SecondsBeforeRespawn); + double timeBeforeRespawn = timeOfRespawn - PhotonNetwork.time; + if (timeUntilRespawnBasedOnTimeBase <= 0) + { + timeBeforeRespawn = 0.0f; + } + + pi.PickedUp((float) timeBeforeRespawn); + } + } + } +} \ No newline at end of file diff --git a/Assets/Photon Unity Networking/UtilityScripts/PickupItemSyncer.cs.meta b/Assets/Photon Unity Networking/UtilityScripts/PickupItemSyncer.cs.meta new file mode 100644 index 0000000..57643c5 --- /dev/null +++ b/Assets/Photon Unity Networking/UtilityScripts/PickupItemSyncer.cs.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: d6826804b93f54045a69115648b2a143 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} diff --git a/Assets/Photon Unity Networking/UtilityScripts/PointedAtGameObjectInfo.cs b/Assets/Photon Unity Networking/UtilityScripts/PointedAtGameObjectInfo.cs new file mode 100644 index 0000000..90a5f12 --- /dev/null +++ b/Assets/Photon Unity Networking/UtilityScripts/PointedAtGameObjectInfo.cs @@ -0,0 +1,19 @@ +using UnityEngine; +using System.Collections; + +[RequireComponent(typeof(InputToEvent))] +public class PointedAtGameObjectInfo : MonoBehaviour +{ + void OnGUI() + { + if (InputToEvent.goPointedAt != null) + { + PhotonView pv = InputToEvent.goPointedAt.GetPhotonView(); + if (pv != null) + { + GUI.Label(new Rect(Input.mousePosition.x + 5, Screen.height - Input.mousePosition.y - 15, 300, 30), string.Format("ViewID {0} {1}{2}", pv.viewID, (pv.isSceneView) ? "scene " : "", (pv.isMine) ? "mine" : "owner: " + pv.ownerId)); + } + } + } + +} diff --git a/Assets/Photon Unity Networking/UtilityScripts/PointedAtGameObjectInfo.cs.meta b/Assets/Photon Unity Networking/UtilityScripts/PointedAtGameObjectInfo.cs.meta new file mode 100644 index 0000000..9ffbb4f --- /dev/null +++ b/Assets/Photon Unity Networking/UtilityScripts/PointedAtGameObjectInfo.cs.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: e6262dd9a9b078c4e8cbd47495aa6d23 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} diff --git a/Assets/Photon Unity Networking/UtilityScripts/PunPlayerScores.cs b/Assets/Photon Unity Networking/UtilityScripts/PunPlayerScores.cs new file mode 100644 index 0000000..dd50863 --- /dev/null +++ b/Assets/Photon Unity Networking/UtilityScripts/PunPlayerScores.cs @@ -0,0 +1,42 @@ +using System.Collections.Generic; +using UnityEngine; +using System.Collections; +using Hashtable = ExitGames.Client.Photon.Hashtable; + +public class PunPlayerScores : MonoBehaviour +{ + public const string PlayerScoreProp = "score"; +} + +public static class ScoreExtensions +{ + public static void SetScore(this PhotonPlayer player, int newScore) + { + Hashtable score = new Hashtable(); // using PUN's implementation of Hashtable + score[PunPlayerScores.PlayerScoreProp] = newScore; + + player.SetCustomProperties(score); // this locally sets the score and will sync it in-game asap. + } + + public static void AddScore(this PhotonPlayer player, int scoreToAddToCurrent) + { + int current = player.GetScore(); + current = current + scoreToAddToCurrent; + + Hashtable score = new Hashtable(); // using PUN's implementation of Hashtable + score[PunPlayerScores.PlayerScoreProp] = current; + + player.SetCustomProperties(score); // this locally sets the score and will sync it in-game asap. + } + + public static int GetScore(this PhotonPlayer player) + { + object score; + if (player.CustomProperties.TryGetValue(PunPlayerScores.PlayerScoreProp, out score)) + { + return (int) score; + } + + return 0; + } +} \ No newline at end of file diff --git a/Assets/Photon Unity Networking/UtilityScripts/PunPlayerScores.cs.meta b/Assets/Photon Unity Networking/UtilityScripts/PunPlayerScores.cs.meta new file mode 100644 index 0000000..5904915 --- /dev/null +++ b/Assets/Photon Unity Networking/UtilityScripts/PunPlayerScores.cs.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 6b4df3943860f1d45bfe232053a58d80 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} diff --git a/Assets/Photon Unity Networking/UtilityScripts/PunTeams.cs b/Assets/Photon Unity Networking/UtilityScripts/PunTeams.cs new file mode 100644 index 0000000..e9e4b23 --- /dev/null +++ b/Assets/Photon Unity Networking/UtilityScripts/PunTeams.cs @@ -0,0 +1,129 @@ +using System; +using System.Collections.Generic; +using ExitGames.Client.Photon; +using UnityEngine; +using Hashtable = ExitGames.Client.Photon.Hashtable; + + +/// +/// Implements teams in a room/game with help of player properties. Access them by PhotonPlayer.GetTeam extension. +/// +/// +/// Teams are defined by enum Team. Change this to get more / different teams. +/// There are no rules when / if you can join a team. You could add this in JoinTeam or something. +/// +public class PunTeams : MonoBehaviour +{ + /// Enum defining the teams available. First team should be neutral (it's the default value any field of this enum gets). + public enum Team : byte {none, red, blue}; + + /// The main list of teams with their player-lists. Automatically kept up to date. + /// Note that this is static. Can be accessed by PunTeam.PlayersPerTeam. You should not modify this. + public static Dictionary> PlayersPerTeam; + + /// Defines the player custom property name to use for team affinity of "this" player. + public const string TeamPlayerProp = "team"; + + + #region Events by Unity and Photon + + public void Start() + { + PlayersPerTeam = new Dictionary>(); + Array enumVals = Enum.GetValues(typeof (Team)); + foreach (var enumVal in enumVals) + { + PlayersPerTeam[(Team)enumVal] = new List(); + } + } + + public void OnDisable() + { + PlayersPerTeam = new Dictionary>(); + } + + /// Needed to update the team lists when joining a room. + /// Called by PUN. See enum PhotonNetworkingMessage for an explanation. + public void OnJoinedRoom() + { + + this.UpdateTeams(); + } + + public void OnLeftRoom() + { + Start(); + } + + /// Refreshes the team lists. It could be a non-team related property change, too. + /// Called by PUN. See enum PhotonNetworkingMessage for an explanation. + public void OnPhotonPlayerPropertiesChanged(object[] playerAndUpdatedProps) + { + this.UpdateTeams(); + } + + public void OnPhotonPlayerDisconnected(PhotonPlayer otherPlayer) + { + this.UpdateTeams(); + } + + public void OnPhotonPlayerConnected(PhotonPlayer newPlayer) + { + this.UpdateTeams(); + } + + #endregion + + + public void UpdateTeams() + { + Array enumVals = Enum.GetValues(typeof(Team)); + foreach (var enumVal in enumVals) + { + PlayersPerTeam[(Team)enumVal].Clear(); + } + + for (int i = 0; i < PhotonNetwork.playerList.Length; i++) + { + PhotonPlayer player = PhotonNetwork.playerList[i]; + Team playerTeam = player.GetTeam(); + PlayersPerTeam[playerTeam].Add(player); + } + } +} + +/// Extension used for PunTeams and PhotonPlayer class. Wraps access to the player's custom property. +public static class TeamExtensions +{ + /// Extension for PhotonPlayer class to wrap up access to the player's custom property. + /// PunTeam.Team.none if no team was found (yet). + public static PunTeams.Team GetTeam(this PhotonPlayer player) + { + object teamId; + if (player.CustomProperties.TryGetValue(PunTeams.TeamPlayerProp, out teamId)) + { + return (PunTeams.Team)teamId; + } + + return PunTeams.Team.none; + } + + /// Switch that player's team to the one you assign. + /// Internally checks if this player is in that team already or not. Only team switches are actually sent. + /// + /// + public static void SetTeam(this PhotonPlayer player, PunTeams.Team team) + { + if (!PhotonNetwork.connectedAndReady) + { + Debug.LogWarning("JoinTeam was called in state: " + PhotonNetwork.connectionStateDetailed + ". Not connectedAndReady."); + return; + } + + PunTeams.Team currentTeam = player.GetTeam(); + if (currentTeam != team) + { + player.SetCustomProperties(new Hashtable() {{PunTeams.TeamPlayerProp, (byte) team}}); + } + } +} \ No newline at end of file diff --git a/Assets/Photon Unity Networking/UtilityScripts/PunTeams.cs.meta b/Assets/Photon Unity Networking/UtilityScripts/PunTeams.cs.meta new file mode 100644 index 0000000..9dffb8a --- /dev/null +++ b/Assets/Photon Unity Networking/UtilityScripts/PunTeams.cs.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 6587c8104d7524f4280d0a68dd779f27 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} diff --git a/Assets/Photon Unity Networking/UtilityScripts/PunTurnManager.cs b/Assets/Photon Unity Networking/UtilityScripts/PunTurnManager.cs new file mode 100644 index 0000000..a90a390 --- /dev/null +++ b/Assets/Photon Unity Networking/UtilityScripts/PunTurnManager.cs @@ -0,0 +1,411 @@ +// ---------------------------------------------------------------------------- +// +// PhotonNetwork Framework for Unity - Copyright (C) 2016 Exit Games GmbH +// +// +// Manager for Turn Based games, using PUN +// +// developer@exitgames.com +// ---------------------------------------------------------------------------- + + +using System; +using System.Collections.Generic; +using ExitGames.Client.Photon; +using Photon; +using UnityEngine; +using ExitGames = ExitGames.Client.Photon.Hashtable; + +/// +/// Pun turnBased Game manager. +/// Provides an Interface (IPunTurnManagerCallbacks) for the typical turn flow and logic, between players +/// Provides Extensions for PhotonPlayer, Room and RoomInfo to feature dedicated api for TurnBased Needs +/// +public class PunTurnManager : PunBehaviour +{ + /// + /// Wraps accessing the "turn" custom properties of a room. + /// + /// The turn index + public int Turn + { + get { return PhotonNetwork.room.GetTurn(); } + private set { + + _isOverCallProcessed = false; + + PhotonNetwork.room.SetTurn(value, true); + } + } + + + /// + /// The duration of the turn in seconds. + /// + public float TurnDuration = 20f; + + /// + /// Gets the elapsed time in the current turn in seconds + /// + /// The elapsed time in the turn. + public float ElapsedTimeInTurn + { + get { return ((float)(PhotonNetwork.ServerTimestamp - PhotonNetwork.room.GetTurnStart()))/1000.0f; } + } + + + /// + /// Gets the remaining seconds for the current turn. Ranges from 0 to TurnDuration + /// + /// The remaining seconds fo the current turn + public float RemainingSecondsInTurn + { + get { return Mathf.Max(0f,this.TurnDuration - this.ElapsedTimeInTurn); } + } + + + /// + /// Gets a value indicating whether the turn is completed by all. + /// + /// true if this turn is completed by all; otherwise, false. + public bool IsCompletedByAll + { + get { return PhotonNetwork.room != null && Turn > 0 && this.finishedPlayers.Count == PhotonNetwork.room.PlayerCount; } + } + + /// + /// Gets a value indicating whether the current turn is finished by me. + /// + /// true if the current turn is finished by me; otherwise, false. + public bool IsFinishedByMe + { + get { return this.finishedPlayers.Contains(PhotonNetwork.player); } + } + + /// + /// Gets a value indicating whether the current turn is over. That is the ElapsedTimeinTurn is greater or equal to the TurnDuration + /// + /// true if the current turn is over; otherwise, false. + public bool IsOver + { + get { return this.RemainingSecondsInTurn <= 0f; } + } + + /// + /// The turn manager listener. Set this to your own script instance to catch Callbacks + /// + public IPunTurnManagerCallbacks TurnManagerListener; + + + /// + /// The finished players. + /// + private readonly HashSet finishedPlayers = new HashSet(); + + /// + /// The turn manager event offset event message byte. Used internaly for defining data in Room Custom Properties + /// + public const byte TurnManagerEventOffset = 0; + /// + /// The Move event message byte. Used internaly for saving data in Room Custom Properties + /// + public const byte EvMove = 1 + TurnManagerEventOffset; + /// + /// The Final Move event message byte. Used internaly for saving data in Room Custom Properties + /// + public const byte EvFinalMove = 2 + TurnManagerEventOffset; + + // keep track of message calls + private bool _isOverCallProcessed = false; + + #region MonoBehaviour CallBack + /// + /// Register for Event Call from PhotonNetwork. + /// + void Start() + { + PhotonNetwork.OnEventCall = OnEvent; + } + + void Update() + { + if (Turn > 0 && this.IsOver && !_isOverCallProcessed) + { + _isOverCallProcessed = true; + this.TurnManagerListener.OnTurnTimeEnds(this.Turn); + } + + } + + + #endregion + + + /// + /// Tells the TurnManager to begins a new turn. + /// + public void BeginTurn() + { + Turn = this.Turn + 1; // note: this will set a property in the room, which is available to the other players. + } + + + /// + /// Call to send an action. Optionally finish the turn, too. + /// The move object can be anything. Try to optimize though and only send the strict minimum set of information to define the turn move. + /// + /// + /// + public void SendMove(object move, bool finished) + { + if (IsFinishedByMe) + { + UnityEngine.Debug.LogWarning("Can't SendMove. Turn is finished by this player."); + return; + } + + // along with the actual move, we have to send which turn this move belongs to + Hashtable moveHt = new Hashtable(); + moveHt.Add("turn", Turn); + moveHt.Add("move", move); + + byte evCode = (finished) ? EvFinalMove : EvMove; + PhotonNetwork.RaiseEvent(evCode, moveHt, true, new RaiseEventOptions() { CachingOption = EventCaching.AddToRoomCache }); + if (finished) + { + PhotonNetwork.player.SetFinishedTurn(Turn); + } + + // the server won't send the event back to the origin (by default). to get the event, call it locally + // (note: the order of events might be mixed up as we do this locally) + OnEvent(evCode, moveHt, PhotonNetwork.player.ID); + } + + /// + /// Gets if the player finished the current turn. + /// + /// true, if player finished the current turn, false otherwise. + /// The Player to check for + public bool GetPlayerFinishedTurn(PhotonPlayer player) + { + if (player != null && this.finishedPlayers != null && this.finishedPlayers.Contains(player)) + { + return true; + } + + return false; + } + + #region Callbacks + + /// + /// Called by PhotonNetwork.OnEventCall registration + /// + /// Event code. + /// Content. + /// Sender identifier. + public void OnEvent(byte eventCode, object content, int senderId) + { + PhotonPlayer sender = PhotonPlayer.Find(senderId); + switch (eventCode) + { + case EvMove: + { + Hashtable evTable = content as Hashtable; + int turn = (int)evTable["turn"]; + object move = evTable["move"]; + this.TurnManagerListener.OnPlayerMove(sender, turn, move); + + break; + } + case EvFinalMove: + { + Hashtable evTable = content as Hashtable; + int turn = (int)evTable["turn"]; + object move = evTable["move"]; + + if (turn == this.Turn) + { + this.finishedPlayers.Add(sender); + + this.TurnManagerListener.OnPlayerFinished(sender, turn, move); + + } + + if (IsCompletedByAll) + { + this.TurnManagerListener.OnTurnCompleted(this.Turn); + } + break; + } + } + } + + /// + /// Called by PhotonNetwork + /// + /// Properties that changed. + public override void OnPhotonCustomRoomPropertiesChanged(Hashtable propertiesThatChanged) + { + + // Debug.Log("OnPhotonCustomRoomPropertiesChanged: "+propertiesThatChanged.ToStringFull()); + + if (propertiesThatChanged.ContainsKey("Turn")) + { + _isOverCallProcessed = false; + this.finishedPlayers.Clear(); + this.TurnManagerListener.OnTurnBegins(this.Turn); + } + } + + #endregion +} + + +public interface IPunTurnManagerCallbacks +{ + /// + /// Called the turn begins event. + /// + /// Turn Index + void OnTurnBegins(int turn); + + /// + /// Called when a turn is completed (finished by all players) + /// + /// Turn Index + void OnTurnCompleted(int turn); + + /// + /// Called when a player moved (but did not finish the turn) + /// + /// Player reference + /// Turn Index + /// Move Object data + void OnPlayerMove(PhotonPlayer player, int turn, object move); + + /// + /// When a player finishes a turn (includes the action/move of that player) + /// + /// Player reference + /// Turn index + /// Move Object data + void OnPlayerFinished(PhotonPlayer player, int turn, object move); + + + /// + /// Called when a turn completes due to a time constraint (timeout for a turn) + /// + /// Turn index + void OnTurnTimeEnds(int turn); +} + + +public static class TurnExtensions +{ + /// + /// currently ongoing turn number + /// + public static readonly string TurnPropKey = "Turn"; + + /// + /// start (server) time for currently ongoing turn (used to calculate end) + /// + public static readonly string TurnStartPropKey = "TStart"; + + /// + /// Finished Turn of Actor (followed by number) + /// + public static readonly string FinishedTurnPropKey = "FToA"; + + /// + /// Sets the turn. + /// + /// Room reference + /// Turn index + /// If set to true set start time. + public static void SetTurn(this Room room, int turn, bool setStartTime = false) + { + if (room == null || room.CustomProperties == null) + { + return; + } + + Hashtable turnProps = new Hashtable(); + turnProps[TurnPropKey] = turn; + if (setStartTime) + { + turnProps[TurnStartPropKey] = PhotonNetwork.ServerTimestamp; + } + + room.SetCustomProperties(turnProps); + } + + /// + /// Gets the current turn from a RoomInfo + /// + /// The turn index + /// RoomInfo reference + public static int GetTurn(this RoomInfo room) + { + if (room == null || room.CustomProperties == null || !room.CustomProperties.ContainsKey(TurnPropKey)) + { + return 0; + } + + return (int)room.CustomProperties[TurnPropKey]; + } + + + /// + /// Returns the start time when the turn began. This can be used to calculate how long it's going on. + /// + /// The turn start. + /// Room. + public static int GetTurnStart(this RoomInfo room) + { + if (room == null || room.CustomProperties == null || !room.CustomProperties.ContainsKey(TurnStartPropKey)) + { + return 0; + } + + return (int)room.CustomProperties[TurnStartPropKey]; + } + + /// + /// gets the player's finished turn (from the ROOM properties) + /// + /// The finished turn index + /// Player reference + public static int GetFinishedTurn(this PhotonPlayer player) + { + Room room = PhotonNetwork.room; + if (room == null || room.CustomProperties == null || !room.CustomProperties.ContainsKey(TurnPropKey)) + { + return 0; + } + + string propKey = FinishedTurnPropKey + player.ID; + return (int)room.CustomProperties[propKey]; + } + + /// + /// Sets the player's finished turn (in the ROOM properties) + /// + /// Player Reference + /// Turn Index + public static void SetFinishedTurn(this PhotonPlayer player, int turn) + { + Room room = PhotonNetwork.room; + if (room == null || room.CustomProperties == null) + { + return; + } + + string propKey = FinishedTurnPropKey + player.ID; + Hashtable finishedTurnProp = new Hashtable(); + finishedTurnProp[propKey] = turn; + + room.SetCustomProperties(finishedTurnProp); + } +} \ No newline at end of file diff --git a/Assets/Photon Unity Networking/UtilityScripts/PunTurnManager.cs.meta b/Assets/Photon Unity Networking/UtilityScripts/PunTurnManager.cs.meta new file mode 100644 index 0000000..0076919 --- /dev/null +++ b/Assets/Photon Unity Networking/UtilityScripts/PunTurnManager.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 1a1b3bda60e9e804f87fd1e5d20a885a +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Photon Unity Networking/UtilityScripts/QuitOnEscapeOrBack.cs b/Assets/Photon Unity Networking/UtilityScripts/QuitOnEscapeOrBack.cs new file mode 100644 index 0000000..d1020ae --- /dev/null +++ b/Assets/Photon Unity Networking/UtilityScripts/QuitOnEscapeOrBack.cs @@ -0,0 +1,14 @@ +using UnityEngine; +using System.Collections; + +public class QuitOnEscapeOrBack : MonoBehaviour +{ + private void Update() + { + // "back" button of phone equals "Escape". quit app if that's pressed + if (Input.GetKeyDown(KeyCode.Escape)) + { + Application.Quit(); + } + } +} diff --git a/Assets/Photon Unity Networking/UtilityScripts/QuitOnEscapeOrBack.cs.meta b/Assets/Photon Unity Networking/UtilityScripts/QuitOnEscapeOrBack.cs.meta new file mode 100644 index 0000000..6133070 --- /dev/null +++ b/Assets/Photon Unity Networking/UtilityScripts/QuitOnEscapeOrBack.cs.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 1fbabafd914a48f4eb6108d8d8f43d29 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} diff --git a/Assets/Photon Unity Networking/UtilityScripts/ShowStatusWhenConnecting.cs b/Assets/Photon Unity Networking/UtilityScripts/ShowStatusWhenConnecting.cs new file mode 100644 index 0000000..8f2dc55 --- /dev/null +++ b/Assets/Photon Unity Networking/UtilityScripts/ShowStatusWhenConnecting.cs @@ -0,0 +1,45 @@ +using UnityEngine; +using System.Collections; + +public class ShowStatusWhenConnecting : MonoBehaviour +{ + public GUISkin Skin; + + void OnGUI() + { + if( Skin != null ) + { + GUI.skin = Skin; + } + + float width = 400; + float height = 100; + + Rect centeredRect = new Rect( ( Screen.width - width ) / 2, ( Screen.height - height ) / 2, width, height ); + + GUILayout.BeginArea( centeredRect, GUI.skin.box ); + { + GUILayout.Label( "Connecting" + GetConnectingDots(), GUI.skin.customStyles[ 0 ] ); + GUILayout.Label( "Status: " + PhotonNetwork.connectionStateDetailed ); + } + GUILayout.EndArea(); + + if( PhotonNetwork.inRoom ) + { + enabled = false; + } + } + + string GetConnectingDots() + { + string str = ""; + int numberOfDots = Mathf.FloorToInt( Time.timeSinceLevelLoad * 3f % 4 ); + + for( int i = 0; i < numberOfDots; ++i ) + { + str += " ."; + } + + return str; + } +} diff --git a/Assets/Photon Unity Networking/UtilityScripts/ShowStatusWhenConnecting.cs.meta b/Assets/Photon Unity Networking/UtilityScripts/ShowStatusWhenConnecting.cs.meta new file mode 100644 index 0000000..a6a7b83 --- /dev/null +++ b/Assets/Photon Unity Networking/UtilityScripts/ShowStatusWhenConnecting.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 321c592dfcb49cd458c8f2cbe497513d +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Photon Unity Networking/UtilityScripts/SmoothSyncMovement.cs b/Assets/Photon Unity Networking/UtilityScripts/SmoothSyncMovement.cs new file mode 100644 index 0000000..cc49e49 --- /dev/null +++ b/Assets/Photon Unity Networking/UtilityScripts/SmoothSyncMovement.cs @@ -0,0 +1,54 @@ +using UnityEngine; +using System.Collections; + +[RequireComponent(typeof(PhotonView))] +public class SmoothSyncMovement : Photon.MonoBehaviour, IPunObservable +{ + public float SmoothingDelay = 5; + public void Awake() + { + bool observed = false; + foreach (Component observedComponent in this.photonView.ObservedComponents) + { + if (observedComponent == this) + { + observed = true; + break; + } + } + if (!observed) + { + Debug.LogWarning(this + " is not observed by this object's photonView! OnPhotonSerializeView() in this class won't be used."); + } + } + + public void OnPhotonSerializeView(PhotonStream stream, PhotonMessageInfo info) + { + if (stream.isWriting) + { + //We own this player: send the others our data + stream.SendNext(transform.position); + stream.SendNext(transform.rotation); + } + else + { + //Network player, receive data + correctPlayerPos = (Vector3)stream.ReceiveNext(); + correctPlayerRot = (Quaternion)stream.ReceiveNext(); + } + } + + private Vector3 correctPlayerPos = Vector3.zero; //We lerp towards this + private Quaternion correctPlayerRot = Quaternion.identity; //We lerp towards this + + public void Update() + { + if (!photonView.isMine) + { + //Update remote player (smooth this, this looks good, at the cost of some accuracy) + transform.position = Vector3.Lerp(transform.position, correctPlayerPos, Time.deltaTime * this.SmoothingDelay); + transform.rotation = Quaternion.Lerp(transform.rotation, correctPlayerRot, Time.deltaTime * this.SmoothingDelay); + } + } + +} \ No newline at end of file diff --git a/Assets/Photon Unity Networking/UtilityScripts/SmoothSyncMovement.cs.meta b/Assets/Photon Unity Networking/UtilityScripts/SmoothSyncMovement.cs.meta new file mode 100644 index 0000000..ed3764a --- /dev/null +++ b/Assets/Photon Unity Networking/UtilityScripts/SmoothSyncMovement.cs.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 35144820bcc25444bb8f0fd767d9423e +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} diff --git a/Assets/Photon Unity Networking/UtilityScripts/SupportLogger.cs b/Assets/Photon Unity Networking/UtilityScripts/SupportLogger.cs new file mode 100644 index 0000000..a6906b0 --- /dev/null +++ b/Assets/Photon Unity Networking/UtilityScripts/SupportLogger.cs @@ -0,0 +1,109 @@ +using System.Text; +using UnityEngine; +using System.Collections; +using ExitGames.Client.Photon; + +public class SupportLogger : MonoBehaviour +{ + public bool LogTrafficStats = true; + + public void Start() + { + GameObject go = GameObject.Find("PunSupportLogger"); + if (go == null) + { + go = new GameObject("PunSupportLogger"); + DontDestroyOnLoad(go); + SupportLogging sl = go.AddComponent(); + sl.LogTrafficStats = this.LogTrafficStats; + } + } +} + +public class SupportLogging : MonoBehaviour +{ + public bool LogTrafficStats; + + public void Start() + { + if (LogTrafficStats) + { + this.InvokeRepeating("LogStats", 10, 10); + } + } + + + protected void OnApplicationPause(bool pause) + { + Debug.Log("SupportLogger OnApplicationPause: " + pause + " connected: " + PhotonNetwork.connected); + } + + public void OnApplicationQuit() + { + this.CancelInvoke(); + } + + public void LogStats() + { + if (this.LogTrafficStats) + { + Debug.Log("SupportLogger " + PhotonNetwork.NetworkStatisticsToString()); + } + } + + private void LogBasics() + { + StringBuilder sb = new StringBuilder(); + sb.AppendFormat("SupportLogger Info: PUN {0}: ", PhotonNetwork.versionPUN); + + sb.AppendFormat("AppID: {0}*** GameVersion: {1} PeerId: {2} ", PhotonNetwork.networkingPeer.AppId.Substring(0, 8), PhotonNetwork.networkingPeer.AppVersion, PhotonNetwork.networkingPeer.PeerID); + sb.AppendFormat("Server: {0}. Region: {1} ", PhotonNetwork.ServerAddress, PhotonNetwork.networkingPeer.CloudRegion); + sb.AppendFormat("HostType: {0} ", PhotonNetwork.PhotonServerSettings.HostType); + + + Debug.Log(sb.ToString()); + } + + + public void OnConnectedToPhoton() + { + Debug.Log("SupportLogger OnConnectedToPhoton()."); + this.LogBasics(); + + if (LogTrafficStats) + { + PhotonNetwork.NetworkStatisticsEnabled = true; + } + } + + public void OnFailedToConnectToPhoton(DisconnectCause cause) + { + Debug.Log("SupportLogger OnFailedToConnectToPhoton("+cause+")."); + this.LogBasics(); + } + + public void OnJoinedLobby() + { + Debug.Log("SupportLogger OnJoinedLobby(" + PhotonNetwork.lobby + ")."); + } + + public void OnJoinedRoom() + { + Debug.Log("SupportLogger OnJoinedRoom(" + PhotonNetwork.room + "). " + PhotonNetwork.lobby + " GameServer:" + PhotonNetwork.ServerAddress); + } + + public void OnCreatedRoom() + { + Debug.Log("SupportLogger OnCreatedRoom(" + PhotonNetwork.room + "). " + PhotonNetwork.lobby + " GameServer:" + PhotonNetwork.ServerAddress); + } + + public void OnLeftRoom() + { + Debug.Log("SupportLogger OnLeftRoom()."); + } + + public void OnDisconnectedFromPhoton() + { + Debug.Log("SupportLogger OnDisconnectedFromPhoton()."); + } +} diff --git a/Assets/Photon Unity Networking/UtilityScripts/SupportLogger.cs.meta b/Assets/Photon Unity Networking/UtilityScripts/SupportLogger.cs.meta new file mode 100644 index 0000000..7e8b7cc --- /dev/null +++ b/Assets/Photon Unity Networking/UtilityScripts/SupportLogger.cs.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 9b61c60d38639484ebbd7f2100dd3d08 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} diff --git a/Assets/Photon Unity Networking/UtilityScripts/TimeKeeper.cs b/Assets/Photon Unity Networking/UtilityScripts/TimeKeeper.cs new file mode 100644 index 0000000..8cc124a --- /dev/null +++ b/Assets/Photon Unity Networking/UtilityScripts/TimeKeeper.cs @@ -0,0 +1,62 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Exit Games GmbH, 2012 +// +// +// TimeKeeper Helper. See class description. +// +// developer@exitgames.com +// -------------------------------------------------------------------------------------------------------------------- + +namespace ExitGames.Client.DemoParticle +{ + using System; + + /// + /// A utility class that turns it's ShouldExecute property to true after a set interval time has passed. + /// + /// + /// TimeKeepers can be useful to execute tasks in a certain interval within a game loop (integrating a recurring task into a certain thread). + /// + /// An interval can be overridden, when you set ShouldExecute to true. + /// Call Reset after execution of whatever you do to re-enable the TimeKeeper (ShouldExecute becomes false until interval passed). + /// Being based on Environment.TickCount, this is not very precise but cheap. + /// + public class TimeKeeper + { + private int lastExecutionTime = Environment.TickCount; + private bool shouldExecute; + + /// Interval in which ShouldExecute should be true (and something is executed). + public int Interval { get; set; } + + /// A disabled TimeKeeper never turns ShouldExecute to true. Reset won't affect IsEnabled! + public bool IsEnabled { get; set; } + + /// Turns true of the time interval has passed (after reset or creation) or someone set ShouldExecute manually. + /// Call Reset to start a new interval. + public bool ShouldExecute + { + get { return (this.IsEnabled && (this.shouldExecute || (Environment.TickCount - this.lastExecutionTime > this.Interval))); } + set { this.shouldExecute = value; } + } + + /// + /// Creates a new, enabled TimeKeeper and sets it's interval. + /// + /// + public TimeKeeper(int interval) + { + this.IsEnabled = true; + this.Interval = interval; + } + + /// ShouldExecute becomes false and the time interval is refreshed for next execution. + /// Does not affect IsEnabled. + public void Reset() + { + this.shouldExecute = false; + this.lastExecutionTime = Environment.TickCount; + } + } +} diff --git a/Assets/Photon Unity Networking/UtilityScripts/TimeKeeper.cs.meta b/Assets/Photon Unity Networking/UtilityScripts/TimeKeeper.cs.meta new file mode 100644 index 0000000..f8143a1 --- /dev/null +++ b/Assets/Photon Unity Networking/UtilityScripts/TimeKeeper.cs.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 11b45bfcb19ad694bb6f199fb97642ce +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} diff --git a/Assets/Photon Unity Networking/UtilityScripts/UI.meta b/Assets/Photon Unity Networking/UtilityScripts/UI.meta new file mode 100644 index 0000000..0982106 --- /dev/null +++ b/Assets/Photon Unity Networking/UtilityScripts/UI.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 3120b9b90409541138b1d5e7aa07c602 +folderAsset: yes +timeCreated: 1501014811 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Photon Unity Networking/UtilityScripts/UI/ButtonInsideScrollList.cs b/Assets/Photon Unity Networking/UtilityScripts/UI/ButtonInsideScrollList.cs new file mode 100644 index 0000000..36fe137 --- /dev/null +++ b/Assets/Photon Unity Networking/UtilityScripts/UI/ButtonInsideScrollList.cs @@ -0,0 +1,55 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Part of: Photon Unity Utilities, +// +// +// Used on Buttons inside UI lists to prevent scrollRect parent to scroll when down on buttons. +// +// developer@exitgames.com +// -------------------------------------------------------------------------------------------------------------------- + + +using UnityEngine; +using System.Collections; +using UnityEngine.EventSystems; +using UnityEngine.UI; + +namespace ExitGames.UtilityScripts +{ + /// + /// Button inside scroll list will stop scrolling ability of scrollRect container, so that when pressing down on a button and draggin up and down will not affect scrolling. + /// this doesn't do anything if no scrollRect component found in Parent Hierarchy. + /// + public class ButtonInsideScrollList : MonoBehaviour, IPointerDownHandler, IPointerUpHandler { + + ScrollRect scrollRect; + + // Use this for initialization + void Start () { + scrollRect = GetComponentInParent(); + } + + #region IPointerDownHandler implementation + void IPointerDownHandler.OnPointerDown (PointerEventData eventData) + { + if (scrollRect !=null) + { + scrollRect.StopMovement(); + scrollRect.enabled = false; + } + } + #endregion + + #region IPointerUpHandler implementation + + void IPointerUpHandler.OnPointerUp (PointerEventData eventData) + { + if (scrollRect !=null && !scrollRect.enabled) + { + scrollRect.enabled = true; + } + } + + #endregion + } +} \ No newline at end of file diff --git a/Assets/Photon Unity Networking/UtilityScripts/UI/ButtonInsideScrollList.cs.meta b/Assets/Photon Unity Networking/UtilityScripts/UI/ButtonInsideScrollList.cs.meta new file mode 100644 index 0000000..9e18870 --- /dev/null +++ b/Assets/Photon Unity Networking/UtilityScripts/UI/ButtonInsideScrollList.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: e0e8b381f2c05442ca5c01638958156a +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Photon Unity Networking/UtilityScripts/UI/TextButtonTransition.cs b/Assets/Photon Unity Networking/UtilityScripts/UI/TextButtonTransition.cs new file mode 100644 index 0000000..55c0700 --- /dev/null +++ b/Assets/Photon Unity Networking/UtilityScripts/UI/TextButtonTransition.cs @@ -0,0 +1,45 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// +// +// Use this on Button texts to have some color transition on the text as well without corrupting button's behaviour. +// +// developer@exitgames.com +// -------------------------------------------------------------------------------------------------------------------- + + +using UnityEngine; +using System.Collections; +using UnityEngine.EventSystems; +using UnityEngine.UI; + +namespace ExitGames.UtilityScripts +{ + + /// + /// Use this on Button texts to have some color transition on the text as well without corrupting button's behaviour. + /// + [RequireComponent(typeof(Text))] + public class TextButtonTransition : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler { + + Text _text; + + public Color NormalColor= Color.white; + public Color HoverColor = Color.black; + + public void Awake() + { + _text = GetComponent(); + } + + public void OnPointerEnter(PointerEventData eventData) + { + _text.color = HoverColor; + } + + public void OnPointerExit(PointerEventData eventData) + { + _text.color = NormalColor; + } + } +} \ No newline at end of file diff --git a/Assets/Photon Unity Networking/UtilityScripts/UI/TextButtonTransition.cs.meta b/Assets/Photon Unity Networking/UtilityScripts/UI/TextButtonTransition.cs.meta new file mode 100644 index 0000000..43cf251 --- /dev/null +++ b/Assets/Photon Unity Networking/UtilityScripts/UI/TextButtonTransition.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 9d234639538a34b8d9e3cc6362a7afd0 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Photon Unity Networking/UtilityScripts/UI/TextToggleIsOnTransition.cs b/Assets/Photon Unity Networking/UtilityScripts/UI/TextToggleIsOnTransition.cs new file mode 100644 index 0000000..81befa6 --- /dev/null +++ b/Assets/Photon Unity Networking/UtilityScripts/UI/TextToggleIsOnTransition.cs @@ -0,0 +1,68 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// +// +// Use this on Button texts to have some color transition on the text as well without corrupting button's behaviour. +// +// developer@exitgames.com +// -------------------------------------------------------------------------------------------------------------------- + + +using UnityEngine; +using System.Collections; +using UnityEngine.EventSystems; +using UnityEngine.UI; + +namespace ExitGames.UtilityScripts +{ + + /// + /// Use this on toggles texts to have some color transition on the text depending on the isOnState. + /// + [RequireComponent(typeof(Text))] + public class TextToggleIsOnTransition : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler { + + public Toggle toggle; + + Text _text; + + public Color NormalOnColor= Color.white; + public Color NormalOffColor = Color.black; + public Color HoverOnColor= Color.black; + public Color HoverOffColor = Color.black; + + bool isHover; + + public void OnEnable() + { + _text = GetComponent(); + + toggle.onValueChanged.AddListener(OnValueChanged); + } + + public void OnDisable() + { + toggle.onValueChanged.RemoveListener(OnValueChanged); + } + + public void OnValueChanged(bool isOn) + { + + _text.color = isOn? (isHover?HoverOnColor:HoverOffColor) : (isHover?NormalOnColor:NormalOffColor) ; + + } + + public void OnPointerEnter(PointerEventData eventData) + { + isHover = true; + _text.color = toggle.isOn?HoverOnColor:HoverOffColor; + } + + public void OnPointerExit(PointerEventData eventData) + { + isHover = false; + _text.color = toggle.isOn?NormalOnColor:NormalOffColor; + } + + } +} \ No newline at end of file diff --git a/Assets/Photon Unity Networking/UtilityScripts/UI/TextToggleIsOnTransition.cs.meta b/Assets/Photon Unity Networking/UtilityScripts/UI/TextToggleIsOnTransition.cs.meta new file mode 100644 index 0000000..a2ae161 --- /dev/null +++ b/Assets/Photon Unity Networking/UtilityScripts/UI/TextToggleIsOnTransition.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ec99d371d7c8e44899ce4b834dfd4d6a +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Photon Unity Networking/changelog.txt b/Assets/Photon Unity Networking/changelog.txt new file mode 100644 index 0000000..a965dc3 --- /dev/null +++ b/Assets/Photon Unity Networking/changelog.txt @@ -0,0 +1,998 @@ +v1.85 (6. July 2017) +Fixed: Interest Groups IDs are now of type byte for Instantiate (and all related code) as well. This fixes a cast exception. +Fixed: Internal use of NetworkingPeer.IsInitialConnect. It's now reset when the connection fails while connecting. This (currently) affects the "connected" and "connecting" values, which is likely to change. This fix is minimal by design. +Updated: PUN to no longer make use of obsolete enum values of the Photon library (dll). +Updated: Chat API and ChatGui. Now uses a thread to call SendOutgoingCommands, which keeps connections up (except on WebGL, where threading is not available). +Updated: To Photon library v4.1.1.14 with various fixes. See plugins\release_history.txt. + + +v1.84.1 (2. June 2017) +Fixed: A minor bug in the Photon3Unity3d.dll, which is now v4.1.1.13. The StreamBuffer.Seek() could fail to seek position 0 when length is 0. + +v1.84 (30. May 2017) +Fixed: PlayerRoomIndexing can now be added at runtime even on non MasterClient instance. master player is now indicated in the inspector. +Updated: NetworkingPeer.RunViewUpdate allocates less memory. +Moved: ReorderableListResources to namespace Photon.Pun to avoid conflicts with other "Rotorz" variants. This is an internal Editor-only change. +Updated: Unity 2017 Support. +Added: Support for a Switch add-on. You need to be certified developer for the platform to get access for this. Contact us by mail: developer@photonengine.com +Changed: SocketWebTcp to handle status changes for the used WebSocket. This fixes uncommon issues in WebGL exports. +Changed: SocketUdp.cs to lock less parts of the DNS / connection setup, which avoids potential freezes. +Updated: To Photon library v4.1.1.12 with various fixes. See plugins\release_history.txt. + +v1.83 (13. April 2017) +Fixed: A bug in the Photon3Unity3D.dll which led to timeouts. The bug was in v4.1.1.10 (PUN v1.82) and is fixed in v4.1.1.11 (now used in PUN v1.83). + +v1.82 (12. April 2017) +Fixed: Memory allocation in OnSerializeWrite(), when the view doesn't write data to the stream. +Removed: Conversion Wizard for very old Unity Networking projects of Unity 4.x. There is no automatic conversion possible for Unity 5.x "uNet" networking. +Moved: hasVoice and hasChat values are now in the general PhotonEditorUtils as HasVoice and HasChat, available to more Photon editor-classes if needed. Also, make sure to use HasCheckedProducts. +Added: RoomOption.DeleteNullProperties. When set to true, the server will delete Custom Room properties, when they are set to null as value. Defaults to off/false but can be really useful to keep the number of room-properties in check. The Photon Cloud update for this is scheduled after the Easter holidays (20th April or so). Before that date, the server will not use the new setting (but clients can prepare to send it already). +Fixed: Room.SetCustomProperties() to delete keys with null as value (the client that was setting the custom props did keep the key/value until until it was updated). The callback OnPhotonCustomRoomPropertiesChanged still has the keys with null values. They just don't get stored in Room.CustomProperties anymore. +Changed: Interest Groups IDs are now of type byte, as used by the Photon servers. It was an integer before but for the wrong reasons. This affects PhotonView.group, PhotonNetwork.SetSendingEnabled() and PhotonNetwork.SetReceivingEnabled(). The method SetReceivingEnabled is replaced by SetInterestGroups(). When you update, make sure to use the correct order of parameters. +Changed: UtilityScripts folder. Some scripts were not useful and got moved or deleted. General clean up. +Removed: PlayerVariables script content. It's completely replaced with the ColorPerPlayer script, which is more versatile. +Added: Checks of mandatory configuration values for console exports to make sure no setting is missing. In doubt, look out for error logs or a NotSupportedException on connect. +Fixed: The server selection "Best Region" now supports clusters, if sent by the Name Server. Clusters are optionally used by Exit Games as set of machines in a region. As before, PUN only stores the best region, not the cluster. The idea is that this automatically selects a fitting region (not a specific cluster). +Added: PhotonNetwork.CloudRegion to make the currently used Cloud Region accessible. This is mostly to expose existing values and to make debugging a little easier. +Updated: To Photon3Unity3D.dll v4.1.1.10 with some additional improvements in terms of memory usage. + +v1.81 (16. March 2017) +Updated: Basic Demo Launcher.cs: removed Log Level setup, it's now done in the Photon Settings. +Updated: Chat Demo ChatGui.cs: removed running in background setup, it's now done in the Photon settings. +Fixed: NetworkingPeer.cs: Fixed Scene Object OwnerShip transfer on late Join. +Fixed: ColorPerPlayer.cs and ColorPerPlayerApply.cs for a more robust connection with PlayerRoomIndexing.cs instance. +Fixed: Ownership handling when returning to a game. +Updated: Setting the log levels via code will now override the logging settings ("Pun Logging" and "Network Logging") from the PhotonServerSettings config. +Updated: Demo Hub scene to better highlight tutorial links versus links to online documentation. +Updated: Link for PhotonAnimatorView trigger doc url. +Added: Callback OnOwnershipTransfered. Called when a PhotonView Owner is transfered to a Player. +Added: Callback OnPhotonPlayerActivityChanged. Called when a remote Photon Player activity changed. This will be called ONLY is PlayerTtl is greater than 0. Check PhotonPlayer.IsInactive for the player. +Added: GetCustomRoomList(). Enables you to fetch a short, filtered list of room names from an "SQL lobby". +Fixed: Basic Demo Launcher: Fixed 5.4+ SceneManager OnSceneLoad callback to not throw errors when coming back to the demo hub +Fixed: ColorPerPlayerApply.cs: Disable routine was not safe and would throw errors +Changed: WebGL exports will now use secure https "GetPing" requests. This enables Best Region for content on https hosting. +Changed: The fallback thread to keep connections doesn't have to run when in offlineMode. +Updated: The Photon assemblies to v4.1.1.9, which includes several fixes. E.g. "WouldBlock Exception" and "BlockCopy Exception". More info is in the release history file for the dll. + +v1.80 (15. December 2016) +Fixed: PhotonTransformView first take routine to take in consideration what to update instead of forcing position, rotation scale no matter what. +Updated: PlayerRoomIndexing.cs to account for potential race conditions when masterClient is transfered and new player joins. SanitizeIndexing() is now in place. +Fixed: Fix ownership management for scene objects when MasterCLient is/was changed. +Updated: Chat demo, with new Friend Status update and message implementation available in the Interface as a friends' List. +Added: "Best Region" support for WebGL exports (uses http to measure roundtrip times). +Fixed: JoinRandomRoom() will now correctly send ExpectedUsers to the Game Server (if any were set in the RoomOptions). This fixes issues when you wanted to reserve slots in a room for other players. +Added: A null-reference check in FindGameObjectsWithComponent(), which could fail in rare cases otherwise. +Changed: Setting RunInBackground is now done in the PhotonSettings file. It's enabled by default but in a few exports, this could lead to issues. +Added: The internal "AuthEvent". This event by the server can now update the client's token anytime (before that expires). Good for longer play sessions. +Removed: Surplus debug log output. +Changed: Public variable- and property-naming to PascalCase (beginning with an uppercase character) in RoomInfo, Room and PhotonPlayer class. The old naming is still available but attributed as Obsolete, so you should update asap. Sadly, this is extra work for everyone but we want to make the API more stringent. +Changed: The PhotonPlayer.name is now .NickName to make it more obvious that this is not the user's ID (and might be changed at will). +Removed: Obsolete PhotonView.observed. Since a while, each PhotonView has a list of observed components instead. If you have a very old (!) project, check your PhotonViews and make sure they still observe the scripts you meant to observe. Newer projects won't be affected. + +v1.79 (18. November 2016) +Changed: PUN will no longer aggregate the data from ALL objects in a group into ONE message. Instead, a maximum of 10 objects will be sent together. The idea is to avoid huge messages, which need fragmentation. Fragmentation needs to be avoided, cause fragments are always reliable (and you basically lose "unreliable" updates when you send too much). There is a new variable for this: NetworkingPeer.ObjectsInOneUpdate. +Changed: As we send a max of 10 gameobject-updates in one message, we can use a byte as type for their ID (instead of short). This minimally saves data but makes this PUN incompatible with older builds. We separate PUN versions for you so there won't be a clash. PhotonNetwork.versionPUN is inserted into your Game Version to separate players. +Updated: PunTeams to keep PlayerPerTeams Listing up to date. +Updated: PlayerRoomIndexing improved consistency across various network contexts. +Fixed: SocketWebTcp for WebGL was time scale dependant and would stop receiving events when Time.TimeScale = 0. +Updated: DemoChat UI reworked to match demo Hub look and feel. +Updated: DemoHub pixel Perfect Canvas fix. +Added: Two more regions: Korea, Seoul (kr) and India, Chennai (in). If you're using the hosting option "Best Region", you may want to update the configuration in your PhotonServerSettings file. +Updated: PunBasics-Launcher demo scene Canvas screensize fix. + +v1.78 (1. November 2016) +Fixed: NetworkingPeer ownership assignment on late join when MasterClient is involved. +Fixed: SetTeam() (in PunTeam) now assigns the team to the target player, instead of the local one. You could use the extension method on any PhotonPlayer (not only on yours). +Fixed: PlayerVariable.cs material assignment to take MasterClient as a special case and avoid color mixup. +New: PlayerRoomIndexing component in Utilities to have simple indexing of Players inside a room. Used in ColorPerPlayer script. +Updated: PunTeams more consistent for PlayersPerTeam content, and now featuring a custom inspector to show Teams assignment to each Player. + +v1.77 (24. October 2016) +Changed: Transfer Ownership requests are now handled a little different. For "takeover", any player's request is successful if taking from the correct, current owner OR when taking from the master client (even though the owner is technically the room). E.g.: You can takeover from actor 1, even when clients registered the object's owner as 0 (null is used for "the room", which is equivalent to "belongs to master client"). +Fixed: late joining would not be aware of ownership transfers. Now owner is matching who sends events. +Updated: The Photon "Demo Hub" to the new uGUI. Setup demos by "Window" -> "Photon Unity Networking" -> "Configure Demos (build setup)" to get all demos in a build. +Fixed: Chat and RPS demo when going back to the demo hub would throw errors, this is corrected now. +Fixed: PhotonViewInspector not setting target to dirty when editing ownershipTransfer +Changed: The "Background Thread" in PhotonHandler will only call SendAcksOnly(), if Update() didn't recently (last 200ms). This makes sure that timeouts are not affected by the background thread (which keeps the client side from timing out for a while). +Fixed: PhotonTransformView DoDrawEstimatedPositionError was not taking in consideration parenting. +Fixed: The RoomOptions.EmptyRoomTtl got set if only PlayerTtl was > 0. Now both values are fully independent. Note: To allow the last player to come back to a room after a disconnect, you need to define a EmptyRoomTtl. Else, the room gets cleared when the last player leaves or becomes inactive. +Updated: Api reference for FindFriends, AuthenticationValues. It should be clearer how the userId is set (and if the playerName gets used at all). +Fixed: An issue in NetworkingPeer.NewSceneLoaded(). It did not clean up correctly in v1.76 on loading scenes. +Updated: PhotonNetwork.BackgroundTimeout. It's now disconnecting (not timing out) and the doc got updated for that. + +v1.76 (21. September 2016) +Fixed: Compatibility with ".Net 2.0 Subset". This can be used again. +Updated: Some minor things to support Unity 5.5 beta. As always, this is work in progress. Let us know if you run into issues. +Fixed: Values in enum DisconnectCause are now assigned with the ones from the lower level StatusCode, so that the values make sense again. +Fixed: NetworkingPeer ReconnectAndJoin procedure by not cleaning up Ip Address on disconnection. +Added: RoomOptions EmptyRoomTtl are now available. You can set how long a room stays in Photon Server's memory before it's being cleaned up or saved/persisted. +Improved: Remove initial drifts on remote PhotonView transform values for ThirdPersonNetwork and PhotonTransformView components. When using these components, the first "life update" defines the position of a GO (instead of lerping there from the instantiate-position). +Updated: The Chat Demo. It has a new text-input command and shows channels and private conversations properly. +Updated: To Photon assemblies v4.1.1.3. which includes a fix for WSA builds. Also, only one WSA compatible dll is used across Windows Store exports (8.1 and 10). + +v1.75 (23. August 2016) +Fixed: The Photon assemblies (.dll) to support IPv6 correctly again. This was broken temporarily in v1.74. +Fixed: UWP assembly. It now contains Photon's Hashtable, as all other libraries do. This fixes Windows 10 UWP exports. +Changed: PhotonMessageInfo is now a struct (was a class). This is less garbage to collect. +Changed: Demo script "ColorPerPlayer" to use less resources. When entering a room, it ignores property-changes until an initial check is done "on join". +Changed: Internally, the ServerSettings class now contains a VoiceAppId field. This allows easier merging with PUN Voice. +Changed: Internally, OnSerializeRead() now re-uses a stream object and just applies new, incoming values to it. This saves a bit of garbage. +Fixed: Compatibility with Unity 5.4, where OnLevelWasLoaded is obsolete and SceneManagement.SceneManager.sceneLoaded should be used to register "on loaded" callbacks. +Updated: To Photon assemblies v4.1.1.1. + +v1.74 (15. August 2016) +Fixed: PUN+ is now compatible with Unity 4.x Free again and can export to iOS and Android as expected. If you have Unity 5.x or 4.x Mobile Pro, you were not affected. +Fixed: TCP Socket for Windows Store 8.1 and UWP. +Changed: Due to upcoming new encryption options, exports now must use API Compatibility Level ".Net 2.0" instead of ".Net 2.0 Subset". We hope this is a minor issue. Let us know if not. +Note: When the Bytecode Stripper fails, see the note above about Compatibility Level. +Added: Optimization if a observed component implements IPunObservable. If so, we use a shortcut to call OnPhotonSerializeView(). This can speed up observed component calling in PhotonViews. +Fixed: NetworkingPeer.HandleEventLeave() inactive state missing masterClient assignement during first leave call (A second leave call will be made after playerTtl expires). +Improved: DemoChat : Exposed FriendsList to the inspector to prevent hardcoded friends references, and allow for easier testing without code modification +Fixed: PhotonEditor.cs: Pun+ plugins libs paths discovery. For Unity 4.7.2, the wizard window detect PUN+ correctly again. +Internal: Changed the workflow for setting up protocols. One method aggregates this now. +Internal: NetworkingPeer.SetupProtocol(). Gets called before each PhotonPeer.Connect(). +Changed: PhotonNetwork constructor no longer sets protocols for special cases. +Updated: The IPhotonSocket implementations to set their "IPv6-resolved" state. +Updated: To new library build with new internal workflow for the "Init Request". +Improved: PhotonPlayer.cs: Implemented IComparable and IEquatable. +Fixed: NetworkingPeer.cs: Check for null view before adding view's GameObject. +Fixed: Room.ClearExpectedUsers() is now sending it's current, local "expected users" to update the server with "CAS" (Check and Swap). This gives the client an update when the values become valid (which updates the local cache after the roundtrip). +Added: link.xml file to preserve some classes from being stripped. This is in Assets\Photon Unity Networking\. +Changed: The name/string of the "OnPhotonInstantiate" callback is now cached once, instead of using enum.ToString() each time. This is a minor performance improvement. +Changed: The initial Dictionary size used in a PhotonView. This stores the the observed components and their methods to call. +Fixed: Compatibility with Unity 5.4 by not adding a MonoBehaviour as Component. Instead, a derived class is used. + +v1.73 (26. July 2016) +Changed: Some variable and field names. PeerState is now ClientState. +Renamed: mAppId is now simply AppId. mAppVersion is now AppVersion. +Renamed: networkingPeer.server is now networkingPeer.Server (uppercase, being public). +Replaced: Most checks of PhotonNetwork.connectionStateDetailed being PeerState.Joined (or not) with checking PhotonNetwork.inRoom. +Added: Regions to the PhotonServerSettings: "sa" South America (Sao Paulo), "usw" USA West (San Jos) and "cae" Canada East (Montreal). If you're using the "Best Region" setting, make sure to include/exclude them as needed. +Fixed: NetworkingPeer:SendMonoMessage() null check before sendmessage to a GameObject that could be null. +PunTurnManager API: + Changed: GetRemainingSeconds() becomes .RemainingSecondsInTurn + Changed: TurnDuration is now a float and defaults to 20 + Added: IsOver() properly implemented + Added: OnTurnTimeEnds interface callback properly implemented + Fixed: RpsCore edited to account for PunTurnManager api changes and additions. +Fixed: NetworkingPeer.RunViewUpdate(), which was sending messages, even if no new updates were written. This got introduced in v1.70 and caused more messages than necessary. + +v1.72 (22. June 2016) +Fixed: When the server address resolves to both, IPv6 and IPv4 addresses, the client will prefer IPv6, matching Apple's requirements. + +v1.71 (15. June 2016) +Fixed: Best Region is now working with IPv6 networks. (It's not supported for WebGL though) +Moved: PunTurnManager moved to UtilityScript folder for reusability when cleaning up demos. + +v1.70 (8. June 2016) +Changed: Serialization methods from MemoryStream to StreamBuffer. This is a light wrapper for a byte[] which provides access to this array. That was not allowed in the Windows Store compatible API. To update, just replace MemoryStream with StreamBuffer in your custom type serialization. +New: PUN Basics Tutorial, available within the Demo Hub. +Updated: Input for some demos now also works with controllers (RPGCamera, RPGMovement and JumpAndRunMovement support this now). +Fixed: Ownership of a PhotonView no longer gets updated when anyone (aside from the owner) sends updates for it. This could cause issues when the (new) owner of an object got outdated updates from another (older) owner. +Fixed: PhotonViewInspector. When ownership gets transferred for scene objects, this shows correctly in the inspector at runtime. +Fixed: PhotonAnimatorView. removed warning thrown during trigger caching checks. +Changed: Delta compression will now re-use some memory, which should be more effective. +Changed: Aggregation of internal OnPhotonSerializeView()-updates is more effective. More memory is being re-used. +Updated: To latest Photon3Unity3D.dll v4.1.0.5. It will no longer fail Windows Store Certification and has several improvements throughout. + +v1.69 (19. May 2016) +Updated: Rock Paper Scissors Demo Scene, featuring fixes for timing and turn management, and implementation of a progress bar to indicate timer +Updated: PUN+ native socket library for Unity 4.7 iOS to support IPv6. +Fixed: PhotonAnimatorView. Triggers now properly synchronized if set to "discrete" mode. + +v1.68 (3. May 2016) +Fixed: The "reset" action of a PhotonTransformView-inspector now works as expected and sets proper, useful default values. +Fixed: PhotonAnimatorView. Layers in Unity 4 where not counted properly, it now lists layers properly. +Fixed: Buffered RPCs can be removed (as expected) from the buffer with RemoveRPCs(). Affected versions were v1.66 and v1.67. Please update those. +Updated: The docs (.chm and .pdf). + +v1.67 (21. April 2016) +Fixed: PhotonAnimatorView, Triggers now supported +Added: PhotonAnimatorView, Live view in Inspector of current Values for parameters +Fixed: Photon Chat for WebGL export. It failed to compile because SocketWebTcp was not found. The PhotonChatApi folder now got moved from Assets\Plugins to Assets. +Changed: If sent by server, UserId and Nickname values are updated (with the server's values). This can be done with CustomAuthentication. All clients always get some UserId assigned by the server (if you didn't set one in the first place). +Added: "Slot Reservation" as feature for matchmaking. +Added: ExpectedUsers parameter in PhotonNetwork methods: CreateRoom, JoinRoom and JoinOrCreateRoom. +Added: Room.expectedUsers. List of users who are expected to join this room. In matchmaking these UserIDs block a slot out of the MaxPlayers. +Added: RoomOptions.publishUserId. This tells the server to publish the UserIds of players in a room. You can use those in FindFriends or when you join/create another room, to reserve slots for other players. +Added: PhotonPlayer.userId. If the server publishes the UserIds of players, you can access the UserId here while being in a room with others. +Internal: Added GamePropertyKey.ExpectedUsers (247) and ParameterCode.NickName (202). +Added: PhotonNetwork.StartRpcsAsCoroutine as optional performance improvement. If set to false, PUN will not attempt to start and RPCs as coroutine. While coroutines are efficient, starting them needlessly is not the best approach either. This defaults to true, which means RPC methods get started as coroutine, if they return IEnumerator. +Changed: Internal handling of RPC methods. Now their parameter list is being cached, instead being fetched every time we have to find an RPC. This uses a limited amount of memory to improve speed of RPCs. To do this elegantly, we extended MethodInfo with a GetCachedParemeters() method. +Changed: AccountService is now wrapped in "#if UNITY_EDITOR" to avoid export to any players. +Added: RoomOptions.PlayerTtl, which can be used when creating a room. If set, a player who disconnects becomes inactive for the defined time, instead of being removed from the players list. This allows the player to join a room. It blocks the player's slot in the room in matchmaking, too. +Added: PhotonPlayer.isInactive. If a Player Time To Live is set, players can become inactive in a room. The PhotonPlayer instance is still present, as if the player were connected. +Added: A client which lost connection, can now rejoin a room quite easily with PhotonNetwork.ReJoinRoom(string roomName). Important: To enable this, a room must have a PlayerTtl != 0 and the client which is rejoining, must use the same UserID as before. +Fixed: The State of a client when it fails to join/create a room on the Master Server. It's now set correctly to either PeerState.JoinedLobby or PeerState.ConnectedToMaster (depending on whether the client was in a lobby or not). +Fixed: The "Open Dashboard" button in the PUN Wizard, which was not working on OSx. +Updated: Usage of EditorUtility.SetDirty() and Undo.RecordObject() in Editor scripts according to Unity 5.3 changes. This should enable undo in most Inspector windows, too. +Changed: PhotonNetwork.BackgroundTimeout no longer calls Disconnect() directly. Instead a normal timeout period is granted after the BackgroundTimeout elapsed. PUN will use the common timeout callbacks (when the app gets active again). +Changed: PhotonNetwork.BackgroundTimeout now defaults to 60 seconds. This keeps all new apps from being connected for longer times in background but allows loading lots of assets and taking short calls, etc. +Changed: Usage of SupportClass is now SupportClassPun to avoid clashes with IL2CPP on some platforms. +Added: RoomOptions.plugins to define which server-side plugins are expected. This is a feature of the Enterprise Cloud and when using the Photon Server SDK (so it's not available in the Public Cloud). +Added: Handling of an "Info Event", which could be used by server-side plugins. EventCode.ErrorInfo is code 251 and PUN will call the delegate you defined in PhotonNetwork.OnEventCall (or log a warning that no delegate was set). This only applies to customized servers (not the Public Cloud). +Added: PhotonNetwork.ReconnectAndRejoin() to be used when a client loses connection while in a room (e.g. when you press the lock button on iOS and then return to the app). +Added: PhotonNetwork.Reconnect() to be used when a client lost connection. Use this only when your client was connected to a region or a game before (to get into the same region). +Fixed: A compile warning about Photon.MonoBehaviour.networkView "does not hide an inherited member" in Unity 5.3.4 and up. The old networking API of Unity is being removed, it seems. +Fixed: PhotonNetwork.time for offline mode. Internal: It now uses the Environment.TickCount, which is similar to the server's timestamps. All usage of time in PUN is now either based on PhotonNetwork.time or .ServerTimestamp. + +v1.66 (21. January 2016) +Important: This might affect your import! The folder "ChatApi" is now renamed to "PhotonChatApi". This way, the folder uses the same name as in our other packages. Remove the "ChatApi" folder, if the import didn't do that for you! +Added: Callback OnCustomAuthenticationResponse to make the data available, that could be sent by a custom authentication server. See description in PunBehaviour. +Fixed: Usage of "networkView" (old Unity Networking) to using photonView (PUN naming) in a script of the Boxes Demo. +Changed: The photonView in Photon.MonoBehaviour is now cached. If you intend to remove a PhotonView from a GameObject without destroying that object, you should modify this accordingly. +Changed: Internally, the PhotonStream now has a object[] for read values. This avoids wrapping them in a List, which saves memory and time. +Added: Support for Enum types in RPC methods. Enums that are based of byte, short or int can now be used as parameters in RPCs. The underlying type has to be serializable by PUN for that. +Internal: CheckTypeMatch() to match "assignable" types to enum values. This is what enables the support for using Enum types in RPCs as parameter. +Fixed: Several scripts in the Demo Synchronization. They now work more like you'd expect. The whole demo is refreshed to a more useful state. +Internal: Refactored RPCs and "Synchronization" updates to waste far less memory and perform better. For that, Hashtables were replaced with simpler object[]. This means, that this client version is completely incompatible with older ones. +Internal: The PhotonStream now has 3 values pre-set. Those are needed in the stream to be sent along with your custom values. This doesn't change anything usage-wise. It also has a object[] which is used for readin values and a List which is used when you write. This is leaner. +Internal: PhotonView.ExecuteComponentOnSerialize() now makes better use of its cache Dictionary. It fetches cached methods with TryFetchValue(), instead of checking for content, then accessing it. +Fixed: PhotonTransformView interpolation for "estimated speed". It was way too slow, because it didn't factor in that there are 10 updates per second. So speed as a value per second is 10 times higher. 10 being the default send rate here. Note that the object can overshoot (the actual position due to this and extrapolation). +Fixed: PhotonTransformView interpolation for "estimated speed" now avoids jitter when joining a game. The initial received position simply defines where the object is (after being instantiated at the position of it's Instantiate message). With the next update, it can begin to move. + +v1.65 (16. December 2015) +Fixed: Potential NullReference Exception when transfering ownership. The PhotonView which gets transfered might get destroyed before the transfer is complete and that case is now handled. +Fixed: PUN Wizard for Unity 5, which incorrectly pointed out that you need PUN+ to export to iOS or Android. This was the case in Unity 4 but it's no longer true. Removed this note. +Fixed: Automatic configuration of the demos, when you import PUN (with demos) into a new, empty project and have no saved (named) scene open. This is done once per Editor only. You can do this in the Editor Main Menu: Window, Photon Unity Networking, Configure Demos. +Fixed: Compatibility with Unity 5.3. The new SceneManager class is re-implemented for our needs for older Editors and the code got adjusted. No "obsolete" warnings anymore. +Added: Useful component to select a color per player (out of a configurable list of available colors). Check out: ColorPerPlayer. +Updated: Boxes Demo. This demo now uses the ColorPerPlayer and ColorPerPlayerApply scripts to colorize each player's cubes. Also, it shows more clearly how RPCs work. There are more tips at runtime, too. +Fixed: Friends And Custom Authentication Demo. A script was waiting for the client to join the lobby, which isn't done anymore by default. Now the UI is fixed to show when connected to the Master Server, where FindFriend() can be called. + +v1.64.2 (6. November 2015) +Fixed: SetCustomProperties in PhotonPlayer and Room classes. It applies set properties locally, unless you do a server-side Check and Swap with expected properties. It also does the callbacks as before (CAS delays the callback by one roundtrip, as the server sets it). In OfflineMode, CAS gets ignored but props stored. +Changed: The Mecanim Demo minimally with a new scene / meshes. + +v1.64 (5. November 2015) +Changed: Online docs are now generated with search enabled. +Changed: Some scripts in UtilityScripts to not use the PhotonNetwork.networkingPeer directly anymore. This improves compatibility when using PUN in UnityScript. +Added: Description how to use PUN from UnityScript. This is in the readme.txt. +Added: PhotonNetwork.ServerTimestamp to expose the low level, synced server timestamp. More doc and usage samples are upcoming. +Updated: SetCustomProperties() in Room and PhotonPlayer classes. There is now an option to "WebForward" the changes. You can setup a WebHook for this in the Cloud Dashboard (or server config). The parameter expectedProperties is still available (optional, too) to check some key-values before updating the properties. +Changed: SetCustomProperties() in Room and PhotonPlayer now update the locally cached Custom Properties, as if the client was online. Note: The callbacks (OnPhotonCustomRoomPropertiesChanged and OnPhotonPlayerPropertiesChanged, respectively) get called immediately by SetCustomProperties(). +Changed: PhotonTransformView*Control classes now also update their internally cached values when sending. When transferring ownership, this gives them a recent value as "last networked update", so smoothing and extrapolation works better. +Updated: To Photon3Unity3d.dll v4.0.0.12. + +v1.63 (27. October 2015) +Changed: The case "no match found" is now logged as Warning, instead of Error. This happens and it was confusing if you used "Break on Error" in the Editor. +Changed: OnMasterClientSwitched handler documentation to make it more clear if the master is still in list or already removed. +Fixed: 2D Demo. There was an issue with a missing script and the layers. The demo no longer relies on the Layers for the "isGorunded" check (as Layers are not existing in Asset Store Packages). +Fixed: A bug that prevented manually instantiated GameObjects (PhotonViews) from being cleaned up when a player leaves. Even if you manually instantiate GameObjects, they get cleaned up, as long as PhotonNetwork.autoCleanUpPlayerObjects is true. The doc is updated. +Changed: Several scripts in demos to handle PUN's both callbacks: OnJoinedLobby() and OnConnectedToMaster(). Which one gets called, depends on the "Auto-Join Lobby" setting in the PhotonServerSettings (default is off / OnConnectedToMaster()). +Updated: To latest Photon3Unity3d.dll v4.0.0.11p1. + +v1.62 (13. October 2015) +Fixed: Clean up of instantiated Game Objects (Clean Up Cache on Leave). This bug was only in v1.61. +Changed: PhotonView.OnDestroy() to not use Application.isLoadingLevel in Unity 5.2 (which makes it obsolete). Loading a level will destroy a GameObject without using PhotonNetwork.Destroy() and that can lead to errors. When loading a level that's ok. The logging got adjusted for this case. +Added: PhotonNetwork.BackgroundTimeout. It defines after how many seconds PUN will close a connection, when Unity called OnApplicationPause(true). By default, this is not active but on Android (e.g.), it can be useful to close a connection when the app is in background for a while. + +v1.61 (17. September 2015) +Added: Option to use an Object Pool. Implement IPunPrefabPool and assign it to PhotonNetwork.PrefabPool. Note: GameObjects will not run Awake() and Start() but PUN will call OnPhotonInstantiate() as if the GameObject would be new. +Changed: The internal state when PUN connected to the Master Server but did not yet authenticate. The server does not allow you to do requests before authenticate and the new state reflects this. This also affects connectedAndReady for that state. +Removed: Obsolete variants of methods: JoinRoom(), CreateRoom(). +Fixed: A bug with PhotonAnimatorView, which could cause exceptions when there was only 1 sample in a "continuous updates" message. +Fixed: Docs for codeAndMessage parameters. The error code is of short type, not int. This applies to some callbacks. Usually, this requires no code adjustments. +Fixed: An issue for AuthenticationValues.AuthType. If you used Object Initialization for this, some types could not be set due to a compiling issue. Now this is a property with a backup field and those work fine. +Changed: PhotonHandler is no longer a IPhotonPeerListener and does not implement those callbacks. They were empty, aside from DebugReturn(). This is now implemented by NetworkingPeer (too). +Updated: Photon assemblies to v4.0.0.11 with various fixes and enhancements. See release_history.txt. +Added: Better description to PhotonNetwork playerList and otherPlayers. +Changed: The Editor field ObservedComponentsFoldoutOpen for PhotonViews is now exclusively available in the Editor. It only stores if the Inspector should show the Observed list or fold it. +Internal: The NetworkingPeer now creates the base without a Listener and then assigns itself to make sure there is one. The externalListener is no longer needed. +Internal: Refactored a lot in classes NetworkingPeer and LoadBalancingPeer. The code is more like that of the LoadBalancing API now. + +v1.60 (30. July 2015) +Added: PhotonNetwork.EnableLobbyStatistics to enable/request statistics about lobbies and .LobbyStatistics as list of lobbies (available while on the Master Server). The list of lobbies is provided as a list of TypedLobbyInfo per lobby, which wraps room- and player-count per lobby (so you can find the active ones). +Added: Callback OnLobbyStatisticsUpdate(). Implement this to be notified when new lobby statistics become available (to update your UI, etc). +Added: PhotonNetwork.QuickResends, which controls a new feature. For reliable messages that got lost, the first few repeats can be done quicker. This improves connection reliability and reduces gaps in case of loss. Only up to 3 resends can be quick. Read the doc! +Changed: Some PhotonNetwork fields that didn't have to be public are now internal, as intended. +Updated: Api reference for PhotonNetwork.playerName, .SendMonoMessageTargetType and .automaticallySyncScene. Also for enum CloudRegionCode and ServerConnection and class WebRpcResponse. +Changed: PhotonNetwork.gameVersion is now a auto-property field (and no longer sets a private field). +Internal: Removed NetworkingPeer.mAppVersion. +Changed: Some "per project" settings are now being moved into the PhotonServerSettings file. Currently, this can be used to set: Auto-Join Lobby, Enable Lobby Stats +Changed: Order of updating internal values when joining a room. The actor list is now updated before we do callbacks. This clean up a reference to our local "dummy" player before we do the "joined" callback. +Fixed: The inspector no longer attempts to update a PhotonView "observed" field to a list while the game is running. This led to ArgumentOutOfRange exceptions (while inspecting at runtime). +Changed: The ChatGui class now contains a Instance field, which you could use from other scripts. It's supposed to be a singleton and to persist across loading levels (which is why it will apply DontDestroyOnLoad() to it's GameObject). +Changed: ChatGui now also disconnects when it's GameObject gets destroyed (OnDestroyed()). +Fixed: ConnectUsingSettings, ConnectToBestCloudServer and ConnectToRegion will only work while the client is not connected. In doubt, use Disconnect() first. +Changed: When the PhotonHandler gets destroyed, it now cleans up the background thread which usually keeps the connection. This hopefully avoids rare freezes of the Unity Editor when closing. +Changed: When switching the protocol, the networkingPeer is being replaced. Now we apply the previously set disconnect timeout to the new one. +Updated: To Photon Unity Assemblies v4.0.0.11. +Fixed: The logical order of assigning a player number when turning on OfflineMode. The callback OnConnectedToMaster be done with PhotonPlayer.ID being -1 but when you join or create a room, the client's PhotonPlayer.ID will be 1 in the callbacks. +Changed: WebGL WebSocket.jslib. The socket.onmessage is now using an arraybuffer to read messages. This should be leaner and is a workaround for infrequent long read-times in Chrome. +Skipped: v1.59 +Chat API: + Added: IChatClientListener.DebugReturn(). This is a breaking change, if you use the interface. Photon lib and chat client log via this method (no logging to console by default). + Changed: ChatClient.CustomAuthenticationValues is now .AuthValues. You can use those values to identify a user, even if you don't setup an external, custom authentication service. + Changed: ChatClient.UserId no longer directly stores the id but puts it into AuthValues. This means, the UserId could also be set via setting AuthValues. + Changed: The API of AuthenticationValues. There is now the UserId and AddAuthParameter() replaces the less general SetAuthParameters() (which only set specific key/values). + Note: All users should have a UserId. You can set chatClient.UserId before you connect, or you can set the AuthenticationValues in Connect(..., authValues) to set a UserId. + Added: ChatChannel.ToStringMessages(), which gets all messages in a single string, line by line. The format is "Sender:Message". + Added: ChatClient.TryGetChannel() to find a channel only by name, no matter if public or private. + +v1.58 (30. June 2015) +Fixed: Compile warning about last remaining reference to RPC attribute (in Unity 5.1) by suppressing the warning. This reference is only in the Editor scripts and works unless RPC gets removed. +Removed: Native socket libs from Unity 5 PUN+ package. The native libraries are no longer useful and keep us from supporting more platforms that are covered by Unity. Using the Socket class in C# is no longer a Unity-license problem. Download from the Asset Store with Unity 5.x to get this package. In Unity 4.x, you still get the Android and iOS (32bit and 64bit) libraries. + +v1.57 (22. June 2015) +Fixed: An issue with the RPC list update, which was still looking for the old RPC attribute. So when you switched over to PunRPC, the list was empty. +Added: Automatic check if the obsolete RPC attribute is in source, to offer an automatic conversion to the new PunRPC attribute. Conversion uses search and replace for [RPC] to [PunRPC] and @RPC to @PunRPC. +Added: PhotonNetwork.ConnectToRegion(), which enables you to connect to a specific region easily. This can be useful when you do your own region selection. +Note: Best Region selection won't work in WebGL exports currently. A fix needs updates on the server side and is in work. +Note: Chat API won't work in WebGL exports at the moment. Delete it from a project which targets WebGL. +Note: PUN+ does not support WebGL at the moment. It requires an update of the lower level APIs which we work on. Unity 5 can export PUN Free to all platforms, so use this as workaround. + +v1.56 (16. June 2015) +Changed: The RPC attribute is now replaced by PunRPC and no longer supported. Search and replace your code for [RPC] and replace it with [PunRPC]. The change is necessary, because the RPC attribute is obsolete in Unity 5.1 (which causes a large amount of warnings at compile time). + +v1.55 (12. June 2015) +Changed: PhotonNetwork.time so that it's always positive, even on iOS 64bit exports. Note: this time value does not start at 0 and it will "wrap around" from 4294967.295 to 0! Use with care - we will implement a better soltion asap. +Changed: ServerSettings.EnabledRegions (for "Best Region" Cloud hosting) now defaults to "all". The old default had the same effect but it was labelled as "none" of the regions (which is not allowed). +Fixed: Re-creation of the PhotonServerSettings file in case you deleted a duplicate. This always created a file in the default location. Now, it does not matter where the PhotonSettingsFile is: If you have one at least, it will be found. +Changed: AuthenticationValues now has a property UserId. You can set a UserId independent from the playerName now. This UserId should be unique per player and does not have to be readable. FindFriends will use this UserId (or one set by a Custom Auth Service). If you don't set it, PUN will use PhotonNetwork.playerName to identify a user. +Changed: AuthenticationValues now uses AddAuthParameter(key, value) to set parameters. Simply call it once for each parameter that your authentication service expects. Changed GUICustomAuth accordingly. + +v1.54 (3. June 2015) +Fixed: In Offline Mode, the NetworkingPeer.mMasterClientId always returns the local player ID. This fixes RPCs in offline mode targeted at the Master Client. +Fixed: WebGL support no longer breaks other platform exports. Download the package from the Asset Store with Unity 5 to get WebGL support (Unity 4 can't handle it). +Changed: WebSockets are now only used for the WebGL platform (in-editor and in export). You can't select WebSockets on any other platform (because we can't support the websocket-csharp.dll on each). +Added: When you select "Best Region" as Hosting Type (in PhotonServerSettings), you can now select the regions that are enabled. Deselect those you don't want to use and they are dropped from the list of available regions (in the client, obviously). +Changed: Setup Wizard. It's now considerably leaner. The idea is to improve the Inspector for the PhotonServerSettings some more. Working but also "Work in Progress". +Fixed: A bug when setting properties via SetCustomProperties(propertiesToSet, expectedValues). Those updates were not sent reliable, so they could get lost and de-sync with any clients. This only affects currently updated clients which used this new feature (since v1.52). Thanks, Lino. + +v1.53 (28. May 2015) +Fixed: Master Client selection for older servers (was broken in v1.52 only). Effectively, if the new features are not present on the server, we use the old client-side workflow. Photon OnPremise is still v3.x and the "Server Side Master Client" feature requires Photon v4. The public cloud servers support this feature already. +Fixed: NullreferenceException in extension method StripToStringKeys(). Extension-methods could be called on objects that are null. +Changed: PhotonPlayer.Find() now re-uses a method that implements finding a player in an effective way. +Changed: SetCustomProperties(propertiesToSet, expectedValues) now requires expectedValues and will not send anything if those are null or empty. Use SetCustomProperties(propertiesToSet) if you don't have props to check. +Changed: Internally used operation GetRegions will now log a warning if the AppId wasn't set. Then the client doesn't get a list of regions. +Fixed: An issue with TCP clients which would fail to connect again, after a disconnect. As before, you should use UDP as default, so most likely you were not affected. Fixed in the Photon3Unity3d.dll. + +v1.52 (22. May 2015) +Added: WebGL support! Select WebGL as export target and PUN will use a special library for WebSockets. This might have some kinks in the Editor-playmode but works well in JS/WebGL exports. Please report issues. Chat should also work with WebSocket. Both use WSS. +Added: Server Side Master Client control. The server now selects the Master Client and sends the current ID to everyone in a room. This is updated when the current master leaves and clients can override this and tell the server who should be the Master Client. This way, the server is authoritative and sending RPCs or events (RaiseEvent) to the MasterClient is deterministic. +Changed: In offline mode, PhotonNetwork.masterClient always return the local player. +Changed: PhotonNetwork.SetMasterClient(PhotonPlayer nextMaster) will attempt to set a new Master Client. It sends the client's current known Master Client and the switch will fail if that's not matching with the server's current Master Client (e.g. if someone else switches the Master Client concurrently). +Internal: Removed older code referring to a custom Master Client, as the server now is authoritative for the Master Client. This affected RpcSecure (e.g.). +Updated: Doc for PhotonNetwork.insideLobby, OnReceivedRoomListUpdate(), OnJoinedLobby() and more. +Added: GetNameServerAddress() which creates host address for Cloud including WebSockets. +Changed: NameServerAddress is now a property using GetNameServerAddress(). +Added: UNITY_WEBGL for RPC class. It's now compiled into WebGL, too. +Fixed: Visibility of OnPhotonSerializeView, according to IPunObservable. +Fixed: OnPhotonJoinRoomFailed callback did not provide the object[] parameter with the detailed cause for failing on the Master Server. Thanks, Chris. +Updated: Platform compilation for Unity 5. There is now a define for major number. As this was not present in early 5.0 versions, we now use: UNITY_5 || UNITY_5_0 +Fixed: PhotonNetwork.player.name now syncs the name with others while in a room. If the name changes, the setter simply sets the local value first, then PhotonNetwork.playerName (which syncs). +Added: PhotonNetwork.RemovePlayerCustomProperties() which must be used with care. It can clear custom properties you set in one room and don't want to use in the next but it won't sync changes. Read the summary and remarks. +Added: Optional caching of a PhotonView's MonoBehaviours for RPCs. This is off by default (as before) but can be enabled with PhotonNetwork.UseRpcMonoBehaviourCache. +Added: PhotonView.RefreshRpcMonoBehaviourCache() for manual refreshing of the PhotonView's MonoBehaviour cache. Only useful when PhotonNetwork.UseRpcMonoBehaviourCache is true. +Fixed: Potential NullReference Exception when a PhotonView has no ObservedComponents list. It can be null, if an existing view was never shown in Inspector. Thanks Don. +Fixed: Issue with PhotonNetwork.time. On 64bit builds and on Mac Editor, this was showing different values than on some other platforms. This should be fixed for Unity 5.0.2p1 and newer (some IL2CPP exports have bugs in EnvironmentTickCount). +Fixed: A special case when you return from a Demo to the Demo Hub, this will now Disconnect you, so the next demo will connect again. The "Return to Hub" button is bottom right in all demos. +Changed: Internally, an encrypted authentication-token by the Name Server is now used as shortcut for authentication on Master- and Game-Server (if available). +Changed: When joining/creating a room, the order of callbacks is now changed a bit. PUN first reads the player props (and calls OnPhotonPlayerPropertiesChanged) and then calls OnPhotonCustomRoomPropertiesChanged. Before, the order was room- then player-props. + +v1.51 (17. March 2015) +Updated: PUN+ with a new native socket lib for iOS 32bit and 64bit. Please note: You need Unity 4.6.3p2 (or newer) to successfully export PUN+ to iOS! Before that "Patch 2" release, the new export did not work with PUN+. +Fixed: PhotonAnimatorViewEditor for compatibility with Unity 5. Now Layers and Parameters can be configured as expected. +Changed: A PhotonView that is created manually (by AddComponent()) will not attempt to register itself with PUN's internal list. Its viewID is 0. When you assign an ID to photonView.viewID, then it will register itself and can be found in PhotonView.Find(id). Make sure your IDs don't clash with IDs used in PhotonViews in the scene (1..999). Best, use PhotonView.AllocateViewID(). +Removed: A debug log in PhotonNetwork.networkingPeer.RegisterPhotonView(view) when you attempt to re-register a PhotonView and it's already in the list. This special case does not need logging. +Updated: Several links to online docs, as the URLs changed. The basis is: http://doc.exitgames.com/en/pun +Updated: Doc of PhotonNetwork.RaiseEvent. The EventCallback description here was wrong. In the callback you get the ID of the PhotonPlayer who raised the event. It might be 0 for "done on behalf of the room". +Fixed: OnPhotonCreateRoomFailed gets the 2 extra parameters (return code and message) in all cases now. +Added: Initial implementation of "CAS for Properties". This allows "Check And Swap" for SetCustomProperties. This should be a nice tool when any client can change a value and you want to make sure only one will succeed (can be picking up a item, making a kill, etc). + +v1.50.3 (14. January 2015) +Fixed: Custom serialization with nested Protocol.Serialize() calls. The change in 1.50 to re-use a MemoryStream has unpredictable results in this case. + +v1.50.2 (13. January 2015) +Fixed: Arrays of Custom Types can be sent again. Serialization failed for (e.g.) Vector3[] and is now fixed. (This is a fix in: Assets\Plugins\Photon3Unity3D.dll and it's platform-specific variants). +Fixed: When leaving a room, GameObjects created by InstantiateSceneObject() will be cleaned up (destroyed). For this, the PhotonViews now have a new (internal!) value isRuntimeInstantiated. Objects loaded with the scene are not cleaned up (as before). +Fixed: Destroying a scene GameObject that was created by InstantiateSceneObject() will not cause joining clients to log an error. Only objects that were loaded with the scene get a buffered Destroy message (for joining clients which load the GO with the scene from disc). +Changed: NetworkingPeer.RemoveInstantiatedGO() now also finds disabled PhotonViews, which is cleaner for destroying the GOs. +Added: PhotonView.RpcSecure(). This variant gives you the OPTION to encrypt an RPC. You should use this rarely but in some cases it makes sense to send your data encrypted. Simply set the "encrypted" parameter to true to do. +Changed: Minor refactoring to avoid frequently creating objects. + +v1.50.1 (17. December 2014) +Fixed: JoinRandomRoom filtering with the expectedMaxPlayers parameter wasn't working properly. If you create rooms with different maxplayer value, you can now filter them as expected. +Fixed: PhotonPlayer could not be sent in RPCs or anywhere. It caused an exception "Exception: Serialization failed. Stream position corrupted.", even though you didn't do anything wrong. +Fixed: PhotonView.viewID initialization. This only affected cases where a PhotonView was added to a GameObject by code at runtime. This was causing multiple different errors. Now the default viewID is 0 as expected by PUN. Before a PhotonView is really usable, it must get a viewID which you generate/select via AllocateViewId(). + +v1.50 (10. December 2014) +Added: Chat Api and Chat Demo. The demo is just a basic UI which shows one option to handle input and commands. It should help you to use the very simple ChatClient functionality to build your own GUI for Chat. This can be combined easily with PUN but it's optional. +Added: Mecanim Support! There is a new component "PhotonAnimatorView" which can be used to synchronize the state of a Mecanim Animator. +Added: PhotonTransformView, PhotonRigidbodyView, PhotonRigidbody2DView. Each offers several options to smooth movement updates. Also check out their code as inspiration how you can implement your own. +Added: New Demos: Mecanim, RpgMovement and 2D Jump and Run. +Added: New feature: Ownership Transfer. +Added: PhotonView.RequestOwnership() and .TransferOwnership(). Per PhotonView you can define if it can be "taken" by anyone or if the owner gets a "request" to hand over control. A PhotonView can also be "Fixed" and not transfer control at all. This is set as OwnershipOption in Inspector. +Added: Callback OnOwnershipRequest() where a transfer could be executed (or rejected). For OwnershipOption.Request, this callback is called on the current owner of the PhotonView in question. It can TransferOwnership() but doesn't have to. +Note: Ownership Transfer would break if you set the transfer-option changes at runtime (as it's not synced). Due to that it's deactivated in Editor when playing. +Added: Events OwnershipTransfer and OwnershipRequest for internal use. +New: IPunObservable and IPunCallbacks define the callbacks of PUN to be easier implemented. +Added: Photon.PunBehaviour which implements all IPunCallbacks. If your scripts derive from this class, they can override the callback methods to implement them. This is easier to write as auto-completion in MonoDevelop and Visual Studio will support you. IPunObservable is not in PunBehaviour - OnPhotonSerializeView() is called too often to have it in all scripts. +Changed: The PhotonView component has now a list of observed components. You can observe one or multiple components per GameObject, which makes it easier to split tasks across some scripts. Of course you can still observe no script at all (if you use RPCs only on that PhotonView). Existing prefabs with PhotonViews are compatible and will be updated. +Changed: SendMonoMessage can now be limited to a specific Type. Instead of calling all MonoBehaviour, you could callback only on Photon.Monobehaviour. Set the Type via: PhotonNetwork.SendMonoMessageTargetType. By default, this is MonoBehaviour (as before). +Added: Option to cache the scripts that get PUN callbacks. With this caching, you can skip expensive FindObjectsOfType() calls when a callback is done. The drawback is that new components won't automatically get the callbacks! They could miss something unless you refresh the caching. Use with care. +Fixed: Issues with RoomOptions when using Object Initializer syntax. For example "new RoomOptions() { isVisible = false };" now actually sets isVisible of the room. We found this is a known issue in Unity, es discussed here: http://tinyurl.com/pnxrc8r . +Added: PhotonNetwork.AllocateSceneViewID() to be able to allocate scene view IDs. Only allowed for a Master Client. +Added: In offline mode, RPCs that are sent to AllViaServer and AllBufferedViaServer will execute locally (immediately). The RPC method will be called in the same frame. Before this, the RPC wasn't called in offline mode for those two settings. +Fixed: Assignment of minimum ViewId for scenes in Editor. The Application.loadedLevelName is not correct in that case, so better use EditorApplication.currentScene to get the name in Editor. Thanks to paulusul from the forum. +Changed: The PhotonNetwork constructor creates a NetworkingPeer based on protocol of server settings. This avoids creating another networking peer, unless you deliberately switch protocol. Debug Level and other settings won't be lost due to SwitchProtocol. +Updated: The Demo for Custom Authentication and Find Friends. It should be a bit easier to use and digest. +Changed: PhotonViewHandler now assigns a ViewID and InstantiationId to views (was using a "SubId"). Scene objects get the same InstantiationId for all views. +Removed: NetworkingPeer.instantiatedObjects. PhotonViews are enough to access all instantiated game objects (even including scene objects). Adjusted NetworkingPeer.LocalCleanupAnythingInstantiated(), .DoInstantiate() and .DestroyPlayerObjects() and PhotonView.OnDestroy() accordingly. +Changed: NetworkingPeer.RemoveInstantiatedGO() to use the creator's ActorNr when cleaning up the Instantiate events. +Changed: ServerCleanInstantiateAndDestroy(). As scene objects are not created via buffered "Instantiate" events, a "Destroy" has to be buffered instead. This is now done automatically. Destroyed scene objects will be destroyed when a player joins late. Also ServerCleanInstantiateAndDestroy() now expects the creator's ActorNr to remove Instantiate events from the server's buffer. +Changed: PhotonView.isSceneView now checks if the creator of an object is 0 (scene). Previously the owner was checked but this can change now. +Changed: PhotonView.isMine now checks ownerId first. On the Master Client, isMine is also true if isOwnerActive is false! This way, abandoned and scene objects fall to the Master Client. +Changed: PhotonView.isOwnerActive checks if the owner is 0 (scene). If so, the owner is never active. This is just a shortcut. +Added: SupportLogger now logs Game Server address when entering a room. +Changed: Some of the internally used classes are now wrapped in a namespace to avoid clashes with other products. + + +v1.28.2 (13. October 2014) +Fixed: PUN now loads the new PunSceneSettingsFile no matter where it is in the project. It can be relocated but it gets by default created next to the PunSceneSettings.cs. +Updated: Included .chm and .pdf documentation files. + +v1.28.1 (26. September 2014) +Fixed: PhotonViewID assignment. This got broken in a subtle way when we added the PunSceneSettings file. Please update. For each scene with any PhotonView in, edit at least one PhotonView.viewID in the inspector and save the scene. + +v1.28 (23. September 2014) +Changed: Compile conditions for WII U should work now! The demos don't run out of the box on Wii U though. You need to adjust some screen settings to get the GUI and input right. +Changed: Ping on native platforms does not disconnect PUN anymore. +Updated: FindFriends documentation. +Added: PunSceneSettings. This allows you to define the minimum value for ViewIDs per scene-file name. This helps to avoid clashes between ViewIDs when switching scenes or loading multiple incrementally. A PunSceneSettingsFile is created and only used in the Editor. Add names of scenes and their minimum ViewID value. Any scene that is not entered, begins at 0. You must edit at any PhotonView in each scene to correct the scene-views! Save the scenes. +Updated: To library v4.0.0.5 which fixes a problem with CRC Checking and reduces the amount of logging it does. See details in the separate release history file. + +v1.27 (15. September 2014) +Updated: Chat can now be used with PUN+ (after a Chat API update)! Updated assemblies and native plugins for PUN+. +Added: ServerSettings for PUN+ will not allow you to use TCP. PUN+ uses reliable UDP. Added a note about this fact in the inspector for ServerSettings files. +Added: When switching the protocol for self-hosted server in ServerSettings, the port is switched to fit the new protocol, unless it was a custom port already. +Fixed: Issue with "Best Region" hosting option and wrong AppIds. In this case, we now disconnect and call OnFailedToConnectToPhoton(DisconnectCause.InvalidAuthentication) and disconnect. Also, no pinging is done in this error case. +Changed: When calling Connect*(null), the PhotonNetwork.gameVersion is not changed. You could set it once in a project and leave it alone in Connect*(). +Added: PhotonNetwork.gameVersion caches the game version that gets set via any of the Connect-methods. This can be useful when a client needs to re-connect. +Internal: The two internal cleanup methods LeftRoomCleanup() and LeftLobbyCleanup() are no longer called from various places but only on disconnect (which happens when you leave a room, too) and LeaveLobby(). This is cleaner internally. +Added: OnConnectionFail callback with the case DisconnectCause.AuthenticationTicketExpired. This is a rare disconnect cause which usually means our server's timing is mixed up or your client uses a very (!) old authentication ticket. Handle this by connecting again (which will do a fresh authenticate). +Changed: The callback OnPhotonInstantiate is now called via GameObject.SendMessage() like any other callback (as listed by enum PhotonNetworkingMessage). OnPhotonInstantiate can be a coroutine. If your implementation has 0 parameters it will be fine, too. +Updated: To latest Photon Unity dll v4.0.0.3. This now tries to tell the server when the client timed out (used in counters to analyze issues) and it uses a newer native-socket-api. This is incompatible with older libs in Assets\Plugins\Android and Assets\Plugins\iOS! Update all when you use PUN+. + +v1.26.1 (11. August 2014) +Fixed: Nullreference Exception on import (due to ServerSettings RPC List). + +v1.26 (11. August 2014) +Added: Demo Pickup! Simple soltion for picking up items in a game. It also has Teams and Scores per player. Some of it is "work in progress" but it should give you a base to extend. +Changed: PUN now uses Photon's "Name Server". Per AppId and region, it returns the Master Server's address to use. This allows us to dynamically move games if we have to. +Changed: Best Region selection. It should now be supported on all platforms that PUN runs on, too. +Changed: NetworkingPeer.AvailableRegions is now a List. It can be populated when connected to the NameServer. When the list is available PUN can send pings to each server and find the best. +Added: Enum CloudRegionCode to be used for Regions. This defines the regions typically available and "none", if no region was set. It's no longer just a string (but we do use the value's name). +Added: Hosting type "BestRegion" which makes the client ping available regions one time and then store the best in the PlayerPrefs. Wait time is minimized that way. +Changed: PhotonNetwork.Friends is now updated when the server's response becomes available (not on request). This avoids cases where the friends are offline for the moment between requesting the update and getting it. Initially, it is null as before. +Changed: PhotonNetwork.Friends is now a List. When you fetch your friend's info, PUN will keep the current list until it got the reply from Photon, then it will replace the current list completely. If you fragment your friend list (because it's very long), you should take care of storing partial updates into some "complete" list yourself. Still, FindFriends blocks further requests until the response is read. +Fixed: Initialization for Room.autoCleanUpField which has to be false by default, even if a PhotonNetwork.autoCleanUpPlayerObjects is true. It defaults to false unless explicitly set to true per room. In v1.25, this could make clients clean up, even if the room-setting (set by just one user) was false. +Fixed: A wrong internal state which treats the initial connect differently to provide help in the logs. +Fixed: How PUN internally re-connects from the new NameServer to connect to the assigend Master Server. As the new technique is not yet used, this did only affect a few select clients. +Changed: Enabled a shortcut for authentication. A server might now summarize our initial authenticate into an encrypted secret for the client. If that's available, the client can send this instead of encrypting the original values again. This speeds up connecting minimally. +Internal: Updated some constants and descriptions. +Added: PhotonHandler.AppQuits which is set in OnApplicationQuit. Helps PUN with app-quits where we never want to re-connect (not even by a clever re-connect script). +Changed: Connect*() will check of AppQuits is true and skips connecting if so. +Changed: PhotonHandler has a OnApplicationQuit() method which will always immediately stop all Threads of PUN. This stabilizes some issues we had in the Editor. +Fixed: LobbyType enum had a wrong value for Default Lobby. If you wanted to create multiple, named lobbies that behave like the default lobby, the server wouldn't provide you room lists as expected. This is now working. +Updated: Description how to redeem a PUN+ code in readme.txt. +Added: OnJoinedInstantiate script (in UtilityScripts folder) for easy-peasy instantiation of prefabs on join (common task). +Added: Interface IPunObservable as definition of OnPhotonSerializeView with parameters. Refer to enum PhotonNetworkingMessage and it's values to find the callbacks PUN uses! They are described and you get an example how to use them. +Added: PhotonPlayer.GetNext() and .GetNextFor() methods. Those are useful when you want to find the next best player, in relation to another. The one that's next after the Master Client or after yourself. +Added: PhotonPlayer.TagObject. It could be used to keep any object which you need in relation to a player. This is not synced automatically! You have to setup relations manually. +Added: PhotonPing class as base for different ping implementations. +Changed: Photon.MonoBehaviour now explicitly ExitGames.Client.Photon.Hashtable. +Internal: PhotonHandler now does some of the work that PingCloudRegions did before. That was a separate Component which is no longer needed really. +Internal: PhotonPingManager uses the new PhotonPing class to ping regions several times. Each region gets it's average ping time set. +Added: Support for Photon Cloud "Region Pinging" on Windows 8 Store, Windows 8 Phone and Linux. +Internal: PhotonHandler disconnect from NameServer when pinging. This avoids threading issues in native lib. +Changed: ConnectToBestCloudServer() is now in all platforms (but not sure if it works). +Added: PlayerScores script. Really just a few extensions to the PhotonPlayer actually. +Added: Sample script that turns a pickup into scores. Implements another event method. +Changed: All demo GUI is now in a separate script. This is like in a proper game or another GUI. +Changed: Due to GUI being somewhere else, access to scores and teams got adjusted slightly. +Added: Drop(pos) for PickupItem. This allows you to drop an item anywhere! Yay! +Added: PickupItemSyncer script which is a temporary solution for sending the pickup item state to incoming players. At the moment, we don't guarantee it's 100% working but you get the idea and can adjust the thing. If no players can join while things are picked up, then this script is not needed. +Note: The PickupItemSyncer is known to be slightly imperfect. There are rare conditions when a player joins and the state is not synced correctly. We are working on a server-side solution, so this is a) temporary and b) an idea how to solve things right now. +Updated: Settings inspector. Options are per hosting type. Added protocol. +Updated: Wizard accordingly. +Changed: For settings, the server address does not have to contain a port. Using defaults. +Added: NetworkingPeer.ProtocolToNameServerPort and made use of it. +Added: Pickup Demo to Hub and pun-demo-build setup. +Fixed: In offline mode, Room.SetCustomProperties and PhotonPlayer.SetCustomProperties will not axctually try to send the properties. Instead, they are updated locally and the callback get called (See PhotonNetworkingMessage.OnPhotonPlayerPropertiesChanged and PhotonNetworkingMessage.OnPhotonCustomRoomPropertiesChanged). +Changed: OfflineMode now uses an internal Room instance which is created in JoinRoom or CreateRoom and set to null on LeaveRoom, Disconnect and when you set offlineMode = false. It can be used to store properties (only locally!). +Added: PhotonNetwork.SetReceivingEnabled(int[] enableGroups, int[] disableGroups) to change multiple interest groups in one call. +Added: PhotonNetwork.SetSendingEnabled(int[] enableGroups, int[] disableGroups) to change multiple interest groups in one call. +Added: Extensions for handling active and SetActive independent of Unity-version. This makes our demos compatible with Unity 3.5.7 and up without using absolete code. +Added: Ability to send WebRPCs. Check out PhotonNetwork.WebRpc method. +Added: Class WebRpcResponse (in file PhotonClasses). +Added: Callback OnWebRpcResponse (see: PhotonNetworkingMessage.OnWebRpcResponse for details). +Added: Error messages on-screen in the "Worker Demo" menu. When CreateRoom, JoinRoom or JoinRandomRoom fail, there is a temporary notice. Not beautiful but you get the idea. +Added: ShowInfoOfPlayer component (in UtilityScripts folder). It's an example how to display the owner's name of networked GameObjects (those with PhotonView). Note that the owner might be "" if you don't set a PhotonNetwork.playerName. Best set it before/at connect. +Added: SupportLogger component (in UtilityScripts folder). Attach to any GameObject in a start scene and it will vital values we need when you have support-questions about your subscription, your CCU usage, etc. We might ask you to run your game with this script. Send the log or at least the output starting with "SupportLogger Info" in doubt. +Added: InRoomRoundTimer component (again: in UtilityScripts folder). It is a simple synchronized timer for rounds. Players who join late can still count down to the end of a round, etc. Check out the code and usage and you should be able to implement state changes on top of this. +Added: ErrorCode.WebHookCallFailed (32752). This can happen when you accidentally use a Turnbased or Chat ApplicationId. It just makes sense to know and maybe check AppID. +Added: LogError for Operations that failed in a WebHook or Server Plugin. This should make it relatively easy to spot situations where an AppId is misconfigured on the server. +Added: Optional object[] parameter for OnPhotonRandomJoinFailed, OnPhotonJoinRoomFailed and OnPhotonCreateRoomFailed. It makes debugging easier. When your callback has this parameter, you get ErrorCode and the debug message. You don't have to implement this new parameter though. It's only interesting in a few cases. +Changed: RaiseEvent can now send events with code 0..199. They also get dispatched when you registered a OnEventCall. Before, eventCode had to be 1 and up which was a unnecessary limitation. +Added: Description for all RoomOptions. +Changed: The RPC-List is now sorted when new ones are added. On refresh, the whole list is sorted, which is more likely to be the same across Editors. +Added: HashCode for RPC-List so you can (more easily) compare them across Editors. +Added: Commented-out potential solution for OfflineMode RPCs which go to all via server. +Updated: Reference documentation. PhotonNetworkingMessage is now well documented, PhotonView.RPC and some others are improved. Also the organization of "General" topics is improved. +Changed: When setting offlineMode to true, PUN now directly calls OnConnectedToMaster. This is the same workflow as if you go online but not into a lobby. There won't be any room-listing in offlineMode, so this hopefully makes sense. +Updated: To latest Photon Unity dll v4.0.0.2. + +v1.25.2 (03. April 2014) +Fixed: ConnectToBestRegion now sets the found best region's address and automatically return to it when leaving a room. This fixes an issue where the server's address becomes empty. +Added: Option to switch protocol while offline: SwitchToProtocol(ConnectionProtocol cp) + +v1.25.1 (26. March 2014) +Fixed: Custom Authentication was failing in v1.25. This version is again compatible with the currently deployed servers in the Photon Cloud. +Note: This version is compatible with v1.25 clients, so no new versionPUN string. + +v1.25 (25. March 2014) +Fixed: Coroutines (IENumerators) are now called via their own script instance instead of the PhotonHandler monobehaviour. This fixes an issue where the IENumerators would continue running even after the script was destroyed. +Fixed: The Demo Worker controller no longer makes the character shake wildly when colliding with others. It was some issue with the grounded flag. This makes movement finally smooth-ish. +Changed: When using JoinRoom with the option to create a room (on demand), it will call OnJoinedRoom in all cases. It will call OnCreatedRoom (only) if it actually created the room. +Changed: PingCloudRegions no longer needs the Socket class. It checks for IPv4 addresses (which we prefer over IPv6 ones) by looking up a '.' in the address. This makes it usable in PUN+. +Changed: NetworkingPeer constructor will set a SocketImplementation when the "no-socket" (PUN+) assembly is in the project. This allows the same code to run with either PUN Free or PUN+. +Changed: The "player comparisons" to check for same ID, not same object (just a bit cheaper). +Removed: Some surplus debug logs from PUN. +Updated: Compatibility with Unity 4 by working around some features that are obselete (but needed in Unity 3.5). +Internal: Renamed AuthValues to CustomAuthenticationValues. +Changed: PeerState (in Enums.cs) no longer has a Connecting and Connected value. Instead we use ConnectingTo*server. Also gone: ConnectedComingFromGameserver. New: ConnectingToNameServer and ConnectedToNameServer. +Changed: In OfflineMode, the PhotonNetwork.connectionStateDetailed is now PeerState.ConnectedToMaster and PeerState.Joined when in a Room (after join, before leave). Before it was: "Connected". +Added: Compatibility with "NameServer", which will be contacted by clients to find a suitable MasterServer. This will allow the Photon Cloud to dynamically put applications on separate MasterServers. Self-hosted Photon instances will not have a NameServer soon, so this step is optional. +Added: PhotonNetwork.UseNameServer, which is false by default for now. It activates using the NameServer for ConnectUsingSetting(). +Added: Internally used NetworkingPeer.GetRegions method. It gets a list of regions from the NameServer (to be able to ping them). NetworkingPeer.AvailableRegions and .AvailableRegionsServers will store the result of that. +Added: PhotonNetwork.Server. The ServerConnection enum lets you know which type of server the client is connected to. +Changed: PhotonNetwork.Connect is now .ConnectToMaster and explicitly skips the NameServer to connect to a specific address. +Changed: Internal code of PhotonNetwork and NetworkingPeer due to some refactoring and the new states needed for NameServer. +Added: PhotonNetwork.JoinLobby and PhotonNetwork.LeaveLobby, which were lpong overdue to leave/join the lobby on demand. Make use of PhotonNetwork.autoJoinLobby, too! +Fixed: When authentication failed, the state Disconnected could not be reached and the client could not re-connect anymore. It could get stuck being 'Disconnecting'. +Changed: PingCloudRegions according to changes with connect process and using settings. +Changed: PhotonNetwork.connected is now true even while the client is switching servers! Only if you are disconnected or not yet connected, this is false. This should be what you want to know in most cases, when you just need a "yes/no". +Added: PhotonNetwork.connecting which is true until you successfully connected to any Photon server when you called ConnectUsingSetting (or one of it's alternatives). +Added: PhotonNetwork.connectedAndReady which is true when you can call operations like Join, Leave, etc. Note: You can call most operations only on a specific type of server, so even when connectedAndReady is true, you can't call Join while in a room on the GameServer. +Changed: PhotonNetwork.countOfRooms is always returning the statistic value we get from the Master Server (before: it returned the number of listed rooms in lobby). +Added: OnFailedToConnectToPhoton(DisconnectCause cause) is now also called when the AppId wasn't ok. DisconnectCause is then: InvalidAuthentication. +Changed: PunStartup script will do a "demo setup" only once in any Editor, saving the success in EditorPrefs. Still, it only runs if no (saved) scene was loaded and the build-setup is empty. If so, we load the hub scene and setup the build settings, so you can test all demos. This should be less annoying than before. If you don't want this at all: Delete PunStartup.cs. +Changed: The "Windows" menu "Photon Unity Networking" is now a submenu. This allows you to setup your project build settings and open the "Hub Scene" anytime you want. The PUN Wizard is also still opened from here (or ALT+p). +Changed: The callback OnPhotonPlayerPropertiesChanged now has an object[] as parameter! This way, we can also give you the properties that were changed. Due to limitations in GameObject.SendMessage, we are using a object[] instead of two parameters. Please adjust your code accordingly. If you implemented this method, it will now break until you fix it. See description in Enums.cs, enum PhotonNetworkingMessage, OnPhotonPlayerPropertiesChanged. +Changed: The callback OnPhotonCustomRoomPropertiesChanged now has an optional parameter: Hashtable propsThatChanged which contains the key-values that you set by calling SetCustomProperties. If you implemented this method before, it will still be called but without the new propsThatChanged (obviously). +Internal: When destroying a GO locally, we don't check for a valid instantiationID anymore. This improves the cleanup. Changed in RemoveInstantiatedGO. +Changed: Instantiate will now check if you are in a room and fail if you are not. In offline mode, you can also "join" a room. The reason for this check: Anything instantiated outside of a room is not going to by synced later on or might even conflict with networked objects in the room. The bool value PhotonNetwork.InstantiateInRoomOnly can be set to false, to skip this check. +Internal: Private method VerifyCanUseNetwork is simpler now. The property connected checks everything that was (also) checked in VerifyCanUseNetwork. +Added: New value PingCloudServersOnAwake to PhotonServerSettings. Only if this is true, a client will automatically ping our Photon Cloud regions on start and find the best regions (even before you call PhotonNetwork.ConnectToBestCloudServer). The result is saved in a player preference but not used when the client connects to a specific region anyways. Due to that, the default setting is now "disabled" (false). ConnectToBestCloudServer will simply start pinging when you need it. +Changed: Many PhotonNetwork methods now return a bool which tells you if the action (Photon-term: operation) will be send or not. A returned true value usually only means that some operation was sent to the server and doesn't guarantee that it will be executed successfully on that machine. So: Callbacks are as important as before but you can detect more easily if you (e.g.) tried to JoinRandomRoom when you actually can't at that moment. PhotonNetwork.connectedAndReady can be checked before you simply try to send operations. +Changed: PhotonNetwork.Destroy to enable you to destroy GameObjects while not in a room. By default GameObjects of one room get destroyed when you leave it. Useful if you disabled autoCleanUpPlayerObjects. +Added: PhotonNetwork.CrcCheckEnabled and PhotonNetwork.PacketLossByCrcCheck. The first makes PUN use a CRC checksum per package, which is overhead but adds security against broken datagram data. The latter counts how many packages this client got and rejected, because the content-checksum wasn't correct. This prevents issues in some cases, where hardware or software errors corrupt UDP data coming from the server to the client. You can switch while not connected and the server will also check a CRC (but you can't get access the counter for packages dropped by server). +Added: PhotonNetwork.MaxResendsBeforeDisconnect. Defines the number of times a reliable message can be resent before not getting an ACK for it will trigger a disconnect. Default: 5. It's limited to 10 but you should not really need to go higher than 6. +Added: Initial support for RaiseEvent. This offers something similar to RPCs but is independent of PhotonViews. The events only contain what you send! To get those events, you need to register a callback method (it's not using SendMessage). Some advanced features are not yet exposed fully (like Interest Groups). +Added: Documentation of PhotonTargets values (used in RPCs). +Added: New options for RPCs. When you want all clients to execute an RPC, it's usually sent to everyone else and executed locally instantly. With PhotonTargets.AllViaServer you can actually send the RPC to yourself through the server. This makes sure that those RPCs are executed in the same order on all clients. It's the order in which they arrive on the server (which is still depending on timing and ping, of course). This also works with buffered events. You should use this where needed only, as it causes extra traffic. +Added: "Typed Lobby" and "SQL Lobby" support. You can now create multiple lobbies and split room-listings according to your own needs. The default lobby (empty name and type "default") still works as before. +Note: The lobby type defines how a lobby behaves and which options it provides. There are only 2 types currently. The new SQL-Lobby provides more options for filtering in JoinRandomRoom. The "default lobby type" is what was used so far and works with a Hashtable of key-values that a room must match. +Changed: PUN will now store the lobby that is in use or was used last as PhotonNetwork.lobby. If you join a lobby "map1" and create a room, this room usually gets attached to the "map1"-lobby (unless you call CreateRoom with another lobby). PhotonNetwork.lobby can have a value, even if you are not joined/active in a lobby! It only changes when you set PhotonNetwork.lobby directly or use JoinLobby(typedLobby). +Added: Parameter "typedLobby" to JoinLobby, JoinRandomRoom and CreateRoom. If this parameter is null, the current lobby is not changed. If you never used any lobby explicitly, then the default lobby is used. +Added: Classes TypedLobby (a combination of lobby name and lobby type) and enum LobbyType, which contains the two currently possible types. TypedLobby.Default points to the default lobby (no name, default-type). +Added: JoinRandomRoom has a new parameter sqlLobbyFilter. This parameter is a sql-like string which allows more fine grained filtering with pre-defined properties. +Changed: When autoJoinLobby is used, it will now return to the lobby that was used last (for creating or joining a room). Of course, this joins the default lobby as before, if no other lobby was used explicitly. +Added: PhotonNetwork.OnEventCall to get a callback when your custom events are received and executed. Custom event codes must be below 200. Implement your method as EventCallback delegate. +Added: New class RoomOptions. This wraps up some of the options that a room commonly needs to be set. Visible, closed, MaxPlayers and some others no longer need to be individual parameters of CreateRoom and JoinOrCreateRoom. +Changed: JoinRoom(name, createIfNotExists) is now JoinOrCreateRoom(string roomName, RoomOptions options, TypedLobby lobby). The "createIfNotExists" is set implicitly and you now have the room options and can set a lobby. The latter 2 parameters are used only if you create a new game! This means: Only player ID 1 sets room props with JoinOrCreateRoom (player 2 and up just join). +Changed: If you set automaticallySyncScene = true and call PhotonNetwork.LoadLevel on the Master Client, PUN syncs the level-id before loading the level locally. If loading takes a while, you might notice that everyone else starts loading a bit earlier. +Added: Documentation as Compiled HTML Help (.chm) as well. The PDF might be removed in later updates. + + +v1.24 (18. October 2013) +Changed: CustomTypes is now endianness independent and also streamlined +Added: New synchronization mode "Unreliable On Change". It's basically a mixed mode which uses unreliable when things change. When the data doesn't change, it's sent a last time in a reliable mode, so everyone gets the final state for sure. Then, similar updates will be skipped. This can be applied to anything observed: Transforms, Rigidbodies and even scripts. +Changed: The new "Unreliable On Change" observe mode is the default for any new PhotonView. Existing PhotonViews on prefabs are not changed but you might consider doing this for objects that might stop moving / change. +Added: New internal values for PhotonViews. +Added: JoinRoom option to create a room if it doesn't exist currently. +Changed: JoinRoom calls OnCreatedRoom() if the room was created due to JoinRoom() option "createIfNotExists" +Added: Room.SetPropertiesListedInLobby() to set the list of properties sent to a lobby. This is useful when createIfNotExists creates a new room and you want specific properties shown in the room listing. +Changed: PingCloudRegions and RPC class conditional compilation to: #if !(UNITY_WINRT || UNITY_WP8 || UNITY_PS3 || UNITY_WIIU) +Updated: To new Photon assembly v3.2.2.1. + +v1.23.1 (7. October 2013) +Fixed: PhotonHandler nullreference crash on mobiles when using offlinemode +Change: PingCloudRegions.closestRegion is now public so that the developer can check this and possibly limit the amount of used regions (useful when not enough players) +Fixed: issue with Editor input fields (in wizard) which didn't repaint unless focus was changed +Added: Note how to get rid of auto-setup and loading of the hub scene. + +v1.23 (27. September 2013) +Changed: Unity 3.5.7 is the lowest supported Unity version (again)! +Changed: The Windows Store and Windows 8 Phone libraries are now hidden from Unity 3.5 in a unitypackage. They will automatically unpack in Unity 4.2 to get available seamlessly. +Updated: To new Photon dlls: v3.2.2.0. These contain a lot of changes and updates. +Changed: NetworkingPeer.SendMonoMessage() to optionally just use a list of GameObjects as target of PUN callbacks: PhotonNetwork.SendMonoMessageTargets. That saves performance and FindObjectsOfType() calls at the cost of maintaining the list manually. +Added: PhotonNetwork.SendMonoMessageTargets and description. +Updated: Demo Synchronization + Fixed: Issue with Lerp interpolation + Added: Explanation (a.k.a. comments) of what we do how and why in CubeLerp.cs +PUN Plus Only + Added: PUN+ check and property "isPunPlus" in PhotonEditor. + Added: PUN+ note in Wizard that export to mobiles will be done with native sockets. + +v1.22.3 (6. September 2013) +Note: This is a minor update improving connection-stability when loading stuff or grabbing the player-window by it's title bar for a while. +Changed: PhotonHandler now always runs a background thread to keep a connection alive - no matter if loading assets or not. This makes the connection less dependent on the engine's Update calls. Check PhotonHandler methods StartFallbackSendAckThread, StopFallbackSendAckThread and FallbackSendAckThread if you need control over this or the Thread gets in your way. It should not bother you usually. +Changed: Due to the new background Thread, PhotonNetwork.isMessageQueueRunning only controls if incoming messages are dispatched (executed) and if this client creates new updates for the other clients and sends them (while IsMessageQueueRunning == false, the OnPhotonSerializeView calls are paused and nothing is sent by a client). +Added: description of PhotonView.isSceneView +Changed: Internally, the editor script to add demos to the build is more flexible. Adding new stuff is easier for us. + +v1.22.1 (13. August 2013) +Fixed: M2H Demos. They were missing a change from callback OnReceivedRoomList() to OnReceivedRoomListUpdate(). +Removed: PhotonServerSettings.asset which contained an appid. Will be disabled soon. +Changed: Worker Demo now has two scenes and uses PhotonNetwork.LoadLevel(). Mind the PhotonNetwork.automaticallySyncScene = true in Awake() to enable this feature! +Changed: Description in Hub scene minimally. +Changed: InRoomChat to have a "Send" button, as mobile clients (e.g.) don't have a proper "enter". (Despite this, the Demos are not optimized for mobile) + +v1.22 (08. August 2013) +Added: Windows 8 Store and Windows Phone 8 support! +Note: In the player settings are checkboxes for all kinds of rights: Check "Internet Client". +Note: Build "D3D C# solution", not XAML. +Note: Before you update an existing project, delete PUN's "library" folder which contains Photon3DotNet.dll. This package has new libs in the "Plugins" folder in the root of the project. +Note: Ping does not yet work on Win 8, so ConnectBestRegion is not usable on those platforms. PingCloudRegions is excluded from those builds. +Changed: Windows 8 RT and Phone no longer support the standard Hashtable class, so we replaced it. PUN now uses Photon.Hashtable on all platforms to keep porting effort a minimum. +Note: Add this to the "usings" part of your CS scripts: using Hashtable = ExitGames.Client.Photon.Hashtable; +Changed: Our Photon3Unity3D.dll is now has to be in Assets\Plugins\. It has two alternative builds for Windows 8 Store and Phone (in specific subfolders). +Todo: When you update an existing PUN version, remove the "library" folder in your project first. The dll that's in there moved but Unity won't do this for you when importing this package. +Changed: We are now using Unity 4 to upload this package to the Asset Store. Aside from the new platform-folders (for Windows RT and Phone), the code should basically still run in Unity 3.5. Mail us if you need support for Unity 3.5: developer@exitgames.com +Added: Several helpful, basic components +InRoomChat: Basis component for chat. Has a list of lines (you could limit it), can be aligned to bootom of screen and is controlled by using "Enter" key (focus, send + unfocus). +ConnectAndJoinRandom: Simple component with instant matchmaking! This ignores room names and room properties but you can copy or extend it at will. +MoveByKeys: On GameObjects you control, this will apply keyboard movement by keys WASD. It disables itself if the GameObject is owned by a remote player. Todo: Re-enable this component on Scene objects when the Master client changes. +SmoothSyncMovement: Very basic movement smoothing script to be used on a GameObject with PhotonView. To setup: Ass component and PhotonView to GameObject. Drag and Drop SmoothSyncMovement component (that on the GameObject or Prefab) to PhotonView observe field. +Changed: AuthenticationValues can now have AuthPostData (needed for some communities which have huge session tokens). Use SetAuthPostData with either byte[] or string parameter. +Added: CustomAuthenticationType enum values for Steam and Facebook. + +v1.21 (10. July 2013) +Added: Lite version of the PUN Guide by M2H +Changed: Moved all demos to "PUN/Demos/" folder +Changed: Destroy methods and operations for those. Cleanup of workflow. This might break your game on update from previous versions. Keep an eye on Destroy usage if it mis-behaves after an update. +Removed: Support for Transform sending as custom type. It's technically impossible to create a Transform without a Unity game object, so we can't replicate them. Instead, send Position, Rotation and Scale where needed. +Changed: DisconnectCause to more explicit names. TimeoutDisconnect is now: DisconnectByClientTimeout. DisconnectByServer is now: DisconnectByServerTimeout +Added: Feature to override/set a Master Client manually. Default Master Client selection will trigger when a Master leaves and only this "default" selected Master Client can assign another one via SetMasterClient(). +Added: PunEvent.AssignMaster as internal event to override the current master client. +Internal: Changed implementation of CheckMasterClient(). Should be a bit cleaner and leaner. +Internal: Renamed PhotonNetworkMessages to PunEvent. This is usually only used by code in PUN's classes, not in your game. +Fixed: When a game uses Connect with a server-address, this is set as MasterServer address and after playing a game, the client will return to that server. This fixes the case when you don't use ConnectUsingSettings(). +Internal: GameVersion and PunVersion are combined for the (internal) virtual-app version string, they are now separated by underscore: '_'. +Added: PhotonNetwork.ResentReliableCommands. It can be an indicator for bad connections and as such is helpful during issue analysis. +Updated: To Photon client lib v3.2.1.4, containing a few minor fixes. + +v1.20 (19 April 2013) +Added: Features "Find Friends" and "Custom Authentication" plus (simple) demo. +Added: PhotonNetwork.FindFriends(string[] friendsToFind) to be used with (external) friends lists. If all users set their names before connecting, they could be found using this method and it's possible to join their games/rooms. +Added: OnUpdatedFriendList() can be implememented by your game to get a call when FindFriends() finished. Also see PhotonNetworkingMessage.OnUpdatedFriendList for info. +Added: PhotonNetwork.Friends property which will provide the result of a FindFriends call (takes a roundtrip to the server). +Added: FriendInfo class for the friends list (filled with names when FindFriends is called and getting updated with online status and room names when result was received). +Internal: Authenticate now sends the playername if not null or empty. This allows tracking of players and in which room they are. +Added: PhotonNetwork.ConnectToBestCloudServer() to connect to the region with the lowest averaged ping. PingCloudRegions MonoBehaviour is used to actually do the pinging. +Internal: Converted all visible text to string variables in PUN Wizard class. To be translated. +Fixed: Converter for Network.GetLastPing(player) and Network.CloseConnection(player,bool). They now get converted into their closest variants in PUN (which doesn't sync each player's ping) +Internal: The Extension class now explicitly uses SupportClass == ExitGames.Client.Photon.SupportClass, avoiding some name clash with other libs. At the same time, that class is now the only place where the SupportClass is used. +Internal: Renamed "utility" component DontDestroyOnLoad to TestDontDestroyOnLoad. Now filename and classname are identical again and this avoids another name clash with other projects. +Internal: Player properties are no longer sent if the actorNumber is < 1. While in room, the actorNumber is always > 0. +Updated: Reference doc (the PDF in this package). +Added: PhotonNetwork.FetchServerTimestamp to have that method available +Added: PhotonNetwork.ServerAddress to access this directly (but only as getter) +Changed: The ServerSettings field is now public (to be able to read and show settings) +Internal: ServerSettings file now has an enum CloudServerRegion. Used as names-list and in a few methods +Added: PhotonNetwork.ConnectToBestCloudServer(gameVersion) to connect the region with best ping. The PingCloudRegions script automatically pings available regions once, then saves the results in the PlayerPrefs. Currently this is enabled by default. + +v1.19.3 (12. April 2013) +Fixed: DemoSynchronization was missing a script on the CubeInterpo (game object) +Fixed: OfflineMode for all overrides of CreateRoom() will now call both OnCreatedRoom() and OnJoinedRoom(). +Fixed: Inspector for PhotonViews now makes the Editor save every change in the component. Before, prefabs were overriding (linked) objects in the hierarchy/scene. +Changed: PhotonViewInspector now shows if the (local) client is controlling a GameObject (via PhotonView). + +v1.19.1 (14. March 2013) +Fixed: Calls to OnMasterClientSwitched are now re-enabled. They went missing in 1.18, it seems. If a proper player was master before, then OnMasterClientSwitched is called when a new master was picked. + +v1.19 (14. March 2013) +Updated: PUN Wizard for setup and help. +Added: Editor key shortcuts. For PUN Wizard: ALT+P. To add PhotonView: ALT+V. +Added: PUN Wizard button to select the PhotonServerSettings file in project (to have a look at the config and RPC list). +Added: Wizard shows a note when iOS or Android Pro licenses are not available. Ignore if you don't build for those platforms. +Added: Context menu for PhotonView Components to open the PUN Wizard. +Added: Demo Hub scene to select the different demos. +Added: Demo "Boxes" and "Synchronization". +Updated: Marco Polo Tutorial. This "result" is slightly different from the online tutorial. Read it's readme for details. Also uses the current "Monster" asset from Asset Store (minus some surplus scene, geometry, etc). +Added: PunStartup. On import this Editor script opens the Hub scene (if no scene is open) and adds all demo scenes to the build settings (if no scenes are in the list). +Fixed: OnPhotonSerializeView was fired for playerpropertychange. +Changed: Log entries for failed random matchmaking. It's perfectly ok that sometimes no room is available, so that is no Error. +Changed: Instead of sending RPC names, PUN now compiles an index of RPC-methods and sends a shortcut (just a byte). RPC searching is done in-Editor. Currently a byte is used as shortcut, enabling 255 distinct RPC methods. PUN can be modified to use short or int as shortcuts (look up comments "LIMITS RPC COUNT"). +Changed: ServerSettings class is extended by the RPC-List. The PhotonServerSettings asset will be updated seamlessly if this new PUN version is imported. Copying the new class file over older ones will erease your settinsg and you might need to edit them again. +Changed: RPC calls without parameters are now a little more compact, cause the key for parameters is skipped. + +v1.18.2 (18. February 2013) +Updated: To a new Photon Client library (v3.2.0.1) which includes a fix for disconnects caused by network simulation. +Fixed: A potential endless loading-loop on the master client, when using level synchronization +Added: callback for changes to custom room properties and changes to player properties + +v1.18 (31. January 2013) +Note: Open all scenes that have PhotonViews and just save them again. + +Changed: The script PhotonViewPrefabApply is updated into an empty file. The file is obsolete (and just included to make upgrades from older versions more smooth). +Changed: PhotonView.cs is no longer in a folder "Extension". On import to existing projects, Unity will update the correct file but new projects have the PhotonView directly in the Plugins folder. You can move the file in Unity's project window and remove the "Extension" folder. + +Added: enable PhotonNetwork.automaticallySyncScene for automatic loading of the correct scenes. Simply join a room and all clients will always open the same scene as the MasterClient. +Fixed: IENumerators are now called via their own script instance instead of the PhotonHandler monobehaviour. This fixes an issue where the IENumerators would continue running even after the script was destroyed. +Added: Error logging in case a PhotonView (on any network instantiated object) is not being destroyed by PhotonNetwork.Destroy() or similar. GameObject.Destroy() on those items will break networking! +Fixed: Some places where old instantiate IDs were probably used in PhotonNetwork.Destroy(). +Added: Caching for Resources used by Instantiate. PhotonNetwork.UsePrefabCache can be used to turn this off, while PrefabCache lets you access the individual Prefabs (you could remove specific ones if needed). +Note: The new Instantiate-Resource caching should perform better on mobiles when a few prefabs are instantiated over and over. +Removed: Callback OnReceivedRoomList(). If you implemented this method, we instead call OnReceivedRoomListUpdate() now in all cases the room list is refreshed (no matter if new or just updated). Seems easier. +Changed: Callback OnMasterClientSwitched() is now only called when the master client actually switcheds, not when the master client value is initialized (when entering a room). +Changed: LevelPrefix is now applied to PhotonViews (GameObjects) when they get instantiated or loaded into a scene and then they don't change again. They are sent in instantiate, too, so remote instances use the same (not the prefix someone else set). +Note: Despite the LevelPrefix, PhotonViews with the same ViewIDs will "collide" as we store those by viewID only. +Renamed: PhotonNetSimSettingsGui class is now called PhotonLagSimulationGui. The name often collided with "PhotonNetwork" in an IDE's auto-completion. When upgrading existing PUN versions, you can delete the old file "PhotonNetSimSettingsGui.cs" +Changed: Internal system to allocate viewIDs. The new system is much simpler and saves performance at runtime. +Fixed: LevelPrefix for RPCs in ExecuteRpc() is now cast correctly. +Fixed: PhotonNetwork.countOfPlayersOnMaster was returning PhotonNetwork.countOfPlayers instead just those on master server (looking for rooms/games). +Fixed: PhotonNetwork.Destroy for anything owned by a player who already left. This affects you only if autoCleanup is disabled by your game. +Fixed: OfflineMode for PhotonNetwork.Disconnect() now resets the state and calls events (leaving room, disconnect) as you know it by online mode. +Changed: If you use OfflineMode, this now ends (!) when you call PhotonNetwork.Disconnect(). +Added: NetworkView groups are now using Photon's new Interest Group feature (new server SDK v3.2 and up required). This might save some bandwidth but might also lead to inconsistant states (when ignoring essential RPCs accidentally). Check out "Using Groups in PUN" topic in the PDF. +Added: New ErrorCode constants: MaxCcuReached and InvalidRegion. +Added: DisconnectCause values: MaxCcuReached and InvalidRegion. +Added: OnConnectionFail() is now also called in case of Photon Cloud MaxCcuReached (the callback OnMaxCcuReached() is still called but maybe you want to handle these similar errors in one method). +Added: OnConnectionFail() is called in case of "Invalid Region". +Changed: RPCs are now also called on a script that inherits the RPC implementation from a class it extends. Internally, ExecuteRPC() doesn't use BindingFlags.DeclaredOnly in type.GetMethods() anymore to achieve this. +Internal: NetworkingPeer fields renamed: mPeerCount is now: mPlayersInRoomsCount and mMasterCount is now: mPlayersOnMasterCount. +Internal: PhotonViewID and PhotonView both got a new property OwnerActorNr, to fix removing items owned by players who left. +Added: Alternative random matchmaking rulesets! Instead of filling up rooms asap, you can distribute players across available games. This might make sense when there's a high maxPlayer value per room and players cooperate / can join anytime. +Added: enum MatchmakingMode with options for random matchmaking +Internal: ParameterCode.MatchMakingType +Added: matchingType parameter to OpJoinRandomRoom() +Removed: OpJoinRandomRoom(expectedGameProperties). It was exclusively used internally and obsolete. +Changed: The converter now also replaces NetworkStateSynchronization with PUN's ViewSynchronization enum. +Changed: Converter will now turn Network.InitializeServer into PhotonNetwork.CreateRoom (was converting to .JoinRoom). +Updated: To new client library (Photon3Unity3D.dll) with some fixes. +Fixed: Manual viewID allocation is now more stable. It works only for player-owned objects. Use AllocateViewID() and UnAllocateViewID accordingly. If you manually assign viewIDs, RPCs on instantiated objects will fail until you do. You need to destroy those objects, too. +Changed: Default cap of unreliable updates per dispatch is now 40. In cases with many unreliable synchronized objects, the previous default of 20 resulted in choppy updates. +Changed: PhotonServerSettings.asset can now be moved to any 'Resources' folder. The Photon Wizard detects if more than one exists (when opening the window) and warns you if there are more than one file. +Internal: The PhotonHandler now uses Time.realtimeSinceStartup to check intervals for updates and sending. Each time that updates are produced, they are sent immediately (reducing local lag). +Internal: The hidden GameObject for the PhotonHandler script should only be created once and not be saved in the scene. This is taken care of with DestroyImmediately now, for any surplus duplicates of this object. + +Known Issue: When you load a new scene, all instantiated GameObjects are destroyed only locally but not on the server. Anyone who joins the room later on still creates those GOs. To work around this, PhotonNetwork.Destroy your instantiated game objects before loading a new scene. Or use: PhotonNetwork.RemoveAllInstantiatedObjects(player). +Known Issue: Changing the group of a PhotonView is only done locally and not synced. + +v1.17 (27. September 2012) +Note: this version has breaking changes! don't try to use it with clients with older PUN versions +Updated: PUN version string to "1.17" +Updated: client library (the dll) to v3.0.1.14. This fixes an exception and adds some better iOS 5 udp-socket fixes (see release_history.txt) +Fixed: Player list checking when client joins. The client now first checks the local player-list with the list from server. Then calls OnJoinedRoom. (was: the other way round) +Fixed: observing a rigidbody via a PhotonView was bugged (velocity and angular velocity were mixed up) +Changed: PhotonNetwork.SetLevelPrefix() is now short typed. It practically never happens that you have more than 32k levels (and short saves a bit of traffic) +Changed: Reliable delta compression now uses a different format and is a bit leaner +Changed: The data you produce in OnPhotonSerialize is sent is now sent completely and uncompressed, if the length of it changes to previous sends. If length doesn't change, we assume the data content and order is same as last time +Internal: OnPhotonSerialize data is trasported in a hashtable in: key 1 original, 2 compressed, 3 list of "true" null values (when using compression) +Internal: Instead of overriding compressed data[] into Hashtable key 1, this now uses key 2 (and removes key 1). this makes it easy to decide if anything was compressed at all +Internal: PhotonView.lastOnSerializeDataSent and .lastOnSerializeDataReceived are now object[] +Internal: OnSerializeWrite now uses an int-array to send view ID, timestamp and level-prefix +Added: output for ping + variance to PhotonStatsGui (in health values) +Added: Event / callback method OnPhotonMaxCccuReached. This is called when the CCU limit for your title is reached (this means: either a Cloud subscription limit or a Photon Server license limit is reached) +Changed: OnPhotonMaxCccuReached might be called after authentication. When it was called, PUN will automatically disconnect. The player might re-try later on. + +v1.16.2 (3. August 2012) +Fixed: version 1.16 didn't compile for non-Editor environments because the ServerSettings used EditorClasses but is needed at runtime +Internal: In SendMonoMessage, replaced List with HashSet which has a constant lookup time for .contains +Changed: Some foreach into for loops + +v1.16 (3. August 2012) +Updated: To being a Unity 3.5.3 package +Updated: To Unity 4 compatibility +Fixed: In-room player list didn't include players who didn't set any properties (no name and no custom properties) +Fixed: PhotonViewInspector now displays owner as null if not set, instead of showing the PV as sceneView +Updated: To new client lib. This is now thread safe, which means that a thread could call SendOutgoingCommands in intervals, as fallback when Update() is paused for too long +Updated: Usage of the lib's NetworkSimulationSettings property (this is an internal change) +Updated: Some links in the Setup Wizard window became outdated and are now fixed +Updated: InstantiateSceneObject to use FindObjectsOfType less often, which improves performance +Changed: Methods that are intended for PUN-internal use are now becoming internal or private instead of public. Public methods and classes are the ones really meant for game development +Internal: RemoveAllInstantiatedObjects now also (re)sets the cacheInstantiationCount to 0 +Internal: Updated to new account service +Internal: PhotonEditor was modified to be extended and customized. Saves if the setup wizard did open at least once. Also gets less updates. +Added: JoinRandomRoom overload to use expectedCustomProperties. These can filter which properies a room must match to join it randomly. +Changed: Documentation to be generated from code and topic files. This provides a complete reference documentation. The pdf is still the best option for a single-file document. +Changed: Documentation was extended. "Timing for RPCs and Loading Levels" and the topics about the GUI elements available is new. +Updated: The optional GUIs are now draggable windows and a bit cleaned up +Changed: ServerSettings class has another value that needs serialization (maybe this means your serverSettings will have to be re-written after update). +Updated: PUN version string to "1.16" + +v1.15 (11. June 2012) +Fixed: PhotonMessageInfo.timestamp. The conversion of the sent ms-timestamp to a second-based timestamp double value was imprecise +Fixed: Room-filtering for join random room did not work, cause a parameter code was wrong. Now, filtering works as expected. +Changed: The Marco Polo Tutorial is no longer packaged but in a sub-folder of PUN. The scene/project for this is complete but in best case, you still work through the tutorial pdf. +Added: short paragraph about the tutorial-result being in the PUN package to tutorial text +Changed: OnFailedToConnectToPhoton is now called when the connection could not be established, OnConnectionFail is called when a established connection fails. The difference between both is sometimes minimal. In either case, OnDisconnectedFromPhoton is called afterwards, too. +Changed: description of PhotonNetworkingMessage.OnDisconnectedFromPhoton, PhotonNetworkingMessage.OnConnectionFail and PhotonNetworkingMessage.OnFailedToConnectToPhoton according to above's changes +Added: Warnings to log console when connections fail (showing the current address and a hint what might be wrong) +Changed: If a script doesn't write any data to the stream in OnPhotonSerializeView(), then this view's update is not sent. This allows you to skip updates from within your own logic. Simply don't fill anything into the stream. +Changed: Only when DeltaCompression is active, copies of sent and received data are cached. You can't change a PhotonView's synchronization method on the fly (that didn't work before, either). +Fixed: MarcoPolo-Tutorial: audio was missing +Updated: PUN version string to "1.15" +Updated: to latest client lib v3.0.1.11 (some fixes from previous builds) + +v1.14 (08. May 2012) +Fixed: OnSerializePhotonView is always ONLY called when at least one other player is connected. This is by design. What has changed is that offlineMode will now also no longer run OnSerializePhotonView. +Fixed: Duplicate IDs when duplicating Scene PhotonViews (they are now updated correctly). +Improved: When connected to the lobby, countOfRooms is based on the room list length for improved update rate. +Fixed: When the connection 'breaks', via a disconnect call the network state will be reset properly. This mainly fixes the behaviour of iOS apps going to the background (which drops the connection). +Fixed: Bug which kept authorize from being encrypted. Authorize encryption is now enabled by default. The AppId is now only sent in the op authorize (v1.14.2) +Updated: PhotonStatsGui. This simple component can be attached to gameobjects and shown with shift+tab. It now shows gaps in send- and dispatch-intervals. If those go beyond a few milliseconds, the game FPS obviously stutters which might cause connection issues. +Updated: doc for ActorProperties, ErrorCode, GameProprties, EventCode, ParameterCode, OperationCode. +Updated: Internally used client library to latest release v3.0.1.6 +Updated: PUN version string to "1.14" +Internal only: + Renamed: OpCreateGame is now OpCreateRoom, OpJoin -> OpJoinRoom, OpJoinRandom->OpJoinRandomRoom OpSetPropertyOfGame -> OpSetPropertyOfRoom + Renamed: ParameterCode.ActorProperties -> ParameterCode.PlayerProperties + Renamed: ParameterCode.GameId -> ParameterCode.RoomName + +v1.12 (18. April 2012) +Fixed: playerList and otherPlayerList are now updated when the local player's id changes. In 1.10, this caused issues when leaving a room +Fixed: Extension method for Hashtable StripKeysWithNullValues(), used to remove properties set to null +Fixed: Custom properties which are set to null, are now synced and removed everywhere +Added: PhotonNetwork.SetPlayerCustomProperties to make actor properties more comfortable + + v1.10 (16. April 2012) +Added: Info on how to activate Photon Cloud Subscriptions that are bought through the Assset Store (this currently requires a mail by you). See readme.txt +Fixed: OnLeftLobby is now called as expected +Fixed: OnLeftRoom is now called as expected (also on disconnect from game server) +Fixed: OnSerialize issue with null as object +Fixed: PhotonNetwork.time now keeps it's precision even with high values for ServerTimestamp (fixed it's casting). This will update every ~15ms by default. +Changed: playerList and otherPlayerList now return Player[] instead of List (simpler conversion) +Changed: Optimized playerList and otherPlayerList. They are now cached and only created when some player is added or removed +Added: PhotonNetwork.insideLobby +Added: Comments for enum PeerState +Added: In PhotonServerSettings you can now chose Offline mode +Removed: PhotonNetwork.Instantiate(GameObject go, ...) variant. Use a resource name instead (folders work). +Removed: PhotonNetwork.Destroy(int). Use PhotonNetwork.Destroy(PhotonView) instead. +Added: Vital Network Statistics. These will help analyze issues with client-to-server communication by provinding (limited) insight in the client's timing. See below. +Added: PhotonNetwork.NetworkStatisticsEnabled, .NetworkStatisticsReset and .NetworkStatisticsToString to control and get the vital stats. +Fixed: OnFailedToConnectToPhoton() is no longer called for any connection loss but only while the connection is being established. Note: OnDisconnectedFromPhoton is called, too, to let you know when the connection is closed. +Added: enum DisconnectCause for OnFailedToConnectToPhoton and OnConnectionFail +Added: new callback/MonoEvent OnConnectionFail. This provides a DisconnectCause that hints at the cause for a connection loss. Note: OnDisconnectedFromPhoton is called, too, to let you know when the connection is closed. +Added: Wizard now has a button to bring you to the Photon Cloud's Dashboard page (login) +Fixed: An issue where Unity recompile (any file) caused the PhotonServerSettings to be wiped if the Wizard was open +Updated: documentation JoinGame -> JoinRoom +Updated: client library to a intermediate version (not yet released but improved with new features): v3.0.1.305 +Updated: to client lib v3.0.1.3 and added related release_history.txt +Fixed: removed 3.5+ compile warnings about PrefabUtility + +v 1.9.6 (20 March 2012) +New: PhotonNetwork.InstantiateSceneObject to spawn scene based objects that persist even if the current master client drops (usefull for AI etc.) +Workaround: calling LeaveRoom in Disconnect to prevent a rare bug where players get stuck in room while being disconnected. +Improved: offline mode will now also fire OnJoinedRoom after calling CreateRoom +Fixed: No null playerName when using offline mode +Fixed: MC and ID's not set correctly after switching from offline mode to online + +v1.9.5 (05 March 2012) +New: Delta compression has been added to the observe option of reliable PhotonViews. This greatly reduces the network bandwidth. +Fixed: OnLeftRoom error. +Fixed: Stats timer didn't reset +Moved: OnPhotonSerializeView and OnPhotonInstantiate to enums.cs (PhotonNetworkingMessages) + +v1.9 (27 February 2012) +Fixed: Bugfix for cleanup after a player left. (bug introduced in 1.8) +Fixed: PUN viewID assignment after conversion from Unity Networking +Added: More checks to validate PhotonViews (PhotonViewIDs are stripped from Prefabs but GOs in the Hierarchy must have one). +Removed: Removed TODO's from PhotonNetwork and made Destroy behaviour more consistent: Players can only destroy objects that they own, the master client can destroy everyones objects. +Changed: PhotonNetwork.Instantiate now requires a PhotonView at the root of a prefab +Changed: PhotonNetwork.Destroy(GameObject go) required the gameobject to be created via PhotonNetwork.Instantiate +Added: Summary and Example for each of the PhotonNetworkingMessage values (each names a "callback" method used by PUN) +Added: PhotonNetwork.Instantiate overloads which take a prefab's Name to instantiate. You no longer need to pass a GameObject for a asset that's in the Resouces anyways. +Changed: PhotonNetwork.GetRoomList() now returns RoomInfo[] instead of a Room[]. Simply change the type! RoomInfo a different class but behaves like the rooms did. +Added: RoomInfo class, as base for Room. The RoomInfo is what you get in room listing: PhotonNetwork.GetRoomList() and you can't modify RoomInfo (you're not yet in those rooms) +Added: Room.SetCustomProperties() and PhotonPlayer.SetCustomProperties() to add/update custom properties to players or rooms. The key of those must be string! You can't currently delete customProperties from the server (but set them null). This is likely to change. +Added: Room.customProperties and PhotonPlayer.customProperties as getter for the custom properties you set. These sync once set. +Changed: Custom room properties are no longer automatically listed in the lobby! see CreateRoom() note below. +Added: CreateRoom() overload that takes string[] propsToListInLobby as last parameter. This defines which custom properties of your room get into the lobby. By default no other props get listed. So if you want to set "map" and have that in the lobby, apply it by CreateRoom(). +Added: Check if values are changed more than a minimum before they are sent. Floating point precision for positions and rotations cause many updates and messages, so these thresholds help skip updates that are too tiny to notice. See note below. +Added: PhotonNetwork precisionForVectorSynchronization, precisionForQuaternionSynchronization, precisionForFloatSynchronization properties. +Added: Option to not join the lobby and respective callback. Use PhotonNetwork.autoJoinLobby to set and implement OnConnectedToMaster() instead of OnJoinedLobby(). You can join random games, create or join named games just fine, without the lobby. +Changed: PhotonNetwork.autoCleanUpPlayerObjects is now done by server and can be set per room. In a room, all clients adhere to the room's setting (as set when the first player calls create). This should solve some rare issues due to racing conditions. The Master is not doing extra work anymore for this. +Added: Room.autoCleanUp. This property tells each client if the room actually cleans up buffers for players that leave. Set when the room is created to the then current value of PhotonNetwork.autoCleanUpPlayerObjects. +Changed: PhotonNetwork.autoCleanUpPlayerObjects fires an error when changed while in a room +Fixed: isMasterClient and PhotonNetwork.masterClient for some rare conditions. +Fixed: PhotonPlayer.ToString() returned null, if no name was set. This now returns "". +Added: PhotonNetwork.unreliableCommandsLimit which could be used to fine tune how many of the most recent unreliable messages should be dispatched while the rest is skipped. This has a useful default, so you don't really have to care. +Added: Initial version of PhotonStatsGui script, which shows messages total and for a interval. This is giving a first impression of the message-usage of your games. This will be extended. +Added: Profiler samples to SendOutgoingCommands and DispatchIncomingCommands. These tell you how often they run (in some frames only) and how long. +Changed: Internally, SendOutgoingCommands() is now called as long as there are outgoing commands queued. This will produce UDP packets when absolutely needed but stabilizes the connection, especially when joining games and getting a lot of messages. +Changed: The connectionStateDetailed is now changed before PUN calls your OnFailedToConnectToPhoton(), so you could re-connect from inside of that method. +Updated: To Photon Unity3d client lib v3.0.1.1 + + +v1.8 (25 January 2012) +Added: changelog tp PUN package +Fixed: a bug that occured when calling a PhotonNetwork.Instantiate in the same frame after calling a PhotonNetwork.Destroy. +Changed: InitializeSecurity made obselete. requestSecurity is now true per default, this will encrypt authenticate(the APPID etc.) All normal messages (RPC etc) are NOT encrypted ATM. +Removed: instances of GAME to ROOM inside PhotonNetwork.(Please mind isNonMasterClientInGame' -> 'isNonMasterClientInRoom') +Added: new statistic: PN.countOfPlayersInRooms +Changed: OnPhotonPlayerDisconnected is now called AFTER possible MasterClient switch +Changed: OnPhotonPlayerDisconnected is now called AFTER the playerList (and playercount) has been updated: The player is first removed from the playerlist. +Changed: OnPhotonRandomJoinFailed is now properly called after RandomJoin failed because an empty room was accidently joined. Previously OnPhotonJoinRoomFailed would be called instead. +Changed: PhotonNetwork won't generate a player name. Instead the Worker Demo does this when no name was applied yet. (player names are synced automatically when set) + +v1.7: +Changed: renamed "Room" to "Game" in event/callback methods for OnPhotonCreateGameFailed and OnPhotonJoinGameFailed. This is important to adjust! +Changed: PhotonViews are now usable via Awake() on any script (previously they were setup between Awake and Start) +Fixed: No more broken connection if Join/Create/JoinRandom/LeaveRoom is called during connection or disconnection: an error is logged instead. +Changes: cacheInstantiationCount is ONLY reset in LeftRoomCleanup() if autoCleanUpPlayerObjects is true +Fixed: cacheInstantiationCount is now caompared to ushort.MaxValue (with u in ushort) +Added: New GameVersion argument to Connect*, plus new PUN version. These version strings make sure only clients that use the exact same game version AND PUN version will be able to play together. +Added: Information about versioning in documentation +Changed: Unregisters allocated viewIDs after PhotonNetwork.Destroy* +Fixed: Compatibility with Unity 3.5 (excluding Flash export for the time being) +Changed: Destroy was sent twice for views in some cases. Cleaned up. As this was no real bug, this is no fix. +Updated: to new client lib (v3.0.0.9) +Fixed: Relatively rare encryption issue which led to a disconnect. + +v1.6: +Updated: Client library to v3.0.0.8 which brings important fixes and some Unity-targeted performance optimizations +Changed: Default update rate is 10/second now, which is a better standard (send-rate stays at 20/second) +Changed: During disconnect, operation responses are now ignored. Example: Join a random game, then disconnect before entering the room. This now disconnects you (instead of getting you in the room). +Changed: Internals how the PhotonStream works. This is now leaner and faster and is the first step to optimized syncing +Note: This is incompatible with previous PUN versions. Don't run separate PUN versions in one game + +v1.5: +Fixed: Background thread now starts when message queue is paused (for loading something, by setting isMessageQueueRunning to false) +Fixed: Destroy(gameObject) now removes the instantiate from the server's cache +Fixed: Some of the Log output was not included in "more verbose" log levels +Updated: Client library to that of Photon Unity SDK v3.0.0.7 which uses less memory and gives you some performance if your game causes a lot of traffic +Removed: some obsolete values +Added: LoadbalancingPeer class and moved aroud some other classes. The goal is to extract some classes for general use in DotNet (without Unity, if needed) +Note: If you want to host your own Photon server please update to Photon 3 SDK RC7 (it has some memory fixes, too) +Note: Destroy() for views is not yet working for players who join late into existing games. This is not a buffered action. We're on it. + +v1.4.1: +Re-Submit same package to asset store. + +v1.4: +Fixed: Caching of RPCs and Instantiates. This is a major fix, affecting all situations where players join a room where RPCs and Instantiations were done previously. This fix is "hidden" by the API, so no code changes are necessary in a game. +Changed: The new cache is no longer cleaned by the server if someone leaves. The "MasterClient" will delete another user's RPCs and Instantiations, when someone leaves (unless auto cleanup is turned off). +Changed: Internals of RPCs and Instantiates. Their events are streamlined and contain only data that's not a default value. This is incompatible with v1.3 clients. +Fixed: Position and rotation synchronization is now done local to the object. This helps with positions relative to ancestor objects. +Fixed: PhotonNetwork.Destroy(). +Improved: If you disable the message queue (while loading levels), a thread will keep the connection alive. Timeouts are less frequent this way. Use isMessageQueueRunning. +Improved: The framework now discards older incoming unreliable updates. By default, everything past the newest 20 unreliable updates (like pos syncs) gets skipped. Reliable data is not affected. +Changed: RPC calls now can be called without any parameters (null), too. +Added: PhotonNetwork.SendOutgoingCommands() which is useful to send RPCs before the client will load (and suspend sending) for a while. +Updated: To new Photon client library v3.0.0.6. + +v1.3: +Changed: MasterClient handover: When leaveing a room, the MasterClient becomes null. It only is available inside a room. +Changed: PhotonNetwork.time is now a double with millisecond precision and always positive. It's 0 at server-start and goes up to ~4294967, where it will overflow to 0 again. This happens every ~49 days. +Fixed: A call to Disconnect() while not being connected set a state that made it impossible to Connect() later on. +Changed: Connect() is only possible when disconnected. Disconnect() is only allowed when the client is connected. +Added: enum PhotonNetworkingMessage now contains all method names that could be called by our framework (in no particular order). Check it's description. +Changed: A few internals to improve performance and reduce object creation (and save some GC calls). Example: SendMonoMessage(). +Updated: client library is now from Photon Unity SDK v3.0.0.5 +Changed: PhotonNetwork will now limit incoming unreliable messages to 20 instead of dispatching everything. This can cause gaps in updates but lets a client catch up much faster after loading a level (which pauses dispatching of incoming events). +Fixed: Converter will now make JS scripts extend Photon.MonoBehaviour after conversion. +Updated: PhotonView and inspector to also handle scene views on disabled objects. Before, these could collide easily. Please give feedback, if PhotonViews cause errors. + +v1.2: +Fixed: DemoWorker, random double spawn bug fixed. Loading the same scene and scripts caused initialization errors +Fixed: LevelPrefix bug for newly spawned PhotonViews (after setting the prefix) +Fixed: OnDestroy message +Fixed: Suppressed error messages when setting a name when not connected. +Fixed: Master client handover fixed +Fixed: SetSendingEnabled() and SetReceivingEnabled() which was doing the opposite of what you expected. +Added: CreateRoom now has parameters for: maxplayers, visible and open +Added: Room.maxPlayers, .open and .visible will now be synced and affect the lobby +Added: PhotonView OnSerialize now only runs on scripts on active gameobjects +Added: PhotonVIew.isMine also returns true on scene objects for the masterclient +Added: Server setup wizard, which offers instant access to a cloud account +Added: Server settings file + +v1.1: +Fixed: Server "Access Denied" issue on start on XP machines. +Fixed: observing classes that inherit Monobehaviour, but not directly. +Fixed: scene view ID errors when using prefabs (APPLY from scene to project) diff --git a/Assets/Photon Unity Networking/changelog.txt.meta b/Assets/Photon Unity Networking/changelog.txt.meta new file mode 100644 index 0000000..e35d233 --- /dev/null +++ b/Assets/Photon Unity Networking/changelog.txt.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 612a7d8fb44bb994d90d9c0fa1408703 +labels: +- ExitGames +- PUN +- Photon +- Networking diff --git a/Assets/Photon Unity Networking/link.xml b/Assets/Photon Unity Networking/link.xml new file mode 100644 index 0000000..c916499 --- /dev/null +++ b/Assets/Photon Unity Networking/link.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/Assets/link.xml.meta b/Assets/Photon Unity Networking/link.xml.meta old mode 100755 new mode 100644 similarity index 58% rename from Assets/link.xml.meta rename to Assets/Photon Unity Networking/link.xml.meta index 1240c42..850d94d --- a/Assets/link.xml.meta +++ b/Assets/Photon Unity Networking/link.xml.meta @@ -1,4 +1,4 @@ fileFormatVersion: 2 -guid: 688299b18b3aecc4bba61613f5cf576d +guid: cecd4a32eba31cd4393c185e20824bfc TextScriptImporter: userData: diff --git a/Assets/Photon Unity Networking/readme.txt b/Assets/Photon Unity Networking/readme.txt new file mode 100644 index 0000000..ce2a2e7 --- /dev/null +++ b/Assets/Photon Unity Networking/readme.txt @@ -0,0 +1,96 @@ + +Photon Unity Networking (PUN) + This package is a re-implementation of Unity 4's Networking, using Photon. + Also included: A setup wizard, demo scenes, documentation and Editor extensions. + + +PUN & PUN+ + PUN is the free package of Photon Unity Networking. Export to iOS or Android from Unity 4 requires Unity Pro Licenses. + PUN+ contains special native plugins that allow export to mobiles from Unity 4.x Free. You also get a Photon Cloud subscription upgrade. See below. + Unity 5 does not restrict export to mobiles. + + +Android and iOS Exports + See "PUN & PUN+" + iOS: Set the stripping level to "Strip Bytecode" and use ".Net 2.0" in the player settings. + More aggressive stripping will break the runtime and you can't connect anymore with PUN Free. + + +UnityScript / JavaScript + PUN is written with C# in mind primarily. + To use PUN from UnityScript, you need to move some folders in your project. + Move both folders "PhotonNetwork" and "UtilityScripts" to the Assets\Plugins\ folder. + from: \Photon Unity Networking\Plugins\ + and: \Photon Unity Networking\ + to: \Plugins\ + Now PUN compiles before UnityScript and that makes it available from regular UnityScript code. + + +Help and Documentation + Please read the included chm (or pdf). + Online documentation: http://doc.photonengine.com/en/pun + Exit Games Forum: http://forum.photonengine.com/categories/unity-networking-plugin-pun + Unity Forum Thread: http://forum.unity3d.com/threads/photon-unity-networking.101734/ + + +Integration + This package adds an Editor window "PUN Wizard" for connection setup: + Menu -> Window -> Photon Unity Networking (shortcut: ALT+P) + It also adds a commonly used component "PhotonView" to this menu: + Menu -> Component -> Miscellaneous -> PhotonView (shortcut: ALT+V) + When imported into a new, empty project, the "PunStartup" script opens the "demo hub" and setup scenes to build. + + +Clean PUN Import (no demos) + To get a clean import of PUN and PUN+ into your project, just skip the folders "Demos" and "UtilityScripts". + UtilityScripts can be useful for rapid prototyping but are optional to use. + "Important Files" are listed below. + + +Server + Exit Games Photon can be run on your servers or you can subscribe to the Photon Cloud for managed servers. + + The window "Photon Unity Networking" will help you setup a Photon Cloud account. + This service is geared towards room-based games and the server cannot be modified. + Read more about it: http://www.photonengine.com + + Alternatively, download the Server SDK and run your own Photon Server. + The SDK has the binaries to run immediately but also includes the source code and projects + for the game logic. You can use that as basis to modify and extend it. + A 100 concurrent user license is free (also for commercial use) per game. + Read more about it: http://www.photonengine.com/en/OnPremise + + +PUN+ and Networking Guide Subscriptions + Follow these steps when you bought an asset that includes an upgrade for a Photon Cloud subscription: + Use an existing Photon Cloud Account or register. https://www.photonengine.com/Account/SignUp + Sign in and open the Dashboard. https://www.photonengine.com/dashboard/Realtime/ + Select the Subscription to upgrade and click "Apply Unity Purchase". + Enter your Unity Invoice Number and App ID. + + You find the App ID on: https://www.photonengine.com/dashboard/Realtime/ + You find your Unity Invoice Number in the Unity AssetStore: + https://www.assetstore.unity3d.com/en/#!/account/transactions + Or while logged in to the Asset Store, click on your name on the top right. + From the drop-down select the payment method you used to obtain PUN+). + Navigate to your PUN+ purchase and copy the number following the "#" symbol (excluding the "#" and spaces). + + +Important Files + + Documentation + PhotonNetwork-Documentation.chm (a pdf is also included) + changelog.txt + + Extensions & Source + Photon Unity Networking\Editor\PhotonNetwork\*.* + Photon Unity Networking\Plugins\PhotonNetwork\*.* + Plugins\**\Photon*.* + + + The server-setup will be saved as file (can be moved into any Resources folder and edited in inspector) + Photon Unity Networking\Resources\PhotonServerSettings.asset + + Demos + All demos are in separate folders in Photon Unity Networking\Demos\. Delete this folder in your projects. + Each has a Demo-Scene. diff --git a/Assets/Photon Unity Networking/readme.txt.meta b/Assets/Photon Unity Networking/readme.txt.meta new file mode 100644 index 0000000..e8c13cd --- /dev/null +++ b/Assets/Photon Unity Networking/readme.txt.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: d90864ccbf99d4a449c87472b0a181e8 +labels: +- ExitGames +- PUN +- Photon +- Networking diff --git a/Assets/PhotonChatApi.meta b/Assets/PhotonChatApi.meta new file mode 100644 index 0000000..46cc186 --- /dev/null +++ b/Assets/PhotonChatApi.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: e218cc4bd668742079c5f5e8afea63d8 +folderAsset: yes +timeCreated: 1501014811 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/PhotonChatApi/ChatChannel.cs b/Assets/PhotonChatApi/ChatChannel.cs new file mode 100644 index 0000000..157a56a --- /dev/null +++ b/Assets/PhotonChatApi/ChatChannel.cs @@ -0,0 +1,106 @@ +// ---------------------------------------------------------------------------------------------------------------------- +// The Photon Chat Api enables clients to connect to a chat server and communicate with other clients. +// ChatClient is the main class of this api. +// Photon Chat Api - Copyright (C) 2014 Exit Games GmbH +// ---------------------------------------------------------------------------------------------------------------------- + +#if UNITY_4_7 || UNITY_5 || UNITY_5_0 || UNITY_5_1 || UNITY_6_0 +#define UNITY +#endif + +namespace ExitGames.Client.Photon.Chat +{ + using System.Collections.Generic; + using System.Text; + + #if UNITY || NETFX_CORE + using Hashtable = ExitGames.Client.Photon.Hashtable; + using SupportClass = ExitGames.Client.Photon.SupportClass; + #endif + + + /// + /// A channel of communication in Photon Chat, updated by ChatClient and provided as READ ONLY. + /// + /// + /// Contains messages and senders to use (read!) and display by your GUI. + /// Access these by: + /// ChatClient.PublicChannels + /// ChatClient.PrivateChannels + /// + public class ChatChannel + { + /// Name of the channel (used to subscribe and unsubscribe). + public readonly string Name; + + /// Senders of messages in chronoligical order. Senders and Messages refer to each other by index. Senders[x] is the sender of Messages[x]. + public readonly List Senders = new List(); + + /// Messages in chronoligical order. Senders and Messages refer to each other by index. Senders[x] is the sender of Messages[x]. + public readonly List Messages = new List(); + + /// If greater than 0, this channel will limit the number of messages, that it caches locally. + public int MessageLimit; + + /// Is this a private 1:1 channel? + public bool IsPrivate { get; internal protected set; } + + /// Count of messages this client still buffers/knows for this channel. + public int MessageCount { get { return this.Messages.Count; } } + + + /// Used internally to create new channels. This does NOT create a channel on the server! Use ChatClient.Subscribe. + public ChatChannel(string name) + { + this.Name = name; + } + + /// Used internally to add messages to this channel. + public void Add(string sender, object message) + { + this.Senders.Add(sender); + this.Messages.Add(message); + this.TruncateMessages(); + } + + /// Used internally to add messages to this channel. + public void Add(string[] senders, object[] messages) + { + this.Senders.AddRange(senders); + this.Messages.AddRange(messages); + this.TruncateMessages(); + } + + /// Reduces the number of locally cached messages in this channel to the MessageLimit (if set). + public void TruncateMessages() + { + if (this.MessageLimit <= 0 || this.Messages.Count <= this.MessageLimit) + { + return; + } + + int excessCount = this.Messages.Count - this.MessageLimit; + this.Senders.RemoveRange(0, excessCount); + this.Messages.RemoveRange(0, excessCount); + } + + /// Clear the local cache of messages currently stored. This frees memory but doesn't affect the server. + public void ClearMessages() + { + this.Senders.Clear(); + this.Messages.Clear(); + } + + /// Provides a string-representation of all messages in this channel. + /// All known messages in format "Sender: Message", line by line. + public string ToStringMessages() + { + StringBuilder txt = new StringBuilder(); + for (int i = 0; i < this.Messages.Count; i++) + { + txt.AppendLine(string.Format("{0}: {1}", this.Senders[i], this.Messages[i])); + } + return txt.ToString(); + } + } +} \ No newline at end of file diff --git a/Assets/PhotonChatApi/ChatChannel.cs.meta b/Assets/PhotonChatApi/ChatChannel.cs.meta new file mode 100644 index 0000000..0d73965 --- /dev/null +++ b/Assets/PhotonChatApi/ChatChannel.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 35b2a4878e5e99e438c97fbe8dbbd863 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/PhotonChatApi/ChatClient.cs b/Assets/PhotonChatApi/ChatClient.cs new file mode 100644 index 0000000..0f47f2b --- /dev/null +++ b/Assets/PhotonChatApi/ChatClient.cs @@ -0,0 +1,1122 @@ +// ---------------------------------------------------------------------------------------------------------------------- +// The Photon Chat Api enables clients to connect to a chat server and communicate with other clients. +// ChatClient is the main class of this api. +// Photon Chat Api - Copyright (C) 2014 Exit Games GmbH +// ---------------------------------------------------------------------------------------------------------------------- + +#if UNITY_4_7 || UNITY_5 || UNITY_5_0 || UNITY_5_1 || UNITY_6_0 +#define UNITY +#endif + +namespace ExitGames.Client.Photon.Chat +{ + using System; + using System.Collections.Generic; + using ExitGames.Client.Photon; + + #if UNITY || NETFX_CORE + using Hashtable = ExitGames.Client.Photon.Hashtable; + using SupportClass = ExitGames.Client.Photon.SupportClass; + #endif + + + /// Central class of the Photon Chat API to connect, handle channels and messages. + /// + /// This class must be instantiated with a IChatClientListener instance to get the callbacks. + /// Integrate it into your game loop by calling Service regularly. If the target platform supports Threads/Tasks, + /// set UseBackgroundWorkerForSending = true, to let the ChatClient keep the connection by sending from + /// an independent thread. + /// + /// Call Connect with an AppId that is setup as Photon Chat application. Note: Connect covers multiple + /// messages between this client and the servers. A short workflow will connect you to a chat server. + /// + /// Each ChatClient resembles a user in chat (set in Connect). Each user automatically subscribes a channel + /// for incoming private messages and can message any other user privately. + /// Before you publish messages in any non-private channel, that channel must be subscribed. + /// + /// PublicChannels is a list of subscribed channels, containing messages and senders. + /// PrivateChannels contains all incoming and sent private messages. + /// + public class ChatClient : IPhotonPeerListener + { + const int FriendRequestListMax = 1024; + + /// The address of last connected Name Server. + public string NameServerAddress { get; private set; } + + /// The address of the actual chat server assigned from NameServer. Public for read only. + public string FrontendAddress { get; private set; } + + /// Region used to connect to. Currently all chat is done in EU. It can make sense to use only one region for the whole game. + private string chatRegion = "EU"; + + /// Settable only before you connect! Defaults to "EU". + public string ChatRegion + { + get { return this.chatRegion; } + set { this.chatRegion = value; } + } + + /// Current state of the ChatClient. Also use CanChat. + public ChatState State { get; private set; } + + public ChatDisconnectCause DisconnectedCause { get; private set; } + + public bool CanChat + { + get { return this.State == ChatState.ConnectedToFrontEnd && this.HasPeer; } + } + + public bool CanChatInChannel(string channelName) + { + return this.CanChat && this.PublicChannels.ContainsKey(channelName) && !this.PublicChannelsUnsubscribing.Contains(channelName); + } + + private bool HasPeer + { + get { return this.chatPeer != null; } + } + + /// The version of your client. A new version also creates a new "virtual app" to separate players from older client versions. + public string AppVersion { get; private set; } + + /// The AppID as assigned from the Photon Cloud. If you host yourself, this is the "regular" Photon Server Application Name (most likely: "LoadBalancing"). + public string AppId { get; private set; } + + + /// Settable only before you connect! + public AuthenticationValues AuthValues { get; set; } + + /// The unique ID of a user/person, stored in AuthValues.UserId. Set it before you connect. + /// + /// This value wraps AuthValues.UserId. + /// It's not a nickname and we assume users with the same userID are the same person. + public string UserId + { + get + { + return (this.AuthValues != null) ? this.AuthValues.UserId : null; + } + private set + { + if (this.AuthValues == null) + { + this.AuthValues = new AuthenticationValues(); + } + this.AuthValues.UserId = value; + } + } + + /// If greater than 0, new channels will limit the number of messages they cache locally. + /// + /// This can be useful to limit the amount of memory used by chats. + /// You can set a MessageLimit per channel but this value gets applied to new ones. + /// + /// Note: + /// Changing this value, does not affect ChatChannels that are already in use! + /// + public int MessageLimit; + + public readonly Dictionary PublicChannels; + public readonly Dictionary PrivateChannels; + + // channels being in unsubscribing process + // items will be removed on successful unsubscription or subscription (the latter required after attempt to unsubscribe from not existing channel) + private readonly HashSet PublicChannelsUnsubscribing; + + private readonly IChatClientListener listener = null; + public ChatPeer chatPeer = null; + private const string ChatAppName = "chat"; + private bool didAuthenticate; + + private int msDeltaForServiceCalls = 50; + private int msTimestampOfLastServiceCall; + + /// Defines if a background thread will call SendOutgoingCommands, while your code calls Service to dispatch received messages. + /// + /// The benefit of using a background thread to call SendOutgoingCommands is this: + /// + /// Even if your game logic is being paused, the background thread will keep the connection to the server up. + /// On a lower level, acknowledgements and pings will prevent a server-side timeout while (e.g.) Unity loads assets. + /// + /// Your game logic still has to call Service regularly, or else incoming messages are not dispatched. + /// As this typicalls triggers UI updates, it's easier to call Service from the main/UI thread. + /// + public bool UseBackgroundWorkerForSending { get; set; } + + + public ChatClient(IChatClientListener listener, ConnectionProtocol protocol = ConnectionProtocol.Udp) + { + this.listener = listener; + this.State = ChatState.Uninitialized; + + this.chatPeer = new ChatPeer(this, protocol); + + this.PublicChannels = new Dictionary(); + this.PrivateChannels = new Dictionary(); + + this.PublicChannelsUnsubscribing = new HashSet(); + } + + /// + /// Connects this client to the Photon Chat Cloud service, which will also authenticate the user (and set a UserId). + /// + /// Get your Photon Chat AppId from the Dashboard. + /// Any version string you make up. Used to separate users and variants of your clients, which might be incompatible. + /// Values for authentication. You can leave this null, if you set a UserId before. If you set authValues, they will override any UserId set before. + /// + public bool Connect(string appId, string appVersion, AuthenticationValues authValues) + { + this.chatPeer.TimePingInterval = 3000; + this.DisconnectedCause = ChatDisconnectCause.None; + + if (authValues != null) + { + this.AuthValues = authValues; + if (string.IsNullOrEmpty(this.AuthValues.UserId)) + { + if (this.DebugOut >= DebugLevel.ERROR) + { + this.listener.DebugReturn(DebugLevel.ERROR, "Connect failed: no UserId specified in authentication values."); + } + return false; + } + } + else + { + if (this.DebugOut >= DebugLevel.ERROR) + { + this.listener.DebugReturn(DebugLevel.ERROR, "Connect failed: no authentication values specified"); + } + return false; + } + this.AppId = appId; + this.AppVersion = appVersion; + this.didAuthenticate = false; + this.chatPeer.QuickResendAttempts = 2; + this.chatPeer.SentCountAllowance = 7; + + + // clean all channels + this.PublicChannels.Clear(); + this.PrivateChannels.Clear(); + this.PublicChannelsUnsubscribing.Clear(); + + this.NameServerAddress = this.chatPeer.NameServerAddress; + bool isConnecting = this.chatPeer.Connect(); + if (isConnecting) + { + this.State = ChatState.ConnectingToNameServer; + } + + if (this.UseBackgroundWorkerForSending) + { + SupportClass.StartBackgroundCalls(this.SendOutgoingInBackground, this.msDeltaForServiceCalls, "ChatClient Service Thread"); + } + + return isConnecting; + } + + /// + /// Must be called regularly to keep connection between client and server alive and to process incoming messages. + /// + /// + /// This method limits the effort it does automatically using the private variable msDeltaForServiceCalls. + /// That value is lower for connect and multiplied by 4 when chat-server connection is ready. + /// + public void Service() + { + // Dispatch until every already-received message got dispatched + while (this.HasPeer && this.chatPeer.DispatchIncomingCommands()) + { + } + + // if there is no background thread for sending, Service() will do that as well, in intervals + if (!this.UseBackgroundWorkerForSending) + { + if (Environment.TickCount - this.msTimestampOfLastServiceCall > this.msDeltaForServiceCalls || this.msTimestampOfLastServiceCall == 0) + { + this.msTimestampOfLastServiceCall = Environment.TickCount; + + while (this.HasPeer && this.chatPeer.SendOutgoingCommands()) + { + } + } + } + } + + /// + /// Called by a separate thread, this sends outgoing commands of this peer, as long as it's connected. + /// + /// True as long as the client is not disconnected. + private bool SendOutgoingInBackground() + { + while (this.HasPeer && this.chatPeer.SendOutgoingCommands()) + { + } + + return this.State != ChatState.Disconnected; + } + + + [Obsolete("Better use UseBackgroundWorkerForSending and Service().")] + public void SendAcksOnly() + { + if (this.HasPeer) this.chatPeer.SendAcksOnly(); + } + + + /// + /// Disconnects from the Chat Server by sending a "disconnect command", which prevents a timeout server-side. + /// + public void Disconnect() + { + if (this.HasPeer && this.chatPeer.PeerState != PeerStateValue.Disconnected) + { + this.chatPeer.Disconnect(); + } + } + + /// + /// Locally shuts down the connection to the Chat Server. This resets states locally but the server will have to timeout this peer. + /// + public void StopThread() + { + if (this.HasPeer) + { + this.chatPeer.StopThread(); + } + } + + /// Sends operation to subscribe to a list of channels by name. + /// List of channels to subscribe to. Avoid null or empty values. + /// If the operation could be sent at all (Example: Fails if not connected to Chat Server). + public bool Subscribe(string[] channels) + { + return this.Subscribe(channels, 0); + } + + /// + /// Sends operation to subscribe client to channels, optionally fetching a number of messages from the cache. + /// + /// + /// Subscribes channels will forward new messages to this user. Use PublishMessage to do so. + /// The messages cache is limited but can be useful to get into ongoing conversations, if that's needed. + /// + /// List of channels to subscribe to. Avoid null or empty values. + /// 0: no history. 1 and higher: number of messages in history. -1: all available history. + /// If the operation could be sent at all (Example: Fails if not connected to Chat Server). + public bool Subscribe(string[] channels, int messagesFromHistory) + { + if (!this.CanChat) + { + if (this.DebugOut >= DebugLevel.ERROR) + { + this.listener.DebugReturn(DebugLevel.ERROR, "Subscribe called while not connected to front end server."); + } + return false; + } + + if (channels == null || channels.Length == 0) + { + if (this.DebugOut >= DebugLevel.WARNING) + { + this.listener.DebugReturn(DebugLevel.WARNING, "Subscribe can't be called for empty or null channels-list."); + } + return false; + } + + return this.SendChannelOperation(channels, (byte)ChatOperationCode.Subscribe, messagesFromHistory); + } + + /// Unsubscribes from a list of channels, which stops getting messages from those. + /// + /// The client will remove these channels from the PublicChannels dictionary once the server sent a response to this request. + /// + /// The request will be sent to the server and IChatClientListener.OnUnsubscribed gets called when the server + /// actually removed the channel subscriptions. + /// + /// Unsubscribe will fail if you include null or empty channel names. + /// + /// Names of channels to unsubscribe. + /// False, if not connected to a chat server. + public bool Unsubscribe(string[] channels) + { + if (!this.CanChat) + { + if (this.DebugOut >= DebugLevel.ERROR) + { + this.listener.DebugReturn(DebugLevel.ERROR, "Unsubscribe called while not connected to front end server."); + } + return false; + } + + if (channels == null || channels.Length == 0) + { + if (this.DebugOut >= DebugLevel.WARNING) + { + this.listener.DebugReturn(DebugLevel.WARNING, "Unsubscribe can't be called for empty or null channels-list."); + } + return false; + } + + foreach (string ch in channels) + { + this.PublicChannelsUnsubscribing.Add(ch); + } + return this.SendChannelOperation(channels, ChatOperationCode.Unsubscribe, 0); + } + + /// Sends a message to a public channel which this client subscribed to. + /// + /// Before you publish to a channel, you have to subscribe it. + /// Everyone in that channel will get the message. + /// + /// Name of the channel to publish to. + /// Your message (string or any serializable data). + /// Optionally, public messages can be forwarded as webhooks. Configure webhooks for your Chat app to use this. + /// False if the client is not yet ready to send messages. + public bool PublishMessage(string channelName, object message, bool forwardAsWebhook = false) + { + return this.publishMessage(channelName, message, true, forwardAsWebhook); + } + + internal bool PublishMessageUnreliable(string channelName, object message, bool forwardAsWebhook = false) + { + return this.publishMessage(channelName, message, false, forwardAsWebhook); + } + + private bool publishMessage(string channelName, object message, bool reliable, bool forwardAsWebhook = false) + { + if (!this.CanChat) + { + if (this.DebugOut >= DebugLevel.ERROR) + { + this.listener.DebugReturn(DebugLevel.ERROR, "PublishMessage called while not connected to front end server."); + } + return false; + } + + if (string.IsNullOrEmpty(channelName) || message == null) + { + if (this.DebugOut >= DebugLevel.WARNING) + { + this.listener.DebugReturn(DebugLevel.WARNING, "PublishMessage parameters must be non-null and not empty."); + } + return false; + } + + Dictionary parameters = new Dictionary + { + { (byte)ChatParameterCode.Channel, channelName }, + { (byte)ChatParameterCode.Message, message } + }; + if (forwardAsWebhook) + { + parameters.Add(ChatParameterCode.WebFlags, (byte)0x1); + } + return this.chatPeer.OpCustom((byte)ChatOperationCode.Publish, parameters, reliable); + } + + /// + /// Sends a private message to a single target user. Calls OnPrivateMessage on the receiving client. + /// + /// Username to send this message to. + /// The message you want to send. Can be a simple string or anything serializable. + /// Optionally, private messages can be forwarded as webhooks. Configure webhooks for your Chat app to use this. + /// True if this clients can send the message to the server. + public bool SendPrivateMessage(string target, object message, bool forwardAsWebhook = false) + { + return this.SendPrivateMessage(target, message, false, forwardAsWebhook); + } + + /// + /// Sends a private message to a single target user. Calls OnPrivateMessage on the receiving client. + /// + /// Username to send this message to. + /// The message you want to send. Can be a simple string or anything serializable. + /// Optionally, private messages can be encrypted. Encryption is not end-to-end as the server decrypts the message. + /// Optionally, private messages can be forwarded as webhooks. Configure webhooks for your Chat app to use this. + /// True if this clients can send the message to the server. + public bool SendPrivateMessage(string target, object message, bool encrypt, bool forwardAsWebhook) + { + return this.sendPrivateMessage(target, message, encrypt, true, forwardAsWebhook); + } + + internal bool SendPrivateMessageUnreliable(string target, object message, bool encrypt, bool forwardAsWebhook = false) + { + return this.sendPrivateMessage(target, message, encrypt, false, forwardAsWebhook); + } + + private bool sendPrivateMessage(string target, object message, bool encrypt, bool reliable, bool forwardAsWebhook = false) + { + if (!this.CanChat) + { + if (this.DebugOut >= DebugLevel.ERROR) + { + this.listener.DebugReturn(DebugLevel.ERROR, "SendPrivateMessage called while not connected to front end server."); + } + return false; + } + + if (string.IsNullOrEmpty(target) || message == null) + { + if (this.DebugOut >= DebugLevel.WARNING) + { + this.listener.DebugReturn(DebugLevel.WARNING, "SendPrivateMessage parameters must be non-null and not empty."); + } + return false; + } + + Dictionary parameters = new Dictionary + { + { ChatParameterCode.UserId, target }, + { ChatParameterCode.Message, message } + }; + if (forwardAsWebhook) + { + parameters.Add(ChatParameterCode.WebFlags, (byte)0x1); + } + return this.chatPeer.OpCustom((byte)ChatOperationCode.SendPrivate, parameters, reliable, 0, encrypt); + } + + /// Sets the user's status (pre-defined or custom) and an optional message. + /// + /// The predefined status values can be found in class ChatUserStatus. + /// State ChatUserStatus.Invisible will make you offline for everyone and send no message. + /// + /// You can set custom values in the status integer. Aside from the pre-configured ones, + /// all states will be considered visible and online. Else, no one would see the custom state. + /// + /// The message object can be anything that Photon can serialize, including (but not limited to) + /// Hashtable, object[] and string. This value is defined by your own conventions. + /// + /// Predefined states are in class ChatUserStatus. Other values can be used at will. + /// Optional string message or null. + /// If true, the message gets ignored. It can be null but won't replace any current message. + /// True if the operation gets called on the server. + private bool SetOnlineStatus(int status, object message, bool skipMessage) + { + if (!this.CanChat) + { + if (this.DebugOut >= DebugLevel.ERROR) + { + this.listener.DebugReturn(DebugLevel.ERROR, "SetOnlineStatus called while not connected to front end server."); + } + return false; + } + + Dictionary parameters = new Dictionary + { + { ChatParameterCode.Status, status }, + }; + + if (skipMessage) + { + parameters[ChatParameterCode.SkipMessage] = true; + } + else + { + parameters[ChatParameterCode.Message] = message; + } + return this.chatPeer.OpCustom(ChatOperationCode.UpdateStatus, parameters, true); + } + + /// Sets the user's status without changing your status-message. + /// + /// The predefined status values can be found in class ChatUserStatus. + /// State ChatUserStatus.Invisible will make you offline for everyone and send no message. + /// + /// You can set custom values in the status integer. Aside from the pre-configured ones, + /// all states will be considered visible and online. Else, no one would see the custom state. + /// + /// This overload does not change the set message. + /// + /// Predefined states are in class ChatUserStatus. Other values can be used at will. + /// True if the operation gets called on the server. + public bool SetOnlineStatus(int status) + { + return this.SetOnlineStatus(status, null, true); + } + + /// Sets the user's status without changing your status-message. + /// + /// The predefined status values can be found in class ChatUserStatus. + /// State ChatUserStatus.Invisible will make you offline for everyone and send no message. + /// + /// You can set custom values in the status integer. Aside from the pre-configured ones, + /// all states will be considered visible and online. Else, no one would see the custom state. + /// + /// The message object can be anything that Photon can serialize, including (but not limited to) + /// Hashtable, object[] and string. This value is defined by your own conventions. + /// + /// Predefined states are in class ChatUserStatus. Other values can be used at will. + /// Also sets a status-message which your friends can get. + /// True if the operation gets called on the server. + public bool SetOnlineStatus(int status, object message) + { + return this.SetOnlineStatus(status, message, false); + } + + /// + /// Adds friends to a list on the Chat Server which will send you status updates for those. + /// + /// + /// AddFriends and RemoveFriends enable clients to handle their friend list + /// in the Photon Chat server. Having users on your friends list gives you access + /// to their current online status (and whatever info your client sets in it). + /// + /// Each user can set an online status consisting of an integer and an arbitratry + /// (serializable) object. The object can be null, Hashtable, object[] or anything + /// else Photon can serialize. + /// + /// The status is published automatically to friends (anyone who set your user ID + /// with AddFriends). + /// + /// Photon flushes friends-list when a chat client disconnects, so it has to be + /// set each time. If your community API gives you access to online status already, + /// you could filter and set online friends in AddFriends. + /// + /// Actual friend relations are not persistent and have to be stored outside + /// of Photon. + /// + /// Array of friend userIds. + /// If the operation could be sent. + public bool AddFriends(string[] friends) + { + if (!this.CanChat) + { + if (this.DebugOut >= DebugLevel.ERROR) + { + this.listener.DebugReturn(DebugLevel.ERROR, "AddFriends called while not connected to front end server."); + } + return false; + } + + if (friends == null || friends.Length == 0) + { + if (this.DebugOut >= DebugLevel.WARNING) + { + this.listener.DebugReturn(DebugLevel.WARNING, "AddFriends can't be called for empty or null list."); + } + return false; + } + if (friends.Length > FriendRequestListMax) + { + if (this.DebugOut >= DebugLevel.WARNING) + { + this.listener.DebugReturn(DebugLevel.WARNING, "AddFriends max list size exceeded: " + friends.Length + " > " + FriendRequestListMax); + } + return false; + } + + Dictionary parameters = new Dictionary + { + { ChatParameterCode.Friends, friends }, + }; + return this.chatPeer.OpCustom(ChatOperationCode.AddFriends, parameters, true); + } + + /// + /// Removes the provided entries from the list on the Chat Server and stops their status updates. + /// + /// + /// Photon flushes friends-list when a chat client disconnects. Unless you want to + /// remove individual entries, you don't have to RemoveFriends. + /// + /// AddFriends and RemoveFriends enable clients to handle their friend list + /// in the Photon Chat server. Having users on your friends list gives you access + /// to their current online status (and whatever info your client sets in it). + /// + /// Each user can set an online status consisting of an integer and an arbitratry + /// (serializable) object. The object can be null, Hashtable, object[] or anything + /// else Photon can serialize. + /// + /// The status is published automatically to friends (anyone who set your user ID + /// with AddFriends). + /// + /// Photon flushes friends-list when a chat client disconnects, so it has to be + /// set each time. If your community API gives you access to online status already, + /// you could filter and set online friends in AddFriends. + /// + /// Actual friend relations are not persistent and have to be stored outside + /// of Photon. + /// + /// AddFriends and RemoveFriends enable clients to handle their friend list + /// in the Photon Chat server. Having users on your friends list gives you access + /// to their current online status (and whatever info your client sets in it). + /// + /// Each user can set an online status consisting of an integer and an arbitratry + /// (serializable) object. The object can be null, Hashtable, object[] or anything + /// else Photon can serialize. + /// + /// The status is published automatically to friends (anyone who set your user ID + /// with AddFriends). + /// + /// + /// Actual friend relations are not persistent and have to be stored outside + /// of Photon. + /// + /// Array of friend userIds. + /// If the operation could be sent. + public bool RemoveFriends(string[] friends) + { + if (!this.CanChat) + { + if (this.DebugOut >= DebugLevel.ERROR) + { + this.listener.DebugReturn(DebugLevel.ERROR, "RemoveFriends called while not connected to front end server."); + } + return false; + } + + if (friends == null || friends.Length == 0) + { + if (this.DebugOut >= DebugLevel.WARNING) + { + this.listener.DebugReturn(DebugLevel.WARNING, "RemoveFriends can't be called for empty or null list."); + } + return false; + } + if (friends.Length > FriendRequestListMax) + { + if (this.DebugOut >= DebugLevel.WARNING) + { + this.listener.DebugReturn(DebugLevel.WARNING, "RemoveFriends max list size exceeded: " + friends.Length + " > " + FriendRequestListMax); + } + return false; + } + + Dictionary parameters = new Dictionary + { + { ChatParameterCode.Friends, friends }, + }; + return this.chatPeer.OpCustom(ChatOperationCode.RemoveFriends, parameters, true); + } + + /// + /// Get you the (locally used) channel name for the chat between this client and another user. + /// + /// Remote user's name or UserId. + /// The (locally used) channel name for a private channel. + public string GetPrivateChannelNameByUser(string userName) + { + return string.Format("{0}:{1}", this.UserId, userName); + } + + /// + /// Simplified access to either private or public channels by name. + /// + /// Name of the channel to get. For private channels, the channel-name is composed of both user's names. + /// Define if you expect a private or public channel. + /// Out parameter gives you the found channel, if any. + /// True if the channel was found. + public bool TryGetChannel(string channelName, bool isPrivate, out ChatChannel channel) + { + if (!isPrivate) + { + return this.PublicChannels.TryGetValue(channelName, out channel); + } + else + { + return this.PrivateChannels.TryGetValue(channelName, out channel); + } + } + + /// + /// Simplified access to all channels by name. Checks public channels first, then private ones. + /// + /// Name of the channel to get. + /// Out parameter gives you the found channel, if any. + /// True if the channel was found. + public bool TryGetChannel(string channelName, out ChatChannel channel) + { + bool found = false; + found = this.PublicChannels.TryGetValue(channelName, out channel); + if (found) return true; + + found = this.PrivateChannels.TryGetValue(channelName, out channel); + return found; + } + + /// + /// Sets the level (and amount) of debug output provided by the library. + /// + /// + /// This affects the callbacks to IChatClientListener.DebugReturn. + /// Default Level: Error. + /// + public DebugLevel DebugOut + { + set { this.chatPeer.DebugOut = value; } + get { return this.chatPeer.DebugOut; } + } + + #region Private methods area + + #region IPhotonPeerListener implementation + + void IPhotonPeerListener.DebugReturn(DebugLevel level, string message) + { + this.listener.DebugReturn(level, message); + } + + void IPhotonPeerListener.OnEvent(EventData eventData) + { + switch (eventData.Code) + { + case ChatEventCode.ChatMessages: + this.HandleChatMessagesEvent(eventData); + break; + case ChatEventCode.PrivateMessage: + this.HandlePrivateMessageEvent(eventData); + break; + case ChatEventCode.StatusUpdate: + this.HandleStatusUpdate(eventData); + break; + case ChatEventCode.Subscribe: + this.HandleSubscribeEvent(eventData); + break; + case ChatEventCode.Unsubscribe: + this.HandleUnsubscribeEvent(eventData); + break; + } + } + + void IPhotonPeerListener.OnOperationResponse(OperationResponse operationResponse) + { + switch (operationResponse.OperationCode) + { + case (byte)ChatOperationCode.Authenticate: + this.HandleAuthResponse(operationResponse); + break; + + // the following operations usually don't return useful data and no error. + case (byte)ChatOperationCode.Subscribe: + case (byte)ChatOperationCode.Unsubscribe: + case (byte)ChatOperationCode.Publish: + case (byte)ChatOperationCode.SendPrivate: + default: + if ((operationResponse.ReturnCode != 0) && (this.DebugOut >= DebugLevel.ERROR)) + { + if (operationResponse.ReturnCode == -2) + { + this.listener.DebugReturn(DebugLevel.ERROR, string.Format("Chat Operation {0} unknown on server. Check your AppId and make sure it's for a Chat application.", operationResponse.OperationCode)); + } + else + { + this.listener.DebugReturn(DebugLevel.ERROR, string.Format("Chat Operation {0} failed (Code: {1}). Debug Message: {2}", operationResponse.OperationCode, operationResponse.ReturnCode, operationResponse.DebugMessage)); + } + } + break; + } + } + + void IPhotonPeerListener.OnStatusChanged(StatusCode statusCode) + { + switch (statusCode) + { + case StatusCode.Connect: + if (!this.chatPeer.IsProtocolSecure) + { + this.chatPeer.EstablishEncryption(); + } + else + { + if (!this.didAuthenticate) + { + this.didAuthenticate = this.chatPeer.AuthenticateOnNameServer(this.AppId, this.AppVersion, this.chatRegion, this.AuthValues); + if (!this.didAuthenticate) + { + if (this.DebugOut >= DebugLevel.ERROR) + { + ((IPhotonPeerListener)this).DebugReturn(DebugLevel.ERROR, "Error calling OpAuthenticate! Did not work. Check log output, AuthValues and if you're connected. State: " + this.State); + } + } + } + } + + if (this.State == ChatState.ConnectingToNameServer) + { + this.State = ChatState.ConnectedToNameServer; + this.listener.OnChatStateChange(this.State); + } + else if (this.State == ChatState.ConnectingToFrontEnd) + { + this.AuthenticateOnFrontEnd(); + } + break; + case StatusCode.EncryptionEstablished: + // once encryption is availble, the client should send one (secure) authenticate. it includes the AppId (which identifies your app on the Photon Cloud) + if (!this.didAuthenticate) + { + this.didAuthenticate = this.chatPeer.AuthenticateOnNameServer(this.AppId, this.AppVersion, this.chatRegion, this.AuthValues); + if (!this.didAuthenticate) + { + if (this.DebugOut >= DebugLevel.ERROR) + { + ((IPhotonPeerListener)this).DebugReturn(DebugLevel.ERROR, "Error calling OpAuthenticate! Did not work. Check log output, AuthValues and if you're connected. State: " + this.State); + } + } + } + break; + case StatusCode.EncryptionFailedToEstablish: + this.State = ChatState.Disconnecting; + this.chatPeer.Disconnect(); + break; + case StatusCode.Disconnect: + if (this.State == ChatState.Authenticated) + { + this.ConnectToFrontEnd(); + } + else + { + this.State = ChatState.Disconnected; + this.listener.OnChatStateChange(ChatState.Disconnected); + this.listener.OnDisconnected(); + } + break; + } + } + + #if SDK_V4 + void IPhotonPeerListener.OnMessage(object msg) + { + // in v4 interface IPhotonPeerListener + return; + } + #endif + + #endregion + + private bool SendChannelOperation(string[] channels, byte operation, int historyLength) + { + Dictionary opParameters = new Dictionary { { (byte)ChatParameterCode.Channels, channels } }; + + if (historyLength != 0) + { + opParameters.Add((byte)ChatParameterCode.HistoryLength, historyLength); + } + + return this.chatPeer.OpCustom(operation, opParameters, true); + } + + private void HandlePrivateMessageEvent(EventData eventData) + { + //Console.WriteLine(SupportClass.DictionaryToString(eventData.Parameters)); + + object message = (object)eventData.Parameters[(byte)ChatParameterCode.Message]; + string sender = (string)eventData.Parameters[(byte)ChatParameterCode.Sender]; + + string channelName; + if (this.UserId != null && this.UserId.Equals(sender)) + { + string target = (string)eventData.Parameters[(byte)ChatParameterCode.UserId]; + channelName = this.GetPrivateChannelNameByUser(target); + } + else + { + channelName = this.GetPrivateChannelNameByUser(sender); + } + + ChatChannel channel; + if (!this.PrivateChannels.TryGetValue(channelName, out channel)) + { + channel = new ChatChannel(channelName); + channel.IsPrivate = true; + channel.MessageLimit = this.MessageLimit; + this.PrivateChannels.Add(channel.Name, channel); + } + + channel.Add(sender, message); + this.listener.OnPrivateMessage(sender, message, channelName); + } + + private void HandleChatMessagesEvent(EventData eventData) + { + object[] messages = (object[])eventData.Parameters[(byte)ChatParameterCode.Messages]; + string[] senders = (string[])eventData.Parameters[(byte)ChatParameterCode.Senders]; + string channelName = (string)eventData.Parameters[(byte)ChatParameterCode.Channel]; + + ChatChannel channel; + if (!this.PublicChannels.TryGetValue(channelName, out channel)) + { + if (this.DebugOut >= DebugLevel.WARNING) + { + this.listener.DebugReturn(DebugLevel.WARNING, "Channel " + channelName + " for incoming message event not found."); + } + return; + } + + channel.Add(senders, messages); + this.listener.OnGetMessages(channelName, senders, messages); + } + + private void HandleSubscribeEvent(EventData eventData) + { + string[] channelsInResponse = (string[])eventData.Parameters[ChatParameterCode.Channels]; + bool[] results = (bool[])eventData.Parameters[ChatParameterCode.SubscribeResults]; + + for (int i = 0; i < channelsInResponse.Length; i++) + { + if (results[i]) + { + string channelName = channelsInResponse[i]; + if (!this.PublicChannels.ContainsKey(channelName)) + { + ChatChannel channel = new ChatChannel(channelName); + channel.MessageLimit = this.MessageLimit; + this.PublicChannels.Add(channel.Name, channel); + } + } + } + + this.listener.OnSubscribed(channelsInResponse, results); + } + + private void HandleUnsubscribeEvent(EventData eventData) + { + string[] channelsInRequest = (string[])eventData[ChatParameterCode.Channels]; + for (int i = 0; i < channelsInRequest.Length; i++) + { + string channelName = channelsInRequest[i]; + this.PublicChannels.Remove(channelName); + this.PublicChannelsUnsubscribing.Remove(channelName); + } + + this.listener.OnUnsubscribed(channelsInRequest); + } + + private void HandleAuthResponse(OperationResponse operationResponse) + { + if (this.DebugOut >= DebugLevel.INFO) + { + this.listener.DebugReturn(DebugLevel.INFO, operationResponse.ToStringFull() + " on: " + this.chatPeer.NameServerAddress); + } + + if (operationResponse.ReturnCode == 0) + { + if (this.State == ChatState.ConnectedToNameServer) + { + this.State = ChatState.Authenticated; + this.listener.OnChatStateChange(this.State); + + if (operationResponse.Parameters.ContainsKey(ParameterCode.Secret)) + { + if (this.AuthValues == null) + { + this.AuthValues = new AuthenticationValues(); + } + this.AuthValues.Token = operationResponse[ParameterCode.Secret] as string; + this.FrontendAddress = (string)operationResponse[ParameterCode.Address]; + + // we disconnect and status handler starts to connect to front end + this.chatPeer.Disconnect(); + } + else + { + if (this.DebugOut >= DebugLevel.ERROR) + { + this.listener.DebugReturn(DebugLevel.ERROR, "No secret in authentication response."); + } + } + } + else if (this.State == ChatState.ConnectingToFrontEnd) + { + this.State = ChatState.ConnectedToFrontEnd; + this.listener.OnChatStateChange(this.State); + this.listener.OnConnected(); + } + } + else + { + //this.listener.DebugReturn(DebugLevel.INFO, operationResponse.ToStringFull() + " NS: " + this.NameServerAddress + " FrontEnd: " + this.frontEndAddress); + + switch (operationResponse.ReturnCode) + { + case ErrorCode.InvalidAuthentication: + this.DisconnectedCause = ChatDisconnectCause.InvalidAuthentication; + break; + case ErrorCode.CustomAuthenticationFailed: + this.DisconnectedCause = ChatDisconnectCause.CustomAuthenticationFailed; + break; + case ErrorCode.InvalidRegion: + this.DisconnectedCause = ChatDisconnectCause.InvalidRegion; + break; + case ErrorCode.MaxCcuReached: + this.DisconnectedCause = ChatDisconnectCause.MaxCcuReached; + break; + case ErrorCode.OperationNotAllowedInCurrentState: + this.DisconnectedCause = ChatDisconnectCause.OperationNotAllowedInCurrentState; + break; + } + + if (this.DebugOut >= DebugLevel.ERROR) + { + this.listener.DebugReturn(DebugLevel.ERROR, "Authentication request error: " + operationResponse.ReturnCode + ". Disconnecting."); + } + + + this.State = ChatState.Disconnecting; + this.chatPeer.Disconnect(); + } + } + + private void HandleStatusUpdate(EventData eventData) + { + string user = (string)eventData.Parameters[ChatParameterCode.Sender]; + int status = (int)eventData.Parameters[ChatParameterCode.Status]; + + object message = null; + bool gotMessage = eventData.Parameters.ContainsKey(ChatParameterCode.Message); + if (gotMessage) + { + message = eventData.Parameters[ChatParameterCode.Message]; + } + + this.listener.OnStatusUpdate(user, status, gotMessage, message); + } + + private void ConnectToFrontEnd() + { + this.State = ChatState.ConnectingToFrontEnd; + + if (this.DebugOut >= DebugLevel.INFO) + { + this.listener.DebugReturn(DebugLevel.INFO, "Connecting to frontend " + this.FrontendAddress); + } + + this.chatPeer.Connect(this.FrontendAddress, ChatAppName); + } + + private bool AuthenticateOnFrontEnd() + { + if (this.AuthValues != null) + { + if (this.AuthValues.Token == null || this.AuthValues.Token == "") + { + if (this.DebugOut >= DebugLevel.ERROR) + { + this.listener.DebugReturn(DebugLevel.ERROR, "Can't authenticate on front end server. Secret is not set"); + } + return false; + } + else + { + Dictionary opParameters = new Dictionary { { (byte)ChatParameterCode.Secret, this.AuthValues.Token } }; + return this.chatPeer.OpCustom((byte)ChatOperationCode.Authenticate, opParameters, true); + } + } + else + { + if (this.DebugOut >= DebugLevel.ERROR) + { + this.listener.DebugReturn(DebugLevel.ERROR, "Can't authenticate on front end server. Authentication Values are not set"); + } + return false; + } + } + + #endregion + } +} diff --git a/Assets/PhotonChatApi/ChatClient.cs.meta b/Assets/PhotonChatApi/ChatClient.cs.meta new file mode 100644 index 0000000..0a1bea9 --- /dev/null +++ b/Assets/PhotonChatApi/ChatClient.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 692e391fa2a297c45b3d530aa85be610 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/PhotonChatApi/ChatDisconnectCause.cs b/Assets/PhotonChatApi/ChatDisconnectCause.cs new file mode 100644 index 0000000..1b56f41 --- /dev/null +++ b/Assets/PhotonChatApi/ChatDisconnectCause.cs @@ -0,0 +1,36 @@ +// ---------------------------------------------------------------------------------------------------------------------- +// The Photon Chat Api enables clients to connect to a chat server and communicate with other clients. +// ChatClient is the main class of this api. +// Photon Chat Api - Copyright (C) 2014 Exit Games GmbH +// ---------------------------------------------------------------------------------------------------------------------- + +namespace ExitGames.Client.Photon.Chat +{ + /// Enumaration of causes for Disconnects (used in LoadBalancingClient.DisconnectedCause). + /// Read the individual descriptions to find out what to do about this type of disconnect. + public enum ChatDisconnectCause + { + /// No error was tracked. + None, + /// OnStatusChanged: The CCUs count of your Photon Server License is exausted (temporarily). + DisconnectByServerUserLimit, + /// OnStatusChanged: The server is not available or the address is wrong. Make sure the port is provided and the server is up. + ExceptionOnConnect, + /// OnStatusChanged: The server disconnected this client. Most likely the server's send buffer is full (receiving too much from other clients). + DisconnectByServer, + /// OnStatusChanged: This client detected that the server's responses are not received in due time. Maybe you send / receive too much? + TimeoutDisconnect, + /// OnStatusChanged: Some internal exception caused the socket code to fail. Contact Exit Games. + Exception, + /// OnOperationResponse: Authenticate in the Photon Cloud with invalid AppId. Update your subscription or contact Exit Games. + InvalidAuthentication, + /// OnOperationResponse: Authenticate (temporarily) failed when using a Photon Cloud subscription without CCU Burst. Update your subscription. + MaxCcuReached, + /// OnOperationResponse: Authenticate when the app's Photon Cloud subscription is locked to some (other) region(s). Update your subscription or master server address. + InvalidRegion, + /// OnOperationResponse: Operation that's (currently) not available for this client (not authorized usually). Only tracked for op Authenticate. + OperationNotAllowedInCurrentState, + /// OnOperationResponse: Authenticate in the Photon Cloud with invalid client values or custom authentication setup in Cloud Dashboard. + CustomAuthenticationFailed, + } +} \ No newline at end of file diff --git a/Assets/PhotonChatApi/ChatDisconnectCause.cs.meta b/Assets/PhotonChatApi/ChatDisconnectCause.cs.meta new file mode 100644 index 0000000..c1f0c5b --- /dev/null +++ b/Assets/PhotonChatApi/ChatDisconnectCause.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b90b85043f1857f43b94fd00edfc1ef1 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/PhotonChatApi/ChatEventCode.cs b/Assets/PhotonChatApi/ChatEventCode.cs new file mode 100644 index 0000000..ea58a4a --- /dev/null +++ b/Assets/PhotonChatApi/ChatEventCode.cs @@ -0,0 +1,22 @@ +// ---------------------------------------------------------------------------------------------------------------------- +// The Photon Chat Api enables clients to connect to a chat server and communicate with other clients. +// ChatClient is the main class of this api. +// Photon Chat Api - Copyright (C) 2014 Exit Games GmbH +// ---------------------------------------------------------------------------------------------------------------------- + +namespace ExitGames.Client.Photon.Chat +{ + /// + /// Wraps up internally used constants in Photon Chat events. You don't have to use them directly usually. + /// + public class ChatEventCode + { + public const byte ChatMessages = 0; + public const byte Users = 1;// List of users or List of changes for List of users + public const byte PrivateMessage = 2; + public const byte FriendsList = 3; + public const byte StatusUpdate = 4; + public const byte Subscribe = 5; + public const byte Unsubscribe = 6; + } +} diff --git a/Assets/PhotonChatApi/ChatEventCode.cs.meta b/Assets/PhotonChatApi/ChatEventCode.cs.meta new file mode 100644 index 0000000..4c0b2e6 --- /dev/null +++ b/Assets/PhotonChatApi/ChatEventCode.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 188e4a680bce12d4cbad8d57a24f7d44 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/PhotonChatApi/ChatOperationCode.cs b/Assets/PhotonChatApi/ChatOperationCode.cs new file mode 100644 index 0000000..4a716fa --- /dev/null +++ b/Assets/PhotonChatApi/ChatOperationCode.cs @@ -0,0 +1,36 @@ +// ---------------------------------------------------------------------------------------------------------------------- +// The Photon Chat Api enables clients to connect to a chat server and communicate with other clients. +// ChatClient is the main class of this api. +// Photon Chat Api - Copyright (C) 2014 Exit Games GmbH +// ---------------------------------------------------------------------------------------------------------------------- + +namespace ExitGames.Client.Photon.Chat +{ + /// + /// Wraps up codes for operations used internally in Photon Chat. You don't have to use them directly usually. + /// + public class ChatOperationCode + { + /// (230) Operation Authenticate. + public const byte Authenticate = 230; + + /// (0) Operation to subscribe to chat channels. + public const byte Subscribe = 0; + /// (1) Operation to unsubscribe from chat channels. + public const byte Unsubscribe = 1; + /// (2) Operation to publish a message in a chat channel. + public const byte Publish = 2; + /// (3) Operation to send a private message to some other user. + public const byte SendPrivate = 3; + + /// (4) Not used yet. + public const byte ChannelHistory = 4; + + /// (5) Set your (client's) status. + public const byte UpdateStatus = 5; + /// (6) Add friends the list of friends that should update you of their status. + public const byte AddFriends = 6; + /// (7) Remove friends from list of friends that should update you of their status. + public const byte RemoveFriends = 7; + } +} \ No newline at end of file diff --git a/Assets/PhotonChatApi/ChatOperationCode.cs.meta b/Assets/PhotonChatApi/ChatOperationCode.cs.meta new file mode 100644 index 0000000..0375688 --- /dev/null +++ b/Assets/PhotonChatApi/ChatOperationCode.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: c90a2a73f3ce648409739c724d3e6cef +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/PhotonChatApi/ChatParameterCode.cs b/Assets/PhotonChatApi/ChatParameterCode.cs new file mode 100644 index 0000000..46f776e --- /dev/null +++ b/Assets/PhotonChatApi/ChatParameterCode.cs @@ -0,0 +1,52 @@ +// ---------------------------------------------------------------------------------------------------------------------- +// The Photon Chat Api enables clients to connect to a chat server and communicate with other clients. +// ChatClient is the main class of this api. +// Photon Chat Api - Copyright (C) 2014 Exit Games GmbH +// ---------------------------------------------------------------------------------------------------------------------- + +namespace ExitGames.Client.Photon.Chat +{ + /// + /// Wraps up codes for parameters (in operations and events) used internally in Photon Chat. You don't have to use them directly usually. + /// + public class ChatParameterCode + { + /// (0) Array of chat channels. + public const byte Channels = 0; + /// (1) Name of a single chat channel. + public const byte Channel = 1; + /// (2) Array of chat messages. + public const byte Messages = 2; + /// (3) A single chat message. + public const byte Message = 3; + /// (4) Array of names of the users who sent the array of chat mesages. + public const byte Senders = 4; + /// (5) Name of a the user who sent a chat message. + public const byte Sender = 5; + /// (6) Not used. + public const byte ChannelUserCount = 6; + /// (225) Name of user to send a (private) message to.The code is used in LoadBalancing and copied over here. + public const byte UserId = 225; + /// (8) Id of a message. + public const byte MsgId = 8; + /// (9) Not used. + public const byte MsgIds = 9; + /// (221) Secret token to identify an authorized user.The code is used in LoadBalancing and copied over here. + public const byte Secret = 221; + /// (15) Subscribe operation result parameter. A bool[] with result per channel. + public const byte SubscribeResults = 15; + + /// (10) Status + public const byte Status = 10; + /// (11) Friends + public const byte Friends = 11; + /// (12) SkipMessage is used in SetOnlineStatus and if true, the message is not being broadcast. + public const byte SkipMessage = 12; + + /// (14) Number of message to fetch from history. 0: no history. 1 and higher: number of messages in history. -1: all history. + public const byte HistoryLength = 14; + + /// (21) WebFlags object for changing behaviour of webhooks from client. + public const byte WebFlags = 21; + } +} \ No newline at end of file diff --git a/Assets/PhotonChatApi/ChatParameterCode.cs.meta b/Assets/PhotonChatApi/ChatParameterCode.cs.meta new file mode 100644 index 0000000..b0d8707 --- /dev/null +++ b/Assets/PhotonChatApi/ChatParameterCode.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d7a17b60c85fb30448492e397c58c7ce +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/PhotonChatApi/ChatPeer.cs b/Assets/PhotonChatApi/ChatPeer.cs new file mode 100644 index 0000000..61ea659 --- /dev/null +++ b/Assets/PhotonChatApi/ChatPeer.cs @@ -0,0 +1,399 @@ +// ---------------------------------------------------------------------------------------------------------------------- +// The Photon Chat Api enables clients to connect to a chat server and communicate with other clients. +// ChatClient is the main class of this api. +// Photon Chat Api - Copyright (C) 2014 Exit Games GmbH +// ---------------------------------------------------------------------------------------------------------------------- + +#if UNITY_4_7 || UNITY_5 || UNITY_5_0 || UNITY_5_1 || UNITY_6_0 +#define UNITY +#endif + +namespace ExitGames.Client.Photon.Chat +{ + using System; + using System.Diagnostics; + using System.Collections.Generic; + using ExitGames.Client.Photon; + + #if UNITY || NETFX_CORE + using Hashtable = ExitGames.Client.Photon.Hashtable; + using SupportClass = ExitGames.Client.Photon.SupportClass; + #endif + + + /// + /// Provides basic operations of the Photon Chat server. This internal class is used by public ChatClient. + /// + public class ChatPeer : PhotonPeer + { + /// Name Server Host Name for Photon Cloud. Without port and without any prefix. + public const string NameServerHost = "ns.exitgames.com"; + + /// Name Server for HTTP connections to the Photon Cloud. Includes prefix and port. + public const string NameServerHttp = "http://ns.exitgamescloud.com:80/photon/n"; + + /// Name Server port per protocol (the UDP port is different than TCP, etc). + private static readonly Dictionary ProtocolToNameServerPort = new Dictionary() { { ConnectionProtocol.Udp, 5058 }, { ConnectionProtocol.Tcp, 4533 }, { ConnectionProtocol.WebSocket, 9093 }, { ConnectionProtocol.WebSocketSecure, 19093 } }; //, { ConnectionProtocol.RHttp, 6063 } }; + + /// Name Server Address for Photon Cloud (based on current protocol). You can use the default values and usually won't have to set this value. + public string NameServerAddress { get { return this.GetNameServerAddress(); } } + + virtual internal bool IsProtocolSecure { get { return this.UsedProtocol == ConnectionProtocol.WebSocketSecure; } } + + + public ChatPeer(IPhotonPeerListener listener, ConnectionProtocol protocol) : base(listener, protocol) + { + this.ConfigUnitySockets(); + } + + + [Conditional("UNITY")] + private void ConfigUnitySockets() + { + #pragma warning disable 0162 // the library variant defines if we should use PUN's SocketUdp variant (at all) + if (PhotonPeer.NoSocket) + { + #if !UNITY_EDITOR && (UNITY_PS3 || UNITY_ANDROID) + this.SocketImplementationConfig[ConnectionProtocol.Udp] = typeof(SocketUdpNativeDynamic); + #elif !UNITY_EDITOR && UNITY_IPHONE + this.SocketImplementationConfig[ConnectionProtocol.Udp] = typeof(SocketUdpNativeStatic); + #elif !UNITY_EDITOR && (UNITY_WINRT) + // this automatically uses a separate assembly-file with Win8-style Socket usage (not possible in Editor) + #else + Type udpSocket = Type.GetType("ExitGames.Client.Photon.SocketUdp, Assembly-CSharp"); + this.SocketImplementationConfig[ConnectionProtocol.Udp] = udpSocket; + if (udpSocket == null) + { + #if UNITY + UnityEngine.Debug.Log("Could not find a suitable C# socket class. This Photon3Unity3D.dll only supports native socket plugins."); + #endif + } + #endif + } + #pragma warning restore 0162 + + + #if UNITY_WEBGL + if (this.TransportProtocol != ConnectionProtocol.WebSocket && this.TransportProtocol != ConnectionProtocol.WebSocketSecure) + { + UnityEngine.Debug.Log("For UNITY_WEBGL, use protocol WebSocketSecure. Overriding currently set protcol " + this.TransportProtocol + "."); + this.TransportProtocol = ConnectionProtocol.WebSocketSecure; + } + #endif + + + // to support WebGL export in Unity, we find and assign the SocketWebTcp class (if it's in the project). + // alternatively class SocketWebTcp might be in the Photon3Unity3D.dll + Type socketTcp = Type.GetType("ExitGames.Client.Photon.SocketWebTcp, Assembly-CSharp", false); + if (socketTcp == null) + { + socketTcp = Type.GetType("ExitGames.Client.Photon.SocketWebTcp, Assembly-CSharp-firstpass", false); + } + if (socketTcp != null) + { + this.SocketImplementationConfig[ConnectionProtocol.WebSocket] = socketTcp; + this.SocketImplementationConfig[ConnectionProtocol.WebSocketSecure] = socketTcp; + } + } + + + /// + /// Gets the NameServer Address (with prefix and port), based on the set protocol (this.UsedProtocol). + /// + /// NameServer Address (with prefix and port). + private string GetNameServerAddress() + { + var protocolPort = 0; + ProtocolToNameServerPort.TryGetValue(this.TransportProtocol, out protocolPort); + + switch (this.TransportProtocol) + { + case ConnectionProtocol.Udp: + case ConnectionProtocol.Tcp: + return string.Format("{0}:{1}", NameServerHost, protocolPort); + #if RHTTP + case ConnectionProtocol.RHttp: + return NameServerHttp; + #endif + case ConnectionProtocol.WebSocket: + return string.Format("ws://{0}:{1}", NameServerHost, protocolPort); + case ConnectionProtocol.WebSocketSecure: + return string.Format("wss://{0}:{1}", NameServerHost, protocolPort); + default: + throw new ArgumentOutOfRangeException(); + } + } + + public bool Connect() + { + if (this.DebugOut >= DebugLevel.INFO) + { + this.Listener.DebugReturn(DebugLevel.INFO, "Connecting to nameserver " + this.NameServerAddress); + } + + return this.Connect(this.NameServerAddress, "NameServer"); + } + + public bool AuthenticateOnNameServer(string appId, string appVersion, string region, AuthenticationValues authValues) + { + if (this.DebugOut >= DebugLevel.INFO) + { + this.Listener.DebugReturn(DebugLevel.INFO, "OpAuthenticate()"); + } + + var opParameters = new Dictionary(); + + opParameters[ParameterCode.AppVersion] = appVersion; + opParameters[ParameterCode.ApplicationId] = appId; + opParameters[ParameterCode.Region] = region; + + if (authValues != null) + { + if (!string.IsNullOrEmpty(authValues.UserId)) + { + opParameters[ParameterCode.UserId] = authValues.UserId; + } + + if (authValues != null && authValues.AuthType != CustomAuthenticationType.None) + { + opParameters[ParameterCode.ClientAuthenticationType] = (byte) authValues.AuthType; + if (!string.IsNullOrEmpty(authValues.Token)) + { + opParameters[ParameterCode.Secret] = authValues.Token; + } + else + { + if (!string.IsNullOrEmpty(authValues.AuthGetParameters)) + { + opParameters[ParameterCode.ClientAuthenticationParams] = authValues.AuthGetParameters; + } + if (authValues.AuthPostData != null) + { + opParameters[ParameterCode.ClientAuthenticationData] = authValues.AuthPostData; + } + } + } + } + + return this.OpCustom((byte)ChatOperationCode.Authenticate, opParameters, true, (byte)0, this.IsEncryptionAvailable); + } + } + + /// + /// Options for optional "Custom Authentication" services used with Photon. Used by OpAuthenticate after connecting to Photon. + /// + public enum CustomAuthenticationType : byte + { + /// Use a custom authentification service. Currently the only implemented option. + Custom = 0, + + /// Authenticates users by their Steam Account. Set auth values accordingly! + Steam = 1, + + /// Authenticates users by their Facebook Account. Set auth values accordingly! + Facebook = 2, + + /// Authenticates users by their Oculus Account and token. + Oculus = 3, + + /// Authenticates users by their PSN Account and token. + PlayStation = 4, + + /// Authenticates users by their Xbox Account and XSTS token. + Xbox = 5, + + /// Disables custom authentification. Same as not providing any AuthenticationValues for connect (more precisely for: OpAuthenticate). + None = byte.MaxValue + } + + + + /// + /// Container for user authentication in Photon. Set AuthValues before you connect - all else is handled. + /// + /// + /// On Photon, user authentication is optional but can be useful in many cases. + /// If you want to FindFriends, a unique ID per user is very practical. + /// + /// There are basically three options for user authentification: None at all, the client sets some UserId + /// or you can use some account web-service to authenticate a user (and set the UserId server-side). + /// + /// Custom Authentication lets you verify end-users by some kind of login or token. It sends those + /// values to Photon which will verify them before granting access or disconnecting the client. + /// + /// The Photon Cloud Dashboard will let you enable this feature and set important server values for it. + /// https://www.photonengine.com/dashboard + /// + public class AuthenticationValues + { + /// See AuthType. + private CustomAuthenticationType authType = CustomAuthenticationType.None; + + /// The type of custom authentication provider that should be used. Currently only "Custom" or "None" (turns this off). + public CustomAuthenticationType AuthType + { + get { return authType; } + set { authType = value; } + } + + /// This string must contain any (http get) parameters expected by the used authentication service. By default, username and token. + /// Standard http get parameters are used here and passed on to the service that's defined in the server (Photon Cloud Dashboard). + public string AuthGetParameters { get; set; } + + /// Data to be passed-on to the auth service via POST. Default: null (not sent). Either string or byte[] (see setters). + public object AuthPostData { get; private set; } + + /// After initial authentication, Photon provides a token for this client / user, which is subsequently used as (cached) validation. + public string Token { get; set; } + + /// The UserId should be a unique identifier per user. This is for finding friends, etc.. + public string UserId { get; set; } + + + /// Creates empty auth values without any info. + public AuthenticationValues() + { + } + + /// Creates minimal info about the user. If this is authenticated or not, depends on the set AuthType. + /// Some UserId to set in Photon. + public AuthenticationValues(string userId) + { + this.UserId = userId; + } + + /// Sets the data to be passed-on to the auth service via POST. + /// String data to be used in the body of the POST request. Null or empty string will set AuthPostData to null. + public virtual void SetAuthPostData(string stringData) + { + this.AuthPostData = (string.IsNullOrEmpty(stringData)) ? null : stringData; + } + + /// Sets the data to be passed-on to the auth service via POST. + /// Binary token / auth-data to pass on. + public virtual void SetAuthPostData(byte[] byteData) + { + this.AuthPostData = byteData; + } + + /// Adds a key-value pair to the get-parameters used for Custom Auth. + /// This method does uri-encoding for you. + /// Key for the value to set. + /// Some value relevant for Custom Authentication. + public virtual void AddAuthParameter(string key, string value) + { + string ampersand = string.IsNullOrEmpty(this.AuthGetParameters) ? "" : "&"; + this.AuthGetParameters = string.Format("{0}{1}{2}={3}", this.AuthGetParameters, ampersand, System.Uri.EscapeDataString(key), System.Uri.EscapeDataString(value)); + } + + public override string ToString() + { + return string.Format("AuthenticationValues UserId: {0}, GetParameters: {1} Token available: {2}", UserId, this.AuthGetParameters, Token != null); + } + } + + + public class ParameterCode + { + public const byte ApplicationId = 224; + /// (221) Internally used to establish encryption + public const byte Secret = 221; + public const byte AppVersion = 220; + /// (217) This key's (byte) value defines the target custom authentication type/service the client connects with. Used in OpAuthenticate + public const byte ClientAuthenticationType = 217; + + /// (216) This key's (string) value provides parameters sent to the custom authentication type/service the client connects with. Used in OpAuthenticate + public const byte ClientAuthenticationParams = 216; + + /// (214) This key's (string or byte[]) value provides parameters sent to the custom authentication service setup in Photon Dashboard. Used in OpAuthenticate + public const byte ClientAuthenticationData = 214; + /// (210) Used for region values in OpAuth and OpGetRegions. + public const byte Region = 210; + /// (230) Address of a (game) server to use. + public const byte Address = 230; + /// (225) User's ID + public const byte UserId = 225; + } + /// + /// ErrorCode defines the default codes associated with Photon client/server communication. + /// + public class ErrorCode + { + /// (0) is always "OK", anything else an error or specific situation. + public const int Ok = 0; + + // server - Photon low(er) level: <= 0 + + /// + /// (-3) Operation can't be executed yet (e.g. OpJoin can't be called before being authenticated, RaiseEvent cant be used before getting into a room). + /// + /// + /// Before you call any operations on the Cloud servers, the automated client workflow must complete its authorization. + /// In PUN, wait until State is: JoinedLobby (with AutoJoinLobby = true) or ConnectedToMaster (AutoJoinLobby = false) + /// + public const int OperationNotAllowedInCurrentState = -3; + + /// (-2) The operation you called is not implemented on the server (application) you connect to. Make sure you run the fitting applications. + public const int InvalidOperationCode = -2; + + /// (-1) Something went wrong in the server. Try to reproduce and contact Exit Games. + public const int InternalServerError = -1; + + // server - PhotonNetwork: 0x7FFF and down + // logic-level error codes start with short.max + + /// (32767) Authentication failed. Possible cause: AppId is unknown to Photon (in cloud service). + public const int InvalidAuthentication = 0x7FFF; + + /// (32766) GameId (name) already in use (can't create another). Change name. + public const int GameIdAlreadyExists = 0x7FFF - 1; + + /// (32765) Game is full. This rarely happens when some player joined the room before your join completed. + public const int GameFull = 0x7FFF - 2; + + /// (32764) Game is closed and can't be joined. Join another game. + public const int GameClosed = 0x7FFF - 3; + + /// (32762) Not in use currently. + public const int ServerFull = 0x7FFF - 5; + + /// (32761) Not in use currently. + public const int UserBlocked = 0x7FFF - 6; + + /// (32760) Random matchmaking only succeeds if a room exists thats neither closed nor full. Repeat in a few seconds or create a new room. + public const int NoRandomMatchFound = 0x7FFF - 7; + + /// (32758) Join can fail if the room (name) is not existing (anymore). This can happen when players leave while you join. + public const int GameDoesNotExist = 0x7FFF - 9; + + /// (32757) Authorization on the Photon Cloud failed becaus the concurrent users (CCU) limit of the app's subscription is reached. + /// + /// Unless you have a plan with "CCU Burst", clients might fail the authentication step during connect. + /// Affected client are unable to call operations. Please note that players who end a game and return + /// to the master server will disconnect and re-connect, which means that they just played and are rejected + /// in the next minute / re-connect. + /// This is a temporary measure. Once the CCU is below the limit, players will be able to connect an play again. + /// + /// OpAuthorize is part of connection workflow but only on the Photon Cloud, this error can happen. + /// Self-hosted Photon servers with a CCU limited license won't let a client connect at all. + /// + public const int MaxCcuReached = 0x7FFF - 10; + + /// (32756) Authorization on the Photon Cloud failed because the app's subscription does not allow to use a particular region's server. + /// + /// Some subscription plans for the Photon Cloud are region-bound. Servers of other regions can't be used then. + /// Check your master server address and compare it with your Photon Cloud Dashboard's info. + /// https://cloud.photonengine.com/dashboard + /// + /// OpAuthorize is part of connection workflow but only on the Photon Cloud, this error can happen. + /// Self-hosted Photon servers with a CCU limited license won't let a client connect at all. + /// + public const int InvalidRegion = 0x7FFF - 11; + + /// + /// (32755) Custom Authentication of the user failed due to setup reasons (see Cloud Dashboard) or the provided user data (like username or token). Check error message for details. + /// + public const int CustomAuthenticationFailed = 0x7FFF - 12; + } + +} diff --git a/Assets/PhotonChatApi/ChatPeer.cs.meta b/Assets/PhotonChatApi/ChatPeer.cs.meta new file mode 100644 index 0000000..a002c43 --- /dev/null +++ b/Assets/PhotonChatApi/ChatPeer.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 3f712805dec728943a668b3bf19dc422 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/PhotonChatApi/ChatState.cs b/Assets/PhotonChatApi/ChatState.cs new file mode 100644 index 0000000..cc81c6d --- /dev/null +++ b/Assets/PhotonChatApi/ChatState.cs @@ -0,0 +1,37 @@ +// ---------------------------------------------------------------------------------------------------------------------- +// The Photon Chat Api enables clients to connect to a chat server and communicate with other clients. +// ChatClient is the main class of this api. +// Photon Chat Api - Copyright (C) 2014 Exit Games GmbH +// ---------------------------------------------------------------------------------------------------------------------- + +namespace ExitGames.Client.Photon.Chat +{ + /// Possible states for a LoadBalancingClient. + public enum ChatState + { + /// Peer is created but not used yet. + Uninitialized, + /// Connecting to master (includes connect, authenticate and joining the lobby) + ConnectingToNameServer, + /// Connected to master server. + ConnectedToNameServer, + /// Usually when Authenticated, the client will join a game or the lobby (if AutoJoinLobby is true). + Authenticating, + /// Usually when Authenticated, the client will join a game or the lobby (if AutoJoinLobby is true). + Authenticated, + /// Transition from master to game server. + DisconnectingFromNameServer, + /// Transition to gameserver (client will authenticate and join/create game). + ConnectingToFrontEnd, + /// Connected to gameserver (going to auth and join game). + ConnectedToFrontEnd, + /// Transition from gameserver to master (after leaving a room/game). + DisconnectingFromFrontEnd, + /// Currently not used. + QueuedComingFromFrontEnd, + /// The client disconnects (from any server). + Disconnecting, + /// The client is no longer connected (to any server). Connect to master to go on. + Disconnected, + } +} \ No newline at end of file diff --git a/Assets/PhotonChatApi/ChatState.cs.meta b/Assets/PhotonChatApi/ChatState.cs.meta new file mode 100644 index 0000000..e862818 --- /dev/null +++ b/Assets/PhotonChatApi/ChatState.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 8f482d8c4fe7ade4cbb08eb4a2d83b39 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/PhotonChatApi/ChatUserStatus.cs b/Assets/PhotonChatApi/ChatUserStatus.cs new file mode 100644 index 0000000..b7d7fa5 --- /dev/null +++ b/Assets/PhotonChatApi/ChatUserStatus.cs @@ -0,0 +1,35 @@ +// ---------------------------------------------------------------------------------------------------------------------- +// The Photon Chat Api enables clients to connect to a chat server and communicate with other clients. +// ChatClient is the main class of this api. +// Photon Chat Api - Copyright (C) 2014 Exit Games GmbH +// ---------------------------------------------------------------------------------------------------------------------- + +namespace ExitGames.Client.Photon.Chat +{ + /// Contains commonly used status values for SetOnlineStatus. You can define your own. + /// + /// While "online" (value 2 and up), the status message will be sent to anyone who has you on his friend list. + /// + /// Define custom online status values as you like with these rules: + /// 0: Means "offline". It will be used when you are not connected. In this status, there is no status message. + /// 1: Means "invisible" and is sent to friends as "offline". They see status 0, no message but you can chat. + /// 2: And any higher value will be treated as "online". Status can be set. + /// + public static class ChatUserStatus + { + /// (0) Offline. + public const int Offline = 0; + /// (1) Be invisible to everyone. Sends no message. + public const int Invisible = 1; + /// (2) Online and available. + public const int Online = 2; + /// (3) Online but not available. + public const int Away = 3; + /// (4) Do not disturb. + public const int DND = 4; + /// (5) Looking For Game/Group. Could be used when you want to be invited or do matchmaking. + public const int LFG = 5; + /// (6) Could be used when in a room, playing. + public const int Playing = 6; + } +} diff --git a/Assets/PhotonChatApi/ChatUserStatus.cs.meta b/Assets/PhotonChatApi/ChatUserStatus.cs.meta new file mode 100644 index 0000000..bfd0c52 --- /dev/null +++ b/Assets/PhotonChatApi/ChatUserStatus.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 7db67e7f5face2e42b6daafcaf4e6c82 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/PhotonChatApi/IChatClientListener.cs b/Assets/PhotonChatApi/IChatClientListener.cs new file mode 100644 index 0000000..52a19a3 --- /dev/null +++ b/Assets/PhotonChatApi/IChatClientListener.cs @@ -0,0 +1,86 @@ +// ---------------------------------------------------------------------------------------------------------------------- +// The Photon Chat Api enables clients to connect to a chat server and communicate with other clients. +// ChatClient is the main class of this api. +// Photon Chat Api - Copyright (C) 2014 Exit Games GmbH +// ---------------------------------------------------------------------------------------------------------------------- + +namespace ExitGames.Client.Photon.Chat +{ + /// + /// Callback interface for Chat client side. Contains callback methods to notify your app about updates. + /// Must be provided to new ChatClient in constructor + /// + public interface IChatClientListener + { + /// + /// All debug output of the library will be reported through this method. Print it or put it in a + /// buffer to use it on-screen. + /// + /// DebugLevel (severity) of the message. + /// Debug text. Print to System.Console or screen. + void DebugReturn(DebugLevel level, string message); + + /// + /// Disconnection happened. + /// + void OnDisconnected(); + + /// + /// Client is connected now. + /// + /// + /// Clients have to be connected before they can send their state, subscribe to channels and send any messages. + /// + void OnConnected(); + + /// The ChatClient's state changed. Usually, OnConnected and OnDisconnected are the callbacks to react to. + /// The new state. + void OnChatStateChange(ChatState state); + + /// + /// Notifies app that client got new messages from server + /// Number of senders is equal to number of messages in 'messages'. Sender with number '0' corresponds to message with + /// number '0', sender with number '1' corresponds to message with number '1' and so on + /// + /// channel from where messages came + /// list of users who sent messages + /// list of messages it self + void OnGetMessages(string channelName, string[] senders, object[] messages); + + /// + /// Notifies client about private message + /// + /// user who sent this message + /// message it self + /// channelName for private messages (messages you sent yourself get added to a channel per target username) + void OnPrivateMessage(string sender, object message, string channelName); + + /// + /// Result of Subscribe operation. Returns subscription result for every requested channel name. + /// + /// + /// If multiple channels sent in Subscribe operation, OnSubscribed may be called several times, each call with part of sent array or with single channel in "channels" parameter. + /// Calls order and order of channels in "channels" parameter may differ from order of channels in "channels" parameter of Subscribe operation. + /// + /// Array of channel names. + /// Per channel result if subscribed. + void OnSubscribed(string[] channels, bool[] results); + + /// + /// Result of Unsubscribe operation. Returns for channel name if the channel is now unsubscribed. + /// + /// If multiple channels sent in Unsubscribe operation, OnUnsubscribed may be called several times, each call with part of sent array or with single channel in "channels" parameter. + /// Calls order and order of channels in "channels" parameter may differ from order of channels in "channels" parameter of Unsubscribe operation. + /// Array of channel names that are no longer subscribed. + void OnUnsubscribed(string[] channels); + + /// + /// New status of another user (you get updates for users set in your friends list). + /// + /// Name of the user. + /// New status of that user. + /// True if the status contains a message you should cache locally. False: This status update does not include a message (keep any you have). + /// Message that user set. + void OnStatusUpdate(string user, int status, bool gotMessage, object message); + } +} \ No newline at end of file diff --git a/Assets/PhotonChatApi/IChatClientListener.cs.meta b/Assets/PhotonChatApi/IChatClientListener.cs.meta new file mode 100644 index 0000000..797bdea --- /dev/null +++ b/Assets/PhotonChatApi/IChatClientListener.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: bab7c8053b486e34aa0d4ca99dcbec80 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Plugins/Metro.meta b/Assets/Plugins/Metro.meta new file mode 100644 index 0000000..11890a6 --- /dev/null +++ b/Assets/Plugins/Metro.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 8b2fea91c10cd4bbba4c9d23cd1d4cbd +folderAsset: yes +timeCreated: 1501014811 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/Metro/Photon3Unity3D.dll b/Assets/Plugins/Metro/Photon3Unity3D.dll new file mode 100644 index 0000000..33baf72 Binary files /dev/null and b/Assets/Plugins/Metro/Photon3Unity3D.dll differ diff --git a/Assets/Plugins/Metro/Photon3Unity3D.dll.meta b/Assets/Plugins/Metro/Photon3Unity3D.dll.meta new file mode 100644 index 0000000..a7b44bb --- /dev/null +++ b/Assets/Plugins/Metro/Photon3Unity3D.dll.meta @@ -0,0 +1,67 @@ +fileFormatVersion: 2 +guid: 3b5a0a7dce46a13459199d174ad3db3f +PluginImporter: + serializedVersion: 1 + iconMap: {} + executionOrder: {} + isPreloaded: 0 + platformData: + Android: + enabled: 0 + settings: + CPU: AnyCPU + Any: + enabled: 0 + settings: {} + Editor: + enabled: 0 + settings: + CPU: AnyCPU + DefaultValueInitialized: true + OS: AnyOS + Linux: + enabled: 0 + settings: + CPU: x86 + Linux64: + enabled: 0 + settings: + CPU: x86_64 + OSXIntel: + enabled: 0 + settings: + CPU: AnyCPU + OSXIntel64: + enabled: 0 + settings: + CPU: AnyCPU + WP8: + enabled: 0 + settings: + CPU: AnyCPU + DontProcess: False + PlaceholderPath: Assets/Plugins/Photon3Unity3D.dll + Win: + enabled: 0 + settings: + CPU: AnyCPU + Win64: + enabled: 0 + settings: + CPU: AnyCPU + WindowsStoreApps: + enabled: 1 + settings: + CPU: AnyCPU + DontProcess: False + PlaceholderPath: Assets/Plugins/Photon3Unity3D.dll + SDK: AnySDK + ScriptingBackend: DotNet + iOS: + enabled: 0 + settings: + CompileFlags: + FrameworkDependencies: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/Metro/Photon3Unity3D.pri b/Assets/Plugins/Metro/Photon3Unity3D.pri new file mode 100644 index 0000000..fa910b6 Binary files /dev/null and b/Assets/Plugins/Metro/Photon3Unity3D.pri differ diff --git a/Assets/GyroDroid-minimal.unitypackage.meta b/Assets/Plugins/Metro/Photon3Unity3D.pri.meta similarity index 64% rename from Assets/GyroDroid-minimal.unitypackage.meta rename to Assets/Plugins/Metro/Photon3Unity3D.pri.meta index 55dceb9..eb420ef 100644 --- a/Assets/GyroDroid-minimal.unitypackage.meta +++ b/Assets/Plugins/Metro/Photon3Unity3D.pri.meta @@ -1,6 +1,6 @@ fileFormatVersion: 2 -guid: ca1d5b4d210bba44783b2f5ed5e5e654 -timeCreated: 1425656968 +guid: 3439a9e4030efca45b6cc06240106c02 +timeCreated: 1460035811 licenseType: Store DefaultImporter: userData: diff --git a/Assets/Plugins/Photon3Unity3D.dll b/Assets/Plugins/Photon3Unity3D.dll new file mode 100644 index 0000000..10da0f7 Binary files /dev/null and b/Assets/Plugins/Photon3Unity3D.dll differ diff --git a/Assets/Plugins/Photon3Unity3D.dll.meta b/Assets/Plugins/Photon3Unity3D.dll.meta new file mode 100644 index 0000000..3b70afb --- /dev/null +++ b/Assets/Plugins/Photon3Unity3D.dll.meta @@ -0,0 +1,90 @@ +fileFormatVersion: 2 +guid: aadb37a20a33632429047acaef43658a +labels: +- ExitGames +- PUN +- Photon +- Networking +PluginImporter: + serializedVersion: 1 + iconMap: {} + executionOrder: {} + isPreloaded: 0 + platformData: + Android: + enabled: 1 + settings: + CPU: AnyCPU + Any: + enabled: 0 + settings: {} + Editor: + enabled: 1 + settings: + CPU: AnyCPU + DefaultValueInitialized: true + OS: AnyOS + Linux: + enabled: 1 + settings: + CPU: x86 + Linux64: + enabled: 1 + settings: + CPU: x86_64 + LinuxUniversal: + enabled: 1 + settings: {} + OSXIntel: + enabled: 1 + settings: + CPU: AnyCPU + OSXIntel64: + enabled: 1 + settings: + CPU: AnyCPU + OSXUniversal: + enabled: 1 + settings: {} + PS4: + enabled: 1 + settings: {} + WP8: + enabled: 0 + settings: + CPU: AnyCPU + DontProcess: False + PlaceholderPath: + Web: + enabled: 1 + settings: {} + WebGL: + enabled: 1 + settings: {} + WebStreamed: + enabled: 1 + settings: {} + Win: + enabled: 1 + settings: + CPU: AnyCPU + Win64: + enabled: 1 + settings: + CPU: AnyCPU + WindowsStoreApps: + enabled: 1 + settings: + CPU: AnyCPU + DontProcess: False + PlaceholderPath: + SDK: AnySDK + ScriptingBackend: Il2Cpp + iOS: + enabled: 1 + settings: + CompileFlags: + FrameworkDependencies: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/Photon3Unity3D.xml b/Assets/Plugins/Photon3Unity3D.xml new file mode 100644 index 0000000..f51a786 --- /dev/null +++ b/Assets/Plugins/Photon3Unity3D.xml @@ -0,0 +1,2089 @@ + + + + Photon3Unity3D + + + + + This is a substitute for the Hashtable class, missing in: Win8RT and Windows Phone. It uses a Dictionary<object,object> as base. + + + Please be aware that this class might act differently than the Hashtable equivalent. + As far as Photon is concerned, the substitution is sufficiently precise. + + + + + Creates a shallow copy of the Hashtable. + + + A shallow copy of a collection copies only the elements of the collection, whether they are + reference types or value types, but it does not copy the objects that the references refer + to. The references in the new collection point to the same objects that the references in + the original collection point to. + + Shallow copy of the Hashtable. + + + + Contains several (more or less) useful static methods, mostly used for debugging. + + + + + Gets the local machine's "milliseconds since start" value (precision is described in remarks). + + + This method uses Environment.TickCount (cheap but with only 16ms precision). + PhotonPeer.LocalMsTimestampDelegate is available to set the delegate (unless already connected). + + Fraction of the current time in Milliseconds (this is not a proper datetime timestamp). + + + + Creates a background thread that calls the passed function in 100ms intervals, as long as that returns true. + + + + + Creates a background thread that calls the passed function in intervals, as long as that returns true. + + The function to call. Must return true, if it should be called again. + Milliseconds to sleep between calls of myThread. Default: 100ms. + An optional name for the task for eased debugging. + + + + Ends the thread with the given id (= index of the thread list). + + The unique ID of the thread. + True if the thread is canceled and false otherwise, e.g. if the thread with the given ID does not exist. + + + + Ends the thread with the given id (= index of the thread list). + + The unique ID of the thread. + True if the thread is canceled and false otherwise, e.g. if the thread with the given ID does not exist. + + + + Writes the exception's stack trace to the received stream. + + Exception to obtain information from. + Output sream used to write to. + + + + Writes the exception's stack trace to the received stream. Writes to: System.Diagnostics.Debug. + + Exception to obtain information from. + + + + This method returns a string, representing the content of the given IDictionary. + Returns "null" if parameter is null. + + + IDictionary to return as string. + + + The string representation of keys and values in IDictionary. + + + + + This method returns a string, representing the content of the given IDictionary. + Returns "null" if parameter is null. + + IDictionary to return as string. + + + + + Converts a byte-array to string (useful as debugging output). + Uses BitConverter.ToString(list) internally after a null-check of list. + + Byte-array to convert to string. + + List of bytes as string. + + + + + Class to wrap static access to the random.Next() call in a thread safe manner. + + + + + Defines block size for encryption/decryption algorithm + + + + + Defines IV size for encryption/decryption algorithm + + + + + Defines HMAC size for packet authentication algorithm + + + + + Enumeration of situations that change the peers internal status. + Used in calls to OnStatusChanged to inform your application of various situations that might happen. + + + Most of these codes are referenced somewhere else in the documentation when they are relevant to methods. + + + + the PhotonPeer is connected.
See {@link PhotonListener#OnStatusChanged}*
+
+ + the PhotonPeer just disconnected.
See {@link PhotonListener#OnStatusChanged}*
+
+ + the PhotonPeer encountered an exception and will disconnect, too.
See {@link PhotonListener#OnStatusChanged}*
+
+ + the PhotonPeer encountered an exception while opening the incoming connection to the server. The server could be down / not running or the client has no network or a misconfigured DNS.
See {@link PhotonListener#OnStatusChanged}*
+
+ + Used on platforms that throw a security exception on connect. Unity3d does this, e.g., if a webplayer build could not fetch a policy-file from a remote server. + + + PhotonPeer outgoing queue is filling up. send more often. + + + PhotonPeer outgoing queue is filling up. send more often. + + + Sending command failed. Either not connected, or the requested channel is bigger than the number of initialized channels. + + + PhotonPeer outgoing queue is filling up. send more often. + + + PhotonPeer incoming queue is filling up. Dispatch more often. + + + PhotonPeer incoming queue is filling up. Dispatch more often. + + + PhotonPeer incoming queue is filling up. Dispatch more often. + + + Exception, if a server cannot be connected. Most likely, the server is not responding. Ask user to try again later. + + + Disconnection due to a timeout (client did no longer receive ACKs from server). + + + Disconnect by server due to timeout (received a disconnect command, cause server misses ACKs of client). + + + Disconnect by server due to concurrent user limit reached (received a disconnect command). + + + Disconnect by server due to server's logic (received a disconnect command). + + + (1048) Value for OnStatusChanged()-call, when the encryption-setup for secure communication finished successfully. + + + (1049) Value for OnStatusChanged()-call, when the encryption-setup failed for some reason. Check debug logs. + + + + Callback interface for the Photon client side. Must be provided to a new PhotonPeer in its constructor. + + + These methods are used by your PhotonPeer instance to keep your app updated. Read each method's + description and check out the samples to see how to use them. + + + + + Provides textual descriptions for various error conditions and noteworthy situations. + In cases where the application needs to react, a call to OnStatusChanged is used. + OnStatusChanged gives "feedback" to the game, DebugReturn provies human readable messages + on the background. + + + All debug output of the library will be reported through this method. Print it or put it in a + buffer to use it on-screen. Use PhotonPeer.DebugOut to select how verbose the output is. + + DebugLevel (severity) of the message. + Debug text. Print to System.Console or screen. + + + + Callback method which gives you (async) responses for called operations. + + + Similar to method-calling, operations can have a result. + Because operation-calls are non-blocking and executed on the server, responses are provided + after a roundtrip as call to this method. + + Example: Trying to create a room usually succeeds but can fail if the room's name is already + in use (room names are their IDs). + + This method is used as general callback for all operations. Each response corresponds to a certain + "type" of operation by its OperationCode. + + + + When you join a room, the server will assign a consecutive number to each client: the + "actorNr" or "player number". This is sent back in the OperationResult's + Parameters as value of key . + + Fetch your actorNr of a Join response like this: + int actorNr = (int)operationResponse[(byte)OperationCode.ActorNr]; + + The response to an operation\-call. + + + + OnStatusChanged is called to let the game know when asyncronous actions finished or when errors happen. + + + Not all of the many StatusCode values will apply to your game. Example: If you don't use encryption, + the respective status changes are never made. + + The values are all part of the StatusCode enumeration and described value-by-value. + + A code to identify the situation. + + + + Called whenever an event from the Photon Server is dispatched. + + + Events are used for communication between clients and allow the server to update clients over time. + The creation of an event is often triggered by an operation (called by this client or an other). + + Each event carries its specific content in its Parameters. Your application knows which content to + expect by checking the event's 'type', given by the event's Code. + + Events can be defined and extended server-side. + + If you use the LoadBalancing application as base, several events like EvJoin and EvLeave are already defined. + For these events and their Parameters, the library provides constants, so check the EventCode and ParameterCode + classes. + + Photon also allows you to come up with custom events on the fly, purely client-side. To do so, use + OpRaiseEvent. + + Events are buffered on the client side and must be Dispatched. This way, OnEvent is always taking + place in the same thread as a call. + + The event currently being dispatched. + + + + The bytes between Position and Length are copied to the beginning of the buffer. Length decreased by Position. Position set to 0. + + + + + Brings StreamBuffer to the state as after writing of 'length' bytes. Returned buffer and offset can be used to actually fill "written" segment with data. + + + + + Sets stream length. If current position is greater than specified value, it's set to the value. + + + SetLength(0) resets the stream to initial state but preserves underlying byte[] buffer. + + + + + Guarantees that the buffer is at least neededSize bytes. + + + + + Value range for a Peer's connection and initialization state, as returned by the PeerState property. + + + While this is not the same as the StatusCode of IPhotonPeerListener.OnStatusChanged(), it directly relates to it. + In most cases, it makes more sense to build a game's state on top of the OnStatusChanged() as you get changes. + + + + The peer is disconnected and can't call Operations. Call Connect(). + + + The peer is establishing the connection: opening a socket, exchanging packages with Photon. + + + The connection is established and now sends the application name to Photon. + You set the "application name" by calling PhotonPeer.Connect(). + + + The peer is connected and initialized (selected an application). You can now use operations. + + + The peer is disconnecting. It sent a disconnect to the server, which will acknowledge closing the connection. + + + + These are the options that can be used as underlying transport protocol. + + + + Use UDP to connect to Photon, which allows you to send operations reliable or unreliable on demand. + + + Use TCP to connect to Photon. + + + A TCP-based protocol commonly supported by browsers.For WebGL games mostly. Note: No WebSocket IPhotonSocket implementation is in this Assembly. + This protocol is only available in Unity exports to WebGL. + + + A TCP-based, encrypted protocol commonly supported by browsers. For WebGL games mostly. Note: No WebSocket IPhotonSocket implementation is in this Assembly. + This protocol is only available in Unity exports to WebGL. + + + + Level / amount of DebugReturn callbacks. Each debug level includes output for lower ones: OFF, ERROR, WARNING, INFO, ALL. + + + + No debug out. + + + Only error descriptions. + + + Warnings and errors. + + + Information about internal workflows, warnings and errors. + + + Most complete workflow description (but lots of debug output), info, warnings and errors. + + + + Instances of the PhotonPeer class are used to connect to a Photon server and communicate with it. + + + A PhotonPeer instance allows communication with the Photon Server, which in turn distributes messages + to other PhotonPeer clients. + An application can use more than one PhotonPeer instance, which are treated as separate users on the + server. Each should have its own listener instance, to separate the operations, callbacks and events. + + + + False if this library build contains C# Socket code. If true, you must set some type as SocketImplementation before connecting. + + + True, if this library needs a native Photon "Encryptor" plugin library for "Datagram Encryption". If false, this dll attempts to use managed encryption. + + + True if the library was compiled with DEBUG setting. + + + A simplified identifier for client SDKs. Photon's APIs might modify this (as a dll can be used in more than one product). Helps debugging. + + + For the Init-request, we shift the ClientId by one and the last bit signals a "debug" (0) or "release" build (1). + + + Defines if Key Exchange for Encryption is done asynchronously in another thread. + + + Version of this library as string. + + + Defines which IPhotonSocket class to use per ConnectionProtocol. + + Several platforms have special Socket implementations and slightly different APIs. + To accomodate this, switching the socket implementation for a network protocol was made available. + By default, UDP and TCP have socket implementations assigned. + + You only need to set the SocketImplementationConfig once, after creating a PhotonPeer + and before connecting. If you switch the TransportProtocol, the correct implementation is being used. + + + + + Can be used to read the IPhotonSocket implementation at runtime (before connecting). + + + Use the SocketImplementationConfig to define which IPhotonSocket is used per ConnectionProtocol. + + + + + Sets the level (and amount) of debug output provided by the library. + + + This affects the callbacks to IPhotonPeerListener.DebugReturn. + Default Level: Error. + + + + + Gets the IPhotonPeerListener of this instance (set in constructor). + Can be used in derived classes for Listener.DebugReturn(). + + + + + Gets count of all bytes coming in (including headers, excluding UDP/TCP overhead) + + + + + Gets count of all bytes going out (including headers, excluding UDP/TCP overhead) + + + + + Gets the size of the dispatched event or operation-result in bytes. + This value is set before OnEvent() or OnOperationResponse() is called (within DispatchIncomingCommands()). + + + Get this value directly in OnEvent() or OnOperationResponse(). Example: + void OnEvent(...) { + int eventSizeInBytes = this.peer.ByteCountCurrentDispatch; + //... + + void OnOperationResponse(...) { + int resultSizeInBytes = this.peer.ByteCountCurrentDispatch; + //... + + + + Returns the debug string of the event or operation-response currently being dispatched or string. Empty if none. + In a release build of the lib, this will always be empty. + + + + Gets the size of the last serialized operation call in bytes. + The value includes all headers for this single operation but excludes those of UDP, Enet Package Headers and TCP. + + + Get this value immediately after calling an operation. + Example: + + this.loadbalancingClient.OpJoinRoom("myroom"); + int opjoinByteCount = this.loadbalancingClient.ByteCountLastOperation; + + + + + Gets the byte-count of incoming "low level" messages, which are either Enet Commands or Tcp Messages. + These include all headers, except those of the underlying internet protocol Udp or Tcp. + + + + + Gets the byte-count of outgoing "low level" messages, which are either Enet Commands or Tcp Messages. + These include all headers, except those of the underlying internet protocol Udp or Tcp. + + + + + Gets a statistic of incoming and outgoing traffic, split by operation, operation-result and event. + + + Operations are outgoing traffic, results and events are incoming. + Includes the per-command header sizes (Udp: Enet Command Header or Tcp: Message Header). + + + + + Returns the count of milliseconds the stats are enabled for tracking. + + + + + Enables or disables collection of statistics in TrafficStatsIncoming, TrafficStatsOutgoing and TrafficstatsGameLevel. + + + Setting this to true, also starts the stopwatch to measure the timespan the stats are collected. + Enables the traffic statistics of a peer: TrafficStatsIncoming, TrafficStatsOutgoing and TrafficstatsGameLevel (nothing else). + Default value: false (disabled). + + + + + Creates new instances of TrafficStats and starts a new timer for those. + + + + Size of CommandLog. Default is 0, no logging. + + A bigger log is better for debugging but uses more memory. + Get the log as string via CommandLogToString. + + + + Converts the CommandLog into a readable table-like string with summary. + + Sent reliable commands begin with SND. Their acknowledgements with ACK. + ACKs list the reliable sequence number of the command they acknowledge (not their own). + Careful: This method should not be called frequently, as it's time- and memory-consuming to create the log. + + + + + Debugging option to tell the Photon Server to log all datagrams. + + + + + Up to 4 resend attempts for a reliable command can be done in quick succession (after RTT+4*Variance). + + + By default 0. Any later resend attempt will then double the time before the next resend. + Max value = 4; + Make sure to adjust SentCountAllowance to a slightly higher value, as more repeats will get done. + + + + + This is the (low level) state of the connection to the server of a PhotonPeer. Managed internally and read-only. + + + Don't mix this up with the StatusCode provided in IPhotonListener.OnStatusChanged(). + Applications should use the StatusCode of OnStatusChanged() to track their state, as + it also covers the higher level initialization between a client and Photon. + + + + + This peer's ID as assigned by the server or 0 if not using UDP. Will be 0xFFFF before the client connects. + + Used for debugging only. This value is not useful in everyday Photon usage. + + + + Initial size internal lists for incoming/outgoing commands (reliable and unreliable). + + + This sets only the initial size. All lists simply grow in size as needed. This means that + incoming or outgoing commands can pile up and consume heap size if Service is not called + often enough to handle the messages in either direction. + + Configure the WarningSize, to get callbacks when the lists reach a certain size. + + UDP: Incoming and outgoing commands each have separate buffers for reliable and unreliable sending. + There are additional buffers for "sent commands" and "ACKs". + TCP: Only two buffers exist: incoming and outgoing commands. + + + + (default=2) minimum number of open connections + + + (default=6) maximum number of open connections, should be > RhttpMinConnections + + + + Limits the queue of received unreliable commands within DispatchIncomingCommands before dispatching them. + This works only in UDP. + This limit is applied when you call DispatchIncomingCommands. If this client (already) received more than + LimitOfUnreliableCommands, it will throw away the older ones instead of dispatching them. This can produce + bigger gaps for unreliable commands but your client catches up faster. + + + This can be useful when the client couldn't dispatch anything for some time (cause it was in a room but + loading a level). + If set to 20, the incoming unreliable queues are truncated to 20. + If 0, all received unreliable commands will be dispatched. + This is a "per channel" value, so each channel can hold up to LimitOfUnreliableCommands commands. + This value interacts with DispatchIncomingCommands: If that is called less often, more commands get skipped. + + + + + Count of all currently received but not-yet-Dispatched reliable commands + (events and operation results) from all channels. + + + + + Count of all commands currently queued as outgoing, including all channels and reliable, unreliable. + + + + + Gets / sets the number of channels available in UDP connections with Photon. + Photon Channels are only supported for UDP. + The default ChannelCount is 2. Channel IDs start with 0 and 255 is a internal channel. + + + + + While not connected, this controls if the next connection(s) should use a per-package CRC checksum. + + + While turned on, the client and server will add a CRC checksum to every sent package. + The checksum enables both sides to detect and ignore packages that were corrupted during transfer. + Corrupted packages have the same impact as lost packages: They require a re-send, adding a delay + and could lead to timeouts. + + Building the checksum has a low processing overhead but increases integrity of sent and received data. + Packages discarded due to failed CRC cecks are counted in PhotonPeer.PacketLossByCrc. + + + + + Count of packages dropped due to failed CRC checks for this connection. + + + + + + Count of packages dropped due to wrong challenge for this connection. + + + + + Count of commands that got repeated (due to local repeat-timing before an ACK was received). + + + + + The WarningSize was used test all message queues for congestion. + + + + + Number of send retries before a peer is considered lost/disconnected. Default: 7. + The initial timeout countdown of a command is calculated by the current roundTripTime + 4 * roundTripTimeVariance. + Please note that the timeout span until a command will be resent is not constant, but based on + the roundtrip time at the initial sending, which will be doubled with every failed retry. + + DisconnectTimeout and SentCountAllowance are competing settings: either might trigger a disconnect on the + client first, depending on the values and Roundtrip Time. + + + + + Sets the milliseconds without reliable command before a ping command (reliable) will be sent (Default: 1000ms). + The ping command is used to keep track of the connection in case the client does not send reliable commands + by itself. + A ping (or reliable commands) will update the RoundTripTime calculation. + + + + + Milliseconds after which a reliable UDP command triggers a timeout disconnect, unless acknowledged by server. + This value currently only affects UDP connections. + DisconnectTimeout is not an exact value for a timeout. The exact timing of the timeout depends on the frequency + of Service() calls and commands that are sent with long roundtrip-times and variance are checked less often for + re-sending! + + DisconnectTimeout and SentCountAllowance are competing settings: either might trigger a disconnect on the + client first, depending on the values and Roundtrip Time. + Default: 10000 ms. + + + + + Approximated Environment.TickCount value of server (while connected). + + + UDP: The server's timestamp is automatically fetched after connecting (once). This is done + internally by a command which is acknowledged immediately by the server. + TCP: The server's timestamp fetched with each ping but set only after connecting (once). + + The approximation will be off by +/- 10ms in most cases. Per peer/client and connection, the + offset will be constant (unless FetchServerTimestamp() is used). A constant offset should be + better to adjust for. Unfortunately there is no way to find out how much the local value + differs from the original. + + The approximation adds RoundtripTime / 2 and uses this.LocalTimeInMilliSeconds to calculate + in-between values (this property returns a new value per tick). + + The value sent by Photon equals Environment.TickCount in the logic layer. + + + 0 until connected. + While connected, the value is an approximation of the server's current timestamp. + + + + The internally used "per connection" time value, which is updated infrequently, when the library executes some connectio-related tasks. + + This integer value is an infrequently updated value by design. + The lib internally sets the value when it sends outgoing commands or reads incoming packages. + This is based on SupportClass.GetTickCount() and an initial time value per (server) connection. + This value is also used in low level Enet commands as sent time and optional logging. + + + + The last ConnectionTime value, when some ACKs were sent out by this client. + Only applicable to UDP connections. + + + The last ConnectionTime value, when SendOutgoingCommands actually checked outgoing queues to send them. Must be connected. + Available for UDP and TCP connections. + + + + Gets a local timestamp in milliseconds by calling SupportClass.GetTickCount(). + See LocalMsTimestampDelegate. + + + + + This setter for the (local-) timestamp delegate replaces the default Environment.TickCount with any equal function. + + + About Environment.TickCount: + The value of this property is derived from the system timer and is stored as a 32-bit signed integer. + Consequently, if the system runs continuously, TickCount will increment from zero to Int32..::.MaxValue + for approximately 24.9 days, then jump to Int32..::.MinValue, which is a negative number, then increment + back to zero during the next 24.9 days. + + Exception is thrown peer.PeerState is not PS_DISCONNECTED. + + + + Time until a reliable command is acknowledged by the server. + + The value measures network latency and for UDP it includes the server's ACK-delay (setting in config). + In TCP, there is no ACK-delay, so the value is slightly lower (if you use default settings for Photon). + + RoundTripTime is updated constantly. Every reliable command will contribute a fraction to this value. + + This is also the approximate time until a raised event reaches another client or until an operation + result is available. + + + + + Changes of the roundtriptime as variance value. Gives a hint about how much the time is changing. + + + + + Stores timestamp of the last time anything (!) was received from the server (including + low level Ping and ACKs but also events and operation-returns). This is not the time when + something was dispatched. + If you enable NetworkSimulation, this value is affected as well. + + + + + The server address which was used in PhotonPeer.Connect() or null (before Connect() was called). + + + The ServerAddress can only be changed for HTTP connections (to replace one that goes through a Loadbalancer with a direct URL). + + + + The protocol this peer is currently connected/connecting with (or 0). + + + This is the protocol to be used for next connect (see remarks). + The TransportProtocol can be changed anytime but it will not change the protocol + of currently active connections. Instead, TransportProtocol will be applied on next Connect. + + + + + Gets or sets the network simulation "enabled" setting. + Changing this value also locks this peer's sending and when setting false, + the internally used queues are executed (so setting to false can take some cycles). + + + + + Gets the settings for built-in Network Simulation for this peer instance + while IsSimulationEnabled will enable or disable them. + Once obtained, the settings can be modified by changing the properties. + + + + + Defines the initial size of an internally used StreamBuffer for Tcp. + The StreamBuffer is used to aggregate operation into (less) send calls, + which uses less resoures. + + + The size is not restricing the buffer and does not affect when poutgoing data is actually sent. + + + + + The Maximum Trasfer Unit (MTU) defines the (network-level) packet-content size that is + guaranteed to arrive at the server in one piece. The Photon Protocol uses this + size to split larger data into packets and for receive-buffers of packets. + + + This value affects the Packet-content. The resulting UDP packages will have additional + headers that also count against the package size (so it's bigger than this limit in the end) + Setting this value while being connected is not allowed and will throw an Exception. + Minimum is 576. Huge values won't speed up connections in most cases! + + + + + This property is set internally, when OpExchangeKeysForEncryption successfully finished. + While it's true, encryption can be used for operations. + + + + + While true, the peer will not send any other commands except ACKs (used in UDP connections). + + + + Implements the message-protocol, based on the underlying network protocol (udp, tcp, http). + + + + Creates a new PhotonPeer instance to communicate with Photon and selects either UDP or TCP as + protocol. We recommend UDP. + + a IPhotonPeerListener implementation + Protocol to use to connect to Photon. + + + + This method does a DNS lookup (if necessary) and connects to the given serverAddress. + + The return value gives you feedback if the address has the correct format. If so, this + starts the process to establish the connection itself, which might take a few seconds. + + When the connection is established, a callback to IPhotonPeerListener.OnStatusChanged + will be done. If the connection can't be established, despite having a valid address, + the OnStatusChanged is called with an error-value. + + The applicationName defines the application logic to use server-side and it should match the name of + one of the apps in your server's config. + + By default, the applicationName is "LoadBalancing" but there is also the "MmoDemo". + You can setup your own application and name it any way you like. + + + Address of the Photon server. Format: ip:port (e.g. 127.0.0.1:5055) or hostname:port (e.g. localhost:5055) + + + The name of the application to use within Photon or the appId of PhotonCloud. + Should match a "Name" for an application, as setup in your PhotonServer.config. + + + true if IP is available (DNS name is resolved) and server is being connected. false on error. + + + + + This method does a DNS lookup (if necessary) and connects to the given serverAddress. + + The return value gives you feedback if the address has the correct format. If so, this + starts the process to establish the connection itself, which might take a few seconds. + + When the connection is established, a callback to IPhotonPeerListener.OnStatusChanged + will be done. If the connection can't be established, despite having a valid address, + the OnStatusChanged is called with an error-value. + + The applicationName defines the application logic to use server-side and it should match the name of + one of the apps in your server's config. + + By default, the applicationName is "LoadBalancing" but there is also the "MmoDemo". + You can setup your own application and name it any way you like. + + + Address of the Photon server. Format: ip:port (e.g. 127.0.0.1:5055) or hostname:port (e.g. localhost:5055) + + + The name of the application to use within Photon or the appId of PhotonCloud. + Should match a "Name" for an application, as setup in your PhotonServer.config. + + + Allows you to send some data, which may be used by server during peer creation + (e.g. as additional authentication info). + You can use any serializable data type of Photon. + Helpful for self-hosted solutions. Server will read this info on peer creation stage, + and may reject client without creating of peer if auth info is invalid. + + + true if IP is available (DNS name is resolved) and server is being connected. false on error. + + + + + This method initiates a mutual disconnect between this client and the server. + + + Calling this method does not immediately close a connection. Disconnect lets the server + know that this client is no longer listening. For the server, this is a much faster way + to detect that the client is gone but it requires the client to send a few final messages. + + On completion, OnStatusChanged is called with the StatusCode.Disconnect. + + If the client is disconnected already or the connection thread is stopped, then there is no callback. + + The default server logic will leave any joined game and trigger the respective event + () for the remaining players. + + + + + This method immediately closes a connection (pure client side) and ends related listening Threads. + + + Unlike Disconnect, this method will simply stop to listen to the server. Udp connections will timeout. + If the connections was open, this will trigger a callback to OnStatusChanged with code StatusCode.Disconnect. + + + + + This will fetch the server's timestamp and update the approximation for property ServerTimeInMilliseconds. + + The server time approximation will NOT become more accurate by repeated calls. Accuracy currently depends + on a single roundtrip which is done as fast as possible. + + The command used for this is immediately acknowledged by the server. This makes sure the roundtrip time is + low and the timestamp + rountriptime / 2 is close to the original value. + + + + + This method creates a public key for this client and exchanges it with the server. + + + Encryption is not instantly available but calls OnStatusChanged when it finishes. + Check for StatusCode EncryptionEstablished and EncryptionFailedToEstablish. + + Calling this method sets IsEncryptionAvailable to false. + This method must be called before the "encrypt" parameter of OpCustom can be used. + + If operation could be enqueued for sending + + + PayloadEncryption Secret. Message payloads get encrypted with it individually and on demand. + + + + Initializes Datagram Encryption. + + secret used to chipher udp packets + secret used for authentication of udp packets + + + + This method excutes DispatchIncomingCommands and SendOutgoingCommands in your application Thread-context. + + + The Photon client libraries are designed to fit easily into a game or application. The application + is in control of the context (thread) in which incoming events and responses are executed and has + full control of the creation of UDP/TCP packages. + + Sending packages and dispatching received messages are two separate tasks. Service combines them + into one method at the cost of control. It calls DispatchIncomingCommands and SendOutgoingCommands. + + Call this method regularly (2..20 times a second). + + This will Dispatch ANY remaining buffered responses and events AND will send queued outgoing commands. + Fewer calls might be more effective if a device cannot send many packets per second, as multiple + operations might be combined into one package. + + + You could replace Service by: + + while (DispatchIncomingCommands()); //Dispatch until everything is Dispatched... + SendOutgoingCommands(); //Send a UDP/TCP package with outgoing messages + + + + + + + This method creates a UDP/TCP package for outgoing commands (operations and acknowledgements) + and sends them to the server. + This method is also called by Service(). + + + As the Photon library does not create any UDP/TCP packages by itself. Instead, the application + fully controls how many packages are sent and when. A tradeoff, an application will + lose connection, if it is no longer calling SendOutgoingCommands or Service. + + If multiple operations and ACKs are waiting to be sent, they will be aggregated into one + package. The package fills in this order: + ACKs for received commands + A "Ping" - only if no reliable data was sent for a while + Starting with the lowest Channel-Nr: + Reliable Commands in channel + Unreliable Commands in channel + + This gives a higher priority to lower channels. + + A longer interval between sends will lower the overhead per sent operation but + increase the internal delay (which adds "lag"). + + Call this 2..20 times per second (depending on your target platform). + + The if commands are not yet sent. Udp limits it's package size, Tcp doesnt. + + + + This method directly causes the callbacks for events, responses and state changes + within a IPhotonPeerListener. DispatchIncomingCommands only executes a single received + command per call. If a command was dispatched, the return value is true and the method + should be called again. + This method is called by Service() until currently available commands are dispatched. + + + In general, this method should be called until it returns false. In a few cases, it might + make sense to pause dispatching (if a certain state is reached and the app needs to load + data, before it should handle new events). + + The callbacks to the peer's IPhotonPeerListener are executed in the same thread that is + calling DispatchIncomingCommands. This makes things easier in a game loop: Event execution + won't clash with painting objects or the game logic. + + + + + Returns a string of the most interesting connection statistics. + When you have issues on the client side, these might contain hints about the issue's cause. + + If true, Incoming and Outgoing low-level stats are included in the string. + Stats as string. + + + + Channel-less wrapper for OpCustom(). + + Operations are handled by their byte\-typed code. + The codes of the "LoadBalancong" application are in the class . + Containing parameters as key\-value pair. The key is byte\-typed, while the value is any serializable datatype. + Selects if the operation must be acknowledged or not. If false, the + operation is not guaranteed to reach the server. + If operation could be enqueued for sending + + + + Allows the client to send any operation to the Photon Server by setting any opCode and the operation's parameters. + + + Photon can be extended with new operations which are identified by a single + byte, defined server side and known as operation code (opCode). Similarly, the operation's parameters + are defined server side as byte keys of values, which a client sends as customOpParameters + accordingly. + Operations are handled by their byte\-typed code. The codes of the + "LoadBalancing" application are in the class . + Containing parameters as key\-value pair. The key is byte\-typed, while the value is any serializable datatype. + Selects if the operation must be acknowledged or not. If false, the + operation is not guaranteed to reach the server. + The channel in which this operation should be sent. + If operation could be enqueued for sending + + + + Allows the client to send any operation to the Photon Server by setting any opCode and the operation's parameters. + + + Variant with encryption parameter. + + Use this only after encryption was established by EstablishEncryption and waiting for the OnStateChanged callback. + + Operations are handled by their byte\-typed code. The codes of the + "LoadBalancing" application are in the class . + Containing parameters as key\-value pair. The key is byte\-typed, while the value is any serializable datatype. + Selects if the operation must be acknowledged or not. If false, the + operation is not guaranteed to reach the server. + The channel in which this operation should be sent. + Can only be true, while IsEncryptionAvailable is true, too. + If operation could be enqueued for sending + + + + Allows the client to send any operation to the Photon Server by setting any opCode and the operation's parameters. + + + Variant with an OperationRequest object. + + This variant offers an alternative way to describe a operation request. Operation code and it's parameters + are wrapped up in a object. Still, the parameters are a Dictionary. + + The operation to call on Photon. + Use unreliable (false) if the call might get lost (when it's content is soon outdated). + Defines the sequence of requests this operation belongs to. + Encrypt request before sending. Depends on IsEncryptionAvailable. + If operation could be enqueued for sending + + + + Registers new types/classes for de/serialization and the fitting methods to call for this type. + + + SerializeMethod and DeserializeMethod are complementary: Feed the product of serializeMethod to + the constructor, to get a comparable instance of the object. + + After registering a Type, it can be used in events and operations and will be serialized like + built-in types. + + Type (class) to register. + A byte-code used as shortcut during transfer of this Type. + Method delegate to create a byte[] from a customType instance. + Method delegate to create instances of customType's from byte[]. + If the Type was registered successfully. + + + Param code. Used in internal op: InitEncryption. + + + Encryption-Mode code. Used in internal op: InitEncryption. + + + Param code. Used in internal op: InitEncryption. + + + Code of internal op: InitEncryption. + + + TODO: Code of internal op: Ping (used in PUN binary websockets). + + + Result code for any (internal) operation. + + + Byte count of last sent operation (set during serialization). + + + Byte count of last dispatched message (set during dispatch/deserialization). + + + The command that's currently being dispatched. + + + EnetPeer will set this value, so trafficstats can use it. TCP has 0 bytes per package extra + + + See PhotonPeer value. + + + See PhotonPeer value. + + + See PhotonPeer value. + + + See PhotonPeer value. + + + This ID is assigned by the Realtime Server upon connection. + The application does not have to care about this, but it is useful in debugging. + + + + This is the (low level) connection state of the peer. It's internal and based on eNet's states. + + Applications can read the "high level" state as PhotonPeer.PeerState, which uses a different enum. + + + + The serverTimeOffset is serverTimestamp - localTime. Used to approximate the serverTimestamp with help of localTime + + + + + Gets the currently used settings for the built-in network simulation. + Please check the description of NetworkSimulationSet for more details. + + + + Size of CommandLog. Default is 0, no logging. + + + Log of sent reliable commands and incoming ACKs. + + + Log of incoming reliable commands, used to track which commands from the server this client got. Part of the PhotonPeer.CommandLogToString() result. + + + Reduce CommandLog to CommandLogSize. Oldest entries get discarded. + + + Initializes the CommandLog and InReliableLog according to CommandLogSize. A value of 0 will set both logs to 0. + + + Converts the CommandLog into a readable table-like string with summary. + + + + Count of all bytes going out (including headers) + + + + + Count of all bytes coming in (including headers) + + + + Set via Connect(..., customObject) and sent in Init-Request. + + + Temporary cache of AppId. Used in Connect() to keep the AppId until we send the Init-Request (after the network-level (and Enet) connect). + + + + This is the replacement for the const values used in eNet like: PS_DISCONNECTED, PS_CONNECTED, etc. + + + + No connection is available. Use connect. + + + Establishing a connection already. The app should wait for a status callback. + + + + The low level connection with Photon is established. On connect, the library will automatically + send an Init package to select the application it connects to (see also PhotonPeer.Connect()). + When the Init is done, IPhotonPeerListener.OnStatusChanged() is called with connect. + + Please note that calling operations is only possible after the OnStatusChanged() with StatusCode.Connect. + + + Connection going to be ended. Wait for status callback. + + + Acknowledging a disconnect from Photon. Wait for status callback. + + + Connection not properly disconnected. + + + Set to timeInt, whenever SendOutgoingCommands actually checks outgoing queues to send them. Must be connected. + + + Connect to server and send Init (which inlcudes the appId). + If customData is not null, the new init will be used (http-based). + + + If IPhotonSocket.Connected is true, this value shows if the server's address resolved as IPv6 address. + + You must check the socket's IsConnected state. Otherwise, this value is not initialized. + Sent to server in Init-Request. + + + + Must be called by a IPhotonSocket when it connected to set IsIpv6. + The new value of IsIpv6. + + + + + + + + + + + + Checks the incoming queue and Dispatches received data if possible. + + If a Dispatch happened or not, which shows if more Dispatches might be needed. + + + + Checks outgoing queues for commands to send and puts them on their way. + This creates one package per go in UDP. + + If commands are not sent, cause they didn't fit into the package that's sent. + + + Returns the UDP Payload starting with Magic Number for binary protocol + + + Maximum Transfer Unit to be used for UDP+TCP + + + (default=2) Rhttp: minimum number of open connections + + + (default=6) Rhttp: maximum number of open connections, should be > rhttpMinConnections + + + + Internally uses an operation to exchange encryption keys with the server. + + If the op could be sent. + + + + Core of the Network Simulation, which is available in Debug builds. + Called by a timer in intervals. + + + + One list for all channels keeps sent commands (for re-sending). + + + One pool of ACK byte arrays ( 20 bytes each) for all channels to keep acknowledgements. + + + Gets enabled by "request" from server (not by client). + + + Initial PeerId as used in Connect command. If EnableServerTracing is false. + + + Initial PeerId to enable Photon Tracing, as used in Connect command. See: EnableServerTracing. + + + + Checks the incoming queue and Dispatches received data if possible. + + If a Dispatch happened or not, which shows if more Dispatches might be needed. + + + + gathers acks until udp-packet is full and sends it! + + + + + gathers commands from all (out)queues until udp-packet is full and sends it! + + + + + Checks if any channel has a outgoing reliable command. + + True if any channel has a outgoing reliable command. False otherwise. + + + + Checks connected state and channel before operation is serialized and enqueued for sending. + + operation parameters + code of operation + send as reliable command + channel (sequence) for command + encrypt or not + usually EgMessageType.Operation + if operation could be enqueued + + + reliable-udp-level function to send some byte[] to the server via un/reliable command + only called when a custom operation should be send + (enet) command type + data to carry (operation) + channel in which to send + the invocation ID for this operation (the payload) + + + Serializes an operation into our binary messages (magic number, msg-type byte and message). Optionally encrypts. + This method is mostly the same in EnetPeer, TPeer and HttpPeerBase. Also, for raw messages, we have another variant. + + + reads incoming udp-packages to create and queue incoming commands* + + + queues incoming commands in the correct order as either unreliable, reliable or unsequenced. return value determines if the command is queued / done. + + + removes commands which are acknowledged* + + + Internal class for "commands" - the package in which operations are sent. + + + this variant does only create outgoing commands and increments . incoming ones are created from a DataInputStream + + + + ACKs should never be created as NCommand. use CreateACK to wrtie the serialized ACK right away... + + + + + + + + + reads the command values (commandHeader and command-values) from incoming bytestream and populates the incoming command* + + + TCP "Package" header: 7 bytes + + + TCP "Message" header: 2 bytes + + + TCP header combined: 9 bytes + + + Defines if the (TCP) socket implementation needs to do "framing". + The WebSocket protocol (e.g.) includes framing, so when that is used, we set DoFraming to false. + + + + Checks the incoming queue and Dispatches received data if possible. Returns if a Dispatch happened or + not, which shows if more Dispatches might be needed. + + + + + gathers commands from all (out)queues until udp-packet is full and sends it! + + + + Sends a ping in intervals to keep connection alive (server will timeout connection if nothing is sent). + Always false in this case (local queues are ignored. true would be: "call again to send remaining data"). + + + Serializes an operation into our binary messages (magic number, msg-type byte and message). Optionally encrypts. + This method is mostly the same in EnetPeer, TPeer and HttpPeerBase. Also, for raw messages, we have another variant. + + + enqueues serialized operations to be sent as tcp stream / package + + + Sends a ping and modifies this.lastPingResult to avoid another ping for a while. + + + reads incoming tcp-packages to create and queue incoming commands* + + + + Container for an Operation request, which is a code and parameters. + + + On the lowest level, Photon only allows byte-typed keys for operation parameters. + The values of each such parameter can be any serializable datatype: byte, int, hashtable and many more. + + + + Byte-typed code for an operation - the short identifier for the server's method to call. + + + The parameters of the operation - each identified by a byte-typed code in Photon. + + + + Contains the server's response for an operation called by this peer. + The indexer of this class actually provides access to the Parameters Dictionary. + + + The OperationCode defines the type of operation called on Photon and in turn also the Parameters that + are set in the request. Those are provided as Dictionary with byte-keys. + There are pre-defined constants for various codes defined in the LoadBalancing application. + Check: OperationCode, ParameterCode, etc. + + An operation's request is summarized by the ReturnCode: a short typed code for "Ok" or + some different result. The code's meaning is specific per operation. An optional DebugMessage can be + provided to simplify debugging. + + Each call of an operation gets an ID, called the "invocID". This can be matched to the IDs + returned with any operation calls. This way, an application could track if a certain OpRaiseEvent + call was successful. + + + + The code for the operation called initially (by this peer). + Use enums or constants to be able to handle those codes, like OperationCode does. + + + A code that "summarizes" the operation's success or failure. Specific per operation. 0 usually means "ok". + + + An optional string sent by the server to provide readable feedback in error-cases. Might be null. + + + A Dictionary of values returned by an operation, using byte-typed keys per value. + + + + Alternative access to the Parameters, which wraps up a TryGetValue() call on the Parameters Dictionary. + + The byte-code of a returned value. + The value returned by the server, or null if the key does not exist in Parameters. + + + ToString() override. + Relatively short output of OpCode and returnCode. + + + Extensive output of operation results. + To be used in debug situations only, as it returns a string for each value. + + + + Contains all components of a Photon Event. + Event Parameters, like OperationRequests and OperationResults, consist of a Dictionary with byte-typed keys per value. + + + The indexer of this class provides access to the Parameters Dictionary. + + The operation RaiseEvent allows you to provide custom event content. Defined in LoadBalancing, this + CustomContent will be made the value of key ParameterCode.CustomEventContent. + + + + The event code identifies the type of event. + + + The Parameters of an event is a Dictionary<byte, object>. + + + + Alternative access to the Parameters. + + The key byte-code of a event value. + The Parameters value, or null if the key does not exist in Parameters. + + + ToString() override. + Short output of "Event" and it's Code. + + + Extensive output of the event content. + To be used in debug situations only, as it returns a string for each value. + + + + Type of serialization methods to add custom type support. + Use PhotonPeer.ReisterType() to register new types with serialization and deserialization methods. + + The method will get objects passed that were registered with it in RegisterType(). + Return a byte[] that resembles the object passed in. The framework will surround it with length and type info, so don't include it. + + + + Type of deserialization methods to add custom type support. + Use PhotonPeer.RegisterType() to register new types with serialization and deserialization methods. + + The framwork passes in the data it got by the associated SerializeMethod. The type code and length are stripped and applied before a DeserializeMethod is called. + Return a object of the type that was associated with this method through RegisterType(). + + + + Provides tools for the Exit Games Protocol + + + + + Serialize creates a byte-array from the given object and returns it. + + The object to serialize + The serialized byte-array + + + + Deserialize returns an object reassembled from the given byte-array. + + The byte-array to be Deserialized + The Deserialized object + + + + Serializes a short typed value into a byte-array (target) starting at the also given targetOffset. + The altered offset is known to the caller, because it is given via a referenced parameter. + + The short value to be serialized + The byte-array to serialize the short to + The offset in the byte-array + + + + Serializes an int typed value into a byte-array (target) starting at the also given targetOffset. + The altered offset is known to the caller, because it is given via a referenced parameter. + + The int value to be serialized + The byte-array to serialize the short to + The offset in the byte-array + + + + Serializes an float typed value into a byte-array (target) starting at the also given targetOffset. + The altered offset is known to the caller, because it is given via a referenced parameter. + + The float value to be serialized + The byte-array to serialize the short to + The offset in the byte-array + + + + Deserialize fills the given int typed value with the given byte-array (source) starting at the also given offset. + The result is placed in a variable (value). There is no need to return a value because the parameter value is given by reference. + The altered offset is this way also known to the caller. + + The int value to deserialize into + The byte-array to deserialize from + The offset in the byte-array + + + + Deserialize fills the given short typed value with the given byte-array (source) starting at the also given offset. + The result is placed in a variable (value). There is no need to return a value because the parameter value is given by reference. + The altered offset is this way also known to the caller. + + The short value to deserialized into + The byte-array to deserialize from + The offset in the byte-array + + + + Deserialize fills the given float typed value with the given byte-array (source) starting at the also given offset. + The result is placed in a variable (value). There is no need to return a value because the parameter value is given by reference. + The altered offset is this way also known to the caller. + + The float value to deserialize + The byte-array to deserialize from + The offset in the byte-array + + + + Exit Games GpBinaryV16 protocol implementation + + + + + The gp type. + + + + + Unkown type. + + + + + An array of objects. + + + This type is new in version 1.5. + + + + + A boolean Value. + + + + + A byte value. + + + + + An array of bytes. + + + + + An array of objects. + + + + + A 16-bit integer value. + + + + + A 32-bit floating-point value. + + + This type is new in version 1.5. + + + + + A dictionary + + + This type is new in version 1.6. + + + + + A 64-bit floating-point value. + + + This type is new in version 1.5. + + + + + A Hashtable. + + + + + A 32-bit integer value. + + + + + An array of 32-bit integer values. + + + + + A 64-bit integer value. + + + + + A string value. + + + + + An array of string values. + + + + + A custom type. 0x63 + + + + + Null value don't have types. + + + + + Calls the correct serialization method for the passed object. + + + + + DeserializeInteger returns an Integer typed value from the given stream. + + + + Uses C# Socket class from System.Net.Sockets (as Unity usually does). + Incompatible with Windows 8 Store/Phone API. + + + + Sends a "Photon Ping" to a server. + + Address in IPv4 or IPv6 format. An address containing a '.' will be interpretet as IPv4. + True if the Photon Ping could be sent. + + + + Separates the given address into address (host name or IP) and port. Port must be included after colon! + + + This method expects any address to include a port. The final ':' in addressAndPort has to separate it. + IPv6 addresses have multiple colons and must use brackets to separate address from port. + + Examples: + ns.exitgames.com:5058 + http://[2001:db8:1f70::999:de8:7648:6e8]:100/ + [2001:db8:1f70::999:de8:7648:6e8]:100 + See: + http://serverfault.com/questions/205793/how-can-one-distinguish-the-host-and-the-port-in-an-ipv6-url + + + + Implements a (very) simple test if a (valid) IPAddress is IPv6 by testing for colons (:). + The reason we use this, is that some DotNet platforms don't provide (or allow usage of) the System.Net namespace. + A valid IPAddress or null. + If the IPAddress.ToString() contains a colon (which means it's IPv6). + + + + Returns null or the IPAddress representing the address, doing Dns resolution if needed. + + Only returns IPv4 or IPv6 adresses, no others. + The string address of a server (hostname or IP). + IPAddress for the string address or null, if the address is neither IPv4, IPv6 or some hostname that could be resolved. + + + Internal class to encapsulate the network i/o functionality for the realtime libary. + + + used by PhotonPeer* + + + Endless loop, run in Receive Thread. + + + + Internal class to encapsulate the network i/o functionality for the realtime libary. + + + + + used by TPeer* + + + + + A simulation item is an action that can be queued to simulate network lag. + + + + With this, the actual delay can be measured, compared to the intended lag. + + + Timestamp after which this item must be executed. + + + Action to execute when the lag-time passed. + + + Starts a new Stopwatch + + + + A set of network simulation settings, enabled (and disabled) by PhotonPeer.IsSimulationEnabled. + + + For performance reasons, the lag and jitter settings can't be produced exactly. + In some cases, the resulting lag will be up to 20ms bigger than the lag settings. + Even if all settings are 0, simulation will be used. Set PhotonPeer.IsSimulationEnabled + to false to disable it if no longer needed. + + All lag, jitter and loss is additional to the current, real network conditions. + If the network is slow in reality, this will add even more lag. + The jitter values will affect the lag positive and negative, so the lag settings + describe the medium lag even with jitter. The jitter influence is: [-jitter..+jitter]. + Packets "lost" due to OutgoingLossPercentage count for BytesOut and LostPackagesOut. + Packets "lost" due to IncomingLossPercentage count for BytesIn and LostPackagesIn. + + + + internal + + + internal + + + internal + + + internal + + + internal + + + internal + + + internal + + + This setting overrides all other settings and turns simulation on/off. Default: false. + + + Outgoing packages delay in ms. Default: 100. + + + Randomizes OutgoingLag by [-OutgoingJitter..+OutgoingJitter]. Default: 0. + + + Percentage of outgoing packets that should be lost. Between 0..100. Default: 1. TCP ignores this setting. + + + Incoming packages delay in ms. Default: 100. + + + Randomizes IncomingLag by [-IncomingJitter..+IncomingJitter]. Default: 0. + + + Percentage of incoming packets that should be lost. Between 0..100. Default: 1. TCP ignores this setting. + + + Counts how many outgoing packages actually got lost. TCP connections ignore loss and this stays 0. + + + Counts how many incoming packages actually got lost. TCP connections ignore loss and this stays 0. + + + + Only in use as long as PhotonPeer.TrafficStatsEnabled = true; + + + + Gets sum of outgoing operations in bytes. + + + Gets count of outgoing operations. + + + Gets sum of byte-cost of incoming operation-results. + + + Gets count of incoming operation-results. + + + Gets sum of byte-cost of incoming events. + + + Gets count of incoming events. + + + + Gets longest time it took to complete a call to OnOperationResponse (in your code). + If such a callback takes long, it will lower the network performance and might lead to timeouts. + + + + Gets OperationCode that causes the LongestOpResponseCallback. See that description. + + + + Gets longest time a call to OnEvent (in your code) took. + If such a callback takes long, it will lower the network performance and might lead to timeouts. + + + + Gets EventCode that caused the LongestEventCallback. See that description. + + + + Gets longest time between subsequent calls to DispatchIncomgingCommands in milliseconds. + Note: This is not a crucial timing for the networking. Long gaps just add "local lag" to events that are available already. + + + + + Gets longest time between subsequent calls to SendOutgoingCommands in milliseconds. + Note: This is a crucial value for network stability. Without calling SendOutgoingCommands, + nothing will be sent to the server, who might time out this client. + + + + + Gets number of calls of DispatchIncomingCommands. + + + + + Gets number of calls of DispatchIncomingCommands. + + + + + Gets number of calls of SendOutgoingCommands. + + + + Gets sum of byte-cost of all "logic level" messages. + + + Gets sum of counted "logic level" messages. + + + Gets sum of byte-cost of all incoming "logic level" messages. + + + Gets sum of counted incoming "logic level" messages. + + + Gets sum of byte-cost of all outgoing "logic level" messages (= OperationByteCount). + + + Gets sum of counted outgoing "logic level" messages (= OperationCount). + + + + Resets the values that can be maxed out, like LongestDeltaBetweenDispatching. See remarks. + + + Set to 0: LongestDeltaBetweenDispatching, LongestDeltaBetweenSending, LongestEventCallback, LongestEventCallbackCode, LongestOpResponseCallback, LongestOpResponseCallbackOpCode. + Also resets internal values: timeOfLastDispatchCall and timeOfLastSendCall (so intervals are tracked correctly). + + + + Gets the byte-size of per-package headers. + + + + Counts commands created/received by this client, ignoring repeats (out command count can be higher due to repeats). + + + + Gets count of bytes as traffic, excluding UDP/TCP headers (42 bytes / x bytes). + + + Timestamp of the last incoming ACK that has been read (every PhotonPeer.TimePingInterval milliseconds this client sends a PING which must be ACKd). + + + Timestamp of last incoming reliable command (every second we expect a PING). + + + + Serialize creates a byte-array from the given object and returns it. + + The object to serialize + The serialized byte-array + + + + Deserialize returns an object reassembled from the given StreamBuffer. + + The buffer to be Deserialized + The Deserialized object + + + + Deserialize returns an object reassembled from the given byte-array. + + The byte-array to be Deserialized + The Deserialized object + + + + Provides classical Diffie-Hellman Modular Exponentiation Groups defined by the + OAKLEY Key Determination Protocol (RFC 2412). + + + + + Gets the genrator (N) used by the the well known groups 1,2 and 5. + + + + + Gets the 768 bit prime for the well known group 1. + + + + + Gets the 1024 bit prime for the well known group 2. + + + + + Gets the 1536 bit prime for the well known group 5. + + + + + Initializes a new instance of the class. + + + + + Gets the public key that can be used by another DiffieHellmanCryptoProvider object + to generate a shared secret agreement. + + + + + Derives the shared key is generated from the secret agreement between two parties, + given a byte array that contains the second party's public key. + + + The second party's public key. + + +
+
diff --git a/Assets/Plugins/Photon3Unity3D.xml.meta b/Assets/Plugins/Photon3Unity3D.xml.meta new file mode 100644 index 0000000..671d824 --- /dev/null +++ b/Assets/Plugins/Photon3Unity3D.xml.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 8d4f08d435c4b6343969d8af249460ff +labels: +- ExitGames +- PUN +- Photon +- Networking +TextScriptImporter: + userData: diff --git a/Assets/Plugins/WebSocket.meta b/Assets/Plugins/WebSocket.meta new file mode 100644 index 0000000..abb4665 --- /dev/null +++ b/Assets/Plugins/WebSocket.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 70b6eb77612ea4c77a6e23ed437736b2 +folderAsset: yes +timeCreated: 1501014811 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/WebSocket/WebSocket.cs b/Assets/Plugins/WebSocket/WebSocket.cs new file mode 100644 index 0000000..25094bc --- /dev/null +++ b/Assets/Plugins/WebSocket/WebSocket.cs @@ -0,0 +1,155 @@ +#if UNITY_WEBGL || UNITY_XBOXONE || WEBSOCKET + +using System; +using System.Text; + +#if UNITY_WEBGL && !UNITY_EDITOR +using System.Runtime.InteropServices; +#else +using System.Collections.Generic; +using System.Security.Authentication; +#endif + + +public class WebSocket +{ + private Uri mUrl; + + public WebSocket(Uri url) + { + mUrl = url; + + string protocol = mUrl.Scheme; + if (!protocol.Equals("ws") && !protocol.Equals("wss")) + throw new ArgumentException("Unsupported protocol: " + protocol); + } + + public void SendString(string str) + { + Send(Encoding.UTF8.GetBytes (str)); + } + + public string RecvString() + { + byte[] retval = Recv(); + if (retval == null) + return null; + return Encoding.UTF8.GetString (retval); + } + +#if UNITY_WEBGL && !UNITY_EDITOR + [DllImport("__Internal")] + private static extern int SocketCreate (string url); + + [DllImport("__Internal")] + private static extern int SocketState (int socketInstance); + + [DllImport("__Internal")] + private static extern void SocketSend (int socketInstance, byte[] ptr, int length); + + [DllImport("__Internal")] + private static extern void SocketRecv (int socketInstance, byte[] ptr, int length); + + [DllImport("__Internal")] + private static extern int SocketRecvLength (int socketInstance); + + [DllImport("__Internal")] + private static extern void SocketClose (int socketInstance); + + [DllImport("__Internal")] + private static extern int SocketError (int socketInstance, byte[] ptr, int length); + + int m_NativeRef = 0; + + public void Send(byte[] buffer) + { + SocketSend (m_NativeRef, buffer, buffer.Length); + } + + public byte[] Recv() + { + int length = SocketRecvLength (m_NativeRef); + if (length == 0) + return null; + byte[] buffer = new byte[length]; + SocketRecv (m_NativeRef, buffer, length); + return buffer; + } + + public void Connect() + { + m_NativeRef = SocketCreate (mUrl.ToString()); + + //while (SocketState(m_NativeRef) == 0) + // yield return 0; + } + + public void Close() + { + SocketClose(m_NativeRef); + } + + public bool Connected + { + get { return SocketState(m_NativeRef) != 0; } + } + + public string Error + { + get { + const int bufsize = 1024; + byte[] buffer = new byte[bufsize]; + int result = SocketError (m_NativeRef, buffer, bufsize); + + if (result == 0) + return null; + + return Encoding.UTF8.GetString (buffer); + } + } +#else + WebSocketSharp.WebSocket m_Socket; + Queue m_Messages = new Queue(); + bool m_IsConnected = false; + string m_Error = null; + + public void Connect() + { + m_Socket = new WebSocketSharp.WebSocket(mUrl.ToString(), new string[] { "GpBinaryV16" });// modified by TS + m_Socket.SslConfiguration.EnabledSslProtocols = m_Socket.SslConfiguration.EnabledSslProtocols | (SslProtocols)(3072| 768); + m_Socket.OnMessage += (sender, e) => m_Messages.Enqueue(e.RawData); + m_Socket.OnOpen += (sender, e) => m_IsConnected = true; + m_Socket.OnError += (sender, e) => m_Error = e.Message + (e.Exception == null ? "" : " / " + e.Exception); + m_Socket.ConnectAsync(); + } + + public bool Connected { get { return m_IsConnected; } }// added by TS + + + public void Send(byte[] buffer) + { + m_Socket.Send(buffer); + } + + public byte[] Recv() + { + if (m_Messages.Count == 0) + return null; + return m_Messages.Dequeue(); + } + + public void Close() + { + m_Socket.Close(); + } + + public string Error + { + get + { + return m_Error; + } + } +#endif +} +#endif \ No newline at end of file diff --git a/Assets/Plugins/WebSocket/WebSocket.cs.meta b/Assets/Plugins/WebSocket/WebSocket.cs.meta new file mode 100644 index 0000000..241c921 --- /dev/null +++ b/Assets/Plugins/WebSocket/WebSocket.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b1bad04f7805f764dba77f0d4518e0f0 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Plugins/WebSocket/WebSocket.jslib b/Assets/Plugins/WebSocket/WebSocket.jslib new file mode 100644 index 0000000..c85639e --- /dev/null +++ b/Assets/Plugins/WebSocket/WebSocket.jslib @@ -0,0 +1,116 @@ +var LibraryWebSockets = { +$webSocketInstances: [], + +SocketCreate: function(url) +{ + var str = Pointer_stringify(url); + var socket = { + socket: new WebSocket(str, ['GpBinaryV16']), + buffer: new Uint8Array(0), + error: null, + messages: [] + } + socket.socket.binaryType = 'arraybuffer'; + socket.socket.onmessage = function (e) { +// if (e.data instanceof Blob) +// { +// var reader = new FileReader(); +// reader.addEventListener("loadend", function() { +// var array = new Uint8Array(reader.result); +// socket.messages.push(array); +// }); +// reader.readAsArrayBuffer(e.data); +// } + if (e.data instanceof ArrayBuffer) + { + var array = new Uint8Array(e.data); + socket.messages.push(array); + } + }; + socket.socket.onclose = function (e) { + if (e.code != 1000) + { + if (e.reason != null && e.reason.length > 0) + socket.error = e.reason; + else + { + switch (e.code) + { + case 1001: + socket.error = "Endpoint going away."; + break; + case 1002: + socket.error = "Protocol error."; + break; + case 1003: + socket.error = "Unsupported message."; + break; + case 1005: + socket.error = "No status."; + break; + case 1006: + socket.error = "Abnormal disconnection."; + break; + case 1009: + socket.error = "Data frame too large."; + break; + default: + socket.error = "Error "+e.code; + } + } + } + } + var instance = webSocketInstances.push(socket) - 1; + return instance; +}, + +SocketState: function (socketInstance) +{ + var socket = webSocketInstances[socketInstance]; + return socket.socket.readyState; +}, + +SocketError: function (socketInstance, ptr, bufsize) +{ + var socket = webSocketInstances[socketInstance]; + if (socket.error == null) + return 0; + var str = socket.error.slice(0, Math.max(0, bufsize - 1)); + writeStringToMemory(str, ptr, false); + return 1; +}, + +SocketSend: function (socketInstance, ptr, length) +{ + var socket = webSocketInstances[socketInstance]; + socket.socket.send (HEAPU8.buffer.slice(ptr, ptr+length)); +}, + +SocketRecvLength: function(socketInstance) +{ + var socket = webSocketInstances[socketInstance]; + if (socket.messages.length == 0) + return 0; + return socket.messages[0].length; +}, + +SocketRecv: function (socketInstance, ptr, length) +{ + var socket = webSocketInstances[socketInstance]; + if (socket.messages.length == 0) + return 0; + if (socket.messages[0].length > length) + return 0; + HEAPU8.set(socket.messages[0], ptr); + socket.messages = socket.messages.slice(1); +}, + +SocketClose: function (socketInstance) +{ + var socket = webSocketInstances[socketInstance]; + socket.socket.close(); +} +}; + +autoAddDeps(LibraryWebSockets, '$webSocketInstances'); +mergeInto(LibraryManager.library, LibraryWebSockets); diff --git a/Assets/Plugins/WebSocket/WebSocket.jslib.meta b/Assets/Plugins/WebSocket/WebSocket.jslib.meta new file mode 100644 index 0000000..e5a1c7d --- /dev/null +++ b/Assets/Plugins/WebSocket/WebSocket.jslib.meta @@ -0,0 +1,21 @@ +fileFormatVersion: 2 +guid: 04bb5f307f2e48b4fbaa6da865fd4091 +PluginImporter: + serializedVersion: 1 + iconMap: {} + executionOrder: {} + isPreloaded: 0 + platformData: + Any: + enabled: 0 + settings: {} + Editor: + enabled: 0 + settings: + DefaultValueInitialized: true + WebGL: + enabled: 1 + settings: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/WebSocket/websocket-sharp.README b/Assets/Plugins/WebSocket/websocket-sharp.README new file mode 100644 index 0000000..10d150b --- /dev/null +++ b/Assets/Plugins/WebSocket/websocket-sharp.README @@ -0,0 +1,3 @@ +websocket-sharp.dll built from https://github.com/sta/websocket-sharp.git, commit 869dfb09778de51081b0ae64bd2c3217cffe0699 on Aug 24, 2016. + +websocket-sharp is provided under The MIT License as mentioned here: https://github.com/sta/websocket-sharp#license \ No newline at end of file diff --git a/Assets/Plugins/WebSocket/websocket-sharp.README.meta b/Assets/Plugins/WebSocket/websocket-sharp.README.meta new file mode 100644 index 0000000..47cc15d --- /dev/null +++ b/Assets/Plugins/WebSocket/websocket-sharp.README.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: 3e262c2b04eaa8440987b50a91e86674 +DefaultImporter: + userData: diff --git a/Assets/Plugins/WebSocket/websocket-sharp.dll b/Assets/Plugins/WebSocket/websocket-sharp.dll new file mode 100644 index 0000000..6eabebe Binary files /dev/null and b/Assets/Plugins/WebSocket/websocket-sharp.dll differ diff --git a/Assets/Plugins/WebSocket/websocket-sharp.dll.meta b/Assets/Plugins/WebSocket/websocket-sharp.dll.meta new file mode 100644 index 0000000..a586786 --- /dev/null +++ b/Assets/Plugins/WebSocket/websocket-sharp.dll.meta @@ -0,0 +1,69 @@ +fileFormatVersion: 2 +guid: 748eb70bc0d7515498ef73fed155520a +PluginImporter: + serializedVersion: 1 + iconMap: {} + executionOrder: {} + isPreloaded: 0 + platformData: + Android: + enabled: 0 + settings: + CPU: AnyCPU + Any: + enabled: 0 + settings: {} + Editor: + enabled: 1 + settings: + CPU: AnyCPU + DefaultValueInitialized: true + OS: AnyOS + Linux: + enabled: 0 + settings: + CPU: x86 + Linux64: + enabled: 0 + settings: + CPU: x86_64 + OSXIntel: + enabled: 0 + settings: + CPU: AnyCPU + OSXIntel64: + enabled: 0 + settings: + CPU: AnyCPU + WP8: + enabled: 0 + settings: + CPU: AnyCPU + DontProcess: False + PlaceholderPath: + Win: + enabled: 0 + settings: + CPU: AnyCPU + Win64: + enabled: 0 + settings: + CPU: AnyCPU + WindowsStoreApps: + enabled: 0 + settings: + CPU: AnyCPU + DontProcess: False + PlaceholderPath: + SDK: AnySDK + XboxOne: + enabled: 1 + settings: {} + iOS: + enabled: 0 + settings: + CompileFlags: + FrameworkDependencies: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/release_history.txt b/Assets/Plugins/release_history.txt new file mode 100644 index 0000000..7dcf379 --- /dev/null +++ b/Assets/Plugins/release_history.txt @@ -0,0 +1,1379 @@ +* release_history.txt +* Release history for the DotNet Photon Client Library (DotNet / Unity / Windows Store 8.1 and 10) +(C) 2016 Exit Games GmbH, http://www.photonengine.com + +Questions? Visit: +https://www.photonengine.com +https://doc.photonengine.com +http://forum.photonengine.com + + +*** Version 4.1.1.14 (5. July 2017 - rev4191) + Changed: SupportClass StartBackgroundCalls method now assigns an ID to each thread/task and enables you to cancel it explicitly via StopBackgroundCalls. CallInBackground is now obsolete due to renaming. +LoadBalancing + Changed: The ClientState "Uninitialized" is now "PeerCreated". This is the initial state. ConnectedToMaster is now ConnectedToMasterserver (both use the same value). + Updated: ClientState values descriptions. + Internal: GameEnteredOnGameServer() first sets the local player's actorNumber, then updates the player lists. +Chat: + Added: ChatClient can optionally run a thread to call SendOutgoingCommands in intervals. This makes sure the connection doesn't fail easily (e.g. when Unity is loading scenes, etc.). You still have to call Service to dispatch received messages. + Added: ChatClient.UseBackgroundWorkerForSending. Set this to true, to use the new background thread. Note: Do not use this in WebGL exports from Unity cause Threads are unavailable in them. +WebSocket: + Changed: Updated enabled protocols for WebSocket.cs. Now it is posible to connect to a server which supports only either TLS 1.1 or TLS 1.2 or TLS 1.0 or any combination of them. + + +*** Version 4.1.1.13 (2. June 2017 - rev4112) + Internal: Fixed StreamBuffer.Seek() which was throwing an exception when seeking position 0 in an empty stream. + Removed: The queue-length checks which were using OnStatusChanged to warn about the amount of data queued for sending. Several StatusCode values are now obsolete accordingly. + Removed: StatusCode InternalReceiveException = 1039 and TcpRouter* which were obsolete for a longer time. + +*** Version 4.1.1.12 (24. May 2017 - rev4086) + Fixed: Peer.timeLastSendOutgoing was set in SendAcksOnly and ReceiveIncomingCommands. This should not happen. In PUN, this led to an issue with the fallback thread, which could not keep the connection. + Fixed: DNS resolution in the UDP socket is no longer inside a lock. Even if it takes longer (without network), the socket can now be closed before it's even opened properly, avoiding a freeze. + Fixed: UWP clients can set a SocketImplementationConfig. This opens up the use of WebSockets or any IPhotonSocket implementation in UWP, too. + Internal: Acknowledgements are no longer created as "commands" and serialized on send. Instead, they are directly written to a byte[] buffer, which is using less memory. + Added: PhotonPeer.EnableServerTracing to enable UDP Datagram Tracing on server side. We might ask you to use this when debugging connection issues. Otherwise, don't use this, as you can't access the server's logs anyways. + +*** Version 4.1.1.11 (13. April 2017 - rev3922) + Fixed: Bug of v4.1.1.10, which caused disconnects after a short time. + +*** Version 4.1.1.10 (11. April 2017 - rev3916) + Internal: Memory Allocation for nCommand and EnetPeer within SendoutGoingCommand, and AreReliableCommandInTransit + Internal: Refactoring of SerializeToBuffer to prevent memory allocation and access udpBuffer directly instead of using BlockCopy. + Internal: EnetPeer.channels got removed and replaced by a simple array and a GetChannel() method to access all channels. + +*** Version 4.1.1.9 (15. March 2017 - rev3884) + Fixed: Size calculation for Datagram Encryption (used on one console only, so far), when the MTU was changed from default. In some cases, an Exception was thrown: ArgumentException: Offset and length were out of bounds [...] at System.Buffer.BlockCopy. Adjusted GetFragmentLength() and CalculateBufferLen() internally. + +*** Version 4.1.1.8 (24. February 2017 - rev3873) + Fixed: Handling of non-fatal "WouldBlock" SocketExceptions when receiving data via TCP. This led to disconnects before. This affects only TCP connections in libs other than Windows Store. + Changed: Memory usage for TCP socket usage. Less memory is being allocated per receive. As we have to queue incoming data, it still has to get copied once. + Changed: Memory usage for encrypting messages. + Changed: SupportClass.DictionaryToString() now logs the length of a byte-array (not the content). + Changed: Deserializing unknown "Custom Types" returns the sent byte[]. There is no warning/error log yet but deserialization won't fail entirely. + Changed: PeerBase.SerializeMessageToMessage() to use less memory for encryption. Also, Raw-Messages can now be de/encrypted successfully. + Internal: Added StreamBuffer.ToArrayFromPos(), enabling you to get a buffer copy, starting with some offset (position of the buffer). + Internal: Removed some NETFX special build cases (obsolete due to using our own SteamBuffer). +PhotonVoice: + Breaking: LocalVoice.Transmit = true by default. + Fixed: LoadBalancingFrontend.DebugEchoMode setter checks if value changed. + Changed: better singleton handling and error logging. +LoadBalancing: + Added: Player.UserId field and code to read published UserIds from the player properties in CacheProperties(). When publishing the UserId in a room (RoomOptions.PublishUserId = true), the UserId becomes available for all players in a room. Good to find/make friends or follow a team player into another room. + Added: New matchmaking operation: OpGetGameList(typedLobby, sqlFilter). This fetches a list of rooms that match the filter. You can show lists of rooms with specific properties, if needed (or still use OpJoinRandom). + Fixed: WebFlags properties setters. + +*** Version 4.1.1.7 (16. December 2016) + Note: No new lib version. Just updated demos for the SDK. +Demos: + Fixed: Demos with persistent (Turnbased) games. The Memory Demo was not setting up rooms correctly (which led to errors joining them) and used a "join" rather than a "rejoin" to get into saved games (getting added to the room once more). + +*** Version 4.1.1.6 (9. December 2016 - rev3801) + Changed: Default SentCountAllowance = 7. +Loadbalancing: + Added: OpJoinRandom will now "remember" to send ExpectedUsers to the Game Server (by caching the value). + Added: AuthEvent and it's handling. This (internally sent) event can now update the client's token anytime (before that expires). + Added: LoadBalancingClient.OpChangeGroups(). + Changed: LoadBalancingClient.Disconnect() no longer sets it's own State to Disconnected. It waits till the state-change callback gets called by the lib. + +*** Version 4.1.1.5 (18. November 2016 - rev3775) +Internal: + Fixed: Photon-init request is now created by the factory method CreateAndEnqueueCommand to make sure we fragment the init if needed (for small MTU and more init-data). + Fixed: Bug in TrafficStatsReset method, which caused the averaged stats to go up infinitely after a reset. + +*** Version 4.1.1.4 (21. October 2016 - rev3737) + Internal: Added ArraySegment support for byte[]. This way, we can internally reuse more memory. + Changed: Implementations of PeerBase Disconnect() are now using EnqueueStatusCallback(StatusCode.Disconnect) to delay the "callback". That enables any thread to call Disconnect() while the status change correctly gets called in the main thread via DispatchIncomingCommands(). + Changed: When a SocketImplementationConfig for UDP is set, this will be used via Activator.CreateInstance(socketImplementation, this). + +*** Version 4.1.1.3 (20. September 2016 - rev3673) + Changed: NETFX_CORE implementation for UDP. This no longer attempts to detach the stream after every single Send, which caused issues when connecting and getting a lot of messages. + +*** Version 4.1.1.2 (13. September 2016 - rev3652) + Changed: There are less variants of the Photon library now, which makes it easier to integrate, run and test. There is a general "DotNet" version and a Windows Store (universal) dll. These two also come as Unity build and in Debug and Release. UWP can use the Universal/WSA library. + Added: PhotonPeer.SocketImplementationConfig. This allows easier configuration of the IPhotonSocket type to use per protocol, so that switching protocols is easier (compared to having to set a SocketImplementation before connecting). + Changed: PhotonPeer.SocketImplementation can't be set public. Use the SocketImplementationConfig instead. + Internal: This release summarizes a lot of internal refactorings. It's easy now to switch protocols (internally), to set socket implementations (platform dependent) if needed, etc. +LoadBalancing: + Removed: LoadBalancingClient.PlayerName and Player.Name. Were obsolete for more than a year. There is a NickName and the UserId can be set in the AuthValues. + Removed: OpJoinRoom() overload with actorNumber. This was obsolete. To enable clients to return to a room, set AuthValues and a userID. + Changed: LoadBalancingClient no longer overrides the protocol for Unity WebGL. This is done in the LoadBalancingPeer.ConfigUnitySockets(). + Changed: GetNameServerAddress() is the same in Chat and LoadBalancing APIs now. + Added: DisconnectCause.DisconnectByServerLogic and handling for this case. You can check this DisconnectedCause when the LoadBalancingClient.State is ClientState.Disconnected. + Added: Hashtable definition to use Photon's own implementation for Windows Store builds (NETFX_CORE). This must be used but it means you to use the same Hashtable definition in all builds (no matter if 8.1 or 10). + Added: Support for WebGL export in Unity. + Changed: OnStateChangeAction, OnEventAction and OnOpResponseAction are now events. To register a method in one of those, use += and to deregister you need to use -=. This prevents assigning a new method and de-registering any previously registered ones. +Chat: + Changed: ChatPeer now has ConfigUnitySockets(), which defines the SocketImplementationConfig. It's only used in Unity (using UNITY define). + Changed: ChatClient is not setting socket implementations anymore. + Added: Hashtable definition to use Photon's own implementation for Windows Store builds (NETFX_CORE). This must be used but it means you to use the same Hashtable definition in all builds (no matter if 8.1 or 10). + Added: Support for WebGL export in Unity. + +*** Version 4.1.1.1 (22. August 2016 - rev3549) + Fixed: IPv6 support. The init-message was missing it in 4.1.1.0. + Fixed: UWP build for Unity now has (Photon-)Hashtable class once more. Unlike Windows RT, UWP does support Hashtable (again). But in Unity, we always use ours. + +*** Version 4.1.1.0 (15. August 2016 - rev3536) + Changed: Unity exports now need to set the API Compatibility to ".Net 2.0". The ".Net 2.0 Subset" won't work anymore, due to need of some features for a new encryption mode. + Fixed: Windows Store implementation of TCP Socket. This is now compatible with 8.1 and 10 and the locally configured timeout is also applied while connecting initially. + Fixed: OpWebRPC documentation. +LoadBalancing: + Fixed: Room.ClearExpectedUsers() is now sending it's current, local "expected users" to update the server with "CAS" (Check and Swap). This gives the client an update when the values become valid (which updates the local cache after the roundtrip). + Added: Support for the 'Server Side Master Client' feature. The Room will read master client updates from the server accordingly. Room.SetMasterClient() enables you to override the server's selection (provided it did not change before your operation gets executed). + Changed: Option for bool WebForward into the new "WebFlags". This allows fine control of which data is being sent to WebHooks. This affects all SetProperties, OpWebRPC and the RaiseEventOptions. + Added: WebRPC.cs to the LoadBalancing API folder (was available separately before). It contains WebFlags and WebRpcResponse. +Internal: + Changed: Instead of Windows Phone 8.0 support, we now have a Windows 8.1 Universal library ("Metro") and one for Windows 10 Universal ("UWP"). + Changed: Changed initialization of PhotonPeer and related classes. + Changed: Workflow to send Init command. + Added: Option for "Datagram Encryption" and a new Authentication Workflow ("AuthOnce" and "AuthOnceWss"). This is part of the LoadBalancing API. + Added: ClientSdkId, which is used internally for reference. + +*** Version 4.1.0.6 (30. June 2016 - rev3400) + Changed: ExchangeKeysForEncryption() and internally called DeriveSharedKey() can now be executed in their own Thread. + Added: static PhotonPeer.AsyncKeyExchange to define if encryption calculations are done in parallel. +Internal: + Changed: NetworkSimulationSet.IsSimulationEnabled only does any work, if the value gets changed (saving some surplus work). + +*** Version 4.1.0.6 (21. June 2016 - rev3376) +Internal: + Removed: The wrapper for the optional "native encryption library" from most assemblies. It didn't get certified for the Windows Store and caused problems in the Unity WebPlayer. This will be provided on demand instead. + Removed: Our upcoming protocol implementation until it's fully compatible with all supported platforms. Despite not being used, it also caused some issues on some Unity exports. + Changed: Usage of MemoryStream is being replaced with a StreamBuffer. This is our own implementation and always grants access to the underlying byte[] (which is not possible in Windows Phone / Store API in some cases). For your Custom Type serialization, replace MemoryStream with StreamBuffer. That's all. + Internal: Commands are now split into header and payload byte-arrays, instead of copying them into yet another buffer before sending them. + Added: Support for IPv6 adresses in Photon Ping classes. This supports "Best Region" usage in PUN. + Fixed: After DNS resolution, IPv6 adresses are preferred over IPv4 ones. +LoadBalancing: + Fixed: LoadBalancingPeer.OpRaiseEvent(...) to send operations (and events) unencrypted again. + +*** Version 4.1.0.4 (19. May 2016 - rev3322) +Internal: + Updated: For Unity, the usage of the optional "native sockets" library is now compatible with IPv6 addresses, as required by Apple. + +*** Version 4.1.0.3 (28. April 2016) +Internal: + Added: An optional native library for encryption. This speeds up the (rarely used) key-exchange and encryption of messages. The usual case is to use the C# variant, as before. + +*** Version 4.1.0.2 (21. April 2016 - rev3283) +Internal: + Changed: PeerBase: ipv6 flag set in INIT_BYTES[5] after dns lookup, when ip address type already known + Changed: PeerBase: INIT_BYTES[4] contains clientlibid and release flag (15) + Changed: PeerBase: client version packed in INIT_BYTES[5,7,6] bytes + Changed: pProtocol prefix and path parsed (and trimmed) in IPhotonSocket.TryParseAddress to support websocket urls + Changed: Client version moved to separate version.cs + Changed: Protocol static methods reworked to instance methods, IProtocol interface extracted + Changed: PeerBase.DeserializeMessageAndCallback() to use a variant of new MemoryStream that exists in Windows 10 Universal APIs, too. +LoadBalancing: + Added: Expected Users. This affects the Room, LoadBalancingClient, JoinRoom, JoinOrCreateRoom and CreateRoom. + Added: null check in Extensions.StripToStringKeys(). + Fixed: FriendInfo.IsInRoom, which returned the opposite of it's naming! Also changed FriendInfo ToString() according to PUN's. + Added: RoomInfo expectedUsersField, which is updated with room properties (well known ones). + Added: Room.ExpectedUsers and ClearExpectedUsers() to expose the list of expected players. + Added: RoomInfo.serverSideMasterClient and masterClientIdField (also updated with well known properties). + Changed: OpRaiseEvent now re-uses a Dictionary in the LoadBalancingPeer. It uses Clear(), rather than creating a new Dict each time. + Changed: AuthenticationValues to also use C# properties and and backup-fields. This is guaranteed to work in Unity. + Updated: EventCode ErrorInfo reference with a link to "WebHooks" doc online. + Changed: Disconnect handling in the LoadBalancingClient. The client should reset correctly and log info, if it's in a State where a disconnect is a proper error. Note: In some cases like "switching server", a disconnect is expected, so it's not an error then. + Fixed: PlayerProperties sent to game server will now include well-known properties again. This fixes the "NickName missing" bug. + Fixed: LoadBalancingClient.State value when the client fails to join or create a game on the Master Server. The state is correctly re-set to ClientState.JoinedLobby or ClientState.ConnectedToMaster. + Internal: Added private inLobby value, to store if the client was/is in a lobby on the Master Server. + Fixed: DemoClient (in demo-loadbalancing) now makes use of the Name Server by using: ConnectToRegionMaster("eu"). + Added: DemoClient now has debug output when the connection times out or can't be established. + + +*** Version 4.0.5.1 (18. January 2016 - rev3187) + Fixed: EnetPeer.ExecuteCommand(). Fixed: Receiving a Disconnect-command didn't clear the receive-buffers. However, it has to be the last command executed. + Note: The bug related to the Disconnect-command happened, when an app paused, queued incoming commands and executed the Disconnect while incoming commands were queued. + Fixed: Setting of DisconnectTimeout for TCP connections (ReceiveTimeout and SendTimeout). + Changed: Our protocol serializes Enums implicitly as their underlying Type. This means you can easily send them but will lose the Type info (they don't arrive as your Enum type). This is now also working in Windows Store libraries (NETFX_CORE). +LoadBalancing: + Added: OpSetCustomPropertiesOfActor() and OpSetCustomPropertiesOfRoom() now check locally, if the client is currently in a room. It must be, to be able to set these properties. An exception exists for setting properties for the local player's actorNumber, but those are better set via LoadBalancingClient.LocalPlayer. +Unity SDK: + Changed: The Unity condition which defines "using Hashtable = ExitGames.Client.Photon.Hashtable;". All versions of Unity 4 and up now define that Photon's Hashtable is needed. This is only in the LoadBalancing API, not in the demos. + Added: WebGL support + +*** Version 4.0.5.0 (3. December 2015 - rev3144) + Changed: Signature of SetCustomProperties methods. All overloads now include a final, optional "webForward" parameter. This enables you to update a WebHook when properties change. This is intended for turnbased games, not for high-frequency updates - use with care. + Internal: Added more debug output to error messages from the socket usage. This should now always include the ServerAddress to make things easier to debug server-side, if needed. + Added: Serveral new ErrorCode values, which will be used by v4RC5 and newer servers. See ErrorCode.JoinFailed***, HttpLimitReached and ExternalHttpCallFailed. + Fixed: LoadBalancing API now reads the correct "NickName" key from the server's authentication response. So far, it was reading a key that is never used. Note: This means you can set a user's NickName server-side to override the client's nickname. +Chat + Added: A MessageLimit field for ChatClient and ChatChannel to limit the number of messages the client keeps locally. It might be useful to limit memory usage in long running chats. Set ChatClient.MessageLimit to apply the limit to any channel subscribed afterwards or apply a limit individually. + +*** Version 4.0.0.12 (3. November 2015 - rev3112) + Added: Support for IPv6. Note: IPv6 does not work in Unity yet. It has issues with IPv6. (Case 740910) + Note: Host name resolution will prefer IPv4 over IPv6, if both IPs should be available. IPv6 Addresses must use brackets! Example: [::1]:5055. This separates the port from the address. + Added: Error logging when Addresses can not be resolved to IPs. + Changed: LoadBalancingClient OpJoinOrCreateRoom() no longer allows you to re-join a room. Simply remove the ActorNumber from the parameters. To re-join, use OpJoin with actorNumber (Player.ID that was assigned in the room). + Added: Support for PS4 in Unity LoadBalancing SDK. Note: The demos are not all updated with controller support, as we use the old UI, still. To test export, use the Particle Demo. + +*** Version 4.0.0.11 (28. October 2015 - rev3093) + Changed: Sending a generic Dictionary (with specific types) will now throw an Exception, if any key or value is null. This limitation does not include Dictionaries which use object as type. Those Exceptions are one of the few, which are not catched and turned into a debug message. Catch them by wrapping Operation calls, where needed (OpRaiseEvent()). + Changed: TrafficStatsGameLevel public properties are now settable. This enables you to reset individual values to (e.g.) show "LongestDeltaBetweenSending of the past second". + Added: CommandLog debugging option. This can be used to get a list of sent reliable commands and their ACKs (from the server). Default is 0 size ("off"). + Added: CommandLogSize and CommandLogToString() to PhotonPeer. This is part of a LoadBalancingClient.loadBalancingPeer. + Added: Several PhotonPeer values to analyze connections: ConnectionTime, LastSendAckTime and LastSendOutgoingTime. PacketLossByChallenge is probably a tempoary addition to check if we have to drop corrupted packages due to bad "challenge" value. + Added: Log for incoming reliable commands. The most recent 200 entries will be logged with the CommandLogToString(). This is probably temporary. + Changed: Timing for resending reliable commands in RUDP. The peer will check the sent-queue more frequently now, no matter at what time some random command would have to be repeated. Repeats should be more timely, based on their dynamic resend-timing. + Changed: PhotonPeer.MaximumTransferUnit minimum is now 576 (was 520, which was lower than on the server). + Internal: Channels in the EnetPeer are now stored in an array, so we can replace some foreach-loops with for-loops. +LoadBalancing (Realtime and Turnbased API) + Added: LeaveLobby handling in OnOperationResponse(), which sets the client's state correctly. + Changed: Order of execution for Ev Join. If user is known (inactive user rejoins), the player's props are read. The actor list is used, if available. + Changed: RoomOptions to use properties with backup-fields to avoid issues in Unity which has issues with Object Initializer (curly brackets). + Changed: JoinMode 2 is now "JoinOrRejoin". Was: "Rejoin". + Added: ErrorCode constant AuthenticationTicketExpired. + Internal: OpJoinRoom, OpCreateRoom and OpJoinRandomRoom no longer use a (growing) list of properties. Instead, classes were created to "sum up" their parameters. The api for games didn't change. + Internal: Related to the refactoring of Join/Create, the LoadBalancingClient now creates a Room instance when the client arrived on the GameServer (before, it got created in the initial "create" call). +Chat + Added: More sanity checks on operations (empty userId or secret, max friends). + Added: Special debug logging when the server returns an error for "Operation Unknown". In this case, it's highly likely that you don't use a Chat AppId. + Added: More helpful error logging. + +*** Version 4.0.0.10 (14. July 2015 - rev2988) + Removed: LitePeer class and complete "Lite" namespace. It's highly recommended to use the LoadBalancing API (LoadBalancingClient, etc). The (few) operations that were defined in Lite are no longer required really. + Refactored: Some "base" enumerations that were provided by the Lite peer. They are now in LoadBalancingPeer. + Added: support for RoomOptions.Plugins. Which we need now since we support multiple plugins per plugin dll - for testing purposes for instance. + Fixed: The wrapper classes for the native sockets now do a Sleep(15) when there's nothing to receive. This reduces CPU load considerably. + Fixed: Unity library SocketWebTcp class for websocket support. It requires a coroutine on a new GameObject which is now marked as DontDestroyOnLoad(go) and survives scene loading. + Fixed: The Windows 8 SDKs now include the release assemblies. This makes sure you can submit your app to the Windows Store. + Added: ConnectionProtocol WebSocket and WebSocketSecure. It's simply a different protocol, compared to UDP and TCP, so it should be separated. + Internal: DoFraming is now a part of TPeer (was in IPhotonSocket). It's set by the ConnectionProtocol which avoids misconfiguration. + Changed: SendPing can now send a ping binary message or enqueue the Ping Operation (when DoFraming is false). + Added: A null-check for TrafficStatsStopwatch to avoid NullReferenceExceptions. + Added: Compile condition for Ping result handling. It's only used when the client uses Sockets as well (for the time being). + Added: Unity WebGL export also sets a "using" Hashtable definition. + Fixed: An exception in Photon.Hashtable.ToString() if a value was null. The assumption was that there are no null-values. + Changed: SocketUdp and SocketTcp now implement IDisposable, which seems to help with infrequent freezes in the Unity Editor. + Added: PhotonPeer.QuickResendAttempts. Sets how many resend attempts for a reliable command will be done in quick succession (after RTT+4*Variance), before the time between repeats will be increased. Use with care and with low values. + Added: IP/Hostname to logged exceptions when Connect fails. This is easier to support (e.g. DNS lookup fails). + Fixed: Library for PUN+ export to WebGL. Originally, we forced UDP as protocol for PUN+ export, as the native sockets library doesn't support TCP. However, WebGL export introduced a new use case. + Added: LoadBalancingClient.EnableLobbyStatistics and .LobbyStatistics. They provide an overview which lobbies your game uses and how busy they are. + Fixed: The LB Demo should set CustomProperties instead of directly setting (any) properties. + Fixed: SocketWebTcp is completely empty, unless WEBSOCKET is defined. Before the file still contained the "using" part of the class. +LoadBalancing (Realtime and Turnbased API) + Updated: Description for IsConnectedAndReady. + Changed: NameServerAddress to return a fitting address depending on protocol (including WebSocket but not yet RHTTP). + Updated: The only name server host is now "ns.exitgames.com", which gets turned into a proper address by protocol. + Changed: LoadBalancingClient.CustomAuthenticationValues is now .AuthValues. You can use those values to identify a user, even if you don't setup an external, custom authentication service. + Changed: LoadBalancingClient.UserId no longer directly stores the id but puts it into AuthValues. This means, the UserId could also be set via setting AuthValues. + Changed: The API of AuthenticationValues. There is now the UserId and AddAuthParameter() replaces the less general SetAuthParameters() (which only set specific key/values). + Changed: PlayerName gets renamed to NickName, so PhotonPlayer.Name becomes .NickName and LoadBalancingClient.Name becomes .NickName, too. The old naming is marked as obsolete. + Changed: Particle Demo now connects to the Cloud by default (because it's easier to setup and try). You can define your own Master Server (Photon OnPremise) of course. + Added: GamePropertyKey.MasterClientId (248) and ParameterCode.MasterClientId (203) + Added: ParameterCode.ExpectedValues (231) + Added: ParameterCode.SuppressRoomEvents (237) +Chat API: + Added: A Unity 4.6 demo with uGUI. It's missing a few features but should give you a good start to making your own. + Added: Unity/WebGL support (merged from PUN). + Added: Breaking! IChatClientListener.DebugReturn(). Photon lib and chat client log via this method (no logging to console by default). + Changed: ChatClient.CustomAuthenticationValues is now .AuthValues. You can use those values to identify a user, even if you don't setup an external, custom authentication service. + Changed: ChatClient.UserId no longer directly stores the id but puts it into AuthValues. This means, the UserId could also be set via setting AuthValues. + Changed: The API of AuthenticationValues. There is now the UserId and AddAuthParameter() replaces the less general SetAuthParameters() (which only set specific key/values). + Note: All users should have a UserId. You can set chatClient.UserId before you connect, or you can set the AuthenticationValues in Connect(..., authValues) to set a UserId. + Added: ChatChannel.ToStringMessages(), which gets all messages in a single string, line by line. The format is "Sender:Message". + Added: ChatClient.TryGetChannel() to find a channel only by name, no matter if public or private. +Photon Unity SDK + Changed: Organization of APIs and Assemblies in SDK. Now you can copy the content of folder "PhotonAssets" into your project's Assets folder and you have all APIs. + Added: PhotonAssets-U5 folder which includes only the Windows Universal DLL. + +*** Version 4.0.0.8 (14. January 2015 - rev2765) + Fixed: Serialization of custom types with nested Serialize-calls. In this case, re-using a specific memory stream breaks it. + +*** Version 4.0.0.7 (12. January 2015 - rev2763) + Fixed: Serialization of arrays of custom-types. +Chat API + Internal: Changed code for UserID from 7 to 225. The latter is used in LoadBalancing, too, so we want to re-use the code here. + +*** Version 4.0.0.6 (05. December 2014 - rev2758) + Added: ChatApi and LoadBalancingApi folders to Unity SDK. They are needed in any Photon project with Unity. When updating, copy and paste the files over existing ones and make sure to replace the assembly-files, too. + Changed: Protocol to save more memory or re-use it. The idea is to have less Garbage Collection (primarily for Unity/PUN and custom types). + Added: New CustomType de/serialization methods which provide the MemoryStream, instead of a byte[] COPY from the stream. + Changed: Now using one method to identify a Type. This was duplicated code before. + Changed: De/Serialization of some types. + Note: The drawback is now, that there are more places with: lock(). This is far from optimal but the alternative would be to make Protocol instances per thread. As most is static at the moment, this would not be an easy task. + Added: position check for DeserializeStreamFunction() call. Stream position must be "previous + customtype length". It gets corrected but at the moment no error is thrown. + Changed: DispatchIncomingCommands() no longer instantiates the commandsToRemove each call. This is reused and thus saves memory. + Changed: net_fx build will now check IsConstructedGenericType to detect if something is a dictionary +LoadBalancing + Added: LoadBalancingClient.OpJoinOrCreateRoom overload which has lobby as parameter. If a room gets created, this defines in which lobby it belongs. + Changed: LoadBalancingPeer: Added new error code PluginMismatch, documentation for Plugins parameter code. + +*** Version 4.0.0.5 (23. September 2014 - rev2738) + Updated: AddFriends and RemoveFriends doc. + Changed: Logging level for two cases. Dropping a package due to failed CRC-check is now logged for INFO. It's expected and certainly not an error. Dropping a package when the incoming challenge does not match is also not an ERROR. It is expected when you switch servers and packages arrive late. This is now debug level ALL. + +*** Version 4.0.0.4 (19. September 2014 - rev2736) + Fixed: Fragmentation when CRC checks are enabled. This kept clients from sending fragmented commands when the additional 4 bytes CRC were included later on. + Fixed: An issue in the ChatClient which was referring to a class from Photon Unity networking. This caused compile issues in the Unity Chat Demo. + Updated: Reference doc generation. + +*** Version 4.0.0.3 (15. September 2014 - rev2731) + Updated: Doc generation settings and style. + Note: This version has no code changes to rev2728 described below. That version is already released in the Unity Asset Store in PUN. + +*** Version 4.0.0.3 (11. September 2014 - rev2728) + Fixed: A simple "order of things" issue when detecting a timeout (due to resends). We first have to set "Zombie" state so that any Disconnect() call created a disconnect-command with reserved byte = 2 = "due to timeout". + Fixed: Chat to be compatible with native sockets of PUN+ (iOS and Android exports from Unity). + Fixed: Access to native sockets (in classes SocketUdpNativeDynamic and SocketUdpNativeStatic) is now using a lock(). The native methods are not thread safe but we need more than one socket for PUN+ and Chat (with native sockets, too). + Changed: Logging for the case "Ignoring received package due to wrong challenge". This got logged on log-level ERROR but maybe is better as WARNING only. Now this should log less often. + Internal: Updated to a newer native-sockets interface. + Internal: Updated to a newer native-sockets interface (affects PUN+ only). Cleaned up precompile defines and #if usage. + +*** Version 4.0.0.2 (01. August 2014 - rev2715) + Added: PhotonPing class and subclasses per platform. Allows clients to use regular UDP messages to ping our servers and find the best region. + Added: Native and Win8 support for PhotonPing. + Known Issue: Native ping has to be done "one by one" and without any other connection in Unity. It's not yet thread safe (but that is ok as we don't want to ping most of the time but only rarely and out of game). + Added: PhotonPing class/file to Win8 platforms. + Changed: The extern static methods for the native libs are now internal (instead of private). Pings are using them, too. + Changed: WebRpcResponse.ReturnCode comment to include fail code. + Changed: OpWebRpc doc is now much more complete and helpful. + Updated: Unity SDK Particle Demo (more) and LoadBalancing Demo (just a bit). + +*** Version 4.0.0.1 (17. June 2014 - rev2663) + Fixed: DotNet assembly no longer contains classes that try to include our Unity native socket libs. This was causing issues in some cases. + Added: PhotonPeer.CommandInfoCurrentDispatch. This property gives you the debug string of the currently dispatched command (events or responses). Only useful for UDP. +LoadBalancing: + Added: LoadBalancingClient.OpRaiseEvent(). Now that LoadBalancingClient USES a loadBalancingPeer (and doesn't extend it), things are much easier by offering this method, too! + Added: LoadBalancingClient.IsConnected and .IsConnectedAndReady to LB API. Going to be part of the API from now on. + Removed: Unused fields clientId and clientCount. + Changed: Field for internal use "lastJoinActorNumber" is now private as intended. + Changed: LoadBalancingClient.Disconnect is now setting it's own state to Disconnected if the connection got closed (as expected). +Chat: + Changed: How the server responds to Subscribe and Unsubscribe. Events will now contain success/failure of those. This allows us to send the answer after calling a WebHook if needed and we can even send it to multiple clients (which authenticated with the same userID). + Changed: Handling of subscription responsed. This is done to allow web services to subscribe a client remotely and to be able to prevent joining some channel that a user should not join (the channel of some guild or another team, e.g.). + Changed: Debug loggging. In Unity we can't use Debug.Assert, etc. So we have to log more cleanly. This works in Editor and several platforms (but not all). + Changed: Folder for Chat API. It now begins with "Photon" which provides some context no matter where you copy the files. Easier to find in Unity projects. + Changed: Operation FriendList and method SendFriendList renamed to AddFriends + Added: Operation RemoveFriends and corresponding method in ChatClient.cs + Added: Console Demo has new command 'fr' to remove friends + +*** Version 4.0.0.0 (23. May 2014 - rev2614) + Changed: This version contains a few features that are not compatible with the Photon Server SDK v3.x. Notable features that are not in the Server SDK are: NameServer, WebHooks and Turnbased API features. + Changed: This SDK is the first that contains all current APIs for Realtime, Turnbased and Chat. + Fixed: Release build of the Unity assembly now also excludes native-socket using code, fixing a Unity Free export issue. We only use the debug assembly in our demos though and suggest you do the same. +LoadBalancing: + Changed: LoadBalancingClient.FriendList creation/update is delayed until the server's response is available. This avoids cases where the friends are offline for the moment between requesting the update and getting it. Initially, it is null as before. + Added: some methods to Player to find next player, etc. Useful for turnbased games to find an opponent. + Added: LoadBalancingClient.UserId, which is the ID of a user(account). This is used in FindFriends and when you fetch account-related data (like save-games for Turnbased games). Set it before Connect*(). As fallback when empty during connect, the PlayerName is used instead. + Removed: LoadBalancingPeer.OpSetCustomPropertiesOfActor and OpSetPropertyOfRoom which were too special to be so low level. Could be implemented to LBClient. +Turnbased: + Fixed: OpJoinRandomRoom and OpCreateRoom which didn't reset the ActorNr to claim when entering the room. Depending on previous actions, some calls of those methods did fail when the actorNumber wasn't available. + Changed: OperationCode.Rpc is now called OperationCode.WebRpc. It's simply much cleaner (considering PUN has RPCs as well but in a different context). + Changed: WebRpcResponse reading to be able to handle additional data. + Added: Parameter webForward to: OpSetCustomPropertiesOfRoom and OpSetPropertiesOfRoom. The "old" overloads of these methods are still there, too. If webForward is true, the properties are sent to the WebHooks. +Chat: + Added: SendPrivateMessage() overload that has option to encrypt private messages. Public messages don't need encryption. + Removed: lastId and LastMessageIndex from channels. Those were impractical and should be removed from the API. + Changed: UserStatus class to ChatUserStatus. + Changed: Most classes are defined in their own file now. + Removed: Folders "Shared" and their subfolders. This gives a much better overview. + Added: Handling for event SubscribeResponse. This is not actually a response but gives you info about channels that got subscribed (e.g. when you re-login quickly or when a user is logged in in multiple clients). + Added: HandleSubscriptionResults() method to handle the event and proper responses. + +*** Version 3.2.2.6 (13. May - rev2575) + Fixed: Windows Store and Windows Phone libraries now only send the bytes they should send. This means we have to copy the payload from the "complete package buffer" in order to send it. + Fixed: SocketTcp now handles all exceptions during reading. Still, abort-by-server is treated as ServerDisconnect. Everything else as client side disconnect. This fix is especially for iOS exports from Unity. The iOS Power-button will immediately cut any connection. The Home-button allows us to keep the connection if we return the app to focus within a few seconds. + Fixed: TPeer.StopConnection() now clears the incoming queue when it disconnects. This avoids getting any more (already received) commands. + Changed: TPeer.Disconnect() now uses StopConnection instead of implementing the same code again. + +*** Version 3.2.2.5 (30. April - rev2566) +LoadBalancing: + Added: TypedLobby class to replace lobby name/type pair. + Added: LoadbalancingClient.CurrentLobby property. CurrentLobbyName and CurrentLobbyType are obsolete. + Added: New overloads in LoadbalancingClient with TypedLobby parameter instead of separate lobby name and type: OpJoinLobby, OpJoinRandomRoom. Old methods marked obsolete. + Added: New overloads in LoadbalancingClient for OpJoinOrCreateRoom, OpCreateRoom, CreateRoom with parameters packed in RoomOptions class. Old methods marked obsolete. + Breaking: LoadbalancingClient.CreateRoom parameters changed to (string roomName, RoomOptions opt). + Internal: Removed obsolete LoadBalancingPeer overloads of OpCreateRoom and OpJoinRoom + Internal: Added 'onGameServer' parameter to LoadBalancingPeer OpCreateRoom, OpJoinRoom; used to avoid sending extra data to master (player- and room-props) + Internal: Loadbalancing Room constructor(string roomName, RoomOptions opt). + Internal: Added use of the "JoinMode" parameter which is used in context of Turnbased games. + Fixed: Bug in OpLeaveLobby which joined the default lobby instead of leaving any lobby. +General: + Fixed: Server ports were read as short, which was wrong. We now use the correct unsigned short to convert from the address string). + Fixed: A minor issue in the SupportClass ToString conversion which used a Hashtable's key type instead of the value's type in one place. + +*** Version 3.2.2.4 (21. March 2014 - rev2519) + Internal: For Unity, the classes that handle native sockets can now be compiled in a variant that does not actually reference the native-socket-libs. The dll for PUN+ uses native sockets and need the native libs. Any regular dll will have the (not used and empty) classes for build-compatibility reasons. + Added: Values to enum EventCaching: SliceIncreaseIndex, SliceSetIndex, SlicePurgeIndex and SlicePurgeUpToIndex. They are in Lite but used in LoadBalancing. This is likely to be cleaned up in the next major release. + Changed: EventCaching MergeCache, ReplaceCache and RemoveCache as they belong to an outdated form of caching. The "RoomCache" is the better option in any case. +LoadBalancing: + Added: RaiseEventOptions class. It's used for OpRaiseEvent to avoid further parameter- and overload-clutter for this operation. While it's still not optimal for all cases, the fields in the RaiseEventOptions class are hopefully more clear how to use. Maybe some constructors will be added soon. + Changed: All OpRaiseEvent variants, except the one with RaiseEventOptions is now obsolete. + Added: Event Cache Slicing. Cached events can now be organized into "slices" which allows you to handle them in chunks. You can purge events in specific slices (e.g. get rid of the previous game-rounds events). +Turnbased: + Added: RaiseEventOptions.ForwardToWebhook which allows you to forward an event to a webhook (to be defined in Dashboard). Use this rarely, as it has an impact on (server) performance! + +*** Version 3.2.2.3 (18. February 2013 - rev2493) + Added: const PhotonPeer.NoSocket, so programs using our assemblies can detect if they must provide an external SocketImplementation. Some builds avoid using the Socket class (cause Unity Free doesn't support it on all platforms). + Added: PhotonPeer.SendMessage method in order to send any serializable object to server. + Added: IPhotonPeerListener.OnMessage in order to be notified about getting message from server. + Added: new 'Connect' method, which accepts as third parameter any serializable object. You may use this object on server before creating peer. + Added: OnMessage callback to samples + Changed: TCP and UDP both set the socket to null explicitly in Disconnect(). Hopefully this fixes a misbehaviour in Unity Editor which locked up often. + Changed: SocketTCP now has a syncer object and locks in Disconnect(), so only one Disconnect call can be made anytime. + Fixed: Nullreference when calling DispatchIncomingCommands() before Connect(). This was due to a (new) use of the socket wrapper. Commented this out until needed. + Fixed: Nullreference when calling SendAcksOnly() before Connect() with a new non-null check. + Fixed: breaking issue in Hashtable replacement class. Enumerators used in 2 "foreach" loops were breaking with a nullreference. Fix: No caching of enumerator. + Changed: AutoJoinLobby now uses this.CurrentLobbyName and this.CurrentLobbyType to join a specified lobby. + Changed: EnetPeer.StopConnection will always reset the state to be able to re-connect. + Changed: Disconnect() in SocketTcp and SocketUdp sets this.socket = null, even if socket.Close() caused an exception. This is what was expected. + Added: SocketUdpNativeDynamic and SocketUdpNativeStatic to "regular" Unity Lib, to improve compatibility in Unity for different export platforms (with and without native sockets). + +*** Version 3.2.2.1 (17. October 2013 - rev2335) + Note: This lib contains a lot of breaking changes and socket handling has been refactored. By now, this is well tested and confirmed working. + Changed: The way sockets are handled and added native-socket-lib support. There is a new IPhotonSocket interface which even allows to use external classes as socket wrapper. + Added: SocketImplementation property to set a class as socket implementation (Unity. sets native implementation or c# socket at compile time) + Changed: Win 8 RT and Phone now use fewer separate classes and files. Instead, more files from the (regular) DotNet client are used. RT and Phone are now part of the trunk folder in our SVN. + Added: TrafficStats.TimestampOfLastAck and .TimestampOfLastReliableCommand + Changed: Handling of server-side shutdown (a form of TCP disconnect) is now handled specifically as server-side-disconnect (was: generic receive exception) + Added: If a UDP connection times out in a client, it sends a special flag in it's disconnect command (to the server). This enables us to detect which side is triggering timeouts more often (and we can improve things). +LoadBalancing API + Fixed: issue where we called a virtual member from a constructor (http://confluence.jetbrains.com/display/ReSharper/Virtual+method+call+in+constructor) + Changed: LocalPlayer is now a property which checks null and returns a new Player (via virtual CreatePlayer) on demand. + Added: OpJoinRoom now optionally creates a room if parameter "createIfNotExists" is set to true and the room didn't exist. Room properties can't be set "on create" this way. LocalPlayer.IsMasterClient will be true. + Added: When OpJoinRoom can create a room, it also won't define which properties go into the lobby. You can use the new Room.SetPropertiesListedInLobby(). + Added: You can pass a actorNumber to OpJoinRoom when you re-enter a room and want to reclaim a specific actorNumber in that room. In best case, the client can re-join after a disconnect/crash and seamlessly go on playing. + +*** Version 3.2.1.6 (15. August 2013 - rev2272) + Changed: The library for Unity now contains a ExitGames.Client.Photon.Hashtable to be compatible with Win 8 exports. This must be used from now on! + Note: In Unity, the compiler will complain about ambiguous Hashtable definitions. To solve this, add this to the "using" part of your code: using Hashtable = ExitGames.Client.Photon.Hashtable; + Removed: Builds for Silverlight and Windows Phone 7.1 (this is not affecting Windows 8 RT and Windows 8 Phone SDKs which are of course supported) + Fixed: A null-reference check for a TCP connection's SendAcksOnly(). + +*** Version 3.2.1.5 (06.08.2013 - rev2242) + Added: Steam and Facebook entries to CustomAuthenticationType enum. + Fixed: Potential nullreference exception in TCP SendAcksOnly() code. If called before Connect(), this always failed. + Updated: Replacement classes for datatypes not supported on some platforms (Hashtable mostly). + Added: Hashtable got a new GetEnumerator that returns a IDictionary just like the standard Hashtable does. + Changed: Constructor with int InitialSize now calls the matching base constructor. + Removed: Synchronized() method which didn't do much and is not used. + Changed: ToString is now an override instead a "new" method. + Changed: DataTypes.cs: the Stopwatch is only implemented for Silverlight (non Windows Phone 8) + Updated: Description. + Changed: Protocol to expect Hashtable always providing a DictionaryEntry. Related to change in DataTypes.cs. + Changed: Protocol now has conditional "Dictionary" detection. In WP8 the API is different for that. Uses #if WINDOWS_PHONE. same file now works in W8 and WP8. + Changed: Removed PRPCAttribute from SupportClass.cs. This is used only in PUN and needs conditional per-platform compilation anyways, so it gets implemented there. + Removed: surplus debug output in ReceiveIncomingCommands(). + Fixed: Debug output in FetchServerTimestamp() depended on the Thread calling the method. Correct: The output is enqueued and dispatched later on. + Fixed: FetchServerTimestamp no longer fails with a SendError when the state is not "Connected". + Internal: Metro-Alike project now uses DataTypes.cs of Silverlight (like everyone else). Removed surplus copy. + Internal: DataTypes.cs and Protocol.cs files can now be used in DotNet 3.5, Windows Store and Windows 8 Phone. + Internal: outdated compiler-definitions "Photon" and "METROALIKE". + +*** Version 3.2.1.4 (10.07.2013 - rev2209) + Added: "Typed Lobby" API. Photon Cloud and Loadbalancing now support multiple lobbies per app/title. Also, different types of lobbies are now possible, each can have different options and different rules for matchmaking. + Added: enum LobbyType with "Default" and "SqlLobby". The SqlLobby is a new type of lobby that uses up to 10 room properties with sql-like filters. The filter being written like the "where" part of a sql query. + Changed: FetchServerTimestamp now enqueues callbacks (can be called by socket-receive-thread). also no longer causes a disconnect callback if offline + Changed: RemoveSentReliableCommand now enqueues callbacks (can be called by socket-receive-thread) + Internal: SendAcksOnly override in TCP's TPeer class. This now sends pings but nothing else. That resets the server's timeout for this peer +LoadBalancing API + Updated: LoadBalancing API in the Unity demos (now gets copied over at build time, making sure it's identical to the DotNet "original") + Fixed: LoadBalancingClient now handles SecurityException and InternalReceiveExceptions and disconnects correctly. Before, especially Unity web clients would get stuck in "Disconnecting" state. + Fixed: LoadBalancingClient state on disconnect (no matter what caused the disconnect). + +*** Version 3.2.1.3 (19.06.2013 - rev2170) + Fixed: surplus conversion of incoming data to string, which was used in debugging. + +*** Version 3.2.1.2 (17.06.2013 - rev2160) + Fixed: custom auth will send custom auth parameters if any authentication params are set + +*** Version 3.2.1.1 (10.06.2013 - rev2148) + Added: new POST value for Custom Authentication. POST can carry more data than GET (usually used). AuthenticationValues has a setter for this. +LoadBalancing API + Changed: LoadBalancingClient.AuthValues is renamed to CustomAuthenticationValues property (sets the custom authentication values). + Changed: Player class now compares by ActorNumer (assigned by server) instead of comparing the instance. + Internal: SupportClass.GetMethods() now returns type.GetRuntimeMethods(), filtered by attribute (if at all needed). This is used by Photon Unity Networking (PUN) internally. It also returns inherited methods now, not only Declared. + +*** Version 3.2.1.0 (24.05.2013 - rev2112) + Added: Feature "Custom Authentication" which lets you authorize players/users in the Photon Cloud with an external account/user service. More on that online: http://doc.photonengine.com/photon-cloud/CustomAuthentication + Added: LoadBalancing API Feature "Friend Finding" which enables a client to find friends in rooms by userId. If an external service provides a userID per player and a friend list, this can be used to find a friend's room (game) and join it (unless closed or full). + Added: CustomAuthenticationType enum to enable differnt types of custom auth later on (only one actually useful value so far). + Added: Class AuthenticationValues as container for authentication values. + Added: LoadBalancingClient.Connect overload which takes a AuthenticationValues parameter. + Added: LoadBalancingPeer.AuthValues property to set the custom authentication values. + Added: Parameter authValues to OpAuthenticate. This is used to provide the authentication parameters and or the secret/ticket provided by Photon. + Added: ErrorCode.CustomAuthenticationFailed to be used in switches for OperationResponse.ErrorCode (for OpAuthenticate). + Changed: LoadBalancingClient.PlayerName can be set before connecting to get a UserId which is "findable" by OpFindFriends(). Find friends does NOT use any values set for custom authentication! + Added: Class FriendInfo to contain a friend's name, online state and room name (if available and after using OpFindFriends()). + Added: OpFindFriends() to actually find the friends. Use on the Master Server only, not on a room. + Added: LoadBalancingClient.FriendList, a List of FriendInfo entries. Filled by using OpFindFriends (don't modify this list directly!). + Added: LoadBalancingClient.FriendListAge, to let you know how old the FriendList is. Only get updates when the list gets "old". + Fixed: OpRaiseEvent will no longer send "group" if it's 0 (which is the default). + Added: OpRaiseEvent overload to send object instead of Hashtable. This overload uses another parameter order to not mix up with the older implementation. You can send any serializable datatype now but must be aware if the event is Hashtable or something else. + Changed: Several variants of OpAuthenticate(), Connect() and ConnectToMaster() are now obsolete or removed. Use the alternative implementations (which should be cleaner). + Internal: Added several (operation) parameters to enum ParameterCode: ClientAuthenticationType, ClientAuthenticationParams, FindFriendsRequestList, FindFriendsResponseOnlineList, FindFriendsResponseRoomIdList. + Added: PhotonPeer.ResentReliableCommands to get count of re-sent commands (might be higher than out command count (as that counts created commands only) + Internal: Address (string) handling now uses string.Split instead of IndexOf to separate port from address and short.TryParse instead of short.Parse + Added: TrafficStatsGameLevel.ResetMaximumCounters() to reset those values that could max-out easily. Allows to get "longest delta between SendOutgoingCommands()-calls since last query". + +*** Version 3.2.0.2 (21.02.2013 - rev2066) + Fixed: Potential lock-up during sending. This could cause infinite blocking and thus a crash in some apps. (Win8 / Win Store api only) + +*** Version 3.2.0.1 (15.02.2013 - rev2060) + Fixed: Issue with delayed sending of operations in udp. The data could become overwritten before being sent. The bug was leading to high disconnect rates for clients using Windows Phone 7 and 8 and Silverlight or any client that used Network Simulation. + +*** Version 3.2.0.0 (13.02.2013 - rev2053) + Note: This release only changed the version, matching the new Server SDK v3.2.0.0 + Updated: readme.txt + Fixed: Reference for Windows 8 RT and Windows Phone 8 SDKs. + Added: Particle Demo to Unity Client SDK. + +*** Version 3.0.1.18 (11.02.2013 - rev1998) + Added: Optional per package CRC checksums to filter out compromised packages (avoiding more issues, compared to reading bad values). + Added: PhotonPeer .CrcEnabled and .PacketLossByCrc to handle CRC and get the count of affected (incoming) packages. + Note: Checking packages with CRC will take some computation time. Consider this an option to detect if/why someone's connection is bad. It's likely not good to be enabled by default. +Windows 8 RT & Windows 8 Phone: + Fixed: Serialization of foat and double values. These caused exceptions when used in object-arrays. + +*** Version 3.0.1.17 (19.12.2012 - rev1946) + Added: New Platform: Mono 4 Android. Please check the Readme.txt for hints how to build the demo in Mono 4 Android. + Changed: The referenced DotNet assemblies used by our libraries, which makes ours compatible with Mono 4 Android and others. + Changed: The Particle Demo Logic to also handle events sent by JavaScript clients. In case these are used, the types used in event differ from what DotNet or other clients send. + Changed: PhotonPeer.LocalTimeInMilliSeconds property now uses SupportClass.GetTickCount(). That method is using Environment.TickCount (which can be replaced if needed). + Changed: Any place that directly used Environment.TickCount (as the way SupportClass.GetTickCount() gets the value can be replaced). + Renamed: GetLocalMsTimestampDelegate is now: SupportClass.IntegerMillisecondsDelegate (rarely used if at all). + +*** Version 3.0.1.16 (29.11.2012 - rev1923) + Internal: A client timeout now internally sets connectionState to Zombie and then calls Disconnect() instead of stopping the connection right away. + Changed: Disconnect() sends a disconnect-command in any case (except not connected or disconnecting). If the connection is not in state connected anymore, said command is unsequenced (unreliable) and the disconnect is locally executed immediately as call to StopThread(). As before, disconnecting and disconnected clients won't send this. + Changed: Ping creation is now more strict and checks also if any reliable commands are outgoing AreReliableCommandsInTransit(). this avoids a few pings. + Fixed: NullReference exception in StopConnection() if it's called before being connected for the first time (late object creation made this fail). + Changed: PhotonPeer.LocalTimeInMilliSeconds property now uses SupportClass.GetTickCount(). That method is using Environment.TickCount (which can be replaced if needed). + Changed: Any place that directly used Environment.TickCount (as the way SupportClass.GetTickCount() gets the value can be replaced). + Renamed: GetLocalMsTimestampDelegate is now: SupportClass.IntegerMillisecondsDelegate (rarely used if at all). + + +*** Version 3.0.1.15 (27.11.2012 - rev1917) + Note: Silverlight SDK release only! + Updated: Silverlight projects with proper references (hopefully). In case you wonder: Some projects are included even though only their (source) files are linked in Silverlight. We can't reference DotNet projects directly, so we use the (shared) files instead. + Updated: Silverlight Particle Demo now has a basic gui and hopefully helps with your first steps. + +*** Version 3.0.1.14 (16.11.2012 - rev1891) + Added: Interest Groups! In rooms, you might send events to an interest group, identified by a byte (255 groups are currently allowed). OpChangeGroups lets you add or remove groups you're interested in. + Added: New platform! Welcome Windows 8 RT and Windows Phone 8. Both are "preview" releases but based on the stable DotNet basis we have. + Note: The Windows Phone 8 SDK does not yet have a LoadBalancing demo but the API is available (Windows Phone 8 is separate from the still existing Windows Phone 7.1 SDK). + Added: Another new platform: Playstation Mobile! This is Sony's SDK for mobile platforms. Find out more about it: www.playstation.com/psm + Added: Silverlight 4 SDK is back. Now with LoadBalancing API (the demo implementation is not finished but the basic "logic" is running). + Fixed: Windows Phone 7 and Silverlight TCP error handling while connecting to the server. This should fix issues with failing connects due to missing policy settings. + Internal: Windows Phone 7 and Silverlight TCP connections now set their state a bit differently (this doesn't affect the workflow though). + Internal: Http implementation now checks if a Proxy was set deliberately. Check is: (WebRequest.DefaultWebProxy as WebProxy != null). + Internal: DispatchIncomingCommands() now avoids copying lists when checking for commands that need a repeat. + Internal: SendOutgoingCommands() now re-uses a buffer to create UDP packages in before sending. This should save a lot of memory allocation. +LoadBalancing API: + Added: New demo "Particle". You will notice it's similar to the "Realtime Demo" but LoadBalancing- and Cloud-compatible and it makes better use of the default features. Check out Particle "Logic". + Added: LoadBalancingClient.DisconnectedCause to track certain disconnect causes (no matter if the connection or an operation caused the disconnect). + Added: DisconnectCause enum to enumerate those disconnection causes. + Changed: LoadBalancing OnOperationResponse() and OnStatusChanged() to track most disconnect reasons (in DisconnectedCause). + Removed: LoadBalancing Connect() variants that essentially were duplicates of others. + Changed: LoadBalancingClient debug output now goes to: Debug.WriteLine (which is available in debugger, while Console is not always). + Changed: CacheProperties method is now virtual for Room and Player. This allows you to override it and use this as callback to update props. + Added: Player.Tag to store arbitrary (game) data with the Player. Put in (e.g.) a player's representation/avatar or similar. + Added: ErrorCode constants MaxCcuReached and InvalidRegion. These are important for the Photon Cloud. + Added: Handling for DisconnectedByUserLimit. This is a status of OnStatusChanged when a Photon Server License's CCU limit is reached. This no longer will try to connect to a Game Server (where it gets rejected, too). + Changed: Debug output of loadBalancingClient now goes to Debug.WriteLine (which is available in debugger). + Changed: API now uses a factory method to create Room instances (this makes it possible to extend the Room class and instantiate the new class instead). + Changed: The Player constructor now has an "actorProperties" parameter and will cache the provided properties. This makes sure actor-props are available locally. +Windows Phone 8: + Added: Demo for Cloud / LoadBalancing. The Particle Demo only has a special WP8 GUI and links it's logic from a separate project (read: folder). +Windows 8 RT: + Added: Demo "Phong", which is a simplified, basic multiplayer game. It's focus is to show how to sync data, not to make it super smooth and error free. Let us know any issues but bear with us as it isn't fully featured. + +*** Version 3.0.1.13 (26.09.2012 - rev1731) + Fixed: Internals of method DispatchIncomingCommands() for UDP. In some cases this removed commands from a dictionary inside a foreach loop (which causes an Exception due to changing the dictionary) + Added: Support for Dictionary<,>[]. This is not a very lean way to send data (especially when using ) but if needed, it now works + Changed: Replaced several foreach loops with for loops (it doesn't change usage but in Unity exports to iOS, foreach uses more memory than for) + Added: Doc for public methods in Protocol class (they are useful to quickly write values into an existing byte-array) + Fixed: Unity UDP send code: iOS 5 devices will kill a socket when the power button is pressed (screen locked). This case was not detectable by checking socket.Connected. + Added: Unity UDP send code: Now tries to open another socket to refresh/keep the connection. This is affected by timeouts still, of course (as are all connections). + Internal: locked usage of UDP / enet channels + +*** Version 3.0.1.12 (26.07.2012 - rev1683) + Changed: The DotNet client libraries are now Thread safe! You could start a background Thread to keep calling SendOutgoingCommands in intervals and still call it from a game loop, too + Changed: Due to the thread safety, the demos no longer use excessive locks. This is now solved by the lib, more streamlined and hidden. One Thread is used instead of Timers (which could fire concurrently if execution was longer then their interval) + Changed: Moved the enable/disable property fro NetworkSimulationSettings to PhotonPeer.IsSimulationEnabled (this should now be thread safe) + Changed: NetworkSimulation will create and keep one thread when you first enable it in a (debug) client. Disabling it, will execute any delayed action immediately (in IsSimulationEnabled!) and pause the simulation thread + Changed: All demos are updated. We assigned new event codes (starting at 0, like any developer's code should) and extended the comments. Check them out + Changed: All Loadbalancing demos are now using the same DemoBasisCode linked in, so it can be changed in one position. Where needed an extension is made + Updated: comments / documentation for LoadBalancing API, Lite API and basic Photon API (basically anything public) + Changed: SupportClass.NumberToByteArray is now obsolete. It can be replaced with Protocol.Serialize() easily and that is performing better + Fixed: Windows Phone UDP socket was sending a full package of zeros on connect. It didn't break anything but is not needed, of course. + Fixed: SupportClass.StripKeysWithNullValues method was prone to throw an exception +LoadBalancing API: + Changed: LoadBalancingClient.OpLeaveRoom() skips execution when the room is null or the server is not GameServer or the client is disconnecting from GS already + Note: LoadBalancingClient.OpLeaveRoom() returns false in those cases and won't change the state, so check return of this method + Fixed: workflow for authentication (which should be called only once per connection, instead of "any time we establish encryption) + +*** Version 3.0.1.11 (05.06.2012 - rev1569) + Fixed: Udp issue with channels and unreliable commands. Unreliable commands of one channel were discarded, when another channel had unreliable commands, too + +*** Version 3.0.1.10 (04.06.2012 - rev1561) + Fixed: TCP connection issues for DotNet and Unity (Silverlight and WindowsPhone are different) + Fixed: DotNet+Unity TCP send calls with 0 bytes to send (this was ignored by the socket but useless anyways) + Moved: DNS resolution and socket.Connect() are now handled in the connection thread (TCP in DotNet and Unity) + Fixed: Issue with (TCP) socket connections being closed directly while connecting. in this case, socket.Receive() might receive 0 bytes instead of blocking until more bytes are available. without sending anything, the socket never updates its .Connected state and never throws a Exception. now we send a ping and thus trigger a exception + Fixed: Some documentation errors (due to changed API, etc) +Loadbalancing API: + Changed: LoadBalancingClient.OnEvent() now uses a join-event's actornumber-list to create Player instances for anyone who wasn't created as Player before + Fixed: LoadBalancingClient.OnEvent() handling for join-event does not expect any actor/player properties anymore (which fixes a potential null-reference exception when not even a name is set) + +*** Version 3.0.1.9 (10.05.2012 - rev1512) + Fixed: Reference to project in Windows Phone SDK + +*** Version 3.0.1.8 (09.05.2012 - rev1508) + Fixed: The OpJoinRandom of the LoadBalancingAPI failed to filter rooms for their custom room properties. Instead, any room matched. This is fixed now. + Added: New Demo for Windows Phone: Cloud Basics + Changed: The loadbalancing / cloud-based demos are refactored to share a similar codebase + +*** Version 3.0.1.6 (07.05.2012 - rev1489) + Note: This is a "stable" release, containing only a few updates. The bulk of changes are in the "odd" numbered releases. Read those updates carefully. + +*** Version 3.0.1.5 + Changed: adopted the even/odd version numbering system. versions ending on a odd number = intermediate/in-development version, even number = released (that makes 3.0.1.5 a intermediate) + Fixed: When NetworkSimulation is disabled, all remaining packages are sent/received immediately (ignoring the former delays) + Note: NetworkSimulation should be working nicely now. Be aware that sudden, additional lag might (!) lead to a disconnect. Play with the settings to find out which ones work for you + Changed: Protocol class now has a few methods to (effectively) serialize some datatypes to arrays (and into existing arrays) + Removed: Surplus public methods from Protocol that were "type-named" like SerializeFloat. The functionality is in still with overloaded methods + Added: count of packages (requests) outgoing if TrafficStatsEnabled +Demo Realtime: + Changed: The commandline arguments are now server:port, protocol (udp,tcp,http), reliable sending, interval dispatch, interval send, interval move. Example: localhost:5055 Udp false 15 25 15 + Changed: Demo Realtime: If the commandline sets an unknown protocol, the client shows a message and closes gracefully + Changed: Demo Realtime: The demo now starts in the grid view (showing something). Local player and player list are created with the Game instance. Player startpoint is randomized. +Loadbalancing API: + Renamed: LoadBalancingClient.lbPeer to .loadBalancingPeer + Fixed: LocalPlayer.SetCustomProperties() usage + Added: Service() method, which calls the LoadBalancingClient's Service simply + Changed: LoadBalancingClient is no longer extending LoadBalancingPeer but instead using one + Changed: the many overloads of Operations are gone in LoadBalancingPeer to streamline the api + Changed: ActorProperties are no longer set via JoinRoom, JoinRandomRoom or CreateRoom. instead, set the properties in the LocalPlayer and let the LoadBalancingClient send and sync them where necessary + Fixed: MasterClientId is now 0 when there are no more players in the room (it was set to int.max before) +Internal: + Changed: all DispatchIncomingCommands now use a while loop to dispatch the ActionQueue (in the hope this is the fastest way to do it) + Changed: DispatchIncomingCommands now looks for the received unreliable command with lowest unreliable seqNr to dispatch this + Changed: DispatchIncomingCommands discards commands if the reliable OR unreliable sequence is beyond the command's sequences + Changed: DispatchIncomingCommands now truncates the incoming unreliable commands to limitOfUnreliableCommands (if that's > 0) + Changed: the next reliable command to dispatch is now fetched with Dictionary.TryGetValue() (for being faster) + Changed: no longer using BinaryReader streams anywhere (this should improve speed and reduce mem usage) + Changed: PeerBase accordingly + Changed: Unit test MyType de/serialization now supports null-references (as 1 byte being 0) + Changed: Protocol.SerializeOperationRequest is now used in the same way, no matter if request is "top level" or inside some other datatype + Changed: the peer bases accordingly to use only one SerializeMemStream and lock it + Changed: how encryption fits in to the new serialization (it is a special case, as only the operation bytes get encrypted) + Added: Protocol.SerializeParameterTable() as requests, events and responses all use the same way to write their parameters + Changed: SerializeOperationToMessage parameter order + Changed: Order of Protocol methods to make more sense (from byte to more complex types for serialization) + New: PhotonDotNet library prototype for windows 8 metro + +*** Version 3.0.1.3 (13.04.2012 - rev1430) + Known issues: The Network Simulation is currently not guaranteed to work properly. Please bear with us. + Note: the following change might be a breaking one: + Changed: When dispatching a server's disconnect-command, the state is changed to ConnectionStateValue.Disconnecting BEFORE any callback due to state change is called. This should disallow game-code from calling any operations immediately. + Changed: Many internals. This should result in better performance + Changed: Service() now calls SendOutgoingCommands() until send-queues are empty. This might take more time but gets important commands out. If you need more control, Service() can be replaced with DispatchIncomingCommands and SendOutgoingCommands! + Added: null check to GetEndpoint() to avoid issues when the host address is null + Fixed: queueIncomingCommand() debug out message when a command is being received AND in in-queue (the list it accesses is now a dict) + Added: new "vital" stats to TrafficStats + Added: LongestOpResponseCallback and LongestOpResponseCallbackOpCode (opcode and time of longest callback) + Added: LongestEventCallback and LongestEventCallbackCode (event code and time of longest callback) + Added: LongestDeltaBetweenDispatching and LongestDeltaBetweenSending to detect "gaps" between subsequent calls of those + Added: DispatchCalls and SendOutgoingCommandsCalls to measure average call-rate + Fixed: PeerBase.TrafficStatsEnabledTime now checks if a stopwatch is set, else it returns 0 + Fixed: TrafficStatsReset() now works as intended (starting a new stopwatch, too) +Internal: + Changed: name of variable timeLastReceive. is now: timeLastAckReceive (better fit with what it does) + Internal: queueOutgoingReliableCommand() to use a lock on the channel it accesses + Internal: SerializeOperationRequest() now locks the MemoryStream while using it (avoids threading-issues with calling OPs) + Internal: SendUdpPackage() now checks if socket is obsolete (and disconnected for a reason) or not. only if not, a error is logged + Internal: EnetChannel now uses Dictionary and Queue for commands (should be faster to access) + Internal: simplified access methods in EnetChannel according to changes + Internal: outgoingAcknowledgementsList is now a Queue + Internal: receiveIncomingCommands() no longer has a local variable sentTime. instead using this.serverSentTime directly + Internal: UDP sending is now done with a synchronous socket call (profiling told us: this is cheaper) + Internal: re-using the socket arguments for receiving packages (saves some buffer allocation) + Internal: socket to non-blocking (maybe not possible on all devices) + Removed: initial-HTTP-protocol support (HTTP support not public yet) + Added: support for encryption with HTTP protocol + +*** Version 3.0.1.2 +- Added: Rooms now have a "well known" property to list the custom properties that should be available in the lobby. This can be set per room (but most likely makes sense per title/application). +- Added: LoadBalancingClient.OpCreateRoom() has a new parameter "propsListedInLobby" and Room.PropsListedInLobby is available to check this list (if needed at all). +- Added: GameProperties.PropsListedInLobby as "well known property" key +- Changed: LoadBalancingPeer.OpCreateRoom now sets ParameterCode.CleanupCacheOnLeave to true by default. This makes the server clean a player's event cache on leave. +- Added: SupportClass.DictionaryToString() will now print values of string[] and optionally leaves out type information. +- Note: 3.0.1.1 didn't get it's own SDK, so read that version's changes, too + +*** Version 3.0.1.1 +- Added: PhotonPeer.TrafficStatsElapsedMs, which gives you the milliseconds that the traffic stats are enabled. This internally uses a stopwatch (for now) which might not be available on all platforms. Please report if this new SDK causes issues. +- Added: PhotonPeer.TrafficStatsReset() to reset the traffic stats and the timer. This could be useful to get stats of "in game" versus "out of game". Note: Loadbalancing includes frequent server-switching and each disconnect/reconnect causes a reset. +- Changed: In LoadBalancingPeer EventCode.SetProperties is obsolete and replaced with EventCode.PropertiesChanged. Please switch to new constant. +- Added: Support in LoadBalancingAPI for Player.IsMasterClient. For this, the Players now get a RoomReference set (when added). The active player with the lowest ID is the master (per room). +- Added: Room.MasterClientId, which is updated when new players are added or the current master is removed. +- Added: SupportClass.DictionaryToString() has an overload which doesn't "print" the Type per key/value. +- Added: Loadbalancing API overload for OpJoinRandomRoom(...) taking additional parameter 'playerProperties' +- Added: Loadbalancing API CacheProperties() and Room.GetPlayer() are public now +- Added: LoadBalancingClient will now handle ExceptionOnConnect and keep clients from re-connecting if establishing a connection fails +- Note: The following changes affect only HTTP, which is an upcoming option for connections. So far, the public server SDKs don't support this. Feel free to contact us about it. +- Added: setter for PhotonPeer.ServerAddress to allow setting a http url (even while connected) +- Added: PhotonPeer.HttpUrlParameters setting parameters to be added to end of url (must begin with '&') +- Added: HttpUrlParameters to PeerBase +- Added: HttpUrlParameters is now attached to the end of a URL in http usecase +- Added: "Http2" support to Unity library +- Internal: method HttpBase.ConnectAsync is no longer needed and Request() is now directly passed to thread + +*** Version 3.0.1.0 +- Added: Loadbalancing (Cloud) Features +- Added: Project with the Loadbalancing sourcecode for DotNet, WindowsPhone and Unity3d (usable without PUN) +- Added: Initial, simple Loadbalancing demos for each platform (will update and extend those) +- Note: The API of the client libraries didn't change. The new features were added on top of the known API +- Added: VS2010 solutions for DotNet and Windows Phone SDKs containing the demos and APIs in the package +- Added: readme.txt with initial help to setup the Cloud/Loadbalancing demos +- Added: default appId for Loadblanacing demos: "" + +*** Version 3.0.0.10 +- Added: When UDP StartConnection (internal method) fails, callbacks to OnStatusChanged(StatusCode.Disconnect) are now done additionally to the SecurityExceptionOnConnect and ExceptionOnConnect calls. This happens direcly inside PhotonPeer.Connect()! +- Changed: When Unity UDP implementation fails to connect due to missing DNS resolution, it now also calls OnStatusChanged(StatusCode.ExceptionOnConnect) +- Removed: StatusCode.Exception_Connect value (obsolete, replaced by ExceptionOnConnect, same value) +- Fixed: Http connections (DotNet & Unity) now skip results while in disconnected state +- Fixed: Http connections (DotNet & Unity) now ignore results after a disconnect and reconnect was done (this applies only to HttpBase, not HttpBase2) +- Fixed: misleading debug out (pointing to WindowsPhone while the class is now in general use) +- Changed: DotNet UDP connection now only logs socket errors if the connection isn't obsolete (disconnected) already + +*** Version 3.0.0.9 +- Fixed: issue with HTTP connections and EstablishEncryption() +- Changed: ActionQueue is now a Queue, allowing Dequeue in a while loop instead of foreach(i in list) and clear() +- Changed: Unity HttpBase DispatchIncomingCommands() to make use of the queue +- Fixed: init byte[] length (internal. did not have consequences) +- Fixed: LitePeer OpRaiseEvent() was sending encrypted +- Internal: ContainsUnreliableSequenceNumber() check if reliable list needed sorting +- Fixed: Unity/Silverlight bug with encryption. Their implementation of BigInteger.GetBytes() failed when the 2nd, 3rd or 4th of the first 4 bytes was 0 but the previous wasnt. This led to incompatible secrets. +- Changed: TCP socket sending debug output now checks debuglevel (when send is skipped, cause the sender is obsolete already) +- Added: caching option RemoveFromRoomCacheForActorsLeft = 7 +- Internal: Added another http-based communication protocol. Please note: The fitting server's are not yet publicly released. This does not affect UDP or TCP protocols. + +*** Version 3.0.0.8 +- Fixed: Udp fragment reassembly in case fragments are received out of order and incoming queue was not yet sorted +- Fixed: Handling of incoming reliable commands (udp) which were skipped in some cases, if not received in order +- Fixed: Network simulation issue which caused lost incoming commands +- Fixed: Demo Realtime. protocol is now again Udp, fitting the default server address "localhost:5055" (make sure to build the demo with your server's address if Photon is not on the same machine) + +*** Version 3.0.0.7 +- Changed: Udp socket usage for Unity 3d lib. Both threads (send (in game loop) and receive (separate)) now have minimal locks while using the socket +- Fixed: SendOutgoingCommands now returns true if anything didn't make it into the outgoing UDP package +- Internal: TCP connections also skip network simulation when it's turned off + +*** Version 3.0.0.6 +- Fixed: SendOutgoingCommands now returns true if commands are remaining in outgoing queues (UDP only sends one package per call, TCP will send anything outgoing). +- Added: New "RoomCache" for Events. The EventCaching enum allows you to use it. Events in this cache will keep the order in which they arrived in the server. A filter makes deleting them very flexible. +- Internal: Ability to make lib send only ACKs and nothing else. This is probably a temp solution as it might be better to make sending and calling ops completely thread safe. +- Internal: PhotonPeer.IsSendingOnlyAcks, which is locked with the sending (not changing while sending). This makes SendOutgoingCommands() thread safe, which is good if you need a separate thread to keep connection. You could call operations while sending. +- Internal: Unity3d's connection now also syncs socket usage + +*** Version 3.0.0.5 +- Fixed: ObjectDisposedException in DotNet UDP workflow. This was caused by disconnecting while incoming data was processed (and before the next datagram was accepted) +- Added: PhotonPeer.LimitOfUnreliableCommands property. This helps you skip potentially "outdated" unreliable commands (events), which helps if you couldn't dispatch for a while +- Internal: Minor performance improvements. Example: The check if network simulation is turned on is done earlier in the workflow, which avoids a bit of overhead + +*** Version 3.0.0.4 +- Fixed: Tcp connections have been throwing ArgumentNullException in DispatchIncomgingCommands() if they were not connected yet +- Internal: Adjusted Http client to server rev2360 + +*** Version 3.0.0.3 RC2 +- Internal: Communication with HTTP server is WIP (Work In Progress - not a publicly available feature) + +*** Version 3.0.0.2 +- Fixed: OpRaiseEvent overload with EventCaching and ReceiverGroup parameters was not sending the customEventContent as expected. This was always null. +- Fixed: Time fetching case where no time was accepted. Servertime is now accepted, if the fetch-time-command was less or equal as the current roundtrip time. Avoids issues if rtt is exceptionally low immediately. +- Internal: When using multiple channels, dispatching incoming commands now will continue with the next channel, if one doesn't yet have the next reliable command (reliable sequence of one channel does not affect others) +- Internal: Changed protocol for TCP and message headers. This will support bigger message sizes. Also changed debug out related to unknown headers. +- Internal: Changed handling of TCP receive-callbacks for unfinished messages in Silverlight and WP. This should fix handling of very big data that's received in multiple "chunks" +- Internal: Http messages are now deserialized the same way that content in tcp or udp is handled + +*** Version 3.0.0.1 RC1 +- Fixed: Packaging of SDK now includes all files in demo folders, except a list of ignored file-endings (xaml and jpg files were missing in previous Silverlight and WindowsPhone SDKs) + +*** Version 3.0.0.0 RC1 +- Changed: Filenames! Now include a '3' for Photon v3. Update your references! Also, Silverlight libraries now use "Silverlight" in the filename (was: SL) +- Changed: Versioning. A dll's version has now 4 digits. The first 2 match Major and Minor number of the Server SDK. The latter 2 are Release and Build respectively +- Changed: Silverlight DataTypes (like Hashtable) are now in namespace ExitGames.Client.Photon. This is easier to include (as that namespace is in "using" in most cases) + +*** Version 6.4.5 +- Changed: Parameters for OpCustom are now of type Dictionary, making sure that only byte-codes are used for parameters +- Changed: Most IPhotonPeer names (to match those in server code): EventAction -> OnEvent, OperationResult -> OnOperationResponse, PeerStatusCallback -> OnStatusChanged +- Added: SupportClass.DictionaryToString(), which converts the content to string (includes support for Hashtables) +- Moved: Definitions of Lite and Lite Lobby specific codes for Parameters, operations and events are now in LitePeer. Will be available as source and could be replaced +- Changed: Usage of codes in Lite and Lite Lobby. Now pre-defined codes are starting at 255 and go down. Your events, operations and operation-parameters can now start at 0 and go up without clashing with pre-defined ones +- Changed: Constants that are non-exclusive (like event codes and OpKeys, which can be extended) are no longer "defined" as enums but as class of const byte values. Less casting but also less convenient "name" representation in debug output +- Added: LiteEventKey.CustomContent as key to access the content you sent via OpRaiseEvent ("Data" seems a bit misleading but is also available) +- Changed: Namespace of LitePeer to ExitGames.Client.Photon.Lite (the Lite-specific class is still compiled into the library for convenience but can be ignored quite easily this way) +- Added: Property MaximumTransferUnit. The default is 1200 bytes. Usually this is ok. In few cases, it might make sense to lower this value to ~520, which is commonly assumed the minimum MTU. Don't change this, if you don't know why. +- Added: New classes to wrap up op-requests (OperationRequest), op-results (OperationResponse) and events (EventData). Those new classes are now used in callback methods OnEvent and OnOperationResponse +- Changed: by using the new classes (note above), the client is a bit more like the server in its naming. We didn't want to change every last bit though. +- Internal: Changed protocol (to 1.6) so that it does not require any parameter codes internally. Any application can now define any operation, parameter and event codes it wants to. +- Changed: Encryption is now triggered by you and resolved by the library. You don't have to look out for the result of EstablishEncryption and use it. Instead: wait for OnPeerStateChanged call with either EncryptionEstablished or EncryptionFailedToEstablish +- Removed: InvocationId. This concept was very rarely used but confusing. It's easy to implement, if needed. If you don't know what this means: Nevermind. +- Changed: Operation calls now return bool: if they could be enqueued or not. If enqueued (cause you are connected and the data was serializable), then SendOutgoingCommands will send those operations (as before). +- Added: Support to de/serialize Dictionary. If the types are more specific than object, the serialization writes the type-code only once (lean byte usage in protocol) +- Added: Support to de/serialize null. Enables you to send a null value, e.g. in a Hashtable +- Added: ReceiverGroup enum to select a range of players that get an event via Operation Raise Event +- Added: Event Caching. Any event sent via RaiseEvent can now be buffered on the server side and is "repeated" when a new player is joining a room. This is similar to Properties but lets you categorize your info better and works just like regular events, too. +- Added: EventCaching enum to select if an event is to be cached and how it's cached: either "not at all" (default), replacing anything cached so far (fast) or "merge" (which will add new and replace old keys with new values). Optionally, a event can be raise with option "remove". +- Added: new overload of OpRaiseEvent() with the two new parameters noted above +- Added: Support for custom de/serializer methods. By writing 2 methods to convert a object into a byte-array (and back from that), Photon now supports any custom object type (standard datatypes are still supported out of the box) +- Added: PhotonPeer.RegisterType() to register serializer and deserialize methods for a certain type. Per object, a length and one byte 'type code' are added to the serialized data +- Added: Support for non-strict object[]. Unlike strictly-typed array, here each element will carry its own type. +- Note: If you want to use the new Custom Types or the object[], you have to update your server! Older Servers don't support the new features. As long as you don't use these features, the library is compatible with previous servers. +- Added: ByteCountCurrentDispatch and ByteCountLastOperation properties to PhotonPeer (the ancestor of LiteGame, etc). A game can now access the size of operation-results and events as well as operation-call size. +- Added: Traffic statistic set: PhotonPeer.TrafficStatsGameLevel as "high level" game-related traffic statistic. Counts bytes used by operations, their results and events. This includes overhead for these types of messages, but excludes connection-related overhead +- Added: Traffic statistic set: PhotonPeer.TrafficStatsIncoming and PhotonPeer.TrafficStatsOutgoing as low level statistics of the traffic +- Added: PhotonPeer.TrafficStatsEnabled which enables two sets of traffic statistics. By default, statistics are turned off. +- Added: Classes TrafficStats and TrafficStatsGameLevel for the two statistic cases metioned above +- Changed: NetworkSimulation now starts a Thread when it becomes enabled and the thread ends on simulation disable. Disable the NetworkSimulation to stop the thread, as Disconnect does not change the simulation settings! +- Internal: Cleanup and renaming of several properties +- Internal: Each new peer increases the PeerCount but it is no longer reduced on disconnect (it is existing still, after all) +- Internal: Udp commands will be buffered when serialized. This saves some work when re-sending a reliable command +- Added: TCP Routing code (not in Silverlight). To be used when running Photon on Azure (can be ignored in regular use) +- Added: to StatusCode: TcpRouterResponseOk = 1044, TcpRouterResponseNodeIdUnknown = 1045, TcpRouterResponseEndpointUnknown = 1046 and TcpRouterResponseNodeNotReady = 1047, +- Added: override for PhotonPeer.Connect() with node +- Internal: DotNet now reads the 2 bytes routing response, if a routing request was made (also, not in Silverlight) +- Internal: If TConnect sent a routing request, nothing else will be sent until 2 bytes response are read. +- Internal: If the routing-response does not start with ProxyResponseMarkerByte = 0xF1, a debug message is enqueued and TCP will disconnect +- Internal: Init request for TCP is now always enqueued instead sent directly. This way, it can be delayed if a routing node is selected +- Internal: TPeer EnqueueInit() and SendProxyInit() now create init and routing request respectively +- Internal: TConnect.sendTcp() checks isRunning before it tries to send (the socket might close before the NetSim does). This won't be an issue anytime, still INFO-level callback to DebugReturn is done. +- Removed: debug out for "send package" situation (even on ALL-level, this is more or less spam) +- Internal: updated version numbers of init to 6.4.5 +- Changed: SupportClass HashtableToString() returns "null" if parameter is null +- Internal: Removed SortedCommandList and CommandList classes. Replaced by List and a Sort() where necessary +- Internal: EnetPeer.channels is now a Dictionary instead of a SortedList +- Internal: the channels are initialized with channel 0xff first - this makes 0xff high prio in all foreach usaged +- Internal: NCommand class is now IComparable for usage in Sort() + + +*** Version 6.4.4 +- Added: PhotonPeer.TimestampOfLastSocketReceive now provides the time when something was received. Can be used warn players of bad communication-timing even before the disconnect timeout will be happening +- Fixed: OpGetPropertiesOfActor did use the actorNrList correctly, which always got you all properties of all players + +*** Version 6.4.3 +- Changed: A udp connection timeout in Unity will now end the socket-handling thread correctly +- Changed: The thread for Network simulation is now stopped when the client disconnects and started on connection (instead of keeping it per peer) +- Fixed: Exceptions in network simulation, when Disconnect() was called soon after Connect() but before the connection was established. + +*** Version 6.4.2 +- Fixed: It was possible to send PhotonPeer.FetchServerTimestamp() before being connected properly. Now the method triggers debug output (INFO level) and the callback PeerStatusCallback(StatusCode.SendError) +- Internal: Added a lock in the UDP version of SendOutgoingCommands(). It's still illegal to access a peer from multiple threads but the follow-up issues this lock avoids are very difficult to track. +- Internal: to stay compatible with all exports of Unity, the use of System.Threading.Interlocked.Exchange was replaced by simply replacing the list's reference instead + +*** Version 6.4.1 +- Changed: The Unity library now uses the WWW class for Http based requests. Results are checked within DispatchIncomingCommands(). Important: Unity allows handling WWW requests only on the MainThread, so dispatch must be called from this context! +- Note: Photon does not support Http requests out of the box. Customers get access to a fitting server on demand +- Changed: outgoing list is now replaced on send, instead of calling remove(0) repeatedly (which takes longer). Internal: this uses System.Threading.Interlocked.Exchange to switch to a new outgoing list in one step + +*** Version 6.4.0 +- Fixed: TCP handling of incoming data. This avoids loss of data (operation-results or events) when a lot of data is incoming. +- Changed: PeerStatusCallback() is less often called for queue-length warnings (e.g.: StatusCode.QueueIncomingReliableWarning). Only if a queue has a multiple of PhotonPeer.WarningSize items. +- Changed: WarningSize is now 100 by default +- Changed: Description of PhotonPeer.WarningSize and PhotonPeer.CommandBufferSize, which really is just the initial size of any buffer. The warnings are there to avoid situations where all heap is used up. +- Changed: Naming: StatusCode.Exception_Connect is now Obsolete and replaced with StatusCode.ExceptionOnConnect +- Added: Missing summary for StatusCode.SecurityExceptionOnConnect +- Added: NetworkSimulationSet.ToString override to provide a better overview +- Added: Support for arrays of Hashtables + +*** Version 6.3.1 +- Fixed: Network simulation now delays incoming packages by IncomingLag and IncomingJitter as expected (it was using the outgoing values, too) + +*** Version 6.3.0 +- Added: Network simulation (lag, jitter and drop rate) to debug builds +- Added: class NetworkSimulationSet with properties to control network simulation +- Added: NetworkSimulationSettings.NetworkSimulationSettings property to get current simulation settings +- Changed: only the first peerId of a VerifyConnect is accepted in client (avoids surplus peerID changes) +- Internal: added PeerBase.SendNetworkSimulated() and PeerBase.ReceiveNetworkSimulated() and a Thread to run delay simulation +Siverlight: +- Updated: to Silverlight v4.0 +- Added: Encryption to Silverlight library +- Internal: updated internal BigInteger class for Silverlight +- Internal: DiffieHellmanCryptoProvider in Silverlight, so it uses AesManaged instead of Rijndael (which is not part of Silverlight 3) +- Added: Stopwatch class to DataTypes.cs (for Silverlight only) + +*** Version 6.2.0 +- Added: "Demo LiteLobby Chatroom" to Unity SDK +- Updated: Demo Realtime in Unity client SDK. It's still compatible with the demo on other platforms but cleaned up and much better commented +- Updated: Documentation is now clearer on where the Lite logic is used (it runs on Photon but is not the only application logic) +- Updated: Documentation for the enumerations in IPhotonListener. The Lite application based ones are better described and it's now clear which ones are essential to the Photon client (not only in Lite) +- Updated: Documentation in several other places +- Added: StatusCode.SecurityExceptionOnConnect which is thrown if a security exception keeps a socket from connecting (happens in Unity when it's missing a policy file) +- Added: PhotonEventKey and PhotonOpParameterKey which contain the fixed byte keys that cannot be re-assigned by applications at will (as these keys are used in the clients and server in their respective context) +- Change: PhotonPeer.PeerState is no longer a byte but of type PhotonPeer.PeerStateValue, which makes checking the state simpler. The PeerStateCallback() for state changes is still called as before. +- Changed: Property PhotonPeer.PeerState. It now converts the low level ConnectionStateValue to a PeerStateValue, which now includes a state InitializingApplication. See reference for PeerStateValue. +- Changed: PeerStateValue enum is now part of the ExitGames.Client.Photon namespace, making it more accessible +- Internal: NConnect in DotNet and Unity to catch security exceptions +- Internal: from using var to explicit type usage in DiffieHellmanCryptoProvider.cs (Mono Develop friendly) +- Internal: made const: ENET_PEER_PACKET_LOSS_SCALE, ENET_PEER_DEFAULT_ROUND_TRIP_TIME and ENET_PEER_PACKET_THROTTLE_INTERVAL +- Internal: PeerBase "PeerStateValue peerState" is now: "ConnectionStateValue peerConnectionState" (holding the low level connection state, nothing more) +- Internal: added PeerBase.ApplicationIsInitialized, which stores if the init command was answered by Photon (reset on connect/disconnect) +- Removed: PhotonDemoServerUrlPort and PhotonDemoServerIpPort of PhotonPeer. All demos now use "localhost:5055" and you should run your own server. +- Added: enum ConnectionProtocol to get rid of the "useTcp" parameter in the PhotonPeer constructor (which was less clear than the explicit enum now in use) +- Added: overload of PhotonPeer constructor, which is still compatible with the "useTcp" bool parameter (to avoid a breaking change for the time being) +- Added: PhotonPeer.UsedProtocol property to find out this peer's protcol +- Added: LitePeer.OpLeave() overload without the gameName parameter. That name is not checked in the Lite application (on the server), so it's not really needed + +*** Version 6.1.0 +- Added: Encryption for Unity and DotNet. Operations (and their responses) can be encrypted after exchanging the public keys with the server +- Added: OpExchangeKeysForEncryption(), DeriveSharedKey() and IsEncryptionAvailable to PhotonPeer (and LitePeer inherits these) +- Added: OpCustom() will throw an ArgumentException if the operation should be encrypted but keys are not yet exchanged (exchange keys first) +- Added: LiteOpCode.ExchangeKeysForEncryption = (byte)95 +- Added: Overloaded PhotonPeer.OpCustom() with new "encrypt" parameter +- Added: property PhotonPeer.IsEncryptionAvailable is true if public-keys are exchanged and the secret is compiled from them +- Added: Encryption demo to Realtime Demo. Press E to exchange keys and R to toggle encrypted sending for the move data (even though events are never encrypted) +- Changed: PeerBase methods: sendOperation()->EnqueueOperation(...,encrypt), updateRoundTripTimeAndVariance()->UpdateRoundTripTimeAndVariance() +- Updated: the Unity client is now a Unity v3.1 project. Make sure to change the server address before you build for iPhone (localhost:5055 won't work on the mobile) +- Removed: the outdated, separate iPhone demo (was: Unity v1.7 for iPhone) +- Updated: PhotonPeer documentation for Service(), DispatchIncomingCommands() and SendOutgoingCommands() +- Added: OpRaiseEvent() overload with parameter TargetActors. Sends optional list of actors that will receive the event (if null, all *other* actors will receive the event, as default) +- Internal: Added source BigInteger.cs, DiffieHellmanCryptoProvider.cs and OakleyGroups.cs +- Internal: PeerBase.CryptoProvider, PeerBase.ExchangeKeysForEncryption() and PeerBase.DeriveSharedKey() +- Internal: EnetPeer.initPhotonPeer() and TPeer.initPhotonPeer() are setting PeerBase.isEncryptionAvailable = false +- Internal: De/Serialization methods (and some variables for it) are moved from NConnect to PeerBase and renamed to: SerializeOperationToMessage() and DeserializeMessageAndCallback() +- Internal: switched project to allow "unsafe" functions (used by BigInteger) +- Internal: renamed PhotonPeer.sendOperation()->EnqueueOperation +- Internal: changed assembly version to 6.1.0 and "client version" in init-byte-block to 6,1,0 +- Internal: moved protocol handling to EnetPeer and TPeer classes (where encryption is added) +- Internal: moved InitBlock to (shared) PeerBase (same for UDP/TCP) +- Internal: serialization is now done by Protocol.SerializeOpParameters(), which excludes the message header. this makes encryption simpler + +*** Version 6.0.0 +- Changed: This library requires Photon v2.2.0 and up! (in other words: the libraries are not compatible with older Photon servers, due to servertime changes) +- Added: Support for arrays in arrays. Any serializable datatype can now be used in nested arrays. Even arrays of Hashtables are possible. +- Added: Realtime Demo optional command line arguments for game config. set all or none: serverAddress, useTcp (true/false), useReliable (true/false), int intervalDispatch, intervalSend (ms), intervalMove (ms) +- Note: Realtime Demo commandline might look like this: start demo-realtime.exe localhost:5055 false true 5 25 100 +- Changed: renamed GetLocalMsTimestamp property to LocalMsTimestampDelegate (it does not have a getter, despite the old name's implication) +- Added: PhotonPeer.LocalTimeInMilliSeconds property to use the timestamp delegate to get the current client milliseconds (by default this is Environment.TickCount) +- Changed: UDP: The default value for PhotonPeer.RoundTripTime (300ms, used before connecting) is now replaced with the turnaround time of connect. This should lead to accurate RTT values much sooner +- Changed: PhotonPeer.ServerTimeInMilliSeconds is no longer updated all the time. Instead it's fetched soon after connect (when initialization won't affect rountrips anymore) and extrapolated. It should be better to be off by a constant value than by a changing value +- Changed: PhotonPeer.ServerTimeInMilliSeconds now returns 0 until the server's timestamp is fetched. Updated the documentation with some internals for this. +- Added: PhotonPeer.FetchServerTimestamp() to send the time fetch command (this is done automatically as well. this method is here for completeness) +- Fixed: roundtrip time calculation is no longer affected by long intervals between Service() or DispatchIncomingCommands() calls (bug of v5.9.0, caused by internal action queues) +- Added: internally for UDP, we use a new command to fetch the timestamp which minimizes the latency for that roundtrip. this one is excluded in roundtrip time measuring +- Changed: internal: ACKs by the server are again directly executed (other commands which are put into the action queue and dispatched) +- Fixed: Peers with TCP as protocol will no longer try to disconnect while not being connected (does not do anything of disconnected or disconnecting) +- Changed: Peers with TCP as protocol will clear the outgoing queue when disconnect() is called (while connected. see fix above) +- Updated: Silverlight Realtime Demo slightly +- Added: PhotonPeer.Listener property to give subclasses access to the IPhotonPeerListener (set in constructor). Can be useful to call Listener.DebugReturn() +- Added: LitePeer-Source.cs to demo-realtime. This is the source of a LitePeer and could be used as sample to create custom operations on the client side + +*** Version 5.9.0 +- Release: of changes in 5.7.6 and 5.7.5 + +*** Version 5.7.6 +- Fixed: a debug output line for TCP connections which did not heed the debug-level. +- Changed: PhotonPeer uses less locking internally and will handle incoming data in the game thread (inside DispatchIncomingCommands() or Service()). +- Changed: Internally, all commands are put into a (locked) queue which is processed within DispatchIncomingCommands(). Your dispatch interval affects local lag but not the PhotonPeer.RoundTripTime value. +- Note: Don't use a peer from multiple threads! It's not thread safe. All callbacks to IPhotonPeerListener methods are happening in your game thread (again: inside DispatchIncomingCommands()). +- Changed: removed locks inside the callbacks (according to above change). +- Changed: DNS resolution is now done in Connect() unless you provide a valid IP address (if IPAddress.Parse(address) is successful, the IP is used directly). +- Fixed: PhotonPeer.Connect() should fail if the IP is unknown or unavailable. Exception: using a localhost might succeed but fail when we try to receive anything. +- Updated: Game.cs now initialized the timing intervals. This avoids issues if the client system is having a negative TickCount. +- Added: ServerAddress property to PhotonPeer, which might help while developing with several servers and peers. +- Changed: This version includes GetLocalMsTimestampDelegate and the PhotonPeer property GetLocalMsTimestamp to set the delegate for local timestamp. + +*** Version 5.7.5 +- Changed: All precompiled demos now connect to localhost! From now on, you need to run Photon before trying any of the demos (as we don't guarantee that udp.exitgames.com is online anyways) +- Changed: OpCustom() now accepts null as parameter Hashtable, which is a shortcut to "no parameters" for simple operations (an empty hashtable is sent though, it does not reduce bandwidth) +- Added: new feature: UDP timeout definition by setting PhotonPeer.DisconnectTimeout (individual per command, set in milliseconds, checked when a command is repeated) +- Renamed: enum ReturnCode to StatusCode. The StatusCode values are only used for status callbacks (not as operation results) +- Changed: parameter type of PeerStatusCallback() from int to StatusCode (to differentiate them from operation ReturnCodes, which are customizable) +- Removed: StatusCode.Ok (as it was actually an Operation ReturnCode) +- Added: new StatusCallback value: StatusCode.SendError. Used for sending error cases: "not connected" and "channel not available" +- Changed: sendOperation() (Udp and Tcp) does not throw an exception while disconnected or for wrong channel (using StatusCode.SendError instead) +- Changed: callback DebugReturn() now has the additional parameter (DebugLevel)level, analog to logging +- Changed: UDP connection is disconnected when a read exception happens (before we tried to read despite this until a timeout ended it) +- Changed: EnetPeer.Disconnect() now ignores calls when peer is disconnected or disconnecting already +- Fixed: TCP code tried to detect socket issues by checking for IOExceptions but now checks SocketException instead +- Changed: internal threading: Callbacks due to incoming packages and commands are now queued and triggered by dispatch (in game loop) +- Changed: dispatch of action-queue as added to DispatchIncomingCommands (in EnetPeer and TPeer) +- Changed: internally, there is no locking for outgoing reliable and unreliable command lists anymore +- Changed: Realtime Demo timer usage to avoid nullref on form-close +- Changed: Realtime Demo propety isReliable is now in the Player class +- Changed: Game.cs and Player.cs for all realtime demos. There is now something like a gameloop (Update()) which must be called regularly and makes (pretty) sure just one thread accesses the peer +- Changed: all realtime demos to use the new Update() method and use more similar Game and Player classes (cleanup for less differences) +- Fixed: RoundtripTimeVariance is now also reset on connect / init, so the resend-timing of reliable udp does not suffer when a peer connects after a disconnect +- Fixed: typo in ExitGames.Client.Photon.StatusCode.QueueIncomingUnreliableWarning (was QueueIncomingUneliableWarning) + +*** Version 5.7.4 RC3 +- Changed: Unity3D lib again has it's own UDP handling (the DotNet one causes browser crashes on web-player exit) + +*** Version 5.7.3 RC3 +- Changed: Unity3D lib is now identical to DotNet lib (Unity iPhone is compatible with DotNet 2.0 now and this got tested) +- Fixed: DNS resolution (did not work for "localhost", which gave two results (IPv4 and IPv6), mixing up things + +*** Version 5.7.2 RC3 +- Changed: Unity3D lib: the receive thread will now receive until no data is available, then sleep 5ms and check again +- Changed: serverTime is now a signed int (as on server) and adds averaged rountripTime/2 when it gets an update +- Changed: ServerTimeInMilliSeconds doc (more concrete, explains how server time works) +- Added: support for serverTime, RountripTime and RoundtripTimeVariance when using TCP (Silverlight does not allow UDP) +- Added: Silverlight supports either URL:Port and IP:Port as server url string + +*** Version 5.7.1 RC2 +- Added: DotNet "Lobby Demo" which uses the "LiteLobby" application of the server SDK to show running games and their player-count +- Changed: the realtime demos to use the more similar Game and Player classes + +*** Version 5.7.0 RC1 +- Added: documentation: project for Silverlight Hashtable and ArrayList substitutes. +- Changed: RealtimeDemo uses same classes Game and Player for Unity3 + Silverlight +- Changed: Silverlight: Hashtable and ArrayList are now a separate project / lib +- Internal: Silverlight: listener interfaces (Photon and Neutron) now conditionally use ExitGames.Client datatypes from lib +- Changed: Photon: connect callback is now deferred to on-init-response (instead of enet-connect) which ensures "no ops before init" +- Changed: Unity Realtime demo: using game and player classes merged over from silverlight and re-wrote sample code to display players +- Internal: photon projects now have a pre-compile setting "Photon" +- Changed: SupportClass Namespace is now compiling into either ExitGames.Client .Photon or .Neutron (to avoid ambiguation) +- Added: LitePeer as Lite Application specific peer (with OpJoin and the rest) +- Changed: demos accordingly +- Changed: case of PhotonPeer methods to first-letter-is-uppercase (as usual in C#) +- Removed: nNet-prefix (Connect and Disconnect are self-explanatory) +- Renamed: PropertyTypes are now LitePropertyTypes (as they belong to the Lite application) +- Changed: Peer state constants with PS_* converted into enum "PeerStateValue" +- Removed: URL_RT_SERVER, URL_RT_SERVER_DEV, IP_RT_SERVER and IP_RT_SERVER_DEV +- Added: PhotonDemoServerUrlPort and PhotonDemoServerIpPort +- Renamed: NPeer to PhotonPeer +- Renamed: PhotonPeerListener to IPhotonListener (class and file) +- Changed: namespace from Com.ExitGames to ExitGames and ExitGames.Client, ExitGames.Client.Photon and ExitGames.Client.Neutron +- Removed: QueueOutgoingUnreliableError, QueueOutgoingAcksError, QueueIncomingReliableError, QueueIncomingUneliableError, QueueSentError (no errors, only warnings) +- Removed: error "report" when TCP incoming queue getts fuller +- Internal: updates Neutron part to run with Protocol.cs de/serialization (added a serializeParametersNeutron() as there are multiple differences to UDP part) +- Changed: projects and scripts to build documentation xml in debug builds +- Renamed: demo-photon-SL to demo-realtime-SL (according to other demo realtime implementations) +- Changed: many classes and properties are now internal. e.g. Protocol, EnetChannel, EnetPeer (and inner classes), TPeer, SuppportClass.ReadInput() +- Updated: AssemblyInfo.cs for photon dotnet and silverlight +- Internal: projects to have precompile-flags also in release builds +- Updated: build scripts for SDK building +- Removed: Compact Framework support + +*** Version 5.6.1 +- Fixed: 0 element arrays caused bugs +- Fixed: double type was cast incorrectly after being read + +*** Version 5.6.0 +- Added: more supported datatypes: float, double and arrays of all basic datatypes (no arrays of hashtable or arrays) +- Internal: changed Photon protocol internally to 1.5. (needs a server update to Photon Server SDK 1.6.1+)! +- Changed: Channels for Photon UDP are now priorized (from low to high) getting the lower channels out first +- Internal: switched de/serialization at several places from manual shifting to a support function, which should provide endian-correctness (Photon Unity PPC compatibility) +- Added: Unity info about "Application.runInBackground = true;" to Unity Appendix in doc +- Changed: Photon return values are put into a NEW hashtable on receive. not just a cleared one which was not reference-safe (no more need to deep-copy the data of events) +- Added: Photon support for "disconnect-reason" which is sent by server in the enet "reserved" byte +- Added: Photon ReturnCode.DisconnectByServerUserLimit and .DisconnectByServerLogic +- Removed: NPeer.IncomingReliableCommands (was more or less useless) +- Added: QueuedIncomingCommands and QueuedOutgoingCommands as metric for how effective send and dispatch is done +- Changed: now throwing exceptions when trying to set init-values at runtime (to be fixed at development-time) +- Added: doc for sequencing and updated channel doc, (too) short chapter on custom operations, topic "opCodes: byte versus short", doc for property-related functions +- Added: overloaded functions for opGetProperties*() for byte-keys +- Fixed: Realtime Demo keypress in input-fields have been used as in-game actions, too +- Changed: Realtime Demo game-name is now that of the native samples ("play" with other platform SDKs) +- Changed: Silverlight SDK has a different port in the constants NPeer.URL_RT_SERVER* and .IP_RT_SERVER* (as Silverlight uses TCP port 4350) + +*** Version 5.4.1 +- Added: missing documentation in Unity3d SDK + +*** Version 5.4.0 +- Change: The timespan until a sent and unacknowledged reliable command is considered lost, is now calculated by + current roundTripTime + 4 * roundTripTimeVariance + The result of this calculation is doubled with every following resend. The maximum number of retries can still be defined by calling SetSentCountAllowance. +- Change: Removed TimeAllowanceInt +- Change: removed surplus debug out, adjusted levels for other, output of command sent-time from hex to decimal +- Added: fragmentation support: bigger data is now placed into multiple packages and reassembled +- Internal: command-buffers are replaced with CommandList and SortedCommandList (major change, but fully internal) +- Fixed: possibility of command buffer overflow. now everything is stored and warnings are used as hint for temporary problems +- Added: property NPeer.IncomingReliableCommands, which returns the count of reliable commands currently queued +- Added: callback on NCommand.CT_DISCONNECT to inform the NPeerListener about a disconnect from server (see above) +- Added: disconnect command will be sent by server in case of timeout, connection-limitations or other issues +- Added: NPeer ReturnCode.DisconnectByServer is called on server-side disconnect (see description) +- Added: call to StopConnection() on disconnect (by server) +- Added: NPeer.PeerID property to get ENet's peerID (useful while debugging) +- Internal: SupportClass.WriteIntToByteArray() to ease writing ints to byte[] +- Internal: added several values to NCommand to store fragments +- Added: support for channels. read more about this in the documentation +- Added: NPeer.ChannelCount which sets the number of channels while not connected (default: 2) +- Changed: opRaiseEvent() and opCustom() now optionally have a channel parameter +- Added: Photon properties functions to NPeer (available with Photon Server SDK v1.5.0) and doc +- Added: LiteEventKey.SetProperties = 92 for broadcasted property set +- Added: LiteOpKey.Broadcast = 13 and .Properties = 12 +- Added: LiteEventKey.TargetActorNr = 10 (actorNr the properties are attached to) and .Properties = 12 (changed properties) + + +*** Version 5.3.11 +- Change: all bytes sent to and from server are treated as unsigned bytes (standard for c#). same for byte-arrays +- Change: updated realtime demo to use int for posx,posy but still sending just a byte-value (the field is 16x16, after all) + +*** Version 5.3.10 +- Change: switched from sbyte-array to byte-array in de/serialization! important: bytes (ev-keys etc) are sbyte. arrays of bytes are unsigned (on client and server) +- Change: NeutronListener functions getShadowReturn() and HasbadwordsReturn() now have byte-array return values. please adjust, even if you don't use those +- Internal: changed SupportClass for Compact Framework +- Internal: getting ticks sitched from expensive "System.DateTime.Now.Ticks / 10000" to cheap "Environment.TickCount" +- Change: Unity lib will now give more debug out if serialisation fails + +*** Version 5.3.9 +- Fixed: result-queue, timeouts and customOps work also fine for Unity build again (were broken due to Neutron Unity webplayer compatibility changes in 5.3.8 for Unity) +- Fixed: if the browser is closed and the unity webplayer immediatly can't use http anymore, Neutron now informs the application via NetworkStatusReturn() + +*** Version 5.3.8 +- Fixed: Neutron Unity now also works fine in webplayer -> Neutron and Photon now both support all platforms of Unity und Unity iPhone +- Fixed: default value for parameter encrypt of NeutronGame::RaiseEvent() now is false like for all other RaiseEvent methods and like on all other platforms, instead of true, as it was before + +*** Version 5.3.7 +- Fixed: .Net UDP issue, where standard MTU settings caused dropped UDP packages +- Internal: refactored ACK queue to arraylist + +*** Version 5.3.6 +- Fixed: NPeer issue with ACKs for repeated commands. this enhances handling of lost packages +- Changed: NPeer.opJoin() no longer needs the SID + +*** Version 5.3.5 +- Known issues: to use Photon on iPhone device, you do need Unity iPhone 1.0.2b1 or higher (current official release is 1.0.1, so please ask for a prerelease or wait until next official release), but of course you can use Photon with Unity iPhone 1.0.1 IDE +- Merged: renamed .NET 1.1 NeutronUnity3DiPhone into NeutronUnity3D to replace the old .NET 2.0 lib of that name, which means, that you can use the same .NET 1.1 based lib for Unity and for Unity iPhone now, since 1.1 cpmpatibility fixes are all done now +- Fixed: photon is fully compatible to .NET 1.1 now +- Internal: optimized UDP package size in Unity3D library (was sending surplus bytes, which were ignored) +- Fixed: NPeer.opCustom() now sends the operation given by parameter +- Changed: IP_RT_SERVER points to new server IP of udp.exitgames.com +- Changed: a new NeutronSession now clears the NetworkLoss state and the sendQueue +- Changed: timeout of a HTTP request to 10 seconds. it triggers + +*** Version 5.3.4 +- Added: prealpha Unity3DiPhone version of Neutron .NET: core lib already functional, but realtime part not usable on device yet +- Internal: there are 4 different versions of Neutron.NET now: + - Full .NET: .NET 2.0 based, with asnyc realtime part + - Compact Framework: .NET 2.0 based, with threaded realtime part + - Unity3D: .NET 2.0 based, with Unity www-class based http part and threaded realtime part + - Unity3DiPhone: .NET 1.1 based, with Unity www-class based http part and threaded realtime part + +*** Version 5.3.3 +- New: ReturnCode.RC_RT_EXCEPTION_CONNECT, which covers the cases where a server is not running +- New: NPeer can now be created with UDP or TCP (by new bool parameter) +- Change: renamed most of the constants for NPeer (in INPeerListener structs) +- Note: TCP does not offer ServerTime or RoundTripTime jet + +*** Version 5.3.2 +- Internal: reverted to threaded model in NConnect (as async UDP is not supported by Unity3D) + +*** Version 5.3.1 +- New: login(), register(), customOperation() and raiseEvent() (all variants) can be encrypted with additional parameter "encrypt" (overloaded function) +- New: encryption uses HTTPs as transfer, by changing the "http:" url to a "https:" url +- New: returnCode for failure of encrypted HTTPs requests: RC_SSL_AUTHENTICATION_FAILED (if certificate is not found, valid or expired) +- Fixed: Realtime Demo using the older Realtime Server + +*** Version 5.3.0 +- New: separated libraries into "Compact Framework" (CF) and "Regular Framework" (no name postfix) +- Change: libraries are now in "libs" folder as debug/release and in libs/CompactFramework debug/release +- Change: libs default URL set to EU/Test. use setServerURL() with Neutron.URL_NEUTRON_* for other Neutron instances +- Internal: lib now uses async UDP communication now with "regular" framework +- Added: properties serverTimeInMilliSeconds, serverTimeAsTimeSpan and serverTimeAsDateTime for getting the current server time +- Removed: serverTimeOffset is now internal only and removed from the API (was only needed to calculate the servertime by yourself, before neutron could do this for you) +- Change: debug out for realtime classes is now layered +- Change: debug level NPeer.DebugOut is now a NPeer.DebugLevel enum and will include all lower levels in output, default: DebugLevel.ERROR +- Fixed: size of realtime demo board +- Change: NPeer constructor now always throws an exception if listener is null +- Change: EventAction() parameter eventCode is now of type sbyte (was int), which corresponds to type of RaiseEvent (and server-side used type) +- Internal: NPeer.opRaiseEvent() now treats eventCode as parameter of operation RaiseEvent (as changed in latest RT server) +- Change: NPeer has its own listener (INPeerListener) and several (better named) structs for the constants used with NPeer / realtime +- Added: LiteOpKey and LiteOpKey.ActorNumber to have a constant for the only OP key of interest +- Change: EventAction() always returns the complete event, which contains a code, the ActorNumber (if any given) and data from raiseEvent (see below) +- Change: in custom events, the data from opRaiseEvent() is in placed as value of key: LiteEventKey.EV_RT_KEY_DATA. to get the data use: Hashtable data = (Hashtable)neutronEvent[LiteEventKey.EV_RT_KEY_DATA]; + +*** Version 5.2.0 +- changed library filename to neutron-lib__.dll with server "test" and "run" (no debug out) and billing "dummy" and "none" +- removed US build of library. please use NeutronSession.SetServerUrl() and the constants: Neutron.URL_NEUTRON_SERVER_*. + +*** Version 5.1.0 +- added realtime classes to DotNet library: ported NPeer (and internal: NCommand and NConnect) classes +- added nPeerReturn() to NeutronListener interface +- added constants for realtime returnCodes (RC_RT_*): RC_RT_CONNECT, RC_RT_DISCONNECT and RC_RT_EXCEPTION +- added constants for realtime eventCodes (EV_RT_*) +- added constants for Neutron servers to Neutron class: URL_NEUTRON_* +- added Reamtime Demo +- updated samples +- added test for UDP to NUnit + +*** Version 5.0.1 +- New: operation Spectate (including new SpectateReturn) to get events from any game (as admin) +- New: SetServerUrl and SetCustomServerUrl now return the URL to debugReturn +- Internal: constant "DEBUG_- InternalS" to be used for intern debugging output + +*** Version 5.0.0 +- New: hasBadwords() as OP and return. Server side check of strings for badwords + +*** Version 5.0.0 RC3 +- Internal: changed constant values: EV_KEY_PROPERTIES = "Data", EV_KEY_REVISION = "Rev" +- New: EV_KEY_CHANNELTYPE for channel-type in property-change events +- New: constants for default channels, CHANNEL_APPLICATION_LONGLIFE, CHANNEL_ACTOR_SHORTLIFE, CHANNEL_ACTOR_LONGLIFE and CHANNEL_APPINSTANCE +- Change: operations that fail due to missing moderation-rights now return RC_MODERATION_DENIED instead of RC_COMMAND_ACCESS_DENIED +- Change: actor-properties can no longer be broadcasted in any way - removed "broadcast" parameter from setActorProperties() +- Change: properties now have a revision which is increased on each change. this way outdated updates might be skipped +- Change: parameters of GetPropertiesReturn(). property-type is replaced by channel. added revision +- Change: EV_PROPERTIES_CHANGE now has a key EV_KEY_OWNERNR if it's a "player property" (the key is missing if it's a game-property) +- Internal: changed setProperties and getProperties to new operation-codes using different parameters (with similar results) +- New: parameter "textMessage" for NeutronGame.invite() adds personal message to invited players (in EV_INV and gameListInvitations()) +- New: key EV_KEY_INFO will be added to EV_INV if "textMessage" was used in NeutronGame.invite() (it's not there otherwise) +- New: gameListInvitations() has new value parameter {t} to get "textMessage" from NeutronGame.invite() +- New: RC_APPINSTANCE_NOT_OPEN is now used for "singleton namebased pools" where a game is full (not able to join / instanciate) +- New: gameCreate() with invitations will fail if the chosen game-name is already taken in a "singleton namebased pool" +- New: RC_APPINSTANCE_ALREADY_EXISTS for the case above + +*** Version 5.0.0 RC2 +- Change: gameCreateReturn() now returns RC_APPINSTANCE_NOT_OPEN (instead of RC_AI_TOO_MANY_ACTORSESSIONS) for full games in "singleton" pools +- Change: obsolete events EV_TURN, EV_TXTMSG and EV_DATA which could be sent by raiseEvent*() and still handled +- Change: switched Neutron URLs to "[..].neutron5.[..]" for test/run libs +- Fix: Polling (getEvents operation) again calls sendGameDataReturn() for all errors (as intended for v4.9.2 already) +- New: constant NeutronListener.EV_KEY_TYPE as part of event EV_BUDDNOTICE + +*** Version 5.0.0 RC1 +- New: RaiseEvent (all functions of this name) now has a "filter" parameter. If filter is true, all String-typed values in an event are badword filtered +- Change: signature of NeutronGame.raiseEvent(), NeutronGame.raiseEventInChannel(), NeutronSession.raiseEventInChannel(), NeutronSession.raiseEventForActor() start with: byte eventCode, Hashtable event, boolean filter +- Change: signature of NeutronSession.raiseEventForActor() is changed to "byte eventCode, Hashtable eventData, boolean filter, String userID, int minutesValid, byte maxTypeCount, byte channel" +- Change: NeutronGame.doModerate() is now isModerator() +- Change: moved GpOperation.SerializeData() and GpOperation.DeserializeData() to Neutron.SerializeData() and Neutron.DeserializeData(). +- New: errorCode RC_INVALID_TARGET and RC_PARAMETER_NOT_SUPPLIED added as constant. + +*** Version 4.9.3 +- New: Errors constants in NeutronListener: RC_FATAL_LOGIC, RC_MATCHMAKING_NOT_COMPLETED, RC_CHANNEL_ACCESS_VIOLATION +- New: for game-creation you can now reserve "spots", which are not filled up by Neutron matchmaking. players can be invited to fill the spots, or they can be deblocked later on +- New: Parameter reservedSpots in NeutronSession.gameCreate() +- New: NeutronGame.setReservedSpots() to modify the number of reserved slots (to make them available to matchmaking again, or block/reserve them) +- New: event EV_RESERVED_SPOTS will update the NeutronGame.reservedSpots value after a call to NeutronGame.setReservedSpots() +- New: NeutronSession.listBannedPlayers() gives you the list of banned players for a known game - only usable by "admin" users +- New: NeutronSession.unbanPlayer() is a modified "kick" operation which allows the respective user to join a certain game again - only usable by "admin" users +- New: the event invitation includes now the game's name (in the new key EV_KEY_NAME) +- New: NeutronSession.gameListPerPool() has now three options to sort the results: by game-name, player-count or "persistent games first" +- Removed: NeutronGame: handoverTurn(), sendData(), sendTextMsg(), getEventHistory() and getEventHistoryReturn(). Obsolete events: EV_TURN, EV_TXTMSG, EV_DATA. Session: getScorePosition()+getScorePositionReturn() +- Update: release_history.txt was updated from v4.0. All changes up to v4.0.4 are added to v4.9.3 + +*** Version 4.9.2 +- New: Players can be admins (by list of logins on server) or moderator (by being the first active player of a game) +- New: Players may request and become moderator for game: NeutronSession.gameCanModerate(boolean), NeutronSession.canModerate, NeutronGame.doModerate() and NeutronGame.moderatorActorNr +- Change: the new value NeutronSession.canModerate will be sent with gameCreate() operations (if set to true) +- New: Event key NeutronListener.EV_KEY_MODERATOR to get moderator's actorNr from events +- Change: EV_QUIT and EV_KICKED now carry the new key EV_KEY_MODERATOR which tells all players who is the current moderator (by actorNr); this is stored into NeutronGame.moderatorActorNr +- New: Players in NeutronGame can have new state PLAYER_KICKED (player-data is updated with EV_KICKED) +- New: NeutronGame.kickPlayer() (for moderators) and NeutronSession.kickPlayer() (for admin's who are not active in the game to shutdown) +- New: NeutronSession.shutdownGame() can be used by admin-players (for others, this operation will fail) +- New: Namebased pools can now be defined as "singleton": only one instance per pool and name will be created; if such a game is full players get an error instead of a new game +- New: Errors constants in NeutronListener: RC_ACTORSESSION_KICKED, RC_ACTORSESSION_BANNED, RC_APPINSTANCE_CLOSED, RC_ACTORSESSION_ALREADY_JOINED +- Change: NeutronGame.raiseEvent() accepts a "targetActorNr" which defines a single player to get the raised event; leave 0 to target "all players in game" (as before) +- New: NeutronGame.quitLocally() to release a NeutronGame instance locally (without having to quit()); used after a player was kicked or game shutdown +- Update: NeutronGame.playerGetCount() is updated to simply count all active or inactive players (excluding quit and kicked ones) +- Internal: NeutronGame constructor reads new parameter: P_MODERATOR +- Change: Polling (getEvents operation) now calls sendGameDataReturn() for all errors (not just RC_ACTORSESSION_EXPIRED and RC_ACTORSESSION_NOT_FOUND); takes care of kicked/banned errors +- Fix: Fatal server errors cause a returnCode of NeutronListener.RC_OP_SERVER again; debug test-server libs print out debug text! (during development fatal errors could happen in case of not matching client/server setups) +- Change: removed (already deprecated) NeutronListener.gameListPerPoolReturn() +- Change / Internal: canModerate is sent as Byte (not bool) as in definition; Code: if ( canModerate ) op.addParameter(Neutron.P_MODERATOR , new Byte((byte)1)); +- Add: NeutronGame.PLAYER_KICKED is now listed in JavaDoc for NeutronGame.playerGetStatus() +- Update: JavaDoc package.html, gameCreateReturn(), gamesListReturn(), EV_DEACTIVATE, kickPlayer(), quitLocally(), RC_ACTORSESSION_KICKED, RC_ACTORSESSION_BANNED, RC_APPINSTANCE_CLOSED, RC_ACTORSESSION_ALREADY_JOINED +- Added: Event EV_STATUS (50) includes a key EV_KEY_ISADMIN if the current player has administrator rights; the value is (byte)1 in that case. The key does not exist in any other case (normal users) +- Update: JavaDoc gameCreateReturn; +- New: Added constant RC_APPINSTANCE_NOT_FOUND = 137 for shutdownGameReturn() +- Fix: serializable datatypes are now completely listed in NeutronSession JavaDoc +- New: Constant for property-change events: EV_PROPERTIES_CHANGE including new keys: EV_KEY_PROPERTY_TYPE, EV_KEY_PROPERTIES, EV_KEY_ISDIFF +- Update: JavaDoc for properties in NeutronSession + +*** Version 4.1.1 +- Fix: gameListPerPool() defaults to 10 games and no offset if the values are less than 1 +- Fix: gamesListReturn() JavaDoc description for "listType" is now: 0 = open games; 1 = invitations; 2 = pool's open games list +- Update: gameListPerPool() sends "{gn}" as values-parameter if it's null +- Update: getPropertiesReturn() gets new parameters: actorNr, userID. These are optional and are available in certain situations only. See JavaDoc +- Update: gameListPerPoolReturn() is now deprecated and merged into gamesListReturn() which in turn got a "type" to identify the list-type +- New: getListBuddyIgnore() got one more value: 't'. This requests the type of relation to users. useful when getting lists of type "both". this is buddies and ignores. +- Change: renamed returned parameters to: count and countOnline. These values are referring to the number in the returned list +- Internal: parameter P_USERID = 85; used in getProperties +- New: made methods nullpointer resistant: getListBuddyIgnore, buddySet, get/set PlayerProperties, get/set ActorProperties, get/set GameProperties; some methods throw exceptions in debug version + +*** Version 4.1.0 +- New: Properties. NeutronSession: setActorProperties(), getActorProperties(). NeutronGame: setLocalPlayerProperties(), getPlayerProperties(), getGameProperties(), setGameProperties() +- New: Buddylist and Ignorelist in NeutronSession: listBuddies(), listIgnored(), getListBuddyIgnore(), buddySet() +- New: Listing of games per pool in NeutronSession: NeutronSession gameListPerPool() +- New: Games with password (only usable for named games) +- Internal: Changed parameter in buddySet from P_STATUS to P_TYPE + +*** Version 4.0.4 +- Change: NeutronGame.handoverTurn() and NeutronGame.sendData() are now getting a Hashtable parameter instead of Object +- New: RC_ACTORSESSION_BUSY (121) constant to help identify common development error! check in gameCreateReturn() + +*** Version 4.0.3 +- New: RC_INVALID_CONNECTIONSTRING (74) constant to help identify a common error! check in loginReturn() +- Update: list of serializable datatypes in NeutronSession JavaDoc +- Fix: Fatal server errors cause a returnCode of NeutronListener.RC_OP_SERVER again; debug test-server libs print out debug text! (during development fatal errors could happen in case of not matching client/server setups) + +*** Version 4.0.2 +- Internal: Neutron.deserializeData() now returns either the P_DATA part of the deserialized data (if available / serialized by serializeData()) or the resulting hashtable itself + +*** Version 4.0.1 +- New: NConnectSE connects to server defined by parameter: ipPort (before: fixed host) +- New: SE version is now completely independent from Java ME classes (were not used, but had to be present) +- Fix: Changed versioning for "ClientLibVersion" in Login/CC +*** Version 4.0.0.0 + +- Removed methods: + - NeutronSession.BuggyGetList - replaced by new GetListBuddyIgnore method; + - NeutronSession.ReSubscribe; + - NeutrinSession.ConfirmBilling; + - NeutronListener.ResubscribeReturn; + +- Added methods: + - NeutronSession.GameCreateNamed with password parameter; + - NeutronSession.GameListPerPool; + - NeutronSession.GetActorProperties; + - NeutronSession.SetActorProperties; + - NeutronSession.GetListBuddyIgnore - replaces removed BuggyGetList; + - NeutronSession.ListBuddies; + - NeutronSession.ListIgnore; + - NeutronSession.BillingInitPayment; + - NeutronSession.BillingProcessPayment; + - NeutronGame.Invite; + - NeutronGame.GetGameProperties; + - NeutronGame.SetGameProperties; + - NeutronGame.GetPlayerProperties; + - NeutronGame.SetLocatPlayerProperties; + - NeutronListener.GameInviteReturn; + - NeutronListener.GetPropertiesReturn; + - NeutronListener.SetPropertiesReturn; + +- Changed argument list: + - NeutronSession.GameCreate - added password parameter; + - NeutronListener.GamesListReturn added listType parameter; + - NeutronListener.BuddyGetListReturn all buddy related info now in passing in one strings array parrameter; + - NeutronListener.BuddySetReturn added type parameter; + - NeutronListener.BillingInitPaymentReturn; + + +- added constants: + - OPC_INVITE + - OPC_TELLAFRIEND + - OPC_LISTGAMES + - OPC_SETPROPERTIES + - OPC_GETPROPERTIES + - P_USERID + - P_RESERVE + - P_RESULT + - P_PROPERTIES + - P_BROADCAST + - P_ISDIFF + - RCB_CHARGING_ERROR + - RCB_POST_CHARGING_ERROR + - RCB_TIMEOUT + - RCB_PRICE_- Changed + - RCB_PRICE_INVALID + - RCB_FATAL_SERVER_ERROR + - RCB_FATAL_LOGIC_ERROR + - RCB_NOT_INCLUDED + - RCB_WMA_UNAVAILABLE + +*** Version 3.0.2.2 +- CLS-specifications largely corrected + +*** Version 3.0.1.1 +- changes in neutron-java-lib integrated + +*** +- Removed: NeutronGame: playerNames, playerIDs, playerLobbies, playerStats +- Change: removed GpOperation.roundtripTime, now using public Neutron.roundtripTime + to be sent in operation headers (GpOperation.serializeParameters(), internal) +- Change: channelRaiseEvent() is now raiseEventInChannel() and gets the eventCode + as seperate parameter value - analog to raiseEventForActor() +- Fix: renamed EV_KEY_M_MIPLAYERS to EV_KEY_M_MINPLAYERS (number of min players of game, before start) +- Fix: values for EV_KEY_M_MINPLAYERS and EV_KEY_M_MAXPLAYERS corrected (wrong case so far) +- Changed: Neutron.millisecondsToWait (current value of polling-interval) is now + set in Neutron.receiveResponse() for login, register and alike diff --git a/Assets/Plugins/release_history.txt.meta b/Assets/Plugins/release_history.txt.meta new file mode 100644 index 0000000..a06c625 --- /dev/null +++ b/Assets/Plugins/release_history.txt.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: c29089d5f5388bf479c9c8c96ba6df54 +labels: +- ExitGames +- PUN +- Photon +- Networking diff --git a/Assets/Scenes/MainNetworking.unity b/Assets/Scenes/MainNetworking.unity new file mode 100644 index 0000000..1c19742 Binary files /dev/null and b/Assets/Scenes/MainNetworking.unity differ diff --git a/Assets/Scenes/MainNetworking.unity.meta b/Assets/Scenes/MainNetworking.unity.meta new file mode 100644 index 0000000..dedc996 --- /dev/null +++ b/Assets/Scenes/MainNetworking.unity.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 775f6ee2f532c42e184e62e644ba52e7 +timeCreated: 1501015809 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scenes/VuforiaVariantScene.unity b/Assets/Scenes/VuforiaVariantScene.unity index 5db5783..3a2b7c4 100644 Binary files a/Assets/Scenes/VuforiaVariantScene.unity and b/Assets/Scenes/VuforiaVariantScene.unity differ diff --git a/Assets/Scripts/ModelController.cs b/Assets/Scripts/ModelController.cs index 73da4a9..7ebafef 100644 --- a/Assets/Scripts/ModelController.cs +++ b/Assets/Scripts/ModelController.cs @@ -10,10 +10,14 @@ public class ModelController : MonoBehaviour { [SerializeField] private Slider scaleSlider; private float scale; + private Quaternion targetRotation; + + private bool isRotChanged = false; public bool isWalking = false; // Use this for initialization void Start () { - + targetRotation = transform.rotation; + StartCoroutine ("startRotation"); } // Update is called once per frame @@ -39,5 +43,19 @@ public void walkAnimStart () { foreach (GameObject model in models) { model.GetComponent ().isWalking = true; } + isRotChanged = true; + } + + IEnumerator startRotation () { + while (true) { + isRotChanged = false; + yield return new WaitForSeconds (3f); + isRotChanged = true; + yield return new WaitForSeconds (1f); + if (isRotChanged) { + targetRotation *= Quaternion.AngleAxis (60, Vector3.up); + transform.rotation = Quaternion.Lerp (transform.rotation, targetRotation, 10f * Time.deltaTime); + } + } } } diff --git a/Assets/Scripts/ModelCountController.cs b/Assets/Scripts/ModelCountController.cs index a1f14b1..3b1ce58 100644 --- a/Assets/Scripts/ModelCountController.cs +++ b/Assets/Scripts/ModelCountController.cs @@ -16,7 +16,7 @@ void Start() } // Update is called once per frame - void Update() + public void CountUpdate() { string[] tags = new[] { "Spider", "Butterfly", "Serpent" }; int current =dr.value; diff --git a/Assets/Scripts/NetworkManager.cs b/Assets/Scripts/NetworkManager.cs new file mode 100644 index 0000000..8259fac --- /dev/null +++ b/Assets/Scripts/NetworkManager.cs @@ -0,0 +1,36 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +public class NetworkManager : MonoBehaviour { + [SerializeField] private GameObject VuforiaComponent; + //[SerializeField] private GameObject Controls; + [SerializeField] private GameObject mainCam; + private bool isHost; + + void Start () { + isHost = false; + Connect (); + } + + void Connect () { + PhotonNetwork.ConnectUsingSettings ("ARPhobia v1.0.0"); + } + + void OnJoinedLobby () { + PhotonNetwork.JoinRandomRoom (); + } + + void OnPhotonRandomJoinFailed() { + PhotonNetwork.CreateRoom (null); + //Controls.SetActive (true); + isHost = true; + } + + void OnJoinedRoom () { + if (!isHost) { + mainCam.SetActive (false); + VuforiaComponent.SetActive (true); + } + } +} diff --git a/Assets/Scripts/NetworkManager.cs.meta b/Assets/Scripts/NetworkManager.cs.meta new file mode 100644 index 0000000..282116c --- /dev/null +++ b/Assets/Scripts/NetworkManager.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 8e05221ee658745d49b3a2be6411d1ce +timeCreated: 1501015993 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Switch.cs b/Assets/Scripts/Switch.cs similarity index 100% rename from Assets/Switch.cs rename to Assets/Scripts/Switch.cs diff --git a/Assets/Switch.cs.meta b/Assets/Scripts/Switch.cs.meta similarity index 100% rename from Assets/Switch.cs.meta rename to Assets/Scripts/Switch.cs.meta diff --git a/Assets/license_3rdpartynotice.txt b/Assets/license_3rdpartynotice.txt deleted file mode 100755 index 3523080..0000000 --- a/Assets/license_3rdpartynotice.txt +++ /dev/null @@ -1,4254 +0,0 @@ -Vuforia SDK v6.2.10 -PTC Inc. -============================================================= - -This Readme file contains certain notices of software components -included with the Vuforia SDK v6.2.10 that -PTC Inc. is required to provide you. Notwithstanding anything in the - notices in this file, your use of these software components together -with the Vuforia SDK is subject to the terms of your license from -PTC Inc.. Compliance with all copyright laws and software license -agreements included in the notice section of this file are the -responsibility of the user. Except as may be granted by separate -express written agreement, this file provides no license to any -patents, trademarks, copyrights, or other intellectual -property of PTC Inc. or its affiliates. - -Software provided with this notice is NOT A CONTRIBUTION to any Open Source project. - -Copyright (c) 2012-2016 PTC Inc. -All rights reserved. - -PTC is a trademark of PTC Inc., registered in -the United States and other countries. Vuforia is a trademark of -PTC Inc.. Trademarks of PTC Inc. are used -with permission. All other trademarks and service marks are the -property of their respective owners. - - -============================================================= -NOTICES -============================================================= - -============================================================= -1.1 TINYXML (V.2.4.2) - This software contains TinyXML code - and is subject to the following: -============================================================= - -TinyXml is released under the zlib license: - -This software is provided 'as-is', without any express or implied -warranty. In no event will the authors be held liable for any -damages arising from the use of this software. - -Permission is granted to anyone to use this software for any -purpose, including commercial applications, and to alter it and -redistribute it freely, subject to the following restrictions: - -1. The origin of this software must not be misrepresented; you must -not claim that you wrote the original software. If you use this -software in a product, an acknowledgment in the product documentation -would be appreciated but is not required. - -2. Altered source versions must be plainly marked as such, and -must not be misrepresented as being the original software. - -3. This notice may not be removed or altered from any source -distribution. - - -============================================================= -1.2 LIBPNG (V.1.4.2) - This software contains LibPNG code and - is subject to the following: -============================================================= - -COPYRIGHT NOTICE, DISCLAIMER, and LICENSE: - -If you modify libpng you may insert additional notices immediately following -this sentence. - -This code is released under the libpng license. - -libpng versions 1.0.7, July 1, 2000 through 1.6.25, September 1, 2016 are -Copyright (c) 2000-2002, 2004, 2006-2016 Glenn Randers-Pehrson, are -derived from libpng-1.0.6, and are distributed according to the same -disclaimer and license as libpng-1.0.6 with the following individuals -added to the list of Contributing Authors: - - Simon-Pierre Cadieux - Eric S. Raymond - Mans Rullgard - Cosmin Truta - Gilles Vollant - James Yu - -and with the following additions to the disclaimer: - - There is no warranty against interference with your enjoyment of the - library or against infringement. There is no warranty that our - efforts or the library will fulfill any of your particular purposes - or needs. This library is provided with all faults, and the entire - risk of satisfactory quality, performance, accuracy, and effort is with - the user. - -Some files in the "contrib" directory and some configure-generated -files that are distributed with libpng have other copyright owners and -are released under other open source licenses. - -libpng versions 0.97, January 1998, through 1.0.6, March 20, 2000, are -Copyright (c) 1998-2000 Glenn Randers-Pehrson, are derived from -libpng-0.96, and are distributed according to the same disclaimer and -license as libpng-0.96, with the following individuals added to the list -of Contributing Authors: - - Tom Lane - Glenn Randers-Pehrson - Willem van Schaik - -libpng versions 0.89, June 1996, through 0.96, May 1997, are -Copyright (c) 1996-1997 Andreas Dilger, are derived from libpng-0.88, -and are distributed according to the same disclaimer and license as -libpng-0.88, with the following individuals added to the list of -Contributing Authors: - - John Bowler - Kevin Bracey - Sam Bushell - Magnus Holmgren - Greg Roelofs - Tom Tanner - -Some files in the "scripts" directory have other copyright owners -but are released under this license. - -libpng versions 0.5, May 1995, through 0.88, January 1996, are -Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc. - -For the purposes of this copyright and license, "Contributing Authors" -is defined as the following set of individuals: - - Andreas Dilger - Dave Martindale - Guy Eric Schalnat - Paul Schmidt - Tim Wegner - -The PNG Reference Library is supplied "AS IS". The Contributing Authors -and Group 42, Inc. disclaim all warranties, expressed or implied, -including, without limitation, the warranties of merchantability and of -fitness for any purpose. The Contributing Authors and Group 42, Inc. -assume no liability for direct, indirect, incidental, special, exemplary, -or consequential damages, which may result from the use of the PNG -Reference Library, even if advised of the possibility of such damage. - -Permission is hereby granted to use, copy, modify, and distribute this -source code, or portions hereof, for any purpose, without fee, subject -to the following restrictions: - - 1. The origin of this source code must not be misrepresented. - - 2. Altered versions must be plainly marked as such and must not - be misrepresented as being the original source. - - 3. This Copyright notice may not be removed or altered from any - source or altered source distribution. - -The Contributing Authors and Group 42, Inc. specifically permit, without -fee, and encourage the use of this source code as a component to -supporting the PNG file format in commercial products. If you use this -source code in a product, acknowledgment is not required but would be -appreciated. - - - -============================================================= -1.3 USTL (V.1.4) - This software contains uSTL (aka - Codespace-Frugal STL implementation) code - and is subject to the following: -============================================================= - -The MIT License - -Copyright (c) 2005-2009 by Mike Sharov - -Permission is hereby granted, free of charge, to any person obtaining a -copy of this software and associated documentation files (the "Software"), -to deal in the Software without restriction, including without limitation -the rights to use, copy, modify, merge, publish, distribute, sublicense, -and/or sell copies of the Software, and to permit persons to whom the -Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included -in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR -OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, -ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -OTHER DEALINGS IN THE SOFTWARE. - - -============================================================= -1.4 FAST - This software contains FAST code and is subject to - the following: -============================================================= - -Copyright (c) 2006, 2008, 2009, 2010 Edward Rosten -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions -are met: - - - *Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - *Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - *Neither the name of the University of Cambridge nor the names of - its contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -============================================================= -1.2 STDINT - This software contains type definition information and is - subject to the following: -============================================================= - -// ISO C9x compliant stdint.h for Microsoft Visual Studio -// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124 -// -// Copyright (c) 2006-2008 Alexander Chemeris -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// 1. Redistributions of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// -// 2. Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// -// 3. The name of the author may be used to endorse or promote products -// derived from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED -// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO -// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; -// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR -// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF -// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -/////////////////////////////////////////////////////////////////////////////// - -============================================================= -1.3 CPU_Features.c - This software is subject to the following: -============================================================= -/* - * Copyright (C) 2010 The Android Open Source Project - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. -*/ - -============================================================= -1.4 CPU_Features.h - This software is subject to the following: -============================================================= -/* - * Copyright (C) 2010 The Android Open Source Project - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. -*/ - -============================================================= -1.5 Median Filter - This software contains Median Filter code and is subject to - the following: -============================================================= - -Copyright (c) Morgan McGuire and Williams College, 2006 -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - -Redistributions of source code must retain the above copyright notice, -this list of conditions and the following disclaimer. - -Redistributions in binary form must reproduce the above copyright -notice, this list of conditions and the following disclaimer in the -documentation and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.*/ - - -============================================================= -1.5 LIBJPEG (V.8a) - This software contains LibJPEG code and - is subject to the following: -============================================================= - -This software is based in part on the work of the Independent JPEG Group. - - -============================================================= -1.6 ZLIB (V.1.2.5) - This software contains ZLIB code and - is subject to the following: -============================================================= - -Copyright (C) 1995-2010 Jean-loup Gailly and Mark Adler - -This software is provided 'as-is', without any express or implied -warranty. In no event will the authors be held liable for any damages -arising from the use of this software. - -Permission is granted to anyone to use this software for any purpose, -including commercial applications, and to alter it and redistribute it -freely, subject to the following restrictions: - -1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. -2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. -3. This notice may not be removed or altered from any source distribution. - -Jean-loup Gailly Mark Adler -jloup@gzip.org madler@alumni.caltech.edu - - -The data format used by the zlib library is described by RFCs (Request for -Comments) 1950 to 1952 in the files http://www.ietf.org/rfc/rfc1950.txt -(zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format). - - -============================================================= -1.7 base64 (V.0.00.00B) - This software contains base64 code - and is subject to the following: -============================================================= - -Copyright (c) 2001 Bob Trower, Trantor Standard Systems Inc. - - Permission is hereby granted, free of charge, to any person - obtaining a copy of this software and associated - documentation files (the "Software"), to deal in the - Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, - sublicense, and/or sell copies of the Software, and to - permit persons to whom the Software is furnished to do so, - subject to the following conditions: - - The above copyright notice and this permission notice shall - be included in all copies or substantial portions of the - Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY - KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE - WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR - PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS - OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR - OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR - OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - -============================================================= -1.8 FLANN (V.1.2) - This software contains FLANN code and is - subject to the following: -============================================================= - -/* -Copyright 2008-2009 Marius Muja (mariusm@cs.ubc.ca). All rights reserved. -Copyright 2008-2009 David G. Lowe (lowe@cs.ubc.ca). All rights reserved. - -THE BSD LICENSE - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions -are met: - -1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. -2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, -INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - - -============================================================= -1.9 Json-parser - This software contains Json-parser code and - is subject to the following: -============================================================= - -Copyright (C) 2012 James McLaughlin et al. All rights reserved. -https://github.com/udp/json-parser - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions -are met: - -1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - -2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -SUCH DAMAGE. - - -============================================================= -1.10 ANDROID NDK (V.r4b2) - This software contains Android NDK - header files and is subject to the - following: -============================================================= - -/* - * Copyright (C) 2008 The Android Open Source Project - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -------------------------------------------------------------- - -/*- - * Copyright (c) 1992, 1993 - * The Regents of the University of California. All rights reserved. - * (c) UNIX System Laboratories, Inc. - * All or some portions of this file are derived from material licensed - * to the University of California by American Telephone and Telegraph - * Co. or Unix System Laboratories, Inc. and are reproduced herein with - * the permission of UNIX System Laboratories, Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)assert.h 8.2 (Berkeley) 1/21/94 - */ - -------------------------------------------------------------- - -/* - * Copyright (c) 2002 Marc Espie. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE OPENBSD PROJECT AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OPENBSD - * PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -------------------------------------------------------------- - -/*- - * Copyright (c) 1990 The Regents of the University of California. - * All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Chris Torek. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)stdio.h 5.17 (Berkeley) 6/3/91 - */ - -------------------------------------------------------------- - -/*- - * Copyright (c) 1998 The NetBSD Foundation, Inc. - * All rights reserved. - * - * This code is derived from software contributed to The NetBSD Foundation - * by Klaus Klein. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the NetBSD - * Foundation, Inc. and its contributors. - * 4. Neither the name of The NetBSD Foundation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -------------------------------------------------------------- - -/* - * Copyright (c) 1988 The Regents of the University of California. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * from: @(#)limits.h 7.2 (Berkeley) 6/28/90 - */ - -------------------------------------------------------------- - -/*- - * Copyright (c) 1990, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)types.h 8.3 (Berkeley) 1/5/94 - * @(#)ansi.h 8.2 (Berkeley) 1/4/94 - */ - -------------------------------------------------------------- - -/* - * Copyright (c) 1991, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Berkeley Software Design, Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)cdefs.h 8.8 (Berkeley) 1/9/95 - */ - -------------------------------------------------------------- - -/*- - * Copyright (c) 1990, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)types.h 8.3 (Berkeley) 1/5/94 - */ - - ------------------------------------------------------------- - - /* - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunPro, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== - */ - -------------------------------------------------------------- - -/* - * Copyright (c) 1995, 1996 Carnegie-Mellon University. - * All rights reserved. - * - * Author: Chris G. Demetriou - * - * Permission to use, copy, modify and distribute this software and - * its documentation is hereby granted, provided that both the copyright - * notice and this permission notice appear in all copies of the - * software, derivative works or modified versions, and any portions - * thereof, and that both notices appear in supporting documentation. - * - * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" - * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND - * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. - * - * Carnegie Mellon requests users of this software to return to - * - * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU - * School of Computer Science - * Carnegie Mellon University - * Pittsburgh PA 15213-3890 - * - * any improvements or extensions that they make and grant Carnegie the - * rights to redistribute these changes. - */ - - ------------------------------------------------------------- - - Copyright (c) 2005-2008, The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - - -============================================================= -1.11 iOS SDK (V.6.0) - This software is developed using unmodified -iOS SDK header files included in Apple's iOS SDK and such use is not a -Modification. - -Mac OS X SDK (V.10.8) - This software is developed using unmodified -OS X SDK header files included in Apple's Mac OS X SDK and such use is not a -Modification. - -This software contains iOS and OS X SDK header files that were received with -notices indicating they were subject to the following. -============================================================= - -/* - * Copyright (c) 1991, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - */ - -------------------------------------------------------------- - -/* - * Copyright (c) 1987, 1991, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - */ - -------------------------------------------------------------- - -/* - * Copyright (c) 1988, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - */ - -------------------------------------------------------------- - -/*- - * Copyright (c) 1990, 1993 - * The Regents of the University of California. All rights reserved. - * (c) UNIX System Laboratories, Inc. - * All or some portions of this file are derived from material licensed - * to the University of California by American Telephone and Telegraph - * Co. or Unix System Laboratories, Inc. and are reproduced herein with - * the permission of UNIX System Laboratories, Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - */ - -------------------------------------------------------------- - -/* - * Copyright (c) 1990, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - */ - -------------------------------------------------------------- - -/* - * ++Copyright++ 1983, 1993 - * - - * Copyright (c) 1983, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - - * Portions Copyright (c) 1993 by Digital Equipment Corporation. - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies, and that - * the name of Digital Equipment Corporation not be used in advertising or - * publicity pertaining to distribution of the document or software without - * specific, written prior permission. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL - * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT - * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL - * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR - * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS - * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS - * SOFTWARE. - * - - * --Copyright-- - */ - -------------------------------------------------------------- - -/*- - * Copyright (c) 1992, 1993 - * The Regents of the University of California. All rights reserved. - * (c) UNIX System Laboratories, Inc. - * All or some portions of this file are derived from material licensed - * to the University of California by American Telephone and Telegraph - * Co. or Unix System Laboratories, Inc. and are reproduced herein with - * the permission of UNIX System Laboratories, Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - */ - -------------------------------------------------------------- - -/* - * Copyright (c) 1989, 1993 - * The Regents of the University of California. All rights reserved. - * (c) UNIX System Laboratories, Inc. - * All or some portions of this file are derived from material licensed - * to the University of California by American Telephone and Telegraph - * Co. or Unix System Laboratories, Inc. and are reproduced herein with - * the permission of UNIX System Laboratories, Inc. - * - * This code is derived from software contributed to Berkeley by - * Paul Borman at Krystal Technologies. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - */ - -------------------------------------------------------------- - -/* - * Copyright (c) 1982, 1986, 1989, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - */ - -------------------------------------------------------------- - -/* - * ++Copyright++ 1980, 1983, 1988, 1993 - * - - * Copyright (c) 1980, 1983, 1988, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * - - * Portions Copyright (c) 1993 by Digital Equipment Corporation. - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies, and that - * the name of Digital Equipment Corporation not be used in advertising or - * publicity pertaining to distribution of the document or software without - * specific, written prior permission. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL - * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT - * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL - * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR - * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS - * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS - * SOFTWARE. - * - - * --Copyright-- - */ - -------------------------------------------------------------- - -/* - * Copyright (c) 1982, 1986, 1990, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - */ - -------------------------------------------------------------- - -/*- - * Copyright (c) 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Paul Borman at Krystal Technologies. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - */ - -------------------------------------------------------------- - -/*- - * Copyright (c) 1991, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - */ - -------------------------------------------------------------- - -/*- - * Copyright (c) 1990, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Chris Torek. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - */ - -------------------------------------------------------------- - -/*- - * Copyright (c) 1990, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - */ - -------------------------------------------------------------- - -/* - * Copyright (c) 1987, 1991, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -------------------------------------------------------------- - -/* - * Copyright (c) 1991, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Berkeley Software Design, Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - */ - -------------------------------------------------------------- - -/* - * Copyright (c) 1982, 1986, 1989, 1993 - * The Regents of the University of California. All rights reserved. - * (c) UNIX System Laboratories, Inc. - * All or some portions of this file are derived from material licensed - * to the University of California by American Telephone and Telegraph - * Co. or Unix System Laboratories, Inc. and are reproduced herein with - * the permission of UNIX System Laboratories, Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - */ - -------------------------------------------------------------- - -/*- - * Copyright (c) 1983, 1990, 1993 - * The Regents of the University of California. All rights reserved. - * (c) UNIX System Laboratories, Inc. - * All or some portions of this file are derived from material licensed - * to the University of California by American Telephone and Telegraph - * Co. or Unix System Laboratories, Inc. and are reproduced herein with - * the permission of UNIX System Laboratories, Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - */ - -------------------------------------------------------------- - -/* - * Copyright (c) 1995 - * The Regents of the University of California. All rights reserved. - * - * This code contains ideas from software contributed to Berkeley by - * Avadis Tevanian, Jr., Michael Wayne Young, and the Mach Operating - * System project at Carnegie-Mellon University. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - */ - -------------------------------------------------------------- - -/*- - * Copyright (c) 1982, 1986, 1989, 1993 - * The Regents of the University of California. All rights reserved. - * (c) UNIX System Laboratories, Inc. - * All or some portions of this file are derived from material licensed - * to the University of California by American Telephone and Telegraph - * Co. or Unix System Laboratories, Inc. and are reproduced herein with - * the permission of UNIX System Laboratories, Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - */ - -------------------------------------------------------------- - -/*- - * Copyright (c) 1986, 1989, 1991, 1993 - * The Regents of the University of California. All rights reserved. - * (c) UNIX System Laboratories, Inc. - * All or some portions of this file are derived from material licensed - * to the University of California by American Telephone and Telegraph - * Co. or Unix System Laboratories, Inc. and are reproduced herein with - * the permission of UNIX System Laboratories, Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - */ - -------------------------------------------------------------- - -/*- - * Copyright (c) 1991, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - */ - -------------------------------------------------------------- - -/* - * Copyright (c) 1982, 1986, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - */ - -------------------------------------------------------------- - -/* - * Copyright (c) 1992, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - */ - -------------------------------------------------------------- - -/* - * Copyright (c) 1982, 1986, 1989, 1991, 1993 - * The Regents of the University of California. All rights reserved. - * (c) UNIX System Laboratories, Inc. - * All or some portions of this file are derived from material licensed - * to the University of California by American Telephone and Telegraph - * Co. or Unix System Laboratories, Inc. and are reproduced herein with - * the permission of UNIX System Laboratories, Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - */ - -------------------------------------------------------------- - -/* - * Copyright (c) 1982, 1985, 1986, 1988, 1993, 1994 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - */ - -------------------------------------------------------------- - -/* - * Copyright (c) 1989, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Mike Karels at Berkeley Software Design, Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - */ - -------------------------------------------------------------- - -/* - * Copyright (c) 1982, 1986, 1991, 1993, 1994 - * The Regents of the University of California. All rights reserved. - * (c) UNIX System Laboratories, Inc. - * All or some portions of this file are derived from material licensed - * to the University of California by American Telephone and Telegraph - * Co. or Unix System Laboratories, Inc. and are reproduced herein with - * the permission of UNIX System Laboratories, Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - */ - -------------------------------------------------------------- - -/* - * Copyright (c) 1989, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - */ - -------------------------------------------------------------- - -/* - * Copyright (c) 1982, 1986, 1989, 1993, 1994 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - */ - -------------------------------------------------------------- - -/* - * Copyright (c) 1989, 1993 - * The Regents of the University of California. All rights reserved. - * (c) UNIX System Laboratories, Inc. - * All or some portions of this file are derived from material licensed - * to the University of California by American Telephone and Telegraph - * Co. or Unix System Laboratories, Inc. and are reproduced herein with - * the permission of UNIX System Laboratories, Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - */ - -------------------------------------------------------------- - -/*- - * Copyright (c) 1998-1999 Apple Computer, Inc. All Rights Reserved - * Copyright (c) 1991, 1993, 1994 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * - * Copyright (c) 1998 Apple Compter, Inc. - * All Rights Reserved - */ - -------------------------------------------------------------- - - * @APPLE_APACHE_LICENSE_HEADER_START@ - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * @APPLE_APACHE_LICENSE_HEADER_END@ - - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - -------------------------------------------------------------- - -/*- - * Copyright (c) 2005-2009 Apple Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of Apple Inc. ("Apple") nor the names of - * its contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * $P4: //depot/projects/trustedbsd/openbsm/sys/bsm/audit.h#10 $ - */ - -------------------------------------------------------------- - - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - -------------------------------------------------------------- - - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - -------------------------------------------------------------- - - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - -------------------------------------------------------------- - - * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. The rights granted to you under the License - * may not be used to create, or enable the creation or redistribution of, - * unlawful or unlicensed copies of an Apple operating system, or to - * circumvent, violate, or enable the circumvention or violation of, any - * terms of an Apple operating system software license agreement. - * - * Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ - -------------------------------------------------------------- - - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - -------------------------------------------------------------- - - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - -------------------------------------------------------------- - -/*- - * Copyright (c)1999 Citrus Project, - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - */ - -------------------------------------------------------------- - -/*===---- arm_neon.h - ARM Neon intrinsics ---------------------------------=== - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - *===-----------------------------------------------------------------------=== - */ - -------------------------------------------------------------- - -/*===---- float.h - Characteristics of floating point types ----------------=== - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - *===-----------------------------------------------------------------------=== - */ - -------------------------------------------------------------- - -/*===---- limits.h - Standard header for integer sizes --------------------===*\ - * - * Copyright (c) 2009 Chris Lattner - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * -\*===----------------------------------------------------------------------===*/ - -------------------------------------------------------------- - -/*===---- stdarg.h - Variable argument handling ----------------------------=== - * - * Copyright (c) 2008 Eli Friedman - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - *===-----------------------------------------------------------------------=== - */ - -------------------------------------------------------------- - -/*===---- stdbool.h - Standard header for booleans -------------------------=== - * - * Copyright (c) 2008 Eli Friedman - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - *===-----------------------------------------------------------------------=== - */ - -------------------------------------------------------------- - -/*===---- stddef.h - Basic type definitions --------------------------------=== - * - * Copyright (c) 2008 Eli Friedman - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - *===-----------------------------------------------------------------------=== - */ - -------------------------------------------------------------- - -/*===---- stdint.h - Standard header for sized integer types --------------===*\ - * - * Copyright (c) 2009 Chris Lattner - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * -\*===----------------------------------------------------------------------===*/ - -------------------------------------------------------------- - -/* - * Mach Operating System - * Copyright (c) 1991,1990,1989 Carnegie Mellon University - * All Rights Reserved. - * - * Permission to use, copy, modify and distribute this software and its - * documentation is hereby granted, provided that both the copyright - * notice and this permission notice appear in all copies of the - * software, derivative works or modified versions, and any portions - * thereof, and that both notices appear in supporting documentation. - * - * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" - * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR - * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. - * - * Carnegie Mellon requests users of this software to return to - * - * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU - * School of Computer Science - * Carnegie Mellon University - * Pittsburgh PA 15213-3890 - * - * any improvements or extensions that they make and grant Carnegie Mellon - * the rights to redistribute these changes. - */ - -------------------------------------------------------------- - -/* - * Mach Operating System - * Copyright (c) 1991,1990,1989,1988 Carnegie Mellon University - * All Rights Reserved. - * - * Permission to use, copy, modify and distribute this software and its - * documentation is hereby granted, provided that both the copyright - * notice and this permission notice appear in all copies of the - * software, derivative works or modified versions, and any portions - * thereof, and that both notices appear in supporting documentation. - * - * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" - * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR - * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. - * - * Carnegie Mellon requests users of this software to return to - * - * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU - * School of Computer Science - * Carnegie Mellon University - * Pittsburgh PA 15213-3890 - * - * any improvements or extensions that they make and grant Carnegie Mellon - * the rights to redistribute these changes. - */ - -------------------------------------------------------------- - -/* - * Mach Operating System - * Copyright (c) 1991,1990,1989,1988,1987 Carnegie Mellon University - * All Rights Reserved. - * - * Permission to use, copy, modify and distribute this software and its - * documentation is hereby granted, provided that both the copyright - * notice and this permission notice appear in all copies of the - * software, derivative works or modified versions, and any portions - * thereof, and that both notices appear in supporting documentation. - * - * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" - * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR - * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. - * - * Carnegie Mellon requests users of this software to return to - * - * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU - * School of Computer Science - * Carnegie Mellon University - * Pittsburgh PA 15213-3890 - * - * any improvements or extensions that they make and grant Carnegie Mellon - * the rights to redistribute these changes. - */ - -------------------------------------------------------------- - -/* - * Mach Operating System - * Copyright (c) 1991 Carnegie Mellon University - * All Rights Reserved. - * - * Permission to use, copy, modify and distribute this software and its - * documentation is hereby granted, provided that both the copyright - * notice and this permission notice appear in all copies of the - * software, derivative works or modified versions, and any portions - * thereof, and that both notices appear in supporting documentation. - * - * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" - * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR - * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. - * - * Carnegie Mellon requests users of this software to return to - * - * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU - * School of Computer Science - * Carnegie Mellon University - * Pittsburgh PA 15213-3890 - * - * any improvements or extensions that they make and grant Carnegie Mellon - * the rights to redistribute these changes. - */ - -------------------------------------------------------------- - -/* - * Mach Operating System - * Copyright (c) 1991,1990,1989,1988 Carnegie Mellon University - * All Rights Reserved. - * - * Permission to use, copy, modify and distribute this software and its - * documentation is hereby granted, provided that both the copyright - * notice and this permission notice appear in all copies of the - * software, derivative works or modified versions, and any portions - * thereof, and that both notices appear in supporting documentation. - * - * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" - * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR - * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. - * - * Carnegie Mellon requests users of this software to return to - * - * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU - * School of Computer Science - * Carnegie Mellon University - * Pittsburgh PA 15213-3890 - * - * any improvements or extensions that they make and grant Carnegie Mellon - * the rights to redistribute these changes. - */ - -------------------------------------------------------------- - -/* - * Block.h - * - * Copyright (c) 2008-2010 Apple Inc. All rights reserved. - * - * @APPLE_LLVM_LICENSE_HEADER@ - * - */ - -------------------------------------------------------------- - -// The LLVM Compiler Infrastructure -// -// This file is dual licensed under the MIT and the University of Illinois Open -// Source Licenses. See LICENSE.TXT for details. - -------------------------------------------------------------- - -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. - -============================================================================== -LLVM Release License -============================================================================== -University of Illinois/NCSA -Open Source License - -Copyright (c) 2007 University of Illinois at Urbana-Champaign. -All rights reserved. - -Developed by: - - LLVM Team - - University of Illinois at Urbana-Champaign - - http://llvm.org - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal with -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies -of the Software, and to permit persons to whom the Software is furnished to do -so, subject to the following conditions: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimers. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimers in the - documentation and/or other materials provided with the distribution. - - * Neither the names of the LLVM Team, University of Illinois at - Urbana-Champaign, nor the names of its contributors may be used to - endorse or promote products derived from this Software without specific - prior written permission. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE -SOFTWARE. - -============================================================================== -The LLVM software contains code written by third parties. Such software will -have its own individual LICENSE.TXT file in the directory in which it appears. -This file will describe the copyrights, license, and restrictions which apply -to that code. - -The disclaimer of warranty in the University of Illinois Open Source License -applies to all code in the LLVM Distribution, and nothing in any of the -other licenses gives permission to use the names of the LLVM Team or the -University of Illinois to endorse or promote products derived from this -Software. - -The following pieces of software have additional or alternate copyrights, -licenses, and/or restrictions: - -Program Directory -------- --------- - - -------------------------------------------------------------- - -/*- - * Copyright (c) 1996 The NetBSD Foundation, Inc. - * All rights reserved. - * - * This code is derived from software contributed to The NetBSD Foundation - * by J.T. Conklin. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the NetBSD - * Foundation, Inc. and its contributors. - * 4. Neither the name of The NetBSD Foundation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - */ - -------------------------------------------------------------- - -/*- - * Copyright (c) 1999, 2000 The NetBSD Foundation, Inc. - * All rights reserved. - * - * This code is derived from software contributed to The NetBSD Foundation - * by Julian Coleman. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the NetBSD - * Foundation, Inc. and its contributors. - * 4. Neither the name of The NetBSD Foundation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - */ - -------------------------------------------------------------- - -/* - * Copyright 1996 1995 by Open Software Foundation, Inc. 1997 1996 1995 1994 1993 1992 1991 - * All Rights Reserved - * - * Permission to use, copy, modify, and distribute this software and - * its documentation for any purpose and without fee is hereby granted, - * provided that the above copyright notice appears in all copies and - * that both the copyright notice and this permission notice appear in - * supporting documentation. - * - * OSF DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE. - * - * IN NO EVENT SHALL OSF BE LIABLE FOR ANY SPECIAL, INDIRECT, OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM - * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, - * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION - * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - */ - -------------------------------------------------------------- - -/* -** License Applicability. Except to the extent portions of this file are -** made subject to an alternative license as permitted in the SGI Free -** Software License B, Version 1.0 (the "License"), the contents of this -** file are subject only to the provisions of the License. You may not use -** this file except in compliance with the License. You may obtain a copy -** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600 -** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at: -** -** http://oss.sgi.com/projects/FreeB -** -** Note that, as provided in the License, the Software is distributed on an -** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS -** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND -** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A -** PARTICULAR PURPOSE, AND NON-INFRINGEMENT. -** -** Original Code. The Original Code is: OpenGL Sample Implementation, -** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics, -** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc. -** Copyright in any portions created by third parties is as indicated -** elsewhere herein. All Rights Reserved. -** -** Additional Notice Provisions: The application programming interfaces -** established by SGI in conjunction with the Original Code are The -** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released -** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version -** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X -** Window System(R) (Version 1.3), released October 19, 1998. This software -** was created using the OpenGL(R) version 1.2.1 Sample Implementation -** published by SGI, but has not been independently verified as being -** compliant with the OpenGL(R) version 1.2.1 Specification. -*/ - -------------------------------------------------------------- - -/* - * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the project nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -------------------------------------------------------------- - -============================================================= -1.12 Python 2.7.5 -============================================================= - -PSF LICENSE AGREEMENT FOR PYTHON 2.7.5 - - This LICENSE AGREEMENT is between the Python Software Foundation (“PSF”), and the Individual or Organization (“Licensee”) accessing and otherwise using Python 2.7.5 software in source or binary form and its associated documentation. - Subject to the terms and conditions of this License Agreement, PSF hereby grants Licensee a nonexclusive, royalty-free, world-wide license to reproduce, analyze, test, perform and/or display publicly, prepare derivative works, distribute, and otherwise use Python 2.7.5 alone or in any derivative version, provided, however, that PSF’s License Agreement and PSF’s notice of copyright, i.e., “Copyright © 2001-2013 Python Software Foundation; All Rights Reserved” are retained in Python 2.7.5 alone or in any derivative version prepared by Licensee. - In the event Licensee prepares a derivative work that is based on or incorporates Python 2.7.5 or any part thereof, and wants to make the derivative work available to others as provided herein, then Licensee hereby agrees to include in any such work a brief summary of the changes made to Python 2.7.5. - PSF is making Python 2.7.5 available to Licensee on an “AS IS” basis. PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON 2.7.5 WILL NOT INFRINGE ANY THIRD PARTY RIGHTS. - PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON 2.7.5 FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON 2.7.5, OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. - This License Agreement will automatically terminate upon a material breach of its terms and conditions. - Nothing in this License Agreement shall be deemed to create any relationship of agency, partnership, or joint venture between PSF and Licensee. This License Agreement does not grant permission to use PSF trademarks or trade name in a trademark sense to endorse or promote products or services of Licensee, or any third party. - By copying, installing or otherwise using Python 2.7.5, Licensee agrees to be bound by the terms and conditions of this License Agreement. - - -============================================================= -1.13 LLVM Release license -============================================================= - -University of Illinois/NCSA -Open Source License - -Copyright (c) 2009-2014 by the contributors listed in CREDITS.TXT - -All rights reserved. - -Developed by: - - LLVM Team - - University of Illinois at Urbana-Champaign - - http://llvm.org - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal with -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies -of the Software, and to permit persons to whom the Software is furnished to do -so, subject to the following conditions: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimers. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimers in the - documentation and/or other materials provided with the distribution. - - * Neither the names of the LLVM Team, University of Illinois at - Urbana-Champaign, nor the names of its contributors may be used to - endorse or promote products derived from this Software without specific - prior written permission. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE -SOFTWARE. - -============================================================================== - -Copyright (c) 2009-2014 by the contributors listed in CREDITS.TXT - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - -============================================================================== - -Copyright (c) 2002-2004 Tim J. Robbins. -* -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions -are met: -1. Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. -2. Redistributions in binary form must reproduce the above copyright -notice, this list of conditions and the following disclaimer in the -documentation and/or other materials provided with the distribution. -* -THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -SUCH DAMAGE. -*/ - -============================================================= -1.14 OpenCV MSER -============================================================= - -/* Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * The name of Contributor may not be used to endorse or - * promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, - * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR - * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * Copyright© 2009, Liu Liu All rights reserved. - * - * OpenCV functions for MSER extraction - - -============================================================= -ADDITIONAL ACKNOWLEDGEMENTS -============================================================= - -This software contains QuickSort code by Darel Rex Finley. - -This software contains Grapics Gems III – Chapter: General Filtered Image -Rescaling code by Dale Schumacher. - -This software contains Grapics Gems III – Chapter: Optimization of Bitmap -Scaling Operations code by Dale Schumacher. - -This software contains altered TinyXML code by Tyge Lovset. - -This software contains simage code. All portions of the used code have been -released in the public domain. - -This software contains KLT Optical Flow v1.3.4 which is in the public domain. - - - - - - - - -Copyright 2010, 2012 Adobe Systems Incorporated (http://www.adobe.com/), with Reserved Font Name 'Source'. Source is a trademark of Adobe Systems Incorporated in the United States and/or other countries. - -This Font Software is licensed under the SIL Open Font License, Version 1.1. - -This license is copied below, and is also available with a FAQ at: http://scripts.sil.org/OFL - - ------------------------------------------------------------ -SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 ------------------------------------------------------------ - -PREAMBLE -The goals of the Open Font License (OFL) are to stimulate worldwide -development of collaborative font projects, to support the font creation -efforts of academic and linguistic communities, and to provide a free and -open framework in which fonts may be shared and improved in partnership -with others. - -The OFL allows the licensed fonts to be used, studied, modified and -redistributed freely as long as they are not sold by themselves. The -fonts, including any derivative works, can be bundled, embedded, -redistributed and/or sold with any software provided that any reserved -names are not used by derivative works. The fonts and derivatives, -however, cannot be released under any other type of license. The -requirement for fonts to remain under this license does not apply -to any document created using the fonts or their derivatives. - -DEFINITIONS -"Font Software" refers to the set of files released by the Copyright -Holder(s) under this license and clearly marked as such. This may -include source files, build scripts and documentation. - -"Reserved Font Name" refers to any names specified as such after the -copyright statement(s). - -"Original Version" refers to the collection of Font Software components as -distributed by the Copyright Holder(s). - -"Modified Version" refers to any derivative made by adding to, deleting, -or substituting -- in part or in whole -- any of the components of the -Original Version, by changing formats or by porting the Font Software to a -new environment. - -"Author" refers to any designer, engineer, programmer, technical -writer or other person who contributed to the Font Software. - -PERMISSION & CONDITIONS -Permission is hereby granted, free of charge, to any person obtaining -a copy of the Font Software, to use, study, copy, merge, embed, modify, -redistribute, and sell modified and unmodified copies of the Font -Software, subject to the following conditions: - -1) Neither the Font Software nor any of its individual components, -in Original or Modified Versions, may be sold by itself. - -2) Original or Modified Versions of the Font Software may be bundled, -redistributed and/or sold with any software, provided that each copy -contains the above copyright notice and this license. These can be -included either as stand-alone text files, human-readable headers or -in the appropriate machine-readable metadata fields within text or -binary files as long as those fields can be easily viewed by the user. - -3) No Modified Version of the Font Software may use the Reserved Font -Name(s) unless explicit written permission is granted by the corresponding -Copyright Holder. This restriction only applies to the primary font name as -presented to the users. - -4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font -Software shall not be used to promote, endorse or advertise any -Modified Version, except to acknowledge the contribution(s) of the -Copyright Holder(s) and the Author(s) or with their explicit written -permission. - -5) The Font Software, modified or unmodified, in part or in whole, -must be distributed entirely under this license, and must not be -distributed under any other license. The requirement for fonts to -remain under this license does not apply to any document created -using the Font Software. - -TERMINATION -This license becomes null and void if any of the above conditions are -not met. - -DISCLAIMER -THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - ---------------------------------------------- -Wordnet 3.0 Copyright Notice ----------------------------------------------- -WordNet 3.0 Copyright 2006 by Princeton University. All rights reserved. -THIS SOFTWARE AND DATABASE IS PROVIDED "AS IS" AND PRINCETON UNIVERSITY -MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED. BY WAY OF -EXAMPLE, BUT NOT LIMITATION, PRINCETON UNIVERSITY MAKES NO REPRESENTATIONS - OR WARRANTIES OF MERCHANT- ABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE - OR THAT THE USE OF THE LICENSED SOFTWARE, DATABASE OR DOCUMENTATION WILL - NOT INFRINGE ANY THIRD PARTY PATENTS, COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS. - The name of Princeton University or Princeton may not be used in advertising - or publicity pertaining to distribution of the software and/or database. - Title to copyright in this software, database and any associated documentation - shall at all times remain with Princeton University and you agree to preserve same. - - PSF LICENSE AGREEMENT FOR PYTHON 2.7.5 -1. This LICENSE AGREEMENT is between the Python Software Foundation (“PSF”), and the -Individual or Organization (“Licensee”) accessing and otherwise using Python 2.7.5 -software in source or binary form and its associated documentation. -2. Subject to the terms and conditions of this License Agreement, PSF hereby grants -Licensee a nonexclusive, royalty-free, world-wide license to reproduce, analyze, test, -perform and/or display publicly, prepare derivative works, distribute, and otherwise -use Python 2.7.5 alone or in any derivative version, provided, however, that PSF’s License -Agreement and PSF’s notice of copyright, i.e., “Copyright © 2001-2013 Python Software -Foundation; All Rights Reserved” are retained in Python 2.7.5 alone or in any derivative -version prepared by Licensee. -3. In the event Licensee prepares a derivative work that is based on or incorporates -Python 2.7.5 or any part thereof, and wants to make the derivative work available to -others as provided herein, then Licensee hereby agrees to include in any such work a brief -summary of the changes made to Python 2.7.5. -4. PSF is making Python 2.7.5 available to Licensee on an “AS IS” basis. PSF MAKES NO -REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, -PSF MAKES NO AND DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS -FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON 2.7.5 WILL NOT INFRINGE ANY THIRD PARTY RIGHTS. -5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON 2.7.5 FOR ANY INCIDENTAL, -SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE -USING PYTHON 2.7.5, OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. -6. This License Agreement will automatically terminate upon a material breach of its terms -and conditions. -7. Nothing in this License Agreement shall be deemed to create any relationship of agency, - partnership, or joint venture between PSF and Licensee. This License Agreement does not grant - permission to use PSF trademarks or trade name in a trademark sense to endorse or promote - products or services of Licensee, or any third party. -8. By copying, installing or otherwise using Python 2.7.5, Licensee agrees to be bound by the -terms and conditions of this License Agreement. - ---------------------------------------------- -STLport ---------------------------------------------- -Boris Fomitchev grants Licensee a non-exclusive, non-transferable, royalty-free license to use STLport and its documentation without fee. - -By downloading, using, or copying STLport or any portion thereof, Licensee agrees to abide by the intellectual property laws and all other applicable laws of the United States of America, and to all of the terms and conditions of this Agreement. - -Licensee shall maintain the following copyright and permission notices on STLport sources and its documentation unchanged : - -Copyright 1999,2000 Boris Fomitchev - -This material is provided "as is", with absolutely no warranty expressed or implied. Any use is at your own risk. -Permission to use or copy this software for any purpose is hereby granted without fee, provided the above notices are retained on all copies. Permission to modify the code and to distribute modified code is granted, provided the above notices are retained, and a notice that the code was modified is included with the above copyright notice. -The Licensee may distribute binaries compiled with STLport (whether original or modified) without any royalties or restrictions. - -The Licensee may distribute original or modified STLport sources, provided that: - -The conditions indicated in the above permission notice are met; -The following copyright notices are retained when present, and conditions provided in accompanying permission notices are met : -Copyright 1994 Hewlett-Packard Company - -Copyright 1996,97 Silicon Graphics Computer Systems, Inc. - -Copyright 1997 Moscow Center for SPARC Technology. - -Permission to use, copy, modify, distribute and sell this software and its documentation for any purpose is hereby granted without fee, provided that the above copyright notice appear in all copies and that both that copyright notice and this permission notice appear in supporting documentation. Hewlett-Packard Company makes no representations about the suitability of this software for any purpose. It is provided "as is" without express or implied warranty. - -Permission to use, copy, modify, distribute and sell this software and its documentation for any purpose is hereby granted without fee, provided that the above copyright notice appear in all copies and that both that copyright notice and this permission notice appear in supporting documentation. Silicon Graphics makes no representations about the suitability of this software for any purpose. It is provided "as is" without express or implied warranty. - -Permission to use, copy, modify, distribute and sell this software and its documentation for any purpose is hereby granted without fee, provided that the above copyright notice appear in all copies and that both that copyright notice and this permission notice appear in supporting documentation. Moscow Center for SPARC Technology makes no representations about the suitability of this software for any purpose. It is provided "as is" without express or implied warranty. - ---------------------------------------------- -CPU-Features ---------------------------------------------- -Code downloaded from “http://developer.android.com/sdk/ndk/index.html”. Licensing information taken from header file “sources/android/cpufeatures/cpu-features.h” -/* - * Copyright (C) 2010 The Android Open Source Project - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ ---------------------------------------------- -libGLES ---------------------------------------------- -Copyright (C) [dates of first publication] Silicon Graphics, Inc. All Rights Reserved. -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -The above copyright notice including the dates of first publication and either this permission notice or a reference to http://oss.sgi.com/projects/FreeB/ shall be included in all copies or substantial portions of the Software. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - Except as contained in this notice, the name of Silicon Graphics, Inc. shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Silicon Graphics, Inc. - ---------------------------------------------- -Qhull ---------------------------------------------- -Qhull, Copyright (c) 1993-2012 - -C.B. Barber -Arlington, MA - -and - -The National Science and Technology Research Center for -Computation and Visualization of Geometric Structures -(The Geometry Center) -University of Minnesota - -email: qhull@qhull.org - -This software includes Qhull from C.B. Barber and The Geometry Center. -Qhull is copyrighted as noted above. Qhull is free software and may -be obtained via http from www.qhull.org. It may be freely copied, modified, -and redistributed under the following conditions: - -1. All copyright notices must remain intact in all files. - -2. A copy of this text file must be distributed along with any copies -of Qhull that you redistribute; this includes copies that you have -modified, or copies of programs or other software products that -include Qhull. - -3. If you modify Qhull, you must include a notice giving the -name of the person performing the modification, the date of -modification, and the reason for such modification. - -4. When distributing modified versions of Qhull, or other software -products that include Qhull, you must provide notice that the original -source code may be obtained as noted above. - -5. There is no warranty or other guarantee of fitness for Qhull, it is -provided solely "as is". Bug reports or fixes may be sent to -qhull_bug@qhull.org; the authors may or may not act on them as -they desire. - ---------------------------------------------- -Windows SDK Headers ---------------------------------------------- - - Header files included in the build include (directly or indirectly) files with the following licenses. These files are all part of the Visual Studio C include path or the Windows SDK, the license for which can be found below. Some of them were provided to Microsoft by third parties, but Microsoft licenses them to the developer as part of their Windows SDK. - -/* -* This file is derived from software bearing the following -* restrictions: -* -* Copyright (c) 1994 -* Hewlett-Packard Company -* -* Permission to use, copy, modify, distribute and sell this -* software and its documentation for any purpose is hereby -* granted without fee, provided that the above copyright notice -* appear in all copies and that both that copyright notice and -* this permission notice appear in supporting documentation. -* Hewlett-Packard Company makes no representations about the -* suitability of this software for any purpose. It is provided -* "as is" without express or implied warranty. -*/ - -/* -* Copyright (c) 1992-2012 by P.J. Plauger. ALL RIGHTS RESERVED. -* Consult your license regarding permissions and restrictions. -V6.00:0009 */ - - /* -* Copyright (c) 1992-2012 by P.J. Plauger. ALL RIGHTS RESERVED. -* Consult your license regarding permissions and restrictions. -V6.00:0009 */ - - /* -* Copyright (c) 1992-2007 by P.J. Plauger. ALL RIGHTS RESERVED. -* Consult your license regarding permissions and restrictions. -V5.03:0009 */ - -// -// Copyright (C) Microsoft. All rights reserved. -// - -(The following license text was found in: C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\include\mm3dnow.h) - /*** -*** Copyright (C) 1999 Advanced Micro Devices Inc. All rights reserved. -*** -** The information and source code contained herein is the exclusive -*** property of Advanced Micro Devices and may not be disclosed, examined -*** or reproduced in whole or in part without explicit written authorization -*** from the company. -*** -****/ - -/**** -* Copyright (C) 2007-2008 Advanced Micro Devices Inc. All rights reserved. -* -* The information and source code contained herein is the exclusive -* property of Advanced Micro Devices and may not be disclosed, examined -* or reproduced in whole or in part without explicit written authorization -* from the company. -* -* ammintrin.h - Definitions for AMD-specific intrinsics -* -****/ - -/*** -* imminitrin.h - Meta Header file for Intel(R) Architecture intrinsic functions. -* -* Copyright (C) 1985-2011 Intel Corporation. All rights reserved. -* -* The information and source code contained herein is the exclusive -* property of Intel Corporation and may not be disclosed, examined -* or reproduced in whole or in part without explicit written authorization -* from the company. -* -* -*******************************************************************************/ - - /*** -*** Copyright (C) 1985-2007 Intel Corporation. All rights reserved. -*** -*** The information and source code contained herein is the exclusive -*** property of Intel Corporation and may not be disclosed, examined -*** or reproduced in whole or in part without explicit written authorization -*** from the company. -*** -****/ - -/*** -*** -*** Copyright (C) 1985-2005 Intel Corporation. All rights reserved. -*** -*** The information and source code contained herein is the exclusive -*** property of Intel Corporation and may not be disclosed, examined -*** or reproduced in whole or in part except as expressly provided -*** by the accompanying LICENSE AGREEMENT -*** -*** cvs_id[] = "$Id: pmmintrin.h,v 1.5 2005/01/03 22:55:01 hhle Exp $"; -*** -****/ - -/*** -*** Copyright (C) 1985-1999 Intel Corporation. All rights reserved. -*** -*** The information and source code contained herein is the exclusive -*** property of Intel Corporation and may not be disclosed, examined -*** or reproduced in whole or in part without explicit written authorization -*** from the company. -*** -****/ - -/*** -*** Copyright (C) 1985-2005 Intel Corporation. All rights reserved. -*** -*** The information and source code contained herein is the exclusive -*** property of Intel Corporation and may not be disclosed, examined -*** or reproduced in whole or in part without explicit written authorization -*** from the company. -*** -****/ - -/*** -*** Copyright (C) 1985-2008 Intel Corporation. All rights reserved. -*** -*** The information and source code contained herein is the exclusive -*** property of Intel Corporation and may not be disclosed, examined -*** or reproduced in whole or in part without explicit written authorization -*** from the company. -*** -****/ - - /* Winsock2.h -- definitions to be used with the WinSock 2 DLL and -* WinSock 2 applications. -* -* This header file corresponds to version 2.2.x of the WinSock API -* specification. -* -* This file includes parts which are Copyright (c) 1982-1986 Regents -* of the University of California. All rights reserved. The -* Berkeley Software License Agreement specifies the terms and -* conditions for redistribution. -*/ - -  -************************************************************************ -MICROSOFT SOFTWARE LICENSE TERMS -MICROSOFT WINDOWS SOFTWARE DEVELOPMENT KIT FOR WINDOWS 8 -These license terms are an agreement between Microsoft Corporation (or based on where you live, one of its affiliates) and you. Please read them. They apply to the software named above, which includes the media on which you received it, if any. The terms also apply to any Microsoft - updates, - supplements, - Internet-based services, and - support services -for this software, unless other terms accompany those items. If so, those terms apply. -By using the software, you accept these terms. If you do not accept them, do not use the software. -As described below, using some features also operates as your consent to the transmission of certain standard computer information for Internet-based services. -If you comply with these license terms, you have the perpetual rights below. -1. INSTALLATION AND USE RIGHTS. -a. You may install and use any number of copies of the software on your devices to design, develop and test your programs that run on a Windows operating system. Further, you may install, use and/or deploy via a network management system or as part of a desktop image, any number of copies of the software on computer devices within your internal corporate network to design, develop and test your programs that run on a Windows operating system. Each copy must be complete, including all copyright and trademark notices. You must require end users to agree to terms that protect the software as much as these license terms. -b. Utilities. The software contains certain components that are identified in the Utilities List located at http://go.microsoft.com/fwlink/?LinkId=251959. Depending on the specific edition of the software, the number of Utility files you receive with the software may not be equal to the number of Utilities listed in the Utilities List. Except as otherwise provided on the Utilities List for specific files, you may copy and install the Utilities you receive with the software on to other third party machines. These Utilities may only be used to debug and deploy your programs and databases you have developed with the software. You must delete all the Utilities installed onto a third party machine within the earlier of (i) when you have finished debugging or deploying your programs; or (ii) thirty (30) days after installation of the Utilities onto that machine. We may add additional files to this list from time to time. -c. Build Server List. The software contains certain components that are identified in the Build Server List located at http://go.microsoft.com/fwlink/?LinkId=251961. You may install copies of the files listed in it, onto your build machines, solely for the purpose of compiling, building, verifying and archiving your programs. These components may only be used in order to create and configure build systems internal to your organization to support your internal build environment. These components do not provide external distribution rights to any of the software or enable you to provide a build environment as a service to third parties. We may add additional files to this list from time to time. -d. Included Microsoft Programs. The software contains other Microsoft programs. These license terms apply to your use of those programs. -e. Third Party Notices. The software may include third party code that Microsoft, not the third party, licenses to you under this agreement. Notices, if any, for the third party code are included for your information only. Notices, if any, for this third party code are included with the software and may be found in the ThirdPartyNotices.txt file located at http://go.microsoft.com/fwlink/?LinkId=251962. -2. ADDITIONAL LICENSING REQUIREMENTS AND/OR USE RIGHTS. -a. Distributable Code. The software contains code that you are permitted to distribute in programs you develop if you comply with the terms below. -i. Right to Use and Distribute. The code and text files listed below are “Distributable Code.” - REDIST.TXT Files. You may copy and distribute the object code form of code listed in REDIST.TXT files plus any of the files listed on the REDIST list located at http://go.microsoft.com/fwlink/?LinkId=251953. Depending on the specific edition of the software, the number of REDIST files you receive with the software may not be equal to the number of REDIST files listed in the REDIST.TXT List. We may add additional files to this list from time to time. - Third Party Distribution. You may permit distributors of your programs to copy and distribute the Distributable Code as part of those programs. -ii. Distribution Requirements. For any Distributable Code you distribute, you must - add significant primary functionality to it in your programs; - for any Distributable Code having a filename extension of .lib, distribute only the results of running such Distributable Code through a linker with your program; - distribute Distributable Code included in a setup program only as part of that setup program without modification; - require distributors and external end users to agree to terms that protect it at least as much as this agreement; - for Distributable Code from the Windows Performance Toolkit portions of the software, distribute the unmodified software package as a whole with your programs, with the exception of the KernelTraceControl.dll and the WindowsPerformanceRecorderControl.dll which can be distributed with your programs; - display your valid copyright notice on your programs; and - indemnify, defend, and hold harmless Microsoft from any claims, including attorneys’ fees, related to the distribution or use of your programs. -iii. Distribution Restrictions. You may not - alter any copyright, trademark or patent notice in the Distributable Code; - use Microsoft’s trademarks in your programs’ names or in a way that suggests your programs come from or are endorsed by Microsoft; - distribute partial copies of the Windows Performance Toolkit portion of the software package with the exception of the KernelTraceControl.dll and the WindowsPerformanceRecorderControl.dll which can be distributed with your programs; - distribute Distributable Code to run on a platform other than the Windows platform; - include Distributable Code in malicious, deceptive or unlawful programs; or - modify or distribute the source code of any Distributable Code so that any part of it becomes subject to an Excluded License. An Excluded License is one that requires, as a condition of use, modification or distribution, that - the code be disclosed or distributed in source code form; or - others have the right to modify it. -b. Windows Store. If you distribute your programs through the Windows Store you understand and agree such distribution is subject to the Windows Store developer terms and terms of use, -3. WINDOWS APPLICATION CERTIFICATION KIT. You may use the Windows Application Certification Kit solely to test your programs before you submit them for a potential Microsoft Windows Certification and for inclusion on the Microsoft Windows Store. The results you receive are for informational purposes only. Microsoft has no obligation to either (i) provide you with a Windows Certification for your programs and/or (ii) include your program on the Microsoft Windows Store. -4. INTERNET-BASED SERVICES. Microsoft provides Internet-based services with the software. It may change or cancel them at any time. -a. Consent for Internet-Based Services. The software features described below and in the Windows SDK for Windows 8 Privacy Statement at http://go.microsoft.com/fwlink/?LinkID=234352 connect to Microsoft or service provider computer systems over the Internet. In some cases, you will not receive a separate notice when they connect. In some cases, you may switch off these features or not use them. For more information about these features, see the software documentation. By using these features, you consent to the transmission of this information. Microsoft does not use the information to identify or contact you. -i. Computer Information. The following features use Internet protocols, which send to the appropriate systems computer information, such as your Internet protocol address, the type of operating system, browser, and name and version of the software you are using, and the language code of the device where you installed the software. Microsoft uses this information to make the Internet-based services available to you. - Customer Experience Improvement Program (CEIP). This software uses CEIP. CEIP automatically sends Microsoft information about your hardware and how you use this software. We do not use this information to identify or contact you. When available, new help information about the errors might also be automatically downloaded. To learn more about CEIP, see http://www.microsoft.com/products/ceip/en-us/privacypolicy.mspx. - Error Reports. This software automatically sends error reports to Microsoft. These reports include information about problems that occur in the software. Sometimes reports contain information about other programs that interact with the software. Reports might unintentionally contain personal information. For example, a report that contains a snapshot of computer memory might include your name. Part of a document you were working on could be included as well. Microsoft does not use this information to identify or contact you. To learn more about error reports, see http://oca.microsoft.com/en/dcp20.asp. -ii. Use of Information. We may use the computer information, error reports, and CEIP information, to improve our software and services. We may also share it with others, such as hardware and software vendors. They may use the information to improve how their products run with Microsoft software. -5. SCOPE OF LICENSE. The software is licensed, not sold. This agreement only gives you some rights to use the software. Microsoft reserves all other rights. Unless applicable law gives you more rights despite this limitation, you may use the software only as expressly permitted in this agreement. In doing so, you must comply with any technical limitations in the software that only allow you to use it in certain ways. You may not - disclose the results of any benchmark tests of the software to any third party without Microsoft’s prior written approval; - work around any technical limitations in the software; - reverse engineer, decompile or disassemble the software, except and only to the extent that applicable law expressly permits, despite this limitation; - make more copies of the software than specified in this agreement or allowed by applicable law, despite this limitation; - publish the software for others to copy; - rent, lease or lend the software; - transfer the software or this agreement to any third party; or - use the software for commercial software hosting services. -6. BACKUP COPY. You may make one backup copy of the software. You may use it only to reinstall the software. -7. DOCUMENTATION. Any person that has valid access to your computer or internal network may copy and use the documentation for your internal, reference purposes. -8. EXPORT RESTRICTIONS. The software is subject to United States export laws and regulations. You must comply with all domestic and international export laws and regulations that apply to the software. These laws include restrictions on destinations, end users and end use. For additional information, see www.microsoft.com/exporting. -9. SUPPORT SERVICES. Because this software is “as is,” we may not provide support services for it. -10. ENTIRE AGREEMENT. This agreement, and the terms for supplements, updates, Internet-based services and support services that you use, are the entire agreement for the software and support services. -11. APPLICABLE LAW. -a. United States. If you acquired the software in the United States, Washington state law governs the interpretation of this agreement and applies to claims for breach of it, regardless of conflict of laws principles. The laws of the state where you live govern all other claims, including claims under state consumer protection laws, unfair competition laws, and in tort. -b. Outside the United States. If you acquired the software in any other country, the laws of that country apply. -12. LEGAL EFFECT. This agreement describes certain legal rights. You may have other rights under the laws of your country. You may also have rights with respect to the party from whom you acquired the software. This agreement does not change your rights under the laws of your country if the laws of your country do not permit it to do so. -13. DISCLAIMER OF WARRANTY. The software is licensed “as is.” You bear the risk of using it. Microsoft gives no express warranties, guarantees or conditions. You may have additional consumer rights or statutory guarantees under your local laws which this agreement cannot change. To the extent permitted under your local laws, Microsoft excludes the implied warranties of merchantability, fitness for a particular purpose and non-infringement. -FOR AUSTRALIA – You have statutory guarantees under the Australian Consumer Law and nothing in these terms is intended to affect those rights. -14. LIMITATION ON AND EXCLUSION OF REMEDIES AND DAMAGES. You can recover from Microsoft and its suppliers only direct damages up to U.S. $5.00. You cannot recover any other damages, including consequential, lost profits, special, indirect or incidental damages. -This limitation applies to - anything related to the software, services, content (including code) on third party Internet sites, or third party programs; and - claims for breach of contract, breach of warranty, guarantee or condition, strict liability, negligence, or other tort to the extent permitted by applicable law. -It also applies even if Microsoft knew or should have known about the possibility of the damages. The above limitation or exclusion may not apply to you because your country may not allow the exclusion or limitation of incidental, consequential or other damages. - -Please note: As this software is distributed in Quebec, Canada, some of the clauses in this agreement are provided below in French. -Remarque : Ce logiciel étant distribué au Québec, Canada, certaines des clauses dans ce contrat sont fournies ci-dessous en français. -EXONÉRATION DE GARANTIE. Le logiciel visé par une licence est offert « tel quel ». Toute utilisation de ce logiciel est à votre seule risque et péril. Microsoft n’accorde aucune autre garantie expresse. Vous pouvez bénéficier de droits additionnels en vertu du droit local sur la protection des consommateurs, que ce contrat ne peut modifier. La ou elles sont permises par le droit locale, les garanties implicites de qualité marchande, d’adéquation à un usage particulier et d’absence de contrefaçon sont exclues. -LIMITATION DES DOMMAGES-INTÉRÊTS ET EXCLUSION DE RESPONSABILITÉ POUR LES DOMMAGES. Vous pouvez obtenir de Microsoft et de ses fournisseurs une indemnisation en cas de dommages directs uniquement à hauteur de 5,00 $ US. Vous ne pouvez prétendre à aucune indemnisation pour les autres dommages, y compris les dommages spéciaux, indirects ou accessoires et pertes de bénéfices. -Cette limitation concerne : - tout ce qui est relié au logiciel, aux services ou au contenu (y compris le code) figurant sur des sites Internet tiers ou dans des programmes tiers ; et - les réclamations au titre de violation de contrat ou de garantie, ou au titre de responsabilité stricte, de négligence ou d’une autre faute dans la limite autorisée par la loi en vigueur. -Elle s’applique également, même si Microsoft connaissait ou devrait connaître l’éventualité d’un tel dommage. Si votre pays n’autorise pas l’exclusion ou la limitation de responsabilité pour les dommages indirects, accessoires ou de quelque nature que ce soit, il se peut que la limitation ou l’exclusion ci-dessus ne s’appliquera pas à votre égard. -EFFET JURIDIQUE. Le présent contrat décrit certains droits juridiques. Vous pourriez avoir d’autres droits prévus par les lois de votre pays. Le présent contrat ne modifie pas les droits que vous confèrent les lois de votre pays si celles-ci ne le permettent pas. - - -EULAID:WINKITS.RTM.6.2.0.0_en-US - - ---------------------------------------------- -NanoSVG ---------------------------------------------- - -Copyright (c) 2013-14 Mikko Mononen memon@inside.org - -This software is provided 'as-is', without any express or implied -warranty. In no event will the authors be held liable for any damages -arising from the use of this software. - -Permission is granted to anyone to use this software for any purpose, -including commercial applications, and to alter it and redistribute it -freely, subject to the following restrictions: - -1. The origin of this software must not be misrepresented; you must not -claim that you wrote the original software. If you use this software -in a product, an acknowledgment in the product documentation would be -appreciated but is not required. -2. Altered source versions must be plainly marked as such, and must not be -misrepresented as being the original software. -3. This notice may not be removed or altered from any source distribution. - - ---------------------------------------------- -Schifra ---------------------------------------------- - -Schifra -Reed-Solomon Error Correcting Code Library -http://www.schifra.com -Copyright (c) 2000-2015 Arash Partow, All Rights Reserved. - -The Schifra Reed-Solomon Error Correcting Code Library and all its -components are supplied under the terms of the General Schifra License -agreement. The contents of the Schifra Reed-Solomon Error Correcting -Code Library and its components may not be copied or disclosed except -in accordance with the terms of that agreement. - -URL: http://www.schifra.com/license.html - - -Parties wanting to use the Schifra Reed-Solomon Error Correcting Code -Library and its components within an open source, academic or other -noncommercial or not-for-profit environment may do so under the -guidelines and in complete accordance with the below attached General -Public License (version 2). Under the described terms of "free" use -for open source and noncommercial purposes of the Schifra Reed-Solomon -Error Correcting Code Library and its components, this license file -must accompany ALL Schifra related files including but not limited to -source code, examples and documentation in its original unaltered -form. - - -Persons wanting to use the Schifra Reed-Solomon Error Correcting Code -Library and its components, in environments other than the ones -described above, which include but not limited to any form of -commercial environment, should consult and comply (aka purchase a -commercial Schifra license) with the General Schifra License agreement -before proceeding. - - ---------------------------------------------- -Windows 10 SDK Headers ---------------------------------------------- - - Header files included in the build include (directly or indirectly) files with the following licenses. These files are all part of the Visual Studio 2015 include path or the Windows 10 SDK, the license for which can be found below. Some of them were provided to Microsoft by third parties, but Microsoft licenses them to the developer as part of their Windows SDK. - -// -// Copyright (C) Microsoft. All rights reserved. -// - - -/*** -*** Copyright (C) 1999 Advanced Micro Devices Inc. All rights reserved. -*** -*** The information and source code contained herein is the exclusive -*** property of Advanced Micro Devices and may not be disclosed, examined -*** or reproduced in whole or in part without explicit written authorization -*** from the company. -*** -****/ - -/**** -* Copyright (C) 2007-2008 Advanced Micro Devices Inc. All rights reserved. -* -* The information and source code contained herein is the exclusive -* property of Advanced Micro Devices and may not be disclosed, examined -* or reproduced in whole or in part without explicit written authorization -* from the company. -* -* ammintrin.h - Definitions for AMD-specific intrinsics -* -****/ - -/*** -*** Copyright (C) 1985-1999 Intel Corporation. All rights reserved. -*** -*** The information and source code contained herein is the exclusive -*** property of Intel Corporation and may not be disclosed, examined -*** or reproduced in whole or in part without explicit written authorization -*** from the company. -*** -****/ - - -/*** -* imminitrin.h - Meta Header file for Intel(R) Architecture intrinsic functions. -* -* Copyright (C) 1985-2015 Intel Corporation. All rights reserved. -* -* The information and source code contained herein is the exclusive -* property of Intel Corporation and may not be disclosed, examined -* or reproduced in whole or in part without explicit written authorization -* from the company. -* -* -*******************************************************************************/ - -/*** -*** Copyright (C) 1985-1999 Intel Corporation. All rights reserved. -*** -*** The information and source code contained herein is the exclusive -*** property of Intel Corporation and may not be disclosed, examined -*** or reproduced in whole or in part without explicit written authorization -*** from the company. -*** -****/ - -/*** -*** Copyright (C) 1985-2015 Intel Corporation. All rights reserved. -*** -*** The information and source code contained herein is the exclusive -*** property of Intel Corporation and may not be disclosed, examined -*** or reproduced in whole or in part without explicit written authorization -*** from the company. -*** -****/ - -/* - * This file is derived from software bearing the following - * restrictions: - * - * (c) Copyright William E. Kempf 2001 - * - * Permission to use, copy, modify, distribute and sell this - * software and its documentation for any purpose is hereby - * granted without fee, provided that the above copyright - * notice appear in all copies and that both that copyright - * notice and this permission notice appear in supporting - * documentation. William E. Kempf makes no representations - * about the suitability of this software for any purpose. - * It is provided "as is" without express or implied warranty. - */ - -/* - * Copyright (c) by P.J. Plauger. All rights reserved. - * Consult your license regarding permissions and restrictions. -V6.50:0009 */ - - -/* Winsock2.h -- definitions to be used with the WinSock 2 DLL and - * WinSock 2 applications. - * - * This header file corresponds to version 2.2.x of the WinSock API - * specification. - * - * This file includes parts which are Copyright (c) 1982-1986 Regents - * of the University of California. All rights reserved. The - * Berkeley Software License Agreement specifies the terms and - * conditions for redistribution. - */ - - - -MICROSOFT SOFTWARE LICENSE TERMS -MICROSOFT WINDOWS SOFTWARE DEVELOPMENT KIT (SDK) FOR WINDOWS 10 -_______________________________________________________________________________________________________ -These license terms are an agreement between Microsoft Corporation (or based on where you live, one of its affiliates) and you. Please read them. They apply to the software named above, which includes the media on which you received it, if any. The terms also apply to any Microsoft -• updates, -• supplements, -• Internet-based services, and -• support services -for this software, unless other terms accompany those items. If so, those terms apply. -By using the software, you accept these terms. If you do not accept them, do not use the software. -As described below, using some features also operates as your consent to the transmission of certain standard computer information for Internet-based services. -________________________________________________________________________________________________ -If you comply with these license terms, you have the rights below. -1. INSTALLATION AND USE RIGHTS. -a. You may install and use any number of copies of the software on your devices to design, develop and test your programs that run on a Microsoft operating system. Further, you may install, use and/or deploy via a network management system or as part of a desktop image, any number of copies of the software on computer devices within your internal corporate network to design, develop and test your programs that run on a Microsoft operating system. Each copy must be complete, including all copyright and trademark notices. You must require end users to agree to terms that protect the software as much as these license terms. -b. Utilities. The software contains certain components that are identified in the Utilities List located at http://go.microsoft.com/fwlink/?LinkId=524839. Depending on the specific edition of the software, the number of Utility files you receive with the software may not be equal to the number of Utilities listed in the Utilities List. Except as otherwise provided on the Utilities List for specific files, you may copy and install the Utilities you receive with the software on to other third party machines. These Utilities may only be used to debug and deploy your programs and databases you have developed with the software. You must delete all the Utilities installed onto a third party machine within the earlier of (i) when you have finished debugging or deploying your programs; or (ii) thirty (30) days after installation of the Utilities onto that machine. We may add additional files to this list from time to time. -c. Build Server List.  The software contains certain components that are identified in the Build Server List located at http://go.microsoft.com/fwlink/?LinkId=524838. You may install copies of the files listed in it, onto your build machines, solely for the purpose of compiling, building, verifying and archiving your programs.  These components may only be used in order to create and configure build systems internal to your organization to support your internal build environment.  These components do not provide external distribution rights to any of the software or enable you to provide a build environment as a service to third parties. We may add additional files to this list from time to time. -d. Included Microsoft Programs. The software contains other Microsoft programs. The license terms with those programs apply to your use of them. -e. Third Party Notices. The software may include third party code that Microsoft, not the third party, licenses to you under this agreement. Notices, if any, for the third party code are included for your information only. Notices, if any, for this third party code are included with the software and may be located at http://go.microsoft.com/fwlink/?LinkId=524840. -2. ADDITIONAL LICENSING REQUIREMENTS AND/OR USE RIGHTS. -a. Distributable Code. The software contains code that you are permitted to distribute in programs you develop if you comply with the terms below. -i. Right to Use and Distribute. The code and test files listed below are “Distributable Code”. -• REDIST.TXT Files. You may copy and distribute the object code form of code listed in REDIST.TXT files plus the files listed on the REDIST.TXT list located at http://go.microsoft.com/fwlink/?LinkId=524842. Depending on the specific edition of the software, the number of REDIST files you receive with the software may not be equal to the number of REDIST files listed in the REDIST.TXT List. We may add additional files to the list from time to time. -• Third Party Distribution. You may permit distributors of your programs to copy and distribute the Distributable Code as part of those programs. -ii. Distribution Requirements. For any Distributable Code you distribute, you must -• Add significant primary functionality to it in your programs; -• For any Distributable Code having a filename extension of .lib, distribute only the results of running such Distributable Code through a linker with your program; -• Distribute Distributable Code included in a setup program only as part of that setup program without modification; -• Require distributors and external end users to agree to terms that protect it at least as much as this agreement; -• For Distributable Code from the Windows Performance Toolkit portions of the software, distribute the unmodified software package as a whole with your programs, with the exception of the KernelTraceControl.dll and the WindowsPerformanceRecorderControl.dll which can be distributed with your programs; -• Display your valid copyright notice on your programs; and -• Indemnify, defend, and hold harmless Microsoft from any claims, including attorneys’ fees, related to the distribution or use of your programs. -iii. Distribution Restrictions. You may not -• Alter any copyright, trademark or patent notice in the Distributable Code; -• Use Microsoft’s trademarks in your programs’ names or in a way that suggests your programs come from or are endorsed by Microsoft; -• Distribute partial copies of the Windows Performance Toolkit portion of the software package with the exception of the KernelTraceControl.dll and the WIndowsPerformanceRecorderControl.dll which can be distributed with your programs; -• Distribute Distributable Code to run on a platform other than the Microsoft operating system platform; -• Include Distributable Code in malicious, deceptive or unlawful programs; or -• Modified or distribute the source code of any Distributable Code so that any part of it becomes subject to an Excluded License. And Excluded License is on that requir3es, as a condition of use, modification or distribution, that -• The code be disclosed or distributed in source code form; or -• Others have the right to modify it. -b. Additional Licensing Requirements and/or Distribution Rights for Features made Available with the Software. -i. Windows App Requirements. If you intend to make your program available in the Windows Store, the program must comply with the Certification Requirements as defined and described in the App Developer Agreement, currently available at: https://msdn.microsoft.com/en-us/library/windows/apps/hh694058.aspx. -ii. Bing Maps. The software may include features that retrieve content such as maps, images and other data through the Bing Maps (or successor branded) application programming interface (the “Bing Maps API”) to create reports displaying data on top of maps, aerial and hybrid imagery. If these features are included, you may use these features to create and view dynamic or static documents only in conjunction with and through methods and means of access integrated in the software. You may not otherwise copy, store, archive, or create a database of the entity information including business names, addresses and geocodes available through the Bing Maps API. You may not use the Bing Maps API to provide sensor based guidance/routing, nor use any Road Traffic Data or Bird’s Eye Imager (or associated metadata) even if available through the Bing Maps API for any purpose. Your use of the Bing Maps API and associated content is also subject to the additional terms and conditions at http://go.microsoft.com/fwlink/?LinkId=21969. -iii. Additional Mapping APIs. The software may include application programming interfaces that provide maps and other related mapping features and services that are not provided by Bing (the “Additional Mapping APIs”). These Additional Mapping APIs are subject to additional terms and conditions and may require payment of fees to Microsoft and/or third party providers based on the use or volume of use of such Additional Mapping APIs. These terms and conditions will be provided when you obtain any necessary license keys to use such Additional Mapping APIs or when you review or receive documentation related to the use of such Additional Mapping APIs. -iv. Push Notifications. The Microsoft Push Notification Service may not be used to send notifications that are mission critical or otherwise could affect matters of life or death, including without limitation critical notifications related to a medical device or condition. MICROSOFT EXPRESSLY DISCLAIMS ANY WARRANTIES THAT THE USE OF THE MICROSOFT PUSH NOTIFICATION SERVICE OR DELIVERY OF MICROSOFT PUSH NOTIFICATION SERVICE NOTIFICATIONS WILL BE UNINTERRUPTED, ERROR FREE, OR OTHERWISE GUARANTEED TO OCCUR ON A REAL-TIME BASIS. -v. Speech namespace API. Using speech recognition functionality via the Speech namespace APIs in a program requires the support of a speech recognition service. The service may require network connectivity at the time of recognition (e.g., when using a predefined grammar). In addition, the service may also collect speech-related data in order to provide and improve the service. The speech-related data may include, for example, information related to grammar size and string phrases in a grammar. - Also, in order for a user to use speech recognition on the phone they must first accept certain terms of use. The terms of use notify the user that data related to their use of the speech recognition service will be collected and used to provide and improve the service. If a user does not accept the terms of use and speech recognition is attempted by the application, the operation will not work and an error will be returned to the application. -vi. API Use. We may monitor and collect data related to a program’s use of APIs in order to provide, improve and personalize Microsoft products and services.  End user information collected by Microsoft‘s monitoring and data collection related to your program’s use of APIs is subject to the Microsoft Consumer Privacy Statement. -vii. Location Framework. The software may contain a location framework component that enables support of location services in programs. In addition to the other limitations in this agreement, you must comply with all applicable local laws and regulations when using the location framework component or the rest of the software. -viii. Device ID Access. The software may contain a component that enables programs to access the device ID of the device that is running the program. In addition to the other limitations in this agreement, you must comply with all applicable local laws and regulations when using the device ID access component or the rest of the software. -ix. PlayReady Support. The software may include the Windows Emulator, which contains Microsoft’s PlayReady content access technology. Content owners use Microsoft PlayReady content access technology to protect their intellectual property, including copyrighted content. This software uses PlayReady technology to access PlayReady-protected content and/or WMDRM-protected content. Microsoft may decide to revoke the software’s ability to consume PlayReady-protected content for reasons including but not limited to (i) if a breach or potential breach of PlayReady technology occurs, (ii) proactive robustness enhancement, and (iii) if Content owners require the revocation because the software fails to properly enforce restrictions on content usage. Revocation should not affect unprotected content or content protected by other content access technologies. Content owners may require you to upgrade PlayReady to access their content. If you decline an upgrade, you will not be able to access content that requires the upgrade and may not be able to install other operating system updates or upgrades. -x. Package Managers. The software may include package managers, like NuGet, that give you the option to download other Microsoft and third party software packages to use with your application. Those packages are under their own licenses, and not this agreement. Microsoft does not distribute, license or provide any warranties for any of the third party packages. -xi. Font Components. While the software is running, you may use its fonts to display and print content. You may only embed fonts in content as permitted by the embedding restrictions in the fonts; and temporarily download them to a printer or other output device to help print content. -xii. Notice about the H.264/AVD Visual Standard, and the VC-1 Video Standard. This software may include H.264/MPEG-4 AVC and/or VD-1 decoding technology. MPEG LA, L.L.C. requires this notice: -THIS PRODUCT IS LICENSED UNDER THE AVC AND THE VC-1 PATENT PORTFOLIO LICENSES FOR THE PERSONAL AND NON-COMMERCIAL USE OF A CONSUMER TO (i) ENCODE VIDEO IN COMPLIANCE WITH THE ABOVE STANDARDS (“VIDEO STANDARDS”) AND/OR (ii) DECODE AVC, AND VC-1 VIDEO THAT WAS ENCODED BY A CONSUMER ENGAGED IN A PERSONAL AND NON-COMMERCIAL ACTIVITY AND/OR WAS OBTAINED FROM A VIDEO PROVIDER LICENSED TO PROVIDE SUCH VIDEO. NONE OF THE LICENSES EXTEND TO ANY OTHER PRODUCT REGARDLESS OF WHETHER SUCH PRODUCT IS INCLUDED WITH THIS SOFTWARE IN A SINGLE ARTICLE. NO LICENSE IS GRANTED OR SHALL BE IMPLIED FOR ANY OTHER USE. ADDITIONAL INFORMATION MAY BE OBTAINED FROM MPEG LA, L.L.C. SEE WWW.MPEGLA.COM. -For clarification purposes, this notice does not limit or inhibit the use of the software for normal business uses that are personal to that business which do not include (i) redistribution of the software to third parties, or (ii) creation of content with the VIDEO STANDARDS compliant technologies for distribution to third parties. -3. INTERNET-BASED SERVICES. Microsoft provides Internet-based services with the software. It may change or cancel them at any time. -a. Consent for Internet-Based Services. The software features described below and in the privacy statement at http://go.microsoft.com/fwlink/?LinkId=521839 connect to Microsoft or service provider computer systems over the Internet. In some cases, you will not receive a separate notice when they connect. In some cases, you may switch off these features or not use them. By using these features, you consent to the transmission of this information. Microsoft does not use the information to identify or contact you. -i. Computer Information. The following features use Internet protocols, which send to the appropriate systems computer information, such as your Internet protocol address, the type of operating system, browser, and name and version of the software you are using, and the language code of the device where you installed the software. Microsoft uses this information to make the Internet-based services available to you. -• Customer Experience Improvement Program (CEIP). This software uses CEIP. CEIP automatically sends Microsoft information about your hardware and how you use the software. We do not use this information to identify or contact you. CEIP will also periodically download a small file to your computer. This file helps us collect information about problems that you have while using the software. When available, new help information about the errors might also be automatically downloaded. To learn more about CEIP and how to turn it off, see http://go.microsoft.com/fwlink/?LinkId=525878. -• Digital Certificates. The software uses digital certificates. These digital certificates confirm the identity of Internet users sending X.509 standard encryption information. They also can be used to digitally sign files and macros to verify the integrity and origin of the file contents. The software retrieves certificates and updates certificate revocation lists using the Internet, when available. -• Error Reports. This software automatically sends error reports to Microsoft. These reports include information about problems that occur in the software. Sometimes reports contain information about other programs that interact with the software. Reports might unintentionally contain personal information. For example, a report that contains a snapshot of computer memory might include your name. Part of a document you were working on could be included as well. Microsoft does not use this information to identify or contact you. To learn more about error reports, see http://oca.microsoft.com/en/dcp20.asp. -• Windows Application Certification Kit. To ensure you have the latest certification tests, when launched this software periodically checks a Windows Application Certification Kit file on download.microsft.com to see if an update is available.  If an update is found, you are prompted and provided a link to a web site where you can download the update. You may use the Windows Application Certification Kit solely to test your programs before you submit them for a potential Microsoft Windows Certification and for inclusion on the Microsoft Windows Store. The results you receive are for informational purposes only. Microsoft has no obligation to either (i) provide you with a Windows Certification for your programs and/or ii) include your program in the Microsoft Windows Store. -• Microsoft Digital Rights Management for Silverlight. -If you use Silverlight to access content that has been protected with Microsoft Digital Rights Management (DRM), in order to let you play the content, the software may automatically -• request media usage rights from a rights server on the Internet and -• download and install available DRM Updates. -For more information about this feature, including instructions for turning the Automatic Updates off, go to http://go.microsoft.com/fwlink/?LinkId=147032. -• Web Content Features. Features in the software can retrieve related content from Microsoft and provide it to you. To provide the content, these features send to Microsoft the type of operating system, name and version of the software you are using, type of browser and language code of the device where you installed the software. Examples of these features are clip art, templates, online training, online assistance, help and Appshelp. You may choose not to use these web content features. -ii. Use of Information. We may use the computer information, error reports, and CEIP information, to improve our software and services. We may also share it with others, such as hardware and software vendors. They may use the information to improve how their products run with Microsoft software. -iii. Misuse of Internet-based Services. You may not use these services in any way that could harm them or impair anyone else’s use of them. You may not use the services to try to gain unauthorized access to any service, data, account or network by any means. -4. BACKUP COPY. You may make one backup copy of the software. You may use it only to reinstall the software. -5. DOCUMENTATION. Any person that has valid access to your computer or internal network may copy and use the documentation for your internal, reference purposes. -6. SCOPE OF LICENSE. The software is licensed, not sold. This agreement only gives you some rights to use the software. Microsoft reserves all other rights. Unless applicable law gives you more rights despite this limitation, you may use the software only as expressly permitted in this agreement. In doing so, you must comply with any technical limitations in the software that only allow you to use it in certain ways. You may not -• Except for the Microsoft .NET Framework, you must obtain Microsoft's prior written approval to disclose to a third party the results of any benchmark test of the software. -• work around any technical limitations in the software; -• reverse engineer, decompile or disassemble the software, except and only to the extent that applicable law expressly permits, despite this limitation; -• make more copies of the software than specified in this agreement or allowed by applicable law, despite this limitation; -• publish the software for others to copy; -• rent, lease or lend the software; -• transfer the software or this agreement to any third party; or -• use the software for commercial software hosting services. -7. EXPORT RESTRICTIONS. The software is subject to United States export laws and regulations. You must comply with all domestic and international export laws and regulations that apply to the software. These laws include restrictions on destinations, end users and end use. For additional information, see www.microsoft.com/exporting. -8. SUPPORT SERVICES. Because this software is “as is,” we may not provide support services for it. -9. ENTIRE AGREEMENT. This agreement, and the terms for supplements, updates, Internet-based services and support services that you use, are the entire agreement for the software and support services. -10. APPLICABLE LAW. -a. United States. If you acquired the software in the United States, Washington state law governs the interpretation of this agreement and applies to claims for breach of it, regardless of conflict of laws principles. The laws of the state where you live govern all other claims, including claims under state consumer protection laws, unfair competition laws, and in tort. -b. Outside the United States. If you acquired the software in any other country, the laws of that country apply. -11. LEGAL EFFECT. This agreement describes certain legal rights. You may have other rights under the laws of your country. You may also have rights with respect to the party from whom you acquired the software. This agreement does not change your rights under the laws of your country if the laws of your country do not permit it to do so. -12. DISCLAIMER OF WARRANTY. The software is licensed “as-is.” You bear the risk of using it. Microsoft gives no express warranties, guarantees or conditions. You may have additional consumer rights or statutory guarantees under your local laws which this agreement cannot change. To the extent permitted under your local laws, Microsoft excludes the implied warranties of merchantability, fitness for a particular purpose and non-infringement. -FOR AUSTRALIA – You have statutory guarantees under the Australian Consumer Law and nothing in these terms is intended to affect those rights. -13. LIMITATION ON AND EXCLUSION OF REMEDIES AND DAMAGES. You can recover from Microsoft and its suppliers only direct damages up to U.S. $5.00. You cannot recover any other damages, including consequential, lost profits, special, indirect or incidental damages. -This limitation applies to -• anything related to the software, services, content (including code) on third party Internet sites, or third party programs; and -• claims for breach of contract, breach of warranty, guarantee or condition, strict liability, negligence, or other tort to the extent permitted by applicable law. -It also applies even if Microsoft knew or should have known about the possibility of the damages. The above limitation or exclusion may not apply to you because your country may not allow the exclusion or limitation of incidental, consequential or other damages. - -Please note: As this software is distributed in Quebec, Canada, some of the clauses in this agreement are provided below in French. -Remarque : Ce logiciel étant distribué au Québec, Canada, certaines des clauses dans ce contrat sont fournies ci-dessous en français. -EXONÉRATION DE GARANTIE. Le logiciel visé par une licence est offert « tel quel ». Toute utilisation de ce logiciel est à votre seule risque et péril. Microsoft n’accorde aucune autre garantie expresse. Vous pouvez bénéficier de droits additionnels en vertu du droit local sur la protection des consommateurs, que ce contrat ne peut modifier. La ou elles sont permises par le droit locale, les garanties implicites de qualité marchande, d’adéquation à un usage particulier et d’absence de contrefaçon sont exclues. -LIMITATION DES DOMMAGES-INTÉRÊTS ET EXCLUSION DE RESPONSABILITÉ POUR LES DOMMAGES. Vous pouvez obtenir de Microsoft et de ses fournisseurs une indemnisation en cas de dommages directs uniquement à hauteur de 5,00 $ US. Vous ne pouvez prétendre à aucune indemnisation pour les autres dommages, y compris les dommages spéciaux, indirects ou accessoires et pertes de bénéfices. -Cette limitation concerne : -• tout ce qui est relié au logiciel, aux services ou au contenu (y compris le code) figurant sur des sites Internet tiers ou dans des programmes tiers ; et -• les réclamations au titre de violation de contrat ou de garantie, ou au titre de responsabilité stricte, de négligence ou d’une autre faute dans la limite autorisée par la loi en vigueur. -Elle s’applique également, même si Microsoft connaissait ou devrait connaître l’éventualité d’un tel dommage. Si votre pays n’autorise pas l’exclusion ou la limitation de responsabilité pour les dommages indirects, accessoires ou de quelque nature que ce soit, il se peut que la limitation ou l’exclusion ci-dessus ne s’appliquera pas à votre égard. -EFFET JURIDIQUE. Le présent contrat décrit certains droits juridiques. Vous pourriez avoir d’autres droits prévus par les lois de votre pays. Le présent contrat ne modifie pas les droits que vous confèrent les lois de votre pays si celles-ci ne le permettent pas. -*************** -EULAID:WIN10SDK.RTM.MAY 26_en-US - - -************************************************************************* - - diff --git a/Assets/license_3rdpartynotice.txt.meta b/Assets/license_3rdpartynotice.txt.meta deleted file mode 100755 index 61eecac..0000000 --- a/Assets/license_3rdpartynotice.txt.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: e72eeac74ff8fb844b551125a82b2593 -timeCreated: 1486470706 -licenseType: Pro -TextScriptImporter: - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/link.xml b/Assets/link.xml deleted file mode 100755 index 2fc90e8..0000000 --- a/Assets/link.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - - - - - - - - diff --git a/Assets/readme_SDK.txt b/Assets/readme_SDK.txt deleted file mode 100755 index d528bc9..0000000 --- a/Assets/readme_SDK.txt +++ /dev/null @@ -1,12 +0,0 @@ -Vuforia Augmented Reality SDK Release Package -============================================== -Vuforia support Unity 5.3.6 or newer -To learn more about Vuforia, go to https://developer.vuforia.com/library/getting-started -To view the SDK license agreement, go to https://developer.vuforia.com/legal/vuforia-developer-agreement -To view the release notes, go to https://developer.vuforia.com/library/release-notes - -/*============================================================================ - Copyright (c) 2010-2015 PTC Inc. - All Rights Reserved. - Confidential and Proprietary - PTC Inc. - ============================================================================*/ diff --git a/Assets/readme_SDK.txt.meta b/Assets/readme_SDK.txt.meta deleted file mode 100755 index 830b45b..0000000 --- a/Assets/readme_SDK.txt.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: b82b905470d354e4b897d717e72aabf2 -timeCreated: 1486470706 -licenseType: Pro -TextScriptImporter: - userData: - assetBundleName: - assetBundleVariant: diff --git a/ProjectSettings/EditorBuildSettings.asset b/ProjectSettings/EditorBuildSettings.asset index 9067199..bfa1deb 100644 Binary files a/ProjectSettings/EditorBuildSettings.asset and b/ProjectSettings/EditorBuildSettings.asset differ diff --git a/QCAR/somedata16 b/QCAR/somedata16 index fc16bb6..e416178 100644 --- a/QCAR/somedata16 +++ b/QCAR/somedata16 @@ -1 +1 @@ -AAAAGRhFRmoOIn2/nCy5Qb/I7KT6wh87HAs2KKyHOVIUHkOwFiI+WWXO2ZAS4JEZ3wsA5aeHggzqqdj2hmaH4XGZFTBv3qgWo7q5DF4IJ1D6xjLS56cLxK4LYlLjEabPp64cqznOuZpmmeW9aunUYIHlQbjdwNDuCSmB3ZcDFmktyLFfd7JLSVF1m9AX/URnNSMiu2yS5Vv9o0Y8IGOq7EoxCkRRMVBeXLQsphBT2EqxBndnapsKT/moaueDBfpEFXfMkadXQZ9tyD5DKBVx47NWbg+YZY8aXsFsxDYBALdRXKXXmtQlqRR97jplVzHFR795E4KMWMV8m5bot+0wYKXNj0A= \ No newline at end of file +AAAAGRBycUT5oDobAZbBAdY4ZjrjNdjef3+Vo06FHBhMOU73Tlfh4c3EwHi++dQPAlN1nbPkFAxNYeaVLlFHhNaMHqJvAe26P4RnpOggo6P+5/b2Gog1fFuPvDgvpzN3lIf3FbDH+BivP7lQZ3SR0XQ6TXrmnCjFjnlSn7yAdhfiHQjWQjbeykwBhFR5oB/BTCUxurodnDLBjW+PhkhZcDPCF9o3V1XC6oTlOh31gG2tg4jFCk4NZfJNx4FjMh2LY5Woc/e2+6LocAF16bL1pMMFRwW6rYXdQuAo9gM4pJ5In0He1mMe0O2btpVDxRBJuFGuiwDELP4tiL7qHSGwEXxXX9g= \ No newline at end of file