first commit
This commit is contained in:
7
Assets/Photon/PhotonUnityNetworking/Code.meta
Normal file
7
Assets/Photon/PhotonUnityNetworking/Code.meta
Normal file
@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9a312e4dbb5268d4e859200f68478e0c
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
74
Assets/Photon/PhotonUnityNetworking/Code/CustomTypes.cs
Normal file
74
Assets/Photon/PhotonUnityNetworking/Code/CustomTypes.cs
Normal file
@ -0,0 +1,74 @@
|
||||
// ----------------------------------------------------------------------------
|
||||
// <copyright file="CustomTypes.cs" company="Exit Games GmbH">
|
||||
// PhotonNetwork Framework for Unity - Copyright (C) 2018 Exit Games GmbH
|
||||
// </copyright>
|
||||
// <summary>
|
||||
// Sets up support for Unity-specific types. Can be a blueprint how to register your own Custom Types for sending.
|
||||
// </summary>
|
||||
// <author>developer@exitgames.com</author>
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
|
||||
namespace Photon.Pun
|
||||
{
|
||||
using UnityEngine;
|
||||
using Photon.Realtime;
|
||||
using ExitGames.Client.Photon;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Internally used class, containing de/serialization method for PUN specific classes.
|
||||
/// </summary>
|
||||
internal static class CustomTypes
|
||||
{
|
||||
/// <summary>Register de/serializer methods for PUN specific types. Makes the type usable in RaiseEvent, RPC and sync updates of PhotonViews.</summary>
|
||||
internal static void Register()
|
||||
{
|
||||
PhotonPeer.RegisterType(typeof(Player), (byte) 'P', SerializePhotonPlayer, DeserializePhotonPlayer);
|
||||
}
|
||||
|
||||
|
||||
#region Custom De/Serializer Methods
|
||||
|
||||
public static readonly byte[] memPlayer = new byte[4];
|
||||
|
||||
private static short SerializePhotonPlayer(StreamBuffer outStream, object customobject)
|
||||
{
|
||||
int ID = ((Player) customobject).ActorNumber;
|
||||
|
||||
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)
|
||||
{
|
||||
if (length != 4)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
int ID;
|
||||
lock (memPlayer)
|
||||
{
|
||||
inStream.Read(memPlayer, 0, length);
|
||||
int off = 0;
|
||||
Protocol.Deserialize(out ID, memPlayer, ref off);
|
||||
}
|
||||
|
||||
if (PhotonNetwork.CurrentRoom != null)
|
||||
{
|
||||
Player player = PhotonNetwork.CurrentRoom.GetPlayer(ID);
|
||||
return player;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
12
Assets/Photon/PhotonUnityNetworking/Code/CustomTypes.cs.meta
Normal file
12
Assets/Photon/PhotonUnityNetworking/Code/CustomTypes.cs.meta
Normal file
@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ab517bd36a2b2504b83979fcad45d4a2
|
||||
labels:
|
||||
- ExitGames
|
||||
- PUN
|
||||
- Photon
|
||||
- Networking
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
7
Assets/Photon/PhotonUnityNetworking/Code/Editor.meta
Normal file
7
Assets/Photon/PhotonUnityNetworking/Code/Editor.meta
Normal file
@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e14293cef01c2f742a605d63babcb803
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
BIN
Assets/Photon/PhotonUnityNetworking/Code/Editor/CopyIcon.png
Normal file
BIN
Assets/Photon/PhotonUnityNetworking/Code/Editor/CopyIcon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 131 B |
@ -0,0 +1,116 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d1228d93299ce47a8a5ac1a33513aeaf
|
||||
TextureImporter:
|
||||
fileIDToRecycleName: {}
|
||||
externalObjects: {}
|
||||
serializedVersion: 4
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
sRGBTexture: 0
|
||||
linearTexture: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapsPreserveCoverage: 0
|
||||
alphaTestReferenceValue: 0.5
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: 0.25
|
||||
normalMapFilter: 0
|
||||
isReadable: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 6
|
||||
cubemapConvolution: 0
|
||||
seamlessCubemap: 0
|
||||
textureFormat: 1
|
||||
maxTextureSize: 2048
|
||||
textureSettings:
|
||||
serializedVersion: 2
|
||||
filterMode: -1
|
||||
aniso: 1
|
||||
mipBias: -1
|
||||
wrapU: 1
|
||||
wrapV: 1
|
||||
wrapW: -1
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 0
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spritePixelsToUnits: 100
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spriteGenerateFallbackPhysicsShape: 1
|
||||
alphaUsage: 1
|
||||
alphaIsTransparency: 1
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 2
|
||||
textureShape: 1
|
||||
maxTextureSizeSet: 0
|
||||
compressionQualitySet: 0
|
||||
textureFormatSet: 0
|
||||
platformSettings:
|
||||
- buildTarget: DefaultTexturePlatform
|
||||
maxTextureSize: 32
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
- buildTarget: Standalone
|
||||
maxTextureSize: 32
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
- buildTarget: iPhone
|
||||
maxTextureSize: 32
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
- buildTarget: Android
|
||||
maxTextureSize: 32
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
- buildTarget: WebGL
|
||||
maxTextureSize: 32
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
spriteSheet:
|
||||
serializedVersion: 2
|
||||
sprites: []
|
||||
outline: []
|
||||
physicsShape: []
|
||||
spritePackingTag:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
BIN
Assets/Photon/PhotonUnityNetworking/Code/Editor/CopyIconPro.png
Normal file
BIN
Assets/Photon/PhotonUnityNetworking/Code/Editor/CopyIconPro.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.3 KiB |
@ -0,0 +1,116 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 81b8e0c5ffa3345b7aa3af3a2c0257ce
|
||||
TextureImporter:
|
||||
fileIDToRecycleName: {}
|
||||
externalObjects: {}
|
||||
serializedVersion: 4
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
sRGBTexture: 0
|
||||
linearTexture: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapsPreserveCoverage: 0
|
||||
alphaTestReferenceValue: 0.5
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: 0.25
|
||||
normalMapFilter: 0
|
||||
isReadable: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 6
|
||||
cubemapConvolution: 0
|
||||
seamlessCubemap: 0
|
||||
textureFormat: 1
|
||||
maxTextureSize: 2048
|
||||
textureSettings:
|
||||
serializedVersion: 2
|
||||
filterMode: -1
|
||||
aniso: 1
|
||||
mipBias: -1
|
||||
wrapU: 1
|
||||
wrapV: 1
|
||||
wrapW: -1
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 0
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spritePixelsToUnits: 100
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spriteGenerateFallbackPhysicsShape: 1
|
||||
alphaUsage: 1
|
||||
alphaIsTransparency: 1
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 2
|
||||
textureShape: 1
|
||||
maxTextureSizeSet: 0
|
||||
compressionQualitySet: 0
|
||||
textureFormatSet: 0
|
||||
platformSettings:
|
||||
- buildTarget: DefaultTexturePlatform
|
||||
maxTextureSize: 32
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
- buildTarget: Standalone
|
||||
maxTextureSize: 32
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
- buildTarget: iPhone
|
||||
maxTextureSize: 32
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
- buildTarget: Android
|
||||
maxTextureSize: 32
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
- buildTarget: WebGL
|
||||
maxTextureSize: 32
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
spriteSheet:
|
||||
serializedVersion: 2
|
||||
sprites: []
|
||||
outline: []
|
||||
physicsShape: []
|
||||
spritePackingTag:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
855
Assets/Photon/PhotonUnityNetworking/Code/Editor/PhotonEditor.cs
Normal file
855
Assets/Photon/PhotonUnityNetworking/Code/Editor/PhotonEditor.cs
Normal file
@ -0,0 +1,855 @@
|
||||
// ----------------------------------------------------------------------------
|
||||
// <copyright file="PhotonEditor.cs" company="Exit Games GmbH">
|
||||
// PhotonNetwork Framework for Unity - Copyright (C) 2018 Exit Games GmbH
|
||||
// </copyright>
|
||||
// <summary>
|
||||
// MenuItems and in-Editor scripts for PhotonNetwork.
|
||||
// </summary>
|
||||
// <author>developer@exitgames.com</author>
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
|
||||
using UnityEditor;
|
||||
using UnityEditor.Callbacks;
|
||||
using UnityEditor.Compilation;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Photon.Pun
|
||||
{
|
||||
using Realtime;
|
||||
|
||||
|
||||
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<b>-</b> To use an existing Photon Cloud App, enter your AppId.\n<b>-</b> To register an account or access an existing one, enter the account's mail address.\n<b>-</b> 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 = "<b>Done!</b>\nAll connection settings can be edited in the <b>PhotonServerSettings</b> now.\nHave a look.";
|
||||
public string CloseWindowButton = "Close";
|
||||
public string SkipButton = "Skip";
|
||||
public string SetupButton = "Setup Project";
|
||||
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 = "Disconnecting PUN due to recompile. Exit PlayMode.";
|
||||
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 = "Doc Pages / 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 = "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, which breaks compatibility with older builds. You should update the \"App Version\" in the PhotonServerSettings to avoid issues.";
|
||||
public string WizardMainWindowInfo = "This window should help you find important settings for PUN, as well as documentation.";
|
||||
}
|
||||
|
||||
|
||||
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();
|
||||
|
||||
/// <summary>
|
||||
/// third parties custom token
|
||||
/// </summary>
|
||||
public static string CustomToken = null;
|
||||
|
||||
/// <summary>
|
||||
/// third parties custom context
|
||||
/// </summary>
|
||||
public static string CustomContext = null;
|
||||
|
||||
protected static string DocumentationLocation = "Assets/Photon/PhotonNetworking-Documentation.pdf";
|
||||
|
||||
protected static string UrlFreeLicense = "https://dashboard.photonengine.com/en-US/SelfHosted";
|
||||
|
||||
public const string UrlDevNet = "https://doc.photonengine.com/en-us/pun/v2";
|
||||
|
||||
protected static string UrlForum = "https://forum.photonengine.com";
|
||||
|
||||
protected static string UrlCompare = "https://doc.photonengine.com/en-us/realtime/current/getting-started/onpremise-or-saas";
|
||||
|
||||
protected static string UrlHowToSetup = "https://doc.photonengine.com/en-us/onpremise/current/getting-started/photon-server-in-5min";
|
||||
|
||||
protected static string UrlAppIDExplained = "https://doc.photonengine.com/en-us/realtime/current/getting-started/obtain-your-app-id";
|
||||
|
||||
public const string UrlCloudDashboard = "https://dashboard.photonengine.com/en-US/account/signin?email=";
|
||||
|
||||
public const string UrlPunSettings = "https://doc.photonengine.com/en-us/pun/v2/getting-started/initial-setup"; // the SeverSettings class has this url directly in it's HelpURL attribute.
|
||||
|
||||
private enum PhotonSetupStates
|
||||
{
|
||||
MainUi,
|
||||
|
||||
RegisterForPhotonCloud,
|
||||
|
||||
EmailAlreadyRegistered,
|
||||
|
||||
GoEditPhotonServerSettings,
|
||||
|
||||
EmailRegistrationPending
|
||||
}
|
||||
|
||||
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 postInspectorUpdate;
|
||||
|
||||
|
||||
|
||||
[MenuItem("Window/Photon Unity Networking/PUN Wizard &p", false, 0)]
|
||||
protected static void MenuItemOpenWizard()
|
||||
{
|
||||
PhotonEditor win = GetWindow<PhotonEditor>(false, CurrentLang.WindowTitle, true);
|
||||
if (win == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
win.photonSetupState = PhotonSetupStates.MainUi;
|
||||
win.isSetupWizard = false;
|
||||
}
|
||||
|
||||
[MenuItem("Window/Photon Unity Networking/Highlight Server Settings %#&p", false, 1)]
|
||||
protected static void MenuItemHighlightSettings()
|
||||
{
|
||||
HighlightSettings();
|
||||
}
|
||||
|
||||
|
||||
|
||||
[UnityEditor.InitializeOnLoadMethod]
|
||||
public static void InitializeOnLoadMethod()
|
||||
{
|
||||
//Debug.Log("InitializeOnLoadMethod()");
|
||||
EditorApplication.delayCall += OnDelayCall;
|
||||
}
|
||||
|
||||
|
||||
// used to register for various events (post-load)
|
||||
private static void OnDelayCall()
|
||||
{
|
||||
//Debug.Log("OnDelayCall()");
|
||||
|
||||
postInspectorUpdate = true;
|
||||
|
||||
EditorApplication.playModeStateChanged -= PlayModeStateChanged;
|
||||
EditorApplication.playModeStateChanged += PlayModeStateChanged;
|
||||
|
||||
#if UNITY_2021_1_OR_NEWER
|
||||
CompilationPipeline.compilationStarted -= OnCompileStarted21;
|
||||
CompilationPipeline.compilationStarted += OnCompileStarted21;
|
||||
#else
|
||||
CompilationPipeline.assemblyCompilationStarted -= OnCompileStarted;
|
||||
CompilationPipeline.assemblyCompilationStarted += OnCompileStarted;
|
||||
#endif
|
||||
|
||||
#if (UNITY_2018 || UNITY_2018_1_OR_NEWER)
|
||||
EditorApplication.projectChanged -= OnProjectChanged;
|
||||
EditorApplication.projectChanged += OnProjectChanged;
|
||||
#else
|
||||
EditorApplication.projectWindowChanged -= OnProjectChanged;
|
||||
EditorApplication.projectWindowChanged += OnProjectChanged;
|
||||
#endif
|
||||
|
||||
|
||||
if (!EditorApplication.isPlaying && !EditorApplication.isPlayingOrWillChangePlaymode)
|
||||
{
|
||||
OnProjectChanged(); // call this initially from here, as the project change events happened earlier (on start of the Editor)
|
||||
PhotonEditor.UpdateRpcList();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// 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 OnProjectChanged()
|
||||
{
|
||||
PhotonEditorUtils.ProjectChangedWasCalled = true;
|
||||
|
||||
|
||||
// Prevent issues with Unity Cloud Builds where ServerSettings are not found.
|
||||
// Also, within the context of a Unity Cloud Build, ServerSettings is already present anyway.
|
||||
#if UNITY_CLOUD_BUILD
|
||||
return;
|
||||
#endif
|
||||
|
||||
if (PhotonNetwork.PhotonServerSettings == null || PhotonNetwork.PhotonServerSettings.AppSettings == null || string.IsNullOrEmpty(PhotonNetwork.PhotonServerSettings.AppSettings.AppIdRealtime))
|
||||
{
|
||||
PhotonNetwork.LoadOrCreateSettings(true);
|
||||
}
|
||||
|
||||
if (PhotonNetwork.PhotonServerSettings == null)
|
||||
{
|
||||
// the PhotonServerSettings are loaded or created. If both fails, the Editor should probably not run (anymore).
|
||||
return;
|
||||
}
|
||||
|
||||
PunSceneSettings.SanitizeSceneSettings();
|
||||
|
||||
|
||||
// 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)
|
||||
{
|
||||
ShowRegistrationWizard();
|
||||
PhotonNetwork.PhotonServerSettings.DisableAutoOpenWizard = true;
|
||||
PhotonEditor.SaveSettings();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#if UNITY_2021_1_OR_NEWER
|
||||
private static void OnCompileStarted21(object obj)
|
||||
{
|
||||
OnCompileStarted(obj as string);
|
||||
}
|
||||
#endif
|
||||
|
||||
private static void OnCompileStarted(string obj)
|
||||
{
|
||||
if (PhotonNetwork.IsConnected)
|
||||
{
|
||||
// log warning, unless there was one recently
|
||||
if (EditorApplication.timeSinceStartup - lastWarning > 3)
|
||||
{
|
||||
Debug.LogWarning(CurrentLang.WarningPhotonDisconnect);
|
||||
lastWarning = EditorApplication.timeSinceStartup;
|
||||
}
|
||||
|
||||
PhotonNetwork.Disconnect();
|
||||
PhotonNetwork.NetworkingClient.LoadBalancingPeer.DispatchIncomingCommands();
|
||||
#if UNITY_2019_4_OR_NEWER && UNITY_EDITOR
|
||||
EditorApplication.ExitPlaymode();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[DidReloadScripts]
|
||||
private static void OnDidReloadScripts()
|
||||
{
|
||||
//Debug.Log("OnDidReloadScripts() postInspectorUpdate: "+postInspectorUpdate + " isPlayingOrWillChangePlaymode: "+EditorApplication.isPlayingOrWillChangePlaymode);
|
||||
if (postInspectorUpdate && !EditorApplication.isPlayingOrWillChangePlaymode)
|
||||
{
|
||||
PhotonEditor.UpdateRpcList(); // could be called when compilation finished (instead of when reload / compile starts)
|
||||
}
|
||||
}
|
||||
|
||||
private static void PlayModeStateChanged(PlayModeStateChange state)
|
||||
{
|
||||
//Debug.Log("PlayModeStateChanged");
|
||||
if (EditorApplication.isPlaying || !EditorApplication.isPlayingOrWillChangePlaymode)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(PhotonNetwork.PhotonServerSettings.AppSettings.AppIdRealtime) && !PhotonNetwork.PhotonServerSettings.AppSettings.IsMasterServerAddress)
|
||||
{
|
||||
EditorUtility.DisplayDialog(CurrentLang.SetupWizardWarningTitle, CurrentLang.SetupWizardWarningMessage, CurrentLang.OkButton);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#region GUI and Wizard
|
||||
|
||||
|
||||
// setup per window
|
||||
public PhotonEditor()
|
||||
{
|
||||
this.minSize = this.preferredSize;
|
||||
}
|
||||
|
||||
protected void Awake()
|
||||
{
|
||||
// check if some appid is set. if so, we can avoid registration calls.
|
||||
if (PhotonNetwork.PhotonServerSettings != null && PhotonNetwork.PhotonServerSettings.AppSettings != null && !string.IsNullOrEmpty(PhotonNetwork.PhotonServerSettings.AppSettings.AppIdRealtime))
|
||||
{
|
||||
this.mailOrAppId = PhotonNetwork.PhotonServerSettings.AppSettings.AppIdRealtime;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Creates an Editor window, showing the cloud-registration wizard for Photon (entry point to setup PUN).</summary>
|
||||
protected static void ShowRegistrationWizard()
|
||||
{
|
||||
PhotonEditor win = GetWindow(WindowType, false, CurrentLang.WindowTitle, true) as PhotonEditor;
|
||||
if (win == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
win.photonSetupState = PhotonSetupStates.RegisterForPhotonCloud;
|
||||
win.isSetupWizard = true;
|
||||
}
|
||||
|
||||
// Window Update() callback. On-demand, when Window is open
|
||||
protected void Update()
|
||||
{
|
||||
if (this.close)
|
||||
{
|
||||
this.Close();
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void OnGUI()
|
||||
{
|
||||
if (BackgroundImage == null)
|
||||
{
|
||||
string[] paths = AssetDatabase.FindAssets("PunGradient t:Texture2D");
|
||||
if (paths != null && paths.Length > 0)
|
||||
{
|
||||
BackgroundImage = AssetDatabase.LoadAssetAtPath<Texture2D>(AssetDatabase.GUIDToAssetPath(paths[0]));
|
||||
}
|
||||
}
|
||||
|
||||
PhotonSetupStates oldGuiState = this.photonSetupState; // used to fix an annoying Editor input field issue: wont refresh until focus is changed.
|
||||
|
||||
GUI.SetNextControlName(string.Empty);
|
||||
this.scrollPos = GUILayout.BeginScrollView(this.scrollPos);
|
||||
|
||||
|
||||
if (this.photonSetupState == PhotonSetupStates.MainUi)
|
||||
{
|
||||
this.UiMainWizard();
|
||||
}
|
||||
else
|
||||
{
|
||||
EditorGUI.BeginDisabledGroup(this.photonSetupState == PhotonSetupStates.EmailRegistrationPending);
|
||||
this.UiSetupApp();
|
||||
EditorGUI.EndDisabledGroup();
|
||||
}
|
||||
|
||||
|
||||
GUILayout.EndScrollView();
|
||||
|
||||
if (oldGuiState != this.photonSetupState)
|
||||
{
|
||||
GUI.FocusControl(string.Empty);
|
||||
}
|
||||
}
|
||||
|
||||
private string emailSentToAccount;
|
||||
private bool emailSentToAccountIsRegistered;
|
||||
|
||||
|
||||
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
|
||||
this.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.minimumInput = false;
|
||||
this.useMail = false;
|
||||
this.useAppId = false;
|
||||
this.mailOrAppId = EditorGUILayout.TextField(this.mailOrAppId);
|
||||
if (!string.IsNullOrEmpty(this.mailOrAppId))
|
||||
{
|
||||
this.mailOrAppId = this.mailOrAppId.Trim(); // note: we trim all input
|
||||
if (AccountService.IsValidEmail(this.mailOrAppId))
|
||||
{
|
||||
// input should be a mail address
|
||||
this.useMail = true;
|
||||
|
||||
// check if the current input equals earlier input, which is known to be registered already
|
||||
this.minimumInput = !this.mailOrAppId.Equals(this.emailSentToAccount) || !this.emailSentToAccountIsRegistered;
|
||||
}
|
||||
else if (ServerSettings.IsAppId(this.mailOrAppId))
|
||||
{
|
||||
// this should be an appId
|
||||
this.minimumInput = true;
|
||||
this.useAppId = true;
|
||||
}
|
||||
}
|
||||
|
||||
// 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)
|
||||
{
|
||||
this.RegisterWithEmail(this.mailOrAppId); // sets state
|
||||
}
|
||||
else 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(string.Concat(UrlCloudDashboard, Uri.EscapeUriString(this.mailOrAppId)));
|
||||
this.mailOrAppId = string.Empty;
|
||||
}
|
||||
GUILayout.FlexibleSpace();
|
||||
GUILayout.EndHorizontal();
|
||||
}
|
||||
|
||||
|
||||
else 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 = EditorGUIUtility.isProSkin ? new GUIStyle(GUI.skin.GetStyle("Label")) : new GUIStyle(GUI.skin.GetStyle("WhiteLabel"));
|
||||
bgStyle.padding = new RectOffset(10, 10, 10, 10);
|
||||
bgStyle.fontSize = 22;
|
||||
bgStyle.fontStyle = FontStyle.Bold;
|
||||
if (bgIcon != null)
|
||||
{
|
||||
bgStyle.normal.background = bgIcon;
|
||||
}
|
||||
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
GUILayout.FlexibleSpace();
|
||||
EditorGUILayout.EndHorizontal();
|
||||
Rect scale = GUILayoutUtility.GetLastRect();
|
||||
scale.height = 44;
|
||||
|
||||
GUI.Label(scale, title, bgStyle);
|
||||
GUILayout.Space(scale.height + 5);
|
||||
}
|
||||
|
||||
protected virtual void UiMainWizard()
|
||||
{
|
||||
GUILayout.Space(15);
|
||||
|
||||
// title
|
||||
this.UiTitleBox(CurrentLang.PUNWizardLabel, BackgroundImage);
|
||||
|
||||
EditorGUILayout.BeginVertical(new GUIStyle() { padding = new RectOffset(10, 10, 10, 10) });
|
||||
|
||||
// wizard info text
|
||||
GUILayout.Label(CurrentLang.WizardMainWindowInfo, new GUIStyle("Label") { wordWrap = true });
|
||||
GUILayout.Space(15);
|
||||
|
||||
|
||||
// settings button
|
||||
GUILayout.Label(CurrentLang.SettingsButton, EditorStyles.boldLabel);
|
||||
|
||||
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.Space(15);
|
||||
|
||||
|
||||
// documentation
|
||||
GUILayout.Label(CurrentLang.DocumentationLabel, EditorStyles.boldLabel);
|
||||
|
||||
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();
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
private AccountService serviceClient;
|
||||
protected virtual void RegisterWithEmail(string email)
|
||||
{
|
||||
List<ServiceTypes> types = new List<ServiceTypes>();
|
||||
types.Add(ServiceTypes.Pun);
|
||||
if (PhotonEditorUtils.HasChat)
|
||||
{
|
||||
types.Add(ServiceTypes.Chat);
|
||||
}
|
||||
if (PhotonEditorUtils.HasVoice)
|
||||
{
|
||||
types.Add(ServiceTypes.Voice);
|
||||
}
|
||||
|
||||
|
||||
if (this.serviceClient == null)
|
||||
{
|
||||
this.serviceClient = new AccountService();
|
||||
this.serviceClient.CustomToken = CustomToken;
|
||||
this.serviceClient.CustomContext = CustomContext;
|
||||
}
|
||||
else
|
||||
{
|
||||
// while RegisterByEmail will check RequestPendingResult below, it would also display an error message. no needed in this case
|
||||
if (this.serviceClient.RequestPendingResult)
|
||||
{
|
||||
Debug.LogWarning("Registration request is pending a response. Please wait.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
this.emailSentToAccount = email;
|
||||
this.emailSentToAccountIsRegistered = false;
|
||||
|
||||
if (this.serviceClient.RegisterByEmail(email, types, RegisterWithEmailSuccessCallback, RegisterWithEmailErrorCallback, "PUN"+PhotonNetwork.PunVersion))
|
||||
{
|
||||
this.photonSetupState = PhotonSetupStates.EmailRegistrationPending;
|
||||
EditorUtility.DisplayProgressBar(CurrentLang.ConnectionTitle, CurrentLang.ConnectionInfo, 0.5f);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.DisplayErrorMessage("Email registration request could not be sent. Retry again or check error logs and contact support.");
|
||||
}
|
||||
}
|
||||
|
||||
private void RegisterWithEmailSuccessCallback(AccountServiceResponse res)
|
||||
{
|
||||
EditorUtility.ClearProgressBar();
|
||||
this.emailSentToAccountIsRegistered = true; // email is either registered now, or was already
|
||||
|
||||
if (res.ReturnCode == AccountServiceReturnCodes.Success)
|
||||
{
|
||||
string key = ((int) ServiceTypes.Pun).ToString();
|
||||
string appId;
|
||||
if (res.ApplicationIds.TryGetValue(key, out appId))
|
||||
{
|
||||
this.mailOrAppId = appId;
|
||||
PhotonNetwork.PhotonServerSettings.UseCloud(this.mailOrAppId, null);
|
||||
key = ((int) ServiceTypes.Chat).ToString();
|
||||
if (res.ApplicationIds.TryGetValue(key, out appId))
|
||||
{
|
||||
PhotonNetwork.PhotonServerSettings.AppSettings.AppIdChat = appId;
|
||||
}
|
||||
else if (PhotonEditorUtils.HasChat)
|
||||
{
|
||||
Debug.LogWarning("Registration successful but no Chat AppId returned");
|
||||
}
|
||||
key = ((int) ServiceTypes.Voice).ToString();
|
||||
if (res.ApplicationIds.TryGetValue(key, out appId))
|
||||
{
|
||||
PhotonNetwork.PhotonServerSettings.AppSettings.AppIdVoice = appId;
|
||||
}
|
||||
else if (PhotonEditorUtils.HasVoice)
|
||||
{
|
||||
Debug.LogWarning("Registration successful but no Voice AppId returned");
|
||||
}
|
||||
PhotonEditor.SaveSettings();
|
||||
this.photonSetupState = PhotonSetupStates.GoEditPhotonServerSettings;
|
||||
}
|
||||
else
|
||||
{
|
||||
DisplayErrorMessage("Registration successful but no PUN AppId returned");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
PhotonEditor.SaveSettings();
|
||||
|
||||
if (res.ReturnCode == AccountServiceReturnCodes.EmailAlreadyRegistered)
|
||||
{
|
||||
this.photonSetupState = PhotonSetupStates.EmailAlreadyRegistered;
|
||||
}
|
||||
else
|
||||
{
|
||||
DisplayErrorMessage(res.Message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void RegisterWithEmailErrorCallback(string error)
|
||||
{
|
||||
EditorUtility.ClearProgressBar();
|
||||
DisplayErrorMessage(error);
|
||||
}
|
||||
|
||||
private void DisplayErrorMessage(string error)
|
||||
{
|
||||
EditorUtility.DisplayDialog(CurrentLang.ErrorTextTitle, error, CurrentLang.OkButton);
|
||||
this.photonSetupState = PhotonSetupStates.RegisterForPhotonCloud;
|
||||
}
|
||||
|
||||
// Pings PhotonServerSettings and makes it selected (show in Inspector)
|
||||
private static void HighlightSettings()
|
||||
{
|
||||
ServerSettings serverSettings = (ServerSettings)Resources.Load(PhotonNetwork.ServerSettingsFileName, typeof(ServerSettings));
|
||||
Selection.objects = new UnityEngine.Object[] { serverSettings };
|
||||
EditorGUIUtility.PingObject(serverSettings);
|
||||
}
|
||||
|
||||
// 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()
|
||||
{
|
||||
//Debug.Log("UpdateRpcList()");
|
||||
|
||||
if (PhotonNetwork.PhotonServerSettings == null)
|
||||
{
|
||||
Debug.LogWarning("UpdateRpcList() wasn not able to access the PhotonServerSettings. Not updating the RPCs.");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// check all "script assemblies" for methods with PunRPC attribute
|
||||
List<string> additionalRpcs = new List<string>(); // not yet listed rpc-method names go here
|
||||
List<string> allRpcs = new List<string>();
|
||||
|
||||
|
||||
#if UNITY_2019_2_OR_NEWER
|
||||
|
||||
// we can make use of the new TypeCache to find methods with PunRPC attribute
|
||||
var extractedMethods = TypeCache.GetMethodsWithAttribute<PunRPC>();
|
||||
foreach (var methodInfo in extractedMethods)
|
||||
{
|
||||
allRpcs.Add(methodInfo.Name);
|
||||
if (!PhotonNetwork.PhotonServerSettings.RpcList.Contains(methodInfo.Name) && !additionalRpcs.Contains(methodInfo.Name))
|
||||
{
|
||||
additionalRpcs.Add(methodInfo.Name);
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
System.Reflection.Assembly[] assemblies = System.AppDomain.CurrentDomain.GetAssemblies().Where(a => !(a.ManifestModule is System.Reflection.Emit.ModuleBuilder)).ToArray();
|
||||
|
||||
foreach (var assembly in assemblies)
|
||||
{
|
||||
if (!assembly.Location.Contains("ScriptAssemblies") || assembly.FullName.StartsWith("Assembly-CSharp-Editor"))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var types = assembly.GetTypes().Where(t => t.IsSubclassOf(typeof(MonoBehaviour)));
|
||||
var methodInfos = types.SelectMany(t => t.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance));
|
||||
var methodNames = methodInfos.Where(m => m.IsDefined(typeof(PunRPC), false)).Select(mi => mi.Name).ToArray();
|
||||
var additional = methodNames.Where(n => !PhotonNetwork.PhotonServerSettings.RpcList.Contains(n) && !additionalRpcs.Contains(n));
|
||||
|
||||
allRpcs.AddRange(methodNames);
|
||||
additionalRpcs.AddRange(additional);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
if (additionalRpcs.Count <= 0)
|
||||
{
|
||||
//Debug.Log("UpdateRPCs did not found new.");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (additionalRpcs.Count + PhotonNetwork.PhotonServerSettings.RpcList.Count >= byte.MaxValue)
|
||||
{
|
||||
if (allRpcs.Count <= byte.MaxValue)
|
||||
{
|
||||
bool clearList = EditorUtility.DisplayDialog(CurrentLang.IncorrectRPCListTitle, CurrentLang.IncorrectRPCListLabel, CurrentLang.RemoveOutdatedRPCsLabel, CurrentLang.CancelButton);
|
||||
if (clearList)
|
||||
{
|
||||
PhotonNetwork.PhotonServerSettings.RpcList.Clear();
|
||||
additionalRpcs = allRpcs.Distinct().ToList(); // we add all unique names
|
||||
}
|
||||
else
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
EditorUtility.DisplayDialog(CurrentLang.FullRPCListTitle, CurrentLang.FullRPCListLabel, CurrentLang.SkipRPCListUpdateLabel);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
additionalRpcs.Sort();
|
||||
Undo.RecordObject(PhotonNetwork.PhotonServerSettings, "RPC-list update of PUN.");
|
||||
PhotonNetwork.PhotonServerSettings.RpcList.AddRange(additionalRpcs);
|
||||
EditorUtility.SetDirty(PhotonNetwork.PhotonServerSettings);
|
||||
|
||||
//Debug.Log("Updated RPCs. Added: "+additionalRpcs.Count);
|
||||
}
|
||||
|
||||
|
||||
public static void ClearRpcList()
|
||||
{
|
||||
bool clearList = EditorUtility.DisplayDialog(CurrentLang.PUNNameReplaceTitle, CurrentLang.PUNNameReplaceLabel, CurrentLang.RPCListCleared, CurrentLang.CancelButton);
|
||||
if (clearList)
|
||||
{
|
||||
ServerSettings serverSettings = PhotonNetwork.PhotonServerSettings;
|
||||
|
||||
Undo.RecordObject(serverSettings, "RPC-list cleared for PUN.");
|
||||
serverSettings.RpcList.Clear();
|
||||
EditorUtility.SetDirty(serverSettings);
|
||||
|
||||
Debug.LogWarning(CurrentLang.ServerSettingsCleanedWarning);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: dabbbed2a74eac44dac281f20d706ba8
|
||||
labels:
|
||||
- ExitGames
|
||||
- PUN
|
||||
- Photon
|
||||
- Networking
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
363
Assets/Photon/PhotonUnityNetworking/Code/Editor/PhotonGUI.cs
Normal file
363
Assets/Photon/PhotonUnityNetworking/Code/Editor/PhotonGUI.cs
Normal file
@ -0,0 +1,363 @@
|
||||
// ----------------------------------------------------------------------------
|
||||
// <copyright file="PhotonGUI.cs" company="Exit Games GmbH">
|
||||
// PhotonNetwork Framework for Unity - Copyright (C) 2018 Exit Games GmbH
|
||||
// </copyright>
|
||||
// <summary>
|
||||
// GUI scripts for the Editor.
|
||||
// </summary>
|
||||
// <author>developer@exitgames.com</author>
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
|
||||
namespace 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
|
||||
|
||||
|
||||
internal static string GetIconPath(string iconFileName)
|
||||
{
|
||||
string _thisIconPath = PhotonNetwork.FindAssetPath ("PhotonGUI");
|
||||
|
||||
if (string.IsNullOrEmpty(_thisIconPath))
|
||||
{
|
||||
_thisIconPath = "Assets/Photon/PhotonUnityNetworking/Code/Editor/"+iconFileName;
|
||||
}
|
||||
else
|
||||
{
|
||||
_thisIconPath = _thisIconPath.Replace("PhotonGUI.cs", iconFileName);
|
||||
}
|
||||
|
||||
return _thisIconPath;
|
||||
}
|
||||
|
||||
static Texture2D m_HelpIcon;
|
||||
|
||||
public static Texture2D HelpIcon
|
||||
{
|
||||
get
|
||||
{
|
||||
if (m_HelpIcon == null)
|
||||
{
|
||||
m_HelpIcon = AssetDatabase.LoadAssetAtPath(GetIconPath("help.png"), typeof(Texture2D)) as Texture2D;
|
||||
}
|
||||
|
||||
|
||||
return m_HelpIcon;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static Texture2D m_CopyIcon;
|
||||
static Texture2D m_CopyIconPro;
|
||||
|
||||
public static Texture2D CopyIcon
|
||||
{
|
||||
get
|
||||
{
|
||||
if (EditorGUIUtility.isProSkin)
|
||||
{
|
||||
if (m_CopyIconPro == null)
|
||||
{
|
||||
m_CopyIconPro = AssetDatabase.LoadAssetAtPath(GetIconPath("CopyIconPro.png"), typeof(Texture2D)) as Texture2D;
|
||||
}
|
||||
|
||||
return m_CopyIconPro;
|
||||
}
|
||||
|
||||
if (m_CopyIcon == null)
|
||||
{
|
||||
m_CopyIcon = AssetDatabase.LoadAssetAtPath(GetIconPath("CopyIcon.png"), typeof(Texture2D)) as Texture2D;
|
||||
}
|
||||
|
||||
return m_CopyIcon;
|
||||
}
|
||||
}
|
||||
|
||||
#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, System.Action buttonAction = null, string buttonName = null)
|
||||
{
|
||||
return DoContainerHeaderFoldout(headline, foldout, buttonAction, buttonName);
|
||||
}
|
||||
|
||||
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, System.Action buttonAction = null, string buttonLabel = null, float buttonWidth = 48)
|
||||
{
|
||||
bool showButton = buttonAction != null;
|
||||
|
||||
Rect rect = DoContainerHeader("", 27, 0f);
|
||||
|
||||
// Shorten foldout label if button is present, so it doesn't interfere with clicking.
|
||||
float foldoutWidth = rect.width - (showButton ? 15 + buttonWidth: 15);
|
||||
Rect foldoutRect = new Rect(rect.xMin + 15, rect.yMin + 5, foldoutWidth, 16);
|
||||
|
||||
bool expanded = EditorGUI.Foldout(foldoutRect, foldout, headline, FoldoutBold);
|
||||
|
||||
// If a button is defined show it, and invoke action on click.
|
||||
if (showButton && GUI.Button(new Rect(foldoutRect) { x = foldoutRect.xMax, height = 17, width = buttonWidth - 4 }, buttonLabel == null ? "" : buttonLabel))
|
||||
{
|
||||
buttonAction.Invoke();
|
||||
}
|
||||
|
||||
return expanded;
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3d2cadb1ccf05074e8ce96b1393846cf
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
@ -0,0 +1,13 @@
|
||||
{
|
||||
"name": "PhotonUnityNetworking.Editor",
|
||||
"references": [
|
||||
"PhotonRealtime",
|
||||
"PhotonUnityNetworking"
|
||||
],
|
||||
"optionalUnityReferences": [],
|
||||
"includePlatforms": [
|
||||
"Editor"
|
||||
],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": false
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4025d00f1ce60da4ea2d0830acf5ebfb
|
||||
timeCreated: 1537863428
|
||||
licenseType: Store
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -0,0 +1,191 @@
|
||||
// ----------------------------------------------------------------------------
|
||||
// <copyright file="PhotonViewHandler.cs" company="Exit Games GmbH">
|
||||
// PhotonNetwork Framework for Unity - Copyright (C) 2018 Exit Games GmbH
|
||||
// </copyright>
|
||||
// <summary>
|
||||
// This is a Editor script to initialize PhotonView components.
|
||||
// </summary>
|
||||
// <author>developer@exitgames.com</author>
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
|
||||
namespace Photon.Pun
|
||||
{
|
||||
using System.Collections.Generic;
|
||||
using Realtime;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using Debug = UnityEngine.Debug;
|
||||
|
||||
|
||||
[InitializeOnLoad]
|
||||
public class PhotonViewHandler : EditorWindow
|
||||
{
|
||||
static PhotonViewHandler()
|
||||
{
|
||||
// called once per change (per key-press in inspectors) and once after play-mode ends.
|
||||
#if (UNITY_2018 || UNITY_2018_1_OR_NEWER)
|
||||
EditorApplication.hierarchyChanged += OnHierarchyChanged;
|
||||
#else
|
||||
EditorApplication.hierarchyWindowChanged += OnHierarchyChanged;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
internal static void OnHierarchyChanged()
|
||||
{
|
||||
// set prefabs to viewID 0 if needed
|
||||
// organize resource PVs in a list per viewID
|
||||
|
||||
// process the lists: if more than one photonView is in a list, we have to resolve the clash
|
||||
// check if only one view had the viewId earlier
|
||||
// apply a new viewID to the others
|
||||
|
||||
// update the cached list of instances and their viewID
|
||||
|
||||
|
||||
//Debug.LogWarning("OnHierarchyChanged(). isPlaying: " + Application.isPlaying);
|
||||
if (Application.isPlaying)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
PhotonView[] photonViewResources = Resources.FindObjectsOfTypeAll<PhotonView>();
|
||||
List<PhotonView> photonViewInstances = new List<PhotonView>();
|
||||
Dictionary<int, List<PhotonView>> viewInstancesPerViewId = new Dictionary<int, List<PhotonView>>();
|
||||
List<PhotonView> photonViewsToReassign = new List<PhotonView>();
|
||||
|
||||
foreach (PhotonView view in photonViewResources)
|
||||
{
|
||||
if (PhotonEditorUtils.IsPrefab(view.gameObject))
|
||||
{
|
||||
// prefabs should use 0 as ViewID and sceneViewId
|
||||
if (view.ViewID != 0 || view.sceneViewId != 0)
|
||||
{
|
||||
view.ViewID = 0;
|
||||
view.sceneViewId = 0;
|
||||
EditorUtility.SetDirty(view);
|
||||
}
|
||||
|
||||
continue; // skip prefabs in further processing
|
||||
}
|
||||
|
||||
photonViewInstances.Add(view);
|
||||
|
||||
|
||||
// assign a new viewID if the viewId is lower than the minimum for this scene
|
||||
if (!IsViewIdOkForScene(view))
|
||||
{
|
||||
photonViewsToReassign.Add(view);
|
||||
continue; // this view definitely gets cleaned up, so it does not count versus duplicates, checked below
|
||||
}
|
||||
|
||||
|
||||
// organize the viewInstances into lists per viewID, so we know duplicate usage
|
||||
if (!viewInstancesPerViewId.ContainsKey(view.sceneViewId))
|
||||
{
|
||||
viewInstancesPerViewId[view.sceneViewId] = new List<PhotonView>();
|
||||
}
|
||||
viewInstancesPerViewId[view.sceneViewId].Add(view);
|
||||
}
|
||||
|
||||
//Debug.Log("PreviousAssignments: "+PunSceneViews.Instance.Views.Count);
|
||||
|
||||
foreach (List<PhotonView> list in viewInstancesPerViewId.Values)
|
||||
{
|
||||
if (list.Count <= 1)
|
||||
{
|
||||
continue; // skip lists with just one entry (the viewID is unique)
|
||||
}
|
||||
|
||||
|
||||
PhotonView previousAssignment = null;
|
||||
bool wasAssigned = PunSceneViews.Instance.Views.TryGetValue(list[0].sceneViewId, out previousAssignment);
|
||||
|
||||
foreach (PhotonView view in list)
|
||||
{
|
||||
if (wasAssigned && view.Equals(previousAssignment))
|
||||
{
|
||||
// previously, we cached the used viewID as assigned to the current view. we don't change this.
|
||||
continue;
|
||||
}
|
||||
|
||||
//Debug.LogWarning("View to reassign due to viewID: "+view, view.gameObject);
|
||||
photonViewsToReassign.Add(view);
|
||||
}
|
||||
}
|
||||
|
||||
int i;
|
||||
foreach (PhotonView view in photonViewsToReassign)
|
||||
{
|
||||
i = MinSceneViewId(view);
|
||||
while (viewInstancesPerViewId.ContainsKey(i))
|
||||
{
|
||||
i++;
|
||||
}
|
||||
view.sceneViewId = i;
|
||||
viewInstancesPerViewId.Add(i, null); // we don't need the lists anymore but we care about getting the viewIDs listed
|
||||
EditorUtility.SetDirty(view);
|
||||
}
|
||||
|
||||
|
||||
// update the "semi persistent" list of viewIDs and their PhotonViews
|
||||
PunSceneViews.Instance.Views.Clear();
|
||||
foreach (PhotonView view in photonViewInstances)
|
||||
{
|
||||
if (PunSceneViews.Instance.Views.ContainsKey(view.sceneViewId))
|
||||
{
|
||||
Debug.LogError("ViewIDs should no longer have duplicates! "+view.sceneViewId, view);
|
||||
continue;
|
||||
}
|
||||
|
||||
PunSceneViews.Instance.Views[view.sceneViewId] = view;
|
||||
}
|
||||
|
||||
//Debug.Log("photonViewsToReassign.Count: "+photonViewsToReassign.Count + " count of viewIDs in use: "+viewInstancesPerViewId.Values.Count);
|
||||
//Debug.Log("PreviousAssignments now counts: "+PunSceneViews.Instance.Views.Count);
|
||||
}
|
||||
|
||||
|
||||
private static int MinSceneViewId(PhotonView view)
|
||||
{
|
||||
int result = PunSceneSettings.MinViewIdForScene(view.gameObject.scene.name);
|
||||
return result;
|
||||
}
|
||||
|
||||
private static bool IsViewIdOkForScene(PhotonView view)
|
||||
{
|
||||
return view.sceneViewId >= MinSceneViewId(view);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stores a PhotonView instances per viewId (key). Instance is used as cache storage in-Editor.
|
||||
/// </summary>
|
||||
public class PunSceneViews : ScriptableObject
|
||||
{
|
||||
[SerializeField]
|
||||
public Dictionary<int, PhotonView> Views = new Dictionary<int, PhotonView>();
|
||||
|
||||
private static PunSceneViews instanceField;
|
||||
public static PunSceneViews Instance
|
||||
{
|
||||
get
|
||||
{
|
||||
if (instanceField != null)
|
||||
{
|
||||
return instanceField;
|
||||
}
|
||||
|
||||
instanceField = GameObject.FindObjectOfType<PunSceneViews>();
|
||||
if (instanceField == null)
|
||||
{
|
||||
instanceField = ScriptableObject.CreateInstance<PunSceneViews>();
|
||||
}
|
||||
|
||||
return instanceField;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 57b538e62a0ca6248bfd354def935e57
|
||||
labels:
|
||||
- ExitGames
|
||||
- PUN
|
||||
- Photon
|
||||
- Networking
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
@ -0,0 +1,394 @@
|
||||
// ----------------------------------------------------------------------------
|
||||
// <copyright file="PhotonViewInspector.cs" company="Exit Games GmbH">
|
||||
// PhotonNetwork Framework for Unity - Copyright (C) 2018 Exit Games GmbH
|
||||
// </copyright>
|
||||
// <summary>
|
||||
// Custom inspector for the PhotonView component.
|
||||
// </summary>
|
||||
// <author>developer@exitgames.com</author>
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
using System;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
using Photon.Realtime;
|
||||
|
||||
namespace Photon.Pun
|
||||
{
|
||||
[CustomEditor(typeof(PhotonView))]
|
||||
[CanEditMultipleObjects]
|
||||
internal class PhotonViewInspector : Editor
|
||||
{
|
||||
private PhotonView m_Target;
|
||||
|
||||
private static GUIContent ownerTransferGuiContent = new GUIContent("Ownership Transfer", "Determines how ownership changes may be initiated.");
|
||||
private static GUIContent syncronizationGuiContent = new GUIContent("Synchronization", "Determines how sync updates are culled and sent.");
|
||||
private static GUIContent observableSearchGuiContent = new GUIContent("Observable Search", "When set to Auto, On Awake, Observables on this GameObject (and child GameObjects) will be found and populate the Observables List." +
|
||||
"\n\nNested PhotonViews (children with a PhotonView) and their children will not be included in the search.");
|
||||
|
||||
public void OnEnable()
|
||||
{
|
||||
this.m_Target = (PhotonView)this.target;
|
||||
|
||||
if (!Application.isPlaying)
|
||||
m_Target.FindObservables();
|
||||
}
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
|
||||
|
||||
this.m_Target = (PhotonView)this.target;
|
||||
bool isProjectPrefab = PhotonEditorUtils.IsPrefab(this.m_Target.gameObject);
|
||||
bool multiSelected = Selection.gameObjects.Length > 1;
|
||||
|
||||
if (this.m_Target.ObservedComponents == null)
|
||||
{
|
||||
this.m_Target.ObservedComponents = new System.Collections.Generic.List<Component>();
|
||||
}
|
||||
|
||||
if (this.m_Target.ObservedComponents.Count == 0)
|
||||
{
|
||||
this.m_Target.ObservedComponents.Add(null);
|
||||
}
|
||||
|
||||
GUILayout.Space(5);
|
||||
|
||||
EditorGUILayout.BeginVertical((GUIStyle)"HelpBox");
|
||||
// View ID - Hide if we are multi-selected
|
||||
if (!multiSelected)
|
||||
{
|
||||
if (isProjectPrefab)
|
||||
{
|
||||
EditorGUILayout.LabelField("View ID", "<i>Set at runtime</i>", new GUIStyle("Label") { richText = true });
|
||||
}
|
||||
else if (EditorApplication.isPlaying)
|
||||
{
|
||||
EditorGUILayout.LabelField("View ID", this.m_Target.ViewID.ToString());
|
||||
}
|
||||
else
|
||||
{
|
||||
// this is an object in a scene, modified at edit-time. we can store this as sceneViewId
|
||||
int idValue = EditorGUILayout.IntField("View ID [1.." + (PhotonNetwork.MAX_VIEW_IDS - 1) + "]", this.m_Target.sceneViewId);
|
||||
if (this.m_Target.sceneViewId != idValue)
|
||||
{
|
||||
Undo.RecordObject(this.m_Target, "Change PhotonView viewID");
|
||||
this.m_Target.sceneViewId = idValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Locally Controlled
|
||||
if (EditorApplication.isPlaying)
|
||||
{
|
||||
string masterClientHint = PhotonNetwork.IsMasterClient ? " (master)" : "";
|
||||
EditorGUILayout.LabelField("IsMine:", this.m_Target.IsMine.ToString() + masterClientHint);
|
||||
Room room = PhotonNetwork.CurrentRoom;
|
||||
int cretrId = this.m_Target.CreatorActorNr;
|
||||
Player cretr = (room != null) ? room.GetPlayer(cretrId) : null;
|
||||
Player owner = this.m_Target.Owner;
|
||||
Player ctrlr = this.m_Target.Controller;
|
||||
EditorGUILayout.LabelField("Controller:", (ctrlr != null ? ("[" + ctrlr.ActorNumber + "] '" + ctrlr.NickName + "' " + (ctrlr.IsMasterClient ? " (master)" : "")) : "[0] <null>"));
|
||||
EditorGUILayout.LabelField("Owner:", (owner != null ? ("[" + owner.ActorNumber + "] '" + owner.NickName + "' " + (owner.IsMasterClient ? " (master)" : "")) : "[0] <null>"));
|
||||
EditorGUILayout.LabelField("Creator:", (cretr != null ? ("[" +cretrId + "] '" + cretr.NickName + "' " + (cretr.IsMasterClient ? " (master)" : "")) : "[0] <null>"));
|
||||
|
||||
}
|
||||
|
||||
EditorGUILayout.EndVertical();
|
||||
|
||||
EditorGUI.BeginDisabledGroup(Application.isPlaying);
|
||||
|
||||
GUILayout.Space(5);
|
||||
|
||||
// Ownership section
|
||||
|
||||
EditorGUILayout.LabelField("Ownership", (GUIStyle)"BoldLabel");
|
||||
|
||||
OwnershipOption own = (OwnershipOption)EditorGUILayout.EnumPopup(ownerTransferGuiContent, this.m_Target.OwnershipTransfer/*, GUILayout.MaxWidth(68), GUILayout.MinWidth(68)*/);
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
GUILayout.Space(5);
|
||||
|
||||
// Observables section
|
||||
|
||||
EditorGUILayout.LabelField("Observables", (GUIStyle)"BoldLabel");
|
||||
|
||||
EditorGUILayout.PropertyField(this.serializedObject.FindProperty("Synchronization"), syncronizationGuiContent);
|
||||
|
||||
if (this.m_Target.Synchronization == ViewSynchronization.Off)
|
||||
{
|
||||
// Show warning if there are any observables. The null check is because the list allows nulls.
|
||||
var observed = m_Target.ObservedComponents;
|
||||
if (observed.Count > 0)
|
||||
{
|
||||
for (int i = 0, cnt = observed.Count; i < cnt; ++i)
|
||||
if (observed[i] != null)
|
||||
{
|
||||
EditorGUILayout.HelpBox("Synchronization is set to Off. Select a Synchronization setting in order to sync the listed Observables.", MessageType.Warning);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
PhotonView.ObservableSearch autoFindObservables = (PhotonView.ObservableSearch)EditorGUILayout.EnumPopup(observableSearchGuiContent, m_Target.observableSearch);
|
||||
|
||||
if (m_Target.observableSearch != autoFindObservables)
|
||||
{
|
||||
Undo.RecordObject(this.m_Target, "Change Auto Find Observables Toggle");
|
||||
m_Target.observableSearch = autoFindObservables;
|
||||
}
|
||||
|
||||
m_Target.FindObservables();
|
||||
|
||||
if (!multiSelected)
|
||||
{
|
||||
bool disableList = Application.isPlaying || autoFindObservables != PhotonView.ObservableSearch.Manual;
|
||||
|
||||
if (disableList)
|
||||
EditorGUI.BeginDisabledGroup(true);
|
||||
|
||||
this.DrawObservedComponentsList(disableList);
|
||||
|
||||
if (disableList)
|
||||
EditorGUI.EndDisabledGroup();
|
||||
}
|
||||
|
||||
// Cleanup: save and fix look
|
||||
if (GUI.changed)
|
||||
{
|
||||
PhotonViewHandler.OnHierarchyChanged(); // TODO: check if needed
|
||||
}
|
||||
|
||||
EditorGUI.EndDisabledGroup();
|
||||
}
|
||||
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Find Observables, and then baking them into the serialized object.
|
||||
/// </summary>
|
||||
private void EditorFindObservables()
|
||||
{
|
||||
Undo.RecordObject(serializedObject.targetObject, "Find Observables");
|
||||
var property = serializedObject.FindProperty("ObservedComponents");
|
||||
|
||||
// Just doing a Find updates the Observables list, but Unity fails to save that change.
|
||||
// Instead we do the find, and then iterate the found objects into the serialize property, then apply that.
|
||||
property.ClearArray();
|
||||
m_Target.FindObservables(true);
|
||||
for(int i = 0; i < m_Target.ObservedComponents.Count; ++i)
|
||||
{
|
||||
property.InsertArrayElementAtIndex(i);
|
||||
property.GetArrayElementAtIndex(i).objectReferenceValue = m_Target.ObservedComponents[i];
|
||||
}
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
}
|
||||
|
||||
private void DrawObservedComponentsList(bool disabled = false)
|
||||
{
|
||||
SerializedProperty listProperty = this.serializedObject.FindProperty("ObservedComponents");
|
||||
|
||||
if (listProperty == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
float containerElementHeight = 22;
|
||||
float containerHeight = listProperty.arraySize * containerElementHeight;
|
||||
|
||||
string foldoutLabel = "Observed Components (" + this.GetObservedComponentsCount() + ")";
|
||||
bool isOpen = PhotonGUI.ContainerHeaderFoldout(foldoutLabel, this.serializedObject.FindProperty("ObservedComponentsFoldoutOpen").boolValue, () => EditorFindObservables(), "Find");
|
||||
this.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);
|
||||
|
||||
// keep track of old type to catch when a new type is observed
|
||||
Type _oldType = listProperty.GetArrayElementAtIndex(i).objectReferenceValue != null ? listProperty.GetArrayElementAtIndex(i).objectReferenceValue.GetType() : null;
|
||||
|
||||
EditorGUI.PropertyField(propertyPosition, listProperty.GetArrayElementAtIndex(i), new GUIContent());
|
||||
|
||||
// new type, could be different from old type
|
||||
Type _newType = listProperty.GetArrayElementAtIndex(i).objectReferenceValue != null ? listProperty.GetArrayElementAtIndex(i).objectReferenceValue.GetType() : null;
|
||||
|
||||
// the user dropped a Transform, we must change it by adding a PhotonTransformView and observe that instead
|
||||
if (_oldType != _newType)
|
||||
{
|
||||
if (_newType == typeof(PhotonView))
|
||||
{
|
||||
listProperty.GetArrayElementAtIndex(i).objectReferenceValue = null;
|
||||
Debug.LogError("PhotonView Detected you dropped a PhotonView, this is not allowed. \n It's been removed from observed field.");
|
||||
|
||||
}
|
||||
else if (_newType == typeof(Transform))
|
||||
{
|
||||
|
||||
// try to get an existing PhotonTransformView ( we don't want any duplicates...)
|
||||
PhotonTransformView _ptv = this.m_Target.gameObject.GetComponent<PhotonTransformView>();
|
||||
if (_ptv == null)
|
||||
{
|
||||
// no ptv yet, we create one and enable position and rotation, no scaling, as it's too rarely needed to take bandwidth for nothing
|
||||
_ptv = Undo.AddComponent<PhotonTransformView>(this.m_Target.gameObject);
|
||||
}
|
||||
// switch observe from transform to _ptv
|
||||
listProperty.GetArrayElementAtIndex(i).objectReferenceValue = _ptv;
|
||||
Debug.Log("PhotonView has detected you dropped a Transform. Instead it's better to observe a PhotonTransformView for better control and performances");
|
||||
}
|
||||
else if (_newType == typeof(Rigidbody))
|
||||
{
|
||||
|
||||
Rigidbody _rb = listProperty.GetArrayElementAtIndex(i).objectReferenceValue as Rigidbody;
|
||||
|
||||
// try to get an existing PhotonRigidbodyView ( we don't want any duplicates...)
|
||||
PhotonRigidbodyView _prbv = _rb.gameObject.GetComponent<PhotonRigidbodyView>();
|
||||
if (_prbv == null)
|
||||
{
|
||||
// no _prbv yet, we create one
|
||||
_prbv = Undo.AddComponent<PhotonRigidbodyView>(_rb.gameObject);
|
||||
}
|
||||
// switch observe from transform to _prbv
|
||||
listProperty.GetArrayElementAtIndex(i).objectReferenceValue = _prbv;
|
||||
Debug.Log("PhotonView has detected you dropped a RigidBody. Instead it's better to observe a PhotonRigidbodyView for better control and performances");
|
||||
}
|
||||
else if (_newType == typeof(Rigidbody2D))
|
||||
{
|
||||
|
||||
// try to get an existing PhotonRigidbody2DView ( we don't want any duplicates...)
|
||||
PhotonRigidbody2DView _prb2dv = this.m_Target.gameObject.GetComponent<PhotonRigidbody2DView>();
|
||||
if (_prb2dv == null)
|
||||
{
|
||||
// no _prb2dv yet, we create one
|
||||
_prb2dv = Undo.AddComponent<PhotonRigidbody2DView>(this.m_Target.gameObject);
|
||||
}
|
||||
// switch observe from transform to _prb2dv
|
||||
listProperty.GetArrayElementAtIndex(i).objectReferenceValue = _prb2dv;
|
||||
Debug.Log("PhotonView has detected you dropped a Rigidbody2D. Instead it's better to observe a PhotonRigidbody2DView for better control and performances");
|
||||
}
|
||||
else if (_newType == typeof(Animator))
|
||||
{
|
||||
|
||||
// try to get an existing PhotonAnimatorView ( we don't want any duplicates...)
|
||||
PhotonAnimatorView _pav = this.m_Target.gameObject.GetComponent<PhotonAnimatorView>();
|
||||
if (_pav == null)
|
||||
{
|
||||
// no _pav yet, we create one
|
||||
_pav = Undo.AddComponent<PhotonAnimatorView>(this.m_Target.gameObject);
|
||||
}
|
||||
// switch observe from transform to _prb2dv
|
||||
listProperty.GetArrayElementAtIndex(i).objectReferenceValue = _pav;
|
||||
Debug.Log("PhotonView has detected you dropped a Animator, so we switched to PhotonAnimatorView so that you can serialized the Animator variables");
|
||||
}
|
||||
else if (!typeof(IPunObservable).IsAssignableFrom(_newType))
|
||||
{
|
||||
bool _ignore = false;
|
||||
#if PLAYMAKER
|
||||
_ignore = _newType == typeof(PlayMakerFSM);// Photon Integration for PlayMaker will swap at runtime to a proxy using iPunObservable.
|
||||
#endif
|
||||
|
||||
if (_newType == null || _newType == typeof(Rigidbody) || _newType == typeof(Rigidbody2D))
|
||||
{
|
||||
_ignore = true;
|
||||
}
|
||||
|
||||
if (!_ignore)
|
||||
{
|
||||
listProperty.GetArrayElementAtIndex(i).objectReferenceValue = null;
|
||||
Debug.LogError("PhotonView Detected you dropped a Component missing IPunObservable Interface,\n You dropped a <" + _newType + "> instead. It's been removed from observed field.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//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 = !disabled && listProperty.arraySize > 1;
|
||||
if (GUI.Button(removeButtonRect, new GUIContent(ReorderableListResources.texRemoveButton), PhotonGUI.DefaultRemoveButtonStyle))
|
||||
{
|
||||
listProperty.DeleteArrayElementAtIndex(i);
|
||||
}
|
||||
GUI.enabled = !disabled;
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
this.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;
|
||||
this.serializedObject.Update();
|
||||
}
|
||||
|
||||
if (wasObservedComponentsEmpty == false && isObservedComponentsEmpty == true)
|
||||
{
|
||||
Undo.RecordObject(this.m_Target, "Change PhotonView");
|
||||
this.m_Target.Synchronization = ViewSynchronization.Off;
|
||||
this.serializedObject.Update();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e73a30c46df19194f873ea7a9ce12753
|
||||
labels:
|
||||
- ExitGames
|
||||
- PUN
|
||||
- Photon
|
||||
- Networking
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
BIN
Assets/Photon/PhotonUnityNetworking/Code/Editor/PunGradient.png
Normal file
BIN
Assets/Photon/PhotonUnityNetworking/Code/Editor/PunGradient.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 308 B |
@ -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:
|
@ -0,0 +1,178 @@
|
||||
// ----------------------------------------------------------------------------
|
||||
// <copyright file="PunSceneSettings.cs" company="Exit Games GmbH">
|
||||
// PhotonNetwork Framework for Unity - Copyright (C) 2018 Exit Games GmbH
|
||||
// </copyright>
|
||||
// <summary>
|
||||
// Optional lowest-viewID setting per-scene. So PhotonViews don't get the same ID.
|
||||
// </summary>
|
||||
// <author>developer@exitgames.com</author>
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Photon.Pun
|
||||
{
|
||||
[Serializable]
|
||||
public class SceneSetting
|
||||
{
|
||||
public SceneAsset sceneAsset;
|
||||
public string sceneName;
|
||||
public int minViewId;
|
||||
}
|
||||
|
||||
[HelpURL("https://doc.photonengine.com/en-us/pun/current/getting-started/feature-overview#scene_photonviews_in_multiple_scenes")]
|
||||
public class PunSceneSettings : ScriptableObject
|
||||
{
|
||||
|
||||
#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 SceneSettingsListFoldoutOpen = true;
|
||||
#pragma warning restore 0414
|
||||
#endif
|
||||
|
||||
[SerializeField]
|
||||
public List<SceneSetting> MinViewIdPerScene = new List<SceneSetting>();
|
||||
|
||||
|
||||
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 = CreateInstance<PunSceneSettings>();
|
||||
#pragma warning disable 0168
|
||||
try
|
||||
{
|
||||
AssetDatabase.CreateAsset(instanceField, PunSceneSettingsCsPath);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
#if PHOTON_UNITY_NETWORKING
|
||||
Debug.LogError("-- WARNING: PROJECT CLEANUP NECESSARY -- If you delete pun from your project, make sure you also clean up the Scripting define symbols from any reference to PUN like 'PHOTON_UNITY_NETWORKING ");
|
||||
#endif
|
||||
}
|
||||
#pragma warning restore 0168
|
||||
}
|
||||
|
||||
return instanceField;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static int MinViewIdForScene(string sceneName)
|
||||
{
|
||||
if (string.IsNullOrEmpty(sceneName))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
PunSceneSettings pss = Instance;
|
||||
if (pss == null)
|
||||
{
|
||||
Debug.LogError("pss cant be null");
|
||||
return 1;
|
||||
}
|
||||
|
||||
foreach (SceneSetting setting in pss.MinViewIdPerScene)
|
||||
{
|
||||
if (setting.sceneName.Equals(sceneName))
|
||||
{
|
||||
return setting.minViewId;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
public static void SanitizeSceneSettings()
|
||||
{
|
||||
if (Instance == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
foreach (SceneSetting sceneSetting in Instance.MinViewIdPerScene)
|
||||
{
|
||||
if (sceneSetting.sceneAsset == null && !string.IsNullOrEmpty(sceneSetting.sceneName))
|
||||
{
|
||||
|
||||
string[] guids = AssetDatabase.FindAssets(sceneSetting.sceneName + " t:SceneAsset");
|
||||
|
||||
foreach (string guid in guids)
|
||||
{
|
||||
string path = AssetDatabase.GUIDToAssetPath(guid);
|
||||
if (Path.GetFileNameWithoutExtension(path) == sceneSetting.sceneName)
|
||||
{
|
||||
sceneSetting.sceneAsset =
|
||||
AssetDatabase.LoadAssetAtPath<SceneAsset>(
|
||||
AssetDatabase.GUIDToAssetPath(guid));
|
||||
|
||||
// Debug.Log("SceneSettings : ''"+sceneSetting.sceneName+"'' scene is missing: Issue corrected",Instance);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//Debug.Log("SceneSettings : ''"+sceneSetting.sceneName+"'' scene is missing",Instance);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (sceneSetting.sceneAsset != null && sceneSetting.sceneName!= sceneSetting.sceneAsset.name )
|
||||
{
|
||||
// Debug.Log("SceneSettings : '"+sceneSetting.sceneName+"' mismatch with sceneAsset: '"+sceneSetting.sceneAsset.name+"' : Issue corrected",Instance);
|
||||
sceneSetting.sceneName = sceneSetting.sceneAsset.name;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fc3284eace5a64d4bb516df7d7effdb9
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
@ -0,0 +1,21 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!114 &11400000
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 0}
|
||||
m_GameObject: {fileID: 0}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: fc3284eace5a64d4bb516df7d7effdb9, type: 3}
|
||||
m_Name: PunSceneSettingsFile
|
||||
m_EditorClassIdentifier:
|
||||
SceneSettingsListFoldoutOpen: 1
|
||||
MinViewIdPerScene:
|
||||
- sceneAsset: {fileID: 102900000, guid: 559222f4671e440cba71aecba1de3505, type: 3}
|
||||
sceneName: SceneView_A
|
||||
minViewId: 2
|
||||
- sceneAsset: {fileID: 102900000, guid: a81615022a16c489aac8daadf8f51fae, type: 3}
|
||||
sceneName: SceneView_B
|
||||
minViewId: 10
|
@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d0aacb83307022d449e90a09d28222ae
|
@ -0,0 +1,260 @@
|
||||
// ----------------------------------------------------------------------------
|
||||
// <copyright file="PunSceneSettingsInspector.cs" company="Exit Games GmbH">
|
||||
// PhotonNetwork Framework for Unity - Copyright (C) 2019 Exit Games GmbH
|
||||
// </copyright>
|
||||
// <summary>
|
||||
// Custom inspector for the PunSceneSettings component.
|
||||
// </summary>
|
||||
// <author>developer@exitgames.com</author>
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Photon.Pun
|
||||
{
|
||||
[CustomEditor(typeof(PunSceneSettings))]
|
||||
internal class PunSceneSettingsInspector : Editor
|
||||
{
|
||||
private PunSceneSettings m_Target;
|
||||
private bool isOpen;
|
||||
private List<string> _duplicateScenesDefinition;
|
||||
private List<int> _duplicateViewIdDefinition;
|
||||
|
||||
private SerializedProperty listProperty;
|
||||
private SerializedProperty _sceneSettings_i;
|
||||
private SerializedProperty sceneNameProperty;
|
||||
private SerializedProperty sceneAssetProperty;
|
||||
private SerializedProperty minViewIdProperty;
|
||||
|
||||
private bool _firstTime;
|
||||
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
this.m_Target = (PunSceneSettings) this.target;
|
||||
|
||||
// error checking
|
||||
_duplicateScenesDefinition = m_Target.MinViewIdPerScene.GroupBy(x => x.sceneName)
|
||||
.Where(g => g.Count() > 1)
|
||||
.Select(y => y.Key)
|
||||
.ToList();
|
||||
|
||||
_duplicateViewIdDefinition = m_Target.MinViewIdPerScene.GroupBy(x => x.minViewId)
|
||||
.Where(g => g.Count() > 1)
|
||||
.Select(y => y.Key)
|
||||
.ToList();
|
||||
|
||||
DrawSceneSettingsList();
|
||||
|
||||
foreach (string dup in _duplicateScenesDefinition)
|
||||
{
|
||||
EditorGUILayout.LabelField("Found duplicates for scene",dup);
|
||||
}
|
||||
|
||||
|
||||
foreach (SceneSetting sceneSettings in m_Target.MinViewIdPerScene)
|
||||
{
|
||||
if (_duplicateViewIdDefinition.Contains(sceneSettings.minViewId))
|
||||
{
|
||||
GUILayout.Label("Found view Id duplicates '"+sceneSettings.minViewId+"' for scene: " +sceneSettings.sceneName);
|
||||
}
|
||||
|
||||
if (sceneSettings.minViewId > PhotonNetwork.MAX_VIEW_IDS)
|
||||
{
|
||||
GUILayout.Label(sceneSettings.sceneName+" view Id can not exceed the max view Id "+PhotonNetwork.MAX_VIEW_IDS);
|
||||
}
|
||||
|
||||
if (sceneSettings.minViewId < 1)
|
||||
{
|
||||
GUILayout.Label(sceneSettings.sceneName+" view Id can not be less than 1");
|
||||
}
|
||||
|
||||
if (sceneSettings.sceneAsset == null && !string.IsNullOrEmpty(sceneSettings.sceneName))
|
||||
{
|
||||
GUILayout.Label("'"+sceneSettings.sceneName+"' scene is missing in the project");
|
||||
}
|
||||
}
|
||||
|
||||
_firstTime = false;
|
||||
}
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
_firstTime = true;
|
||||
}
|
||||
|
||||
private void DrawSceneSettingsList()
|
||||
{
|
||||
GUILayout.Space(5);
|
||||
|
||||
// check for changes ( from undo for example)
|
||||
this.serializedObject.Update();
|
||||
|
||||
listProperty = this.serializedObject.FindProperty("MinViewIdPerScene");
|
||||
|
||||
if (listProperty == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
float containerElementHeight = 44;
|
||||
float containerHeight = listProperty.arraySize * containerElementHeight;
|
||||
|
||||
isOpen = PhotonGUI.ContainerHeaderFoldout("Scene Settings (" + listProperty.arraySize + ")", this.serializedObject.FindProperty("SceneSettingsListFoldoutOpen").boolValue);
|
||||
this.serializedObject.FindProperty("SceneSettingsListFoldoutOpen").boolValue = isOpen;
|
||||
|
||||
if (isOpen == false)
|
||||
{
|
||||
containerHeight = 0;
|
||||
}
|
||||
|
||||
Rect containerRect = PhotonGUI.ContainerBody(containerHeight);
|
||||
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);
|
||||
|
||||
_sceneSettings_i = listProperty.GetArrayElementAtIndex(i);
|
||||
|
||||
sceneNameProperty = _sceneSettings_i.FindPropertyRelative("sceneName");
|
||||
sceneAssetProperty = _sceneSettings_i.FindPropertyRelative("sceneAsset");
|
||||
minViewIdProperty = _sceneSettings_i.FindPropertyRelative("minViewId");
|
||||
|
||||
string _sceneName = sceneNameProperty.stringValue;
|
||||
SceneAsset _sceneAsset = m_Target.MinViewIdPerScene[i].sceneAsset;
|
||||
|
||||
// check if we need to find the scene asset based on the scene name. This is for backward compatibility or when the scene asset was deleted
|
||||
if (_firstTime)
|
||||
{
|
||||
if (_sceneAsset == null && !string.IsNullOrEmpty(_sceneName))
|
||||
{
|
||||
string[] guids = AssetDatabase.FindAssets(_sceneName + " t:SceneAsset");
|
||||
|
||||
foreach (string guid in guids)
|
||||
{
|
||||
string path = AssetDatabase.GUIDToAssetPath(guid);
|
||||
if (Path.GetFileNameWithoutExtension(path) == _sceneName)
|
||||
{
|
||||
sceneAssetProperty.objectReferenceValue =
|
||||
AssetDatabase.LoadAssetAtPath<SceneAsset>(
|
||||
AssetDatabase.GUIDToAssetPath(guid));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool _missingSceneAsset = _sceneAsset == null && !string.IsNullOrEmpty(_sceneName);
|
||||
// if we don't have a scene asset for the serialized scene named, we show an error.
|
||||
if (_missingSceneAsset ||
|
||||
(sceneNameProperty!=null && _duplicateScenesDefinition!=null && _duplicateScenesDefinition.Contains(sceneNameProperty.stringValue))
|
||||
)
|
||||
{
|
||||
GUI.color = Color.red;
|
||||
}
|
||||
|
||||
EditorGUI.BeginChangeCheck();
|
||||
string _label = _missingSceneAsset
|
||||
? "Scene Asset: Missing '" + _sceneName + "'"
|
||||
: "Scene Asset";
|
||||
|
||||
EditorGUI.PropertyField(propertyPosition,sceneAssetProperty, new GUIContent(_label));
|
||||
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
_sceneAsset = sceneAssetProperty.objectReferenceValue as SceneAsset;
|
||||
if (_sceneAsset == null && !string.IsNullOrEmpty(sceneNameProperty.stringValue))
|
||||
{
|
||||
sceneNameProperty.stringValue = null;
|
||||
}
|
||||
else if (sceneNameProperty.stringValue != _sceneAsset.name)
|
||||
{
|
||||
sceneNameProperty.stringValue = _sceneAsset.name;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// EditorGUI.PropertyField(propertyPosition, sceneNameProperty,
|
||||
// new GUIContent("Scene Name"));
|
||||
|
||||
GUI.color = Color.white;
|
||||
|
||||
if ( minViewIdProperty.intValue<1 || minViewIdProperty.intValue> PhotonNetwork.MAX_VIEW_IDS)
|
||||
{
|
||||
GUI.color = Color.red;
|
||||
}
|
||||
Rect secondPropertyPosition = new Rect(elementRect.xMin + 20, elementRect.yMin + containerElementHeight/2,
|
||||
elementRect.width - 45, 16);
|
||||
|
||||
EditorGUI.PropertyField(secondPropertyPosition, _sceneSettings_i.FindPropertyRelative("minViewId"),
|
||||
new GUIContent("Minimum View ID"));
|
||||
|
||||
GUI.color = Color.white;
|
||||
|
||||
//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);
|
||||
|
||||
|
||||
if (GUI.Button(removeButtonRect, new GUIContent(ReorderableListResources.texRemoveButton),
|
||||
PhotonGUI.DefaultRemoveButtonStyle))
|
||||
{
|
||||
listProperty.DeleteArrayElementAtIndex(i);
|
||||
|
||||
Undo.RecordObject(this.m_Target, "Removed SceneSettings Entry");
|
||||
|
||||
}
|
||||
|
||||
|
||||
if (i < listProperty.arraySize - 1)
|
||||
{
|
||||
texturePosition = new Rect(elementRect.xMin + 2, elementRect.yMax, elementRect.width - 4,
|
||||
1);
|
||||
PhotonGUI.DrawSplitter(texturePosition);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (PhotonGUI.AddButton())
|
||||
{
|
||||
this.listProperty.InsertArrayElementAtIndex(Mathf.Max(0, listProperty.arraySize - 1));
|
||||
_sceneSettings_i = this.listProperty.GetArrayElementAtIndex(listProperty.arraySize - 1);
|
||||
sceneNameProperty = _sceneSettings_i.FindPropertyRelative("sceneName");
|
||||
sceneAssetProperty = _sceneSettings_i.FindPropertyRelative("sceneAsset");
|
||||
minViewIdProperty = _sceneSettings_i.FindPropertyRelative("minViewId");
|
||||
|
||||
sceneAssetProperty.objectReferenceValue = null;
|
||||
sceneNameProperty.stringValue = "";
|
||||
minViewIdProperty.intValue = 1;
|
||||
|
||||
Undo.RecordObject(this.m_Target, "Added SceneSettings Entry");
|
||||
}
|
||||
|
||||
this.serializedObject.ApplyModifiedProperties();
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1ad59deacfd0848dcb64a51b0a0eb960
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 62126d9bb7b8eb64ea07a039d902d0ac
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -0,0 +1,26 @@
|
||||
Copyright (c) 2013, Rotorz Limited
|
||||
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 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.
|
||||
|
||||
The views and conclusions contained in the software and documentation are those
|
||||
of the authors and should not be interpreted as representing official policies,
|
||||
either expressed or implied, of the FreeBSD Project.
|
@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c2fbd2e43c3dfae4d9830e9921238cf5
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -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
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Resources to assist with reorderable list control.
|
||||
/// </summary>
|
||||
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,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resource assets for light skin.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>Resource assets are PNG images which have been encoded using a base-64
|
||||
/// string so that actual asset files are not necessary.</para>
|
||||
/// </remarks>
|
||||
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"
|
||||
};
|
||||
/// <summary>
|
||||
/// Resource assets for dark skin.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>Resource assets are PNG images which have been encoded using a base-64
|
||||
/// string so that actual asset files are not necessary.</para>
|
||||
/// </remarks>
|
||||
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"
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Gets light or dark texture "add_button.png".
|
||||
/// </summary>
|
||||
public static Texture2D texAddButton
|
||||
{
|
||||
get { return s_Cached[ (int)ResourceName.add_button ]; }
|
||||
}
|
||||
/// <summary>
|
||||
/// Gets light or dark texture "add_button_active.png".
|
||||
/// </summary>
|
||||
public static Texture2D texAddButtonActive
|
||||
{
|
||||
get { return s_Cached[ (int)ResourceName.add_button_active ]; }
|
||||
}
|
||||
/// <summary>
|
||||
/// Gets light or dark texture "container_background.png".
|
||||
/// </summary>
|
||||
public static Texture2D texContainerBackground
|
||||
{
|
||||
get { return s_Cached[ (int)ResourceName.container_background ]; }
|
||||
}
|
||||
/// <summary>
|
||||
/// Gets light or dark texture "grab_handle.png".
|
||||
/// </summary>
|
||||
public static Texture2D texGrabHandle
|
||||
{
|
||||
get { return s_Cached[ (int)ResourceName.grab_handle ]; }
|
||||
}
|
||||
/// <summary>
|
||||
/// Gets light or dark texture "remove_button.png".
|
||||
/// </summary>
|
||||
public static Texture2D texRemoveButton
|
||||
{
|
||||
get { return s_Cached[ (int)ResourceName.remove_button ]; }
|
||||
}
|
||||
/// <summary>
|
||||
/// Gets light or dark texture "remove_button_active.png".
|
||||
/// </summary>
|
||||
public static Texture2D texRemoveButtonActive
|
||||
{
|
||||
get { return s_Cached[ (int)ResourceName.remove_button_active ]; }
|
||||
}
|
||||
/// <summary>
|
||||
/// Gets light or dark texture "title_background.png".
|
||||
/// </summary>
|
||||
public static Texture2D texTitleBackground
|
||||
{
|
||||
get { return s_Cached[ (int)ResourceName.title_background ]; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Generated Resources
|
||||
|
||||
public static Texture2D texItemSplitter { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Generate special textures.
|
||||
/// </summary>
|
||||
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 );
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create 1x1 pixel texture of specified color.
|
||||
/// </summary>
|
||||
/// <param name="name">Name for texture object.</param>
|
||||
/// <param name="color">Pixel color.</param>
|
||||
/// <returns>
|
||||
/// The new <c>Texture2D</c> instance.
|
||||
/// </returns>
|
||||
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;
|
||||
|
||||
/// <summary>
|
||||
/// Read textures from base-64 encoded strings. Automatically selects assets based
|
||||
/// upon whether the light or dark (pro) skin is active.
|
||||
/// </summary>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read width and height if PNG file in pixels.
|
||||
/// </summary>
|
||||
/// <param name="imageData">PNG image data.</param>
|
||||
/// <param name="width">Width of image in pixels.</param>
|
||||
/// <param name="height">Height of image in pixels.</param>
|
||||
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();
|
||||
|
||||
/// <summary>
|
||||
/// Draw texture using <see cref="GUIStyle"/> to workaround bug in Unity where
|
||||
/// <see cref="GUI.DrawTexture"/> flickers when embedded inside a property drawer.
|
||||
/// </summary>
|
||||
/// <param name="position">Position of which to draw texture in space of GUI.</param>
|
||||
/// <param name="texture">Texture.</param>
|
||||
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
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 60c609ded101b0a468fb5cf27b31cf27
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
@ -0,0 +1,322 @@
|
||||
// ----------------------------------------------------------------------------
|
||||
// <copyright file="ServerSettingsInspector.cs" company="Exit Games GmbH">
|
||||
// PhotonNetwork Framework for Unity - Copyright (C) 2018 Exit Games GmbH
|
||||
// </copyright>
|
||||
// <summary>
|
||||
// This is a custom editor for the ServerSettings scriptable object.
|
||||
// </summary>
|
||||
// <author>developer@exitgames.com</author>
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
using System;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
using Photon.Pun;
|
||||
|
||||
using ExitGames.Client.Photon;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using Photon.Realtime;
|
||||
|
||||
namespace Photon.Pun
|
||||
{
|
||||
[CustomEditor(typeof(ServerSettings))]
|
||||
public class ServerSettingsInspector : Editor
|
||||
{
|
||||
private string versionPhoton;
|
||||
|
||||
private string[] regionsPrefsList;
|
||||
|
||||
private string prefLabel;
|
||||
private const string notAvailableLabel = "n/a";
|
||||
|
||||
private string rpcCrc;
|
||||
private bool showRpcs;
|
||||
|
||||
private GUIStyle vertboxStyle;
|
||||
|
||||
public void Awake()
|
||||
{
|
||||
this.versionPhoton = System.Reflection.Assembly.GetAssembly(typeof(PhotonPeer)).GetName().Version.ToString();
|
||||
}
|
||||
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
if (vertboxStyle == null)
|
||||
vertboxStyle = new GUIStyle("HelpBox") { padding = new RectOffset(6, 6, 6, 6) };
|
||||
|
||||
SerializedObject sObj = new SerializedObject(this.target);
|
||||
ServerSettings settings = this.target as ServerSettings;
|
||||
|
||||
|
||||
EditorGUI.BeginChangeCheck();
|
||||
|
||||
#region Version Vertical Box
|
||||
|
||||
EditorGUILayout.BeginVertical(/*vertboxStyle*/);
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
EditorGUILayout.PrefixLabel(new GUIContent("Version:", "Version of PUN and Photon3Unity3d.dll."));
|
||||
GUILayout.FlexibleSpace();
|
||||
var helpicorect = EditorGUILayout.GetControlRect(GUILayout.MaxWidth(16));
|
||||
EditorGUIUtility.AddCursorRect(helpicorect, MouseCursor.Link);
|
||||
if (GUI.Button(helpicorect, PhotonGUI.HelpIcon, GUIStyle.none))
|
||||
{
|
||||
Application.OpenURL(PhotonEditor.UrlPunSettings);
|
||||
}
|
||||
EditorGUILayout.EndHorizontal();
|
||||
EditorGUILayout.LabelField("Pun: " + PhotonNetwork.PunVersion + " Photon lib: " + this.versionPhoton);
|
||||
EditorGUILayout.EndVertical();
|
||||
|
||||
#endregion Version Vertical Box
|
||||
|
||||
EditorGUI.indentLevel--;
|
||||
SerializedProperty showSettingsProp = this.serializedObject.FindProperty("ShowSettings");
|
||||
bool showSettings = showSettingsProp.Foldout(new GUIContent("Server/Cloud Settings", "Core Photon Server/Cloud settings."));
|
||||
EditorGUI.indentLevel++;
|
||||
|
||||
|
||||
if (showSettings != settings.ShowSettings)
|
||||
{
|
||||
showSettingsProp.boolValue = showSettings;
|
||||
}
|
||||
|
||||
if (showSettingsProp.boolValue)
|
||||
{
|
||||
SerializedProperty settingsSp = this.serializedObject.FindProperty("AppSettings");
|
||||
|
||||
EditorGUI.indentLevel++;
|
||||
|
||||
//Realtime APP ID
|
||||
this.BuildAppIdField(settingsSp.FindPropertyRelative("AppIdRealtime"), "App Id PUN");
|
||||
|
||||
if (PhotonEditorUtils.HasChat)
|
||||
{
|
||||
this.BuildAppIdField(settingsSp.FindPropertyRelative("AppIdChat"));
|
||||
}
|
||||
if (PhotonEditorUtils.HasVoice)
|
||||
{
|
||||
this.BuildAppIdField(settingsSp.FindPropertyRelative("AppIdVoice"));
|
||||
}
|
||||
|
||||
EditorGUILayout.PropertyField(settingsSp.FindPropertyRelative("AppVersion"));
|
||||
EditorGUILayout.PropertyField(settingsSp.FindPropertyRelative("UseNameServer"), new GUIContent("Use Name Server", "Photon Cloud requires this checked.\nUncheck for Photon Server SDK (OnPremise)."));
|
||||
EditorGUILayout.PropertyField(settingsSp.FindPropertyRelative("FixedRegion"), new GUIContent("Fixed Region", "Photon Cloud setting, needs a Name Server.\nDefine one region to always connect to.\nLeave empty to use the best region from a server-side region list."));
|
||||
EditorGUILayout.PropertyField(settingsSp.FindPropertyRelative("Server"), new GUIContent("Server", "Typically empty for Photon Cloud.\nFor Photon OnPremise, enter your host name or IP. Also uncheck \"Use Name Server\" for older Photon OnPremise servers."));
|
||||
EditorGUILayout.PropertyField(settingsSp.FindPropertyRelative("Port"), new GUIContent("Port", "Leave 0 to use default Photon Cloud ports for the Name Server.\nOnPremise defaults to 5055 for UDP and 4530 for TCP."));
|
||||
EditorGUILayout.PropertyField(settingsSp.FindPropertyRelative("ProxyServer"), new GUIContent("Proxy Server", "HTTP Proxy Server for WebSocket connection. See LoadBalancingClient.ProxyServerAddress for options."));
|
||||
EditorGUILayout.PropertyField(settingsSp.FindPropertyRelative("Protocol"), new GUIContent("Protocol", "Use UDP where possible.\nWSS works on WebGL and Xbox exports.\nDefine WEBSOCKET for use on other platforms."));
|
||||
EditorGUILayout.PropertyField(settingsSp.FindPropertyRelative("EnableProtocolFallback"), new GUIContent("Protocol Fallback", "Automatically try another network protocol, if initial connect fails.\nWill use default Name Server ports."));
|
||||
EditorGUILayout.PropertyField(settingsSp.FindPropertyRelative("EnableLobbyStatistics"), new GUIContent("Lobby Statistics", "When using multiple room lists (lobbies), the server can send info about their usage."));
|
||||
EditorGUILayout.PropertyField(settingsSp.FindPropertyRelative("NetworkLogging"), new GUIContent("Network Logging", "Log level for the Photon libraries."));
|
||||
EditorGUI.indentLevel--;
|
||||
}
|
||||
|
||||
EditorGUILayout.PropertyField(this.serializedObject.FindProperty("PunLogging"), new GUIContent("PUN Logging", "Log level for the PUN layer."));
|
||||
EditorGUILayout.PropertyField(this.serializedObject.FindProperty("EnableSupportLogger"), new GUIContent("Support Logger", "Logs additional info for debugging.\nUse this when you submit bugs to the Photon Team."));
|
||||
EditorGUILayout.PropertyField(this.serializedObject.FindProperty("RunInBackground"), new GUIContent("Run In Background", "Enables apps to keep the connection without focus. Android and iOS ignore this."));
|
||||
EditorGUILayout.PropertyField(this.serializedObject.FindProperty("StartInOfflineMode"), new GUIContent("Start In Offline Mode", "Simulates an online connection.\nPUN can be used as usual."));
|
||||
|
||||
EditorGUILayout.PropertyField(this.serializedObject.FindProperty("DevRegion"), new GUIContent("Dev Region", "Photon Cloud setting, needs a Name Server.\nDefine region the Editor and Development builds will always connect to - ensuring all users can find common rooms.\nLeave empty to use the Fixed Region or best region from a server-side region list. This value will be ignored for non-Development builds."));
|
||||
|
||||
#region Best Region Box
|
||||
|
||||
EditorGUILayout.BeginVertical(vertboxStyle);
|
||||
|
||||
if (!string.IsNullOrEmpty(PhotonNetwork.BestRegionSummaryInPreferences))
|
||||
{
|
||||
this.regionsPrefsList = PhotonNetwork.BestRegionSummaryInPreferences.Split(new[] {';'}, StringSplitOptions.RemoveEmptyEntries);
|
||||
if (this.regionsPrefsList.Length < 2)
|
||||
{
|
||||
this.prefLabel = notAvailableLabel;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.prefLabel = string.Format("'{0}' ping:{1}ms ", this.regionsPrefsList[0], this.regionsPrefsList[1]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
this.prefLabel = notAvailableLabel;
|
||||
}
|
||||
|
||||
EditorGUILayout.LabelField(new GUIContent("Best Region Preference: " + prefLabel, "Best region is used if Fixed Region is empty."));
|
||||
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
|
||||
var resetrect = EditorGUILayout.GetControlRect(GUILayout.MinWidth(64));
|
||||
var editrect = EditorGUILayout.GetControlRect(GUILayout.MinWidth(64));
|
||||
if (GUI.Button(resetrect, "Reset", EditorStyles.miniButton))
|
||||
{
|
||||
ServerSettings.ResetBestRegionCodeInPreferences();
|
||||
}
|
||||
|
||||
if (GUI.Button(editrect, "Edit WhiteList", EditorStyles.miniButton))
|
||||
{
|
||||
Application.OpenURL("https://dashboard.photonengine.com/en-US/App/RegionsWhitelistEdit/" + PhotonNetwork.PhotonServerSettings.AppSettings.AppIdRealtime);
|
||||
|
||||
}
|
||||
|
||||
EditorGUILayout.EndHorizontal();
|
||||
EditorGUILayout.EndVertical();
|
||||
|
||||
#endregion Best Region Box
|
||||
|
||||
|
||||
//this.showRpcs = EditorGUILayout.Foldout(this.showRpcs, new GUIContent("RPCs", "RPC shortcut list."));
|
||||
EditorGUI.indentLevel--;
|
||||
this.showRpcs = this.showRpcs.Foldout(new GUIContent("RPCs", "RPC shortcut list."));
|
||||
EditorGUI.indentLevel++;
|
||||
|
||||
if (this.showRpcs)
|
||||
{
|
||||
// first time check to get the rpc has proper
|
||||
if (string.IsNullOrEmpty(this.rpcCrc))
|
||||
{
|
||||
this.rpcCrc = this.RpcListHashCode().ToString("X");
|
||||
}
|
||||
|
||||
#region Begin Vertical Box CRC
|
||||
|
||||
EditorGUILayout.BeginVertical(vertboxStyle);
|
||||
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
EditorGUILayout.PrefixLabel("List CRC");
|
||||
|
||||
EditorGUI.indentLevel--;
|
||||
var copyrect = EditorGUILayout.GetControlRect(GUILayout.MaxWidth(16));
|
||||
EditorGUILayout.GetControlRect(GUILayout.MaxWidth(12));
|
||||
var hashrect = EditorGUILayout.GetControlRect(GUILayout.MinWidth(16)); // new Rect(copyrect) { xMin = copyrect.xMin + 32 };
|
||||
|
||||
EditorGUIUtility.AddCursorRect(copyrect, MouseCursor.Link);
|
||||
EditorGUI.LabelField(copyrect, new GUIContent("", "Copy Hashcode to Clipboard"));
|
||||
if (GUI.Button(copyrect, PhotonGUI.CopyIcon, GUIStyle.none))
|
||||
{
|
||||
Debug.Log("RPC-List HashCode copied into your ClipBoard: " + this.rpcCrc + ". Make sure clients that send each other RPCs have the same RPC-List.");
|
||||
EditorGUIUtility.systemCopyBuffer = this.rpcCrc;
|
||||
}
|
||||
EditorGUI.SelectableLabel(hashrect, this.rpcCrc);
|
||||
|
||||
EditorGUILayout.EndHorizontal();
|
||||
|
||||
EditorGUI.indentLevel++;
|
||||
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
|
||||
var refreshrect = EditorGUILayout.GetControlRect(GUILayout.MinWidth(64));
|
||||
var clearrect = EditorGUILayout.GetControlRect(GUILayout.MinWidth(64));
|
||||
|
||||
if (GUI.Button(refreshrect, "Refresh RPCs", EditorStyles.miniButton))
|
||||
{
|
||||
PhotonEditor.UpdateRpcList();
|
||||
this.Repaint();
|
||||
}
|
||||
|
||||
if (GUI.Button(clearrect, "Clear RPCs", EditorStyles.miniButton))
|
||||
{
|
||||
PhotonEditor.ClearRpcList();
|
||||
}
|
||||
|
||||
EditorGUILayout.EndHorizontal();
|
||||
|
||||
EditorGUILayout.EndVertical();
|
||||
|
||||
#endregion End Vertical Box CRC
|
||||
|
||||
EditorGUI.indentLevel++;
|
||||
|
||||
SerializedProperty sRpcs = sObj.FindProperty("RpcList");
|
||||
EditorGUILayout.PropertyField(sRpcs, true);
|
||||
|
||||
EditorGUI.indentLevel--;
|
||||
}
|
||||
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
sObj.ApplyModifiedProperties();
|
||||
this.serializedObject.ApplyModifiedProperties();
|
||||
|
||||
// cache the rpc hash
|
||||
this.rpcCrc = this.RpcListHashCode().ToString("X");
|
||||
}
|
||||
|
||||
#region Simple Settings
|
||||
|
||||
/// Conditional Simple Sync Settings DrawGUI - Uses reflection to avoid having to hard connect the libraries
|
||||
var SettingsScriptableObjectBaseType = GetType("Photon.Utilities.SettingsScriptableObjectBase");
|
||||
if (SettingsScriptableObjectBaseType != null)
|
||||
{
|
||||
EditorGUILayout.GetControlRect(false, 3);
|
||||
|
||||
EditorGUILayout.LabelField("Simple Extension Settings", (GUIStyle)"BoldLabel");
|
||||
|
||||
var drawAllMethod = SettingsScriptableObjectBaseType.GetMethod("DrawAllSettings");
|
||||
|
||||
if (drawAllMethod != null && this != null)
|
||||
{
|
||||
bool initializeAsOpen = false;
|
||||
drawAllMethod.Invoke(null, new object[2] { this, initializeAsOpen });
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
private static Type GetType(string typeName)
|
||||
{
|
||||
var type = Type.GetType(typeName);
|
||||
if (type != null) return type;
|
||||
foreach (var a in AppDomain.CurrentDomain.GetAssemblies())
|
||||
{
|
||||
type = a.GetType(typeName);
|
||||
if (type != null)
|
||||
return type;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
private void BuildAppIdField(SerializedProperty property, string label = null)
|
||||
{
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
|
||||
if (label != null)
|
||||
{
|
||||
EditorGUILayout.PropertyField(property, new GUIContent(label), GUILayout.MinWidth(32));
|
||||
}
|
||||
else
|
||||
{
|
||||
EditorGUILayout.PropertyField(property, GUILayout.MinWidth(32));
|
||||
}
|
||||
|
||||
property.stringValue = property.stringValue.Trim();
|
||||
string appId = property.stringValue;
|
||||
|
||||
string url = "https://dashboard.photonengine.com/en-US/PublicCloud";
|
||||
|
||||
if (!string.IsNullOrEmpty(appId))
|
||||
{
|
||||
url = string.Format("https://dashboard.photonengine.com/en-US/App/Manage/{0}", appId);
|
||||
}
|
||||
if (GUILayout.Button("Dashboard", EditorStyles.miniButton, GUILayout.MinWidth(78), GUILayout.MaxWidth(78)))
|
||||
{
|
||||
Application.OpenURL(url);
|
||||
}
|
||||
EditorGUILayout.EndHorizontal();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 21239ba77ac4b534f958e8617ef13ede
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c6024eaa234f94341af9e45cc99285c7
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -0,0 +1,40 @@
|
||||
// ----------------------------------------------------------------------------
|
||||
// <copyright file="PhotonAnimatorViewEditor.cs" company="Exit Games GmbH">
|
||||
// PhotonNetwork Framework for Unity - Copyright (C) 2018 Exit Games GmbH
|
||||
// </copyright>
|
||||
// <summary>
|
||||
// This is a custom editor for the AnimatorView component.
|
||||
// </summary>
|
||||
// <author>developer@exitgames.com</author>
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
namespace Photon.Pun
|
||||
{
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
[CustomEditor(typeof(MonoBehaviourPun))]
|
||||
public abstract class MonoBehaviourPunEditor : Editor
|
||||
{
|
||||
MonoBehaviourPun mbTarget;
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
mbTarget = target as MonoBehaviourPun;
|
||||
}
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
mbTarget = target as MonoBehaviourPun;
|
||||
|
||||
base.OnInspectorGUI();
|
||||
|
||||
if (mbTarget.photonView == null)
|
||||
{
|
||||
EditorGUILayout.HelpBox("Unable to find a PhotonView on this GameObject or on any parent GameObject.", MessageType.Warning);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6da457ee57ad5794782f1f76644536e4
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -0,0 +1,295 @@
|
||||
// ----------------------------------------------------------------------------
|
||||
// <copyright file="PhotonAnimatorViewEditor.cs" company="Exit Games GmbH">
|
||||
// PhotonNetwork Framework for Unity - Copyright (C) 2018 Exit Games GmbH
|
||||
// </copyright>
|
||||
// <summary>
|
||||
// This is a custom editor for the AnimatorView component.
|
||||
// </summary>
|
||||
// <author>developer@exitgames.com</author>
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
|
||||
namespace Photon.Pun
|
||||
{
|
||||
using System.Collections.Generic;
|
||||
using UnityEditor;
|
||||
using UnityEditor.Animations;
|
||||
using UnityEngine;
|
||||
|
||||
|
||||
[CustomEditor(typeof(PhotonAnimatorView))]
|
||||
public class PhotonAnimatorViewEditor : MonoBehaviourPunEditor
|
||||
{
|
||||
private Animator m_Animator;
|
||||
private PhotonAnimatorView m_Target;
|
||||
private AnimatorController m_Controller;
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
base.OnInspectorGUI();
|
||||
|
||||
if (this.m_Animator == null)
|
||||
{
|
||||
EditorGUILayout.HelpBox("GameObject doesn't have an Animator component to synchronize", MessageType.Warning);
|
||||
return;
|
||||
}
|
||||
|
||||
this.DrawWeightInspector();
|
||||
|
||||
if (this.GetLayerCount() == 0)
|
||||
{
|
||||
EditorGUILayout.HelpBox("Animator doesn't have any layers setup to synchronize", MessageType.Warning);
|
||||
}
|
||||
|
||||
this.DrawParameterInspector();
|
||||
|
||||
if (this.GetParameterCount() == 0)
|
||||
{
|
||||
EditorGUILayout.HelpBox("Animator doesn't have any parameters setup to synchronize", MessageType.Warning);
|
||||
}
|
||||
|
||||
this.serializedObject.ApplyModifiedProperties();
|
||||
|
||||
//GUILayout.Label( "m_SynchronizeLayers " + serializedObject.FindProperty( "m_SynchronizeLayers" ).arraySize );
|
||||
//GUILayout.Label( "m_SynchronizeParameters " + serializedObject.FindProperty( "m_SynchronizeParameters" ).arraySize );
|
||||
}
|
||||
|
||||
|
||||
private int GetLayerCount()
|
||||
{
|
||||
return (this.m_Controller == null) ? 0 : this.m_Controller.layers.Length;
|
||||
}
|
||||
|
||||
private int GetParameterCount()
|
||||
{
|
||||
return (this.m_Controller == null) ? 0 : this.m_Controller.parameters.Length;
|
||||
}
|
||||
|
||||
private AnimatorControllerParameter GetAnimatorControllerParameter(int i)
|
||||
{
|
||||
return this.m_Controller.parameters[i];
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
this.m_Target = (PhotonAnimatorView)this.target;
|
||||
this.m_Animator = this.m_Target.GetComponent<Animator>();
|
||||
|
||||
if (m_Animator)
|
||||
{
|
||||
this.m_Controller = this.GetEffectiveController(this.m_Animator) as AnimatorController;
|
||||
|
||||
this.CheckIfStoredParametersExist();
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawWeightInspector()
|
||||
{
|
||||
SerializedProperty foldoutProperty = this.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);
|
||||
}
|
||||
|
||||
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(this.target, "Modify Synchronize Layer Weights");
|
||||
this.m_Target.SetLayerSynchronized(i, syncType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool DoesParameterExist(string name)
|
||||
{
|
||||
for (int i = 0; i < this.GetParameterCount(); ++i)
|
||||
{
|
||||
if (this.GetAnimatorControllerParameter(i).name == name)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private void CheckIfStoredParametersExist()
|
||||
{
|
||||
var syncedParams = this.m_Target.GetSynchronizedParameters();
|
||||
List<string> paramsToRemove = new List<string>();
|
||||
|
||||
for (int i = 0; i < syncedParams.Count; ++i)
|
||||
{
|
||||
string parameterName = syncedParams[i].Name;
|
||||
if (this.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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void DrawParameterInspector()
|
||||
{
|
||||
// flag to expose a note in Interface if one or more trigger(s) are synchronized
|
||||
bool isUsingTriggers = false;
|
||||
|
||||
SerializedProperty foldoutProperty = this.serializedObject.FindProperty("ShowParameterInspector");
|
||||
foldoutProperty.boolValue = PhotonGUI.ContainerHeaderFoldout("Synchronize Parameters", foldoutProperty.boolValue);
|
||||
|
||||
if (foldoutProperty.boolValue == false)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
float lineHeight = 20;
|
||||
Rect containerRect = PhotonGUI.ContainerBody(this.GetParameterCount() * lineHeight);
|
||||
|
||||
for (int i = 0; i < this.GetParameterCount(); i++)
|
||||
{
|
||||
AnimatorControllerParameter parameter = null;
|
||||
parameter = this.GetAnimatorControllerParameter(i);
|
||||
|
||||
string defaultValue = "";
|
||||
|
||||
if (parameter.type == AnimatorControllerParameterType.Bool)
|
||||
{
|
||||
if (Application.isPlaying && this.m_Animator.gameObject.activeInHierarchy)
|
||||
{
|
||||
defaultValue += this.m_Animator.GetBool(parameter.name);
|
||||
}
|
||||
else
|
||||
{
|
||||
defaultValue += parameter.defaultBool.ToString();
|
||||
}
|
||||
}
|
||||
else if (parameter.type == AnimatorControllerParameterType.Float)
|
||||
{
|
||||
if (Application.isPlaying && this.m_Animator.gameObject.activeInHierarchy)
|
||||
{
|
||||
defaultValue += this.m_Animator.GetFloat(parameter.name).ToString("0.00");
|
||||
}
|
||||
else
|
||||
{
|
||||
defaultValue += parameter.defaultFloat.ToString();
|
||||
}
|
||||
}
|
||||
else if (parameter.type == AnimatorControllerParameterType.Int)
|
||||
{
|
||||
if (Application.isPlaying && this.m_Animator.gameObject.activeInHierarchy)
|
||||
{
|
||||
defaultValue += this.m_Animator.GetInteger(parameter.name);
|
||||
}
|
||||
else
|
||||
{
|
||||
defaultValue += parameter.defaultInt.ToString();
|
||||
}
|
||||
}
|
||||
else if (parameter.type == AnimatorControllerParameterType.Trigger)
|
||||
{
|
||||
if (Application.isPlaying && this.m_Animator.gameObject.activeInHierarchy)
|
||||
{
|
||||
defaultValue += this.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);
|
||||
}
|
||||
|
||||
PhotonAnimatorView.SynchronizeType value = this.m_Target.GetParameterSynchronizeType(parameter.name);
|
||||
|
||||
// check if using trigger and actually synchronizing it
|
||||
if (value != PhotonAnimatorView.SynchronizeType.Disabled && parameter.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 < this.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(this.target, "Modify Synchronize Parameter " + parameter.name);
|
||||
this.m_Target.SetParameterSynchronized(parameter.name, (PhotonAnimatorView.ParameterType)parameter.type, value);
|
||||
}
|
||||
}
|
||||
|
||||
// display note when synchronized triggers are detected.
|
||||
if (isUsingTriggers)
|
||||
{
|
||||
EditorGUILayout.HelpBox("When using triggers, make sure this component is last in the stack. " +
|
||||
"If you still experience issues, implement triggers as a regular RPC " +
|
||||
"or in custom IPunObservable component instead.", MessageType.Warning);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a3f61bade114730459f7ad45f5f292c1
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
@ -0,0 +1,50 @@
|
||||
// ----------------------------------------------------------------------------
|
||||
// <copyright file="PhotonRigidbody2DViewEditor.cs" company="Exit Games GmbH">
|
||||
// PhotonNetwork Framework for Unity - Copyright (C) 2018 Exit Games GmbH
|
||||
// </copyright>
|
||||
// <summary>
|
||||
// This is a custom editor for the PhotonRigidbody2DView component.
|
||||
// </summary>
|
||||
// <author>developer@exitgames.com</author>
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
|
||||
namespace Photon.Pun
|
||||
{
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
|
||||
[CustomEditor(typeof (PhotonRigidbody2DView))]
|
||||
public class PhotonRigidbody2DViewEditor : MonoBehaviourPunEditor
|
||||
{
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
base.OnInspectorGUI();
|
||||
|
||||
if (Application.isPlaying)
|
||||
{
|
||||
EditorGUILayout.HelpBox("Editing is disabled in play mode.", MessageType.Info);
|
||||
return;
|
||||
}
|
||||
|
||||
PhotonRigidbody2DView view = (PhotonRigidbody2DView)target;
|
||||
|
||||
view.m_TeleportEnabled = PhotonGUI.ContainerHeaderToggle("Enable teleport for large distances", view.m_TeleportEnabled);
|
||||
|
||||
if (view.m_TeleportEnabled)
|
||||
{
|
||||
Rect rect = PhotonGUI.ContainerBody(20.0f);
|
||||
view.m_TeleportIfDistanceGreaterThan = EditorGUI.FloatField(rect, "Teleport if distance greater than", view.m_TeleportIfDistanceGreaterThan);
|
||||
}
|
||||
|
||||
view.m_SynchronizeVelocity = PhotonGUI.ContainerHeaderToggle("Synchronize Velocity", view.m_SynchronizeVelocity);
|
||||
view.m_SynchronizeAngularVelocity = PhotonGUI.ContainerHeaderToggle("Synchronize Angular Velocity", view.m_SynchronizeAngularVelocity);
|
||||
|
||||
if (GUI.changed)
|
||||
{
|
||||
EditorUtility.SetDirty(view);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3a82e8e86b9eecb40ac3f6ebc949f6ef
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
@ -0,0 +1,50 @@
|
||||
// ----------------------------------------------------------------------------
|
||||
// <copyright file="PhotonRigidbodyViewEditor.cs" company="Exit Games GmbH">
|
||||
// PhotonNetwork Framework for Unity - Copyright (C) 2018 Exit Games GmbH
|
||||
// </copyright>
|
||||
// <summary>
|
||||
// This is a custom editor for the RigidbodyView component.
|
||||
// </summary>
|
||||
// <author>developer@exitgames.com</author>
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
|
||||
namespace Photon.Pun
|
||||
{
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
|
||||
[CustomEditor(typeof (PhotonRigidbodyView))]
|
||||
public class PhotonRigidbodyViewEditor : MonoBehaviourPunEditor
|
||||
{
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
base.OnInspectorGUI();
|
||||
|
||||
if (Application.isPlaying)
|
||||
{
|
||||
EditorGUILayout.HelpBox("Editing is disabled in play mode.", MessageType.Info);
|
||||
return;
|
||||
}
|
||||
|
||||
PhotonRigidbodyView view = (PhotonRigidbodyView)target;
|
||||
|
||||
view.m_TeleportEnabled = PhotonGUI.ContainerHeaderToggle("Enable teleport for large distances", view.m_TeleportEnabled);
|
||||
|
||||
if (view.m_TeleportEnabled)
|
||||
{
|
||||
Rect rect = PhotonGUI.ContainerBody(20.0f);
|
||||
view.m_TeleportIfDistanceGreaterThan = EditorGUI.FloatField(rect, "Teleport if distance greater than", view.m_TeleportIfDistanceGreaterThan);
|
||||
}
|
||||
|
||||
view.m_SynchronizeVelocity = PhotonGUI.ContainerHeaderToggle("Synchronize Velocity", view.m_SynchronizeVelocity);
|
||||
view.m_SynchronizeAngularVelocity = PhotonGUI.ContainerHeaderToggle("Synchronize Angular Velocity", view.m_SynchronizeAngularVelocity);
|
||||
|
||||
if (GUI.changed)
|
||||
{
|
||||
EditorUtility.SetDirty(view);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4bcfebc9a2f1074488adedd1fe84e6c9
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
@ -0,0 +1,412 @@
|
||||
// ----------------------------------------------------------------------------
|
||||
// <copyright file="PhotonTransformViewClassicEditor.cs" company="Exit Games GmbH">
|
||||
// PhotonNetwork Framework for Unity - Copyright (C) 2018 Exit Games GmbH
|
||||
// </copyright>
|
||||
// <summary>
|
||||
// This is a custom editor for the TransformView component.
|
||||
// </summary>
|
||||
// <author>developer@exitgames.com</author>
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
|
||||
namespace Photon.Pun
|
||||
{
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
|
||||
[CustomEditor(typeof(PhotonTransformViewClassic))]
|
||||
public class PhotonTransformViewClassicEditor : MonoBehaviourPunEditor
|
||||
{
|
||||
//private PhotonTransformViewClassic 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 = "https://doc.photonengine.com/en-us/pun/current/demos-and-tutorials/package-demos/rpg-movement#interpolate_options";
|
||||
private const string EXTRAPOLATE_HELP_URL = "https://doc.photonengine.com/en-us/pun/current/demos-and-tutorials/package-demos/rpg-movement#extrapolate_options";
|
||||
|
||||
public void OnEnable()
|
||||
{
|
||||
SetupSerializedProperties();
|
||||
}
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
serializedObject.Update();
|
||||
|
||||
base.OnInspectorGUI();
|
||||
|
||||
//this.m_Target = (PhotonTransformViewClassic) 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 * 3;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 22292ca8ffb574945bedfaf49266672e
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
@ -0,0 +1,72 @@
|
||||
// ----------------------------------------------------------------------------
|
||||
// <copyright file="PhotonTransformViewEditor.cs" company="Exit Games GmbH">
|
||||
// PhotonNetwork Framework for Unity - Copyright (C) 2018 Exit Games GmbH
|
||||
// </copyright>
|
||||
// <summary>
|
||||
// This is a custom editor for the TransformView component.
|
||||
// </summary>
|
||||
// <author>developer@exitgames.com</author>
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
|
||||
namespace Photon.Pun
|
||||
{
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
|
||||
[CustomEditor(typeof(PhotonTransformView))]
|
||||
public class PhotonTransformViewEditor : Editor
|
||||
{
|
||||
private bool helpToggle = false;
|
||||
|
||||
SerializedProperty pos, rot, scl, lcl;
|
||||
|
||||
public void OnEnable()
|
||||
{
|
||||
pos = serializedObject.FindProperty("m_SynchronizePosition");
|
||||
rot = serializedObject.FindProperty("m_SynchronizeRotation");
|
||||
scl = serializedObject.FindProperty("m_SynchronizeScale");
|
||||
lcl = serializedObject.FindProperty("m_UseLocal");
|
||||
}
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
if (Application.isPlaying)
|
||||
{
|
||||
EditorGUILayout.HelpBox("Editing is disabled in play mode.", MessageType.Info);
|
||||
return;
|
||||
}
|
||||
|
||||
PhotonTransformView view = (PhotonTransformView)target;
|
||||
|
||||
|
||||
EditorGUILayout.LabelField("Synchronize Options");
|
||||
|
||||
|
||||
EditorGUI.BeginChangeCheck();
|
||||
{
|
||||
EditorGUILayout.BeginVertical("HelpBox");
|
||||
{
|
||||
EditorGUILayout.PropertyField(pos, new GUIContent("Position", pos.tooltip));
|
||||
EditorGUILayout.PropertyField(rot, new GUIContent("Rotation", rot.tooltip));
|
||||
EditorGUILayout.PropertyField(scl, new GUIContent("Scale", scl.tooltip));
|
||||
}
|
||||
EditorGUILayout.EndHorizontal();
|
||||
|
||||
EditorGUILayout.PropertyField(lcl, new GUIContent("Use Local", lcl.tooltip));
|
||||
}
|
||||
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
}
|
||||
|
||||
this.helpToggle = EditorGUILayout.Foldout(this.helpToggle, "Info");
|
||||
if (this.helpToggle)
|
||||
{
|
||||
EditorGUILayout.HelpBox("The Photon Transform View of PUN 2 is simple by design.\nReplace it with the Photon Transform View Classic if you want the old options.\nThe best solution is a custom IPunObservable implementation.", MessageType.Info, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a8c9ec475ad103b43b901d942ff66e02
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
BIN
Assets/Photon/PhotonUnityNetworking/Code/Editor/help.png
Normal file
BIN
Assets/Photon/PhotonUnityNetworking/Code/Editor/help.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.3 KiB |
@ -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:
|
94
Assets/Photon/PhotonUnityNetworking/Code/Enums.cs
Normal file
94
Assets/Photon/PhotonUnityNetworking/Code/Enums.cs
Normal file
@ -0,0 +1,94 @@
|
||||
// ----------------------------------------------------------------------------
|
||||
// <copyright file="Enums.cs" company="Exit Games GmbH">
|
||||
// PhotonNetwork Framework for Unity - Copyright (C) 2018 Exit Games GmbH
|
||||
// </copyright>
|
||||
// <summary>
|
||||
// Wraps up several enumerations for PUN.
|
||||
// </summary>
|
||||
// <author>developer@exitgames.com</author>
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
|
||||
namespace Photon.Pun
|
||||
{
|
||||
/// <summary>Which PhotonNetwork method was called to connect (which influences the regions we want pinged).</summary>
|
||||
/// <remarks>PhotonNetwork.ConnectUsingSettings will call either ConnectToMaster, ConnectToRegion or ConnectToBest, depending on the settings.</remarks>
|
||||
public enum ConnectMethod { NotCalled, ConnectToMaster, ConnectToRegion, ConnectToBest }
|
||||
|
||||
|
||||
/// <summary>Used to define the level of logging output created by the PUN classes. Either log errors, info (some more) or full.</summary>
|
||||
/// \ingroup publicApi
|
||||
public enum PunLogLevel
|
||||
{
|
||||
/// <summary>Show only errors. Minimal output. Note: Some might be "runtime errors" which you have to expect.</summary>
|
||||
ErrorsOnly,
|
||||
|
||||
/// <summary>Logs some of the workflow, calls and results.</summary>
|
||||
Informational,
|
||||
|
||||
/// <summary>Every available log call gets into the console/log. Only use for debugging.</summary>
|
||||
Full
|
||||
}
|
||||
|
||||
|
||||
/// <summary>Enum of "target" options for RPCs. These define which remote clients get your RPC call. </summary>
|
||||
/// \ingroup publicApi
|
||||
public enum RpcTarget
|
||||
{
|
||||
/// <summary>Sends the RPC to everyone else and executes it immediately on this client. Player who join later will not execute this RPC.</summary>
|
||||
All,
|
||||
|
||||
/// <summary>Sends the RPC to everyone else. This client does not execute the RPC. Player who join later will not execute this RPC.</summary>
|
||||
Others,
|
||||
|
||||
/// <summary>Sends the RPC to MasterClient only. Careful: The MasterClient might disconnect before it executes the RPC and that might cause dropped RPCs.</summary>
|
||||
MasterClient,
|
||||
|
||||
/// <summary>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).</summary>
|
||||
AllBuffered,
|
||||
|
||||
/// <summary>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).</summary>
|
||||
OthersBuffered,
|
||||
|
||||
/// <summary>Sends the RPC to everyone (including this client) through the server.</summary>
|
||||
/// <remarks>
|
||||
/// 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.
|
||||
/// </remarks>
|
||||
AllViaServer,
|
||||
|
||||
/// <summary>Sends the RPC to everyone (including this client) through the server and buffers it for players joining later.</summary>
|
||||
/// <remarks>
|
||||
/// 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.
|
||||
/// </remarks>
|
||||
AllBufferedViaServer
|
||||
}
|
||||
|
||||
|
||||
public enum ViewSynchronization { Off, ReliableDeltaCompressed, Unreliable, UnreliableOnChange }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Options to define how Ownership Transfer is handled per PhotonView.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This setting affects how RequestOwnership and TransferOwnership work at runtime.
|
||||
/// </remarks>
|
||||
public enum OwnershipOption
|
||||
{
|
||||
/// <summary>
|
||||
/// Ownership is fixed. Instantiated objects stick with their creator, room objects always belong to the Master Client.
|
||||
/// </summary>
|
||||
Fixed,
|
||||
/// <summary>
|
||||
/// Ownership can be taken away from the current owner who can't object.
|
||||
/// </summary>
|
||||
Takeover,
|
||||
/// <summary>
|
||||
/// Ownership can be requested with PhotonView.RequestOwnership but the current owner has to agree to give up ownership.
|
||||
/// </summary>
|
||||
/// <remarks>The current owner has to implement IPunCallbacks.OnOwnershipRequest to react to the ownership request.</remarks>
|
||||
Request
|
||||
}
|
||||
}
|
12
Assets/Photon/PhotonUnityNetworking/Code/Enums.cs.meta
Normal file
12
Assets/Photon/PhotonUnityNetworking/Code/Enums.cs.meta
Normal file
@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b7962bbdaba2a4940b1341d755abd40d
|
||||
labels:
|
||||
- ExitGames
|
||||
- PUN
|
||||
- Photon
|
||||
- Networking
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
8
Assets/Photon/PhotonUnityNetworking/Code/Interfaces.meta
Normal file
8
Assets/Photon/PhotonUnityNetworking/Code/Interfaces.meta
Normal file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 38ae0eecc6fe5d340b82bb221198aa89
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -0,0 +1,50 @@
|
||||
namespace Photon.Pun
|
||||
{
|
||||
using Photon.Realtime;
|
||||
|
||||
/// <summary>
|
||||
/// Empty Base class for all PhotonView callbacks.
|
||||
/// </summary>
|
||||
public interface IPhotonViewCallback
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This interface defines a callback which fires prior to the PhotonNetwork destroying the PhotonView and Gameobject.
|
||||
/// </summary>
|
||||
public interface IOnPhotonViewPreNetDestroy : IPhotonViewCallback
|
||||
{
|
||||
/// <summary>
|
||||
/// This method is called before Destroy() is initiated for a networked object.
|
||||
/// </summary>
|
||||
/// <param name="rootView"></param>
|
||||
void OnPreNetDestroy(PhotonView rootView);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This interface defines a callback for changes to the PhotonView's owner.
|
||||
/// </summary>
|
||||
public interface IOnPhotonViewOwnerChange : IPhotonViewCallback
|
||||
{
|
||||
/// <summary>
|
||||
/// This method will be called when the PhotonView's owner changes.
|
||||
/// </summary>
|
||||
/// <param name="newOwner"></param>
|
||||
/// <param name="previousOwner"></param>
|
||||
void OnOwnerChange(Player newOwner, Player previousOwner);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This interface defines a callback for changes to the PhotonView's controller.
|
||||
/// </summary>
|
||||
public interface IOnPhotonViewControllerChange : IPhotonViewCallback
|
||||
{
|
||||
/// <summary>
|
||||
/// This method will be called when the PhotonView's controller changes.
|
||||
/// </summary>
|
||||
/// <param name="newOwner"></param>
|
||||
/// <param name="previousOwner"></param>
|
||||
void OnControllerChange(Player newController, Player previousController);
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d67b3e094fcbf004da7f8771c17126f3
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -0,0 +1,141 @@
|
||||
|
||||
namespace Photon.Pun
|
||||
{
|
||||
using UnityEngine;
|
||||
using Photon.Realtime;
|
||||
|
||||
|
||||
/// <summary>Defines the OnPhotonSerializeView method to make it easy to implement correctly for observable scripts.</summary>
|
||||
/// \ingroup callbacks
|
||||
public interface IPunObservable
|
||||
{
|
||||
/// <summary>
|
||||
/// Called by PUN several times per second, so that your script can write and read synchronization data for the PhotonView.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This method will be called in scripts that are assigned as Observed component of a PhotonView.<br/>
|
||||
/// PhotonNetwork.SerializationRate affects how often this method is called.<br/>
|
||||
/// PhotonNetwork.SendRate affects how often packages are sent by this client.<br/>
|
||||
///
|
||||
/// 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, <i>OnPhotonSerializeView only gets called when it is assigned
|
||||
/// to a PhotonView</i> 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()".
|
||||
/// </remarks>
|
||||
/// \ingroup publicApi
|
||||
void OnPhotonSerializeView(PhotonStream stream, PhotonMessageInfo info);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Global Callback interface for ownership changes. These callbacks will fire for changes to ANY PhotonView that changes.
|
||||
/// Consider using IOnPhotonViewControllerChange for callbacks from a specific PhotonView.
|
||||
/// </summary>
|
||||
public interface IPunOwnershipCallbacks
|
||||
{
|
||||
/// <summary>
|
||||
/// Called when another player requests ownership of a PhotonView.
|
||||
/// Called on all clients, so check if (targetView.IsMine) or (targetView.Owner == PhotonNetwork.LocalPlayer)
|
||||
/// to determine if a targetView.TransferOwnership(requestingPlayer) response should be given.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The parameter viewAndPlayer contains:
|
||||
///
|
||||
/// PhotonView view = viewAndPlayer[0] as PhotonView;
|
||||
///
|
||||
/// Player requestingPlayer = viewAndPlayer[1] as Player;
|
||||
/// </remarks>
|
||||
/// <param name="targetView">PhotonView for which ownership gets requested.</param>
|
||||
/// <param name="requestingPlayer">Player who requests ownership.</param>
|
||||
void OnOwnershipRequest(PhotonView targetView, Player requestingPlayer);
|
||||
|
||||
/// <summary>
|
||||
/// Called when ownership of a PhotonView is transfered to another player.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The parameter viewAndPlayers contains:
|
||||
///
|
||||
/// PhotonView view = viewAndPlayers[0] as PhotonView;
|
||||
///
|
||||
/// Player newOwner = viewAndPlayers[1] as Player;
|
||||
///
|
||||
/// Player oldOwner = viewAndPlayers[2] as Player;
|
||||
/// </remarks>
|
||||
/// <example>void OnOwnershipTransfered(object[] viewAndPlayers) {} //</example>
|
||||
/// <param name="targetView">PhotonView for which ownership changed.</param>
|
||||
/// <param name="previousOwner">Player who was the previous owner (or null, if none).</param>
|
||||
void OnOwnershipTransfered(PhotonView targetView, Player previousOwner);
|
||||
|
||||
/// <summary>
|
||||
/// Called when an Ownership Request fails for objects with "takeover" setting.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Each request asks to take ownership from a specific controlling player. This can fail if anyone
|
||||
/// else took over ownership briefly before the request arrived.
|
||||
/// </remarks>
|
||||
/// <param name="targetView"></param>
|
||||
/// <param name="senderOfFailedRequest"></param>
|
||||
void OnOwnershipTransferFailed(PhotonView targetView, Player senderOfFailedRequest);
|
||||
}
|
||||
|
||||
/// \ingroup callbacks
|
||||
public interface IPunInstantiateMagicCallback
|
||||
{
|
||||
void OnPhotonInstantiate(PhotonMessageInfo info);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Defines an interface for object pooling, used in PhotonNetwork.Instantiate and PhotonNetwork.Destroy.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// To apply your custom IPunPrefabPool, set PhotonNetwork.PrefabPool.
|
||||
///
|
||||
/// The pool has to return a valid, disabled GameObject when PUN calls Instantiate.
|
||||
/// Also, the position and rotation must be applied.
|
||||
///
|
||||
/// Note that Awake and Start are only called once by Unity, so scripts on re-used GameObjects
|
||||
/// should make use of OnEnable and or OnDisable. When OnEnable gets called, the PhotonView
|
||||
/// is already updated to the new values.
|
||||
///
|
||||
/// To be able to enable a GameObject, Instantiate must return an inactive object.
|
||||
///
|
||||
/// Before PUN "destroys" GameObjects, it will disable them.
|
||||
///
|
||||
/// If a component implements IPunInstantiateMagicCallback, PUN will call OnPhotonInstantiate
|
||||
/// when the networked object gets instantiated. If no components implement this on a prefab,
|
||||
/// PUN will optimize the instantiation and no longer looks up IPunInstantiateMagicCallback
|
||||
/// via GetComponents.
|
||||
/// </remarks>
|
||||
public interface IPunPrefabPool
|
||||
{
|
||||
/// <summary>
|
||||
/// Called to get an instance of a prefab. Must return valid, disabled GameObject with PhotonView.
|
||||
/// </summary>
|
||||
/// <param name="prefabId">The id of this prefab.</param>
|
||||
/// <param name="position">The position for the instance.</param>
|
||||
/// <param name="rotation">The rotation for the instance.</param>
|
||||
/// <returns>A disabled instance to use by PUN or null if the prefabId is unknown.</returns>
|
||||
GameObject Instantiate(string prefabId, Vector3 position, Quaternion rotation);
|
||||
|
||||
/// <summary>
|
||||
/// Called to destroy (or just return) the instance of a prefab. It's disabled and the pool may reset and cache it for later use in Instantiate.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// A pool needs some way to find out which type of GameObject got returned via Destroy().
|
||||
/// It could be a tag, name, a component or anything similar.
|
||||
/// </remarks>
|
||||
/// <param name="gameObject">The instance to destroy.</param>
|
||||
void Destroy(GameObject gameObject);
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 421c323e36c065045b2c44e16a184a9a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
401
Assets/Photon/PhotonUnityNetworking/Code/PhotonHandler.cs
Normal file
401
Assets/Photon/PhotonUnityNetworking/Code/PhotonHandler.cs
Normal file
@ -0,0 +1,401 @@
|
||||
// ----------------------------------------------------------------------------
|
||||
// <copyright file="PhotonHandler.cs" company="Exit Games GmbH">
|
||||
// PhotonNetwork Framework for Unity - Copyright (C) 2018 Exit Games GmbH
|
||||
// </copyright>
|
||||
// <summary>
|
||||
// PhotonHandler is a runtime MonoBehaviour to include PUN into the main loop.
|
||||
// </summary>
|
||||
// <author>developer@exitgames.com</author>
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
|
||||
namespace Photon.Pun
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using ExitGames.Client.Photon;
|
||||
using Photon.Realtime;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Profiling;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Internal MonoBehaviour that allows Photon to run an Update loop.
|
||||
/// </summary>
|
||||
public class PhotonHandler : ConnectionHandler, IInRoomCallbacks, IMatchmakingCallbacks
|
||||
{
|
||||
|
||||
private static PhotonHandler instance;
|
||||
internal static PhotonHandler Instance
|
||||
{
|
||||
get
|
||||
{
|
||||
if (instance == null)
|
||||
{
|
||||
instance = FindObjectOfType<PhotonHandler>();
|
||||
if (instance == null)
|
||||
{
|
||||
GameObject obj = new GameObject();
|
||||
obj.name = "PhotonMono";
|
||||
instance = obj.AddComponent<PhotonHandler>();
|
||||
}
|
||||
}
|
||||
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>Limits the number of datagrams that are created in each LateUpdate.</summary>
|
||||
/// <remarks>Helps spreading out sending of messages minimally.</remarks>
|
||||
public static int MaxDatagrams = 3;
|
||||
|
||||
/// <summary>Signals that outgoing messages should be sent in the next LateUpdate call.</summary>
|
||||
/// <remarks>Up to MaxDatagrams are created to send queued messages.</remarks>
|
||||
public static bool SendAsap;
|
||||
|
||||
/// <summary>This corrects the "next time to serialize the state" value by some ms.</summary>
|
||||
/// <remarks>As LateUpdate typically gets called every 15ms it's better to be early(er) than late to achieve a SerializeRate.</remarks>
|
||||
private const int SerializeRateFrameCorrection = 8;
|
||||
|
||||
protected internal int UpdateInterval; // time [ms] between consecutive SendOutgoingCommands calls
|
||||
|
||||
protected internal int UpdateIntervalOnSerialize; // time [ms] between consecutive RunViewUpdate calls (sending syncs, etc)
|
||||
|
||||
private int nextSendTickCount;
|
||||
|
||||
private int nextSendTickCountOnSerialize;
|
||||
|
||||
private SupportLogger supportLoggerComponent;
|
||||
|
||||
|
||||
protected override void Awake()
|
||||
{
|
||||
if (instance == null || ReferenceEquals(this, instance))
|
||||
{
|
||||
instance = this;
|
||||
base.Awake();
|
||||
}
|
||||
else
|
||||
{
|
||||
Destroy(this);
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void OnEnable()
|
||||
{
|
||||
if (Instance != this)
|
||||
{
|
||||
Debug.LogError("PhotonHandler is a singleton but there are multiple instances. this != Instance.");
|
||||
return;
|
||||
}
|
||||
|
||||
this.Client = PhotonNetwork.NetworkingClient;
|
||||
|
||||
if (PhotonNetwork.PhotonServerSettings.EnableSupportLogger)
|
||||
{
|
||||
SupportLogger supportLogger = this.gameObject.GetComponent<SupportLogger>();
|
||||
if (supportLogger == null)
|
||||
{
|
||||
supportLogger = this.gameObject.AddComponent<SupportLogger>();
|
||||
}
|
||||
if (this.supportLoggerComponent != null)
|
||||
{
|
||||
if (supportLogger.GetInstanceID() != this.supportLoggerComponent.GetInstanceID())
|
||||
{
|
||||
Debug.LogWarningFormat("Cached SupportLogger component is different from the one attached to PhotonMono GameObject");
|
||||
}
|
||||
}
|
||||
this.supportLoggerComponent = supportLogger;
|
||||
this.supportLoggerComponent.Client = PhotonNetwork.NetworkingClient;
|
||||
}
|
||||
|
||||
this.UpdateInterval = 1000 / PhotonNetwork.SendRate;
|
||||
this.UpdateIntervalOnSerialize = 1000 / PhotonNetwork.SerializationRate;
|
||||
|
||||
PhotonNetwork.AddCallbackTarget(this);
|
||||
this.StartFallbackSendAckThread(); // this is not done in the base class
|
||||
}
|
||||
|
||||
protected void Start()
|
||||
{
|
||||
UnityEngine.SceneManagement.SceneManager.sceneLoaded += (scene, loadingMode) =>
|
||||
{
|
||||
PhotonNetwork.NewSceneLoaded();
|
||||
};
|
||||
}
|
||||
|
||||
protected override void OnDisable()
|
||||
{
|
||||
PhotonNetwork.RemoveCallbackTarget(this);
|
||||
base.OnDisable();
|
||||
}
|
||||
|
||||
|
||||
/// <summary>Called in intervals by UnityEngine. Affected by Time.timeScale.</summary>
|
||||
protected void FixedUpdate()
|
||||
{
|
||||
#if PUN_DISPATCH_IN_FIXEDUPDATE
|
||||
this.Dispatch();
|
||||
#elif PUN_DISPATCH_IN_LATEUPDATE
|
||||
// do not dispatch here
|
||||
#else
|
||||
if (Time.timeScale > PhotonNetwork.MinimalTimeScaleToDispatchInFixedUpdate)
|
||||
{
|
||||
this.Dispatch();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>Called in intervals by UnityEngine, after running the normal game code and physics.</summary>
|
||||
protected void LateUpdate()
|
||||
{
|
||||
#if PUN_DISPATCH_IN_LATEUPDATE
|
||||
this.Dispatch();
|
||||
#elif PUN_DISPATCH_IN_FIXEDUPDATE
|
||||
// do not dispatch here
|
||||
#else
|
||||
// see MinimalTimeScaleToDispatchInFixedUpdate and FixedUpdate for explanation:
|
||||
if (Time.timeScale <= PhotonNetwork.MinimalTimeScaleToDispatchInFixedUpdate)
|
||||
{
|
||||
this.Dispatch();
|
||||
}
|
||||
#endif
|
||||
|
||||
int currentMsSinceStart = (int)(Time.realtimeSinceStartup * 1000); // avoiding Environment.TickCount, which could be negative on long-running platforms
|
||||
if (PhotonNetwork.IsMessageQueueRunning && currentMsSinceStart > this.nextSendTickCountOnSerialize)
|
||||
{
|
||||
PhotonNetwork.RunViewUpdate();
|
||||
this.nextSendTickCountOnSerialize = currentMsSinceStart + this.UpdateIntervalOnSerialize - SerializeRateFrameCorrection;
|
||||
this.nextSendTickCount = 0; // immediately send when synchronization code was running
|
||||
}
|
||||
|
||||
currentMsSinceStart = (int)(Time.realtimeSinceStartup * 1000);
|
||||
if (SendAsap || currentMsSinceStart > this.nextSendTickCount)
|
||||
{
|
||||
SendAsap = false;
|
||||
bool doSend = true;
|
||||
int sendCounter = 0;
|
||||
while (PhotonNetwork.IsMessageQueueRunning && doSend && sendCounter < MaxDatagrams)
|
||||
{
|
||||
// Send all outgoing commands
|
||||
Profiler.BeginSample("SendOutgoingCommands");
|
||||
doSend = PhotonNetwork.NetworkingClient.LoadBalancingPeer.SendOutgoingCommands();
|
||||
sendCounter++;
|
||||
Profiler.EndSample();
|
||||
}
|
||||
|
||||
this.nextSendTickCount = currentMsSinceStart + this.UpdateInterval;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Dispatches incoming network messages for PUN. Called in FixedUpdate or LateUpdate.</summary>
|
||||
/// <remarks>
|
||||
/// It may make sense to dispatch incoming messages, even if the timeScale is near 0.
|
||||
/// That can be configured with PhotonNetwork.MinimalTimeScaleToDispatchInFixedUpdate.
|
||||
///
|
||||
/// Without dispatching messages, PUN won't change state and does not handle updates.
|
||||
/// </remarks>
|
||||
protected void Dispatch()
|
||||
{
|
||||
if (PhotonNetwork.NetworkingClient == null)
|
||||
{
|
||||
Debug.LogError("NetworkPeer broke!");
|
||||
return;
|
||||
}
|
||||
|
||||
//if (PhotonNetwork.NetworkClientState == ClientState.PeerCreated || PhotonNetwork.NetworkClientState == ClientState.Disconnected || PhotonNetwork.OfflineMode)
|
||||
//{
|
||||
// return;
|
||||
//}
|
||||
|
||||
|
||||
bool doDispatch = true;
|
||||
Exception ex = null;
|
||||
int exceptionCount = 0;
|
||||
while (PhotonNetwork.IsMessageQueueRunning && doDispatch)
|
||||
{
|
||||
// DispatchIncomingCommands() returns true of it dispatched any command (event, response or state change)
|
||||
Profiler.BeginSample("DispatchIncomingCommands");
|
||||
try
|
||||
{
|
||||
doDispatch = PhotonNetwork.NetworkingClient.LoadBalancingPeer.DispatchIncomingCommands();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
exceptionCount++;
|
||||
if (ex == null)
|
||||
{
|
||||
ex = e;
|
||||
}
|
||||
}
|
||||
|
||||
Profiler.EndSample();
|
||||
}
|
||||
|
||||
if (ex != null)
|
||||
{
|
||||
throw new AggregateException("Caught " + exceptionCount + " exception(s) in methods called by DispatchIncomingCommands(). Rethrowing first only (see above).", ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void OnCreatedRoom()
|
||||
{
|
||||
PhotonNetwork.SetLevelInPropsIfSynced(SceneManagerHelper.ActiveSceneName);
|
||||
}
|
||||
|
||||
public void OnRoomPropertiesUpdate(Hashtable propertiesThatChanged)
|
||||
{
|
||||
PhotonNetwork.LoadLevelIfSynced();
|
||||
}
|
||||
|
||||
|
||||
public void OnPlayerPropertiesUpdate(Player targetPlayer, Hashtable changedProps) { }
|
||||
|
||||
public void OnMasterClientSwitched(Player newMasterClient)
|
||||
{
|
||||
var views = PhotonNetwork.PhotonViewCollection;
|
||||
foreach (var view in views)
|
||||
{
|
||||
if (view.IsRoomView)
|
||||
{
|
||||
view.OwnerActorNr= newMasterClient.ActorNumber;
|
||||
view.ControllerActorNr = newMasterClient.ActorNumber;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void OnFriendListUpdate(System.Collections.Generic.List<FriendInfo> friendList) { }
|
||||
|
||||
public void OnCreateRoomFailed(short returnCode, string message) { }
|
||||
|
||||
public void OnJoinRoomFailed(short returnCode, string message) { }
|
||||
|
||||
public void OnJoinRandomFailed(short returnCode, string message) { }
|
||||
|
||||
protected List<int> reusableIntList = new List<int>();
|
||||
|
||||
public void OnJoinedRoom()
|
||||
{
|
||||
|
||||
if (PhotonNetwork.ViewCount == 0)
|
||||
return;
|
||||
|
||||
var views = PhotonNetwork.PhotonViewCollection;
|
||||
|
||||
bool amMasterClient = PhotonNetwork.IsMasterClient;
|
||||
bool amRejoiningMaster = amMasterClient && PhotonNetwork.CurrentRoom.PlayerCount > 1;
|
||||
|
||||
if (amRejoiningMaster)
|
||||
reusableIntList.Clear();
|
||||
|
||||
// If this is the master rejoining, reassert ownership of non-creator owners
|
||||
foreach (var view in views)
|
||||
{
|
||||
int viewOwnerId = view.OwnerActorNr;
|
||||
int viewCreatorId = view.CreatorActorNr;
|
||||
|
||||
// on join / rejoin, assign control to either the Master Client (for room objects) or the owner (for anything else)
|
||||
view.RebuildControllerCache();
|
||||
|
||||
// Rejoining master should enforce its world view, and override any changes that happened while it was soft disconnected
|
||||
if (amRejoiningMaster)
|
||||
if (viewOwnerId != viewCreatorId)
|
||||
{
|
||||
reusableIntList.Add(view.ViewID);
|
||||
reusableIntList.Add(viewOwnerId);
|
||||
}
|
||||
}
|
||||
|
||||
if (amRejoiningMaster && reusableIntList.Count > 0)
|
||||
{
|
||||
PhotonNetwork.OwnershipUpdate(reusableIntList.ToArray());
|
||||
}
|
||||
}
|
||||
|
||||
public void OnLeftRoom()
|
||||
{
|
||||
// Destroy spawned objects and reset scene objects
|
||||
PhotonNetwork.LocalCleanupAnythingInstantiated(true);
|
||||
}
|
||||
|
||||
|
||||
public void OnPlayerEnteredRoom(Player newPlayer)
|
||||
{
|
||||
// note: if the master client becomes inactive, someone else becomes master. so there is no case where the active master client reconnects
|
||||
// what may happen is that the Master Client disconnects locally and uses ReconnectAndRejoin before anyone (including the server) notices.
|
||||
|
||||
bool amMasterClient = PhotonNetwork.IsMasterClient;
|
||||
|
||||
var views = PhotonNetwork.PhotonViewCollection;
|
||||
if (amMasterClient)
|
||||
{
|
||||
reusableIntList.Clear();
|
||||
}
|
||||
|
||||
foreach (var view in views)
|
||||
{
|
||||
view.RebuildControllerCache(); // all clients will potentially have to clean up owner and controller, if someone re-joins
|
||||
|
||||
// the master client notifies joining players of any non-creator ownership
|
||||
if (amMasterClient)
|
||||
{
|
||||
int viewOwnerId = view.OwnerActorNr;
|
||||
if (viewOwnerId != view.CreatorActorNr)
|
||||
{
|
||||
reusableIntList.Add(view.ViewID);
|
||||
reusableIntList.Add(viewOwnerId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// update the joining player of non-creator ownership in the room
|
||||
if (amMasterClient && reusableIntList.Count > 0)
|
||||
{
|
||||
PhotonNetwork.OwnershipUpdate(reusableIntList.ToArray(), newPlayer.ActorNumber);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void OnPlayerLeftRoom(Player otherPlayer)
|
||||
{
|
||||
var views = PhotonNetwork.PhotonViewCollection;
|
||||
|
||||
int leavingPlayerId = otherPlayer.ActorNumber;
|
||||
bool isInactive = otherPlayer.IsInactive;
|
||||
|
||||
// SOFT DISCONNECT: A player has timed out to the relay but has not yet exceeded PlayerTTL and may reconnect.
|
||||
// Master will take control of this objects until the player hard disconnects, or returns.
|
||||
if (isInactive)
|
||||
{
|
||||
foreach (var view in views)
|
||||
{
|
||||
// v2.27: changed from owner-check to controller-check
|
||||
if (view.ControllerActorNr == leavingPlayerId)
|
||||
view.ControllerActorNr = PhotonNetwork.MasterClient.ActorNumber;
|
||||
}
|
||||
|
||||
}
|
||||
// HARD DISCONNECT: Player permanently removed. Remove that actor as owner for all items they created (Unless AutoCleanUp is false)
|
||||
else
|
||||
{
|
||||
bool autocleanup = PhotonNetwork.CurrentRoom.AutoCleanUp;
|
||||
|
||||
foreach (var view in views)
|
||||
{
|
||||
// Skip changing Owner/Controller for items that will be cleaned up.
|
||||
if (autocleanup && view.CreatorActorNr == leavingPlayerId)
|
||||
continue;
|
||||
|
||||
// Any views owned by the leaving player, default to null owner (which will become master controlled).
|
||||
if (view.OwnerActorNr == leavingPlayerId || view.ControllerActorNr == leavingPlayerId)
|
||||
{
|
||||
view.OwnerActorNr = 0;
|
||||
view.ControllerActorNr = PhotonNetwork.MasterClient.ActorNumber;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 177bddf229f8d8445a70c0652f03b7df
|
||||
labels:
|
||||
- ExitGames
|
||||
- PUN
|
||||
- Photon
|
||||
- Networking
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
3312
Assets/Photon/PhotonUnityNetworking/Code/PhotonNetwork.cs
Normal file
3312
Assets/Photon/PhotonUnityNetworking/Code/PhotonNetwork.cs
Normal file
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 88e11b3353de7e94d84b1ec5adbdd15e
|
||||
labels:
|
||||
- ExitGames
|
||||
- PUN
|
||||
- Photon
|
||||
- Networking
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
2559
Assets/Photon/PhotonUnityNetworking/Code/PhotonNetworkPart.cs
Normal file
2559
Assets/Photon/PhotonUnityNetworking/Code/PhotonNetworkPart.cs
Normal file
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cbf2b3734a024f842bd50f8738feb400
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
197
Assets/Photon/PhotonUnityNetworking/Code/PhotonStreamQueue.cs
Normal file
197
Assets/Photon/PhotonUnityNetworking/Code/PhotonStreamQueue.cs
Normal file
@ -0,0 +1,197 @@
|
||||
// ----------------------------------------------------------------------------
|
||||
// <copyright file="PhotonStreamQueue.cs" company="Exit Games GmbH">
|
||||
// PhotonNetwork Framework for Unity - Copyright (C) 2018 Exit Games GmbH
|
||||
// </copyright>
|
||||
// <summary>
|
||||
// Contains the PhotonStreamQueue.
|
||||
// </summary>
|
||||
// <author>developer@exitgames.com</author>
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
|
||||
namespace Photon.Pun
|
||||
{
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
/// <summary>
|
||||
/// The PhotonStreamQueue helps you poll object states at higher frequencies than 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.
|
||||
/// </summary>
|
||||
public class PhotonStreamQueue
|
||||
{
|
||||
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<object> m_Objects = new List<object>();
|
||||
|
||||
private bool m_IsWriting;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="PhotonStreamQueue"/> class.
|
||||
/// </summary>
|
||||
/// <param name="sampleRate">How many times per second should the object states be sampled</param>
|
||||
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 );
|
||||
}*/
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resets the PhotonStreamQueue. You need to do this whenever the amount of objects you are observing changes
|
||||
/// </summary>
|
||||
public void Reset()
|
||||
{
|
||||
this.m_SampleCount = 0;
|
||||
this.m_ObjectsPerSample = -1;
|
||||
|
||||
this.m_LastSampleTime = -Mathf.Infinity;
|
||||
this.m_LastFrameCount = -1;
|
||||
|
||||
this.m_Objects.Clear();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds the next object to the queue. This works just like PhotonStream.SendNext
|
||||
/// </summary>
|
||||
/// <param name="obj">The object you want to add to the queue</param>
|
||||
public void SendNext(object obj)
|
||||
{
|
||||
if (Time.frameCount != this.m_LastFrameCount)
|
||||
{
|
||||
this.BeginWritePackage();
|
||||
}
|
||||
|
||||
this.m_LastFrameCount = Time.frameCount;
|
||||
|
||||
if (this.m_IsWriting == false)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
this.m_Objects.Add(obj);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the queue has stored any objects
|
||||
/// </summary>
|
||||
public bool HasQueuedObjects()
|
||||
{
|
||||
return this.m_NextObjectIndex != -1;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Receives the next object from the queue. This works just like PhotonStream.ReceiveNext
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
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++];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Serializes the specified stream. Call this in your OnPhotonSerializeView method to send the whole recorded stream.
|
||||
/// </summary>
|
||||
/// <param name="stream">The PhotonStream you receive as a parameter in OnPhotonSerializeView</param>
|
||||
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 (this.m_Objects.Count > 0 && this.m_ObjectsPerSample < 0)
|
||||
{
|
||||
this.m_ObjectsPerSample = this.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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deserializes the specified stream. Call this in your OnPhotonSerializeView method to receive the whole recorded stream.
|
||||
/// </summary>
|
||||
/// <param name="stream">The PhotonStream you receive as a parameter in OnPhotonSerializeView</param>
|
||||
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 ) );
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 006991e32d9020c4d896f161318a2bc0
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
@ -0,0 +1,10 @@
|
||||
{
|
||||
"name": "PhotonUnityNetworking",
|
||||
"references": [
|
||||
"PhotonRealtime"
|
||||
],
|
||||
"optionalUnityReferences": [],
|
||||
"includePlatforms": [],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": false
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 57c32fc907df0f54e8e6e8f0d2488336
|
||||
timeCreated: 1537459565
|
||||
licenseType: Store
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
826
Assets/Photon/PhotonUnityNetworking/Code/PhotonView.cs
Normal file
826
Assets/Photon/PhotonUnityNetworking/Code/PhotonView.cs
Normal file
@ -0,0 +1,826 @@
|
||||
// ----------------------------------------------------------------------------
|
||||
// <copyright file="PhotonView.cs" company="Exit Games GmbH">
|
||||
// PhotonNetwork Framework for Unity - Copyright (C) 2018 Exit Games GmbH
|
||||
// </copyright>
|
||||
// <summary>
|
||||
// Contains the PhotonView class.
|
||||
// </summary>
|
||||
// <author>developer@exitgames.com</author>
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
|
||||
namespace Photon.Pun
|
||||
{
|
||||
using System;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Serialization;
|
||||
using System.Collections.Generic;
|
||||
using Photon.Realtime;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// A PhotonView identifies an object across the network (viewID) and configures how the controlling client updates remote instances.
|
||||
/// </summary>
|
||||
/// \ingroup publicApi
|
||||
[AddComponentMenu("Photon Networking/Photon View")]
|
||||
public class PhotonView : MonoBehaviour
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
[UnityEditor.InitializeOnLoadMethod]
|
||||
private static void SetPhotonViewExecutionOrder()
|
||||
{
|
||||
int photonViewExecutionOrder = -16000;
|
||||
GameObject go = new GameObject();
|
||||
PhotonView pv = go.AddComponent<PhotonView>();
|
||||
MonoScript monoScript = MonoScript.FromMonoBehaviour(pv);
|
||||
|
||||
if (photonViewExecutionOrder != MonoImporter.GetExecutionOrder(monoScript))
|
||||
{
|
||||
MonoImporter.SetExecutionOrder(monoScript, photonViewExecutionOrder); // very early but allows other scripts to run even earlier...
|
||||
}
|
||||
|
||||
DestroyImmediate(go);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if UNITY_EDITOR
|
||||
[ContextMenu("Open PUN Wizard")]
|
||||
void OpenPunWizard()
|
||||
{
|
||||
EditorApplication.ExecuteMenuItem("Window/Photon Unity Networking/PUN Wizard");
|
||||
}
|
||||
#endif
|
||||
|
||||
#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
|
||||
|
||||
#if UNITY_EDITOR
|
||||
/// called by Editor to reset the component
|
||||
private void Reset()
|
||||
{
|
||||
observableSearch = ObservableSearch.AutoFindAll;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
[FormerlySerializedAs("group")]
|
||||
public byte Group = 0;
|
||||
|
||||
// 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 prefixField 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.prefixField == -1 && PhotonNetwork.NetworkingClient != null)
|
||||
{
|
||||
this.prefixField = PhotonNetwork.currentLevelPrefix;
|
||||
}
|
||||
|
||||
return this.prefixField;
|
||||
}
|
||||
set { this.prefixField = value; }
|
||||
}
|
||||
|
||||
// this field is serialized by unity. that means it is copied when instantiating a persistent obj into the scene
|
||||
[FormerlySerializedAs("prefixBackup")]
|
||||
public int prefixField = -1;
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// This is the InstantiationData that was passed when calling PhotonNetwork.Instantiate* (if that was used to spawn this prefab)
|
||||
/// </summary>
|
||||
public object[] InstantiationData
|
||||
{
|
||||
get { return this.instantiationDataField; }
|
||||
protected internal set { this.instantiationDataField = value; }
|
||||
}
|
||||
|
||||
internal object[] instantiationDataField;
|
||||
|
||||
/// <summary>
|
||||
/// For internal use only, don't use
|
||||
/// </summary>
|
||||
protected internal List<object> lastOnSerializeDataSent = null;
|
||||
protected internal List<object> syncValues;
|
||||
|
||||
/// <summary>
|
||||
/// For internal use only, don't use
|
||||
/// </summary>
|
||||
protected internal object[] lastOnSerializeDataReceived = null;
|
||||
|
||||
[FormerlySerializedAs("synchronization")]
|
||||
public ViewSynchronization Synchronization = ViewSynchronization.UnreliableOnChange;
|
||||
|
||||
protected internal bool mixedModeIsReliable = false;
|
||||
|
||||
/// <summary>Defines if ownership of this PhotonView is fixed, can be requested or simply taken.</summary>
|
||||
/// <remarks>
|
||||
/// 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.
|
||||
/// </remarks>
|
||||
[FormerlySerializedAs("ownershipTransfer")]
|
||||
public OwnershipOption OwnershipTransfer = OwnershipOption.Fixed;
|
||||
|
||||
|
||||
public enum ObservableSearch { Manual, AutoFindActive, AutoFindAll }
|
||||
|
||||
/// Default to manual so existing PVs in projects default to same as before. Reset() changes this to AutoAll for new implementations.
|
||||
public ObservableSearch observableSearch = ObservableSearch.Manual;
|
||||
|
||||
public List<Component> ObservedComponents;
|
||||
|
||||
|
||||
|
||||
internal MonoBehaviour[] RpcMonoBehaviours;
|
||||
|
||||
|
||||
|
||||
[Obsolete("Renamed. Use IsRoomView instead")]
|
||||
public bool IsSceneView
|
||||
{
|
||||
get { return this.IsRoomView; }
|
||||
}
|
||||
|
||||
/// <summary>True if the PhotonView was loaded with the scene (game object) or instantiated with InstantiateRoomObject.</summary>
|
||||
/// <remarks>
|
||||
/// Room 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).
|
||||
/// </remarks>
|
||||
public bool IsRoomView
|
||||
{
|
||||
get { return this.CreatorActorNr == 0; }
|
||||
}
|
||||
|
||||
public bool IsOwnerActive
|
||||
{
|
||||
get { return this.Owner != null && !this.Owner.IsInactive; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// True if the PhotonView is "mine" and can be controlled by this client.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// PUN has an ownership concept that defines who can control and destroy each PhotonView.
|
||||
/// True in case the controller matches the local Player.
|
||||
/// True if this is a scene photonview (null owner and ownerId == 0) on the Master client.
|
||||
/// </remarks>
|
||||
public bool IsMine { get; private set; }
|
||||
public bool AmController
|
||||
{
|
||||
get { return this.IsMine; }
|
||||
}
|
||||
|
||||
public Player Controller { get; private set; }
|
||||
|
||||
public int CreatorActorNr { get; private set; }
|
||||
|
||||
public bool AmOwner { get; private set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The owner of a PhotonView is the creator of an object by default Ownership can be transferred and the owner may not be in the room anymore. Objects in the scene don't have an owner.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 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.
|
||||
/// </remarks>
|
||||
public Player Owner { get; private set; }
|
||||
|
||||
|
||||
|
||||
[NonSerialized]
|
||||
private int ownerActorNr;
|
||||
|
||||
public int OwnerActorNr
|
||||
{
|
||||
get { return this.ownerActorNr; }
|
||||
set
|
||||
{
|
||||
if (value != 0 && this.ownerActorNr == value)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Player prevOwner = this.Owner;
|
||||
|
||||
this.Owner = PhotonNetwork.CurrentRoom == null ? null : PhotonNetwork.CurrentRoom.GetPlayer(value, true);
|
||||
this.ownerActorNr = this.Owner != null ? this.Owner.ActorNumber : value;
|
||||
|
||||
this.AmOwner = PhotonNetwork.LocalPlayer != null && this.ownerActorNr == PhotonNetwork.LocalPlayer.ActorNumber;
|
||||
|
||||
this.UpdateCallbackLists();
|
||||
if (!ReferenceEquals(this.OnOwnerChangeCallbacks, null))
|
||||
{
|
||||
for (int i = 0, cnt = this.OnOwnerChangeCallbacks.Count; i < cnt; ++i)
|
||||
{
|
||||
this.OnOwnerChangeCallbacks[i].OnOwnerChange(this.Owner, prevOwner);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[NonSerialized]
|
||||
private int controllerActorNr;
|
||||
|
||||
public int ControllerActorNr
|
||||
{
|
||||
get { return this.controllerActorNr; }
|
||||
set
|
||||
{
|
||||
Player prevController = this.Controller;
|
||||
|
||||
this.Controller = PhotonNetwork.CurrentRoom == null ? null : PhotonNetwork.CurrentRoom.GetPlayer(value, true);
|
||||
if (this.Controller != null && this.Controller.IsInactive)
|
||||
{
|
||||
this.Controller = PhotonNetwork.MasterClient;
|
||||
}
|
||||
this.controllerActorNr = this.Controller != null ? this.Controller.ActorNumber : value;
|
||||
|
||||
this.IsMine = PhotonNetwork.LocalPlayer != null && this.controllerActorNr == PhotonNetwork.LocalPlayer.ActorNumber;
|
||||
|
||||
if (!ReferenceEquals(this.Controller, prevController))
|
||||
{
|
||||
this.UpdateCallbackLists();
|
||||
if (!ReferenceEquals(this.OnControllerChangeCallbacks, null))
|
||||
{
|
||||
for (int i = 0, cnt = this.OnControllerChangeCallbacks.Count; i < cnt; ++i)
|
||||
{
|
||||
this.OnControllerChangeCallbacks[i].OnControllerChange(this.Controller, prevController);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// This field is the Scene ViewID (0 if not used). loaded with the scene, used in Awake().
|
||||
[SerializeField]
|
||||
[FormerlySerializedAs("viewIdField")]
|
||||
[HideInInspector]
|
||||
public int sceneViewId = 0; // TODO: in best case, this is not public
|
||||
|
||||
|
||||
/// This field is the "runtime" ViewID as backup for the property.
|
||||
[NonSerialized]
|
||||
private int viewIdField = 0;
|
||||
|
||||
/// <summary>
|
||||
/// The ID of the PhotonView. Identifies it in a networked game (per room).
|
||||
/// </summary>
|
||||
/// <remarks>See: [Network Instantiation](@ref instantiateManual)</remarks>
|
||||
public int ViewID
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.viewIdField;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
// TODO: Check if the isPlaying check is needed when the PhotonViewHandler is updated
|
||||
if (value != 0 && this.viewIdField != 0)
|
||||
{
|
||||
Debug.LogWarning("Changing a ViewID while it's in use is not possible (except setting it to 0 (not being used). Current ViewID: " + this.viewIdField);
|
||||
return;
|
||||
}
|
||||
|
||||
if (value == 0 && this.viewIdField != 0)
|
||||
{
|
||||
PhotonNetwork.LocalCleanPhotonView(this);
|
||||
}
|
||||
|
||||
this.viewIdField = value;
|
||||
this.CreatorActorNr = value / PhotonNetwork.MAX_VIEW_IDS; // the creator can be derived from the viewId. this is also the initial owner and creator.
|
||||
this.OwnerActorNr = this.CreatorActorNr;
|
||||
this.ControllerActorNr = this.CreatorActorNr;
|
||||
this.RebuildControllerCache();
|
||||
|
||||
|
||||
// if the viewID is set to a new, legit value, the view should register in the list of active PVs.
|
||||
if (value != 0)
|
||||
{
|
||||
PhotonNetwork.RegisterPhotonView(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[FormerlySerializedAs("instantiationId")]
|
||||
public int InstantiationId; // if the view was instantiated with a GO, this GO has a instantiationID (first view's viewID)
|
||||
|
||||
[SerializeField]
|
||||
[HideInInspector]
|
||||
public bool isRuntimeInstantiated;
|
||||
|
||||
|
||||
protected internal bool removedFromLocalViewList;
|
||||
|
||||
|
||||
/// <summary>Will FindObservables() and assign the sceneViewId, if that is != 0. This initializes the PhotonView if loaded with the scene. Called once by Unity, when this instance is created.</summary>
|
||||
protected internal void Awake()
|
||||
{
|
||||
if (this.ViewID != 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.sceneViewId != 0)
|
||||
{
|
||||
// PhotonNetwork.Instantiate will set a ViewID != 0 before the object awakes. So only objects loaded with the scene ever use the sceneViewId (even if the obj got pooled)
|
||||
this.ViewID = this.sceneViewId;
|
||||
}
|
||||
|
||||
this.FindObservables();
|
||||
}
|
||||
|
||||
|
||||
/// called by PhotonNetwork.LocalCleanupAnythingInstantiated
|
||||
internal void ResetPhotonView(bool resetOwner)
|
||||
{
|
||||
//// If this was fired by this connection rejoining, reset the ownership cache to owner = creator.
|
||||
//// TODO: This reset may not be needed at all with the ownership being invalidated next.
|
||||
//if (resetOwner)
|
||||
// ResetOwnership();
|
||||
|
||||
//this.ownershipCacheIsValid = OwnershipCacheState.Invalid;
|
||||
|
||||
// Reset the delta check to force a complete update of owned objects, to ensure joining connections get full updates.
|
||||
this.lastOnSerializeDataSent = null;
|
||||
}
|
||||
|
||||
|
||||
/// called by OnJoinedRoom, OnMasterClientSwitched, OnPlayerEnteredRoom and OnEvent for OwnershipUpdate
|
||||
/// OnPlayerLeftRoom will set a new controller directly, if the controller or owner left
|
||||
internal void RebuildControllerCache(bool ownerHasChanged = false)
|
||||
{
|
||||
//var prevController = this.controller;
|
||||
|
||||
// objects without controller and room objects (ownerId 0) check if controller update is needed
|
||||
if (this.controllerActorNr == 0 || this.OwnerActorNr == 0 || this.Owner == null || this.Owner.IsInactive)
|
||||
{
|
||||
var masterclient = PhotonNetwork.MasterClient;
|
||||
this.ControllerActorNr = masterclient == null ? -1 : masterclient.ActorNumber;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.ControllerActorNr = this.OwnerActorNr;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void OnPreNetDestroy(PhotonView rootView)
|
||||
{
|
||||
UpdateCallbackLists();
|
||||
|
||||
if (!ReferenceEquals(OnPreNetDestroyCallbacks, null))
|
||||
for (int i = 0, cnt = OnPreNetDestroyCallbacks.Count; i < cnt; ++i)
|
||||
{
|
||||
OnPreNetDestroyCallbacks[i].OnPreNetDestroy(rootView);
|
||||
}
|
||||
}
|
||||
|
||||
protected internal void OnDestroy()
|
||||
{
|
||||
if (!this.removedFromLocalViewList)
|
||||
{
|
||||
bool wasInList = PhotonNetwork.LocalCleanPhotonView(this);
|
||||
|
||||
if (wasInList && this.InstantiationId > 0 && !PhotonHandler.AppQuits && PhotonNetwork.LogLevel >= PunLogLevel.Informational)
|
||||
{
|
||||
Debug.Log("PUN-instantiated '" + this.gameObject.name + "' got destroyed by engine. This is OK when loading levels. Otherwise use: PhotonNetwork.Destroy().");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Depending on the PhotonView's OwnershipTransfer setting, any client can request to become owner of the PhotonView.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 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.
|
||||
/// </remarks>
|
||||
public void RequestOwnership()
|
||||
{
|
||||
if (OwnershipTransfer != OwnershipOption.Fixed)
|
||||
{
|
||||
PhotonNetwork.RequestOwnership(this.ViewID, this.ownerActorNr);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (PhotonNetwork.LogLevel >= PunLogLevel.Informational)
|
||||
{
|
||||
Debug.LogWarning("Attempting to RequestOwnership of GameObject '" + name + "' viewId: " + ViewID +
|
||||
", but PhotonView.OwnershipTransfer is set to Fixed.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Transfers the ownership of this PhotonView (and GameObject) to another player.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The owner/controller of a PhotonView is also the client which sends position updates of the GameObject.
|
||||
/// </remarks>
|
||||
public void TransferOwnership(Player newOwner)
|
||||
{
|
||||
if (newOwner != null)
|
||||
TransferOwnership(newOwner.ActorNumber);
|
||||
else
|
||||
{
|
||||
if (PhotonNetwork.LogLevel >= PunLogLevel.Informational)
|
||||
{
|
||||
Debug.LogWarning("Attempting to TransferOwnership of GameObject '" + name + "' viewId: " + ViewID +
|
||||
", but provided Player newOwner is null.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Transfers the ownership of this PhotonView (and GameObject) to another player.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The owner/controller of a PhotonView is also the client which sends position updates of the GameObject.
|
||||
/// </remarks>
|
||||
public void TransferOwnership(int newOwnerId)
|
||||
{
|
||||
if (OwnershipTransfer == OwnershipOption.Takeover || (OwnershipTransfer == OwnershipOption.Request && this.AmController))
|
||||
{
|
||||
PhotonNetwork.TransferOwnership(this.ViewID, newOwnerId);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (PhotonNetwork.LogLevel >= PunLogLevel.Informational)
|
||||
{
|
||||
if (OwnershipTransfer == OwnershipOption.Fixed)
|
||||
Debug.LogWarning("Attempting to TransferOwnership of GameObject '" + name + "' viewId: " + ViewID +
|
||||
" without the authority to do so. TransferOwnership is not allowed if PhotonView.OwnershipTransfer is set to Fixed.");
|
||||
else if (OwnershipTransfer == OwnershipOption.Request)
|
||||
Debug.LogWarning("Attempting to TransferOwnership of GameObject '" + name + "' viewId: " + ViewID +
|
||||
" without the authority to do so. PhotonView.OwnershipTransfer is set to Request, so only the controller of this object can TransferOwnership.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Will find IPunObservable components on this GameObject and nested children and add them to the ObservedComponents list.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This is called via PhotonView.Awake(), which in turn is called immediately by the engine's AddComponent method.
|
||||
///
|
||||
/// Changing the ObservedComponents of a PhotonView at runtime can be problematic, if other clients are not also
|
||||
/// updating their list.
|
||||
/// </remarks>
|
||||
/// <param name="force">If true, FindObservables will work as if observableSearch is AutoFindActive.</param>
|
||||
public void FindObservables(bool force = false)
|
||||
{
|
||||
if (!force && this.observableSearch == ObservableSearch.Manual)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.ObservedComponents == null)
|
||||
{
|
||||
this.ObservedComponents = new List<Component>();
|
||||
}
|
||||
else
|
||||
{
|
||||
this.ObservedComponents.Clear();
|
||||
}
|
||||
|
||||
this.transform.GetNestedComponentsInChildren<Component, IPunObservable, PhotonView>(force || this.observableSearch == ObservableSearch.AutoFindAll, this.ObservedComponents);
|
||||
}
|
||||
|
||||
|
||||
public void SerializeView(PhotonStream stream, PhotonMessageInfo info)
|
||||
{
|
||||
if (this.ObservedComponents != null && this.ObservedComponents.Count > 0)
|
||||
{
|
||||
for (int i = 0; i < this.ObservedComponents.Count; ++i)
|
||||
{
|
||||
var component = this.ObservedComponents[i];
|
||||
if (component != null)
|
||||
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)
|
||||
{
|
||||
var component = this.ObservedComponents[i];
|
||||
if (component != null)
|
||||
DeserializeComponent(component, stream, info);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected internal void DeserializeComponent(Component component, PhotonStream stream, PhotonMessageInfo info)
|
||||
{
|
||||
IPunObservable observable = component as IPunObservable;
|
||||
if (observable != null)
|
||||
{
|
||||
observable.OnPhotonSerializeView(stream, info);
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError("Observed scripts have to implement IPunObservable. " + component + " does not. It is Type: " + component.GetType(), component.gameObject);
|
||||
}
|
||||
}
|
||||
|
||||
protected internal void SerializeComponent(Component component, PhotonStream stream, PhotonMessageInfo info)
|
||||
{
|
||||
IPunObservable observable = component as IPunObservable;
|
||||
if (observable != null)
|
||||
{
|
||||
observable.OnPhotonSerializeView(stream, info);
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError("Observed scripts have to implement IPunObservable. " + component + " does not. It is Type: " + component.GetType(), component.gameObject);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Can be used to refesh the list of MonoBehaviours on this GameObject while PhotonNetwork.UseRpcMonoBehaviourCache is true.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Set PhotonNetwork.UseRpcMonoBehaviourCache to true to enable the caching.
|
||||
/// Uses this.GetComponents<MonoBehaviour>() 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.
|
||||
/// </remarks>
|
||||
public void RefreshRpcMonoBehaviourCache()
|
||||
{
|
||||
this.RpcMonoBehaviours = this.GetComponents<MonoBehaviour>();
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Call a RPC method of this GameObject on remote clients of this room (or on all, including this client).
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// [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).
|
||||
/// </remarks>
|
||||
/// <param name="methodName">The name of a fitting method that was has the RPC attribute.</param>
|
||||
/// <param name="target">The group of targets and the way the RPC gets sent.</param>
|
||||
/// <param name="parameters">The parameters that the RPC method has (must fit this call!).</param>
|
||||
public void RPC(string methodName, RpcTarget target, params object[] parameters)
|
||||
{
|
||||
PhotonNetwork.RPC(this, methodName, target, false, parameters);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Call a RPC method of this GameObject on remote clients of this room (or on all, including this client).
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// [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).
|
||||
/// </remarks>
|
||||
///<param name="methodName">The name of a fitting method that was has the RPC attribute.</param>
|
||||
///<param name="target">The group of targets and the way the RPC gets sent.</param>
|
||||
///<param name="encrypt"> </param>
|
||||
///<param name="parameters">The parameters that the RPC method has (must fit this call!).</param>
|
||||
public void RpcSecure(string methodName, RpcTarget target, bool encrypt, params object[] parameters)
|
||||
{
|
||||
PhotonNetwork.RPC(this, methodName, target, encrypt, parameters);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Call a RPC method of this GameObject on remote clients of this room (or on all, including this client).
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// [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).
|
||||
/// </remarks>
|
||||
/// <param name="methodName">The name of a fitting method that was has the RPC attribute.</param>
|
||||
/// <param name="targetPlayer">The group of targets and the way the RPC gets sent.</param>
|
||||
/// <param name="parameters">The parameters that the RPC method has (must fit this call!).</param>
|
||||
public void RPC(string methodName, Player targetPlayer, params object[] parameters)
|
||||
{
|
||||
PhotonNetwork.RPC(this, methodName, targetPlayer, false, parameters);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Call a RPC method of this GameObject on remote clients of this room (or on all, including this client).
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// [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).
|
||||
/// </remarks>
|
||||
///<param name="methodName">The name of a fitting method that was has the RPC attribute.</param>
|
||||
///<param name="targetPlayer">The group of targets and the way the RPC gets sent.</param>
|
||||
///<param name="encrypt"> </param>
|
||||
///<param name="parameters">The parameters that the RPC method has (must fit this call!).</param>
|
||||
public void RpcSecure(string methodName, Player targetPlayer, bool encrypt, params object[] parameters)
|
||||
{
|
||||
PhotonNetwork.RPC(this, methodName, targetPlayer, encrypt, parameters);
|
||||
}
|
||||
|
||||
public static PhotonView Get(Component component)
|
||||
{
|
||||
return component.transform.GetParentComponent<PhotonView>();
|
||||
}
|
||||
|
||||
public static PhotonView Get(GameObject gameObj)
|
||||
{
|
||||
return gameObj.transform.GetParentComponent<PhotonView>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finds the PhotonView Component with a viewID in the scene
|
||||
/// </summary>
|
||||
/// <param name="viewID"></param>
|
||||
/// <returns>The PhotonView with ViewID. Returns null if none found</returns>
|
||||
public static PhotonView Find(int viewID)
|
||||
{
|
||||
return PhotonNetwork.GetPhotonView(viewID);
|
||||
}
|
||||
|
||||
|
||||
#region Callback Interfaces
|
||||
|
||||
|
||||
private struct CallbackTargetChange
|
||||
{
|
||||
public IPhotonViewCallback obj;
|
||||
public Type type;
|
||||
public bool add;
|
||||
|
||||
public CallbackTargetChange(IPhotonViewCallback obj, Type type, bool add)
|
||||
{
|
||||
this.obj = obj;
|
||||
this.type = type;
|
||||
this.add = add;
|
||||
}
|
||||
}
|
||||
|
||||
private Queue<CallbackTargetChange> CallbackChangeQueue = new Queue<CallbackTargetChange>();
|
||||
|
||||
private List<IOnPhotonViewPreNetDestroy> OnPreNetDestroyCallbacks;
|
||||
private List<IOnPhotonViewOwnerChange> OnOwnerChangeCallbacks;
|
||||
private List<IOnPhotonViewControllerChange> OnControllerChangeCallbacks;
|
||||
|
||||
/// <summary>
|
||||
/// Add object to all applicable callback interfaces. Object must implement at least one IOnPhotonViewCallback derived interface.
|
||||
/// </summary>
|
||||
/// <param name="obj">An object that implements OnPhotonView callback interface(s).</param>
|
||||
public void AddCallbackTarget(IPhotonViewCallback obj)
|
||||
{
|
||||
CallbackChangeQueue.Enqueue(new CallbackTargetChange(obj, null, true));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Remove object from all applicable callback interfaces. Object must implement at least one IOnPhotonViewCallback derived interface.
|
||||
/// </summary>
|
||||
/// <param name="obj">An object that implements OnPhotonView callback interface(s).</param>
|
||||
public void RemoveCallbackTarget(IPhotonViewCallback obj)
|
||||
{
|
||||
CallbackChangeQueue.Enqueue(new CallbackTargetChange(obj, null, false));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add object to this PhotonView's callback.
|
||||
/// T is the IOnPhotonViewCallback derived interface you want added to its associated callback list.
|
||||
/// Supplying IOnPhotonViewCallback (the interface base class) as T will add ALL implemented IOnPhotonViewCallback Interfaces found on the object.
|
||||
/// </summary>
|
||||
public void AddCallback<T>(IPhotonViewCallback obj) where T : class, IPhotonViewCallback
|
||||
{
|
||||
CallbackChangeQueue.Enqueue(new CallbackTargetChange(obj, typeof(T), true));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Remove object from this PhotonView's callback list for T.
|
||||
/// T is the IOnPhotonViewCallback derived interface you want removed from its associated callback list.
|
||||
/// Supplying IOnPhotonViewCallback (the interface base class) as T will remove ALL implemented IOnPhotonViewCallback Interfaces found on the object.
|
||||
/// </summary>
|
||||
public void RemoveCallback<T>(IPhotonViewCallback obj) where T : class, IPhotonViewCallback
|
||||
{
|
||||
CallbackChangeQueue.Enqueue(new CallbackTargetChange(obj, typeof(T), false));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Apply any queued add/remove of interfaces from the callback lists. Typically called before looping callback lists.
|
||||
/// </summary>
|
||||
private void UpdateCallbackLists()
|
||||
{
|
||||
while (CallbackChangeQueue.Count > 0)
|
||||
{
|
||||
var item = CallbackChangeQueue.Dequeue();
|
||||
var obj = item.obj;
|
||||
var type = item.type;
|
||||
var add = item.add;
|
||||
|
||||
if (type == null)
|
||||
{
|
||||
TryRegisterCallback(obj, ref OnPreNetDestroyCallbacks, add);
|
||||
TryRegisterCallback(obj, ref OnOwnerChangeCallbacks, add);
|
||||
TryRegisterCallback(obj, ref OnControllerChangeCallbacks, add);
|
||||
}
|
||||
else if (type == typeof(IOnPhotonViewPreNetDestroy))
|
||||
RegisterCallback(obj as IOnPhotonViewPreNetDestroy, ref OnPreNetDestroyCallbacks, add);
|
||||
|
||||
else if (type == typeof(IOnPhotonViewOwnerChange))
|
||||
RegisterCallback(obj as IOnPhotonViewOwnerChange, ref OnOwnerChangeCallbacks, add);
|
||||
|
||||
else if (type == typeof(IOnPhotonViewControllerChange))
|
||||
RegisterCallback(obj as IOnPhotonViewControllerChange, ref OnControllerChangeCallbacks, add);
|
||||
}
|
||||
}
|
||||
|
||||
private void TryRegisterCallback<T>(IPhotonViewCallback obj, ref List<T> list, bool add) where T : class, IPhotonViewCallback
|
||||
{
|
||||
T iobj = obj as T;
|
||||
if (iobj != null)
|
||||
{
|
||||
RegisterCallback(iobj, ref list, add);
|
||||
}
|
||||
}
|
||||
|
||||
private void RegisterCallback<T>(T obj, ref List<T> list, bool add) where T : class, IPhotonViewCallback
|
||||
{
|
||||
if (ReferenceEquals(list, null))
|
||||
list = new List<T>();
|
||||
|
||||
if (add)
|
||||
{
|
||||
if (!list.Contains(obj))
|
||||
list.Add(obj);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (list.Contains(obj))
|
||||
list.Remove(obj);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endregion Callback Interfaces
|
||||
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return string.Format("View {0}{3} on {1} {2}", this.ViewID, (this.gameObject != null) ? this.gameObject.name : "GO==null", (this.IsRoomView) ? "(scene)" : string.Empty, this.Prefix > 0 ? "lvl" + this.Prefix : "");
|
||||
}
|
||||
}
|
||||
}
|
16
Assets/Photon/PhotonUnityNetworking/Code/PhotonView.cs.meta
Normal file
16
Assets/Photon/PhotonUnityNetworking/Code/PhotonView.cs.meta
Normal file
@ -0,0 +1,16 @@
|
||||
fileFormatVersion: 2
|
||||
guid: aa584fbee541324448dd18d8409c7a41
|
||||
labels:
|
||||
- ExitGames
|
||||
- PUN
|
||||
- Photon
|
||||
- Networking
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: -16000
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
974
Assets/Photon/PhotonUnityNetworking/Code/PunClasses.cs
Normal file
974
Assets/Photon/PhotonUnityNetworking/Code/PunClasses.cs
Normal file
@ -0,0 +1,974 @@
|
||||
// ----------------------------------------------------------------------------
|
||||
// <copyright file="PunClasses.cs" company="Exit Games GmbH">
|
||||
// PhotonNetwork Framework for Unity - Copyright (C) 2018 Exit Games GmbH
|
||||
// </copyright>
|
||||
// <summary>
|
||||
// Wraps up smaller classes that don't need their own file.
|
||||
// </summary>
|
||||
// <author>developer@exitgames.com</author>
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
|
||||
#pragma warning disable 1587
|
||||
/// \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.
|
||||
///
|
||||
/// \defgroup callbacks Callbacks
|
||||
/// \brief Callback Interfaces
|
||||
#pragma warning restore 1587
|
||||
|
||||
|
||||
namespace Photon.Pun
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using ExitGames.Client.Photon;
|
||||
using UnityEngine;
|
||||
using UnityEngine.SceneManagement;
|
||||
using Photon.Realtime;
|
||||
using SupportClassPun = ExitGames.Client.Photon.SupportClass;
|
||||
|
||||
|
||||
/// <summary>Replacement for RPC attribute with different name. Used to flag methods as remote-callable.</summary>
|
||||
public class PunRPC : Attribute
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This class adds the property photonView, while logging a warning when your game still uses the networkView.
|
||||
/// </summary>
|
||||
public class MonoBehaviourPun : MonoBehaviour
|
||||
{
|
||||
/// <summary>Cache field for the PhotonView on this GameObject.</summary>
|
||||
private PhotonView pvCache;
|
||||
|
||||
/// <summary>A cached reference to a PhotonView on this GameObject.</summary>
|
||||
/// <remarks>
|
||||
/// 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.
|
||||
/// </remarks>
|
||||
public PhotonView photonView
|
||||
{
|
||||
get
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
// In the editor we want to avoid caching this at design time, so changes in PV structure appear immediately.
|
||||
if (!Application.isPlaying || this.pvCache == null)
|
||||
{
|
||||
this.pvCache = PhotonView.Get(this);
|
||||
}
|
||||
#else
|
||||
if (this.pvCache == null)
|
||||
{
|
||||
this.pvCache = PhotonView.Get(this);
|
||||
}
|
||||
#endif
|
||||
return this.pvCache;
|
||||
}
|
||||
}
|
||||
|
||||
//#if UNITY_EDITOR
|
||||
//protected virtual void Reset()
|
||||
//{
|
||||
// this.pvCache = this.transform.GetParentComponent<PhotonView>();
|
||||
|
||||
// if (this.pvCache == null)
|
||||
// {
|
||||
// Debug.LogWarning(this.GetType().Name + " requires a PhotonView. No PhotonView was found, so one is being added to GameObject '" + this.transform.root.name + "'");
|
||||
// this.pvCache = this.transform.root.gameObject.AddComponent<PhotonView>();
|
||||
// }
|
||||
//}
|
||||
//#endif
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// This class provides a .photonView and all callbacks/events that PUN can call. Override the events/methods you want to use.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// By extending this class, you can implement individual methods as override.
|
||||
///
|
||||
/// Do not add <b>new</b> <code>MonoBehaviour.OnEnable</code> or <code>MonoBehaviour.OnDisable</code>
|
||||
/// Instead, you should override those and call <code>base.OnEnable</code> and <code>base.OnDisable</code>.
|
||||
///
|
||||
/// Visual Studio and MonoDevelop should provide the list of methods when you begin typing "override".
|
||||
/// <b>Your implementation does not have to call "base.method()".</b>
|
||||
///
|
||||
/// This class implements all callback interfaces and extends <see cref="Photon.Pun.MonoBehaviourPun"/>.
|
||||
/// </remarks>
|
||||
/// \ingroup callbacks
|
||||
// the documentation for the interface methods becomes inherited when Doxygen builds it.
|
||||
public class MonoBehaviourPunCallbacks : MonoBehaviourPun, IConnectionCallbacks , IMatchmakingCallbacks , IInRoomCallbacks, ILobbyCallbacks, IWebRpcCallback, IErrorInfoCallback
|
||||
{
|
||||
public virtual void OnEnable()
|
||||
{
|
||||
PhotonNetwork.AddCallbackTarget(this);
|
||||
}
|
||||
|
||||
public virtual void OnDisable()
|
||||
{
|
||||
PhotonNetwork.RemoveCallbackTarget(this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called to signal that the raw connection got established but before the client can call operation on the server.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// After the (low level transport) connection is established, the client will automatically send
|
||||
/// the Authentication operation, which needs to get a response before the client can call other operations.
|
||||
///
|
||||
/// Your logic should wait for either: OnRegionListReceived or OnConnectedToMaster.
|
||||
///
|
||||
/// This callback is useful to detect if the server can be reached at all (technically).
|
||||
/// Most often, it's enough to implement OnDisconnected().
|
||||
///
|
||||
/// This is not called for transitions from the masterserver to game servers.
|
||||
/// </remarks>
|
||||
public virtual void OnConnected()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when the local user/client left a room, so the game's logic can clean up it's internal state.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// When leaving a room, the LoadBalancingClient will disconnect the Game Server and connect to the Master Server.
|
||||
/// This wraps up multiple internal actions.
|
||||
///
|
||||
/// Wait for the callback OnConnectedToMaster, before you use lobbies and join or create rooms.
|
||||
/// </remarks>
|
||||
public virtual void OnLeftRoom()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called after switching to a new MasterClient when the current one leaves.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This is not called when this client enters a room.
|
||||
/// The former MasterClient is still in the player list when this method get called.
|
||||
/// </remarks>
|
||||
public virtual void OnMasterClientSwitched(Player newMasterClient)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when the server couldn't create a room (OpCreateRoom failed).
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The most common cause to fail creating a room, is when a title relies on fixed room-names and the room already exists.
|
||||
/// </remarks>
|
||||
/// <param name="returnCode">Operation ReturnCode from the server.</param>
|
||||
/// <param name="message">Debug message for the error.</param>
|
||||
public virtual void OnCreateRoomFailed(short returnCode, string message)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when a previous OpJoinRoom call failed on the server.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The most common causes are that a room is full or does not exist (due to someone else being faster or closing the room).
|
||||
/// </remarks>
|
||||
/// <param name="returnCode">Operation ReturnCode from the server.</param>
|
||||
/// <param name="message">Debug message for the error.</param>
|
||||
public virtual void OnJoinRoomFailed(short returnCode, string message)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when this client created a room and entered it. OnJoinedRoom() will be called as well.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This callback is only called on the client which created a room (see OpCreateRoom).
|
||||
///
|
||||
/// 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", implement OnMasterClientSwitched()
|
||||
/// and make each new MasterClient check the room's state.
|
||||
/// </remarks>
|
||||
public virtual void OnCreatedRoom()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called on entering a lobby on the Master Server. The actual room-list updates will call OnRoomListUpdate.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// While in the lobby, the roomlist is automatically updated in fixed intervals (which you can't modify in the public cloud).
|
||||
/// The room list gets available via OnRoomListUpdate.
|
||||
/// </remarks>
|
||||
public virtual void OnJoinedLobby()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called after leaving a lobby.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// When you leave a lobby, [OpCreateRoom](@ref OpCreateRoom) and [OpJoinRandomRoom](@ref OpJoinRandomRoom)
|
||||
/// automatically refer to the default lobby.
|
||||
/// </remarks>
|
||||
public virtual void OnLeftLobby()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called after disconnecting from the Photon server. It could be a failure or intentional
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The reason for this disconnect is provided as DisconnectCause.
|
||||
/// </remarks>
|
||||
public virtual void OnDisconnected(DisconnectCause cause)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when the Name Server provided a list of regions for your title.
|
||||
/// </summary>
|
||||
/// <remarks>Check the RegionHandler class description, to make use of the provided values.</remarks>
|
||||
/// <param name="regionHandler">The currently used RegionHandler.</param>
|
||||
public virtual void OnRegionListReceived(RegionHandler regionHandler)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called for any update of the room-listing while in a lobby (InLobby) on the Master Server.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 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.
|
||||
/// </remarks>
|
||||
public virtual void OnRoomListUpdate(List<RoomInfo> roomList)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when the LoadBalancingClient entered a room, no matter if this client created it or simply joined.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// When this is called, you can access the existing players in Room.Players, their custom properties and Room.CustomProperties.
|
||||
///
|
||||
/// In this callback, you could create player objects. For example in Unity, instantiate a prefab for the player.
|
||||
///
|
||||
/// If you want a match to be started "actively", enable the user to signal "ready" (using OpRaiseEvent or a Custom Property).
|
||||
/// </remarks>
|
||||
public virtual void OnJoinedRoom()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when a remote player entered the room. This Player is already added to the playerlist.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 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.
|
||||
/// </remarks>
|
||||
public virtual void OnPlayerEnteredRoom(Player newPlayer)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when a remote player left the room or became inactive. Check otherPlayer.IsInactive.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// If another player leaves the room or if the server detects a lost connection, this callback will
|
||||
/// be used to notify your game logic.
|
||||
///
|
||||
/// Depending on the room's setup, players may become inactive, which means they may return and retake
|
||||
/// their spot in the room. In such cases, the Player stays in the Room.Players dictionary.
|
||||
///
|
||||
/// If the player is not just inactive, it gets removed from the Room.Players dictionary, before
|
||||
/// the callback is called.
|
||||
/// </remarks>
|
||||
public virtual void OnPlayerLeftRoom(Player otherPlayer)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when a previous OpJoinRandom call failed on the server.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The most common causes are that a room is full or does not exist (due to someone else being faster or closing the room).
|
||||
///
|
||||
/// When using multiple lobbies (via OpJoinLobby or a TypedLobby parameter), another lobby might have more/fitting rooms.<br/>
|
||||
/// </remarks>
|
||||
/// <param name="returnCode">Operation ReturnCode from the server.</param>
|
||||
/// <param name="message">Debug message for the error.</param>
|
||||
public virtual void OnJoinRandomFailed(short returnCode, string message)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when the client is connected to the Master Server and ready for matchmaking and other tasks.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The list of available rooms won't become available unless you join a lobby via LoadBalancingClient.OpJoinLobby.
|
||||
/// You can join rooms and create them even without being in a lobby. The default lobby is used in that case.
|
||||
/// </remarks>
|
||||
public virtual void OnConnectedToMaster()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when a room's custom properties changed. The propertiesThatChanged contains all that was set via Room.SetCustomProperties.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Since v1.25 this method has one parameter: Hashtable propertiesThatChanged.<br/>
|
||||
/// Changing properties must be done by Room.SetCustomProperties, which causes this callback locally, too.
|
||||
/// </remarks>
|
||||
/// <param name="propertiesThatChanged"></param>
|
||||
public virtual void OnRoomPropertiesUpdate(Hashtable propertiesThatChanged)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when custom player-properties are changed. Player and the changed properties are passed as object[].
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Changing properties must be done by Player.SetCustomProperties, which causes this callback locally, too.
|
||||
/// </remarks>
|
||||
///
|
||||
/// <param name="targetPlayer">Contains Player that changed.</param>
|
||||
/// <param name="changedProps">Contains the properties that changed.</param>
|
||||
public virtual void OnPlayerPropertiesUpdate(Player targetPlayer, Hashtable changedProps)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when the server sent the response to a FindFriends request.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// After calling OpFindFriends, the Master Server will cache the friend list and send updates to the friend
|
||||
/// list. The friends includes the name, userId, online state and the room (if any) for each requested user/friend.
|
||||
///
|
||||
/// Use the friendList to update your UI and store it, if the UI should highlight changes.
|
||||
/// </remarks>
|
||||
public virtual void OnFriendListUpdate(List<FriendInfo> friendList)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when your Custom Authentication service responds with additional data.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 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) { ... }
|
||||
/// </remarks>
|
||||
/// <see cref="https://doc.photonengine.com/en-us/realtime/current/reference/custom-authentication"/>
|
||||
public virtual void OnCustomAuthenticationResponse(Dictionary<string, object> data)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when the custom authentication failed. Followed by disconnect!
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 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://dashboard.photonengine.com)),
|
||||
/// this won't be called!
|
||||
/// </remarks>
|
||||
/// <param name="debugMessage">Contains a debug message why authentication failed. This has to be fixed during development.</param>
|
||||
public virtual void OnCustomAuthenticationFailed (string debugMessage)
|
||||
{
|
||||
}
|
||||
|
||||
//TODO: Check if this needs to be implemented
|
||||
// in: IOptionalInfoCallbacks
|
||||
public virtual void OnWebRpcResponse(OperationResponse response)
|
||||
{
|
||||
}
|
||||
|
||||
//TODO: Check if this needs to be implemented
|
||||
// in: IOptionalInfoCallbacks
|
||||
public virtual void OnLobbyStatisticsUpdate(List<TypedLobbyInfo> lobbyStatistics)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when the client receives an event from the server indicating that an error happened there.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// In most cases this could be either:
|
||||
/// 1. an error from webhooks plugin (if HasErrorInfo is enabled), read more here:
|
||||
/// https://doc.photonengine.com/en-us/realtime/current/gameplay/web-extensions/webhooks#options
|
||||
/// 2. an error sent from a custom server plugin via PluginHost.BroadcastErrorInfoEvent, see example here:
|
||||
/// https://doc.photonengine.com/en-us/server/current/plugins/manual#handling_http_response
|
||||
/// 3. an error sent from the server, for example, when the limit of cached events has been exceeded in the room
|
||||
/// (all clients will be disconnected and the room will be closed in this case)
|
||||
/// read more here: https://doc.photonengine.com/en-us/realtime/current/gameplay/cached-events#special_considerations
|
||||
/// </remarks>
|
||||
/// <param name="errorInfo">object containing information about the error</param>
|
||||
public virtual void OnErrorInfo(ErrorInfo errorInfo)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Container class for info about a particular message, RPC or update.
|
||||
/// </summary>
|
||||
/// \ingroup publicApi
|
||||
public struct PhotonMessageInfo
|
||||
{
|
||||
private readonly int timeInt;
|
||||
/// <summary>The sender of a message / event. May be null.</summary>
|
||||
public readonly Player Sender;
|
||||
public readonly PhotonView photonView;
|
||||
|
||||
public PhotonMessageInfo(Player player, int timestamp, PhotonView view)
|
||||
{
|
||||
this.Sender = player;
|
||||
this.timeInt = timestamp;
|
||||
this.photonView = view;
|
||||
}
|
||||
|
||||
[Obsolete("Use SentServerTime instead.")]
|
||||
public double timestamp
|
||||
{
|
||||
get
|
||||
{
|
||||
uint u = (uint) this.timeInt;
|
||||
double t = u;
|
||||
return t / 1000.0d;
|
||||
}
|
||||
}
|
||||
|
||||
public double SentServerTime
|
||||
{
|
||||
get
|
||||
{
|
||||
uint u = (uint)this.timeInt;
|
||||
double t = u;
|
||||
return t / 1000.0d;
|
||||
}
|
||||
}
|
||||
|
||||
public int SentServerTimestamp
|
||||
{
|
||||
get { return this.timeInt; }
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return string.Format("[PhotonMessageInfo: Sender='{1}' Senttime={0}]", this.SentServerTime, this.Sender);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>Defines Photon event-codes as used by PUN.</summary>
|
||||
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 OwnershipRequest = 209;
|
||||
public const byte OwnershipTransfer = 210;
|
||||
public const byte VacantViewIds = 211;
|
||||
public const byte OwnershipUpdate = 212;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// This container is used in OnPhotonSerializeView() to either provide incoming data of a PhotonView or for you to provide it.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 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.
|
||||
/// </remarks>
|
||||
/// \ingroup publicApi
|
||||
public class PhotonStream
|
||||
{
|
||||
private List<object> writeData;
|
||||
private object[] readData;
|
||||
private int currentItem; //Used to track the next item to receive.
|
||||
|
||||
/// <summary>If true, this client should add data to the stream to send it.</summary>
|
||||
public bool IsWriting { get; private set; }
|
||||
|
||||
/// <summary>If true, this client should read data send by another client.</summary>
|
||||
public bool IsReading
|
||||
{
|
||||
get { return !this.IsWriting; }
|
||||
}
|
||||
|
||||
/// <summary>Count of items in the stream.</summary>
|
||||
public int Count
|
||||
{
|
||||
get { return this.IsWriting ? this.writeData.Count : this.readData.Length; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a stream and initializes it. Used by PUN internally.
|
||||
/// </summary>
|
||||
public PhotonStream(bool write, object[] incomingData)
|
||||
{
|
||||
this.IsWriting = write;
|
||||
|
||||
if (!write && incomingData != null)
|
||||
{
|
||||
this.readData = incomingData;
|
||||
}
|
||||
}
|
||||
|
||||
public void SetReadStream(object[] incomingData, int pos = 0)
|
||||
{
|
||||
this.readData = incomingData;
|
||||
this.currentItem = pos;
|
||||
this.IsWriting = false;
|
||||
}
|
||||
|
||||
internal void SetWriteStream(List<object> newWriteData, int pos = 0)
|
||||
{
|
||||
if (pos != newWriteData.Count)
|
||||
{
|
||||
throw new Exception("SetWriteStream failed, because count does not match position value. pos: "+ pos + " newWriteData.Count:" + newWriteData.Count);
|
||||
}
|
||||
this.writeData = newWriteData;
|
||||
this.currentItem = pos;
|
||||
this.IsWriting = true;
|
||||
}
|
||||
|
||||
internal List<object> GetWriteStream()
|
||||
{
|
||||
return this.writeData;
|
||||
}
|
||||
|
||||
|
||||
[Obsolete("Either SET the writeData with an empty List or use Clear().")]
|
||||
internal void ResetWriteStream()
|
||||
{
|
||||
this.writeData.Clear();
|
||||
}
|
||||
|
||||
/// <summary>Read next piece of data from the stream when IsReading is true.</summary>
|
||||
public object ReceiveNext()
|
||||
{
|
||||
if (this.IsWriting)
|
||||
{
|
||||
Debug.LogError("Error: you cannot read this stream that you are writing!");
|
||||
return null;
|
||||
}
|
||||
|
||||
object obj = this.readData[this.currentItem];
|
||||
this.currentItem++;
|
||||
return obj;
|
||||
}
|
||||
|
||||
/// <summary>Read next piece of data from the stream without advancing the "current" item.</summary>
|
||||
public object PeekNext()
|
||||
{
|
||||
if (this.IsWriting)
|
||||
{
|
||||
Debug.LogError("Error: you cannot read this stream that you are writing!");
|
||||
return null;
|
||||
}
|
||||
|
||||
object obj = this.readData[this.currentItem];
|
||||
//this.currentItem++;
|
||||
return obj;
|
||||
}
|
||||
|
||||
/// <summary>Add another piece of data to send it when IsWriting is true.</summary>
|
||||
public void SendNext(object obj)
|
||||
{
|
||||
if (!this.IsWriting)
|
||||
{
|
||||
Debug.LogError("Error: you cannot write/send to this stream that you are reading!");
|
||||
return;
|
||||
}
|
||||
|
||||
this.writeData.Add(obj);
|
||||
}
|
||||
|
||||
[Obsolete("writeData is a list now. Use and re-use it directly.")]
|
||||
public bool CopyToListAndClear(List<object> target)
|
||||
{
|
||||
if (!this.IsWriting) return false;
|
||||
|
||||
target.AddRange(this.writeData);
|
||||
this.writeData.Clear();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>Turns the stream into a new object[].</summary>
|
||||
public object[] ToArray()
|
||||
{
|
||||
return this.IsWriting ? this.writeData.ToArray() : this.readData;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Will read or write the value, depending on the stream's IsWriting value.
|
||||
/// </summary>
|
||||
public void Serialize(ref bool myBool)
|
||||
{
|
||||
if (this.IsWriting)
|
||||
{
|
||||
this.writeData.Add(myBool);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (this.readData.Length > this.currentItem)
|
||||
{
|
||||
myBool = (bool) this.readData[this.currentItem];
|
||||
this.currentItem++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Will read or write the value, depending on the stream's IsWriting value.
|
||||
/// </summary>
|
||||
public void Serialize(ref int myInt)
|
||||
{
|
||||
if (this.IsWriting)
|
||||
{
|
||||
this.writeData.Add(myInt);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (this.readData.Length > this.currentItem)
|
||||
{
|
||||
myInt = (int) this.readData[this.currentItem];
|
||||
this.currentItem++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Will read or write the value, depending on the stream's IsWriting value.
|
||||
/// </summary>
|
||||
public void Serialize(ref string value)
|
||||
{
|
||||
if (this.IsWriting)
|
||||
{
|
||||
this.writeData.Add(value);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (this.readData.Length > this.currentItem)
|
||||
{
|
||||
value = (string) this.readData[this.currentItem];
|
||||
this.currentItem++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Will read or write the value, depending on the stream's IsWriting value.
|
||||
/// </summary>
|
||||
public void Serialize(ref char value)
|
||||
{
|
||||
if (this.IsWriting)
|
||||
{
|
||||
this.writeData.Add(value);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (this.readData.Length > this.currentItem)
|
||||
{
|
||||
value = (char) this.readData[this.currentItem];
|
||||
this.currentItem++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Will read or write the value, depending on the stream's IsWriting value.
|
||||
/// </summary>
|
||||
public void Serialize(ref short value)
|
||||
{
|
||||
if (this.IsWriting)
|
||||
{
|
||||
this.writeData.Add(value);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (this.readData.Length > this.currentItem)
|
||||
{
|
||||
value = (short) this.readData[this.currentItem];
|
||||
this.currentItem++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Will read or write the value, depending on the stream's IsWriting value.
|
||||
/// </summary>
|
||||
public void Serialize(ref float obj)
|
||||
{
|
||||
if (this.IsWriting)
|
||||
{
|
||||
this.writeData.Add(obj);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (this.readData.Length > this.currentItem)
|
||||
{
|
||||
obj = (float) this.readData[this.currentItem];
|
||||
this.currentItem++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Will read or write the value, depending on the stream's IsWriting value.
|
||||
/// </summary>
|
||||
public void Serialize(ref Player obj)
|
||||
{
|
||||
if (this.IsWriting)
|
||||
{
|
||||
this.writeData.Add(obj);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (this.readData.Length > this.currentItem)
|
||||
{
|
||||
obj = (Player) this.readData[this.currentItem];
|
||||
this.currentItem++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Will read or write the value, depending on the stream's IsWriting value.
|
||||
/// </summary>
|
||||
public void Serialize(ref Vector3 obj)
|
||||
{
|
||||
if (this.IsWriting)
|
||||
{
|
||||
this.writeData.Add(obj);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (this.readData.Length > this.currentItem)
|
||||
{
|
||||
obj = (Vector3) this.readData[this.currentItem];
|
||||
this.currentItem++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Will read or write the value, depending on the stream's IsWriting value.
|
||||
/// </summary>
|
||||
public void Serialize(ref Vector2 obj)
|
||||
{
|
||||
if (this.IsWriting)
|
||||
{
|
||||
this.writeData.Add(obj);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (this.readData.Length > this.currentItem)
|
||||
{
|
||||
obj = (Vector2) this.readData[this.currentItem];
|
||||
this.currentItem++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Will read or write the value, depending on the stream's IsWriting value.
|
||||
/// </summary>
|
||||
public void Serialize(ref Quaternion obj)
|
||||
{
|
||||
if (this.IsWriting)
|
||||
{
|
||||
this.writeData.Add(obj);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (this.readData.Length > this.currentItem)
|
||||
{
|
||||
obj = (Quaternion) this.readData[this.currentItem];
|
||||
this.currentItem++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public class SceneManagerHelper
|
||||
{
|
||||
public static string ActiveSceneName
|
||||
{
|
||||
get
|
||||
{
|
||||
Scene s = SceneManager.GetActiveScene();
|
||||
return s.name;
|
||||
}
|
||||
}
|
||||
|
||||
public static int ActiveSceneBuildIndex
|
||||
{
|
||||
get { return SceneManager.GetActiveScene().buildIndex; }
|
||||
}
|
||||
|
||||
|
||||
#if UNITY_EDITOR
|
||||
/// <summary>In Editor, we can access the active scene's name.</summary>
|
||||
public static string EditorActiveSceneName
|
||||
{
|
||||
get { return SceneManager.GetActiveScene().name; }
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The default implementation of a PrefabPool for PUN, which actually Instantiates and Destroys GameObjects but pools a resource.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This pool is not actually storing GameObjects for later reuse. Instead, it's destroying used GameObjects.
|
||||
/// However, prefabs will be loaded from a Resources folder and cached, which speeds up Instantiation a bit.
|
||||
///
|
||||
/// The ResourceCache is public, so it can be filled without relying on the Resources folders.
|
||||
/// </remarks>
|
||||
public class DefaultPool : IPunPrefabPool
|
||||
{
|
||||
/// <summary>Contains a GameObject per prefabId, to speed up instantiation.</summary>
|
||||
public readonly Dictionary<string, GameObject> ResourceCache = new Dictionary<string, GameObject>();
|
||||
|
||||
/// <summary>Returns an inactive instance of a networked GameObject, to be used by PUN.</summary>
|
||||
/// <param name="prefabId">String identifier for the networked object.</param>
|
||||
/// <param name="position">Location of the new object.</param>
|
||||
/// <param name="rotation">Rotation of the new object.</param>
|
||||
/// <returns></returns>
|
||||
public GameObject Instantiate(string prefabId, Vector3 position, Quaternion rotation)
|
||||
{
|
||||
GameObject res = null;
|
||||
bool cached = this.ResourceCache.TryGetValue(prefabId, out res);
|
||||
if (!cached)
|
||||
{
|
||||
res = Resources.Load<GameObject>(prefabId);
|
||||
if (res == null)
|
||||
{
|
||||
Debug.LogError("DefaultPool failed to load \"" + prefabId + "\". Make sure it's in a \"Resources\" folder. Or use a custom IPunPrefabPool.");
|
||||
}
|
||||
else
|
||||
{
|
||||
this.ResourceCache.Add(prefabId, res);
|
||||
}
|
||||
}
|
||||
|
||||
bool wasActive = res.activeSelf;
|
||||
if (wasActive) res.SetActive(false);
|
||||
|
||||
GameObject instance =GameObject.Instantiate(res, position, rotation) as GameObject;
|
||||
|
||||
if (wasActive) res.SetActive(true);
|
||||
return instance;
|
||||
}
|
||||
|
||||
/// <summary>Simply destroys a GameObject.</summary>
|
||||
/// <param name="gameObject">The GameObject to get rid of.</param>
|
||||
public void Destroy(GameObject gameObject)
|
||||
{
|
||||
GameObject.Destroy(gameObject);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>Small number of extension methods that make it easier for PUN to work cross-Unity-versions.</summary>
|
||||
public static class PunExtensions
|
||||
{
|
||||
public static Dictionary<MethodInfo, ParameterInfo[]> ParametersOfMethods = new Dictionary<MethodInfo, ParameterInfo[]>();
|
||||
|
||||
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<PhotonView>(true) as PhotonView[];
|
||||
}
|
||||
|
||||
public static PhotonView GetPhotonView(this UnityEngine.GameObject go)
|
||||
{
|
||||
return go.GetComponent<PhotonView>() as PhotonView;
|
||||
}
|
||||
|
||||
/// <summary>compares the squared magnitude of target - second to given float value</summary>
|
||||
public static bool AlmostEquals(this Vector3 target, Vector3 second, float sqrMagnitudePrecision)
|
||||
{
|
||||
return (target - second).sqrMagnitude < sqrMagnitudePrecision; // TODO: inline vector methods to optimize?
|
||||
}
|
||||
|
||||
/// <summary>compares the squared magnitude of target - second to given float value</summary>
|
||||
public static bool AlmostEquals(this Vector2 target, Vector2 second, float sqrMagnitudePrecision)
|
||||
{
|
||||
return (target - second).sqrMagnitude < sqrMagnitudePrecision; // TODO: inline vector methods to optimize?
|
||||
}
|
||||
|
||||
/// <summary>compares the angle between target and second to given float value</summary>
|
||||
public static bool AlmostEquals(this Quaternion target, Quaternion second, float maxAngle)
|
||||
{
|
||||
return Quaternion.Angle(target, second) < maxAngle;
|
||||
}
|
||||
|
||||
/// <summary>compares two floats and returns true of their difference is less than floatDiff</summary>
|
||||
public static bool AlmostEquals(this float target, float second, float floatDiff)
|
||||
{
|
||||
return Mathf.Abs(target - second) < floatDiff;
|
||||
}
|
||||
|
||||
|
||||
public static bool CheckIsAssignableFrom(this Type to, Type from)
|
||||
{
|
||||
#if !NETFX_CORE
|
||||
return to.IsAssignableFrom(from);
|
||||
#else
|
||||
return to.GetTypeInfo().IsAssignableFrom(from.GetTypeInfo());
|
||||
#endif
|
||||
}
|
||||
|
||||
public static bool CheckIsInterface(this Type to)
|
||||
{
|
||||
#if !NETFX_CORE
|
||||
return to.IsInterface;
|
||||
#else
|
||||
return to.GetTypeInfo().IsInterface;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
12
Assets/Photon/PhotonUnityNetworking/Code/PunClasses.cs.meta
Normal file
12
Assets/Photon/PhotonUnityNetworking/Code/PunClasses.cs.meta
Normal file
@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f40f16a0227e5c14293e269c875c0f9b
|
||||
labels:
|
||||
- ExitGames
|
||||
- PUN
|
||||
- Photon
|
||||
- Networking
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
100
Assets/Photon/PhotonUnityNetworking/Code/ServerSettings.cs
Normal file
100
Assets/Photon/PhotonUnityNetworking/Code/ServerSettings.cs
Normal file
@ -0,0 +1,100 @@
|
||||
// ----------------------------------------------------------------------------
|
||||
// <copyright file="ServerSettings.cs" company="Exit Games GmbH">
|
||||
// PhotonNetwork Framework for Unity - Copyright (C) 2018 Exit Games GmbH
|
||||
// </copyright>
|
||||
// <summary>
|
||||
// ScriptableObject defining a server setup. An instance is created as <b>PhotonServerSettings</b>.
|
||||
// </summary>
|
||||
// <author>developer@exitgames.com</author>
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
|
||||
namespace Photon.Pun
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using ExitGames.Client.Photon;
|
||||
using Photon.Realtime;
|
||||
using UnityEngine;
|
||||
|
||||
/// <summary>
|
||||
/// Collection of connection-relevant settings, used internally by PhotonNetwork.ConnectUsingSettings.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Includes the AppSettings class from the Realtime APIs plus some other, PUN-relevant, settings.</remarks>
|
||||
[Serializable]
|
||||
[HelpURL("https://doc.photonengine.com/en-us/pun/v2/getting-started/initial-setup")]
|
||||
public class ServerSettings : ScriptableObject
|
||||
{
|
||||
[Tooltip("Core Photon Server/Cloud settings.")]
|
||||
public AppSettings AppSettings;
|
||||
|
||||
/// <summary>Region that will be used by the Editor and Development Builds. This ensures all users will be in the same region for testing.</summary>
|
||||
[Tooltip("Developer build override for Best Region.")]
|
||||
public string DevRegion;
|
||||
|
||||
[Tooltip("Log output by PUN.")]
|
||||
public PunLogLevel PunLogging = PunLogLevel.ErrorsOnly;
|
||||
|
||||
[Tooltip("Logs additional info for debugging.")]
|
||||
public bool EnableSupportLogger;
|
||||
|
||||
[Tooltip("Enables apps to keep the connection without focus.")]
|
||||
public bool RunInBackground = true;
|
||||
|
||||
[Tooltip("Simulates an online connection.\nPUN can be used as usual.")]
|
||||
public bool StartInOfflineMode;
|
||||
|
||||
[Tooltip("RPC name list.\nUsed as shortcut when sending calls.")]
|
||||
public List<string> RpcList = new List<string>(); // set by scripts and or via Inspector
|
||||
|
||||
#if UNITY_EDITOR
|
||||
public bool DisableAutoOpenWizard;
|
||||
public bool ShowSettings;
|
||||
public bool DevRegionSetOnce;
|
||||
#endif
|
||||
|
||||
/// <summary>Sets appid and region code in the AppSettings. Used in Editor.</summary>
|
||||
public void UseCloud(string cloudAppid, string code = "")
|
||||
{
|
||||
this.AppSettings.AppIdRealtime = cloudAppid;
|
||||
this.AppSettings.Server = null;
|
||||
this.AppSettings.FixedRegion = string.IsNullOrEmpty(code) ? null : code;
|
||||
}
|
||||
|
||||
/// <summary>Checks if a string is a Guid by attempting to create one.</summary>
|
||||
/// <param name="val">The potential guid to check.</param>
|
||||
/// <returns>True if new Guid(val) did not fail.</returns>
|
||||
public static bool IsAppId(string val)
|
||||
{
|
||||
try
|
||||
{
|
||||
new Guid(val);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>Gets the "best region summary" from the preferences.</summary>
|
||||
/// <value>The best region code in preferences.</value>
|
||||
public static string BestRegionSummaryInPreferences
|
||||
{
|
||||
get { return PhotonNetwork.BestRegionSummaryInPreferences; }
|
||||
}
|
||||
|
||||
/// <summary>Sets the "best region summary" in the preferences to null. On next start, the client will ping all available.</summary>
|
||||
public static void ResetBestRegionCodeInPreferences()
|
||||
{
|
||||
PhotonNetwork.BestRegionSummaryInPreferences = null;
|
||||
}
|
||||
|
||||
/// <summary>String summary of the AppSettings.</summary>
|
||||
public override string ToString()
|
||||
{
|
||||
return "ServerSettings: " + this.AppSettings.ToStringFull();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9f3758f8f58fdef43803eb9be1df0608
|
||||
labels:
|
||||
- ExitGames
|
||||
- PUN
|
||||
- Photon
|
||||
- Networking
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
8
Assets/Photon/PhotonUnityNetworking/Code/Utilities.meta
Normal file
8
Assets/Photon/PhotonUnityNetworking/Code/Utilities.meta
Normal file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d67e11e5c968e60489b4eeec4d85e165
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -0,0 +1,494 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Photon.Pun
|
||||
{
|
||||
|
||||
public static class NestedComponentUtilities
|
||||
{
|
||||
|
||||
public static T EnsureRootComponentExists<T, NestedT>(this Transform transform)
|
||||
where T : Component
|
||||
where NestedT : Component
|
||||
{
|
||||
var root = GetParentComponent<NestedT>(transform);
|
||||
if (root)
|
||||
{
|
||||
var comp = root.GetComponent<T>();
|
||||
|
||||
if (comp)
|
||||
return comp;
|
||||
|
||||
return root.gameObject.AddComponent<T>();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
#region GetComponent Replacements
|
||||
|
||||
// Recycled collections
|
||||
private static Queue<Transform> nodesQueue = new Queue<Transform>();
|
||||
public static Dictionary<System.Type, ICollection> searchLists = new Dictionary<System.Type, ICollection>();
|
||||
private static Stack<Transform> nodeStack = new Stack<Transform>();
|
||||
|
||||
/// <summary>
|
||||
/// Find T on supplied transform or any parent. Unlike GetComponentInParent, GameObjects do not need to be active to be found.
|
||||
/// </summary>
|
||||
public static T GetParentComponent<T>(this Transform t)
|
||||
where T : Component
|
||||
{
|
||||
T found = t.GetComponent<T>();
|
||||
|
||||
if (found)
|
||||
return found;
|
||||
|
||||
var par = t.parent;
|
||||
while (par)
|
||||
{
|
||||
found = par.GetComponent<T>();
|
||||
if (found)
|
||||
return found;
|
||||
par = par.parent;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Returns all T found between the child transform and its root. Order in List from child to parent, with the root/parent most being last.
|
||||
/// </summary>
|
||||
/// <param name="t"></param>
|
||||
/// <returns></returns>
|
||||
public static void GetNestedComponentsInParents<T>(this Transform t, List<T> list)
|
||||
where T : Component
|
||||
{
|
||||
list.Clear();
|
||||
|
||||
while (t != null)
|
||||
{
|
||||
T obj = t.GetComponent<T>();
|
||||
if (obj)
|
||||
list.Add(obj);
|
||||
|
||||
t = t.parent;
|
||||
}
|
||||
}
|
||||
|
||||
public static T GetNestedComponentInChildren<T, NestedT>(this Transform t, bool includeInactive)
|
||||
where T : class
|
||||
where NestedT : class
|
||||
{
|
||||
// Look for the most obvious check first on the root.
|
||||
var found = t.GetComponent<T>();
|
||||
if (!ReferenceEquals(found, null))
|
||||
return found;
|
||||
|
||||
// No root found, start testing layer by layer - root is the first layer. Add to queue.
|
||||
nodesQueue.Clear();
|
||||
nodesQueue.Enqueue(t);
|
||||
|
||||
while (nodesQueue.Count > 0)
|
||||
{
|
||||
var node = nodesQueue.Dequeue();
|
||||
|
||||
for (int c = 0, ccnt = node.childCount; c < ccnt; ++c)
|
||||
{
|
||||
var child = node.GetChild(c);
|
||||
|
||||
// Ignore branches that are not active
|
||||
if (!includeInactive && !child.gameObject.activeSelf)
|
||||
continue;
|
||||
|
||||
// Hit a nested node - don't search this node
|
||||
if (!ReferenceEquals(child.GetComponent<NestedT>(), null))
|
||||
continue;
|
||||
|
||||
// see if what we are looking for is on this node
|
||||
found = child.GetComponent<T>();
|
||||
|
||||
// Return if we found what we are looking for
|
||||
if (!ReferenceEquals(found, null))
|
||||
return found;
|
||||
|
||||
// Add node to queue for next depth pass since nothing was found on this layer.
|
||||
nodesQueue.Enqueue(child);
|
||||
}
|
||||
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Same as GetComponentInParent, but will always include inactive objects in search.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <typeparam name="DontRecurseOnT"></typeparam>
|
||||
/// <param name="t"></param>
|
||||
/// <returns></returns>
|
||||
public static T GetNestedComponentInParent<T, NestedT>(this Transform t)
|
||||
where T : class
|
||||
where NestedT : class
|
||||
{
|
||||
T found = null;
|
||||
|
||||
Transform node = t;
|
||||
do
|
||||
{
|
||||
|
||||
found = node.GetComponent<T>();
|
||||
|
||||
if (!ReferenceEquals(found, null))
|
||||
return found;
|
||||
|
||||
// stop search on node with PV
|
||||
if (!ReferenceEquals(node.GetComponent<NestedT>(), null))
|
||||
return null;
|
||||
|
||||
node = node.parent;
|
||||
}
|
||||
while (!ReferenceEquals(node, null));
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// UNTESTED
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <typeparam name="StopSearchOnT"></typeparam>
|
||||
/// <param name="t"></param>
|
||||
/// <returns></returns>
|
||||
public static T GetNestedComponentInParents<T, NestedT>(this Transform t)
|
||||
where T : class
|
||||
where NestedT : class
|
||||
{
|
||||
// First try root
|
||||
var found = t.GetComponent<T>();
|
||||
|
||||
if (!ReferenceEquals(found, null))
|
||||
return found;
|
||||
|
||||
/// Get the reverse list of transforms climbing for start up to netobject
|
||||
var par = t.parent;
|
||||
|
||||
while (!ReferenceEquals(par, null))
|
||||
{
|
||||
found = par.GetComponent<T>();
|
||||
if (!ReferenceEquals(found, null))
|
||||
return found;
|
||||
|
||||
/// Stop climbing at the NetObj (this is how we detect nesting
|
||||
if (!ReferenceEquals(par.GetComponent<NestedT>(), null))
|
||||
return null;
|
||||
|
||||
par = par.parent;
|
||||
};
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Finds components of type T on supplied transform, and every parent above that node, inclusively stopping on node StopSearchOnT component.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <typeparam name="StopSearchOnT"></typeparam>
|
||||
/// <param name="t"></param>
|
||||
/// <param name="list"></param>
|
||||
/// <returns></returns>
|
||||
public static void GetNestedComponentsInParents<T, NestedT>(this Transform t, List<T> list)
|
||||
where T : class
|
||||
where NestedT : class
|
||||
{
|
||||
|
||||
// Get components on the starting node - this is a given.
|
||||
t.GetComponents(list);
|
||||
|
||||
// If the starting node has the stop component, we are done.
|
||||
if (!ReferenceEquals(t.GetComponent<NestedT>(), null))
|
||||
return;
|
||||
|
||||
var tnode = t.parent;
|
||||
|
||||
// If there is no parent, we are done.
|
||||
if (ReferenceEquals(tnode, null))
|
||||
return;
|
||||
|
||||
nodeStack.Clear();
|
||||
|
||||
while (true)
|
||||
{
|
||||
// add new parent to stack
|
||||
nodeStack.Push(tnode);
|
||||
|
||||
// if this node has the Stop, we are done recursing up.
|
||||
if (!ReferenceEquals(tnode.GetComponent<NestedT>(), null))
|
||||
break;
|
||||
|
||||
// Get the next parent node and add it to the stack
|
||||
tnode = tnode.parent;
|
||||
|
||||
// Stop recursing up if the parent is null
|
||||
if (ReferenceEquals(tnode, null))
|
||||
break;
|
||||
}
|
||||
|
||||
if (nodeStack.Count == 0)
|
||||
return;
|
||||
|
||||
System.Type type = typeof(T);
|
||||
|
||||
// Acquire the right searchlist from our pool
|
||||
List<T> searchList;
|
||||
if (!searchLists.ContainsKey(type))
|
||||
{
|
||||
searchList = new List<T>();
|
||||
searchLists.Add(type, searchList);
|
||||
}
|
||||
else
|
||||
{
|
||||
searchList = searchLists[type] as List<T>;
|
||||
}
|
||||
|
||||
// Reverse iterate the nodes found. This produces a GetComponentInParent that starts from the parent Stop down to the provided transform
|
||||
while (nodeStack.Count > 0)
|
||||
{
|
||||
var node = nodeStack.Pop();
|
||||
|
||||
node.GetComponents(searchList);
|
||||
list.AddRange(searchList);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Same as GetComponentsInChildren, but will not recurse into children with component of the DontRecurseOnT type. This allows nesting of PhotonViews/NetObjects to be respected.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="t"></param>
|
||||
/// <param name="list">Pass null and a reused list will be used. Consume immediately.</param>
|
||||
public static List<T> GetNestedComponentsInChildren<T, NestedT>(this Transform t, List<T> list, bool includeInactive = true)
|
||||
where T : class
|
||||
where NestedT : class
|
||||
{
|
||||
System.Type type = typeof(T);
|
||||
|
||||
// Temp lists are also recycled. Get/Create a reusable List of this type.
|
||||
List<T> searchList;
|
||||
if (!searchLists.ContainsKey(type))
|
||||
searchLists.Add(type, searchList = new List<T>());
|
||||
else
|
||||
searchList = searchLists[type] as List<T>;
|
||||
|
||||
nodesQueue.Clear();
|
||||
|
||||
if (list == null)
|
||||
list = new List<T>();
|
||||
|
||||
// Get components on starting transform - no exceptions
|
||||
t.GetComponents(list);
|
||||
|
||||
// Add first layer of children to the queue for next layer processing.
|
||||
for (int i = 0, cnt = t.childCount; i < cnt; ++i)
|
||||
{
|
||||
var child = t.GetChild(i);
|
||||
|
||||
// Ignore inactive nodes (optional)
|
||||
if (!includeInactive && !child.gameObject.activeSelf)
|
||||
continue;
|
||||
|
||||
// ignore nested DontRecurseOnT
|
||||
if (!ReferenceEquals(child.GetComponent<NestedT>(), null))
|
||||
continue;
|
||||
|
||||
nodesQueue.Enqueue(child);
|
||||
}
|
||||
|
||||
// Recurse node layers
|
||||
while (nodesQueue.Count > 0)
|
||||
{
|
||||
var node = nodesQueue.Dequeue();
|
||||
|
||||
// Add found components on this gameobject node
|
||||
node.GetComponents(searchList);
|
||||
list.AddRange(searchList);
|
||||
|
||||
// Add children to the queue for next layer processing.
|
||||
for (int i = 0, cnt = node.childCount; i < cnt; ++i)
|
||||
{
|
||||
var child = node.GetChild(i);
|
||||
|
||||
// Ignore inactive nodes (optional)
|
||||
if (!includeInactive && !child.gameObject.activeSelf)
|
||||
continue;
|
||||
|
||||
// ignore nested NestedT
|
||||
if (!ReferenceEquals(child.GetComponent<NestedT>(), null))
|
||||
continue;
|
||||
|
||||
nodesQueue.Enqueue(child);
|
||||
}
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Same as GetComponentsInChildren, but will not recurse into children with component of the DontRecurseOnT type. This allows nesting of PhotonViews/NetObjects to be respected.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="t"></param>
|
||||
/// <param name="list">Pass null and a reused list will be used. Consume immediately.</param>
|
||||
public static List<T> GetNestedComponentsInChildren<T>(this Transform t, List<T> list, bool includeInactive = true, params System.Type[] stopOn)
|
||||
where T : class
|
||||
{
|
||||
System.Type type = typeof(T);
|
||||
|
||||
// Temp lists are also recycled. Get/Create a reusable List of this type.
|
||||
List<T> searchList;
|
||||
if (!searchLists.ContainsKey(type))
|
||||
searchLists.Add(type, searchList = new List<T>());
|
||||
else
|
||||
searchList = searchLists[type] as List<T>;
|
||||
|
||||
nodesQueue.Clear();
|
||||
|
||||
// Get components on starting transform - no exceptions
|
||||
t.GetComponents(list);
|
||||
|
||||
// Add first layer of children to the queue for next layer processing.
|
||||
for (int i = 0, cnt = t.childCount; i < cnt; ++i)
|
||||
{
|
||||
var child = t.GetChild(i);
|
||||
|
||||
// Ignore inactive nodes (optional)
|
||||
if (!includeInactive && !child.gameObject.activeSelf)
|
||||
continue;
|
||||
|
||||
// ignore nested DontRecurseOnT
|
||||
bool stopRecurse = false;
|
||||
for (int s = 0, scnt = stopOn.Length; s < scnt; ++s)
|
||||
{
|
||||
if (!ReferenceEquals(child.GetComponent(stopOn[s]), null))
|
||||
{
|
||||
stopRecurse = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (stopRecurse)
|
||||
continue;
|
||||
|
||||
nodesQueue.Enqueue(child);
|
||||
}
|
||||
|
||||
// Recurse node layers
|
||||
while (nodesQueue.Count > 0)
|
||||
{
|
||||
var node = nodesQueue.Dequeue();
|
||||
|
||||
// Add found components on this gameobject node
|
||||
node.GetComponents(searchList);
|
||||
list.AddRange(searchList);
|
||||
|
||||
// Add children to the queue for next layer processing.
|
||||
for (int i = 0, cnt = node.childCount; i < cnt; ++i)
|
||||
{
|
||||
var child = node.GetChild(i);
|
||||
|
||||
// Ignore inactive nodes (optional)
|
||||
if (!includeInactive && !child.gameObject.activeSelf)
|
||||
continue;
|
||||
|
||||
// ignore nested NestedT
|
||||
bool stopRecurse = false;
|
||||
for (int s = 0, scnt = stopOn.Length; s < scnt; ++s)
|
||||
{
|
||||
if (!ReferenceEquals(child.GetComponent(stopOn[s]), null))
|
||||
{
|
||||
stopRecurse = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (stopRecurse)
|
||||
continue;
|
||||
|
||||
nodesQueue.Enqueue(child);
|
||||
}
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Same as GetComponentsInChildren, but will not recurse into children with component of the NestedT type. This allows nesting of PhotonViews/NetObjects to be respected.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Cast found components to this type. Typically Component, but any other class/interface will work as long as they are assignable from SearchT.</typeparam>
|
||||
/// <typeparam name="SearchT">Find components of this class or interface type.</typeparam>
|
||||
/// <typeparam name="DontRecurseOnT"></typeparam>
|
||||
/// <param name="t"></param>
|
||||
/// <param name="includeInactive"></param>
|
||||
/// <param name="list"></param>
|
||||
/// <returns></returns>
|
||||
public static void GetNestedComponentsInChildren<T, SearchT, NestedT>(this Transform t, bool includeInactive, List<T> list)
|
||||
where T : class
|
||||
where SearchT : class
|
||||
{
|
||||
list.Clear();
|
||||
|
||||
// If this is inactive, nothing will be found. Give up now if we are restricted to active.
|
||||
if (!includeInactive && !t.gameObject.activeSelf)
|
||||
return;
|
||||
|
||||
System.Type searchType = typeof(SearchT);
|
||||
|
||||
// Temp lists are also recycled. Get/Create a reusable List of this type.
|
||||
List<SearchT> searchList;
|
||||
if (!searchLists.ContainsKey(searchType))
|
||||
searchLists.Add(searchType, searchList = new List<SearchT>());
|
||||
else
|
||||
searchList = searchLists[searchType] as List<SearchT>;
|
||||
|
||||
// Recurse child nodes one layer at a time. Using a Queue allows this to happen without a lot of work.
|
||||
nodesQueue.Clear();
|
||||
nodesQueue.Enqueue(t);
|
||||
|
||||
while (nodesQueue.Count > 0)
|
||||
{
|
||||
var node = nodesQueue.Dequeue();
|
||||
|
||||
// Add found components on this gameobject node
|
||||
searchList.Clear();
|
||||
node.GetComponents(searchList);
|
||||
foreach (var comp in searchList)
|
||||
{
|
||||
var casted = comp as T;
|
||||
if (!ReferenceEquals(casted, null))
|
||||
list.Add(casted);
|
||||
}
|
||||
|
||||
// Add children to the queue for next layer processing.
|
||||
for (int i = 0, cnt = node.childCount; i < cnt; ++i)
|
||||
{
|
||||
var child = node.GetChild(i);
|
||||
|
||||
// Ignore inactive nodes (optional)
|
||||
if (!includeInactive && !child.gameObject.activeSelf)
|
||||
continue;
|
||||
|
||||
// ignore nested DontRecurseOnT
|
||||
if (!ReferenceEquals(child.GetComponent<NestedT>(), null))
|
||||
continue;
|
||||
|
||||
nodesQueue.Enqueue(child);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 40bca7ec270007b40a4de315c071f4d3
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
5
Assets/Photon/PhotonUnityNetworking/Code/Views.meta
Normal file
5
Assets/Photon/PhotonUnityNetworking/Code/Views.meta
Normal file
@ -0,0 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a724ff00b77e85d44a2af6baf46fc6a2
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
userData:
|
@ -0,0 +1,572 @@
|
||||
// ----------------------------------------------------------------------------
|
||||
// <copyright file="PhotonAnimatorView.cs" company="Exit Games GmbH">
|
||||
// PhotonNetwork Framework for Unity - Copyright (C) 2018 Exit Games GmbH
|
||||
// </copyright>
|
||||
// <summary>
|
||||
// Component to synchronize Mecanim animations via PUN.
|
||||
// </summary>
|
||||
// <author>developer@exitgames.com</author>
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
|
||||
namespace Photon.Pun
|
||||
{
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 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
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 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.
|
||||
/// </remarks>
|
||||
[AddComponentMenu("Photon Networking/Photon Animator View")]
|
||||
public class PhotonAnimatorView : MonoBehaviourPun, 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 bool TriggerUsageWarningDone;
|
||||
|
||||
private Animator m_Animator;
|
||||
|
||||
private PhotonStreamQueue m_StreamQueue = new PhotonStreamQueue(120);
|
||||
|
||||
//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<SynchronizedParameter> m_SynchronizeParameters = new List<SynchronizedParameter>();
|
||||
|
||||
[HideInInspector]
|
||||
[SerializeField]
|
||||
private List<SynchronizedLayer> m_SynchronizeLayers = new List<SynchronizedLayer>();
|
||||
|
||||
private Vector3 m_ReceiverPosition;
|
||||
private float m_LastDeserializeTime;
|
||||
private bool m_WasSynchronizeTypeChanged = true;
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
List<string> m_raisedDiscreteTriggersCache = new List<string>();
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Unity
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
this.m_Animator = GetComponent<Animator>();
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
if (this.m_Animator.applyRootMotion && this.photonView.IsMine == false && PhotonNetwork.IsConnected == true)
|
||||
{
|
||||
this.m_Animator.applyRootMotion = false;
|
||||
}
|
||||
|
||||
if (PhotonNetwork.InRoom == false || PhotonNetwork.CurrentRoom.PlayerCount <= 1)
|
||||
{
|
||||
this.m_StreamQueue.Reset();
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.photonView.IsMine == true)
|
||||
{
|
||||
this.SerializeDataContinuously();
|
||||
|
||||
this.CacheDiscreteTriggers();
|
||||
}
|
||||
else
|
||||
{
|
||||
this.DeserializeDataContinuously();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Setup Synchronizing Methods
|
||||
|
||||
/// <summary>
|
||||
/// Caches the discrete triggers values for keeping track of raised triggers, and will be reseted after the sync routine got performed
|
||||
/// </summary>
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if a specific layer is configured to be synchronize
|
||||
/// </summary>
|
||||
/// <param name="layerIndex">Index of the layer.</param>
|
||||
/// <returns>True if the layer is synchronized</returns>
|
||||
public bool DoesLayerSynchronizeTypeExist(int layerIndex)
|
||||
{
|
||||
return this.m_SynchronizeLayers.FindIndex(item => item.LayerIndex == layerIndex) != -1;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if the specified parameter is configured to be synchronized
|
||||
/// </summary>
|
||||
/// <param name="name">The name of the parameter.</param>
|
||||
/// <returns>True if the parameter is synchronized</returns>
|
||||
public bool DoesParameterSynchronizeTypeExist(string name)
|
||||
{
|
||||
return this.m_SynchronizeParameters.FindIndex(item => item.Name == name) != -1;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get a list of all synchronized layers
|
||||
/// </summary>
|
||||
/// <returns>List of SynchronizedLayer objects</returns>
|
||||
public List<SynchronizedLayer> GetSynchronizedLayers()
|
||||
{
|
||||
return this.m_SynchronizeLayers;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get a list of all synchronized parameters
|
||||
/// </summary>
|
||||
/// <returns>List of SynchronizedParameter objects</returns>
|
||||
public List<SynchronizedParameter> GetSynchronizedParameters()
|
||||
{
|
||||
return this.m_SynchronizeParameters;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the type how the layer is synchronized
|
||||
/// </summary>
|
||||
/// <param name="layerIndex">Index of the layer.</param>
|
||||
/// <returns>Disabled/Discrete/Continuous</returns>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the type how the parameter is synchronized
|
||||
/// </summary>
|
||||
/// <param name="name">The name of the parameter.</param>
|
||||
/// <returns>Disabled/Discrete/Continuous</returns>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the how a layer should be synchronized
|
||||
/// </summary>
|
||||
/// <param name="layerIndex">Index of the layer.</param>
|
||||
/// <param name="synchronizeType">Disabled/Discrete/Continuous</param>
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the how a parameter should be synchronized
|
||||
/// </summary>
|
||||
/// <param name="name">The name of the parameter.</param>
|
||||
/// <param name="type">The type of the parameter.</param>
|
||||
/// <param name="synchronizeType">Disabled/Discrete/Continuous</param>
|
||||
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:
|
||||
if (!TriggerUsageWarningDone)
|
||||
{
|
||||
TriggerUsageWarningDone = true;
|
||||
Debug.Log("PhotonAnimatorView: When using triggers, make sure this component is last in the stack.\n" +
|
||||
"If you still experience issues, implement triggers as a regular RPC \n" +
|
||||
"or in custom IPunObservable component instead",this);
|
||||
|
||||
}
|
||||
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:
|
||||
if (!TriggerUsageWarningDone)
|
||||
{
|
||||
TriggerUsageWarningDone = true;
|
||||
Debug.Log("PhotonAnimatorView: When using triggers, make sure this component is last in the stack.\n" +
|
||||
"If you still experience issues, implement triggers as a regular RPC \n" +
|
||||
"or in custom IPunObservable component instead",this);
|
||||
|
||||
}
|
||||
// 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
|
||||
}
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9b8c4a61274f60b4ea5fb4299cfdbf14
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
@ -0,0 +1,111 @@
|
||||
// ----------------------------------------------------------------------------
|
||||
// <copyright file="PhotonRigidbody2DView.cs" company="Exit Games GmbH">
|
||||
// PhotonNetwork Framework for Unity - Copyright (C) 2018 Exit Games GmbH
|
||||
// </copyright>
|
||||
// <summary>
|
||||
// Component to synchronize 2d rigidbodies via PUN.
|
||||
// </summary>
|
||||
// <author>developer@exitgames.com</author>
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
|
||||
namespace Photon.Pun
|
||||
{
|
||||
using UnityEngine;
|
||||
|
||||
|
||||
[RequireComponent(typeof(Rigidbody2D))]
|
||||
[AddComponentMenu("Photon Networking/Photon Rigidbody 2D View")]
|
||||
public class PhotonRigidbody2DView : MonoBehaviourPun, IPunObservable
|
||||
{
|
||||
private float m_Distance;
|
||||
private float m_Angle;
|
||||
|
||||
private Rigidbody2D m_Body;
|
||||
|
||||
private Vector2 m_NetworkPosition;
|
||||
|
||||
private float m_NetworkRotation;
|
||||
|
||||
[HideInInspector]
|
||||
public bool m_SynchronizeVelocity = true;
|
||||
[HideInInspector]
|
||||
public bool m_SynchronizeAngularVelocity = false;
|
||||
|
||||
[HideInInspector]
|
||||
public bool m_TeleportEnabled = false;
|
||||
[HideInInspector]
|
||||
public float m_TeleportIfDistanceGreaterThan = 3.0f;
|
||||
|
||||
public void Awake()
|
||||
{
|
||||
this.m_Body = GetComponent<Rigidbody2D>();
|
||||
|
||||
this.m_NetworkPosition = new Vector2();
|
||||
}
|
||||
|
||||
public void FixedUpdate()
|
||||
{
|
||||
if (!this.photonView.IsMine)
|
||||
{
|
||||
this.m_Body.position = Vector2.MoveTowards(this.m_Body.position, this.m_NetworkPosition, this.m_Distance * (1.0f / PhotonNetwork.SerializationRate));
|
||||
this.m_Body.rotation = Mathf.MoveTowards(this.m_Body.rotation, this.m_NetworkRotation, this.m_Angle * (1.0f / PhotonNetwork.SerializationRate));
|
||||
}
|
||||
}
|
||||
|
||||
public void OnPhotonSerializeView(PhotonStream stream, PhotonMessageInfo info)
|
||||
{
|
||||
if (stream.IsWriting)
|
||||
{
|
||||
stream.SendNext(this.m_Body.position);
|
||||
stream.SendNext(this.m_Body.rotation);
|
||||
|
||||
if (this.m_SynchronizeVelocity)
|
||||
{
|
||||
stream.SendNext(this.m_Body.velocity);
|
||||
}
|
||||
|
||||
if (this.m_SynchronizeAngularVelocity)
|
||||
{
|
||||
stream.SendNext(this.m_Body.angularVelocity);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
this.m_NetworkPosition = (Vector2)stream.ReceiveNext();
|
||||
this.m_NetworkRotation = (float)stream.ReceiveNext();
|
||||
|
||||
if (this.m_TeleportEnabled)
|
||||
{
|
||||
if (Vector3.Distance(this.m_Body.position, this.m_NetworkPosition) > this.m_TeleportIfDistanceGreaterThan)
|
||||
{
|
||||
this.m_Body.position = this.m_NetworkPosition;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.m_SynchronizeVelocity || this.m_SynchronizeAngularVelocity)
|
||||
{
|
||||
float lag = Mathf.Abs((float)(PhotonNetwork.Time - info.SentServerTime));
|
||||
|
||||
if (m_SynchronizeVelocity)
|
||||
{
|
||||
this.m_Body.velocity = (Vector2)stream.ReceiveNext();
|
||||
|
||||
this.m_NetworkPosition += this.m_Body.velocity * lag;
|
||||
|
||||
this.m_Distance = Vector2.Distance(this.m_Body.position, this.m_NetworkPosition);
|
||||
}
|
||||
|
||||
if (this.m_SynchronizeAngularVelocity)
|
||||
{
|
||||
this.m_Body.angularVelocity = (float)stream.ReceiveNext();
|
||||
|
||||
this.m_NetworkRotation += this.m_Body.angularVelocity * lag;
|
||||
|
||||
this.m_Angle = Mathf.Abs(this.m_Body.rotation - this.m_NetworkRotation);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0e7cb724808c322458aa4d15f5035fa9
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
@ -0,0 +1,112 @@
|
||||
// ----------------------------------------------------------------------------
|
||||
// <copyright file="PhotonRigidbodyView.cs" company="Exit Games GmbH">
|
||||
// PhotonNetwork Framework for Unity - Copyright (C) 2018 Exit Games GmbH
|
||||
// </copyright>
|
||||
// <summary>
|
||||
// Component to synchronize rigidbodies via PUN.
|
||||
// </summary>
|
||||
// <author>developer@exitgames.com</author>
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
|
||||
namespace Photon.Pun
|
||||
{
|
||||
using UnityEngine;
|
||||
|
||||
|
||||
[RequireComponent(typeof(Rigidbody))]
|
||||
[AddComponentMenu("Photon Networking/Photon Rigidbody View")]
|
||||
public class PhotonRigidbodyView : MonoBehaviourPun, IPunObservable
|
||||
{
|
||||
private float m_Distance;
|
||||
private float m_Angle;
|
||||
|
||||
private Rigidbody m_Body;
|
||||
|
||||
private Vector3 m_NetworkPosition;
|
||||
|
||||
private Quaternion m_NetworkRotation;
|
||||
|
||||
[HideInInspector]
|
||||
public bool m_SynchronizeVelocity = true;
|
||||
[HideInInspector]
|
||||
public bool m_SynchronizeAngularVelocity = false;
|
||||
|
||||
[HideInInspector]
|
||||
public bool m_TeleportEnabled = false;
|
||||
[HideInInspector]
|
||||
public float m_TeleportIfDistanceGreaterThan = 3.0f;
|
||||
|
||||
public void Awake()
|
||||
{
|
||||
this.m_Body = GetComponent<Rigidbody>();
|
||||
|
||||
this.m_NetworkPosition = new Vector3();
|
||||
this.m_NetworkRotation = new Quaternion();
|
||||
}
|
||||
|
||||
public void FixedUpdate()
|
||||
{
|
||||
if (!this.photonView.IsMine)
|
||||
{
|
||||
this.m_Body.position = Vector3.MoveTowards(this.m_Body.position, this.m_NetworkPosition, this.m_Distance * (1.0f / PhotonNetwork.SerializationRate));
|
||||
this.m_Body.rotation = Quaternion.RotateTowards(this.m_Body.rotation, this.m_NetworkRotation, this.m_Angle * (1.0f / PhotonNetwork.SerializationRate));
|
||||
}
|
||||
}
|
||||
|
||||
public void OnPhotonSerializeView(PhotonStream stream, PhotonMessageInfo info)
|
||||
{
|
||||
if (stream.IsWriting)
|
||||
{
|
||||
stream.SendNext(this.m_Body.position);
|
||||
stream.SendNext(this.m_Body.rotation);
|
||||
|
||||
if (this.m_SynchronizeVelocity)
|
||||
{
|
||||
stream.SendNext(this.m_Body.velocity);
|
||||
}
|
||||
|
||||
if (this.m_SynchronizeAngularVelocity)
|
||||
{
|
||||
stream.SendNext(this.m_Body.angularVelocity);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
this.m_NetworkPosition = (Vector3)stream.ReceiveNext();
|
||||
this.m_NetworkRotation = (Quaternion)stream.ReceiveNext();
|
||||
|
||||
if (this.m_TeleportEnabled)
|
||||
{
|
||||
if (Vector3.Distance(this.m_Body.position, this.m_NetworkPosition) > this.m_TeleportIfDistanceGreaterThan)
|
||||
{
|
||||
this.m_Body.position = this.m_NetworkPosition;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.m_SynchronizeVelocity || this.m_SynchronizeAngularVelocity)
|
||||
{
|
||||
float lag = Mathf.Abs((float)(PhotonNetwork.Time - info.SentServerTime));
|
||||
|
||||
if (this.m_SynchronizeVelocity)
|
||||
{
|
||||
this.m_Body.velocity = (Vector3)stream.ReceiveNext();
|
||||
|
||||
this.m_NetworkPosition += this.m_Body.velocity * lag;
|
||||
|
||||
this.m_Distance = Vector3.Distance(this.m_Body.position, this.m_NetworkPosition);
|
||||
}
|
||||
|
||||
if (this.m_SynchronizeAngularVelocity)
|
||||
{
|
||||
this.m_Body.angularVelocity = (Vector3)stream.ReceiveNext();
|
||||
|
||||
this.m_NetworkRotation = Quaternion.Euler(this.m_Body.angularVelocity * lag) * this.m_NetworkRotation;
|
||||
|
||||
this.m_Angle = Quaternion.Angle(this.m_Body.rotation, this.m_NetworkRotation);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 64179f3720bbfe947b7724caa67b7c1d
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
@ -0,0 +1,194 @@
|
||||
// ----------------------------------------------------------------------------
|
||||
// <copyright file="PhotonTransformView.cs" company="Exit Games GmbH">
|
||||
// PhotonNetwork Framework for Unity - Copyright (C) 2018 Exit Games GmbH
|
||||
// </copyright>
|
||||
// <summary>
|
||||
// Component to synchronize Transforms via PUN PhotonView.
|
||||
// </summary>
|
||||
// <author>developer@exitgames.com</author>
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
|
||||
namespace Photon.Pun
|
||||
{
|
||||
using UnityEngine;
|
||||
|
||||
[AddComponentMenu("Photon Networking/Photon Transform View")]
|
||||
[HelpURL("https://doc.photonengine.com/en-us/pun/v2/gameplay/synchronization-and-state")]
|
||||
public class PhotonTransformView : MonoBehaviourPun, IPunObservable
|
||||
{
|
||||
private float m_Distance;
|
||||
private float m_Angle;
|
||||
|
||||
private Vector3 m_Direction;
|
||||
private Vector3 m_NetworkPosition;
|
||||
private Vector3 m_StoredPosition;
|
||||
|
||||
private Quaternion m_NetworkRotation;
|
||||
|
||||
public bool m_SynchronizePosition = true;
|
||||
public bool m_SynchronizeRotation = true;
|
||||
public bool m_SynchronizeScale = false;
|
||||
|
||||
[Tooltip("Indicates if localPosition and localRotation should be used. Scale ignores this setting, and always uses localScale to avoid issues with lossyScale.")]
|
||||
public bool m_UseLocal;
|
||||
|
||||
bool m_firstTake = false;
|
||||
|
||||
public void Awake()
|
||||
{
|
||||
m_StoredPosition = transform.localPosition;
|
||||
m_NetworkPosition = Vector3.zero;
|
||||
|
||||
m_NetworkRotation = Quaternion.identity;
|
||||
}
|
||||
|
||||
private void Reset()
|
||||
{
|
||||
// Only default to true with new instances. useLocal will remain false for old projects that are updating PUN.
|
||||
m_UseLocal = true;
|
||||
}
|
||||
|
||||
void OnEnable()
|
||||
{
|
||||
m_firstTake = true;
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
var tr = transform;
|
||||
|
||||
if (!this.photonView.IsMine)
|
||||
{
|
||||
if (m_UseLocal)
|
||||
|
||||
{
|
||||
tr.localPosition = Vector3.MoveTowards(tr.localPosition, this.m_NetworkPosition, this.m_Distance * Time.deltaTime * PhotonNetwork.SerializationRate);
|
||||
tr.localRotation = Quaternion.RotateTowards(tr.localRotation, this.m_NetworkRotation, this.m_Angle * Time.deltaTime * PhotonNetwork.SerializationRate);
|
||||
}
|
||||
else
|
||||
{
|
||||
tr.position = Vector3.MoveTowards(tr.position, this.m_NetworkPosition, this.m_Distance * Time.deltaTime * PhotonNetwork.SerializationRate);
|
||||
tr.rotation = Quaternion.RotateTowards(tr.rotation, this.m_NetworkRotation, this.m_Angle * Time.deltaTime * PhotonNetwork.SerializationRate);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void OnPhotonSerializeView(PhotonStream stream, PhotonMessageInfo info)
|
||||
{
|
||||
var tr = transform;
|
||||
|
||||
// Write
|
||||
if (stream.IsWriting)
|
||||
{
|
||||
if (this.m_SynchronizePosition)
|
||||
{
|
||||
if (m_UseLocal)
|
||||
{
|
||||
this.m_Direction = tr.localPosition - this.m_StoredPosition;
|
||||
this.m_StoredPosition = tr.localPosition;
|
||||
stream.SendNext(tr.localPosition);
|
||||
stream.SendNext(this.m_Direction);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.m_Direction = tr.position - this.m_StoredPosition;
|
||||
this.m_StoredPosition = tr.position;
|
||||
stream.SendNext(tr.position);
|
||||
stream.SendNext(this.m_Direction);
|
||||
}
|
||||
}
|
||||
|
||||
if (this.m_SynchronizeRotation)
|
||||
{
|
||||
if (m_UseLocal)
|
||||
{
|
||||
stream.SendNext(tr.localRotation);
|
||||
}
|
||||
else
|
||||
{
|
||||
stream.SendNext(tr.rotation);
|
||||
}
|
||||
}
|
||||
|
||||
if (this.m_SynchronizeScale)
|
||||
{
|
||||
stream.SendNext(tr.localScale);
|
||||
}
|
||||
}
|
||||
// Read
|
||||
else
|
||||
{
|
||||
if (this.m_SynchronizePosition)
|
||||
{
|
||||
this.m_NetworkPosition = (Vector3)stream.ReceiveNext();
|
||||
this.m_Direction = (Vector3)stream.ReceiveNext();
|
||||
|
||||
if (m_firstTake)
|
||||
{
|
||||
if (m_UseLocal)
|
||||
tr.localPosition = this.m_NetworkPosition;
|
||||
else
|
||||
tr.position = this.m_NetworkPosition;
|
||||
|
||||
this.m_Distance = 0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
float lag = Mathf.Abs((float)(PhotonNetwork.Time - info.SentServerTime));
|
||||
this.m_NetworkPosition += this.m_Direction * lag;
|
||||
if (m_UseLocal)
|
||||
{
|
||||
this.m_Distance = Vector3.Distance(tr.localPosition, this.m_NetworkPosition);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.m_Distance = Vector3.Distance(tr.position, this.m_NetworkPosition);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (this.m_SynchronizeRotation)
|
||||
{
|
||||
this.m_NetworkRotation = (Quaternion)stream.ReceiveNext();
|
||||
|
||||
if (m_firstTake)
|
||||
{
|
||||
this.m_Angle = 0f;
|
||||
|
||||
if (m_UseLocal)
|
||||
{
|
||||
tr.localRotation = this.m_NetworkRotation;
|
||||
}
|
||||
else
|
||||
{
|
||||
tr.rotation = this.m_NetworkRotation;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_UseLocal)
|
||||
{
|
||||
this.m_Angle = Quaternion.Angle(tr.localRotation, this.m_NetworkRotation);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.m_Angle = Quaternion.Angle(tr.rotation, this.m_NetworkRotation);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (this.m_SynchronizeScale)
|
||||
{
|
||||
tr.localScale = (Vector3)stream.ReceiveNext();
|
||||
}
|
||||
|
||||
if (m_firstTake)
|
||||
{
|
||||
m_firstTake = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 627855c7f81362d41938ffe0b1475957
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -0,0 +1,557 @@
|
||||
// ----------------------------------------------------------------------------
|
||||
// <copyright file="PhotonTransformViewClassic.cs" company="Exit Games GmbH">
|
||||
// PhotonNetwork Framework for Unity - Copyright (C) 2018 Exit Games GmbH
|
||||
// </copyright>
|
||||
// <summary>
|
||||
// Component to synchronize Transforms via PUN PhotonView.
|
||||
// </summary>
|
||||
// <author>developer@exitgames.com</author>
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
|
||||
namespace Photon.Pun
|
||||
{
|
||||
using UnityEngine;
|
||||
using System.Collections.Generic;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 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 PhotonTransformViewClassic is added to the list of observed components
|
||||
/// </summary>
|
||||
[AddComponentMenu("Photon Networking/Photon Transform View Classic")]
|
||||
public class PhotonTransformViewClassic : MonoBehaviourPun, IPunObservable
|
||||
{
|
||||
//As this component is very complex, we separated it into multiple classes.
|
||||
//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
|
||||
|
||||
[HideInInspector]
|
||||
public PhotonTransformViewPositionModel m_PositionModel = new PhotonTransformViewPositionModel();
|
||||
|
||||
[HideInInspector]
|
||||
public PhotonTransformViewRotationModel m_RotationModel = new PhotonTransformViewRotationModel();
|
||||
|
||||
[HideInInspector]
|
||||
public PhotonTransformViewScaleModel m_ScaleModel = new PhotonTransformViewScaleModel();
|
||||
|
||||
PhotonTransformViewPositionControl m_PositionControl;
|
||||
PhotonTransformViewRotationControl m_RotationControl;
|
||||
PhotonTransformViewScaleControl m_ScaleControl;
|
||||
|
||||
PhotonView m_PhotonView;
|
||||
|
||||
bool m_ReceivedNetworkUpdate = false;
|
||||
|
||||
/// <summary>
|
||||
/// Flag to skip initial data when Object is instantiated and rely on the first deserialized data instead.
|
||||
/// </summary>
|
||||
bool m_firstTake = false;
|
||||
|
||||
void Awake()
|
||||
{
|
||||
this.m_PhotonView = GetComponent<PhotonView>();
|
||||
|
||||
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.IsConnectedAndReady == 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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
/// <param name="speed">The current movement vector of the object in units/second.</param>
|
||||
/// <param name="turnSpeed">The current turn speed of the object in angles/second.</param>
|
||||
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 (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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[System.Serializable]
|
||||
public class PhotonTransformViewPositionModel
|
||||
{
|
||||
public enum InterpolateOptions
|
||||
{
|
||||
Disabled,
|
||||
FixedSpeed,
|
||||
EstimatedSpeed,
|
||||
SynchronizeValues,
|
||||
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 ExtrapolateOptions ExtrapolateOption = ExtrapolateOptions.Disabled;
|
||||
public float ExtrapolateSpeed = 1f;
|
||||
public bool ExtrapolateIncludingRoundTripTime = true;
|
||||
public int ExtrapolateNumberOfStoredPositions = 1;
|
||||
}
|
||||
|
||||
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<Vector3> m_OldNetworkPositions = new Queue<Vector3>();
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
/// <param name="speed">The current movement vector of the object in units/second.</param>
|
||||
/// <param name="turnSpeed">The current turn speed of the object in angles/second.</param>
|
||||
public void SetSynchronizedValues(Vector3 speed, float turnSpeed)
|
||||
{
|
||||
m_SynchronizedSpeed = speed;
|
||||
m_SynchronizedTurnSpeed = turnSpeed;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calculates the new position based on the values setup in the inspector
|
||||
/// </summary>
|
||||
/// <param name="currentPosition">The current position.</param>
|
||||
/// <returns>The new position.</returns>
|
||||
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.SerializationRate;
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
if (m_Model.TeleportEnabled == true)
|
||||
{
|
||||
if (Vector3.Distance(currentPosition, GetNetworkPosition()) > m_Model.TeleportIfDistanceGreaterThan)
|
||||
{
|
||||
currentPosition = GetNetworkPosition();
|
||||
}
|
||||
}
|
||||
|
||||
return currentPosition;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the last position that was received through the network
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public Vector3 GetNetworkPosition()
|
||||
{
|
||||
return m_NetworkPosition;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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
|
||||
/// </summary>
|
||||
/// <returns>Estimated position of the remote object</returns>
|
||||
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.SerializationRate;
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[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;
|
||||
}
|
||||
|
||||
public class PhotonTransformViewRotationControl
|
||||
{
|
||||
PhotonTransformViewRotationModel m_Model;
|
||||
Quaternion m_NetworkRotation;
|
||||
|
||||
public PhotonTransformViewRotationControl(PhotonTransformViewRotationModel model)
|
||||
{
|
||||
m_Model = model;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the last rotation that was received through the network
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[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;
|
||||
}
|
||||
|
||||
public class PhotonTransformViewScaleControl
|
||||
{
|
||||
PhotonTransformViewScaleModel m_Model;
|
||||
Vector3 m_NetworkScale = Vector3.one;
|
||||
|
||||
public PhotonTransformViewScaleControl(PhotonTransformViewScaleModel model)
|
||||
{
|
||||
m_Model = model;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the last scale that was received through the network
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8efc6b1d64977384eb3405357896c656
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
7
Assets/Photon/PhotonUnityNetworking/Demos.meta
Normal file
7
Assets/Photon/PhotonUnityNetworking/Demos.meta
Normal file
@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cb8ec42b3fa78bd4f9a20b7de289d9cd
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 836b5819c0347f0458f3e374fa3c2230
|
||||
folderAsset: yes
|
||||
timeCreated: 1508416790
|
||||
licenseType: Store
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: eb89ce1e7485b214d8f27d2f3901474c
|
||||
folderAsset: yes
|
||||
timeCreated: 1505213271
|
||||
licenseType: Store
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -0,0 +1,153 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!21 &2100000
|
||||
Material:
|
||||
serializedVersion: 6
|
||||
m_ObjectHideFlags: 0
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 0}
|
||||
m_Name: FlyerAsteroid
|
||||
m_Shader: {fileID: 45, guid: 0000000000000000f000000000000000, type: 0}
|
||||
m_ShaderKeywords: _EMISSION
|
||||
m_LightmapFlags: 0
|
||||
m_CustomRenderQueue: -1
|
||||
stringTagMap: {}
|
||||
m_SavedProperties:
|
||||
serializedVersion: 2
|
||||
m_TexEnvs:
|
||||
data:
|
||||
first:
|
||||
name: _MainTex
|
||||
second:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
data:
|
||||
first:
|
||||
name: _BumpMap
|
||||
second:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
data:
|
||||
first:
|
||||
name: _DetailNormalMap
|
||||
second:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
data:
|
||||
first:
|
||||
name: _ParallaxMap
|
||||
second:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
data:
|
||||
first:
|
||||
name: _OcclusionMap
|
||||
second:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
data:
|
||||
first:
|
||||
name: _EmissionMap
|
||||
second:
|
||||
m_Texture: {fileID: 2800000, guid: bfc02e2f0447eaf4190d17879193f0e2, type: 3}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
data:
|
||||
first:
|
||||
name: _DetailMask
|
||||
second:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
data:
|
||||
first:
|
||||
name: _DetailAlbedoMap
|
||||
second:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
data:
|
||||
first:
|
||||
name: _MetallicGlossMap
|
||||
second:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
data:
|
||||
first:
|
||||
name: _SpecGlossMap
|
||||
second:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
m_Floats:
|
||||
data:
|
||||
first:
|
||||
name: _SrcBlend
|
||||
second: 1
|
||||
data:
|
||||
first:
|
||||
name: _DstBlend
|
||||
second: 0
|
||||
data:
|
||||
first:
|
||||
name: _Cutoff
|
||||
second: 0.5
|
||||
data:
|
||||
first:
|
||||
name: _Parallax
|
||||
second: 0.02
|
||||
data:
|
||||
first:
|
||||
name: _ZWrite
|
||||
second: 1
|
||||
data:
|
||||
first:
|
||||
name: _Glossiness
|
||||
second: 0.3
|
||||
data:
|
||||
first:
|
||||
name: _BumpScale
|
||||
second: 1
|
||||
data:
|
||||
first:
|
||||
name: _OcclusionStrength
|
||||
second: 1
|
||||
data:
|
||||
first:
|
||||
name: _DetailNormalMapScale
|
||||
second: 1
|
||||
data:
|
||||
first:
|
||||
name: _UVSec
|
||||
second: 0
|
||||
data:
|
||||
first:
|
||||
name: _Mode
|
||||
second: 0
|
||||
data:
|
||||
first:
|
||||
name: _Metallic
|
||||
second: 0
|
||||
data:
|
||||
first:
|
||||
name: _Alpha
|
||||
second: 1
|
||||
m_Colors:
|
||||
data:
|
||||
first:
|
||||
name: _EmissionColor
|
||||
second: {r: 0.2, g: 0.2, b: 0.2, a: 1}
|
||||
data:
|
||||
first:
|
||||
name: _Color
|
||||
second: {r: 1, g: 1, b: 1, a: 1}
|
||||
data:
|
||||
first:
|
||||
name: _SpecColor
|
||||
second: {r: 0.15686275, g: 0.15686275, b: 0.15686275, a: 1}
|
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 968fc57e6928a5448ae7d0644246d534
|
||||
timeCreated: 1505213348
|
||||
licenseType: Store
|
||||
NativeFormatImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -0,0 +1,149 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!21 &2100000
|
||||
Material:
|
||||
serializedVersion: 6
|
||||
m_ObjectHideFlags: 0
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 0}
|
||||
m_Name: FlyerPlayership
|
||||
m_Shader: {fileID: 45, guid: 0000000000000000f000000000000000, type: 0}
|
||||
m_ShaderKeywords: _EMISSION
|
||||
m_LightmapFlags: 0
|
||||
m_CustomRenderQueue: -1
|
||||
stringTagMap: {}
|
||||
m_SavedProperties:
|
||||
serializedVersion: 2
|
||||
m_TexEnvs:
|
||||
data:
|
||||
first:
|
||||
name: _MainTex
|
||||
second:
|
||||
m_Texture: {fileID: 2800000, guid: b28381ec2a3dce5459a8fd396a0eb560, type: 3}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
data:
|
||||
first:
|
||||
name: _BumpMap
|
||||
second:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
data:
|
||||
first:
|
||||
name: _DetailNormalMap
|
||||
second:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
data:
|
||||
first:
|
||||
name: _ParallaxMap
|
||||
second:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
data:
|
||||
first:
|
||||
name: _OcclusionMap
|
||||
second:
|
||||
m_Texture: {fileID: 2800000, guid: 34b19bc20b665b240af9c0fc9d0086f6, type: 3}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
data:
|
||||
first:
|
||||
name: _EmissionMap
|
||||
second:
|
||||
m_Texture: {fileID: 2800000, guid: 88217866776ce4c49944ecb360a5c6ca, type: 3}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
data:
|
||||
first:
|
||||
name: _DetailMask
|
||||
second:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
data:
|
||||
first:
|
||||
name: _DetailAlbedoMap
|
||||
second:
|
||||
m_Texture: {fileID: 2800000, guid: 2b0c5290f03c1e84dbb05f573458a568, type: 3}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
data:
|
||||
first:
|
||||
name: _MetallicGlossMap
|
||||
second:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
data:
|
||||
first:
|
||||
name: _SpecGlossMap
|
||||
second:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
m_Floats:
|
||||
data:
|
||||
first:
|
||||
name: _SrcBlend
|
||||
second: 1
|
||||
data:
|
||||
first:
|
||||
name: _DstBlend
|
||||
second: 0
|
||||
data:
|
||||
first:
|
||||
name: _Cutoff
|
||||
second: 0.5
|
||||
data:
|
||||
first:
|
||||
name: _Parallax
|
||||
second: 0.02
|
||||
data:
|
||||
first:
|
||||
name: _ZWrite
|
||||
second: 1
|
||||
data:
|
||||
first:
|
||||
name: _Glossiness
|
||||
second: 0.8
|
||||
data:
|
||||
first:
|
||||
name: _BumpScale
|
||||
second: 1
|
||||
data:
|
||||
first:
|
||||
name: _OcclusionStrength
|
||||
second: 1
|
||||
data:
|
||||
first:
|
||||
name: _DetailNormalMapScale
|
||||
second: 1
|
||||
data:
|
||||
first:
|
||||
name: _UVSec
|
||||
second: 1
|
||||
data:
|
||||
first:
|
||||
name: _Mode
|
||||
second: 0
|
||||
data:
|
||||
first:
|
||||
name: _Metallic
|
||||
second: 0
|
||||
m_Colors:
|
||||
data:
|
||||
first:
|
||||
name: _EmissionColor
|
||||
second: {r: 1.8382353, g: 1.8382353, b: 1.8382353, a: 1}
|
||||
data:
|
||||
first:
|
||||
name: _Color
|
||||
second: {r: 1, g: 1, b: 1, a: 1}
|
||||
data:
|
||||
first:
|
||||
name: _SpecColor
|
||||
second: {r: 0.078431375, g: 0.078431375, b: 0.078431375, a: 1}
|
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 99fced4bc2985174cac8512dc765d2bc
|
||||
timeCreated: 1505213348
|
||||
licenseType: Store
|
||||
NativeFormatImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -0,0 +1,40 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!21 &2100000
|
||||
Material:
|
||||
serializedVersion: 3
|
||||
m_ObjectHideFlags: 0
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 0}
|
||||
m_Name: ParticleAfterburner
|
||||
m_Shader: {fileID: 200, guid: 0000000000000000f000000000000000, type: 0}
|
||||
m_ShaderKeywords: []
|
||||
m_CustomRenderQueue: -1
|
||||
m_SavedProperties:
|
||||
serializedVersion: 2
|
||||
m_TexEnvs:
|
||||
data:
|
||||
first:
|
||||
name: _MainTex
|
||||
second:
|
||||
m_Texture: {fileID: 10300, guid: 0000000000000000f000000000000000, type: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
m_Floats:
|
||||
data:
|
||||
first:
|
||||
name: _InvFade
|
||||
second: 1.26696432
|
||||
m_Colors:
|
||||
data:
|
||||
first:
|
||||
name: _Color
|
||||
second: {r: 1, g: 1, b: 1, a: 1}
|
||||
data:
|
||||
first:
|
||||
name: _TintColor
|
||||
second: {r: 1, g: 1, b: 1, a: 1}
|
||||
data:
|
||||
first:
|
||||
name: _EmisColor
|
||||
second: {r: .200000003, g: .200000003, b: .200000003, a: 0}
|
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: dc1a05fba9a6af241a25a35b4caf5e27
|
||||
timeCreated: 1505213349
|
||||
licenseType: Store
|
||||
NativeFormatImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -0,0 +1,174 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!21 &2100000
|
||||
Material:
|
||||
serializedVersion: 4
|
||||
m_ObjectHideFlags: 0
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 0}
|
||||
m_Name: WhiteSmooth
|
||||
m_Shader: {fileID: 45, guid: 0000000000000000f000000000000000, type: 0}
|
||||
m_ShaderKeywords: _LIGHTMAPPING_DYNAMIC_LIGHTMAPS _LIGHTMAPPING_REALTIME _UVSEC_UV1
|
||||
m_CustomRenderQueue: -1
|
||||
m_SavedProperties:
|
||||
serializedVersion: 2
|
||||
m_TexEnvs:
|
||||
data:
|
||||
first:
|
||||
name: _MainTex
|
||||
second:
|
||||
m_Texture: {fileID: 2800000, guid: c798603beb3c1fc4a96620cf6b35cc32, type: 3}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
data:
|
||||
first:
|
||||
name: _BumpMap
|
||||
second:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
data:
|
||||
first:
|
||||
name: _DetailNormalMap
|
||||
second:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
data:
|
||||
first:
|
||||
name: _EmissionMap
|
||||
second:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
data:
|
||||
first:
|
||||
name: _ParallaxMap
|
||||
second:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
data:
|
||||
first:
|
||||
name: _Occlusion
|
||||
second:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
data:
|
||||
first:
|
||||
name: _SpecGlossMap
|
||||
second:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
data:
|
||||
first:
|
||||
name: _DetailMask
|
||||
second:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
data:
|
||||
first:
|
||||
name: _DetailAlbedoMap
|
||||
second:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
data:
|
||||
first:
|
||||
name: _OcclusionMap
|
||||
second:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
data:
|
||||
first:
|
||||
name: _MetallicGlossMap
|
||||
second:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
m_Floats:
|
||||
data:
|
||||
first:
|
||||
name: _AlphaTestRef
|
||||
second: .5
|
||||
data:
|
||||
first:
|
||||
name: _Lightmapping
|
||||
second: 1
|
||||
data:
|
||||
first:
|
||||
name: _SrcBlend
|
||||
second: 1
|
||||
data:
|
||||
first:
|
||||
name: _DstBlend
|
||||
second: 0
|
||||
data:
|
||||
first:
|
||||
name: _Parallax
|
||||
second: .0199999996
|
||||
data:
|
||||
first:
|
||||
name: _ZWrite
|
||||
second: 1
|
||||
data:
|
||||
first:
|
||||
name: _Glossiness
|
||||
second: .100000001
|
||||
data:
|
||||
first:
|
||||
name: _BumpScale
|
||||
second: 1
|
||||
data:
|
||||
first:
|
||||
name: _OcclusionStrength
|
||||
second: 1
|
||||
data:
|
||||
first:
|
||||
name: _DetailNormalMapScale
|
||||
second: 1
|
||||
data:
|
||||
first:
|
||||
name: _UVSec
|
||||
second: 0
|
||||
data:
|
||||
first:
|
||||
name: _Mode
|
||||
second: 0
|
||||
data:
|
||||
first:
|
||||
name: _EmissionScaleUI
|
||||
second: 0
|
||||
data:
|
||||
first:
|
||||
name: _Metallic
|
||||
second: .100000001
|
||||
m_Colors:
|
||||
data:
|
||||
first:
|
||||
name: _EmissionColor
|
||||
second: {r: 0, g: 0, b: 0, a: 0}
|
||||
data:
|
||||
first:
|
||||
name: _Color
|
||||
second: {r: 1, g: 1, b: 1, a: 1}
|
||||
data:
|
||||
first:
|
||||
name: _SpecularColor
|
||||
second: {r: .156862751, g: .156862751, b: .156862751, a: 1}
|
||||
data:
|
||||
first:
|
||||
name: _EmissionColorUI
|
||||
second: {r: 0, g: 0, b: 0, a: 1}
|
||||
data:
|
||||
first:
|
||||
name: _EmissionColorWithMapUI
|
||||
second: {r: 1, g: 1, b: 1, a: 1}
|
||||
data:
|
||||
first:
|
||||
name: _SpecColor
|
||||
second: {r: .117647059, g: .117647059, b: .117647059, a: 1}
|
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b05171e12835ff84fb155f51d69d7c31
|
||||
timeCreated: 1505213348
|
||||
licenseType: Store
|
||||
NativeFormatImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -0,0 +1,180 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!21 &2100000
|
||||
Material:
|
||||
serializedVersion: 6
|
||||
m_ObjectHideFlags: 0
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 0}
|
||||
m_Name: WhiteUnlit
|
||||
m_Shader: {fileID: 10755, guid: 0000000000000000f000000000000000, type: 0}
|
||||
m_ShaderKeywords: _LIGHTMAPPING_DYNAMIC_LIGHTMAPS _LIGHTMAPPING_REALTIME _UVSEC_UV1
|
||||
m_LightmapFlags: 5
|
||||
m_CustomRenderQueue: -1
|
||||
stringTagMap: {}
|
||||
m_SavedProperties:
|
||||
serializedVersion: 2
|
||||
m_TexEnvs:
|
||||
data:
|
||||
first:
|
||||
name: _MainTex
|
||||
second:
|
||||
m_Texture: {fileID: 2800000, guid: c798603beb3c1fc4a96620cf6b35cc32, type: 3}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
data:
|
||||
first:
|
||||
name: _BumpMap
|
||||
second:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
data:
|
||||
first:
|
||||
name: _DetailNormalMap
|
||||
second:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
data:
|
||||
first:
|
||||
name: _ParallaxMap
|
||||
second:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
data:
|
||||
first:
|
||||
name: _OcclusionMap
|
||||
second:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
data:
|
||||
first:
|
||||
name: _EmissionMap
|
||||
second:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
data:
|
||||
first:
|
||||
name: _DetailMask
|
||||
second:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
data:
|
||||
first:
|
||||
name: _DetailAlbedoMap
|
||||
second:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
data:
|
||||
first:
|
||||
name: _Occlusion
|
||||
second:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
data:
|
||||
first:
|
||||
name: _MetallicGlossMap
|
||||
second:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
data:
|
||||
first:
|
||||
name: _SpecGlossMap
|
||||
second:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
m_Floats:
|
||||
data:
|
||||
first:
|
||||
name: _SrcBlend
|
||||
second: 1
|
||||
data:
|
||||
first:
|
||||
name: _DstBlend
|
||||
second: 0
|
||||
data:
|
||||
first:
|
||||
name: _Cutoff
|
||||
second: .5
|
||||
data:
|
||||
first:
|
||||
name: _AlphaTestRef
|
||||
second: .5
|
||||
data:
|
||||
first:
|
||||
name: _Parallax
|
||||
second: .0199999996
|
||||
data:
|
||||
first:
|
||||
name: _Lightmapping
|
||||
second: 1
|
||||
data:
|
||||
first:
|
||||
name: _ZWrite
|
||||
second: 1
|
||||
data:
|
||||
first:
|
||||
name: _Glossiness
|
||||
second: .100000001
|
||||
data:
|
||||
first:
|
||||
name: _BumpScale
|
||||
second: 1
|
||||
data:
|
||||
first:
|
||||
name: _OcclusionStrength
|
||||
second: 1
|
||||
data:
|
||||
first:
|
||||
name: _DetailNormalMapScale
|
||||
second: 1
|
||||
data:
|
||||
first:
|
||||
name: _UVSec
|
||||
second: 0
|
||||
data:
|
||||
first:
|
||||
name: _Mode
|
||||
second: 0
|
||||
data:
|
||||
first:
|
||||
name: _Metallic
|
||||
second: .100000001
|
||||
data:
|
||||
first:
|
||||
name: _EmissionScaleUI
|
||||
second: 0
|
||||
m_Colors:
|
||||
data:
|
||||
first:
|
||||
name: _EmissionColor
|
||||
second: {r: 0, g: 0, b: 0, a: 0}
|
||||
data:
|
||||
first:
|
||||
name: _Color
|
||||
second: {r: 1, g: 1, b: 1, a: 1}
|
||||
data:
|
||||
first:
|
||||
name: _SpecColor
|
||||
second: {r: .117647059, g: .117647059, b: .117647059, a: 1}
|
||||
data:
|
||||
first:
|
||||
name: _SpecularColor
|
||||
second: {r: .156862751, g: .156862751, b: .156862751, a: 1}
|
||||
data:
|
||||
first:
|
||||
name: _EmissionColorUI
|
||||
second: {r: 0, g: 0, b: 0, a: 1}
|
||||
data:
|
||||
first:
|
||||
name: _EmissionColorWithMapUI
|
||||
second: {r: 1, g: 1, b: 1, a: 1}
|
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 073b1ee561def20429e655b5c8893ad4
|
||||
timeCreated: 1505213348
|
||||
licenseType: Store
|
||||
NativeFormatImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ffc8b1d9f846b0f4d9e60bafe6e61a83
|
||||
folderAsset: yes
|
||||
timeCreated: 1505213276
|
||||
licenseType: Store
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user