test
testing
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c0dbb10477565944a8b42db6e26441ff
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
userData:
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: dcbd9d9cedc5c08428abc8d2aea83a12
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
userData:
|
||||
+209
@@ -0,0 +1,209 @@
|
||||
// ----------------------------------------------------------------------------
|
||||
// <copyright file="AccountService.cs" company="Exit Games GmbH">
|
||||
// Photon Cloud Account Service - Copyright (C) 2012 Exit Games GmbH
|
||||
// </copyright>
|
||||
// <summary>
|
||||
// Provides methods to register a new user-account for the Photon Cloud and
|
||||
// get the resulting appId.
|
||||
// </summary>
|
||||
// <author>developer@exitgames.com</author>
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
using System.Net.Security;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
|
||||
using Newtonsoft.Json;
|
||||
|
||||
public class AccountService
|
||||
{
|
||||
private const string ServiceUrl = "https://service.exitgames.com/AccountExt/AccountServiceExt.aspx";
|
||||
|
||||
private Action<AccountService> registrationCallback; // optional (when using async reg)
|
||||
|
||||
public string Message { get; private set; } // msg from server (in case of success, this is the appid)
|
||||
|
||||
protected internal Exception Exception { get; set; } // exceptions in account-server communication
|
||||
|
||||
public string AppId { get; private set; }
|
||||
|
||||
public int ReturnCode { get; private set; } // 0 = OK. anything else is a error with Message
|
||||
|
||||
public enum Origin : byte { ServerWeb = 1, CloudWeb = 2, Pun = 3, Playmaker = 4 };
|
||||
|
||||
/// <summary>
|
||||
/// Creates a instance of the Account Service to register Photon Cloud accounts.
|
||||
/// </summary>
|
||||
public AccountService()
|
||||
{
|
||||
WebRequest.DefaultWebProxy = null;
|
||||
ServicePointManager.ServerCertificateValidationCallback = Validator;
|
||||
}
|
||||
|
||||
public static bool Validator(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors policyErrors)
|
||||
{
|
||||
return true; // any certificate is ok in this case
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to create a Photon Cloud Account.
|
||||
/// Check ReturnCode, Message and AppId to get the result of this attempt.
|
||||
/// </summary>
|
||||
/// <param name="email">Email of the account.</param>
|
||||
/// <param name="origin">Marks which channel created the new account (if it's new).</param>
|
||||
public void RegisterByEmail(string email, Origin origin)
|
||||
{
|
||||
this.registrationCallback = null;
|
||||
this.AppId = string.Empty;
|
||||
this.Message = string.Empty;
|
||||
this.ReturnCode = -1;
|
||||
|
||||
string result;
|
||||
try
|
||||
{
|
||||
WebRequest req = HttpWebRequest.Create(this.RegistrationUri(email, (byte)origin));
|
||||
HttpWebResponse resp = req.GetResponse() as HttpWebResponse;
|
||||
|
||||
// now read result
|
||||
StreamReader reader = new StreamReader(resp.GetResponseStream());
|
||||
result = reader.ReadToEnd();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
this.Message = "Failed to connect to Cloud Account Service. Please register via account website.";
|
||||
this.Exception = ex;
|
||||
return;
|
||||
}
|
||||
|
||||
this.ParseResult(result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to create a Photon Cloud Account asynchronously.
|
||||
/// Once your callback is called, check ReturnCode, Message and AppId to get the result of this attempt.
|
||||
/// </summary>
|
||||
/// <param name="email">Email of the account.</param>
|
||||
/// <param name="origin">Marks which channel created the new account (if it's new).</param>
|
||||
/// <param name="callback">Called when the result is available.</param>
|
||||
public void RegisterByEmailAsync(string email, Origin origin, Action<AccountService> callback = null)
|
||||
{
|
||||
this.registrationCallback = callback;
|
||||
this.AppId = string.Empty;
|
||||
this.Message = string.Empty;
|
||||
this.ReturnCode = -1;
|
||||
|
||||
try
|
||||
{
|
||||
HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create(this.RegistrationUri(email, (byte)origin));
|
||||
req.Timeout = 5000;
|
||||
req.BeginGetResponse(this.OnRegisterByEmailCompleted, req);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
this.Message = "Failed to connect to Cloud Account Service. Please register via account website.";
|
||||
this.Exception = ex;
|
||||
if (this.registrationCallback != null)
|
||||
{
|
||||
this.registrationCallback(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Internal callback with result of async HttpWebRequest (in RegisterByEmailAsync).
|
||||
/// </summary>
|
||||
/// <param name="ar"></param>
|
||||
private void OnRegisterByEmailCompleted(IAsyncResult ar)
|
||||
{
|
||||
try
|
||||
{
|
||||
HttpWebRequest request = (HttpWebRequest)ar.AsyncState;
|
||||
HttpWebResponse response = request.EndGetResponse(ar) as HttpWebResponse;
|
||||
|
||||
if (response != null && response.StatusCode == HttpStatusCode.OK)
|
||||
{
|
||||
// no error. use the result
|
||||
StreamReader reader = new StreamReader(response.GetResponseStream());
|
||||
string result = reader.ReadToEnd();
|
||||
|
||||
this.ParseResult(result);
|
||||
}
|
||||
else
|
||||
{
|
||||
// a response but some error on server. show message
|
||||
this.Message = "Failed to connect to Cloud Account Service. Please register via account website.";
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// not even a response. show message
|
||||
this.Message = "Failed to connect to Cloud Account Service. Please register via account website.";
|
||||
this.Exception = ex;
|
||||
}
|
||||
|
||||
if (this.registrationCallback != null)
|
||||
{
|
||||
this.registrationCallback(this);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates the service-call Uri, escaping the email for security reasons.
|
||||
/// </summary>
|
||||
/// <param name="email">Email of the account.</param>
|
||||
/// <param name="origin">1 = server-web, 2 = cloud-web, 3 = PUN, 4 = playmaker</param>
|
||||
/// <returns>Uri to call.</returns>
|
||||
private Uri RegistrationUri(string email, byte origin)
|
||||
{
|
||||
string emailEncoded = Uri.EscapeDataString(email);
|
||||
string uriString = string.Format("{0}?email={1}&origin={2}", ServiceUrl, emailEncoded, origin);
|
||||
|
||||
return new Uri(uriString);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads the Json response and applies it to local properties.
|
||||
/// </summary>
|
||||
/// <param name="result"></param>
|
||||
private void ParseResult(string result)
|
||||
{
|
||||
if (string.IsNullOrEmpty(result))
|
||||
{
|
||||
this.Message = "Server's response was empty. Please register through account website during this service interruption.";
|
||||
return;
|
||||
}
|
||||
|
||||
Dictionary<string, string> values = JsonConvert.DeserializeObject<Dictionary<string, string>>(result);
|
||||
if (values == null)
|
||||
{
|
||||
this.Message = "Service temporarily unavailable. Please register through account website.";
|
||||
return;
|
||||
}
|
||||
|
||||
int returnCodeInt = -1;
|
||||
string returnCodeString = string.Empty;
|
||||
string message;
|
||||
|
||||
values.TryGetValue("ReturnCode", out returnCodeString);
|
||||
values.TryGetValue("Message", out message);
|
||||
int.TryParse(returnCodeString, out returnCodeInt);
|
||||
|
||||
this.ReturnCode = returnCodeInt;
|
||||
if (returnCodeInt == 0)
|
||||
{
|
||||
// returnCode == 0 means: all ok. message is new AppId
|
||||
this.AppId = message;
|
||||
}
|
||||
else
|
||||
{
|
||||
// any error gives returnCode != 0
|
||||
this.AppId = string.Empty;
|
||||
this.Message = message;
|
||||
}
|
||||
}
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 166dfe22956ef0341b28e18d0499e363
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
BIN
Binary file not shown.
+7
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0268f98d7c649564a818b0768fc68d4b
|
||||
MonoAssemblyImporter:
|
||||
serializedVersion: 1
|
||||
iconMap: {}
|
||||
executionOrder: {}
|
||||
userData:
|
||||
+341
@@ -0,0 +1,341 @@
|
||||
// ----------------------------------------------------------------------------
|
||||
// <copyright file="PhotonConverter.cs" company="Exit Games GmbH">
|
||||
// PhotonNetwork Framework for Unity - Copyright (C) 2011 Exit Games GmbH
|
||||
// </copyright>
|
||||
// <summary>
|
||||
// Script to convert a Unity Networking project to PhotonNetwork.
|
||||
// </summary>
|
||||
// <author>developer@exitgames.com</author>
|
||||
// ----------------------------------------------------------------------------
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
public class PhotonConverter : Photon.MonoBehaviour
|
||||
{
|
||||
|
||||
public static void RunConversion()
|
||||
{
|
||||
//Ask if user has made a backup.
|
||||
bool result = EditorUtility.DisplayDialog("Conversion", "Did you create a backup of your project before converting?", "Yes", "Abort conversion");
|
||||
if (!result)
|
||||
{
|
||||
return;
|
||||
}
|
||||
//REAAAALY?
|
||||
result = EditorUtility.DisplayDialog("Conversion", "Disclaimer: The code conversion feature is quite crude, but should do it's job well (see the sourcecode). A backup is therefore strongly recommended!", "Yes, I've made a backup: GO", "Abort");
|
||||
if (!result)
|
||||
{
|
||||
return;
|
||||
}
|
||||
Output(EditorApplication.timeSinceStartup + " Started conversion of Unity networking -> Photon");
|
||||
|
||||
//Ask to save current scene (optional)
|
||||
EditorApplication.SaveCurrentSceneIfUserWantsTo();
|
||||
|
||||
EditorUtility.DisplayProgressBar("Converting..", "Starting.", 0);
|
||||
|
||||
//Convert NetworkViews to PhotonViews in Project prefabs
|
||||
//Ask the user if we can move all prefabs to a resources folder
|
||||
bool movePrefabs = EditorUtility.DisplayDialog("Conversion", "Can all prefabs that use a PhotonView be moved to a Resources/ folder? You need this if you use Network.Instantiate.", "Yes", "No");
|
||||
|
||||
|
||||
string[] prefabs = Directory.GetFiles("Assets/", "*.prefab", SearchOption.AllDirectories);
|
||||
foreach (string prefab in prefabs)
|
||||
{
|
||||
EditorUtility.DisplayProgressBar("Converting..", "Object:" + prefab, 0.6f);
|
||||
|
||||
Object[] objs = (Object[])AssetDatabase.LoadAllAssetsAtPath(prefab);
|
||||
int converted = 0;
|
||||
foreach (Object obj in objs)
|
||||
{
|
||||
if (obj != null && obj.GetType() == typeof(GameObject))
|
||||
converted += ConvertNetworkView(((GameObject)obj).GetComponents<NetworkView>(), false);
|
||||
}
|
||||
if (movePrefabs && converted > 0)
|
||||
{
|
||||
//This prefab needs to be under the root of a Resources folder!
|
||||
string path = prefab.Replace("\\", "/");
|
||||
int lastSlash = path.LastIndexOf("/");
|
||||
int resourcesIndex = path.LastIndexOf("/Resources/");
|
||||
if (resourcesIndex != lastSlash - 10)
|
||||
{
|
||||
if (path.Contains("/Resources/"))
|
||||
{
|
||||
Debug.LogWarning("Warning, prefab [" + prefab + "] was already in a resources folder. But has been placed in the root of another one!");
|
||||
}
|
||||
//This prefab NEEDS to be placed under a resources folder
|
||||
string resourcesFolder = path.Substring(0, lastSlash) + "/Resources/";
|
||||
EnsureFolder(resourcesFolder);
|
||||
string newPath = resourcesFolder + path.Substring(lastSlash + 1);
|
||||
string error = AssetDatabase.MoveAsset(prefab, newPath);
|
||||
if (error != "")
|
||||
Debug.LogError(error);
|
||||
Output("Fixed prefab [" + prefab + "] by moving it into a resources folder.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Convert NetworkViews to PhotonViews in scenes
|
||||
string[] sceneFiles = Directory.GetFiles("Assets/", "*.unity", SearchOption.AllDirectories);
|
||||
foreach (string sceneName in sceneFiles)
|
||||
{
|
||||
EditorApplication.OpenScene(sceneName);
|
||||
EditorUtility.DisplayProgressBar("Converting..", "Scene:" + sceneName, 0.2f);
|
||||
|
||||
int converted2 = ConvertNetworkView((NetworkView[])GameObject.FindObjectsOfType(typeof(NetworkView)), true);
|
||||
if (converted2 > 0)
|
||||
{
|
||||
//This will correct all prefabs: The prefabs have gotten new components, but the correct ID's were lost in this case
|
||||
PhotonViewInspector.VerifyAllSceneViews();
|
||||
|
||||
Output("Replaced " + converted2 + " NetworkViews with PhotonViews in scene: " + sceneName);
|
||||
EditorApplication.SaveScene(EditorApplication.currentScene);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//Convert C#/JS scripts (API stuff)
|
||||
List<string> scripts = new List<string>();
|
||||
scripts.AddRange(Directory.GetFiles("Assets/", "*.cs", SearchOption.AllDirectories));
|
||||
scripts.AddRange(Directory.GetFiles("Assets/", "*.js", SearchOption.AllDirectories));
|
||||
scripts.AddRange(Directory.GetFiles("Assets/", "*.boo", SearchOption.AllDirectories));
|
||||
EditorUtility.DisplayProgressBar("Converting..", "Scripts..", 0.9f);
|
||||
ConvertScripts(scripts);
|
||||
|
||||
Output(EditorApplication.timeSinceStartup + " Completed conversion!");
|
||||
|
||||
EditorUtility.ClearProgressBar();
|
||||
}
|
||||
|
||||
static void ConvertScripts(List<string> scripts)
|
||||
{
|
||||
foreach (string script in scripts)
|
||||
{
|
||||
if (script.Contains("PhotonNetwork"))//Don't convert this file (and others)
|
||||
continue;
|
||||
if (script.Contains("Image Effects"))
|
||||
continue;
|
||||
|
||||
string text = File.ReadAllText(script);
|
||||
|
||||
text = ConvertToPhotonAPI(script, text);
|
||||
|
||||
File.WriteAllText(script, text);
|
||||
}
|
||||
foreach (string script in scripts){
|
||||
AssetDatabase.ImportAsset(script, ImportAssetOptions.ForceUpdate);
|
||||
}
|
||||
}
|
||||
|
||||
static string ConvertToPhotonAPI(string file, string input)
|
||||
{
|
||||
bool isJS = file.Contains(".js");
|
||||
|
||||
file =file.Replace("\\", "/"); // Get Class name for JS
|
||||
string className = file.Substring(file.LastIndexOf("/")+1);
|
||||
className = className.Substring(0, className.IndexOf("."));
|
||||
|
||||
|
||||
//REGEXP STUFF
|
||||
//Valid are: Space { } , /n /r
|
||||
//string NOT_VAR = @"([^A-Za-z0-9_\[\]\.]+)";
|
||||
string NOT_VAR_WITH_DOT = @"([^A-Za-z0-9_]+)";
|
||||
|
||||
//string VAR_NONARRAY = @"[^A-Za-z0-9_]";
|
||||
|
||||
|
||||
|
||||
//NetworkView
|
||||
{
|
||||
input = PregReplace(input, NOT_VAR_WITH_DOT + "NetworkView" + NOT_VAR_WITH_DOT, "$1PhotonView$2");
|
||||
input = PregReplace(input, NOT_VAR_WITH_DOT + "networkView" + NOT_VAR_WITH_DOT, "$1photonView$2");
|
||||
input = PregReplace(input, NOT_VAR_WITH_DOT + "stateSynchronization" + NOT_VAR_WITH_DOT, "$1synchronization$2");
|
||||
//.RPC
|
||||
input = PregReplace(input, NOT_VAR_WITH_DOT + "RPCMode.Server" + NOT_VAR_WITH_DOT, "$1PhotonTargets.MasterClient$2");
|
||||
input = PregReplace(input, NOT_VAR_WITH_DOT + "RPCMode" + NOT_VAR_WITH_DOT, "$1PhotonTargets$2");
|
||||
}
|
||||
|
||||
//NetworkMessageInfo: 100%
|
||||
{
|
||||
input = PregReplace(input, NOT_VAR_WITH_DOT + "NetworkMessageInfo" + NOT_VAR_WITH_DOT, "$1PhotonMessageInfo$2");
|
||||
input = PregReplace(input, NOT_VAR_WITH_DOT + "networkView" + NOT_VAR_WITH_DOT, "$1photonView$2");
|
||||
}
|
||||
|
||||
//NetworkViewID:
|
||||
{
|
||||
input = PregReplace(input, NOT_VAR_WITH_DOT + "NetworkViewID" + NOT_VAR_WITH_DOT, "$1PhotonViewID$2");
|
||||
}
|
||||
|
||||
//NetworkPlayer
|
||||
{
|
||||
input = PregReplace(input, NOT_VAR_WITH_DOT + "NetworkPlayer" + NOT_VAR_WITH_DOT, "$1PhotonPlayer$2");
|
||||
}
|
||||
|
||||
//Network
|
||||
{
|
||||
//Monobehaviour callbacks
|
||||
{
|
||||
input = PregReplace(input, NOT_VAR_WITH_DOT + "OnPlayerConnected" + NOT_VAR_WITH_DOT, "$1OnPhotonPlayerConnected$2");
|
||||
input = PregReplace(input, NOT_VAR_WITH_DOT + "OnPlayerDisconnected" + NOT_VAR_WITH_DOT, "$1OnPhotonPlayerDisconnected$2");
|
||||
input = PregReplace(input, NOT_VAR_WITH_DOT + "OnNetworkInstantiate" + NOT_VAR_WITH_DOT, "$1OnPhotonInstantiate$2");
|
||||
input = PregReplace(input, NOT_VAR_WITH_DOT + "OnSerializeNetworkView" + NOT_VAR_WITH_DOT, "$1OnPhotonSerializeView$2");
|
||||
input = PregReplace(input, NOT_VAR_WITH_DOT + "BitStream" + NOT_VAR_WITH_DOT, "$1PhotonStream$2");
|
||||
|
||||
//Not completely the same meaning
|
||||
input = PregReplace(input, NOT_VAR_WITH_DOT + "OnServerInitialized" + NOT_VAR_WITH_DOT, "$1OnCreatedRoom$2");
|
||||
input = PregReplace(input, NOT_VAR_WITH_DOT + "OnConnectedToServer" + NOT_VAR_WITH_DOT, "$1OnJoinedRoom$2");
|
||||
|
||||
input = PregReplace(input, NOT_VAR_WITH_DOT + "OnFailedToConnectToMasterServer" + NOT_VAR_WITH_DOT, "$1OnFailedToConnectToPhoton$2");
|
||||
input = PregReplace(input, NOT_VAR_WITH_DOT + "OnFailedToConnect" + NOT_VAR_WITH_DOT, "$1OnFailedToConnect_OBSELETE$2");
|
||||
}
|
||||
|
||||
//Variables
|
||||
{
|
||||
|
||||
input = PregReplace(input, NOT_VAR_WITH_DOT + "Network.connections" + NOT_VAR_WITH_DOT, "$1PhotonNetwork.playerList$2");
|
||||
input = PregReplace(input, NOT_VAR_WITH_DOT + "Network.isServer" + NOT_VAR_WITH_DOT, "$1PhotonNetwork.isMasterClient$2");
|
||||
input = PregReplace(input, NOT_VAR_WITH_DOT + "Network.isClient" + NOT_VAR_WITH_DOT, "$1PhotonNetwork.isNonMasterClientInRoom$2");
|
||||
|
||||
input = PregReplace(input, NOT_VAR_WITH_DOT + "NetworkPeerType" + NOT_VAR_WITH_DOT, "$1ConnectionState$2");
|
||||
input = PregReplace(input, NOT_VAR_WITH_DOT + "Network.peerType" + NOT_VAR_WITH_DOT, "$1PhotonNetwork.connectionState$2");
|
||||
input = PregReplace(input, NOT_VAR_WITH_DOT + "ConnectionState.Server" + NOT_VAR_WITH_DOT, "$1PhotonNetwork.isMasterClient$2");
|
||||
input = PregReplace(input, NOT_VAR_WITH_DOT + "ConnectionState.Client" + NOT_VAR_WITH_DOT, "$1PhotonNetwork.isNonMasterClientInRoom$2");
|
||||
input = PregReplace(input, NOT_VAR_WITH_DOT + "PhotonNetwork.playerList.Length" + NOT_VAR_WITH_DOT, "$1PhotonNetwork.playerList.Count$2");
|
||||
|
||||
/*DROPPED:
|
||||
minimumAllocatableViewIDs
|
||||
natFacilitatorIP is dropped
|
||||
natFacilitatorPort is dropped
|
||||
connectionTesterIP
|
||||
connectionTesterPort
|
||||
proxyIP
|
||||
proxyPort
|
||||
useProxy
|
||||
proxyPassword
|
||||
*/
|
||||
}
|
||||
|
||||
//Methods
|
||||
{
|
||||
input = PregReplace(input, NOT_VAR_WITH_DOT + "Network.InitializeServer" + NOT_VAR_WITH_DOT, "$1PhotonNetwork.JoinRoom$2");//Either Join or Create room
|
||||
input = PregReplace(input, NOT_VAR_WITH_DOT + "Network.Connect" + NOT_VAR_WITH_DOT, "$1PhotonNetwork.JoinRoom$2");
|
||||
input = PregReplace(input, NOT_VAR_WITH_DOT + "Network.GetAveragePing" + NOT_VAR_WITH_DOT, "$1PhotonNetwork.GetPing$2");
|
||||
input = PregReplace(input, NOT_VAR_WITH_DOT + "Network.GetLastPing" + NOT_VAR_WITH_DOT, "$1PhotonNetwork.GetPing$2");
|
||||
/*DROPPED:
|
||||
TestConnection
|
||||
TestConnectionNAT
|
||||
HavePublicAddress
|
||||
*/
|
||||
}
|
||||
|
||||
//Overall
|
||||
input = PregReplace(input, NOT_VAR_WITH_DOT + "Network" + NOT_VAR_WITH_DOT, "$1PhotonNetwork$2");
|
||||
}
|
||||
|
||||
//General
|
||||
{
|
||||
if (input.Contains("Photon")) //Only use the PhotonMonoBehaviour if we use photonView and friends.
|
||||
{
|
||||
if (isJS)//JS
|
||||
{
|
||||
if (input.Contains("extends MonoBehaviour"))
|
||||
input = PregReplace(input, "extends MonoBehaviour", "extends Photon.MonoBehaviour");
|
||||
else
|
||||
input = "class " + className + " extends Photon.MonoBehaviour {\n" + input + "\n}";
|
||||
}
|
||||
else //C#
|
||||
input = PregReplace(input, ": MonoBehaviour", ": Photon.MonoBehaviour");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return input;
|
||||
}
|
||||
|
||||
static string PregReplace(string input, string[] pattern, string[] replacements)
|
||||
{
|
||||
if (replacements.Length != pattern.Length)
|
||||
Debug.LogError("Replacement and Pattern Arrays must be balanced");
|
||||
|
||||
for (var i = 0; i < pattern.Length; i++)
|
||||
{
|
||||
input = Regex.Replace(input, pattern[i], replacements[i]);
|
||||
}
|
||||
|
||||
return input;
|
||||
}
|
||||
static string PregReplace(string input, string pattern, string replacement)
|
||||
{
|
||||
return Regex.Replace(input, pattern, replacement);
|
||||
|
||||
}
|
||||
|
||||
static void EnsureFolder(string path)
|
||||
{
|
||||
if (!Directory.Exists(path))
|
||||
{
|
||||
Directory.CreateDirectory(path);
|
||||
AssetDatabase.ImportAsset(path, ImportAssetOptions.ForceUpdate);
|
||||
AssetDatabase.Refresh();
|
||||
}
|
||||
}
|
||||
|
||||
static int ConvertNetworkView(NetworkView[] netViews, bool isScene)
|
||||
{
|
||||
for (int i = netViews.Length - 1; i >= 0; i--)
|
||||
{
|
||||
NetworkView netView = netViews[i];
|
||||
PhotonView view = netView.gameObject.AddComponent<PhotonView>();
|
||||
if (isScene)
|
||||
{
|
||||
//Get scene ID
|
||||
string str = netView.viewID.ToString().Replace("SceneID: ", "");
|
||||
int firstSpace = str.IndexOf(" ");
|
||||
str = str.Substring(0, firstSpace);
|
||||
int oldViewID = int.Parse(str);
|
||||
|
||||
view.viewID = new PhotonViewID(oldViewID, null);
|
||||
view.SetSceneID(oldViewID);
|
||||
EditorUtility.SetDirty(view);
|
||||
EditorUtility.SetDirty(view.gameObject);
|
||||
}
|
||||
view.observed = netView.observed;
|
||||
if (netView.stateSynchronization == NetworkStateSynchronization.Unreliable)
|
||||
{
|
||||
view.synchronization = ViewSynchronization.Unreliable;
|
||||
}
|
||||
else if (netView.stateSynchronization == NetworkStateSynchronization.ReliableDeltaCompressed)
|
||||
{
|
||||
view.synchronization = ViewSynchronization.ReliableDeltaCompressed;
|
||||
}
|
||||
else
|
||||
{
|
||||
view.synchronization = ViewSynchronization.Off;
|
||||
}
|
||||
DestroyImmediate(netView, true);
|
||||
}
|
||||
AssetDatabase.Refresh();
|
||||
AssetDatabase.SaveAssets();
|
||||
|
||||
return netViews.Length;
|
||||
}
|
||||
|
||||
|
||||
static void Output(string str)
|
||||
{
|
||||
Debug.Log(((int)EditorApplication.timeSinceStartup) + " " + str);
|
||||
}
|
||||
static void ConversionError(string file, string str)
|
||||
{
|
||||
Debug.LogError("Scrip conversion[" + file + "]: " + str);
|
||||
}
|
||||
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 15757b26cd9b53247be86da9e8da19dd
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
+629
@@ -0,0 +1,629 @@
|
||||
// ----------------------------------------------------------------------------
|
||||
// <copyright file="PhotonEditor.cs" company="Exit Games GmbH">
|
||||
// PhotonNetwork Framework for Unity - Copyright (C) 2011 Exit Games GmbH
|
||||
// </copyright>
|
||||
// <summary>
|
||||
// MenuItems and in-Editor scripts for PhotonNetwork.
|
||||
// </summary>
|
||||
// <author>developer@exitgames.com</author>
|
||||
// ----------------------------------------------------------------------------
|
||||
using System;
|
||||
using System.IO;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
[InitializeOnLoad]
|
||||
public class PhotonEditor : EditorWindow
|
||||
{
|
||||
protected static AccountService.Origin RegisterOrigin = AccountService.Origin.Pun;
|
||||
|
||||
protected Vector2 scrollPos = Vector2.zero;
|
||||
|
||||
protected static string DocumentationLocation = "Assets/Photon Unity Networking/PhotonNetwork-Documentation.pdf";
|
||||
|
||||
protected static string UrlFreeLicense = "http://www.exitgames.com/Download/Photon";
|
||||
|
||||
protected static string UrlDevNet = "http://doc.exitgames.com/photon-cloud";
|
||||
|
||||
protected static string UrlForum = "http://forum.exitgames.com";
|
||||
|
||||
protected static string UrlCompare = "http://doc.exitgames.com/photon-cloud";
|
||||
|
||||
protected static string UrlHowToSetup = "http://doc.exitgames.com/photon-server/PhotonIn5Min/#cat-First%20Steps";
|
||||
|
||||
protected static string UrlAppIDExplained = "http://doc.exitgames.com/photon-cloud/PhotonDashboard/#cat-getting_started";
|
||||
|
||||
protected static string UrlAccountPage = "https://www.exitgames.com/Account/SignIn?email="; // opened in browser
|
||||
|
||||
|
||||
private enum GUIState
|
||||
{
|
||||
Uninitialized,
|
||||
|
||||
Main,
|
||||
|
||||
Setup
|
||||
}
|
||||
|
||||
private enum PhotonSetupStates
|
||||
{
|
||||
RegisterForPhotonCloud,
|
||||
|
||||
EmailAlreadyRegistered,
|
||||
|
||||
SetupPhotonCloud,
|
||||
|
||||
SetupSelfHosted
|
||||
}
|
||||
|
||||
private GUIState guiState = GUIState.Uninitialized;
|
||||
|
||||
private bool isSetupWizard = false;
|
||||
|
||||
private PhotonSetupStates photonSetupState = PhotonSetupStates.RegisterForPhotonCloud;
|
||||
|
||||
private static double lastWarning = 0;
|
||||
|
||||
private string photonAddress = "127.0.0.1";
|
||||
|
||||
private int photonPort = ServerSettings.DefaultMasterPort;
|
||||
|
||||
private string emailAddress = string.Empty;
|
||||
|
||||
private string cloudAppId = string.Empty;
|
||||
|
||||
private static int lastPhotonViewListLength = -1;
|
||||
|
||||
private static UnityEngine.Object lastFirstElement;
|
||||
|
||||
private static string lastScene = string.Empty;
|
||||
|
||||
private static bool dontCheckPunSetupField;
|
||||
|
||||
/// <summary>
|
||||
/// Can be used to (temporarily) disable the checks for PUN Setup and scene PhotonViews.
|
||||
/// This will prevent scene PhotonViews from being updated, so be careful.
|
||||
/// When you re-set this value, checks are used again and scene PhotonViews get IDs as needed.
|
||||
/// </summary>
|
||||
protected static bool dontCheckPunSetup
|
||||
{
|
||||
get
|
||||
{
|
||||
return dontCheckPunSetupField;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (dontCheckPunSetupField != value)
|
||||
{
|
||||
lastPhotonViewListLength = 0;
|
||||
dontCheckPunSetupField = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected static Type WindowType = typeof(PhotonEditor);
|
||||
|
||||
protected static string WindowTitle = "PUN Setup Wizard";
|
||||
|
||||
[MenuItem("Window/Photon Unity Networking")]
|
||||
protected static void Init()
|
||||
{
|
||||
PhotonEditor.ReLoadCurrentSeetings();
|
||||
|
||||
PhotonEditor win = GetWindow(WindowType, false, WindowTitle) as PhotonEditor;
|
||||
win.ReApplySettingsToWindow();
|
||||
}
|
||||
|
||||
static PhotonEditor()
|
||||
{
|
||||
EditorApplication.projectWindowChanged += EditorUpdate;
|
||||
EditorApplication.hierarchyWindowChanged += EditorUpdate;
|
||||
EditorApplication.playmodeStateChanged += PlaymodeStateChanged;
|
||||
}
|
||||
|
||||
// called in editor, opens wizard for initial setup, keeps scene PhotonViews up to date and closes connections when compiling (to avoid issues)
|
||||
private static void EditorUpdate()
|
||||
{
|
||||
if (dontCheckPunSetup)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// serverSetting is null when the file gets deleted. otherwise, the wizard should only run once and only if hosting option is not (yet) set
|
||||
if (!PhotonEditor.Current.DisableAutoOpenWizard && PhotonEditor.Current.HostType == ServerSettings.HostingOption.NotSet)
|
||||
{
|
||||
ShowRegistrationWizard();
|
||||
}
|
||||
|
||||
// Workaround for TCP crash. Plus this surpresses any other recompile errors.
|
||||
if (EditorApplication.isCompiling)
|
||||
{
|
||||
if (PhotonNetwork.connected)
|
||||
{
|
||||
if (lastWarning > EditorApplication.timeSinceStartup - 3)
|
||||
{
|
||||
// Prevent error spam
|
||||
Debug.LogWarning("Unity recompile forced a Photon Disconnect");
|
||||
lastWarning = EditorApplication.timeSinceStartup;
|
||||
}
|
||||
|
||||
PhotonNetwork.Disconnect();
|
||||
}
|
||||
}
|
||||
else if (!EditorApplication.isPlaying)
|
||||
{
|
||||
// The following code could be optimized if Unity provides the right callbacks.
|
||||
// The current performance is 'OK' as we do check if the list changes (add/remove/duplicate should always change the length)
|
||||
|
||||
// We are currently checking all selected PhotonViews on hierarchy- and on project-change
|
||||
// Instead, we only want to check this when an NEW asset is placed in a scene (at editor time)
|
||||
// We need some sort of "OnCreated" call for scene objects.
|
||||
UnityEngine.Object[] objs = Selection.GetFiltered(typeof(PhotonView), SelectionMode.ExcludePrefab | SelectionMode.Editable | SelectionMode.Deep);
|
||||
if (objs.Length > 0 && (objs.Length != lastPhotonViewListLength || (lastFirstElement != objs[0])))
|
||||
{
|
||||
bool changed = false;
|
||||
foreach (UnityEngine.Object obj in objs)
|
||||
{
|
||||
PhotonView view = obj as PhotonView;
|
||||
if (!PhotonViewInspector.VerifySceneView(view))
|
||||
{
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (changed)
|
||||
{
|
||||
Debug.Log("PUN: Corrected one or more scene-PhotonViews.");
|
||||
AssetDatabase.SaveAssets();
|
||||
AssetDatabase.Refresh();
|
||||
}
|
||||
|
||||
lastPhotonViewListLength = objs.Length;
|
||||
lastFirstElement = objs[0];
|
||||
}
|
||||
|
||||
// Check the newly opened scene for wrong PhotonViews
|
||||
// This can happen when changing a prefab while viewing scene A. Instances in scene B will not be corrected.
|
||||
if (lastScene != EditorApplication.currentScene && EditorApplication.currentScene != string.Empty)
|
||||
{
|
||||
lastScene = EditorApplication.currentScene;
|
||||
PhotonViewInspector.VerifyAllSceneViews();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// called in editor on change of play-mode (used to show a message popup that connection settings are incomplete)
|
||||
private static void PlaymodeStateChanged()
|
||||
{
|
||||
if (dontCheckPunSetup || EditorApplication.isPlaying || !EditorApplication.isPlayingOrWillChangePlaymode)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (PhotonEditor.Current.HostType == ServerSettings.HostingOption.NotSet)
|
||||
{
|
||||
EditorUtility.DisplayDialog("Warning", "You have not yet run the Photon setup wizard! Your game won't be able to connect. See Windows -> Photon Unity Networking.", "Ok");
|
||||
}
|
||||
}
|
||||
|
||||
private void SwitchMenuState(GUIState newState)
|
||||
{
|
||||
this.guiState = newState;
|
||||
if (this.isSetupWizard && newState != GUIState.Setup)
|
||||
{
|
||||
this.Close();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Creates an Editor window, showing the cloud-registration wizard for Photon (entry point to setup PUN).</summary>
|
||||
protected static void ShowRegistrationWizard()
|
||||
{
|
||||
PhotonEditor.Current.DisableAutoOpenWizard = true;
|
||||
PhotonEditor.Save();
|
||||
|
||||
PhotonEditor window = (PhotonEditor)GetWindow(WindowType, false, WindowTitle, true);
|
||||
window.isSetupWizard = true;
|
||||
window.InitPhotonSetupWindow();
|
||||
}
|
||||
|
||||
/// <summary>Re-initializes the Photon Setup window and shows one of three states: register cloud, setup cloud, setup self-hosted.</summary>
|
||||
protected void InitPhotonSetupWindow()
|
||||
{
|
||||
this.SwitchMenuState(GUIState.Setup);
|
||||
|
||||
this.ReApplySettingsToWindow();
|
||||
|
||||
switch (PhotonEditor.Current.HostType)
|
||||
{
|
||||
case ServerSettings.HostingOption.PhotonCloud:
|
||||
this.photonSetupState = PhotonSetupStates.SetupPhotonCloud;
|
||||
break;
|
||||
case ServerSettings.HostingOption.SelfHosted:
|
||||
this.photonSetupState = PhotonSetupStates.SetupSelfHosted;
|
||||
break;
|
||||
case ServerSettings.HostingOption.NotSet:
|
||||
default:
|
||||
this.photonSetupState = PhotonSetupStates.RegisterForPhotonCloud;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void OnGUI()
|
||||
{
|
||||
this.scrollPos = GUILayout.BeginScrollView(this.scrollPos);
|
||||
|
||||
if (this.guiState == GUIState.Uninitialized)
|
||||
{
|
||||
this.ReApplySettingsToWindow();
|
||||
this.guiState = (PhotonEditor.Current.HostType == ServerSettings.HostingOption.NotSet) ? GUIState.Setup : GUIState.Main;
|
||||
}
|
||||
|
||||
if (this.guiState == GUIState.Main)
|
||||
{
|
||||
this.OnGuiMainWizard();
|
||||
}
|
||||
else
|
||||
{
|
||||
this.OnGuiRegisterCloudApp();
|
||||
}
|
||||
|
||||
GUILayout.EndScrollView();
|
||||
}
|
||||
|
||||
protected virtual void OnGuiRegisterCloudApp()
|
||||
{
|
||||
GUI.skin.label.wordWrap = true;
|
||||
if (!this.isSetupWizard)
|
||||
{
|
||||
GUILayout.BeginHorizontal();
|
||||
GUILayout.FlexibleSpace();
|
||||
if (GUILayout.Button("Close setup", GUILayout.ExpandWidth(false)))
|
||||
{
|
||||
this.SwitchMenuState(GUIState.Main);
|
||||
}
|
||||
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
GUILayout.Space(15);
|
||||
}
|
||||
|
||||
if (this.photonSetupState == PhotonSetupStates.RegisterForPhotonCloud)
|
||||
{
|
||||
GUI.skin.label.fontStyle = FontStyle.Bold;
|
||||
GUILayout.Label("Connect to Photon Cloud");
|
||||
GUI.skin.label.fontStyle = FontStyle.Normal;
|
||||
|
||||
GUILayout.Label("Your e-mail address is required to access your own free app.");
|
||||
this.emailAddress = EditorGUILayout.TextField("Email:", this.emailAddress);
|
||||
|
||||
if (GUILayout.Button("Send"))
|
||||
{
|
||||
GUIUtility.keyboardControl = 0;
|
||||
this.RegisterWithEmail(this.emailAddress);
|
||||
}
|
||||
|
||||
EditorGUILayout.Separator();
|
||||
|
||||
GUILayout.Label("I am already signed up. Let me enter my AppId.");
|
||||
if (GUILayout.Button("Setup"))
|
||||
{
|
||||
this.photonSetupState = PhotonSetupStates.SetupPhotonCloud;
|
||||
}
|
||||
|
||||
GUILayout.Label("I want to register by a website.");
|
||||
if (GUILayout.Button("Open account website"))
|
||||
{
|
||||
EditorUtility.OpenWithDefaultApp(UrlAccountPage + Uri.EscapeUriString(this.emailAddress));
|
||||
}
|
||||
|
||||
EditorGUILayout.Separator();
|
||||
}
|
||||
else if (this.photonSetupState == PhotonSetupStates.EmailAlreadyRegistered)
|
||||
{
|
||||
GUI.skin.label.fontStyle = FontStyle.Bold;
|
||||
GUILayout.Label("Oops!");
|
||||
GUI.skin.label.fontStyle = FontStyle.Normal;
|
||||
|
||||
GUILayout.Label("The provided e-mail-address has already been registered.");
|
||||
|
||||
if (GUILayout.Button("Mh, see my account page"))
|
||||
{
|
||||
EditorUtility.OpenWithDefaultApp(UrlAccountPage + Uri.EscapeUriString(this.emailAddress));
|
||||
}
|
||||
|
||||
EditorGUILayout.Separator();
|
||||
|
||||
GUILayout.Label("Ah, I know my Application ID. Get me to setup.");
|
||||
GUILayout.BeginHorizontal();
|
||||
if (GUILayout.Button("Cancel"))
|
||||
{
|
||||
this.photonSetupState = PhotonSetupStates.RegisterForPhotonCloud;
|
||||
}
|
||||
|
||||
if (GUILayout.Button("Setup"))
|
||||
{
|
||||
this.photonSetupState = PhotonSetupStates.SetupPhotonCloud;
|
||||
}
|
||||
|
||||
GUILayout.EndHorizontal();
|
||||
}
|
||||
else if (this.photonSetupState == PhotonSetupStates.SetupPhotonCloud)
|
||||
{
|
||||
// cloud setup
|
||||
GUI.skin.label.fontStyle = FontStyle.Bold;
|
||||
GUILayout.Label("Connect to Photon Cloud");
|
||||
GUI.skin.label.fontStyle = FontStyle.Normal;
|
||||
|
||||
EditorGUILayout.Separator();
|
||||
this.OnGuiSetupCloudAppId();
|
||||
this.OnGuiCompareAndHelpOptions();
|
||||
}
|
||||
else if (this.photonSetupState == PhotonSetupStates.SetupSelfHosted)
|
||||
{
|
||||
// self-hosting setup
|
||||
GUI.skin.label.fontStyle = FontStyle.Bold;
|
||||
GUILayout.Label("Setup own Photon Host");
|
||||
GUI.skin.label.fontStyle = FontStyle.Normal;
|
||||
|
||||
EditorGUILayout.Separator();
|
||||
|
||||
this.OnGuiSetupSelfhosting();
|
||||
this.OnGuiCompareAndHelpOptions();
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void OnGuiMainWizard()
|
||||
{
|
||||
// settings button
|
||||
GUILayout.BeginHorizontal();
|
||||
GUILayout.Label("Settings", EditorStyles.boldLabel, GUILayout.Width(100));
|
||||
if (GUILayout.Button(new GUIContent("Setup", "Setup wizard for setting up your own server or the cloud.")))
|
||||
{
|
||||
this.InitPhotonSetupWindow();
|
||||
}
|
||||
|
||||
GUILayout.EndHorizontal();
|
||||
GUILayout.Space(12);
|
||||
|
||||
// converter
|
||||
GUILayout.BeginHorizontal();
|
||||
GUILayout.Label("Converter", EditorStyles.boldLabel, GUILayout.Width(100));
|
||||
if (GUILayout.Button(new GUIContent("Start", "Converts pure Unity Networking to Photon Unity Networking.")))
|
||||
{
|
||||
PhotonConverter.RunConversion();
|
||||
}
|
||||
|
||||
GUILayout.EndHorizontal();
|
||||
GUILayout.Space(12);
|
||||
|
||||
// add PhotonView
|
||||
GUILayout.BeginHorizontal();
|
||||
GUILayout.Label("Component", EditorStyles.boldLabel, GUILayout.Width(100));
|
||||
if (GUILayout.Button(new GUIContent("Add PhotonView", "Also in menu: Component, Miscellaneous")))
|
||||
{
|
||||
if (Selection.activeGameObject != null)
|
||||
{
|
||||
Selection.activeGameObject.AddComponent<PhotonView>();
|
||||
}
|
||||
}
|
||||
|
||||
GUILayout.EndHorizontal();
|
||||
GUILayout.Space(22);
|
||||
|
||||
// license
|
||||
GUILayout.BeginHorizontal();
|
||||
GUILayout.Label("Licenses", EditorStyles.boldLabel, GUILayout.Width(100));
|
||||
|
||||
if (GUILayout.Button(new GUIContent("Download Free", "Get your free license for up to 100 concurrent players.")))
|
||||
{
|
||||
EditorUtility.OpenWithDefaultApp(UrlFreeLicense);
|
||||
}
|
||||
|
||||
GUILayout.EndHorizontal();
|
||||
GUILayout.Space(12);
|
||||
|
||||
// documentation
|
||||
GUILayout.BeginHorizontal();
|
||||
GUILayout.Label("Documentation", EditorStyles.boldLabel, GUILayout.Width(100));
|
||||
GUILayout.BeginVertical();
|
||||
if (GUILayout.Button(new GUIContent("Open PDF", "Opens the local documentation pdf.")))
|
||||
{
|
||||
EditorUtility.OpenWithDefaultApp(DocumentationLocation);
|
||||
}
|
||||
|
||||
if (GUILayout.Button(new GUIContent("Open DevNet", "Online documentation for Photon.")))
|
||||
{
|
||||
EditorUtility.OpenWithDefaultApp(UrlDevNet);
|
||||
}
|
||||
|
||||
if (GUILayout.Button(new GUIContent("Open Cloud Dashboard", "Review Cloud App information and statistics.")))
|
||||
{
|
||||
EditorUtility.OpenWithDefaultApp(UrlAccountPage + Uri.EscapeUriString(this.emailAddress));
|
||||
}
|
||||
|
||||
if (GUILayout.Button(new GUIContent("Open Forum", "Online support for Photon.")))
|
||||
{
|
||||
EditorUtility.OpenWithDefaultApp(UrlForum);
|
||||
}
|
||||
|
||||
GUILayout.EndVertical();
|
||||
GUILayout.EndHorizontal();
|
||||
}
|
||||
|
||||
protected virtual void OnGuiCompareAndHelpOptions()
|
||||
{
|
||||
EditorGUILayout.Separator();
|
||||
GUILayout.Label("I am not quite sure how 'my own host' compares to 'cloud'.");
|
||||
if (GUILayout.Button("See comparison page"))
|
||||
{
|
||||
Application.OpenURL(UrlCompare);
|
||||
}
|
||||
|
||||
EditorGUILayout.Separator();
|
||||
|
||||
GUILayout.Label("Questions? Need help or want to give us feedback? You are most welcome!");
|
||||
if (GUILayout.Button("See the Photon Forum"))
|
||||
{
|
||||
Application.OpenURL(UrlForum);
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void OnGuiSetupCloudAppId()
|
||||
{
|
||||
GUILayout.Label("Your APP ID:");
|
||||
|
||||
this.cloudAppId = EditorGUILayout.TextField(this.cloudAppId);
|
||||
|
||||
GUILayout.BeginHorizontal();
|
||||
if (GUILayout.Button("Cancel"))
|
||||
{
|
||||
GUIUtility.keyboardControl = 0;
|
||||
this.ReApplySettingsToWindow();
|
||||
}
|
||||
|
||||
if (GUILayout.Button("Save"))
|
||||
{
|
||||
GUIUtility.keyboardControl = 0;
|
||||
|
||||
PhotonEditor.Current.UseCloud(this.cloudAppId);
|
||||
PhotonEditor.Save();
|
||||
|
||||
EditorUtility.DisplayDialog("Success", "Saved your settings.", "ok");
|
||||
}
|
||||
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
EditorGUILayout.Separator();
|
||||
|
||||
GUILayout.Label("Running my app in the cloud was fun but...\nLet me setup my own Photon server.");
|
||||
|
||||
if (GUILayout.Button("Switch to own host"))
|
||||
{
|
||||
this.photonAddress = ServerSettings.DefaultServerAddress;
|
||||
this.photonPort = ServerSettings.DefaultMasterPort;
|
||||
this.photonSetupState = PhotonSetupStates.SetupSelfHosted;
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void OnGuiSetupSelfhosting()
|
||||
{
|
||||
GUILayout.Label("Your Photon Host");
|
||||
|
||||
this.photonAddress = EditorGUILayout.TextField("IP:", this.photonAddress);
|
||||
this.photonPort = EditorGUILayout.IntField("Port:", this.photonPort);
|
||||
|
||||
// photonProtocol = (ExitGames.Client.Photon.ConnectionProtocol)EditorGUILayout.EnumPopup("Protocol:", photonProtocol);
|
||||
GUILayout.BeginHorizontal();
|
||||
if (GUILayout.Button("Cancel"))
|
||||
{
|
||||
GUIUtility.keyboardControl = 0;
|
||||
this.ReApplySettingsToWindow();
|
||||
}
|
||||
|
||||
if (GUILayout.Button("Save"))
|
||||
{
|
||||
GUIUtility.keyboardControl = 0;
|
||||
|
||||
PhotonEditor.Current.UseMyServer(this.photonAddress, this.photonPort, null);
|
||||
PhotonEditor.Save();
|
||||
|
||||
EditorUtility.DisplayDialog("Success", "Saved your settings.", "ok");
|
||||
}
|
||||
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
EditorGUILayout.Separator();
|
||||
|
||||
GUILayout.Label("Running my own server is too much hassle..\nI want to give Photon's free app a try.");
|
||||
|
||||
if (GUILayout.Button("Get the free cloud app"))
|
||||
{
|
||||
this.cloudAppId = string.Empty;
|
||||
this.photonSetupState = PhotonSetupStates.RegisterForPhotonCloud;
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void RegisterWithEmail(string email)
|
||||
{
|
||||
EditorUtility.DisplayProgressBar("Connecting", "Connecting to the account service..", 0.5f);
|
||||
var client = new AccountService();
|
||||
client.RegisterByEmail(email, RegisterOrigin); // this is the synchronous variant using the static RegisterOrigin. "result" is in the client
|
||||
|
||||
EditorUtility.ClearProgressBar();
|
||||
if (client.ReturnCode == 0)
|
||||
{
|
||||
PhotonEditor.Current.UseCloud(client.AppId);
|
||||
PhotonEditor.Save();
|
||||
this.ReApplySettingsToWindow();
|
||||
this.photonSetupState = PhotonSetupStates.SetupPhotonCloud;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (client.Message.Contains("Email already registered"))
|
||||
{
|
||||
this.photonSetupState = PhotonSetupStates.EmailAlreadyRegistered;
|
||||
}
|
||||
else
|
||||
{
|
||||
EditorUtility.DisplayDialog("Error", client.Message, "OK");
|
||||
// Debug.Log(client.Exception);
|
||||
this.photonSetupState = PhotonSetupStates.RegisterForPhotonCloud;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#region SettingsFileHandling
|
||||
|
||||
private static ServerSettings currentSettings;
|
||||
|
||||
public static ServerSettings Current
|
||||
{
|
||||
get
|
||||
{
|
||||
if (currentSettings == null)
|
||||
{
|
||||
ReLoadCurrentSeetings();
|
||||
|
||||
// if still not loaded, create one
|
||||
if (currentSettings == null)
|
||||
{
|
||||
currentSettings = (ServerSettings)ScriptableObject.CreateInstance(typeof(ServerSettings));
|
||||
string settingsPath = Path.GetDirectoryName(PhotonNetwork.serverSettingsAssetPath);
|
||||
if (!Directory.Exists(settingsPath))
|
||||
{
|
||||
Directory.CreateDirectory(settingsPath);
|
||||
AssetDatabase.ImportAsset(settingsPath);
|
||||
}
|
||||
|
||||
AssetDatabase.CreateAsset(currentSettings, PhotonNetwork.serverSettingsAssetPath);
|
||||
}
|
||||
}
|
||||
|
||||
return currentSettings;
|
||||
}
|
||||
|
||||
protected set
|
||||
{
|
||||
currentSettings = value;
|
||||
}
|
||||
}
|
||||
|
||||
public static void Save()
|
||||
{
|
||||
EditorUtility.SetDirty(PhotonEditor.Current);
|
||||
}
|
||||
|
||||
public static void ReLoadCurrentSeetings()
|
||||
{
|
||||
PhotonEditor.Current = (ServerSettings)AssetDatabase.LoadAssetAtPath(PhotonNetwork.serverSettingsAssetPath, typeof(ServerSettings));
|
||||
}
|
||||
|
||||
protected void ReApplySettingsToWindow()
|
||||
{
|
||||
this.cloudAppId = string.IsNullOrEmpty(PhotonEditor.Current.AppID) ? string.Empty : PhotonEditor.Current.AppID;
|
||||
this.photonAddress = string.IsNullOrEmpty(PhotonEditor.Current.ServerAddress) ? string.Empty : PhotonEditor.Current.ServerAddress;
|
||||
this.photonPort = PhotonEditor.Current.ServerPort;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: dabbbed2a74eac44dac281f20d706ba8
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
+380
@@ -0,0 +1,380 @@
|
||||
// ----------------------------------------------------------------------------
|
||||
// <copyright file="PhotonViewInspector.cs" company="Exit Games GmbH">
|
||||
// PhotonNetwork Framework for Unity - Copyright (C) 2011 Exit Games GmbH
|
||||
// </copyright>
|
||||
// <summary>
|
||||
// Custom inspector for the PhotonView component.
|
||||
// </summary>
|
||||
// <author>developer@exitgames.com</author>
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
using System;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
[CustomEditor(typeof(PhotonView))]
|
||||
public class PhotonViewInspector : Editor
|
||||
{
|
||||
private bool doubleView = false;
|
||||
|
||||
private static PhotonView lastView;
|
||||
|
||||
private static GameObject GetPrefabParent(GameObject mp)
|
||||
{
|
||||
#if UNITY_2_6_1 || UNITY_2_6 || UNITY_3_0 || UNITY_3_0_0 || UNITY_3_1 || UNITY_3_2 || UNITY_3_3 || UNITY_3_4
|
||||
// Unity 3.4 and older use EditorUtility
|
||||
return (EditorUtility.GetPrefabParent(mp) as GameObject);
|
||||
#else
|
||||
// Unity 3.5 uses PrefabUtility
|
||||
return PrefabUtility.GetPrefabParent(mp) as GameObject;
|
||||
#endif
|
||||
}
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
EditorGUIUtility.LookLikeInspector();
|
||||
EditorGUI.indentLevel = 1;
|
||||
|
||||
PhotonView mp = (PhotonView)this.target;
|
||||
bool isProjectPrefab = EditorUtility.IsPersistent(mp.gameObject);
|
||||
|
||||
if (!EditorApplication.isPlaying)
|
||||
{
|
||||
if (mp != lastView)
|
||||
{
|
||||
// First opening of this viewID
|
||||
if (!isProjectPrefab)
|
||||
{
|
||||
if (!IsSceneViewIDFree(mp.viewID.ID, mp))
|
||||
{
|
||||
Debug.LogWarning("PhotonView: Wrong view ID(" + mp.viewID.ID + ") on " + mp.name + ", checking entire scene for fixes...");
|
||||
VerifyAllSceneViews();
|
||||
}
|
||||
}
|
||||
|
||||
lastView = mp;
|
||||
}
|
||||
}
|
||||
|
||||
SerializedObject sObj = new SerializedObject(mp);
|
||||
SerializedProperty sceneProp = sObj.FindProperty("sceneViewID");
|
||||
|
||||
// SerializedProperty sceneProp2 = sObj.FindProperty("isSceneView");
|
||||
|
||||
// FIX for an issue where a prefab(with photon view) is dragged to the scene and its changes APPLIED
|
||||
// This means that the scene assigns a ID, but this ID may not be saved to the prefab.
|
||||
// Unity's prefab AssetImporter doesn't seem to work (3.4), hence this nasty workaround.
|
||||
// Desired values:
|
||||
// scene = true true proj = false false. Thus, error case=
|
||||
if (sceneProp.isInstantiatedPrefab && !sceneProp.prefabOverride)
|
||||
{
|
||||
// Fix the assignment
|
||||
// EDIT: THIS ISSUE HAS BEEN FIXED IN PHOTONVIEW.CS BY CHECKING FOR THE PhotonViewSetup_FindMatchingRoot in Setup();
|
||||
// #if !UNITY_3_5
|
||||
// sceneProp.prefabOverride = true;
|
||||
// #endif
|
||||
sObj.ApplyModifiedProperties();
|
||||
|
||||
// FIX THE EDITOR PREFAB: set it to 0
|
||||
GameObject prefabParent = GetPrefabParent(mp.gameObject);
|
||||
if (prefabParent != null)
|
||||
{
|
||||
// find all PhotonViews on prefab, including those on inactive components to assign a PhotonViewId
|
||||
PhotonView[] views = prefabParent.transform.root.GetComponentsInChildren<PhotonView>(true) as PhotonView[];
|
||||
foreach (PhotonView viewX in views)
|
||||
{
|
||||
MakeProjectView(viewX);
|
||||
}
|
||||
|
||||
// ForceUpdate re-import for the prefab
|
||||
ForceAssetUpdate(mp.gameObject);
|
||||
}
|
||||
|
||||
// Assign the desired scene IDs back (they were reset to 0 by applying)
|
||||
PhotonView[] views2 = mp.transform.root.GetComponentsInChildren<PhotonView>();
|
||||
foreach (PhotonView view in views2)
|
||||
{
|
||||
int wantedID = view.viewID.ID;
|
||||
view.SetSceneID(wantedID);
|
||||
EditorUtility.SetDirty(view);
|
||||
}
|
||||
}
|
||||
|
||||
// Setup
|
||||
if (!isProjectPrefab)
|
||||
{
|
||||
if (mp.viewID.ID == 0)
|
||||
{
|
||||
SetViewID(mp, GetFreeSceneID(mp));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (mp.viewID.ID != 0 || mp.isSceneView)
|
||||
{
|
||||
// Correct the settings
|
||||
Debug.LogWarning("Correcting view ID on project prefab (should be unassigned, but it was " + mp.viewID.ID + ")");
|
||||
MakeProjectView(mp);
|
||||
}
|
||||
}
|
||||
|
||||
// OWNER
|
||||
if (isProjectPrefab)
|
||||
{
|
||||
EditorGUILayout.LabelField("Owner:", "Set at runtime");
|
||||
}
|
||||
else if (mp.isSceneView)
|
||||
{
|
||||
EditorGUILayout.LabelField("Owner:", "Scene");
|
||||
}
|
||||
else if (mp.owner == null)
|
||||
{
|
||||
EditorGUILayout.LabelField("Owner:", "null, disconnected?");
|
||||
}
|
||||
else
|
||||
{
|
||||
EditorGUILayout.LabelField("Owner:", "[" + mp.owner.ID + "] " + mp.owner.name);
|
||||
}
|
||||
|
||||
// View ID
|
||||
if (isProjectPrefab)
|
||||
{
|
||||
EditorGUILayout.LabelField("View ID", "Set at runtime");
|
||||
}
|
||||
else if (EditorApplication.isPlaying)
|
||||
{
|
||||
if (mp.owner != null)
|
||||
{
|
||||
EditorGUILayout.LabelField("View ID", "[" + mp.owner.ID + "] " + mp.viewID);
|
||||
}
|
||||
else
|
||||
{
|
||||
EditorGUILayout.LabelField("View ID", mp.viewID + string.Empty);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int newID = EditorGUILayout.IntField("View ID", mp.viewID.ID);
|
||||
if (GUI.changed)
|
||||
{
|
||||
SetViewID(mp, newID);
|
||||
}
|
||||
|
||||
if (this.doubleView)
|
||||
{
|
||||
GUI.color = Color.red;
|
||||
EditorGUILayout.LabelField("ERROR:", "Invalid view ID");
|
||||
GUI.color = Color.white;
|
||||
}
|
||||
|
||||
if (GUI.changed)
|
||||
{
|
||||
this.ChangedSetting();
|
||||
this.doubleView = false;
|
||||
PhotonView[] photonViews = Resources.FindObjectsOfTypeAll(typeof(PhotonView)) as PhotonView[];
|
||||
foreach (PhotonView view in photonViews)
|
||||
{
|
||||
if (view.isSceneView && view.viewID == mp.viewID && view != mp)
|
||||
{
|
||||
this.doubleView = true;
|
||||
EditorUtility.DisplayDialog("Error", "There is already a viewID with ID=" + view.viewID, "OK");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// OBSERVING
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
|
||||
// Using a lower version then 3.4? Remove the TRUE in the next line to fix an compile error
|
||||
string title = string.Empty;
|
||||
int firstOpen = 0;
|
||||
if (mp.observed != null)
|
||||
{
|
||||
firstOpen = mp.observed.ToString().IndexOf('(');
|
||||
}
|
||||
|
||||
if (firstOpen > 0)
|
||||
{
|
||||
title = mp.observed.ToString().Substring(firstOpen - 1);
|
||||
}
|
||||
|
||||
mp.observed = (Component)EditorGUILayout.ObjectField("Observe: " + title, mp.observed, typeof(Component), true);
|
||||
if (GUI.changed)
|
||||
{
|
||||
this.ChangedSetting();
|
||||
if (mp.observed != null)
|
||||
{
|
||||
mp.synchronization = ViewSynchronization.ReliableDeltaCompressed;
|
||||
}
|
||||
else
|
||||
{
|
||||
mp.synchronization = ViewSynchronization.Off;
|
||||
}
|
||||
}
|
||||
|
||||
EditorGUILayout.EndHorizontal();
|
||||
|
||||
if (mp.synchronization == ViewSynchronization.Off)
|
||||
{
|
||||
GUI.color = Color.grey;
|
||||
}
|
||||
|
||||
mp.synchronization = (ViewSynchronization)EditorGUILayout.EnumPopup("Observe option:", mp.synchronization);
|
||||
if (GUI.changed)
|
||||
{
|
||||
this.ChangedSetting();
|
||||
if (mp.synchronization != ViewSynchronization.Off && mp.observed == null)
|
||||
{
|
||||
EditorUtility.DisplayDialog("Warning", "Setting the synchronization option only makes sense if you observe something.", "OK, I will fix it.");
|
||||
}
|
||||
}
|
||||
|
||||
if (mp.observed != null)
|
||||
{
|
||||
Type type = mp.observed.GetType();
|
||||
if (type == typeof(Transform))
|
||||
{
|
||||
mp.onSerializeTransformOption = (OnSerializeTransform)EditorGUILayout.EnumPopup("Serialization:", mp.onSerializeTransformOption);
|
||||
}
|
||||
else if (type == typeof(Rigidbody))
|
||||
{
|
||||
mp.onSerializeRigidBodyOption = (OnSerializeRigidBody)EditorGUILayout.EnumPopup("Serialization:", mp.onSerializeRigidBodyOption);
|
||||
}
|
||||
}
|
||||
|
||||
GUI.color = Color.white;
|
||||
EditorGUIUtility.LookLikeControls();
|
||||
}
|
||||
|
||||
private void ChangedSetting()
|
||||
{
|
||||
PhotonView mp = (PhotonView)this.target;
|
||||
if (!EditorApplication.isPlaying)
|
||||
{
|
||||
EditorUtility.SetDirty(mp);
|
||||
}
|
||||
}
|
||||
|
||||
public static void MakeProjectView(PhotonView view)
|
||||
{
|
||||
view.viewID = new PhotonViewID(0, null);
|
||||
view.SetSceneID(0);
|
||||
EditorUtility.SetDirty(view);
|
||||
}
|
||||
|
||||
private static void SetViewID(PhotonView mp, int ID)
|
||||
{
|
||||
ID = Mathf.Clamp(ID, 1, PhotonNetwork.MAX_VIEW_IDS - 1);
|
||||
|
||||
if (!IsSceneViewIDFree(ID, mp))
|
||||
{
|
||||
ID = GetFreeSceneID(mp);
|
||||
}
|
||||
|
||||
if (mp.viewID.ID != ID)
|
||||
{
|
||||
mp.viewID = new PhotonViewID(ID, null);
|
||||
}
|
||||
|
||||
if (!EditorApplication.isPlaying)
|
||||
{
|
||||
mp.SetSceneID(mp.viewID.ID);
|
||||
ForceAssetUpdate(mp.gameObject);
|
||||
}
|
||||
|
||||
EditorUtility.SetDirty(mp);
|
||||
}
|
||||
|
||||
public static void ForceAssetUpdate(GameObject mp)
|
||||
{
|
||||
GameObject pPrefab = GetPrefabParent(mp);
|
||||
if (pPrefab != null)
|
||||
{
|
||||
pPrefab = pPrefab.transform.root.gameObject;
|
||||
string assetPath = AssetDatabase.GetAssetPath(pPrefab);
|
||||
if (assetPath == string.Empty)
|
||||
{
|
||||
Debug.LogError("No assetpath for " + pPrefab);
|
||||
}
|
||||
|
||||
AssetDatabase.ImportAsset(assetPath, ImportAssetOptions.ForceUpdate);
|
||||
}
|
||||
}
|
||||
|
||||
private static int GetFreeSceneID(PhotonView targetView)
|
||||
{
|
||||
// No need for bit shifting as scene is "player 0".
|
||||
/* Hashtable takenIDs = new Hashtable();
|
||||
PhotonView[] views = (PhotonView[])GameObject.FindObjectsOfType(typeof(PhotonView));
|
||||
foreach (PhotonView view in views)
|
||||
{
|
||||
takenIDs[view.viewID] = view;
|
||||
}*/
|
||||
for (int i = 1; i < PhotonNetwork.MAX_VIEW_IDS; i++)
|
||||
{
|
||||
if (IsSceneViewIDFree(i, targetView))
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
EditorUtility.DisplayDialog("Error", "You ran out of view ID's (" + PhotonNetwork.MAX_VIEW_IDS + "). Something is seriously wrong!", "OK");
|
||||
return 1;
|
||||
}
|
||||
|
||||
private static bool IsSceneViewIDFree(int ID, PhotonView targetView)
|
||||
{
|
||||
if (ID <= 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
PhotonView[] photonViews = Resources.FindObjectsOfTypeAll(typeof(PhotonView)) as PhotonView[];
|
||||
foreach (PhotonView view in photonViews)
|
||||
{
|
||||
if (!view.isSceneView)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (view != targetView && view.viewID != null && view.viewID.ID == ID)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static int VerifyAllSceneViews()
|
||||
{
|
||||
int correctedViews = 0;
|
||||
PhotonView[] photonViews = Resources.FindObjectsOfTypeAll(typeof(PhotonView)) as PhotonView[];
|
||||
foreach (PhotonView view in photonViews)
|
||||
{
|
||||
if (!VerifySceneView(view))
|
||||
{
|
||||
correctedViews++;
|
||||
}
|
||||
}
|
||||
|
||||
if (correctedViews > 0)
|
||||
{
|
||||
AssetDatabase.SaveAssets();
|
||||
AssetDatabase.Refresh();
|
||||
}
|
||||
return correctedViews;
|
||||
}
|
||||
|
||||
public static bool VerifySceneView(PhotonView view)
|
||||
{
|
||||
if (!EditorUtility.IsPersistent(view.gameObject) && !IsSceneViewIDFree(view.viewID.ID, view))
|
||||
{
|
||||
SetViewID(view, GetFreeSceneID(view));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e73a30c46df19194f873ea7a9ce12753
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
+49
@@ -0,0 +1,49 @@
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
|
||||
using System.Collections;
|
||||
|
||||
public class PhotonViewPrefabApply : AssetPostprocessor
|
||||
{
|
||||
static void OnPostprocessAllAssets(
|
||||
string[] importedAssets,
|
||||
string[] deletedAssets,
|
||||
string[] movedAssets,
|
||||
string[] movedFromAssetPaths)
|
||||
{
|
||||
bool weChangedPhotonViews = false;
|
||||
|
||||
// Strips any scene settings from PhotonViews in prefabs.
|
||||
// (i.e.: assigned viewIDs are removed)
|
||||
foreach (string str in importedAssets)
|
||||
{
|
||||
if (str.EndsWith(".prefab"))
|
||||
{
|
||||
Object[] objs = (Object[])AssetDatabase.LoadAllAssetsAtPath(str);
|
||||
foreach (Object obj in objs)
|
||||
{
|
||||
if (obj != null && obj.GetType() == typeof(GameObject))
|
||||
{
|
||||
PhotonView[] views = ((GameObject)obj).GetComponents<PhotonView>();
|
||||
foreach (PhotonView view in views)
|
||||
PhotonViewInspector.MakeProjectView(view);
|
||||
|
||||
if (views.Length > 0)
|
||||
weChangedPhotonViews = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Problem here: VerifyAllSceneViews will only fix the prefabs instances in the current open scene, not for other scenes!
|
||||
// See PhotonEditor.EditorUpdate: Here we will check all newly opened scenes for this possible issue.
|
||||
// No known issues as of 5 March 2011 this seems to work fine with changing viewIDs on prefabs etc. (Even for scenes that are not open) - Mike/Leepo
|
||||
if (weChangedPhotonViews)
|
||||
{
|
||||
PhotonViewInspector.VerifyAllSceneViews();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8fc479a7e9762e6419b446c9fa57fcfb
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
@@ -0,0 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 76df7f01e71e35a4a8bb6e25a67483bf
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
userData:
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 17f781dfbe35aa24cadfd52f1eba2624
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
userData:
|
||||
+155
@@ -0,0 +1,155 @@
|
||||
// ----------------------------------------------------------------------------
|
||||
// <copyright file="CustomTypes.cs" company="Exit Games GmbH">
|
||||
// PhotonNetwork Framework for Unity - Copyright (C) 2011 Exit Games GmbH
|
||||
// </copyright>
|
||||
// <summary>
|
||||
//
|
||||
// </summary>
|
||||
// <author>developer@exitgames.com</author>
|
||||
// ----------------------------------------------------------------------------
|
||||
using System;
|
||||
using System.IO;
|
||||
using ExitGames.Client.Photon;
|
||||
using UnityEngine;
|
||||
|
||||
/// <summary>
|
||||
/// Internally used class, containing de/serialization methods for various Unity-specific classes.
|
||||
/// Adding those to the Photon serialization protocol allows you to send them in events, etc.
|
||||
/// </summary>
|
||||
internal static class CustomTypes
|
||||
{
|
||||
/// <summary>Register</summary>
|
||||
internal static void Register()
|
||||
{
|
||||
PhotonPeer.RegisterType(typeof(Vector2), (byte)'W', SerializeVector2, DeserializeVector2);
|
||||
PhotonPeer.RegisterType(typeof(Vector3), (byte)'V', SerializeVector3, DeserializeVector3);
|
||||
PhotonPeer.RegisterType(typeof(Transform), (byte)'T', SerializeTransform, DeserializeTransform);
|
||||
PhotonPeer.RegisterType(typeof(Quaternion), (byte)'Q', SerializeQuaternion, DeserializeQuaternion);
|
||||
PhotonPeer.RegisterType(typeof(PhotonPlayer), (byte)'P', SerializePhotonPlayer, DeserializePhotonPlayer);
|
||||
PhotonPeer.RegisterType(typeof(PhotonViewID), (byte)'I', SerializePhotonViewID, DeserializePhotonViewID);
|
||||
}
|
||||
|
||||
#region Custom De/Serializer Methods
|
||||
|
||||
private static byte[] SerializeTransform(object customobject)
|
||||
{
|
||||
Transform t = (Transform)customobject;
|
||||
|
||||
Vector3[] parts = new Vector3[2];
|
||||
parts[0] = t.position;
|
||||
parts[1] = t.eulerAngles;
|
||||
|
||||
return Protocol.Serialize(parts);
|
||||
}
|
||||
|
||||
private static object DeserializeTransform(byte[] serializedcustomobject)
|
||||
{
|
||||
object x = Protocol.Deserialize(serializedcustomobject);
|
||||
return x;
|
||||
}
|
||||
|
||||
private static byte[] SerializeVector3(object customobject)
|
||||
{
|
||||
Vector3 vo = (Vector3)customobject;
|
||||
int index = 0;
|
||||
|
||||
byte[] bytes = new byte[3 * 4];
|
||||
Protocol.Serialize(vo.x, bytes, ref index);
|
||||
Protocol.Serialize(vo.y, bytes, ref index);
|
||||
Protocol.Serialize(vo.z, bytes, ref index);
|
||||
return bytes;
|
||||
}
|
||||
|
||||
private static object DeserializeVector3(byte[] bytes)
|
||||
{
|
||||
Vector3 vo = new Vector3();
|
||||
int index = 0;
|
||||
Protocol.Deserialize(out vo.x, bytes, ref index);
|
||||
Protocol.Deserialize(out vo.y, bytes, ref index);
|
||||
Protocol.Deserialize(out vo.z, bytes, ref index);
|
||||
|
||||
return vo;
|
||||
}
|
||||
|
||||
private static byte[] SerializeVector2(object customobject)
|
||||
{
|
||||
Vector2 vo = (Vector2)customobject;
|
||||
MemoryStream ms = new MemoryStream(2 * 4);
|
||||
|
||||
ms.Write(BitConverter.GetBytes(vo.x), 0, 4);
|
||||
ms.Write(BitConverter.GetBytes(vo.y), 0, 4);
|
||||
return ms.ToArray();
|
||||
}
|
||||
|
||||
private static object DeserializeVector2(byte[] bytes)
|
||||
{
|
||||
Vector2 vo = new Vector2();
|
||||
vo.x = BitConverter.ToSingle(bytes, 0);
|
||||
vo.y = BitConverter.ToSingle(bytes, 4);
|
||||
return vo;
|
||||
}
|
||||
|
||||
private static byte[] SerializeQuaternion(object obj)
|
||||
{
|
||||
Quaternion o = (Quaternion)obj;
|
||||
MemoryStream ms = new MemoryStream(3 * 4);
|
||||
|
||||
ms.Write(BitConverter.GetBytes(o.w), 0, 4);
|
||||
ms.Write(BitConverter.GetBytes(o.x), 0, 4);
|
||||
ms.Write(BitConverter.GetBytes(o.y), 0, 4);
|
||||
ms.Write(BitConverter.GetBytes(o.z), 0, 4);
|
||||
return ms.ToArray();
|
||||
}
|
||||
|
||||
private static object DeserializeQuaternion(byte[] bytes)
|
||||
{
|
||||
Quaternion o = new Quaternion();
|
||||
o.w = BitConverter.ToSingle(bytes, 0);
|
||||
o.x = BitConverter.ToSingle(bytes, 4);
|
||||
o.y = BitConverter.ToSingle(bytes, 8);
|
||||
o.z = BitConverter.ToSingle(bytes, 12);
|
||||
|
||||
return o;
|
||||
}
|
||||
|
||||
private static byte[] SerializePhotonPlayer(object customobject)
|
||||
{
|
||||
int ID = ((PhotonPlayer)customobject).ID;
|
||||
return BitConverter.GetBytes(ID);
|
||||
}
|
||||
|
||||
private static object DeserializePhotonPlayer(byte[] bytes)
|
||||
{
|
||||
int ID = BitConverter.ToInt32(bytes, 0);
|
||||
if (PhotonNetwork.networkingPeer.mActors.ContainsKey(ID))
|
||||
{
|
||||
return PhotonNetwork.networkingPeer.mActors[ID];
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static byte[] SerializePhotonViewID(object customobject)
|
||||
{
|
||||
int ID = ((PhotonViewID)customobject).ID;
|
||||
return BitConverter.GetBytes(ID);
|
||||
}
|
||||
|
||||
private static object DeserializePhotonViewID(byte[] bytes)
|
||||
{
|
||||
int ID = BitConverter.ToInt32(bytes, 0);
|
||||
int internalID = ID % PhotonNetwork.MAX_VIEW_IDS;
|
||||
int actorID = ID / PhotonNetwork.MAX_VIEW_IDS;
|
||||
PhotonPlayer owner = null;
|
||||
if (actorID > 0)
|
||||
{
|
||||
owner = PhotonPlayer.Find(actorID);
|
||||
}
|
||||
|
||||
return new PhotonViewID(internalID, owner);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ab517bd36a2b2504b83979fcad45d4a2
|
||||
labels:
|
||||
- ExitGames
|
||||
- PUN
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
+307
@@ -0,0 +1,307 @@
|
||||
// ----------------------------------------------------------------------------
|
||||
// <copyright file="Enums.cs" company="Exit Games GmbH">
|
||||
// PhotonNetwork Framework for Unity - Copyright (C) 2011 Exit Games GmbH
|
||||
// </copyright>
|
||||
// <summary>
|
||||
//
|
||||
// </summary>
|
||||
// <author>developer@exitgames.com</author>
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
using ExitGames.Client.Photon;
|
||||
|
||||
/// <summary>
|
||||
/// High level connection state of the client. Better use the more detailed <see cref="PeerState"/>.
|
||||
/// </summary>
|
||||
public enum ConnectionState
|
||||
{
|
||||
Disconnected,
|
||||
Connecting,
|
||||
Connected,
|
||||
Disconnecting,
|
||||
InitializingApplication
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Detailed connection / networking peer state.
|
||||
/// PUN implements a loadbalancing and authentication workflow "behind the scenes", so
|
||||
/// some states will automatically advance to some follow up state. Those states are
|
||||
/// commented with "(will-change)".
|
||||
/// </summary>
|
||||
/// \ingroup publicApi
|
||||
public enum PeerState
|
||||
{
|
||||
/// <summary>Not running. Only set before initialization and first use.</summary>
|
||||
Uninitialized,
|
||||
|
||||
/// <summary>Created and available to connect.</summary>
|
||||
PeerCreated,
|
||||
|
||||
/// <summary>Working to establish the initial connection to the master server (until this process is finished, no operations can be sent).</summary>
|
||||
/// <remarks>(will-change)</remarks>
|
||||
Connecting,
|
||||
|
||||
/// <summary>Connection is setup, now PUN will exchange keys for encryption or authenticate.</summary>
|
||||
/// <remarks>(will-change)</remarks>
|
||||
Connected,
|
||||
|
||||
/// <summary>Not used at the moment.</summary>
|
||||
Queued,
|
||||
|
||||
/// <summary>The application is authenticated. PUN usually joins the lobby now.</summary>
|
||||
/// <remarks>(will-change) Unless AutoJoinLobby is false.</remarks>
|
||||
Authenticated,
|
||||
|
||||
/// <summary>Client is in the lobby of the Master Server and gets room listings.</summary>
|
||||
/// <remarks>Use Join, Create or JoinRandom to get into a room to play.</remarks>
|
||||
JoinedLobby,
|
||||
|
||||
/// <summary>Disconnecting.</summary>
|
||||
/// <remarks>(will-change)</remarks>
|
||||
DisconnectingFromMasterserver,
|
||||
|
||||
/// <summary>Connecting to game server (to join/create a room and play).</summary>
|
||||
/// <remarks>(will-change)</remarks>
|
||||
ConnectingToGameserver,
|
||||
|
||||
/// <summary>Similar to Connected state but on game server. Still in process to join/create room.</summary>
|
||||
/// <remarks>(will-change)</remarks>
|
||||
ConnectedToGameserver,
|
||||
|
||||
/// <summary>In process to join/create room (on game server).</summary>
|
||||
/// <remarks>(will-change)</remarks>
|
||||
Joining,
|
||||
|
||||
/// <summary>Final state of a room join/create sequence. This client can now exchange events / call RPCs with other clients.</summary>
|
||||
Joined,
|
||||
|
||||
/// <summary>Leaving a room.</summary>
|
||||
/// <remarks>(will-change)</remarks>
|
||||
Leaving,
|
||||
|
||||
/// <summary>Workflow is leaving the game server and will re-connect to the master server.</summary>
|
||||
/// <remarks>(will-change)</remarks>
|
||||
DisconnectingFromGameserver,
|
||||
|
||||
/// <summary>Workflow is connected to master server and will establish encryption and authenticate your app.</summary>
|
||||
/// <remarks>(will-change)</remarks>
|
||||
ConnectingToMasterserver,
|
||||
|
||||
/// <summary>Same as Connected but coming from game server.</summary>
|
||||
/// <remarks>(will-change)</remarks>
|
||||
ConnectedComingFromGameserver,
|
||||
|
||||
/// <summary>Same Queued but coming from game server.</summary>
|
||||
/// <remarks>(will-change)</remarks>
|
||||
QueuedComingFromGameserver,
|
||||
|
||||
/// <summary>PUN is disconnecting. This leads to Disconnected.</summary>
|
||||
/// <remarks>(will-change)</remarks>
|
||||
Disconnecting,
|
||||
|
||||
/// <summary>No connection is setup, ready to connect. Similar to PeerCreated.</summary>
|
||||
Disconnected,
|
||||
|
||||
/// <summary>Final state for connecting to master without joining the lobby (AutoJoinLobby is false).</summary>
|
||||
ConnectedToMaster
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Internal state how this peer gets into a particular room (joining it or creating it).
|
||||
/// </summary>
|
||||
internal enum JoinType
|
||||
{
|
||||
CreateGame,
|
||||
JoinGame,
|
||||
JoinRandomGame
|
||||
}
|
||||
|
||||
|
||||
// Photon properties, internally set by PhotonNetwork (PhotonNetwork builtin properties)
|
||||
|
||||
/// <summary>
|
||||
/// This enum makes up the set of MonoMessages sent by Photon Unity Networking.
|
||||
/// Implement any of these constant names as method and it will be called
|
||||
/// in the respective situation.
|
||||
/// </summary>
|
||||
/// <example>
|
||||
/// Implement:
|
||||
/// public void OnLeftRoom() { //some work }
|
||||
/// </example>
|
||||
/// \ingroup publicApi
|
||||
public enum PhotonNetworkingMessage
|
||||
{
|
||||
/// <summary>
|
||||
/// Called when the server is available and before client authenticates. Wait for the call to OnJoinedLobby (or OnConnectedToMaster) before the client does anything!
|
||||
/// Example: void OnConnectedToPhoton(){ ... }
|
||||
/// </summary>
|
||||
/// <remarks>This is not called for transitions from the masterserver to game servers, which is hidden for PUN users.</remarks>
|
||||
OnConnectedToPhoton,
|
||||
|
||||
/// <summary>
|
||||
/// Called once the local user left a room.
|
||||
/// Example: void OnLeftRoom(){ ... }
|
||||
/// </summary>
|
||||
OnLeftRoom,
|
||||
|
||||
/// <summary>
|
||||
/// Called -after- switching to a new MasterClient because the previous MC left the room. The last MC will already be removed at this points.
|
||||
/// Example: void OnMasterClientSwitched(PhotonPlayer newMasterClient){ ... }
|
||||
/// </summary>
|
||||
OnMasterClientSwitched,
|
||||
|
||||
/// <summary>
|
||||
/// Called if a CreateRoom() call failed. Most likely because the room name is already in use.
|
||||
/// Example: void OnPhotonCreateRoomFailed(){ ... }
|
||||
/// </summary>
|
||||
OnPhotonCreateRoomFailed,
|
||||
|
||||
/// <summary>
|
||||
/// Called if a JoinRoom() call failed. Most likely because the room does not exist or the room is full.
|
||||
/// Example: void OnPhotonJoinRoomFailed(){ ... }
|
||||
/// </summary>
|
||||
OnPhotonJoinRoomFailed,
|
||||
|
||||
/// <summary>
|
||||
/// Called after a CreateRoom() succeeded creating a room. Note that this implies the local client is the MasterClient. OnJoinedRoom is always called after OnCreatedRoom.
|
||||
/// Example: void OnCreatedRoom(){ ... }
|
||||
/// </summary>
|
||||
OnCreatedRoom,
|
||||
|
||||
/// <summary>
|
||||
/// Called when the connect to the master server is successful and the client can create/join rooms.
|
||||
/// Note: When PhotonNetwork.autoJoinLobby was set to false, OnConnectedToMaster is called instead!
|
||||
/// Example: void OnJoinedLobby(){ ... }
|
||||
/// </summary>
|
||||
/// <remarks>While in the lobby, the roomlist is automatically updated.</remarks>
|
||||
OnJoinedLobby,
|
||||
|
||||
/// <summary>
|
||||
/// Called after leaving the lobby
|
||||
/// Example: void OnLeftLobby(){ ... }
|
||||
/// </summary>
|
||||
OnLeftLobby,
|
||||
|
||||
/// <summary>
|
||||
/// Called after disconnecting from the Photon server.
|
||||
/// In some cases, other events are sent before OnDisconnectedFromPhoton is called. Examples: OnConnectionFail and OnFailedToConnectToPhoton.
|
||||
/// Example: void OnDisconnectedFromPhoton(){ ... }
|
||||
/// </summary>
|
||||
OnDisconnectedFromPhoton,
|
||||
|
||||
/// <summary>
|
||||
/// Called when something causes the connection to fail (after it was established), followed by a call to OnDisconnectedFromPhoton.
|
||||
/// If the server could not be reached in the first place, OnFailedToConnectToPhoton is called instead.
|
||||
/// The reason for the error is provided as StatusCode.
|
||||
/// Example: void OnConnectionFail(DisconnectCause cause){ ... }
|
||||
/// </summary>
|
||||
OnConnectionFail,
|
||||
|
||||
/// <summary>
|
||||
/// Called if a connect call to the Photon server failed before the connection was established, followed by a call to OnDisconnectedFromPhoton.
|
||||
/// If the connection was established but then fails, OnConnectionFail is called.
|
||||
/// Example: void OnFailedToConnectToPhoton(DisconnectCause cause){ ... }
|
||||
/// </summary>
|
||||
OnFailedToConnectToPhoton,
|
||||
|
||||
/// <summary>
|
||||
/// Called after receiving the room list for the first time. Only possible in the Lobby state.
|
||||
/// Example: void OnReceivedRoomList(){ ... }
|
||||
/// </summary>
|
||||
OnReceivedRoomList,
|
||||
|
||||
/// <summary>
|
||||
/// Called after receiving a room list update. Only possible in the Lobby state.
|
||||
/// Example: void OnReceivedRoomListUpdate(){ ... }
|
||||
/// </summary>
|
||||
OnReceivedRoomListUpdate,
|
||||
|
||||
/// <summary>
|
||||
/// Called after joining a room. Called on all clients (including the Master Client)
|
||||
/// Example: void OnJoinedRoom(){ ... }
|
||||
/// </summary>
|
||||
OnJoinedRoom,
|
||||
|
||||
/// <summary>
|
||||
/// Called after a remote player connected to the room. This PhotonPlayer is already added to the playerlist at this time.
|
||||
/// Example: void OnPhotonPlayerConnected(PhotonPlayer newPlayer){ ... }
|
||||
/// </summary>
|
||||
OnPhotonPlayerConnected,
|
||||
|
||||
/// <summary>
|
||||
/// Called after a remote player disconnected from the room. This PhotonPlayer is already removed from the playerlist at this time.
|
||||
/// Example: void OnPhotonPlayerDisconnected(PhotonPlayer otherPlayer){ ... }
|
||||
/// </summary>
|
||||
OnPhotonPlayerDisconnected,
|
||||
|
||||
/// <summary>
|
||||
/// Called after a JoinRandom() call failed. Most likely all rooms are full or no rooms are available.
|
||||
/// Example: void OnPhotonRandomJoinFailed(){ ... }
|
||||
/// </summary>
|
||||
OnPhotonRandomJoinFailed,
|
||||
|
||||
/// <summary>
|
||||
/// Called after the connection to the master is established and authenticated but only when PhotonNetwork.AutoJoinLobby is false.
|
||||
/// If AutoJoinLobby is false, the list of available rooms won't become available but you could join (random or by name) and create rooms anyways.
|
||||
/// Example: void OnConnectedToMaster(){ ... }
|
||||
/// </summary>
|
||||
OnConnectedToMaster,
|
||||
|
||||
/// <summary>
|
||||
/// Called every network 'update' on MonoBehaviours that are being observed by a PhotonView.
|
||||
/// Example: void OnPhotonSerializeView(PhotonStream stream, PhotonMessageInfo info){ ... }
|
||||
/// </summary>
|
||||
OnPhotonSerializeView,
|
||||
|
||||
/// <summary>
|
||||
/// Called on all scripts on a GameObject(and it's children) that have been spawned using PhotonNetwork.Instantiate
|
||||
/// Example: void OnPhotonInstantiate(PhotonMessageInfo info){ ... }
|
||||
/// </summary>
|
||||
OnPhotonInstantiate,
|
||||
|
||||
/// <summary>
|
||||
/// Because the concurrent user limit was (temporarily) reached, this client is rejected by the server and disconnecting.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// When this happens, the user might try again later. You can't create or join rooms in OnPhotonMaxCcuReached(), cause the client will be disconnecting.
|
||||
/// You can raise the CCU limits with a new license (when you host yourself) or extended subscription (when using the Photon Cloud).
|
||||
/// The Photon Cloud will mail you when the CCU limit was reached. This is also visible in the Dashboard (webpage).
|
||||
/// Example: void OnPhotonMaxCccuReached(){ ... }
|
||||
/// </remarks>
|
||||
OnPhotonMaxCccuReached
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Summarizes the cause for a disconnect. Used in: OnConnectionFail and OnFailedToConnectToPhoton.
|
||||
/// </summary>
|
||||
/// <remarks>Extracted from the status codes from ExitGames.Client.Photon.StatusCode.</remarks>
|
||||
/// <seealso cref="PhotonNetworkingMessage"/>
|
||||
/// \ingroup publicApi
|
||||
public enum DisconnectCause
|
||||
{
|
||||
/// <summary>Connection could not be established.
|
||||
/// Possible cause: Local server not running.</summary>
|
||||
ExceptionOnConnect = StatusCode.ExceptionOnConnect,
|
||||
|
||||
/// <summary>Connection timed out.
|
||||
/// Possible cause: Remote server not running or required ports blocked (due to router or firewall).</summary>
|
||||
TimeoutDisconnect = StatusCode.TimeoutDisconnect,
|
||||
|
||||
/// <summary>Exception in the receive-loop.
|
||||
/// Possible cause: Socket failure.</summary>
|
||||
InternalReceiveException = StatusCode.InternalReceiveException,
|
||||
|
||||
/// <summary>Server actively disconnected this client.</summary>
|
||||
DisconnectByServer = StatusCode.DisconnectByServer,
|
||||
|
||||
/// <summary>Server actively disconnected this client.
|
||||
/// Possible cause: Server's send buffer full (too much data for client).</summary>
|
||||
DisconnectByServerLogic = StatusCode.DisconnectByServerLogic,
|
||||
|
||||
/// <summary>Server actively disconnected this client.
|
||||
/// Possible cause: The server's user limit was hit and client was forced to disconnect (on connect).</summary>
|
||||
DisconnectByServerUserLimit = StatusCode.DisconnectByServerUserLimit,
|
||||
|
||||
/// <summary>Some exception caused the connection to close.</summary>
|
||||
Exception = StatusCode.Exception,
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b7962bbdaba2a4940b1341d755abd40d
|
||||
labels:
|
||||
- ExitGames
|
||||
- PUN
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d1ac0ed63c08a9d499b356cfba031d86
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
userData:
|
||||
+241
@@ -0,0 +1,241 @@
|
||||
// ----------------------------------------------------------------------------
|
||||
// <copyright file="PhotonView.cs" company="Exit Games GmbH">
|
||||
// PhotonNetwork Framework for Unity - Copyright (C) 2011 Exit Games GmbH
|
||||
// </copyright>
|
||||
// <summary>
|
||||
//
|
||||
// </summary>
|
||||
// <author>developer@exitgames.com</author>
|
||||
// ----------------------------------------------------------------------------
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
|
||||
public enum ViewSynchronization { Off, ReliableDeltaCompressed, Unreliable }
|
||||
public enum OnSerializeTransform { OnlyPosition, OnlyRotation, OnlyScale, PositionAndRotation, All }
|
||||
public enum OnSerializeRigidBody { OnlyVelocity, OnlyAngularVelocity, All }
|
||||
|
||||
/// <summary>
|
||||
/// PUN's NetworkView replacement class for networking. Use it like a NetworkView.
|
||||
/// </summary>
|
||||
/// \ingroup publicApi
|
||||
[AddComponentMenu("Miscellaneous/Photon View")]
|
||||
public class PhotonView : Photon.MonoBehaviour
|
||||
{
|
||||
//Save scene ID in serializable INT (only changable via Editor)
|
||||
[SerializeField]
|
||||
private int sceneViewID = 0;
|
||||
|
||||
[SerializeField]
|
||||
private PhotonViewID ID = new PhotonViewID(0, null);
|
||||
|
||||
public Component observed;
|
||||
public ViewSynchronization synchronization;
|
||||
public int group = 0;
|
||||
public short prefix = -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 = null;
|
||||
|
||||
/// <summary>
|
||||
/// For internal use only, don't use
|
||||
/// </summary>
|
||||
protected internal object[] lastOnSerializeDataSent = null;
|
||||
|
||||
/// <summary>
|
||||
/// For internal use only, don't use
|
||||
/// </summary>
|
||||
protected internal object[] lastOnSerializeDataReceived = null;
|
||||
|
||||
public OnSerializeTransform onSerializeTransformOption = OnSerializeTransform.PositionAndRotation;
|
||||
|
||||
public OnSerializeRigidBody onSerializeRigidBodyOption = OnSerializeRigidBody.All;
|
||||
|
||||
private bool registeredPhotonView = false;
|
||||
|
||||
public PhotonViewID viewID
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!this.ranSetup)
|
||||
{
|
||||
this.Setup();
|
||||
}
|
||||
|
||||
if (this.ID.ID < 1 && this.sceneViewID > 0)
|
||||
{
|
||||
// Load the correct scene ID
|
||||
this.ID = new PhotonViewID(this.sceneViewID, null);
|
||||
}
|
||||
|
||||
return this.ID;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
if (!this.ranSetup)
|
||||
{
|
||||
this.Setup();
|
||||
}
|
||||
|
||||
if (this.registeredPhotonView && PhotonNetwork.networkingPeer != null)
|
||||
{
|
||||
PhotonNetwork.networkingPeer.RemovePhotonView(this, true);
|
||||
}
|
||||
|
||||
this.ID = value;
|
||||
if (PhotonNetwork.networkingPeer != null)
|
||||
{
|
||||
PhotonNetwork.networkingPeer.RegisterPhotonView(this);
|
||||
this.registeredPhotonView = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return string.Format("View {0} on {1} {2}", this.ID.ID, this.gameObject.name, (this.isSceneView) ? "(scene)" : string.Empty);
|
||||
}
|
||||
|
||||
public bool isSceneView
|
||||
{
|
||||
get
|
||||
{
|
||||
return (this.sceneViewID > 0) // Baked in the scene via editor
|
||||
|| (this.ID.owner == null && this.ID.ID > 0 && this.ID.ID < PhotonNetwork.MAX_VIEW_IDS); //Spawned via InstantiateSceneobject
|
||||
}
|
||||
}
|
||||
|
||||
public PhotonPlayer owner
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!this.ranSetup)
|
||||
{
|
||||
this.Setup();
|
||||
}
|
||||
|
||||
return this.viewID.owner;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Is this photonView mine?
|
||||
/// True in case the owner matches the local PhotonPlayer
|
||||
/// ALSO true if this is a scene photonview on the Master client
|
||||
/// </summary>
|
||||
public bool isMine
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!this.ranSetup)
|
||||
{
|
||||
this.Setup();
|
||||
}
|
||||
|
||||
return (this.owner == PhotonNetwork.player) || (this.isSceneView && PhotonNetwork.isMasterClient);
|
||||
}
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
|
||||
public void SetSceneID(int newID)
|
||||
{
|
||||
sceneViewID = newID;
|
||||
}
|
||||
|
||||
public int GetSceneID()
|
||||
{
|
||||
return sceneViewID;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/// <summary>Called by Unity on start of the application and does a setup the PhotonView.</summary>
|
||||
public void Awake()
|
||||
{
|
||||
this.Setup();
|
||||
}
|
||||
|
||||
private bool ranSetup = false;
|
||||
|
||||
private void Setup()
|
||||
{
|
||||
if (!Application.isPlaying)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.ranSetup)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
this.ranSetup = true;
|
||||
|
||||
if (this.isSceneView)
|
||||
{
|
||||
bool result = PhotonNetwork.networkingPeer.PhotonViewSetup_FindMatchingRoot(gameObject);
|
||||
if (result)
|
||||
{
|
||||
// This instantiated prefab needs to be corrected as it's incorrectly reported as a sceneview.
|
||||
// It is wrongly reported as isSceneView because a scene-prefab changes have been applied to the project prefab
|
||||
// The scene's prefab viewID is therefore saved to the project prefab. This workaround fixes all problems
|
||||
this.sceneViewID = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (this.sceneViewID < 1)
|
||||
{
|
||||
Debug.LogError("SceneView " + sceneViewID);
|
||||
}
|
||||
|
||||
ID = new PhotonViewID(this.sceneViewID, null);
|
||||
this.registeredPhotonView = true;
|
||||
PhotonNetwork.networkingPeer.RegisterPhotonView(this);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
bool res = PhotonNetwork.networkingPeer.PhotonViewSetup_FindMatchingRoot(gameObject);
|
||||
if (!res)
|
||||
{
|
||||
if (PhotonNetwork.logLevel != PhotonLogLevel.ErrorsOnly)
|
||||
{
|
||||
Debug.LogWarning("Warning: Did not find the root of a PhotonView. This is only OK if you used GameObject.Instantiate to instantiate this prefab. Object: " + this.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OnDestroy()
|
||||
{
|
||||
PhotonNetwork.networkingPeer.RemovePhotonView(this, true);
|
||||
}
|
||||
|
||||
public void RPC(string methodName, PhotonTargets target, params object[] parameters)
|
||||
{
|
||||
PhotonNetwork.RPC(this, methodName, target, parameters);
|
||||
}
|
||||
|
||||
public void RPC(string methodName, PhotonPlayer targetPlayer, params object[] parameters)
|
||||
{
|
||||
PhotonNetwork.RPC(this, methodName, targetPlayer, parameters);
|
||||
}
|
||||
|
||||
public static PhotonView Get(Component component)
|
||||
{
|
||||
return component.GetComponent<PhotonView>();
|
||||
}
|
||||
|
||||
public static PhotonView Get(GameObject gameObj)
|
||||
{
|
||||
return gameObj.GetComponent<PhotonView>();
|
||||
}
|
||||
|
||||
public static PhotonView Find(int viewID)
|
||||
{
|
||||
return PhotonNetwork.networkingPeer.GetPhotonView(viewID);
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: aa584fbee541324448dd18d8409c7a41
|
||||
labels:
|
||||
- ExitGames
|
||||
- PUN
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
+160
@@ -0,0 +1,160 @@
|
||||
// ----------------------------------------------------------------------------
|
||||
// <copyright file="Extensions.cs" company="Exit Games GmbH">
|
||||
// PhotonNetwork Framework for Unity - Copyright (C) 2011 Exit Games GmbH
|
||||
// </copyright>
|
||||
// <summary>
|
||||
// Provides some helpful methods and extensions for Hashtables, etc.
|
||||
// </summary>
|
||||
// <author>developer@exitgames.com</author>
|
||||
// ----------------------------------------------------------------------------
|
||||
using System.Collections;
|
||||
using ExitGames.Client.Photon;
|
||||
using UnityEngine;
|
||||
|
||||
/// <summary>
|
||||
/// This static class defines some useful extension methods for several existing classes (e.g. Vector3, float and others).
|
||||
/// </summary>
|
||||
public static class Extensions
|
||||
{
|
||||
/// <summary>compares the square magniture of target - second to given float value</summary>
|
||||
public static bool AlmostEquals(this Vector3 target, Vector3 second, float sqrMagniturePrecision)
|
||||
{
|
||||
return (target - second).sqrMagnitude < sqrMagniturePrecision;
|
||||
}
|
||||
|
||||
/// <summary>compares the square magniture of target - second to given float value</summary>
|
||||
public static bool AlmostEquals(this Vector2 target, Vector2 second, float sqrMagniturePrecision)
|
||||
{
|
||||
return (target - second).sqrMagnitude < sqrMagniturePrecision;
|
||||
}
|
||||
|
||||
/// <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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Merges all keys from addHash into the target. Adds new keys and updates the values of existing keys in target.
|
||||
/// </summary>
|
||||
/// <param name="target">The IDictionary to update.</param>
|
||||
/// <param name="addHash">The IDictionary containing data to merge into target.</param>
|
||||
public static void Merge(this IDictionary target, IDictionary addHash)
|
||||
{
|
||||
if (addHash == null || target.Equals(addHash))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (object key in addHash.Keys)
|
||||
{
|
||||
target[key] = addHash[key];
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Merges keys of type string to target Hashtable.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Does not remove keys from target (so non-string keys CAN be in target if they were before).
|
||||
/// </remarks>
|
||||
/// <param name="target">The target IDicitionary passed in plus all string-typed keys from the addHash.</param>
|
||||
/// <param name="addHash">A IDictionary that should be merged partly into target to update it.</param>
|
||||
public static void MergeStringKeys(this IDictionary target, IDictionary addHash)
|
||||
{
|
||||
if (addHash == null || target.Equals(addHash))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (object key in addHash.Keys)
|
||||
{
|
||||
// only merge keys of type string
|
||||
if (key is string)
|
||||
{
|
||||
target[key] = addHash[key];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a string-representation of the IDictionary's content, inlcuding type-information.
|
||||
/// Note: This might turn out a "heavy-duty" call if used frequently but it's usfuly to debug Dictionary or Hashtable content.
|
||||
/// </summary>
|
||||
/// <param name="origin">Some Dictionary or Hashtable.</param>
|
||||
/// <returns>String of the content of the IDictionary.</returns>
|
||||
public static string ToStringFull(this IDictionary origin)
|
||||
{
|
||||
return SupportClass.DictionaryToString(origin, false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This method copies all string-typed keys of the original into a new Hashtable.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Does not recurse (!) into hashes that might be values in the root-hash.
|
||||
/// This does not modify the original.
|
||||
/// </remarks>
|
||||
/// <param name="original">The original IDictonary to get string-typed keys from.</param>
|
||||
/// <returns>New Hashtable containing parts ot fht original.</returns>
|
||||
public static Hashtable StripToStringKeys(this IDictionary original)
|
||||
{
|
||||
Hashtable target = new Hashtable();
|
||||
foreach (DictionaryEntry pair in original)
|
||||
{
|
||||
if (pair.Key is string)
|
||||
{
|
||||
target[pair.Key] = pair.Value;
|
||||
}
|
||||
}
|
||||
|
||||
return target;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This removes all key-value pairs that have a null-reference as value.
|
||||
/// In Photon properties are removed by setting their value to null.
|
||||
/// Changes the original passed IDictionary!
|
||||
/// </summary>
|
||||
/// <param name="original">The IDictionary to strip of keys with null-values.</param>
|
||||
public static void StripKeysWithNullValues(this IDictionary original)
|
||||
{
|
||||
object[] keys = new object[original.Count];
|
||||
original.Keys.CopyTo(keys, 0);
|
||||
|
||||
for (int index = 0; index < keys.Length; index++)
|
||||
{
|
||||
var key = keys[index];
|
||||
if (original[key] == null)
|
||||
{
|
||||
original.Remove(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if a particular integer value is in an int-array.
|
||||
/// </summary>
|
||||
/// <remarks>This might be useful to look up if a particular actorNumber is in the list of players of a room.</remarks>
|
||||
/// <param name="target">The array of ints to check.</param>
|
||||
/// <param name="nr">The number to lookup in target.</param>
|
||||
/// <returns>True if nr was found in target.</returns>
|
||||
public static bool Contains(this int[] target, int nr)
|
||||
{
|
||||
for (int index = 0; index < target.Length; index++)
|
||||
{
|
||||
if (target[index] == nr)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3c0464991e33a70498abdd85c150cc59
|
||||
labels:
|
||||
- ExitGames
|
||||
- PUN
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
+550
@@ -0,0 +1,550 @@
|
||||
// ----------------------------------------------------------------------------
|
||||
// <copyright file="LoadbalancingPeer.cs" company="Exit Games GmbH">
|
||||
// Loadbalancing Framework for Photon - Copyright (C) 2011 Exit Games GmbH
|
||||
// </copyright>
|
||||
// <summary>
|
||||
// Provides the operations needed to use the loadbalancing server app(s).
|
||||
// </summary>
|
||||
// <author>developer@exitgames.com</author>
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using ExitGames.Client.Photon;
|
||||
using ExitGames.Client.Photon.Lite;
|
||||
|
||||
/// <summary>
|
||||
/// Internally used by PUN, a LoadbalancingPeer provides the operations and enum
|
||||
/// definitions needed to use the Photon Loadbalancing server (or the Photon Cloud).
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The LoadBalancingPeer does not keep a state, instead this is done by a LoadBalancingClient.
|
||||
/// </remarks>
|
||||
internal class LoadbalancingPeer : PhotonPeer
|
||||
{
|
||||
public LoadbalancingPeer(IPhotonPeerListener listener, ConnectionProtocol protocolType) : base(listener, protocolType)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Joins the lobby on the Master Server, where you get a list of RoomInfos of currently open rooms.
|
||||
/// This is an async request which triggers a OnOperationResponse() call.
|
||||
/// </summary>
|
||||
/// <returns>If the operation could be sent (has to be connected).</returns>
|
||||
public virtual bool OpJoinLobby()
|
||||
{
|
||||
if (this.DebugOut >= DebugLevel.INFO)
|
||||
{
|
||||
this.Listener.DebugReturn(DebugLevel.INFO, "OpJoinLobby()");
|
||||
}
|
||||
|
||||
return this.OpCustom(OperationCode.JoinLobby, null, true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Leaves the lobby on the Master Server.
|
||||
/// This is an async request which triggers a OnOperationResponse() call.
|
||||
/// </summary>
|
||||
/// <returns>If the operation could be sent (has to be connected).</returns>
|
||||
public virtual bool OpLeaveLobby()
|
||||
{
|
||||
if (this.DebugOut >= DebugLevel.INFO)
|
||||
{
|
||||
this.Listener.DebugReturn(DebugLevel.INFO, "OpLeaveLobby()");
|
||||
}
|
||||
|
||||
return this.OpCustom(OperationCode.LeaveLobby, null, true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Don't use this method directly, unless you know how to cache and apply customActorProperties.
|
||||
/// The PhotonNetwork methods will handle player and room properties for you and call this method.
|
||||
/// </summary>
|
||||
public virtual bool OpCreateRoom(string gameID, bool isVisible, bool isOpen, byte maxPlayers, bool autoCleanUp, Hashtable customGameProperties, Hashtable customPlayerProperties, string[] customRoomPropertiesForLobby)
|
||||
{
|
||||
if (this.DebugOut >= DebugLevel.INFO)
|
||||
{
|
||||
this.Listener.DebugReturn(DebugLevel.INFO, "OpCreateRoom()");
|
||||
}
|
||||
|
||||
Hashtable gameProperties = new Hashtable();
|
||||
gameProperties[GameProperties.IsOpen] = isOpen;
|
||||
gameProperties[GameProperties.IsVisible] = isVisible;
|
||||
gameProperties[GameProperties.PropsListedInLobby] = customRoomPropertiesForLobby;
|
||||
gameProperties.MergeStringKeys(customGameProperties);
|
||||
if (maxPlayers > 0)
|
||||
{
|
||||
gameProperties[GameProperties.MaxPlayers] = maxPlayers;
|
||||
}
|
||||
|
||||
Dictionary<byte, object> op = new Dictionary<byte, object>();
|
||||
op[ParameterCode.GameProperties] = gameProperties;
|
||||
op[ParameterCode.PlayerProperties] = customPlayerProperties;
|
||||
op[ParameterCode.Broadcast] = true;
|
||||
|
||||
if (!string.IsNullOrEmpty(gameID))
|
||||
{
|
||||
op[ParameterCode.RoomName] = gameID;
|
||||
}
|
||||
|
||||
if (autoCleanUp)
|
||||
{
|
||||
op[ParameterCode.CleanupCacheOnLeave] = autoCleanUp;
|
||||
gameProperties[GameProperties.CleanupCacheOnLeave] = autoCleanUp;
|
||||
}
|
||||
|
||||
Listener.DebugReturn(DebugLevel.INFO, OperationCode.CreateGame + ": " + SupportClass.DictionaryToString(op));
|
||||
return this.OpCustom(OperationCode.CreateGame, op, true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Joins a room by name and sets this player's properties.
|
||||
/// </summary>
|
||||
/// <param name="roomName"></param>
|
||||
/// <param name="playerProperties"></param>
|
||||
/// <returns>If the operation could be sent (has to be connected).</returns>
|
||||
public virtual bool OpJoinRoom(string roomName, Hashtable playerProperties)
|
||||
{
|
||||
if (this.DebugOut >= DebugLevel.INFO)
|
||||
{
|
||||
this.Listener.DebugReturn(DebugLevel.INFO, "OpJoinRoom()");
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(roomName))
|
||||
{
|
||||
this.Listener.DebugReturn(DebugLevel.ERROR, "OpJoinRoom() failed. Please specify a roomname.");
|
||||
return false;
|
||||
}
|
||||
|
||||
Dictionary<byte, object> op = new Dictionary<byte, object>();
|
||||
op[ParameterCode.RoomName] = roomName;
|
||||
op[ParameterCode.Broadcast] = true;
|
||||
if (playerProperties != null)
|
||||
{
|
||||
op[ParameterCode.PlayerProperties] = playerProperties;
|
||||
}
|
||||
|
||||
return this.OpCustom(OperationCode.JoinGame, op, true);
|
||||
}
|
||||
|
||||
/// <remarks>the hashtable is (optionally) used to filter games: only those that fit the contained custom properties will be matched.</remarks>
|
||||
public virtual bool OpJoinRandomRoom(Hashtable expectedGameProperties)
|
||||
{
|
||||
if (this.DebugOut >= DebugLevel.INFO)
|
||||
{
|
||||
this.Listener.DebugReturn(DebugLevel.INFO, "OpJoinRandomRoom()");
|
||||
}
|
||||
|
||||
Dictionary<byte, object> op = new Dictionary<byte, object>();
|
||||
if (expectedGameProperties != null && expectedGameProperties.Count > 0)
|
||||
{
|
||||
op[ParameterCode.GameProperties] = expectedGameProperties;
|
||||
}
|
||||
|
||||
return this.OpCustom(OperationCode.JoinRandomGame, op, true);
|
||||
}
|
||||
|
||||
public bool OpSetCustomPropertiesOfActor(int actorNr, Hashtable actorProperties, bool broadcast, byte channelId)
|
||||
{
|
||||
return this.OpSetPropertiesOfActor(actorNr, actorProperties.StripToStringKeys(), broadcast, channelId);
|
||||
}
|
||||
|
||||
protected bool OpSetPropertiesOfActor(int actorNr, Hashtable actorProperties, bool broadcast, byte channelId)
|
||||
{
|
||||
if (this.DebugOut >= DebugLevel.INFO)
|
||||
{
|
||||
this.Listener.DebugReturn(DebugLevel.INFO, "OpSetPropertiesOfActor()");
|
||||
}
|
||||
|
||||
Dictionary<byte, object> opParameters = new Dictionary<byte, object>();
|
||||
opParameters.Add(ParameterCode.Properties, actorProperties);
|
||||
opParameters.Add(ParameterCode.ActorNr, actorNr);
|
||||
if (broadcast)
|
||||
{
|
||||
opParameters.Add(ParameterCode.Broadcast, broadcast);
|
||||
}
|
||||
|
||||
return this.OpCustom((byte)OperationCode.SetProperties, opParameters, broadcast, channelId);
|
||||
}
|
||||
|
||||
protected void OpSetPropertyOfRoom(byte propCode, object value)
|
||||
{
|
||||
Hashtable properties = new Hashtable();
|
||||
properties[propCode] = value;
|
||||
this.OpSetPropertiesOfRoom(properties, true, (byte)0);
|
||||
}
|
||||
|
||||
public bool OpSetCustomPropertiesOfRoom(Hashtable gameProperties, bool broadcast, byte channelId)
|
||||
{
|
||||
return this.OpSetPropertiesOfRoom(gameProperties.StripToStringKeys(), broadcast, channelId);
|
||||
}
|
||||
|
||||
public bool OpSetPropertiesOfRoom(Hashtable gameProperties, bool broadcast, byte channelId)
|
||||
{
|
||||
if (this.DebugOut >= DebugLevel.INFO)
|
||||
{
|
||||
this.Listener.DebugReturn(DebugLevel.INFO, "OpSetPropertiesOfRoom()");
|
||||
}
|
||||
|
||||
Dictionary<byte, object> opParameters = new Dictionary<byte, object>();
|
||||
opParameters.Add(ParameterCode.Properties, gameProperties);
|
||||
if (broadcast)
|
||||
{
|
||||
opParameters.Add(ParameterCode.Broadcast, broadcast);
|
||||
}
|
||||
|
||||
return this.OpCustom((byte)OperationCode.SetProperties, opParameters, broadcast, channelId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sends this app's appId and appVersion to identify this application server side.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This operation makes use of encryption, if it's established beforehand.
|
||||
/// See: EstablishEncryption(). Check encryption with IsEncryptionAvailable.
|
||||
/// </remarks>
|
||||
/// <param name="appId"></param>
|
||||
/// <param name="appVersion"></param>
|
||||
/// <returns>If the operation could be sent (has to be connected).</returns>
|
||||
public virtual bool OpAuthenticate(string appId, string appVersion)
|
||||
{
|
||||
if (this.DebugOut >= DebugLevel.INFO)
|
||||
{
|
||||
this.Listener.DebugReturn(DebugLevel.INFO, "OpAuthenticate()");
|
||||
}
|
||||
|
||||
Dictionary<byte, object> opParameters = new Dictionary<byte, object>();
|
||||
opParameters[ParameterCode.AppVersion] = appVersion;
|
||||
opParameters[ParameterCode.ApplicationId] = appId;
|
||||
|
||||
return this.OpCustom(OperationCode.Authenticate, opParameters, true, (byte)0, this.IsEncryptionAvailable);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Used in a room to raise (send) an event to the other players.
|
||||
/// Multiple overloads expose different parameters to this frequently used operation.
|
||||
/// </summary>
|
||||
/// <param name="eventCode">Code for this "type" of event (use a code per "meaning" or content).</param>
|
||||
/// <param name="evData">Data to send. Hashtable that contains key-values of Photon serializable datatypes.</param>
|
||||
/// <param name="sendReliable">Use false if the event is replaced by a newer rapidly. Reliable events add overhead and add lag when repeated.</param>
|
||||
/// <param name="channelId">The "channel" to which this event should belong. Per channel, the sequence is kept in order.</param>
|
||||
/// <returns>If the operation could be sent (has to be connected).</returns>
|
||||
public virtual bool OpRaiseEvent(byte eventCode, Hashtable evData, bool sendReliable, byte channelId)
|
||||
{
|
||||
return this.OpRaiseEvent(eventCode, evData, sendReliable, channelId, EventCaching.DoNotCache, ReceiverGroup.Others);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Used in a room to raise (send) an event to the other players.
|
||||
/// Multiple overloads expose different parameters to this frequently used operation.
|
||||
/// </summary>
|
||||
/// <param name="eventCode">Code for this "type" of event (use a code per "meaning" or content).</param>
|
||||
/// <param name="evData">Data to send. Hashtable that contains key-values of Photon serializable datatypes.</param>
|
||||
/// <param name="sendReliable">Use false if the event is replaced by a newer rapidly. Reliable events add overhead and add lag when repeated.</param>
|
||||
/// <param name="channelId">The "channel" to which this event should belong. Per channel, the sequence is kept in order.</param>
|
||||
/// <param name="targetActors">Defines the target players who should receive the event (use only for small target groups).</param>
|
||||
/// <returns>If the operation could be sent (has to be connected).</returns>
|
||||
public virtual bool OpRaiseEvent(byte eventCode, Hashtable evData, bool sendReliable, byte channelId, int[] targetActors)
|
||||
{
|
||||
return this.OpRaiseEvent(eventCode, evData, sendReliable, channelId, targetActors, EventCaching.DoNotCache);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Used in a room to raise (send) an event to the other players.
|
||||
/// Multiple overloads expose different parameters to this frequently used operation.
|
||||
/// </summary>
|
||||
/// <param name="eventCode">Code for this "type" of event (use a code per "meaning" or content).</param>
|
||||
/// <param name="evData">Data to send. Hashtable that contains key-values of Photon serializable datatypes.</param>
|
||||
/// <param name="sendReliable">Use false if the event is replaced by a newer rapidly. Reliable events add overhead and add lag when repeated.</param>
|
||||
/// <param name="channelId">The "channel" to which this event should belong. Per channel, the sequence is kept in order.</param>
|
||||
/// <param name="targetActors">Defines the target players who should receive the event (use only for small target groups).</param>
|
||||
/// <param name="cache">Use EventCaching options to store this event for players who join.</param>
|
||||
/// <returns>If the operation could be sent (has to be connected).</returns>
|
||||
public virtual bool OpRaiseEvent(byte eventCode, Hashtable evData, bool sendReliable, byte channelId, int[] targetActors, EventCaching cache)
|
||||
{
|
||||
if (this.DebugOut >= DebugLevel.INFO)
|
||||
{
|
||||
this.Listener.DebugReturn(DebugLevel.INFO, "OpRaiseEvent()");
|
||||
}
|
||||
|
||||
Dictionary<byte, object> opParameters = new Dictionary<byte, object>();
|
||||
opParameters[ParameterCode.Data] = evData;
|
||||
opParameters[ParameterCode.Code] = (byte)eventCode;
|
||||
|
||||
if (cache != EventCaching.DoNotCache)
|
||||
{
|
||||
opParameters[ParameterCode.Cache] = (byte)cache;
|
||||
}
|
||||
|
||||
if (targetActors != null)
|
||||
{
|
||||
opParameters[ParameterCode.ActorList] = targetActors;
|
||||
}
|
||||
|
||||
return this.OpCustom(OperationCode.RaiseEvent, opParameters, sendReliable, channelId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Used in a room to raise (send) an event to the other players.
|
||||
/// Multiple overloads expose different parameters to this frequently used operation.
|
||||
/// </summary>
|
||||
/// <param name="eventCode">Code for this "type" of event (use a code per "meaning" or content).</param>
|
||||
/// <param name="evData">Data to send. Hashtable that contains key-values of Photon serializable datatypes.</param>
|
||||
/// <param name="sendReliable">Use false if the event is replaced by a newer rapidly. Reliable events add overhead and add lag when repeated.</param>
|
||||
/// <param name="channelId">The "channel" to which this event should belong. Per channel, the sequence is kept in order.</param>
|
||||
/// <param name="cache">Use EventCaching options to store this event for players who join.</param>
|
||||
/// <param name="receivers">ReceiverGroup defines to which group of players the event is passed on.</param>
|
||||
/// <returns>If the operation could be sent (has to be connected).</returns>
|
||||
public virtual bool OpRaiseEvent(byte eventCode, Hashtable evData, bool sendReliable, byte channelId, EventCaching cache, ReceiverGroup receivers)
|
||||
{
|
||||
if (this.DebugOut >= DebugLevel.INFO)
|
||||
{
|
||||
this.Listener.DebugReturn(DebugLevel.INFO, "OpRaiseEvent()");
|
||||
}
|
||||
|
||||
Dictionary<byte, object> opParameters = new Dictionary<byte, object>();
|
||||
opParameters[ParameterCode.Data] = evData;
|
||||
opParameters[ParameterCode.Code] = (byte)eventCode;
|
||||
|
||||
if (receivers != ReceiverGroup.Others)
|
||||
{
|
||||
opParameters[ParameterCode.ReceiverGroup] = (byte)receivers;
|
||||
}
|
||||
|
||||
if (cache != EventCaching.DoNotCache)
|
||||
{
|
||||
opParameters[ParameterCode.Cache] = (byte)cache;
|
||||
}
|
||||
|
||||
return this.OpCustom((byte)OperationCode.RaiseEvent, opParameters, sendReliable, channelId);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Class for constants. These (int) values represent error codes, as defined and sent by the Photon LoadBalancing logic.
|
||||
/// Pun uses these constants internally.
|
||||
/// </summary>
|
||||
/// <note>Codes from the Photon Core are negative. Default-app error codes go down from short.max.</note>
|
||||
public class ErrorCode
|
||||
{
|
||||
/// <summary>(0) is always "OK", anything else an error or specific situation.</summary>
|
||||
public const int Ok = 0;
|
||||
|
||||
// server core errors are negative
|
||||
|
||||
/// <summary>
|
||||
/// Operation can't be executed yet (e.g. OpJoin can't be called before being authenticated, RaiseEvent cant be used before getting into a room).
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Before you call any operations on the Cloud servers, the automated client workflow must complete its authorization.
|
||||
/// In PUN, wait until State is: JoinedLobby (with AutoJoinLobby = true) or ConnectedToMaster (AutoJoinLobby = false)
|
||||
/// </remarks>
|
||||
public const int OperationNotAllowedInCurrentState = -3;
|
||||
|
||||
/// <summary>The operation you called is not implemented on the server (application) you connect to. Make sure you run the fitting applications.</summary>
|
||||
public const int InvalidOperationCode = -2;
|
||||
|
||||
/// <summary>Something went wrong in the server. Try to reproduce and contact Exit Games.</summary>
|
||||
public const int InternalServerError = -1;
|
||||
|
||||
// server - PhotonNetwork: 0x7FFF and down
|
||||
// logic-level error codes start with short.max
|
||||
|
||||
/// <summary>Authentication failed. Possible cause: AppId is unknown to Photon (in cloud service).</summary>
|
||||
public const int InvalidAuthentication = 0x7FFF;
|
||||
|
||||
/// <summary>GameId (name) already in use (can't create another). Change name.</summary>
|
||||
public const int GameIdAlreadyExists = 0x7FFF - 1;
|
||||
|
||||
/// <summary>Game is full. This can when players took over while you joined the game.</summary>
|
||||
public const int GameFull = 0x7FFF - 2;
|
||||
|
||||
/// <summary>Game is closed and can't be joined. Join another game.</summary>
|
||||
public const int GameClosed = 0x7FFF - 3;
|
||||
|
||||
[Obsolete("No longer used, cause random matchmaking is no longer a process.")]
|
||||
public const int AlreadyMatched = 0x7FFF - 4;
|
||||
|
||||
/// <summary>Not in use currently. Used when all game servers are full and this peer is not allowed to switch to any.</summary>
|
||||
public const int ServerFull = 0x7FFF - 5;
|
||||
|
||||
/// <summary>Not in use currently.</summary>
|
||||
public const int UserBlocked = 0x7FFF - 6;
|
||||
|
||||
/// <summary>Random matchmaking only succeeds if a room exists thats neither closed nor full. Repeat in a few seconds or create a new room.</summary>
|
||||
public const int NoRandomMatchFound = 0x7FFF - 7;
|
||||
|
||||
/// <summary>Join can fail if the room (name) is not existing (anymore). This can happen when players leave while you join.</summary>
|
||||
public const int GameDoesNotExist = 0x7FFF - 9;
|
||||
|
||||
/// <summary>This player is denied access to the server, because the concurrent user limit is (temporarily) reached.</summary>
|
||||
/// <remarks>When this happens, try again later. You can lift the CCU limits with a new license (when you host yourself) or extended subscription (when using the Photon Cloud).</remarks>
|
||||
public const int MaxCcuReached = 0x7FFF - 10;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Class for constants. These (byte) values define "well known" properties for an Actor / Player.
|
||||
/// Pun uses these constants internally.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// "Custom properties" have to use a string-type as key. They can be assigned at will.
|
||||
/// </remarks>
|
||||
public class ActorProperties
|
||||
{
|
||||
/// <summary>(255) Name of a player/actor.</summary>
|
||||
public const byte PlayerName = 255; // was: 1
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Class for constants. These (byte) values are for "well known" room/game properties used in Photon Loadbalancing.
|
||||
/// Pun uses these constants internally.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// "Custom properties" have to use a string-type as key. They can be assigned at will.
|
||||
/// </remarks>
|
||||
public class GameProperties
|
||||
{
|
||||
/// <summary>(255) Max number of players that "fit" into this room. 0 is for "unlimited".</summary>
|
||||
public const byte MaxPlayers = 255;
|
||||
/// <summary>(254) Makes this room listed or not in the lobby on master.</summary>
|
||||
public const byte IsVisible = 254;
|
||||
/// <summary>(253) Allows more players to join a room (or not).</summary>
|
||||
public const byte IsOpen = 253;
|
||||
/// <summary>(252) Current count od players in the room. Used only in the lobby on master.</summary>
|
||||
public const byte PlayerCount = 252;
|
||||
/// <summary>(251) True if the room is to be removed from room listing (used in update to room list in lobby on master)</summary>
|
||||
public const byte Removed = 251;
|
||||
/// <summary>(250) A list of the room properties to pass to the RoomInfo list in a lobby. This is used in CreateRoom, which defines this list once per room.</summary>
|
||||
public const byte PropsListedInLobby = 250;
|
||||
/// <summary>Equivalent of Operation Join parameter CleanupCacheOnLeave.</summary>
|
||||
public const byte CleanupCacheOnLeave = 249;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Class for constants. These values are for events defined by Photon Loadbalancing.
|
||||
/// Pun uses these constants internally.
|
||||
/// </summary>
|
||||
/// <remarks>They start at 255 and go DOWN. Your own in-game events can start at 0.</remarks>
|
||||
public class EventCode
|
||||
{
|
||||
/// <summary>(230) Initial list of RoomInfos (in lobby on Master)</summary>
|
||||
public const byte GameList = 230;
|
||||
/// <summary>(229) Update of RoomInfos to be merged into "initial" list (in lobby on Master)</summary>
|
||||
public const byte GameListUpdate = 229;
|
||||
/// <summary>(228) Currently not used. State of queueing in case of server-full</summary>
|
||||
public const byte QueueState = 228;
|
||||
/// <summary>(227) Currently not used. Event for matchmaking</summary>
|
||||
public const byte Match = 227;
|
||||
/// <summary>(226) Event with stats about this application (players, rooms, etc)</summary>
|
||||
public const byte AppStats = 226;
|
||||
/// <summary>(210) Internally used in case of hosting by Azure</summary>
|
||||
public const byte AzureNodeInfo = 210;
|
||||
/// <summary>(255) Event Join: someone joined the game. The new actorNumber is provided as well as the properties of that actor (if set in OpJoin).</summary>
|
||||
public const byte Join = (byte)LiteEventCode.Join;
|
||||
/// <summary>(254) Event Leave: The player who left the game can be identified by the actorNumber.</summary>
|
||||
public const byte Leave = (byte)LiteEventCode.Leave;
|
||||
/// <summary>(253) When you call OpSetProperties with the broadcast option "on", this event is fired. It contains the properties being set.</summary>
|
||||
public const byte PropertiesChanged = (byte)LiteEventCode.PropertiesChanged;
|
||||
/// <summary>(253) When you call OpSetProperties with the broadcast option "on", this event is fired. It contains the properties being set.</summary>
|
||||
[Obsolete("Use PropertiesChanged now.")]
|
||||
public const byte SetProperties = (byte)LiteEventCode.PropertiesChanged;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Class for constants. Codes for parameters of Operations and Events.
|
||||
/// Pun uses these constants internally.
|
||||
/// </summary>
|
||||
public class ParameterCode
|
||||
{
|
||||
/// <summary>(230) Address of a (game) server to use.</summary>
|
||||
public const byte Address = 230;
|
||||
/// <summary>(229) Count of players in this application in a rooms (used in stats event)</summary>
|
||||
public const byte PeerCount = 229;
|
||||
/// <summary>(228) Count of games in this application (used in stats event)</summary>
|
||||
public const byte GameCount = 228;
|
||||
/// <summary>(227) Count of players on the master server (in this app, looking for rooms)</summary>
|
||||
public const byte MasterPeerCount = 227;
|
||||
/// <summary>(225) User's ID</summary>
|
||||
public const byte UserId = 225;
|
||||
/// <summary>(224) Your application's ID: a name on your own Photon or a GUID on the Photon Cloud</summary>
|
||||
public const byte ApplicationId = 224;
|
||||
/// <summary>(223) Not used currently. If you get queued before connect, this is your position</summary>
|
||||
public const byte Position = 223;
|
||||
/// <summary>(222) List of RoomInfos about open / listed rooms</summary>
|
||||
public const byte GameList = 222;
|
||||
/// <summary>(221) Internally used to establish encryption</summary>
|
||||
public const byte Secret = 221;
|
||||
/// <summary>(220) Version of your application</summary>
|
||||
public const byte AppVersion = 220;
|
||||
/// <summary>(210) Internally used in case of hosting by Azure</summary>
|
||||
public const byte AzureNodeInfo = 210; // only used within events, so use: EventCode.AzureNodeInfo
|
||||
/// <summary>(209) Internally used in case of hosting by Azure</summary>
|
||||
public const byte AzureLocalNodeId = 209;
|
||||
/// <summary>(208) Internally used in case of hosting by Azure</summary>
|
||||
public const byte AzureMasterNodeId = 208;
|
||||
|
||||
/// <summary>(255) Code for the gameId/roomName (a unique name per room). Used in OpJoin and similar.</summary>
|
||||
public const byte RoomName = (byte)LiteOpKey.GameId;
|
||||
/// <summary>(250) Code for broadcast parameter of OpSetProperties method.</summary>
|
||||
public const byte Broadcast = (byte)LiteOpKey.Broadcast;
|
||||
/// <summary>(252) Code for list of players in a room. Currently not used.</summary>
|
||||
public const byte ActorList = (byte)LiteOpKey.ActorList;
|
||||
/// <summary>(254) Code of the Actor of an operation. Used for property get and set.</summary>
|
||||
public const byte ActorNr = (byte)LiteOpKey.ActorNr;
|
||||
/// <summary>(249) Code for property set (Hashtable).</summary>
|
||||
public const byte PlayerProperties = (byte)LiteOpKey.ActorProperties;
|
||||
/// <summary>(245) Code of data/custom content of an event. Used in OpRaiseEvent.</summary>
|
||||
public const byte CustomEventContent = (byte)LiteOpKey.Data;
|
||||
/// <summary>(245) Code of data of an event. Used in OpRaiseEvent.</summary>
|
||||
public const byte Data = (byte)LiteOpKey.Data;
|
||||
/// <summary>(244) Code used when sending some code-related parameter, like OpRaiseEvent's event-code.</summary>
|
||||
/// <remarks>This is not the same as the Operation's code, which is no longer sent as part of the parameter Dictionary in Photon 3.</remarks>
|
||||
public const byte Code = (byte)LiteOpKey.Code;
|
||||
/// <summary>(248) Code for property set (Hashtable).</summary>
|
||||
public const byte GameProperties = (byte)LiteOpKey.GameProperties;
|
||||
/// <summary>
|
||||
/// (251) Code for property-set (Hashtable). This key is used when sending only one set of properties.
|
||||
/// If either ActorProperties or GameProperties are used (or both), check those keys.
|
||||
/// </summary>
|
||||
public const byte Properties = (byte)LiteOpKey.Properties;
|
||||
/// <summary>(253) Code of the target Actor of an operation. Used for property set. Is 0 for game</summary>
|
||||
public const byte TargetActorNr = (byte)LiteOpKey.TargetActorNr;
|
||||
/// <summary>(246) Code to select the receivers of events (used in Lite, Operation RaiseEvent).</summary>
|
||||
public const byte ReceiverGroup = (byte)LiteOpKey.ReceiverGroup;
|
||||
/// <summary>(247) Code for caching events while raising them.</summary>
|
||||
public const byte Cache = (byte)LiteOpKey.Cache;
|
||||
/// <summary>(241) Bool parameter of CreateGame Operation. If true, server cleans up roomcache of leaving players (their cached events get removed).</summary>
|
||||
public const byte CleanupCacheOnLeave = (byte)241;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Class for constants. Contains operation codes.
|
||||
/// Pun uses these constants internally.
|
||||
/// </summary>
|
||||
public class OperationCode
|
||||
{
|
||||
/// <summary>(230) Authenticates this peer and connects to a virtual application</summary>
|
||||
public const byte Authenticate = 230;
|
||||
/// <summary>(229) Joins lobby (on master)</summary>
|
||||
public const byte JoinLobby = 229;
|
||||
/// <summary>(228) Leaves lobby (on master)</summary>
|
||||
public const byte LeaveLobby = 228;
|
||||
/// <summary>(227) Creates a game (or fails if name exists)</summary>
|
||||
public const byte CreateGame = 227;
|
||||
/// <summary>(226) Join game (by name)</summary>
|
||||
public const byte JoinGame = 226;
|
||||
/// <summary>(225) Joins random game (on master)</summary>
|
||||
public const byte JoinRandomGame = 225;
|
||||
|
||||
// public const byte CancelJoinRandom = 224; // obsolete, cause JoinRandom no longer is a "process". now provides result immediately
|
||||
|
||||
public const byte Leave = (byte)LiteOpCode.Leave;
|
||||
/// <summary>(253) Raise event (in a room, for other actors/players)</summary>
|
||||
public const byte RaiseEvent = (byte)LiteOpCode.RaiseEvent;
|
||||
/// <summary>(252) Set Properties (of room or actor/player)</summary>
|
||||
public const byte SetProperties = (byte)LiteOpCode.SetProperties;
|
||||
/// <summary>(251) Get Properties</summary>
|
||||
public const byte GetProperties = (byte)LiteOpCode.GetProperties;
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: dc29dca055845754e84d59fdac434098
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
+2932
@@ -0,0 +1,2932 @@
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// <copyright file="NetworkingPeer.cs" company="Exit Games GmbH">
|
||||
// Part of: Photon Unity Networking (PUN)
|
||||
// </copyright>
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using ExitGames.Client.Photon;
|
||||
using ExitGames.Client.Photon.Lite;
|
||||
using UnityEngine;
|
||||
|
||||
/// <summary>
|
||||
/// Implements Photon LoadBalancing used in PUN.
|
||||
/// This class is used internally by PhotonNetwork and not intended as public API.
|
||||
/// </summary>
|
||||
internal class NetworkingPeer : LoadbalancingPeer, IPhotonPeerListener
|
||||
{
|
||||
// game properties must be cached, because the game is created on the master and then "re-created" on the game server
|
||||
// both must use the same props for the game
|
||||
public string mAppVersion;
|
||||
|
||||
private string mAppId;
|
||||
|
||||
private byte nodeId = 0;
|
||||
|
||||
private string masterServerAddress;
|
||||
|
||||
private string playername = "";
|
||||
|
||||
private IPhotonPeerListener externalListener;
|
||||
|
||||
private JoinType mLastJoinType;
|
||||
|
||||
private bool mPlayernameHasToBeUpdated;
|
||||
|
||||
public string PlayerName
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.playername;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
if (string.IsNullOrEmpty(value) || value.Equals(this.playername))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.mLocalActor != null)
|
||||
{
|
||||
this.mLocalActor.name = value;
|
||||
}
|
||||
|
||||
this.playername = value;
|
||||
if (this.mCurrentGame != null)
|
||||
{
|
||||
// Only when in a room
|
||||
this.SendPlayerName();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public PeerState State { get; internal set; }
|
||||
|
||||
// "public" access to the current game - is null unless a room is joined on a gameserver
|
||||
public Room mCurrentGame
|
||||
{
|
||||
get
|
||||
{
|
||||
if (this.mRoomToGetInto != null && this.mRoomToGetInto.isLocalClientInside)
|
||||
{
|
||||
return this.mRoomToGetInto;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// keeps the custom properties, gameServer address and anything else about the room we want to get into
|
||||
/// </summary>
|
||||
internal Room mRoomToGetInto { get; set; }
|
||||
|
||||
public Dictionary<int, PhotonPlayer> mActors = new Dictionary<int, PhotonPlayer>();
|
||||
|
||||
public PhotonPlayer[] mOtherPlayerListCopy = new PhotonPlayer[0];
|
||||
public PhotonPlayer[] mPlayerListCopy = new PhotonPlayer[0];
|
||||
|
||||
public PhotonPlayer mLocalActor { get; internal set; }
|
||||
|
||||
public PhotonPlayer mMasterClient = null;
|
||||
|
||||
public string mGameserver { get; internal set; }
|
||||
|
||||
public bool requestSecurity = true;
|
||||
|
||||
private Dictionary<Type, List<MethodInfo>> monoRPCMethodsCache = new Dictionary<Type, List<MethodInfo>>();
|
||||
|
||||
/// <summary>Count of instantiations. Used to assign an id to each Instantiate event (which is buffered server-side). Reset in LeftRoomCleanup().</summary>
|
||||
private ushort cacheInstantiationCount = 0;
|
||||
|
||||
public Dictionary<string, RoomInfo> mGameList = new Dictionary<string, RoomInfo>();
|
||||
public RoomInfo[] mGameListCopy = new RoomInfo[0];
|
||||
|
||||
public int mQueuePosition { get; internal set; }
|
||||
|
||||
public bool insideLobby = false;
|
||||
|
||||
// stat values:
|
||||
public int mMasterCount { get; internal set; }
|
||||
|
||||
public int mGameCount { get; internal set; }
|
||||
|
||||
public int mPeerCount { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Instantiated objects by their instantiationId. The id (key) is per actor.
|
||||
/// </summary>
|
||||
public Dictionary<int, GameObject> instantiatedObjects = new Dictionary<int, GameObject>();
|
||||
|
||||
private List<int> blockReceivingGroups = new List<int>();
|
||||
|
||||
private List<int> blockSendingGroups = new List<int>();
|
||||
|
||||
private Dictionary<int, PhotonView> photonViewList = new Dictionary<int, PhotonView>();
|
||||
|
||||
private short currentLevelPrefix = -1;
|
||||
|
||||
/// <summary>
|
||||
/// Keeps track of ONLY LOCAL ID assignments (PhotonNetwork.AllocateViewID() etc.)
|
||||
/// </summary>
|
||||
public Dictionary<int, PhotonViewID> allocatedIDs = new Dictionary<int, PhotonViewID>();
|
||||
|
||||
public NetworkingPeer(IPhotonPeerListener listener, string playername, ConnectionProtocol connectionProtocol) : base(listener, connectionProtocol)
|
||||
{
|
||||
this.Listener = this;
|
||||
|
||||
// don't set the field directly! the listener is passed on to other classes, which get updated by the property set method
|
||||
this.externalListener = listener;
|
||||
this.PlayerName = playername;
|
||||
this.mLocalActor = new PhotonPlayer(true, -1, this.playername);
|
||||
this.AddNewPlayer(this.mLocalActor.ID, this.mLocalActor);
|
||||
|
||||
this.State = global::PeerState.PeerCreated;
|
||||
}
|
||||
|
||||
#region Operations and Connection Methods
|
||||
|
||||
public override bool Connect(string serverAddress, string appID, byte nodeId)
|
||||
{
|
||||
if (PhotonNetwork.connectionStateDetailed == global::PeerState.Disconnecting)
|
||||
{
|
||||
Debug.LogError("ERROR: Cannot connect to Photon while Disconnecting. Connection failed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(this.masterServerAddress))
|
||||
{
|
||||
this.masterServerAddress = serverAddress;
|
||||
}
|
||||
|
||||
this.mAppId = appID;
|
||||
|
||||
// connect might fail, if the DNS name can't be resolved or if no network connection is available
|
||||
bool connecting = base.Connect(serverAddress, "", nodeId);
|
||||
this.State = connecting ? global::PeerState.Connecting : global::PeerState.Disconnected;
|
||||
|
||||
return connecting;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Complete disconnect from photon (and the open master OR game server)
|
||||
/// </summary>
|
||||
public override void Disconnect()
|
||||
{
|
||||
if (this.PeerState == PeerStateValue.Disconnected)
|
||||
{
|
||||
if (this.DebugOut >= DebugLevel.WARNING)
|
||||
{
|
||||
this.DebugReturn(DebugLevel.WARNING, string.Format("Can't execute Disconnect() while not connected. Nothing changed. State: {0}", this.State));
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
base.Disconnect();
|
||||
this.State = global::PeerState.Disconnecting;
|
||||
|
||||
this.LeftRoomCleanup();
|
||||
LeftLobbyCleanup();
|
||||
}
|
||||
|
||||
// just switches servers(Master->Game). don't remove the room, actors, etc
|
||||
private void DisconnectFromMaster()
|
||||
{
|
||||
base.Disconnect();
|
||||
this.State = global::PeerState.DisconnectingFromMasterserver;
|
||||
LeftLobbyCleanup();
|
||||
}
|
||||
|
||||
// switches back from gameserver to master and removes the room, actors, etc
|
||||
private void DisconnectFromGameServer()
|
||||
{
|
||||
base.Disconnect();
|
||||
this.State = global::PeerState.DisconnectingFromGameserver;
|
||||
this.LeftRoomCleanup();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called at disconnect/leavelobby etc. This CAN also be called when we are not in a lobby (e.g. disconnect from room)
|
||||
/// </summary>
|
||||
private void LeftLobbyCleanup()
|
||||
{
|
||||
if (!insideLobby)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
SendMonoMessage(PhotonNetworkingMessage.OnLeftLobby);
|
||||
this.insideLobby = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when "this client" left a room to clean up.
|
||||
/// </summary>
|
||||
private void LeftRoomCleanup()
|
||||
{
|
||||
bool wasInRoom = mRoomToGetInto != null;
|
||||
// when leaving a room, we clean up depending on that room's settings.
|
||||
bool autoCleanupSettingOfRoom = (this.mRoomToGetInto != null) ? this.mRoomToGetInto.autoCleanUp : PhotonNetwork.autoCleanUpPlayerObjects;
|
||||
|
||||
this.mRoomToGetInto = null;
|
||||
this.mActors = new Dictionary<int, PhotonPlayer>();
|
||||
mPlayerListCopy = new PhotonPlayer[0];
|
||||
mOtherPlayerListCopy = new PhotonPlayer[0];
|
||||
this.mMasterClient = null;
|
||||
this.blockReceivingGroups = new List<int>();
|
||||
this.blockSendingGroups = new List<int>();
|
||||
this.mGameList = new Dictionary<string, RoomInfo>();
|
||||
mGameListCopy = new RoomInfo[0];
|
||||
|
||||
this.instantiatedPhotonViewSetupList = new List<InstantiatedPhotonViewSetup>();
|
||||
this.ChangeLocalID(-1);
|
||||
|
||||
// Cleanup all network objects (all spawned PhotonViews, local and remote)
|
||||
if (autoCleanupSettingOfRoom)
|
||||
{
|
||||
// Fill list with Instantiated objects
|
||||
List<GameObject> goList = new List<GameObject>(this.instantiatedObjects.Values);
|
||||
|
||||
// Fill list with other PhotonViews (contains doubles from Instantiated GO's)
|
||||
foreach (PhotonView view in this.photonViewList.Values)
|
||||
{
|
||||
if (view != null && !view.isSceneView && view.gameObject != null)
|
||||
{
|
||||
goList.Add(view.gameObject);
|
||||
}
|
||||
}
|
||||
|
||||
// Destroy GO's
|
||||
for (int i = goList.Count - 1; i >= 0; i--)
|
||||
{
|
||||
GameObject go = goList[i];
|
||||
if (go != null)
|
||||
{
|
||||
if (this.DebugOut >= DebugLevel.ALL)
|
||||
{
|
||||
this.DebugReturn(DebugLevel.ALL, "Network destroy Instantiated GO: " + go.name);
|
||||
}
|
||||
this.DestroyGO(go);
|
||||
}
|
||||
}
|
||||
|
||||
this.cacheInstantiationCount = 0; // starts with 0.
|
||||
this.instantiatedObjects = new Dictionary<int, GameObject>();
|
||||
this.allocatedIDs = new Dictionary<int, PhotonViewID>();
|
||||
}
|
||||
|
||||
if (wasInRoom)
|
||||
{
|
||||
SendMonoMessage(PhotonNetworkingMessage.OnLeftRoom);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This is a safe way to delete GO's as it makes sure to cleanup our PhotonViews instead of relying on "OnDestroy" which is called at the end of the current frame only.
|
||||
/// </summary>
|
||||
/// <param name="go">GameObject to destroy.</param>
|
||||
void DestroyGO(GameObject go)
|
||||
{
|
||||
PhotonView[] views = go.GetComponentsInChildren<PhotonView>();
|
||||
foreach (PhotonView view in views)
|
||||
{
|
||||
if (view != null)
|
||||
{
|
||||
this.RemovePhotonView(view, false);
|
||||
}
|
||||
}
|
||||
|
||||
GameObject.Destroy(go);
|
||||
}
|
||||
|
||||
private void SwitchNode(byte masterNodeId)
|
||||
{
|
||||
this.nodeId = masterNodeId;
|
||||
|
||||
// initiates a connection to the master server at disconnect
|
||||
this.DisconnectFromGameServer();
|
||||
}
|
||||
|
||||
// gameID can be null (optional). The server assigns a unique name if no name is set
|
||||
|
||||
// joins a room and sets your current username as custom actorproperty (will broadcast that)
|
||||
|
||||
#endregion
|
||||
|
||||
#region Helpers
|
||||
|
||||
private void readoutStandardProperties(Hashtable gameProperties, Hashtable pActorProperties, int targetActorNr)
|
||||
{
|
||||
// Debug.LogWarning("readoutStandardProperties game=" + gameProperties + " actors(" + pActorProperties + ")=" + pActorProperties + " " + targetActorNr);
|
||||
// read game properties and cache them locally
|
||||
if (this.mCurrentGame != null && gameProperties != null)
|
||||
{
|
||||
this.mCurrentGame.CacheProperties(gameProperties);
|
||||
}
|
||||
|
||||
if (pActorProperties != null && pActorProperties.Count > 0)
|
||||
{
|
||||
if (targetActorNr > 0)
|
||||
{
|
||||
// we have a single entry in the pActorProperties with one
|
||||
// user's name
|
||||
// targets MUST exist before you set properties
|
||||
PhotonPlayer target = this.GetPlayerWithID(targetActorNr);
|
||||
if (target != null)
|
||||
{
|
||||
target.InternalCacheProperties(this.GetActorPropertiesForActorNr(pActorProperties, targetActorNr));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// in this case, we've got a key-value pair per actor (each
|
||||
// value is a hashtable with the actor's properties then)
|
||||
int actorNr;
|
||||
Hashtable props;
|
||||
string newName;
|
||||
PhotonPlayer target;
|
||||
|
||||
foreach (object key in pActorProperties.Keys)
|
||||
{
|
||||
actorNr = (int)key;
|
||||
props = (Hashtable)pActorProperties[key];
|
||||
newName = (string)props[ActorProperties.PlayerName];
|
||||
|
||||
target = this.GetPlayerWithID(actorNr);
|
||||
if (target == null)
|
||||
{
|
||||
target = new PhotonPlayer(false, actorNr, newName);
|
||||
this.AddNewPlayer(actorNr, target);
|
||||
}
|
||||
|
||||
target.InternalCacheProperties(props);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void AddNewPlayer(int ID, PhotonPlayer player)
|
||||
{
|
||||
if (!this.mActors.ContainsKey(ID))
|
||||
{
|
||||
this.mActors[ID] = player;
|
||||
RebuildPlayerListCopies();
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError("Adding player twice: " + ID);
|
||||
}
|
||||
}
|
||||
|
||||
void RemovePlayer(int ID, PhotonPlayer player)
|
||||
{
|
||||
this.mActors.Remove(ID);
|
||||
if (!player.isLocal)
|
||||
{
|
||||
RebuildPlayerListCopies();
|
||||
}
|
||||
}
|
||||
|
||||
void RebuildPlayerListCopies()
|
||||
{
|
||||
this.mPlayerListCopy = new PhotonPlayer[this.mActors.Count];
|
||||
this.mActors.Values.CopyTo(this.mPlayerListCopy, 0);
|
||||
|
||||
List<PhotonPlayer> otherP = new List<PhotonPlayer>();
|
||||
foreach (PhotonPlayer player in this.mPlayerListCopy)
|
||||
{
|
||||
if (!player.isLocal)
|
||||
{
|
||||
otherP.Add(player);
|
||||
}
|
||||
}
|
||||
|
||||
this.mOtherPlayerListCopy = otherP.ToArray();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resets the PhotonView "lastOnSerializeDataSent" so that "OnReliable" synched PhotonViews send a complete state to new clients (if the state doesnt change, no messages would be send otherwise!).
|
||||
/// Note that due to this reset, ALL other players will receive the full OnSerialize.
|
||||
/// </summary>
|
||||
private void ResetPhotonViewsOnSerialize()
|
||||
{
|
||||
foreach (PhotonView photonView in this.photonViewList.Values)
|
||||
{
|
||||
photonView.lastOnSerializeDataSent = null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when the event Leave (of some other player) arrived.
|
||||
/// Cleans game objects, views locally. The master will also clean the
|
||||
/// </summary>
|
||||
/// <param name="actorID">ID of player who left.</param>
|
||||
private void HandleEventLeave(int actorID)
|
||||
{
|
||||
if (this.DebugOut >= DebugLevel.INFO)
|
||||
{
|
||||
this.DebugReturn(DebugLevel.INFO, "HandleEventLeave actorNr: " + actorID);
|
||||
}
|
||||
|
||||
// actorNr is fetched out of event above
|
||||
if (actorID < 0 || !this.mActors.ContainsKey(actorID))
|
||||
{
|
||||
if (this.DebugOut >= DebugLevel.ERROR)
|
||||
{
|
||||
this.DebugReturn(DebugLevel.ERROR, string.Format("Received event Leave for unknown actorNumber: {0}", actorID));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
PhotonPlayer player = this.GetPlayerWithID(actorID);
|
||||
if (player == null)
|
||||
{
|
||||
Debug.LogError("Error: HandleEventLeave for actorID=" + actorID + " has no PhotonPlayer!");
|
||||
}
|
||||
|
||||
// 1: Elect new masterclient, ignore the leaving player (as it's still in playerlists)
|
||||
if (this.mMasterClient != null && this.mMasterClient.ID == actorID)
|
||||
{
|
||||
this.mMasterClient = null;
|
||||
}
|
||||
this.CheckMasterClient(actorID);
|
||||
|
||||
// 2: Destroy objects & buffered messages
|
||||
if (this.mCurrentGame != null && this.mCurrentGame.autoCleanUp)
|
||||
{
|
||||
this.DestroyPlayerObjects(player, true);
|
||||
}
|
||||
|
||||
RemovePlayer(actorID, player);
|
||||
|
||||
// 4: Finally, send notification (the playerList and masterclient are now updated)
|
||||
SendMonoMessage(PhotonNetworkingMessage.OnPhotonPlayerDisconnected, player);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Chooses the new master client. Supply ignoreActorID to ignore a specific actor (e.g. when this actor has just left)
|
||||
/// </summary>
|
||||
/// <param name="ignoreActorID"></param>
|
||||
private void CheckMasterClient(int ignoreActorID)
|
||||
{
|
||||
int lowestActorNumber = int.MaxValue;
|
||||
|
||||
if (this.mMasterClient != null && this.mActors.ContainsKey(this.mMasterClient.ID))
|
||||
{
|
||||
// the current masterClient is still in the list of players, so it can't change
|
||||
return;
|
||||
}
|
||||
|
||||
// the master is unknown. find lowest actornumber == master
|
||||
foreach (int actorNumber in this.mActors.Keys)
|
||||
{
|
||||
if (ignoreActorID != -1 && ignoreActorID == actorNumber)
|
||||
{
|
||||
continue; //Skip this actor as it's leaving.
|
||||
}
|
||||
|
||||
if (actorNumber < lowestActorNumber)
|
||||
{
|
||||
lowestActorNumber = actorNumber;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (this.mMasterClient == null || this.mMasterClient.ID != lowestActorNumber)
|
||||
{
|
||||
this.mMasterClient = this.mActors[lowestActorNumber];
|
||||
SendMonoMessage(PhotonNetworkingMessage.OnMasterClientSwitched, this.mMasterClient);
|
||||
}
|
||||
}
|
||||
|
||||
private Hashtable GetActorPropertiesForActorNr(Hashtable actorProperties, int actorNr)
|
||||
{
|
||||
if (actorProperties.ContainsKey(actorNr))
|
||||
{
|
||||
return (Hashtable)actorProperties[actorNr];
|
||||
}
|
||||
|
||||
return actorProperties;
|
||||
}
|
||||
|
||||
private PhotonPlayer GetPlayerWithID(int number)
|
||||
{
|
||||
if (this.mActors != null && this.mActors.ContainsKey(number))
|
||||
{
|
||||
return this.mActors[number];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private void SendPlayerName()
|
||||
{
|
||||
if (this.State == global::PeerState.Joining)
|
||||
{
|
||||
// this means, the join on the gameServer is sent (with an outdated name). send the new when in game
|
||||
this.mPlayernameHasToBeUpdated = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.mLocalActor != null)
|
||||
{
|
||||
this.mLocalActor.name = this.PlayerName;
|
||||
Hashtable properties = new Hashtable();
|
||||
properties[ActorProperties.PlayerName] = this.PlayerName;
|
||||
this.OpSetPropertiesOfActor(this.mLocalActor.ID, properties, true, (byte)0);
|
||||
this.mPlayernameHasToBeUpdated = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void GameEnteredOnGameServer(OperationResponse operationResponse)
|
||||
{
|
||||
if (operationResponse.ReturnCode != 0)
|
||||
{
|
||||
switch (operationResponse.OperationCode)
|
||||
{
|
||||
case OperationCode.CreateGame:
|
||||
this.DebugReturn(DebugLevel.ERROR, "Create failed on GameServer. Changing back to MasterServer. Msg: " + operationResponse.DebugMessage);
|
||||
SendMonoMessage(PhotonNetworkingMessage.OnPhotonCreateRoomFailed);
|
||||
break;
|
||||
case OperationCode.JoinGame:
|
||||
this.DebugReturn(DebugLevel.WARNING, "Join failed on GameServer. Changing back to MasterServer. Msg: " + operationResponse.DebugMessage);
|
||||
if (operationResponse.ReturnCode == ErrorCode.GameDoesNotExist)
|
||||
{
|
||||
Debug.Log("Most likely the game became empty during the switch to GameServer.");
|
||||
}
|
||||
SendMonoMessage(PhotonNetworkingMessage.OnPhotonJoinRoomFailed);
|
||||
break;
|
||||
case OperationCode.JoinRandomGame:
|
||||
this.DebugReturn(DebugLevel.WARNING, "Join failed on GameServer. Changing back to MasterServer. Msg: " + operationResponse.DebugMessage);
|
||||
if (operationResponse.ReturnCode == ErrorCode.GameDoesNotExist)
|
||||
{
|
||||
Debug.Log("Most likely the game became empty during the switch to GameServer.");
|
||||
}
|
||||
SendMonoMessage(PhotonNetworkingMessage.OnPhotonRandomJoinFailed);
|
||||
break;
|
||||
}
|
||||
|
||||
this.DisconnectFromGameServer();
|
||||
return;
|
||||
}
|
||||
|
||||
this.State = global::PeerState.Joined;
|
||||
this.mRoomToGetInto.isLocalClientInside = true;
|
||||
|
||||
Hashtable actorProperties = (Hashtable)operationResponse[ParameterCode.PlayerProperties];
|
||||
Hashtable gameProperties = (Hashtable)operationResponse[ParameterCode.GameProperties];
|
||||
this.readoutStandardProperties(gameProperties, actorProperties, 0);
|
||||
|
||||
// the local player's actor-properties are not returned in join-result. add this player to the list
|
||||
int localActorNr = (int)operationResponse[ParameterCode.ActorNr];
|
||||
|
||||
this.ChangeLocalID(localActorNr);
|
||||
this.CheckMasterClient(-1);
|
||||
|
||||
if (this.mPlayernameHasToBeUpdated)
|
||||
{
|
||||
this.SendPlayerName();
|
||||
}
|
||||
|
||||
switch (operationResponse.OperationCode)
|
||||
{
|
||||
case OperationCode.CreateGame:
|
||||
SendMonoMessage(PhotonNetworkingMessage.OnCreatedRoom);
|
||||
break;
|
||||
case OperationCode.JoinGame:
|
||||
case OperationCode.JoinRandomGame:
|
||||
// the mono message for this is sent at another place
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private Hashtable GetLocalActorProperties()
|
||||
{
|
||||
if (PhotonNetwork.player != null)
|
||||
{
|
||||
return PhotonNetwork.player.allProperties;
|
||||
}
|
||||
|
||||
Hashtable actorProperties = new Hashtable();
|
||||
actorProperties[ActorProperties.PlayerName] = this.PlayerName;
|
||||
return actorProperties;
|
||||
}
|
||||
|
||||
public void ChangeLocalID(int newID)
|
||||
{
|
||||
if (this.mLocalActor == null)
|
||||
{
|
||||
Debug.LogWarning(
|
||||
string.Format(
|
||||
"Local actor is null or not in mActors! mLocalActor: {0} mActors==null: {1} newID: {2}",
|
||||
this.mLocalActor,
|
||||
this.mActors == null,
|
||||
newID));
|
||||
}
|
||||
|
||||
if (this.mActors.ContainsKey(this.mLocalActor.ID))
|
||||
{
|
||||
this.mActors.Remove(this.mLocalActor.ID);
|
||||
}
|
||||
|
||||
this.mLocalActor.InternalChangeLocalID(newID);
|
||||
this.mActors[this.mLocalActor.ID] = this.mLocalActor;
|
||||
this.RebuildPlayerListCopies();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Operations
|
||||
|
||||
public bool OpCreateGame(string gameID, bool isVisible, bool isOpen, byte maxPlayers, bool autoCleanUp, Hashtable customGameProperties, string[] propsListedInLobby)
|
||||
{
|
||||
this.mRoomToGetInto = new Room(gameID, customGameProperties, isVisible, isOpen, maxPlayers, autoCleanUp, propsListedInLobby);
|
||||
return base.OpCreateRoom(gameID, isVisible, isOpen, maxPlayers, autoCleanUp, customGameProperties, this.GetLocalActorProperties(), propsListedInLobby);
|
||||
}
|
||||
|
||||
public bool OpJoin(string gameID)
|
||||
{
|
||||
this.mRoomToGetInto = new Room(gameID, null);
|
||||
return this.OpJoinRoom(gameID, this.GetLocalActorProperties());
|
||||
}
|
||||
|
||||
/// <remarks>the hashtable is (optionally) used to filter games: only those that fit the contained custom properties will be matched</remarks>
|
||||
public override bool OpJoinRandomRoom(Hashtable expectedGameProperties)
|
||||
{
|
||||
this.mRoomToGetInto = new Room(null, expectedGameProperties);
|
||||
return base.OpJoinRandomRoom(expectedGameProperties);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Operation Leave will exit any current room.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This also happens when you disconnect from the server.
|
||||
/// Disconnect might be a step less if you don't want to create a new room on the same server.
|
||||
/// </remarks>
|
||||
/// <returns></returns>
|
||||
public virtual bool OpLeave()
|
||||
{
|
||||
if (this.State != global::PeerState.Joined)
|
||||
{
|
||||
this.DebugReturn(DebugLevel.ERROR, "NetworkingPeer::leaveGame() - ERROR: no game is currently joined");
|
||||
return false;
|
||||
}
|
||||
|
||||
return this.OpCustom((byte)OperationCode.Leave, null, true, 0);
|
||||
}
|
||||
|
||||
public override bool OpRaiseEvent(byte eventCode, Hashtable evData, bool sendReliable, byte channelId, int[] targetActors, EventCaching cache)
|
||||
{
|
||||
if (PhotonNetwork.offlineMode)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return base.OpRaiseEvent(eventCode, evData, sendReliable, channelId, targetActors, cache);
|
||||
}
|
||||
|
||||
public override bool OpRaiseEvent(byte eventCode, Hashtable evData, bool sendReliable, byte channelId, EventCaching cache, ReceiverGroup receivers)
|
||||
{
|
||||
if (PhotonNetwork.offlineMode)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return base.OpRaiseEvent(eventCode, evData, sendReliable, channelId, cache, receivers);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Implementation of IPhotonPeerListener
|
||||
|
||||
public void DebugReturn(DebugLevel level, string message)
|
||||
{
|
||||
this.externalListener.DebugReturn(level, message);
|
||||
}
|
||||
|
||||
public void OnOperationResponse(OperationResponse operationResponse)
|
||||
{
|
||||
if (PhotonNetwork.networkingPeer.State == global::PeerState.Disconnecting)
|
||||
{
|
||||
if (this.DebugOut >= DebugLevel.INFO)
|
||||
{
|
||||
this.DebugReturn(DebugLevel.INFO, "OperationResponse ignored while disconnecting: " + operationResponse.OperationCode);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// extra logging for error debugging (helping developers with a bit of automated analysis)
|
||||
if (operationResponse.ReturnCode == 0)
|
||||
{
|
||||
if (this.DebugOut >= DebugLevel.INFO)
|
||||
{
|
||||
this.DebugReturn(DebugLevel.INFO, operationResponse.ToString());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (this.DebugOut >= DebugLevel.WARNING)
|
||||
{
|
||||
if (operationResponse.ReturnCode == ErrorCode.OperationNotAllowedInCurrentState)
|
||||
{
|
||||
this.DebugReturn(DebugLevel.WARNING, "Operation could not be executed yet. Wait for state JoinedLobby or ConnectedToMaster and their respective callbacks before calling OPs. Client must be authorized.");
|
||||
}
|
||||
|
||||
this.DebugReturn(DebugLevel.WARNING, operationResponse.ToStringFull());
|
||||
}
|
||||
}
|
||||
|
||||
switch (operationResponse.OperationCode)
|
||||
{
|
||||
case OperationCode.Authenticate:
|
||||
{
|
||||
// PeerState oldState = this.State;
|
||||
|
||||
if (operationResponse.ReturnCode != 0)
|
||||
{
|
||||
if (this.DebugOut >= DebugLevel.ERROR)
|
||||
{
|
||||
this.DebugReturn(DebugLevel.ERROR, string.Format("Authentication failed: '{0}' Code: {1}", operationResponse.DebugMessage, operationResponse.ReturnCode));
|
||||
}
|
||||
if (operationResponse.ReturnCode == ErrorCode.InvalidOperationCode)
|
||||
{
|
||||
this.DebugReturn(DebugLevel.ERROR, string.Format("If you host Photon yourself, make sure to start the 'Instance LoadBalancing'"));
|
||||
}
|
||||
if (operationResponse.ReturnCode == ErrorCode.InvalidAuthentication)
|
||||
{
|
||||
this.DebugReturn(DebugLevel.ERROR, string.Format("The appId this client sent is unknown on the server (Cloud). Check settings. If using the Cloud, check account."));
|
||||
}
|
||||
|
||||
this.Disconnect();
|
||||
this.State = global::PeerState.Disconnecting;
|
||||
|
||||
if (operationResponse.ReturnCode == ErrorCode.MaxCcuReached)
|
||||
{
|
||||
this.DebugReturn(DebugLevel.ERROR, string.Format("Currently, the limit of users is reached for this title. Try again later. Disconnecting"));
|
||||
SendMonoMessage(PhotonNetworkingMessage.OnPhotonMaxCccuReached);
|
||||
}
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (this.State == global::PeerState.Connected || this.State == global::PeerState.ConnectedComingFromGameserver)
|
||||
{
|
||||
if (operationResponse.Parameters.ContainsKey(ParameterCode.Position))
|
||||
{
|
||||
this.mQueuePosition = (int)operationResponse[ParameterCode.Position];
|
||||
|
||||
// returnValues for Authenticate always include this value!
|
||||
if (this.mQueuePosition > 0)
|
||||
{
|
||||
// should only happen, if just out of nowhere the
|
||||
// amount of players going online at the same time
|
||||
// is increasing faster, than automatically started
|
||||
// additional gameservers could have been booten up
|
||||
if (this.State == global::PeerState.ConnectedComingFromGameserver)
|
||||
{
|
||||
this.State = global::PeerState.QueuedComingFromGameserver;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.State = global::PeerState.Queued;
|
||||
}
|
||||
|
||||
// we break here (not joining the lobby, etc) as this client is queued
|
||||
// the EventCode.QueueState will eventually resolve this state
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (PhotonNetwork.autoJoinLobby)
|
||||
{
|
||||
this.OpJoinLobby();
|
||||
this.State = global::PeerState.Authenticated;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.State = global::PeerState.ConnectedToMaster;
|
||||
NetworkingPeer.SendMonoMessage(PhotonNetworkingMessage.OnConnectedToMaster);
|
||||
}
|
||||
}
|
||||
else if (this.State == global::PeerState.ConnectedToGameserver)
|
||||
{
|
||||
this.State = global::PeerState.Joining;
|
||||
if (this.mLastJoinType == JoinType.JoinGame || this.mLastJoinType == JoinType.JoinRandomGame)
|
||||
{
|
||||
// if we just "join" the game, do so
|
||||
this.OpJoin(this.mRoomToGetInto.name);
|
||||
}
|
||||
else if (this.mLastJoinType == JoinType.CreateGame)
|
||||
{
|
||||
// on the game server, we have to apply the room properties that were chosen for creation of the room, so we use this.mRoomToGetInto
|
||||
this.OpCreateGame(
|
||||
this.mRoomToGetInto.name,
|
||||
this.mRoomToGetInto.visible,
|
||||
this.mRoomToGetInto.open,
|
||||
(byte)this.mRoomToGetInto.maxPlayers,
|
||||
this.mRoomToGetInto.autoCleanUp,
|
||||
this.mRoomToGetInto.customProperties,
|
||||
this.mRoomToGetInto.propertiesListedInLobby);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case OperationCode.CreateGame:
|
||||
{
|
||||
if (this.State != global::PeerState.Joining)
|
||||
{
|
||||
if (operationResponse.ReturnCode != 0)
|
||||
{
|
||||
if (this.DebugOut >= DebugLevel.ERROR)
|
||||
{
|
||||
this.DebugReturn(DebugLevel.ERROR, string.Format("createGame failed, client stays on masterserver: {0}.", operationResponse.ToStringFull()));
|
||||
}
|
||||
|
||||
SendMonoMessage(PhotonNetworkingMessage.OnPhotonCreateRoomFailed);
|
||||
break;
|
||||
}
|
||||
|
||||
string gameID = (string)operationResponse[ParameterCode.RoomName];
|
||||
if (!string.IsNullOrEmpty(gameID))
|
||||
{
|
||||
// is only sent by the server's response, if it has not been
|
||||
// sent with the client's request before!
|
||||
this.mRoomToGetInto.name = gameID;
|
||||
}
|
||||
|
||||
this.mGameserver = (string)operationResponse[ParameterCode.Address];
|
||||
this.DisconnectFromMaster();
|
||||
this.mLastJoinType = JoinType.CreateGame;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.GameEnteredOnGameServer(operationResponse);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case OperationCode.JoinGame:
|
||||
{
|
||||
if (this.State != global::PeerState.Joining)
|
||||
{
|
||||
if (operationResponse.ReturnCode != 0)
|
||||
{
|
||||
SendMonoMessage(PhotonNetworkingMessage.OnPhotonJoinRoomFailed);
|
||||
|
||||
if (this.DebugOut >= DebugLevel.ERROR)
|
||||
{
|
||||
this.DebugReturn(DebugLevel.ERROR, string.Format("joinGame failed, client stays on masterserver: {0}. State: {1}", operationResponse.ToStringFull(), this.State));
|
||||
}
|
||||
|
||||
// this.mListener.joinGameReturn(0, null, null, returnCode, debugMsg);
|
||||
break;
|
||||
}
|
||||
|
||||
this.mGameserver = (string)operationResponse[ParameterCode.Address];
|
||||
this.DisconnectFromMaster();
|
||||
this.mLastJoinType = JoinType.JoinGame;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.GameEnteredOnGameServer(operationResponse);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case OperationCode.JoinRandomGame:
|
||||
{
|
||||
// happens only on master. on gameserver, this is a regular join (we don't need to find a random game again)
|
||||
// the operation OpJoinRandom either fails (with returncode 8) or returns game-to-join information
|
||||
if (operationResponse.ReturnCode != 0)
|
||||
{
|
||||
SendMonoMessage(PhotonNetworkingMessage.OnPhotonRandomJoinFailed);
|
||||
if (this.DebugOut >= DebugLevel.ERROR)
|
||||
{
|
||||
this.DebugReturn(DebugLevel.ERROR, string.Format("joinrandom failed, client stays on masterserver: {0}.", operationResponse.ToStringFull()));
|
||||
}
|
||||
|
||||
// this.mListener.createGameReturn(0, null, null, returnCode, debugMsg);
|
||||
break;
|
||||
}
|
||||
|
||||
string gameID = (string)operationResponse[ParameterCode.RoomName];
|
||||
|
||||
this.mRoomToGetInto.name = gameID;
|
||||
this.mGameserver = (string)operationResponse[ParameterCode.Address];
|
||||
this.DisconnectFromMaster();
|
||||
this.mLastJoinType = JoinType.JoinRandomGame;
|
||||
break;
|
||||
}
|
||||
|
||||
case OperationCode.JoinLobby:
|
||||
this.State = global::PeerState.JoinedLobby;
|
||||
this.insideLobby = true;
|
||||
SendMonoMessage(PhotonNetworkingMessage.OnJoinedLobby);
|
||||
|
||||
// this.mListener.joinLobbyReturn();
|
||||
break;
|
||||
case OperationCode.LeaveLobby:
|
||||
this.State = global::PeerState.Authenticated;
|
||||
this.LeftLobbyCleanup();
|
||||
break;
|
||||
|
||||
case OperationCode.Leave:
|
||||
this.DisconnectFromGameServer();
|
||||
break;
|
||||
|
||||
case OperationCode.SetProperties:
|
||||
// this.mListener.setPropertiesReturn(returnCode, debugMsg);
|
||||
break;
|
||||
|
||||
case OperationCode.GetProperties:
|
||||
{
|
||||
Hashtable actorProperties = (Hashtable)operationResponse[ParameterCode.PlayerProperties];
|
||||
Hashtable gameProperties = (Hashtable)operationResponse[ParameterCode.GameProperties];
|
||||
this.readoutStandardProperties(gameProperties, actorProperties, 0);
|
||||
|
||||
// RemoveByteTypedPropertyKeys(actorProperties, false);
|
||||
// RemoveByteTypedPropertyKeys(gameProperties, false);
|
||||
// this.mListener.getPropertiesReturn(gameProperties, actorProperties, returnCode, debugMsg);
|
||||
break;
|
||||
}
|
||||
|
||||
case OperationCode.RaiseEvent:
|
||||
// this usually doesn't give us a result. only if the caching is affected the server will send one.
|
||||
break;
|
||||
|
||||
default:
|
||||
if (this.DebugOut >= DebugLevel.ERROR)
|
||||
{
|
||||
this.DebugReturn(DebugLevel.ERROR, string.Format("operationResponse unhandled: {0}", operationResponse.ToString()));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
this.externalListener.OnOperationResponse(operationResponse);
|
||||
}
|
||||
|
||||
public void OnStatusChanged(StatusCode statusCode)
|
||||
{
|
||||
if (this.DebugOut >= DebugLevel.INFO)
|
||||
{
|
||||
this.DebugReturn(DebugLevel.INFO, string.Format("OnStatusChanged: {0}", statusCode.ToString()));
|
||||
}
|
||||
|
||||
switch (statusCode)
|
||||
{
|
||||
case StatusCode.Connect:
|
||||
if (this.State == global::PeerState.ConnectingToGameserver)
|
||||
{
|
||||
if (this.DebugOut >= DebugLevel.ALL)
|
||||
{
|
||||
this.DebugReturn(DebugLevel.ALL, "Connected to gameserver.");
|
||||
}
|
||||
this.State = global::PeerState.ConnectedToGameserver;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (this.DebugOut >= DebugLevel.ALL)
|
||||
{
|
||||
this.DebugReturn(DebugLevel.ALL, "Connected to masterserver.");
|
||||
}
|
||||
if (this.State == global::PeerState.Connecting)
|
||||
{
|
||||
SendMonoMessage(PhotonNetworkingMessage.OnConnectedToPhoton);
|
||||
this.State = global::PeerState.Connected;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.State = global::PeerState.ConnectedComingFromGameserver;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.requestSecurity)
|
||||
{
|
||||
this.EstablishEncryption();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!this.OpAuthenticate(this.mAppId, this.mAppVersion))
|
||||
{
|
||||
this.externalListener.DebugReturn(DebugLevel.ERROR, "Error Authenticating! Did not work.");
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case StatusCode.Disconnect:
|
||||
if (this.State == global::PeerState.DisconnectingFromMasterserver)
|
||||
{
|
||||
if (this.nodeId != 0)
|
||||
{
|
||||
Debug.Log("connecting to game on node " + this.nodeId);
|
||||
}
|
||||
|
||||
this.Connect(this.mGameserver, this.mAppId, this.nodeId);
|
||||
this.State = global::PeerState.ConnectingToGameserver;
|
||||
}
|
||||
else if (this.State == global::PeerState.DisconnectingFromGameserver)
|
||||
{
|
||||
// don't preselect node
|
||||
this.nodeId = 0;
|
||||
this.Connect(this.masterServerAddress, this.mAppId, 0);
|
||||
this.State = global::PeerState.ConnectingToMasterserver;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.LeftRoomCleanup();
|
||||
this.State = global::PeerState.PeerCreated;
|
||||
SendMonoMessage(PhotonNetworkingMessage.OnDisconnectedFromPhoton);
|
||||
}
|
||||
break;
|
||||
|
||||
case StatusCode.ExceptionOnConnect:
|
||||
this.State = global::PeerState.PeerCreated;
|
||||
|
||||
DisconnectCause cause = (DisconnectCause)statusCode;
|
||||
SendMonoMessage(PhotonNetworkingMessage.OnFailedToConnectToPhoton, cause);
|
||||
break;
|
||||
|
||||
case StatusCode.Exception:
|
||||
if (this.State == global::PeerState.Connecting)
|
||||
{
|
||||
this.DebugReturn(DebugLevel.WARNING, "Exception while connecting to: " + this.ServerAddress + ". Check if the server is available.");
|
||||
if (this.ServerAddress == null || this.ServerAddress.StartsWith("127.0.0.1"))
|
||||
{
|
||||
this.DebugReturn(DebugLevel.WARNING, "The server address is 127.0.0.1 (localhost): Make sure the server is running on this machine. Android and iOS emulators have their own localhost.");
|
||||
if (this.ServerAddress == this.mGameserver)
|
||||
{
|
||||
this.DebugReturn(DebugLevel.WARNING, "This might be a misconfiguration in the game server config. You need to edit it to a (public) address.");
|
||||
}
|
||||
}
|
||||
|
||||
this.State = global::PeerState.PeerCreated;
|
||||
cause = (DisconnectCause)statusCode;
|
||||
SendMonoMessage(PhotonNetworkingMessage.OnFailedToConnectToPhoton, cause);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.State = global::PeerState.PeerCreated;
|
||||
|
||||
cause = (DisconnectCause)statusCode;
|
||||
SendMonoMessage(PhotonNetworkingMessage.OnConnectionFail, cause);
|
||||
}
|
||||
|
||||
this.Disconnect();
|
||||
break;
|
||||
|
||||
case StatusCode.TimeoutDisconnect:
|
||||
case StatusCode.InternalReceiveException:
|
||||
case StatusCode.DisconnectByServer:
|
||||
case StatusCode.DisconnectByServerLogic:
|
||||
case StatusCode.DisconnectByServerUserLimit:
|
||||
if (this.State == global::PeerState.Connecting)
|
||||
{
|
||||
this.DebugReturn(DebugLevel.WARNING, statusCode + " while connecting to: " + this.ServerAddress + ". Check if the server is available.");
|
||||
|
||||
this.State = global::PeerState.PeerCreated;
|
||||
cause = (DisconnectCause)statusCode;
|
||||
SendMonoMessage(PhotonNetworkingMessage.OnFailedToConnectToPhoton, cause);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.State = global::PeerState.PeerCreated;
|
||||
|
||||
cause = (DisconnectCause)statusCode;
|
||||
SendMonoMessage(PhotonNetworkingMessage.OnConnectionFail, cause);
|
||||
}
|
||||
|
||||
this.Disconnect();
|
||||
break;
|
||||
|
||||
case StatusCode.SendError:
|
||||
// this.mListener.clientErrorReturn(statusCode);
|
||||
break;
|
||||
|
||||
case StatusCode.QueueOutgoingReliableWarning:
|
||||
case StatusCode.QueueOutgoingUnreliableWarning:
|
||||
case StatusCode.QueueOutgoingAcksWarning:
|
||||
case StatusCode.QueueSentWarning:
|
||||
|
||||
// this.mListener.warningReturn(statusCode);
|
||||
break;
|
||||
|
||||
case StatusCode.EncryptionEstablished:
|
||||
if (!this.OpAuthenticate(this.mAppId, this.mAppVersion))
|
||||
{
|
||||
this.externalListener.DebugReturn(DebugLevel.ERROR, "Error Authenticating! Did not work.");
|
||||
}
|
||||
break;
|
||||
case StatusCode.EncryptionFailedToEstablish:
|
||||
this.externalListener.DebugReturn(DebugLevel.ERROR, "Encryption wasn't established: " + statusCode + ". Going to authenticate anyways.");
|
||||
|
||||
if (!this.OpAuthenticate(this.mAppId, this.mAppVersion))
|
||||
{
|
||||
this.externalListener.DebugReturn(DebugLevel.ERROR, "Error Authenticating! Did not work.");
|
||||
}
|
||||
break;
|
||||
|
||||
// // TCP "routing" is an option of Photon that's not currently needed (or supported) by PUN
|
||||
//case StatusCode.TcpRouterResponseOk:
|
||||
// break;
|
||||
//case StatusCode.TcpRouterResponseEndpointUnknown:
|
||||
//case StatusCode.TcpRouterResponseNodeIdUnknown:
|
||||
//case StatusCode.TcpRouterResponseNodeNotReady:
|
||||
|
||||
// this.DebugReturn(DebugLevel.ERROR, "Unexpected router response: " + statusCode);
|
||||
// break;
|
||||
|
||||
default:
|
||||
|
||||
// this.mListener.serverErrorReturn(statusCode.value());
|
||||
this.DebugReturn(DebugLevel.ERROR, "Received unknown status code: " + statusCode);
|
||||
break;
|
||||
}
|
||||
|
||||
this.externalListener.OnStatusChanged(statusCode);
|
||||
}
|
||||
|
||||
public void OnEvent(EventData photonEvent)
|
||||
{
|
||||
if (this.DebugOut >= DebugLevel.INFO)
|
||||
{
|
||||
this.DebugReturn(DebugLevel.INFO, string.Format("OnEvent: {0}", photonEvent.ToString()));
|
||||
}
|
||||
|
||||
int actorNr = -1;
|
||||
PhotonPlayer originatingPlayer = null;
|
||||
|
||||
if (photonEvent.Parameters.ContainsKey(ParameterCode.ActorNr))
|
||||
{
|
||||
actorNr = (int)photonEvent[ParameterCode.ActorNr];
|
||||
if (this.mActors.ContainsKey(actorNr))
|
||||
{
|
||||
originatingPlayer = (PhotonPlayer)this.mActors[actorNr];
|
||||
}
|
||||
//else
|
||||
//{
|
||||
// // the actor sending this event is not in actorlist. this is usually no problem
|
||||
// if (photonEvent.Code != (byte)LiteOpCode.Join)
|
||||
// {
|
||||
// Debug.LogWarning("Received event, but we do not have this actor: " + actorNr);
|
||||
// }
|
||||
//}
|
||||
}
|
||||
|
||||
switch (photonEvent.Code)
|
||||
{
|
||||
case EventCode.AzureNodeInfo:
|
||||
{
|
||||
byte currentNodeId = (byte)photonEvent[ParameterCode.AzureLocalNodeId];
|
||||
byte masterNodeId = (byte)photonEvent[ParameterCode.AzureMasterNodeId];
|
||||
|
||||
if (currentNodeId != masterNodeId)
|
||||
{
|
||||
this.SwitchNode(masterNodeId);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.nodeId = currentNodeId;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case EventCode.GameList:
|
||||
{
|
||||
this.mGameList = new Dictionary<string, RoomInfo>();
|
||||
Hashtable games = (Hashtable)photonEvent[ParameterCode.GameList];
|
||||
foreach (DictionaryEntry game in games)
|
||||
{
|
||||
string gameName = (string)game.Key;
|
||||
this.mGameList[gameName] = new RoomInfo(gameName, (Hashtable)game.Value);
|
||||
}
|
||||
mGameListCopy = new RoomInfo[mGameList.Count];
|
||||
mGameList.Values.CopyTo(mGameListCopy, 0);
|
||||
SendMonoMessage(PhotonNetworkingMessage.OnReceivedRoomList);
|
||||
break;
|
||||
}
|
||||
|
||||
case EventCode.GameListUpdate:
|
||||
{
|
||||
Hashtable games = (Hashtable)photonEvent[ParameterCode.GameList];
|
||||
foreach (DictionaryEntry room in games)
|
||||
{
|
||||
string gameName = (string)room.Key;
|
||||
Room game = new Room(gameName, (Hashtable)room.Value);
|
||||
if (game.removedFromList)
|
||||
{
|
||||
this.mGameList.Remove(gameName);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.mGameList[gameName] = game;
|
||||
}
|
||||
}
|
||||
this.mGameListCopy = new RoomInfo[this.mGameList.Count];
|
||||
this.mGameList.Values.CopyTo(this.mGameListCopy, 0);
|
||||
SendMonoMessage(PhotonNetworkingMessage.OnReceivedRoomListUpdate);
|
||||
break;
|
||||
}
|
||||
|
||||
case EventCode.QueueState:
|
||||
if (photonEvent.Parameters.ContainsKey(ParameterCode.Position))
|
||||
{
|
||||
this.mQueuePosition = (int)photonEvent[ParameterCode.Position];
|
||||
}
|
||||
else
|
||||
{
|
||||
this.DebugReturn(DebugLevel.ERROR, "Event QueueState must contain position!");
|
||||
}
|
||||
|
||||
if (this.mQueuePosition == 0)
|
||||
{
|
||||
// once we're un-queued, let's join the lobby or simply be "connected to master"
|
||||
if (PhotonNetwork.autoJoinLobby)
|
||||
{
|
||||
this.OpJoinLobby();
|
||||
this.State = global::PeerState.Authenticated;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.State = global::PeerState.ConnectedToMaster;
|
||||
NetworkingPeer.SendMonoMessage(PhotonNetworkingMessage.OnConnectedToMaster);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case EventCode.AppStats:
|
||||
// Debug.LogInfo("Received stats!");
|
||||
this.mPeerCount = (int)photonEvent[ParameterCode.PeerCount];
|
||||
this.mGameCount = (int)photonEvent[ParameterCode.GameCount];
|
||||
this.mMasterCount = (int)photonEvent[ParameterCode.MasterPeerCount];
|
||||
break;
|
||||
|
||||
case EventCode.Join:
|
||||
// actorNr is fetched out of event above
|
||||
Hashtable actorProperties = (Hashtable)photonEvent[ParameterCode.PlayerProperties];
|
||||
if (originatingPlayer == null)
|
||||
{
|
||||
bool isLocal = this.mLocalActor.ID == actorNr;
|
||||
this.AddNewPlayer(actorNr, new PhotonPlayer(isLocal, actorNr, actorProperties));
|
||||
this.ResetPhotonViewsOnSerialize(); // This sets the correct OnSerializeState for Reliable OnSerialize
|
||||
}
|
||||
|
||||
if (this.mActors[actorNr] == this.mLocalActor)
|
||||
{
|
||||
// in this player's 'own' join event, we get a complete list of players in the room, so check if we know all players
|
||||
int[] actorsInRoom = (int[])photonEvent[ParameterCode.ActorList];
|
||||
foreach (int actorNrToCheck in actorsInRoom)
|
||||
{
|
||||
if (this.mLocalActor.ID != actorNrToCheck && !this.mActors.ContainsKey(actorNrToCheck))
|
||||
{
|
||||
Debug.Log("creating player");
|
||||
this.AddNewPlayer(actorNrToCheck, new PhotonPlayer(false, actorNrToCheck, string.Empty));
|
||||
}
|
||||
}
|
||||
|
||||
SendMonoMessage(PhotonNetworkingMessage.OnJoinedRoom);
|
||||
}
|
||||
else
|
||||
{
|
||||
SendMonoMessage(PhotonNetworkingMessage.OnPhotonPlayerConnected, this.mActors[actorNr]);
|
||||
}
|
||||
break;
|
||||
|
||||
case EventCode.Leave:
|
||||
this.HandleEventLeave(actorNr);
|
||||
break;
|
||||
|
||||
case EventCode.PropertiesChanged:
|
||||
int targetActorNr = (int)photonEvent[ParameterCode.TargetActorNr];
|
||||
Hashtable gameProperties = null;
|
||||
Hashtable actorProps = null;
|
||||
if (targetActorNr == 0)
|
||||
{
|
||||
gameProperties = (Hashtable)photonEvent[ParameterCode.Properties];
|
||||
}
|
||||
else
|
||||
{
|
||||
actorProps = (Hashtable)photonEvent[ParameterCode.Properties];
|
||||
}
|
||||
|
||||
this.readoutStandardProperties(gameProperties, actorProps, targetActorNr);
|
||||
break;
|
||||
|
||||
case PhotonNetworkMessages.RPC:
|
||||
//ts: each event now contains a single RPC. execute this
|
||||
this.ExecuteRPC(photonEvent[ParameterCode.Data] as Hashtable, originatingPlayer);
|
||||
break;
|
||||
|
||||
case PhotonNetworkMessages.SendSerialize:
|
||||
case PhotonNetworkMessages.SendSerializeReliable:
|
||||
Hashtable serializeData = (Hashtable)photonEvent[ParameterCode.Data];
|
||||
//Debug.Log(serializeData.ToStringFull());
|
||||
|
||||
int remoteUpdateServerTimestamp = (int)serializeData[(byte)0];
|
||||
short remoteLevelPrefix = -1;
|
||||
short initialDataIndex = 1;
|
||||
if (serializeData.ContainsKey((byte)1))
|
||||
{
|
||||
remoteLevelPrefix = (short)serializeData[(byte)1];
|
||||
initialDataIndex = 2;
|
||||
}
|
||||
|
||||
for (short s = initialDataIndex; s < serializeData.Count; s++)
|
||||
{
|
||||
this.OnSerializeRead(serializeData[s] as Hashtable, originatingPlayer, remoteUpdateServerTimestamp, remoteLevelPrefix);
|
||||
}
|
||||
break;
|
||||
|
||||
case PhotonNetworkMessages.Instantiation:
|
||||
this.DoInstantiate((Hashtable)photonEvent[ParameterCode.Data], originatingPlayer, null);
|
||||
break;
|
||||
|
||||
case PhotonNetworkMessages.CloseConnection:
|
||||
// MasterClient "requests" a disconnection from us
|
||||
if (originatingPlayer == null || !originatingPlayer.isMasterClient)
|
||||
{
|
||||
Debug.LogError("Error: Someone else(" + originatingPlayer + ") then the masterserver requests a disconnect!");
|
||||
}
|
||||
else
|
||||
{
|
||||
PhotonNetwork.LeaveRoom();
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case PhotonNetworkMessages.Destroy:
|
||||
Hashtable data = (Hashtable)photonEvent[ParameterCode.Data];
|
||||
int viewID = (int)data[(byte)0];
|
||||
PhotonView view = this.GetPhotonView(viewID);
|
||||
|
||||
|
||||
if (view == null || originatingPlayer == null)
|
||||
{
|
||||
Debug.LogError("ERROR: Illegal destroy request on view ID=" + viewID + " from player/actorNr: " + actorNr + " view=" + view + " orgPlayer=" + originatingPlayer);
|
||||
}
|
||||
else
|
||||
{
|
||||
// use this check when a master-switch also changes the owner
|
||||
//if (originatingPlayer == view.owner)
|
||||
//{
|
||||
this.DestroyPhotonView(view, true);
|
||||
//}
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
// actorNr might be null. it is fetched out of event on top of method
|
||||
// Hashtable eventContent = (Hashtable) photonEvent[ParameterCode.Data];
|
||||
// this.mListener.customEventAction(actorNr, eventCode, eventContent);
|
||||
Debug.LogError("Error. Unhandled event: " + photonEvent);
|
||||
break;
|
||||
}
|
||||
|
||||
this.externalListener.OnEvent(photonEvent);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public static void SendMonoMessage(PhotonNetworkingMessage methodString, params object[] parameters)
|
||||
{
|
||||
HashSet<GameObject> haveSendGOS = new HashSet<GameObject>();
|
||||
MonoBehaviour[] mos = (MonoBehaviour[])GameObject.FindObjectsOfType(typeof(MonoBehaviour));
|
||||
for (int index = 0; index < mos.Length; index++)
|
||||
{
|
||||
MonoBehaviour mo = mos[index];
|
||||
if (!haveSendGOS.Contains(mo.gameObject))
|
||||
{
|
||||
haveSendGOS.Add(mo.gameObject);
|
||||
if (parameters != null && parameters.Length == 1)
|
||||
{
|
||||
mo.SendMessage(methodString.ToString(), parameters[0], SendMessageOptions.DontRequireReceiver);
|
||||
}
|
||||
else
|
||||
{
|
||||
mo.SendMessage(methodString.ToString(), parameters, SendMessageOptions.DontRequireReceiver);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// PHOTONVIEW/RPC related
|
||||
|
||||
/// <summary>
|
||||
/// Executes a received RPC event
|
||||
/// </summary>
|
||||
public void ExecuteRPC(Hashtable rpcData, PhotonPlayer sender)
|
||||
{
|
||||
if (rpcData == null || !rpcData.ContainsKey((byte)0))
|
||||
{
|
||||
this.DebugReturn(DebugLevel.ERROR, "Malformed RPC; this should never occur.");
|
||||
return;
|
||||
}
|
||||
|
||||
// ts: updated with "flat" event data
|
||||
int netViewID = (int)rpcData[(byte)0]; // LIMITS PHOTONVIEWS&PLAYERS
|
||||
int otherSidePrefix = -1;
|
||||
if (rpcData.ContainsKey((byte)1))
|
||||
{
|
||||
otherSidePrefix = (int)rpcData[(byte)1];
|
||||
}
|
||||
string inMethodName = (string)rpcData[(byte)3];
|
||||
object[] inMethodParameters = (object[])rpcData[(byte)4];
|
||||
|
||||
if (inMethodParameters == null)
|
||||
{
|
||||
inMethodParameters = new object[0];
|
||||
}
|
||||
|
||||
PhotonView photonNetview = this.GetPhotonView(netViewID);
|
||||
if (photonNetview == null)
|
||||
{
|
||||
Debug.LogError("Received RPC \"" + inMethodName + "\" for viewID " + netViewID + " but this PhotonView does not exist!");
|
||||
return;
|
||||
}
|
||||
|
||||
if (photonNetview.prefix != otherSidePrefix)
|
||||
{
|
||||
Debug.LogError(
|
||||
"Received RPC \"" + inMethodName + "\" on viewID " + netViewID + " with a prefix of " + otherSidePrefix
|
||||
+ ", our prefix is " + photonNetview.prefix + ". The RPC has been ignored.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Get method name
|
||||
if (inMethodName == string.Empty)
|
||||
{
|
||||
this.DebugReturn(DebugLevel.ERROR, "Malformed RPC; this should never occur.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.DebugOut >= DebugLevel.ALL)
|
||||
{
|
||||
this.DebugReturn(DebugLevel.ALL, "Received RPC; " + inMethodName);
|
||||
}
|
||||
|
||||
// SetReceiving filtering
|
||||
if (this.blockReceivingGroups.Contains(photonNetview.group))
|
||||
{
|
||||
return; // Ignore group
|
||||
}
|
||||
|
||||
Type[] argTypes = Type.EmptyTypes;
|
||||
if (inMethodParameters.Length > 0)
|
||||
{
|
||||
argTypes = new Type[inMethodParameters.Length];
|
||||
int i = 0;
|
||||
for (int index = 0; index < inMethodParameters.Length; index++)
|
||||
{
|
||||
object objX = inMethodParameters[index];
|
||||
if (objX == null)
|
||||
{
|
||||
argTypes[i] = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
argTypes[i] = objX.GetType();
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
int receivers = 0;
|
||||
int foundMethods = 0;
|
||||
MonoBehaviour[] mbComponents = photonNetview.GetComponents<MonoBehaviour>();
|
||||
for (int componentsIndex = 0; componentsIndex < mbComponents.Length; componentsIndex++)
|
||||
{
|
||||
MonoBehaviour monob = mbComponents[componentsIndex];
|
||||
Type type = monob.GetType();
|
||||
|
||||
// Get [RPC] methods from cache
|
||||
List<MethodInfo> cachedRPCMethods = null;
|
||||
if (this.monoRPCMethodsCache.ContainsKey(type))
|
||||
{
|
||||
cachedRPCMethods = this.monoRPCMethodsCache[type];
|
||||
}
|
||||
|
||||
if (cachedRPCMethods == null)
|
||||
{
|
||||
List<MethodInfo> entries = new List<MethodInfo>();
|
||||
MethodInfo[] myMethods = type.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
|
||||
for (int i = 0; i < myMethods.Length; i++)
|
||||
{
|
||||
if (myMethods[i].IsDefined(typeof(UnityEngine.RPC), false))
|
||||
{
|
||||
entries.Add(myMethods[i]);
|
||||
}
|
||||
}
|
||||
|
||||
cachedRPCMethods = this.monoRPCMethodsCache[type] = entries;
|
||||
}
|
||||
|
||||
if (cachedRPCMethods == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check cache for valid methodname+arguments
|
||||
for (int index = 0; index < cachedRPCMethods.Count; index++)
|
||||
{
|
||||
MethodInfo mInfo = cachedRPCMethods[index];
|
||||
if (mInfo.Name == inMethodName)
|
||||
{
|
||||
foundMethods++;
|
||||
ParameterInfo[] pArray = mInfo.GetParameters();
|
||||
if (pArray.Length == argTypes.Length)
|
||||
{
|
||||
// Normal, PhotonNetworkMessage left out
|
||||
if (this.CheckTypeMatch(pArray, argTypes))
|
||||
{
|
||||
receivers++;
|
||||
object result = mInfo.Invoke((object)monob, inMethodParameters);
|
||||
if (mInfo.ReturnType == typeof(System.Collections.IEnumerator))
|
||||
{
|
||||
PhotonHandler.SP.StartCoroutine((IEnumerator)result);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ((pArray.Length - 1) == argTypes.Length)
|
||||
{
|
||||
// Check for PhotonNetworkMessage being the last
|
||||
if (this.CheckTypeMatch(pArray, argTypes))
|
||||
{
|
||||
if (pArray[pArray.Length - 1].ParameterType == typeof(PhotonMessageInfo))
|
||||
{
|
||||
receivers++;
|
||||
|
||||
int sendTime = (int)rpcData[(byte)2];
|
||||
object[] deParamsWithInfo = new object[inMethodParameters.Length + 1];
|
||||
inMethodParameters.CopyTo(deParamsWithInfo, 0);
|
||||
deParamsWithInfo[deParamsWithInfo.Length - 1] = new PhotonMessageInfo(sender, sendTime, photonNetview);
|
||||
|
||||
object result = mInfo.Invoke((object)monob, deParamsWithInfo);
|
||||
if (mInfo.ReturnType == typeof(System.Collections.IEnumerator))
|
||||
{
|
||||
PhotonHandler.SP.StartCoroutine((IEnumerator)result);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (pArray.Length == 1 && pArray[0].ParameterType.IsArray)
|
||||
{
|
||||
receivers++;
|
||||
object result = mInfo.Invoke((object)monob, new object[] {inMethodParameters});
|
||||
if (mInfo.ReturnType == typeof(System.Collections.IEnumerator))
|
||||
{
|
||||
PhotonHandler.SP.StartCoroutine((IEnumerator)result);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Error handling
|
||||
if (receivers != 1)
|
||||
{
|
||||
string argsString = string.Empty;
|
||||
for (int index = 0; index < argTypes.Length; index++)
|
||||
{
|
||||
Type ty = argTypes[index];
|
||||
if (argsString != string.Empty)
|
||||
{
|
||||
argsString += ", ";
|
||||
}
|
||||
|
||||
if (ty == null)
|
||||
{
|
||||
argsString += "null";
|
||||
}
|
||||
else
|
||||
{
|
||||
argsString += ty.Name;
|
||||
}
|
||||
}
|
||||
|
||||
if (receivers == 0)
|
||||
{
|
||||
if (foundMethods == 0)
|
||||
{
|
||||
this.DebugReturn(
|
||||
DebugLevel.ERROR,
|
||||
"PhotonView with ID " + netViewID + " has no method \"" + inMethodName
|
||||
+ "\" marked with the [RPC](C#) or @RPC(JS) property!");
|
||||
}
|
||||
else
|
||||
{
|
||||
this.DebugReturn(
|
||||
DebugLevel.ERROR,
|
||||
"PhotonView with ID " + netViewID + " has no method \"" + inMethodName + "\" that takes "
|
||||
+ argTypes.Length + " argument(s): " + argsString);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
this.DebugReturn(
|
||||
DebugLevel.ERROR,
|
||||
"PhotonView with ID " + netViewID + " has " + receivers + " methods \"" + inMethodName
|
||||
+ "\" that takes " + argTypes.Length + " argument(s): " + argsString + ". Should be just one?");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if all types match with parameters. We can have more paramters then types (allow last RPC type to be different).
|
||||
/// </summary>
|
||||
/// <param name="parameters"></param>
|
||||
/// <param name="types"></param>
|
||||
/// <returns>If the types-array has matching parameters (of method) in the parameters array (which may be longer).</returns>
|
||||
private bool CheckTypeMatch(ParameterInfo[] parameters, Type[] types)
|
||||
{
|
||||
if (parameters.Length < types.Length)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
int i = 0;
|
||||
for (int index = 0; index < types.Length; index++)
|
||||
{
|
||||
Type type = types[index];
|
||||
if (type != null && parameters[i].ParameterType != type)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int AllocateInstantiationId()
|
||||
{
|
||||
int id = ++this.cacheInstantiationCount;
|
||||
id += this.mLocalActor.ID << 16;
|
||||
|
||||
if (this.cacheInstantiationCount == ushort.MaxValue)
|
||||
{
|
||||
Debug.LogError("Next Instantiation will create a overflow.");
|
||||
}
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
internal Hashtable SendInstantiate(string prefabName, Vector3 position, Quaternion rotation, int group, PhotonViewID[] viewIDs, object[] data, bool isGlobalObject)
|
||||
{
|
||||
int instantiateId = this.AllocateInstantiationId();
|
||||
|
||||
Hashtable instantiateEvent = new Hashtable(); // This players info is sent via ActorID
|
||||
instantiateEvent[(byte)0] = prefabName;
|
||||
|
||||
if (position != Vector3.zero)
|
||||
{
|
||||
instantiateEvent[(byte)1] = position;
|
||||
}
|
||||
|
||||
instantiateEvent[(byte)2] = rotation;
|
||||
|
||||
if (group != 0)
|
||||
{
|
||||
instantiateEvent[(byte)3] = group;
|
||||
}
|
||||
|
||||
if (viewIDs != null && viewIDs.Length > 0)
|
||||
{
|
||||
instantiateEvent[(byte)4] = viewIDs; // LIMITS PHOTONVIEWS&PLAYERS
|
||||
}
|
||||
|
||||
if (data != null)
|
||||
{
|
||||
instantiateEvent[(byte)5] = data;
|
||||
}
|
||||
|
||||
instantiateEvent[(byte)6] = this.ServerTimeInMilliSeconds;
|
||||
instantiateEvent[(byte)7] = instantiateId;
|
||||
|
||||
EventCaching cacheMode = EventCaching.AddToRoomCache;
|
||||
if (isGlobalObject) cacheMode = EventCaching.AddToRoomCacheGlobal;
|
||||
|
||||
this.OpRaiseEvent(PhotonNetworkMessages.Instantiation, instantiateEvent, true, 0, cacheMode, ReceiverGroup.Others);
|
||||
return instantiateEvent;
|
||||
}
|
||||
|
||||
internal GameObject DoInstantiate(Hashtable evData, PhotonPlayer photonPlayer, GameObject resourceGameObject)
|
||||
{
|
||||
string prefabName = (string)evData[(byte)0];
|
||||
|
||||
Vector3 position;
|
||||
if (evData.ContainsKey((byte)1))
|
||||
{
|
||||
position = (Vector3)evData[(byte)1];
|
||||
}
|
||||
else
|
||||
{
|
||||
position = Vector3.zero;
|
||||
}
|
||||
|
||||
Quaternion rotation = (Quaternion)evData[(byte)2];
|
||||
|
||||
int group = 0;
|
||||
if (evData.ContainsKey((byte)3))
|
||||
{
|
||||
group = (int)evData[(byte)3];
|
||||
}
|
||||
|
||||
PhotonViewID[] viewsIDs;
|
||||
if (evData.ContainsKey((byte)4))
|
||||
{
|
||||
viewsIDs = (PhotonViewID[])evData[(byte)4];
|
||||
}
|
||||
else
|
||||
{
|
||||
viewsIDs = new PhotonViewID[0];
|
||||
}
|
||||
|
||||
object[] data;
|
||||
if (evData.ContainsKey((byte)5))
|
||||
{
|
||||
data = (object[])evData[(byte)5];
|
||||
}
|
||||
else
|
||||
{
|
||||
data = new object[0];
|
||||
}
|
||||
|
||||
int serverTime = (int)evData[(byte)6];
|
||||
int instantiationId = (int)evData[(byte)7];
|
||||
|
||||
// SetReceiving filtering
|
||||
if (this.blockReceivingGroups.Contains(group))
|
||||
{
|
||||
return null; // Ignore group
|
||||
}
|
||||
|
||||
// Check prefab
|
||||
if (resourceGameObject == null)
|
||||
{
|
||||
resourceGameObject = (GameObject)Resources.Load(prefabName, typeof(GameObject));
|
||||
if (resourceGameObject == null)
|
||||
{
|
||||
Debug.LogError("PhotonNetwork error: Could not Instantiate the prefab [" + prefabName + "]. Please verify you have this gameobject in a Resources folder.");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
//Add this PhotonView setup info to a list, so that the PhotonView can use this to setup if it's accessed DURING the Instantiation call (in awake)
|
||||
InstantiatedPhotonViewSetup newPVS = new InstantiatedPhotonViewSetup();
|
||||
newPVS.viewIDs = viewsIDs;
|
||||
newPVS.group = group;
|
||||
newPVS.instantiationData = data;
|
||||
instantiatedPhotonViewSetupList.Add(newPVS);
|
||||
|
||||
// Instantiate the object
|
||||
GameObject go = (GameObject)GameObject.Instantiate(resourceGameObject, position, rotation);
|
||||
this.instantiatedObjects.Add(instantiationId, go);
|
||||
|
||||
SetupInstantiatedGO(go, newPVS);
|
||||
|
||||
|
||||
// Send mono event
|
||||
object[] messageInfoParam = new object[1];
|
||||
messageInfoParam[0] = new PhotonMessageInfo(photonPlayer, serverTime, null);
|
||||
|
||||
MonoBehaviour[] monos = go.GetComponentsInChildren<MonoBehaviour>();
|
||||
for (int index = 0; index < monos.Length; index++)
|
||||
{
|
||||
MonoBehaviour mono = monos[index];
|
||||
MethodInfo methodI = this.GetCachedMethod(mono, PhotonNetworkingMessage.OnPhotonInstantiate);
|
||||
if (methodI != null)
|
||||
{
|
||||
object result = methodI.Invoke((object)mono, messageInfoParam);
|
||||
if (methodI.ReturnType == typeof(System.Collections.IEnumerator))
|
||||
{
|
||||
PhotonHandler.SP.StartCoroutine((IEnumerator)result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return go;
|
||||
}
|
||||
|
||||
#region WorkAround_For_PhotonView_Awake
|
||||
|
||||
private List<InstantiatedPhotonViewSetup> instantiatedPhotonViewSetupList = new List<InstantiatedPhotonViewSetup>();
|
||||
|
||||
class InstantiatedPhotonViewSetup
|
||||
{
|
||||
public PhotonViewID[] viewIDs;
|
||||
public int group;
|
||||
public object[] instantiationData;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// When a PhotonView has not yet setup and we are accessing it via AWAKE, we need to find a matching InstantiatedPhotonViewSetup.
|
||||
/// The InstantiatedPhotonViewSetup list should normally only contain 1 item, and we check for the matching root GO by PhotonView count
|
||||
/// </summary>
|
||||
public bool PhotonViewSetup_FindMatchingRoot(GameObject start)
|
||||
{
|
||||
Transform parent = start.transform.parent;
|
||||
for (int index = 0; index < this.instantiatedPhotonViewSetupList.Count; index++)
|
||||
{
|
||||
InstantiatedPhotonViewSetup setupInfo = this.instantiatedPhotonViewSetupList[index];
|
||||
int childCount = start.GetComponentsInChildren<PhotonView>().Length;
|
||||
if (childCount == setupInfo.viewIDs.Length)
|
||||
{
|
||||
this.SetupInstantiatedGO(start, setupInfo);
|
||||
return true;
|
||||
}
|
||||
else if (parent != null)
|
||||
{
|
||||
if (this.PhotonViewSetup_FindMatchingRoot(parent.gameObject))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//TODO: can we get rid of this?!
|
||||
void SetupInstantiatedGO(GameObject goRoot, InstantiatedPhotonViewSetup setupInfo)
|
||||
{
|
||||
if (!this.instantiatedPhotonViewSetupList.Contains(setupInfo))
|
||||
{
|
||||
// Setup has already been run for this setupInfo (via a Awake access on the PhotonView)
|
||||
return;
|
||||
}
|
||||
|
||||
// Assign view IDs
|
||||
PhotonView[] views = (PhotonView[])goRoot.GetComponentsInChildren<PhotonView>();
|
||||
for (int index = 0; index < views.Length; index++)
|
||||
{
|
||||
PhotonView view = views[index];
|
||||
view.viewID = setupInfo.viewIDs[index];
|
||||
view.group = setupInfo.group;
|
||||
view.instantiationData = setupInfo.instantiationData;
|
||||
}
|
||||
|
||||
instantiatedPhotonViewSetupList.Remove(setupInfo);
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
// Removes PhotonNetwork.Instantiate-ed objects
|
||||
// Does not remove any manually assigned PhotonViews.
|
||||
public void RemoveAllInstantiatedObjects()
|
||||
{
|
||||
GameObject[] instantiatedGoArray = new GameObject[this.instantiatedObjects.Count];
|
||||
this.instantiatedObjects.Values.CopyTo(instantiatedGoArray, 0);
|
||||
|
||||
for (int index = 0; index < instantiatedGoArray.Length; index++)
|
||||
{
|
||||
GameObject go = instantiatedGoArray[index];
|
||||
if (go == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
this.RemoveInstantiatedGO(go, false);
|
||||
}
|
||||
|
||||
if (this.instantiatedObjects.Count > 0)
|
||||
{
|
||||
Debug.LogError("RemoveAllInstantiatedObjects() this.instantiatedObjects.Count should be 0 by now.");
|
||||
}
|
||||
|
||||
this.cacheInstantiationCount = 0; // starts with 0.
|
||||
this.instantiatedObjects = new Dictionary<int, GameObject>();
|
||||
}
|
||||
|
||||
public void RemoveAllInstantiatedObjectsByPlayer(PhotonPlayer player, bool localOnly)
|
||||
{
|
||||
GameObject[] instantiatedGoArray = new GameObject[this.instantiatedObjects.Count];
|
||||
this.instantiatedObjects.Values.CopyTo(instantiatedGoArray, 0);
|
||||
|
||||
for (int index = 0; index < instantiatedGoArray.Length; index++)
|
||||
{
|
||||
GameObject go = instantiatedGoArray[index];
|
||||
if (go == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// all PUN created GameObjects must have a PhotonView, so we could get the owner of it
|
||||
PhotonView[] views = go.GetComponentsInChildren<PhotonView>();
|
||||
for (int j = views.Length - 1; j >= 0; j--)
|
||||
{
|
||||
PhotonView view = views[j];
|
||||
if (view.owner == player)
|
||||
{
|
||||
this.RemoveInstantiatedGO(go, localOnly);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void RemoveInstantiatedGO(GameObject go, bool localOnly)
|
||||
{
|
||||
if (go == null)
|
||||
{
|
||||
if (DebugOut == DebugLevel.ERROR)
|
||||
{
|
||||
this.DebugReturn(DebugLevel.ERROR, "Can't remove instantiated GO if it's null.");
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
int instantiateId = this.GetInstantiatedObjectsId(go);
|
||||
if (instantiateId == -1)
|
||||
{
|
||||
if (DebugOut == DebugLevel.ERROR)
|
||||
{
|
||||
this.DebugReturn(DebugLevel.ERROR, "Can't find GO in instantiation list. Object: " + go);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
this.instantiatedObjects.Remove(instantiateId);
|
||||
|
||||
PhotonView[] views = go.GetComponentsInChildren<PhotonView>();
|
||||
bool removedFromServer = false;
|
||||
for (int j = views.Length - 1; j >= 0; j--)
|
||||
{
|
||||
PhotonView view = views[j];
|
||||
if (view == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!removedFromServer)
|
||||
{
|
||||
// first view's owner should be the same as any further view's owner. use it to clean cache
|
||||
int removeForActorID = 0;
|
||||
if(view.owner != null)
|
||||
{
|
||||
removeForActorID = view.owner.ID;
|
||||
}
|
||||
this.RemoveFromServerInstantiationCache(instantiateId, removeForActorID);
|
||||
removedFromServer = true;
|
||||
}
|
||||
|
||||
if (view.owner == mLocalActor)
|
||||
{
|
||||
PhotonNetwork.UnAllocateViewID(view.viewID);
|
||||
}
|
||||
this.DestroyPhotonView(view, localOnly);
|
||||
}
|
||||
|
||||
if (this.DebugOut >= DebugLevel.ALL)
|
||||
{
|
||||
this.DebugReturn(DebugLevel.ALL, "Network destroy Instantiated GO: " + go.name);
|
||||
}
|
||||
|
||||
this.DestroyGO(go);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This returns -1 if the GO could not be found in list of instantiatedObjects.
|
||||
/// </summary>
|
||||
public int GetInstantiatedObjectsId(GameObject go)
|
||||
{
|
||||
int id = -1;
|
||||
if (go == null)
|
||||
{
|
||||
this.DebugReturn(DebugLevel.ERROR, "GetInstantiatedObjectsId() for GO == null.");
|
||||
return id;
|
||||
}
|
||||
|
||||
foreach (KeyValuePair<int, GameObject> pair in this.instantiatedObjects)
|
||||
{
|
||||
if (go == pair.Value)
|
||||
{
|
||||
id = pair.Key;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (id == -1)
|
||||
{
|
||||
if (DebugOut == DebugLevel.ALL)
|
||||
{
|
||||
this.DebugReturn(DebugLevel.ALL, "instantiatedObjects does not contain: " + go);
|
||||
}
|
||||
}
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes an instantiation event from the server's cache. Needs id and actorNr of player who instantiated.
|
||||
/// </summary>
|
||||
private void RemoveFromServerInstantiationCache(int instantiateId, int actorNr)
|
||||
{
|
||||
Hashtable removeFilter = new Hashtable();
|
||||
removeFilter[(byte)7] = instantiateId;
|
||||
this.OpRaiseEvent(PhotonNetworkMessages.Instantiation, removeFilter, true, 0, new int[] { actorNr }, EventCaching.RemoveFromRoomCache);
|
||||
}
|
||||
|
||||
private void RemoveFromServerInstantiationsOfPlayer(int actorNr)
|
||||
{
|
||||
// removes all "Instantiation" events of player actorNr. this is not an event for anyone else
|
||||
this.OpRaiseEvent(PhotonNetworkMessages.Instantiation, null, true, 0, new int[] { actorNr }, EventCaching.RemoveFromRoomCache);
|
||||
}
|
||||
|
||||
// Destroys all gameobjects from a player with a PhotonView that they own
|
||||
// FIRST: Instantiated objects are deleted.
|
||||
// SECOND: Destroy entire gameobject+children of PhotonViews that they are owner of.
|
||||
// This can mess up if theres no PhotonView on root of the objects!
|
||||
public void DestroyPlayerObjects(PhotonPlayer player, bool localOnly)
|
||||
{
|
||||
this.RemoveAllInstantiatedObjectsByPlayer(player, localOnly); // Instantiated objects
|
||||
|
||||
// Manually spawned ones:
|
||||
PhotonView[] views = (PhotonView[])GameObject.FindObjectsOfType(typeof(PhotonView));
|
||||
for (int i = views.Length - 1; i >= 0; i--)
|
||||
{
|
||||
PhotonView view = views[i];
|
||||
if (view.owner == player)
|
||||
{
|
||||
this.DestroyPhotonView(view, localOnly);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void DestroyPhotonView(PhotonView view, bool localOnly)
|
||||
{
|
||||
if (!localOnly && (view.isMine || mMasterClient == mLocalActor))
|
||||
{
|
||||
// sends the "destroy view" message so others will destroy the view, too. this is not cached
|
||||
Hashtable evData = new Hashtable();
|
||||
evData[(byte)0] = view.viewID.ID;
|
||||
this.OpRaiseEvent(PhotonNetworkMessages.Destroy, evData, true, 0, EventCaching.DoNotCache, ReceiverGroup.Others);
|
||||
}
|
||||
|
||||
if (view.isMine || mMasterClient == mLocalActor)
|
||||
{
|
||||
// Only remove cached RPCs if they are ours
|
||||
this.RemoveRPCs(view);
|
||||
if (view.owner == mLocalActor) PhotonNetwork.UnAllocateViewID(view.viewID);
|
||||
}
|
||||
|
||||
int id = this.GetInstantiatedObjectsId(view.gameObject);
|
||||
if (id != -1)
|
||||
{
|
||||
// Debug.Log("Found view in instantiatedObjects.");
|
||||
this.instantiatedObjects.Remove(id);
|
||||
}
|
||||
|
||||
if (this.DebugOut >= DebugLevel.ALL)
|
||||
{
|
||||
this.DebugReturn(DebugLevel.ALL, "Network destroy PhotonView GO: " + view.gameObject.name);
|
||||
}
|
||||
|
||||
this.DestroyGO(view.gameObject); // OnDestroy calls RemovePhotonView(view);
|
||||
}
|
||||
|
||||
public PhotonView GetPhotonView(int viewID)
|
||||
{
|
||||
PhotonView result = null;
|
||||
this.photonViewList.TryGetValue(viewID, out result);
|
||||
return result;
|
||||
}
|
||||
|
||||
public void RegisterPhotonView(PhotonView netView)
|
||||
{
|
||||
if (!Application.isPlaying)
|
||||
{
|
||||
this.photonViewList = new Dictionary<int, PhotonView>();
|
||||
return;
|
||||
}
|
||||
|
||||
netView.prefix = this.currentLevelPrefix;
|
||||
if (netView.owner != null)
|
||||
{
|
||||
// Error checking
|
||||
int correctOwnerID = netView.viewID.ID / PhotonNetwork.MAX_VIEW_IDS;
|
||||
if (netView.owner.ID != correctOwnerID)
|
||||
{
|
||||
Debug.LogError(
|
||||
"RegisterPhotonView: registered view ID " + netView.viewID + " with owner " + netView.owner.ID
|
||||
+ " but it should be " + correctOwnerID);
|
||||
}
|
||||
}
|
||||
|
||||
if (!this.photonViewList.ContainsKey(netView.viewID.ID))
|
||||
{
|
||||
this.photonViewList.Add(netView.viewID.ID, netView);
|
||||
if (this.DebugOut >= DebugLevel.ALL)
|
||||
{
|
||||
this.DebugReturn(DebugLevel.ALL, "Registered PhotonView: " + netView.viewID);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unregister a photonview. Using the mayFail argument we indicate whether the photonview should be present
|
||||
/// </summary>
|
||||
/// <param name="netView">The PhotonView to remove.</param>
|
||||
/// <param name="mayFail">Indicates whether the photonview should be present (or may be deleted earlier).</param>
|
||||
public void RemovePhotonView(PhotonView netView, bool mayFail)
|
||||
{
|
||||
if (!Application.isPlaying)
|
||||
{
|
||||
this.photonViewList = new Dictionary<int, PhotonView>();
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.photonViewList.ContainsKey(netView.viewID.ID))
|
||||
{
|
||||
if (this.photonViewList[netView.viewID.ID] != netView)
|
||||
{
|
||||
// Only remove it if this ID belongs to the PhotonView we're removing
|
||||
if (!mayFail)
|
||||
{
|
||||
Debug.LogError(
|
||||
"PHOTON ERROR: This should never be possible: Two PhotonViews with same ID registered? ID="
|
||||
+ netView.viewID.ID + " " + netView.name + " and " + this.photonViewList[netView.viewID.ID].name);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
this.photonViewList.Remove(netView.viewID.ID);
|
||||
if (this.DebugOut >= DebugLevel.ALL)
|
||||
{
|
||||
this.DebugReturn(DebugLevel.ALL, "Removed PhotonView: " + netView.viewID);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes the RPCs of someone else (to be used as master).
|
||||
/// This won't clean any local caches. It just tells the server to forget a player's RPCs and instantiates.
|
||||
/// </summary>
|
||||
/// <param name="actorNumber"></param>
|
||||
public void RemoveRPCs(int actorNumber)
|
||||
{
|
||||
this.OpRaiseEvent(PhotonNetworkMessages.RPC, null, true, 0, new int[] { actorNumber }, EventCaching.RemoveFromRoomCache);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Instead removint RPCs or Instantiates, this removed everything cached by the actor.
|
||||
/// </summary>
|
||||
/// <param name="actorNumber"></param>
|
||||
public void RemoveCompleteCacheOfPlayer(int actorNumber)
|
||||
{
|
||||
this.OpRaiseEvent(0, null, true, 0, new int[] { actorNumber }, EventCaching.RemoveFromRoomCache);
|
||||
}
|
||||
|
||||
/// This clears the cache of any player/actor who's no longer in the room (making it a simple clean-up option for a new master)
|
||||
private void RemoveCacheOfLeftPlayers()
|
||||
{
|
||||
Dictionary<byte, object> opParameters = new Dictionary<byte, object>();
|
||||
opParameters[ParameterCode.Code] = (byte)0; // any event
|
||||
opParameters[ParameterCode.Cache] = (byte)EventCaching.RemoveFromRoomCacheForActorsLeft; // option to clear the room cache of all events of players who left
|
||||
|
||||
this.OpCustom((byte)OperationCode.RaiseEvent, opParameters, true, 0);
|
||||
}
|
||||
|
||||
// Remove RPCs of view (if they are local player's RPCs)
|
||||
public void RemoveRPCs(PhotonView view)
|
||||
{
|
||||
if (!mLocalActor.isMasterClient && view.owner != this.mLocalActor)
|
||||
{
|
||||
Debug.LogError("Error, cannot remove cached RPCs on a PhotonView thats not ours! " + view.owner + " scene: " + view.isSceneView);
|
||||
return;
|
||||
}
|
||||
|
||||
Hashtable rpcFilterByViewId = new Hashtable();
|
||||
rpcFilterByViewId[(byte)0] = view.viewID.ID;
|
||||
this.OpRaiseEvent(PhotonNetworkMessages.RPC, rpcFilterByViewId, true, 0, EventCaching.RemoveFromRoomCache, ReceiverGroup.Others);
|
||||
}
|
||||
|
||||
public void RemoveRPCsInGroup(int group)
|
||||
{
|
||||
foreach (KeyValuePair<int, PhotonView> kvp in this.photonViewList)
|
||||
{
|
||||
PhotonView view = kvp.Value;
|
||||
if (view.group == group)
|
||||
{
|
||||
this.RemoveRPCs(view);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void SetLevelPrefix(short prefix)
|
||||
{
|
||||
this.currentLevelPrefix = prefix;
|
||||
foreach (PhotonView view in this.photonViewList.Values)
|
||||
{
|
||||
view.prefix = prefix;
|
||||
}
|
||||
}
|
||||
|
||||
public void RPC(PhotonView view, string methodName, PhotonPlayer player, params object[] parameters)
|
||||
{
|
||||
if (this.blockSendingGroups.Contains(view.group))
|
||||
{
|
||||
return; // Block sending on this group
|
||||
}
|
||||
|
||||
if (view.viewID.ID < 1)
|
||||
{
|
||||
Debug.LogError("Illegal view ID:" + view.viewID + " method: " + methodName + " GO:" + view.gameObject.name);
|
||||
}
|
||||
|
||||
if (this.DebugOut >= DebugLevel.INFO)
|
||||
{
|
||||
this.DebugReturn(DebugLevel.INFO, "Sending RPC \"" + methodName + "\" to player[" + player + "]");
|
||||
}
|
||||
|
||||
//ts: changed RPCs to a one-level hashtable as described in internal.txt
|
||||
Hashtable rpcEvent = new Hashtable();
|
||||
rpcEvent[(byte)0] = (int)view.viewID.ID; // LIMITS PHOTONVIEWS&PLAYERS
|
||||
if (view.prefix > 0)
|
||||
{
|
||||
rpcEvent[(byte)1] = view.prefix;
|
||||
}
|
||||
rpcEvent[(byte)2] = this.ServerTimeInMilliSeconds;
|
||||
rpcEvent[(byte)3] = methodName;
|
||||
rpcEvent[(byte)4] = (object[])parameters;
|
||||
|
||||
if (this.mLocalActor == player)
|
||||
{
|
||||
this.ExecuteRPC(rpcEvent, player);
|
||||
}
|
||||
else
|
||||
{
|
||||
int[] targetActors = new int[] { player.ID };
|
||||
this.OpRaiseEvent(PhotonNetworkMessages.RPC, rpcEvent, true, 0, targetActors);
|
||||
}
|
||||
}
|
||||
|
||||
public void RPC(PhotonView view, string methodName, PhotonTargets target, params object[] parameters)
|
||||
{
|
||||
if (this.blockSendingGroups.Contains(view.group))
|
||||
{
|
||||
return; // Block sending on this group
|
||||
}
|
||||
|
||||
if (view.viewID.ID < 1)
|
||||
{
|
||||
Debug.LogError("Illegal view ID:" + view.viewID + " method: " + methodName + " GO:" + view.gameObject.name);
|
||||
}
|
||||
|
||||
if (this.DebugOut >= DebugLevel.INFO)
|
||||
{
|
||||
this.DebugReturn(DebugLevel.INFO, "Sending RPC \"" + methodName + "\" to " + target);
|
||||
}
|
||||
|
||||
//ts: changed RPCs to a one-level hashtable as described in internal.txt
|
||||
Hashtable rpcEvent = new Hashtable();
|
||||
rpcEvent[(byte)0] = (int)view.viewID.ID; // LIMITS NETWORKVIEWS&PLAYERS
|
||||
if (view.prefix > 0)
|
||||
{
|
||||
rpcEvent[(byte)1] = view.prefix;
|
||||
}
|
||||
rpcEvent[(byte)2] = this.ServerTimeInMilliSeconds;
|
||||
rpcEvent[(byte)3] = methodName;
|
||||
rpcEvent[(byte)4] = (object[])parameters;
|
||||
|
||||
// Check scoping
|
||||
if (target == PhotonTargets.All)
|
||||
{
|
||||
this.OpRaiseEvent(PhotonNetworkMessages.RPC, rpcEvent, true, 0);
|
||||
|
||||
// Execute local
|
||||
this.ExecuteRPC(rpcEvent, this.mLocalActor);
|
||||
}
|
||||
else if (target == PhotonTargets.Others)
|
||||
{
|
||||
this.OpRaiseEvent(PhotonNetworkMessages.RPC, rpcEvent, true, 0);
|
||||
}
|
||||
else if (target == PhotonTargets.AllBuffered)
|
||||
{
|
||||
this.OpRaiseEvent(PhotonNetworkMessages.RPC, rpcEvent, true, 0, EventCaching.AddToRoomCache, ReceiverGroup.Others);
|
||||
|
||||
// Execute local
|
||||
this.ExecuteRPC(rpcEvent, this.mLocalActor);
|
||||
}
|
||||
else if (target == PhotonTargets.OthersBuffered)
|
||||
{
|
||||
this.OpRaiseEvent(PhotonNetworkMessages.RPC, rpcEvent, true, 0, EventCaching.AddToRoomCache, ReceiverGroup.Others);
|
||||
}
|
||||
else if (target == PhotonTargets.MasterClient)
|
||||
{
|
||||
if (this.mMasterClient == this.mLocalActor)
|
||||
{
|
||||
this.ExecuteRPC(rpcEvent, this.mLocalActor);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.OpRaiseEvent(PhotonNetworkMessages.RPC, rpcEvent, true, 0, EventCaching.DoNotCache, ReceiverGroup.MasterClient);//TS: changed from caching to non-cached. this goes to master only
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError("Unsupported target enum: " + target);
|
||||
}
|
||||
}
|
||||
|
||||
// SetReceiving
|
||||
public void SetReceivingEnabled(int group, bool enabled)
|
||||
{
|
||||
if (!enabled)
|
||||
{
|
||||
if (!this.blockReceivingGroups.Contains(group))
|
||||
this.blockReceivingGroups.Add(group);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.blockReceivingGroups.Remove(group);
|
||||
}
|
||||
}
|
||||
|
||||
// SetSending
|
||||
public void SetSendingEnabled(int group, bool enabled)
|
||||
{
|
||||
if (!enabled)
|
||||
{
|
||||
if (!this.blockSendingGroups.Contains(group))
|
||||
this.blockSendingGroups.Add(group);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.blockSendingGroups.Remove(group);
|
||||
}
|
||||
}
|
||||
|
||||
public void NewSceneLoaded()
|
||||
{
|
||||
List<int> removeKeys = new List<int>();
|
||||
foreach (KeyValuePair<int, PhotonView> kvp in this.photonViewList)
|
||||
{
|
||||
PhotonView view = kvp.Value;
|
||||
if (view == null)
|
||||
{
|
||||
removeKeys.Add(kvp.Key);
|
||||
}
|
||||
}
|
||||
|
||||
for (int index = 0; index < removeKeys.Count; index++)
|
||||
{
|
||||
int key = removeKeys[index];
|
||||
this.photonViewList.Remove(key);
|
||||
}
|
||||
|
||||
if (removeKeys.Count > 0)
|
||||
{
|
||||
if (this.DebugOut >= DebugLevel.INFO)
|
||||
{
|
||||
this.DebugReturn(DebugLevel.INFO, "Removed " + removeKeys.Count + " scene view IDs from last scene.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// this is called by Update() and in Unity that means it's single threaded.
|
||||
public void RunViewUpdate()
|
||||
{
|
||||
if (!PhotonNetwork.connected || PhotonNetwork.offlineMode)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.mActors == null || this.mActors.Count <= 1)
|
||||
{
|
||||
return; // No need to send OnSerialize messages (these are never buffered anyway)
|
||||
}
|
||||
|
||||
|
||||
Hashtable reliableUpdates = new Hashtable();
|
||||
reliableUpdates[(byte)0] = this.ServerTimeInMilliSeconds;
|
||||
Hashtable unreliableUpdates = new Hashtable();
|
||||
unreliableUpdates[(byte)0] = this.ServerTimeInMilliSeconds;
|
||||
int originalSize = 1;
|
||||
if (currentLevelPrefix >= 0)
|
||||
{
|
||||
reliableUpdates[(byte)1] = this.currentLevelPrefix;
|
||||
unreliableUpdates[(byte)1] = this.currentLevelPrefix;
|
||||
originalSize = 2;
|
||||
}
|
||||
|
||||
|
||||
foreach (KeyValuePair<int, PhotonView> kvp in this.photonViewList)
|
||||
{
|
||||
PhotonView view = kvp.Value;
|
||||
|
||||
if (view.observed != null && view.synchronization != ViewSynchronization.Off)
|
||||
{
|
||||
// Fetch all sending photonViews
|
||||
if (view.owner == this.mLocalActor || (view.isSceneView && this.mMasterClient == this.mLocalActor))
|
||||
{
|
||||
#if UNITY_2_6_1 || UNITY_2_6 || UNITY_3_0 || UNITY_3_0_0 || UNITY_3_1 || UNITY_3_2 || UNITY_3_3 || UNITY_3_4 || UNITY_3_5
|
||||
if (!view.gameObject.active)
|
||||
{
|
||||
continue; // Only on actives
|
||||
}
|
||||
#else
|
||||
if (!view.gameObject.activeInHierarchy)
|
||||
{
|
||||
continue; // Only on actives
|
||||
}
|
||||
#endif
|
||||
|
||||
if (this.blockSendingGroups.Contains(view.group))
|
||||
{
|
||||
continue; // Block sending on this group
|
||||
}
|
||||
|
||||
// Run it trough its onserialize
|
||||
Hashtable evData = this.OnSerializeWrite(view);
|
||||
if (evData == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (view.synchronization == ViewSynchronization.ReliableDeltaCompressed)
|
||||
{
|
||||
if (!evData.ContainsKey((byte)1) && !evData.ContainsKey((byte)2))
|
||||
{
|
||||
// Everything has been removed by compression, nothing to send
|
||||
}
|
||||
else
|
||||
{
|
||||
reliableUpdates.Add((short)reliableUpdates.Count, evData);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
unreliableUpdates.Add((short)unreliableUpdates.Count, evData);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Debug.Log(" NO OBS on " + view.name + " " + view.owner);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
// actual sending of updates (reliable and unreliable are separated)
|
||||
if (reliableUpdates.Count > originalSize)
|
||||
{
|
||||
//Debug.Log("updates " + reliableUpdates.Count);
|
||||
this.OpRaiseEvent(PhotonNetworkMessages.SendSerializeReliable, reliableUpdates, true, 0);
|
||||
}
|
||||
|
||||
if (unreliableUpdates.Count > originalSize)
|
||||
{
|
||||
//Debug.Log("updates " + reliableUpdates.Count);
|
||||
this.OpRaiseEvent(PhotonNetworkMessages.SendSerialize, unreliableUpdates, false, 1);
|
||||
}
|
||||
}
|
||||
|
||||
private void ExecuteOnSerialize(MonoBehaviour monob, PhotonStream pStream, PhotonMessageInfo info)
|
||||
{
|
||||
object[] paramsX = new object[2];
|
||||
paramsX[0] = pStream;
|
||||
paramsX[1] = info;
|
||||
|
||||
MethodInfo methodI = this.GetCachedMethod(monob, PhotonNetworkingMessage.OnPhotonSerializeView);
|
||||
if (methodI != null)
|
||||
{
|
||||
object result = methodI.Invoke((object)monob, paramsX);
|
||||
if (methodI.ReturnType == typeof(System.Collections.IEnumerator))
|
||||
{
|
||||
PhotonHandler.SP.StartCoroutine((IEnumerator)result);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError("Tried to run " + PhotonNetworkingMessage.OnPhotonSerializeView + ", but this method was missing on: " + monob);
|
||||
}
|
||||
}
|
||||
|
||||
// calls OnPhotonSerializeView (through ExecuteOnSerialize)
|
||||
// the content created here is consumed by receivers in: ReadOnSerialize
|
||||
private Hashtable OnSerializeWrite(PhotonView view)
|
||||
{
|
||||
// each view creates a list of values that should be sent
|
||||
List<object> data = new List<object>();
|
||||
|
||||
// 1=Specific data
|
||||
if (view.observed is MonoBehaviour)
|
||||
{
|
||||
MonoBehaviour monob = (MonoBehaviour)view.observed;
|
||||
PhotonStream pStream = new PhotonStream(true, null);
|
||||
PhotonMessageInfo info = new PhotonMessageInfo(this.mLocalActor, this.ServerTimeInMilliSeconds, view);
|
||||
|
||||
this.ExecuteOnSerialize(monob, pStream, info);
|
||||
if (pStream.Count == 0)
|
||||
{
|
||||
// if an observed script didn't write any data, we don't send anything
|
||||
return null;
|
||||
}
|
||||
|
||||
// we want to use the content of the stream (filled in by user scripts)
|
||||
data = pStream.data;
|
||||
}
|
||||
else if (view.observed is Transform)
|
||||
{
|
||||
Transform trans = (Transform)view.observed;
|
||||
|
||||
if (view.onSerializeTransformOption == OnSerializeTransform.OnlyPosition
|
||||
|| view.onSerializeTransformOption == OnSerializeTransform.PositionAndRotation
|
||||
|| view.onSerializeTransformOption == OnSerializeTransform.All)
|
||||
data.Add(trans.localPosition);
|
||||
else
|
||||
data.Add(null);
|
||||
|
||||
if (view.onSerializeTransformOption == OnSerializeTransform.OnlyRotation
|
||||
|| view.onSerializeTransformOption == OnSerializeTransform.PositionAndRotation
|
||||
|| view.onSerializeTransformOption == OnSerializeTransform.All)
|
||||
data.Add(trans.localRotation);
|
||||
else
|
||||
data.Add(null);
|
||||
|
||||
if (view.onSerializeTransformOption == OnSerializeTransform.OnlyScale
|
||||
|| view.onSerializeTransformOption == OnSerializeTransform.All)
|
||||
data.Add(trans.localScale);
|
||||
}
|
||||
else if (view.observed is Rigidbody)
|
||||
{
|
||||
Rigidbody rigidB = (Rigidbody)view.observed;
|
||||
|
||||
if (view.onSerializeRigidBodyOption != OnSerializeRigidBody.OnlyAngularVelocity)
|
||||
data.Add(rigidB.velocity);
|
||||
else
|
||||
data.Add(null);
|
||||
|
||||
if (view.onSerializeRigidBodyOption != OnSerializeRigidBody.OnlyVelocity)
|
||||
data.Add( rigidB.angularVelocity);
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError("Observed type is not serializable: " + view.observed.GetType());
|
||||
return null;
|
||||
}
|
||||
|
||||
object[] dataArray = data.ToArray();
|
||||
|
||||
// EVDATA:
|
||||
// 0=View ID (an int, never compressed cause it's not in the data)
|
||||
// 1=data of observed type (different per type of observed object)
|
||||
// 2=compressed data (in this case, key 1 is empty)
|
||||
// 3=list of values that are actually null (if something was changed but actually IS null)
|
||||
Hashtable evData = new Hashtable();
|
||||
evData[(byte)0] = (int)view.viewID.ID;
|
||||
evData[(byte)1] = dataArray; // this is the actual data (script or observed object)
|
||||
|
||||
if (view.synchronization == ViewSynchronization.ReliableDeltaCompressed)
|
||||
{
|
||||
// compress content of data set (by comparing to view.lastOnSerializeDataSent)
|
||||
// the "original" dataArray is NOT modified by DeltaCompressionWrite
|
||||
// if something was compressed, the evData key 2 and 3 are used (see above)
|
||||
bool somethingLeftToSend = this.DeltaCompressionWrite(view, evData);
|
||||
|
||||
// buffer the full data set (for next compression)
|
||||
view.lastOnSerializeDataSent = dataArray;
|
||||
|
||||
if (!somethingLeftToSend)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return evData;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads updates created by OnSerializeWrite
|
||||
/// </summary>
|
||||
private void OnSerializeRead(Hashtable data, PhotonPlayer sender, int networkTime, short correctPrefix)
|
||||
{
|
||||
// read view ID from key (byte)0: a int-array (PUN 1.17++)
|
||||
int viewID = (int)data[(byte)0];
|
||||
|
||||
|
||||
PhotonView view = this.GetPhotonView(viewID);
|
||||
if (view == null)
|
||||
{
|
||||
Debug.LogWarning("Received OnSerialization for view ID " + viewID + ". We have no such PhotonView! Ignored this if you're leaving a room. State: " + this.State);
|
||||
return;
|
||||
}
|
||||
|
||||
if (view.prefix > 0 && correctPrefix != view.prefix)
|
||||
{
|
||||
Debug.LogError("Received OnSerialization for view ID " + viewID + " with prefix " + correctPrefix + ". Our prefix is " + view.prefix);
|
||||
return;
|
||||
}
|
||||
|
||||
// SetReceiving filtering
|
||||
if (this.blockReceivingGroups.Contains(view.@group))
|
||||
{
|
||||
return; // Ignore group
|
||||
}
|
||||
|
||||
if (view.synchronization == ViewSynchronization.ReliableDeltaCompressed)
|
||||
{
|
||||
if (!this.DeltaCompressionRead(view, data))
|
||||
{
|
||||
// Skip this packet as we haven't got received complete-copy of this view yet.
|
||||
this.DebugReturn(DebugLevel.INFO, "Skipping packet for " + view.name + " [" + view.viewID + "] as we haven't received a full packet for delta compression yet. This is OK if it happens for the first few frames after joining a game.");
|
||||
return;
|
||||
}
|
||||
|
||||
// store last received for delta-compression usage
|
||||
view.lastOnSerializeDataReceived = data[(byte)1] as object[];
|
||||
}
|
||||
|
||||
// Use incoming data according to observed type
|
||||
if (view.observed is MonoBehaviour)
|
||||
{
|
||||
object[] contents = data[(byte)1] as object[];
|
||||
MonoBehaviour monob = (MonoBehaviour)view.observed;
|
||||
PhotonStream pStream = new PhotonStream(false, contents);
|
||||
PhotonMessageInfo info = new PhotonMessageInfo(sender, networkTime, view);
|
||||
|
||||
this.ExecuteOnSerialize(monob, pStream, info);
|
||||
}
|
||||
else if (view.observed is Transform)
|
||||
{
|
||||
object[] contents = data[(byte)1] as object[];
|
||||
Transform trans = (Transform)view.observed;
|
||||
if (contents.Length >= 1 && contents[0] != null)
|
||||
trans.localPosition = (Vector3)contents[0];
|
||||
if (contents.Length >= 2 && contents[1] != null)
|
||||
trans.localRotation = (Quaternion)contents[1];
|
||||
if (contents.Length >= 3 && contents[2] != null)
|
||||
trans.localScale = (Vector3)contents[2];
|
||||
|
||||
}
|
||||
else if (view.observed is Rigidbody)
|
||||
{
|
||||
object[] contents = data[(byte)1] as object[];
|
||||
Rigidbody rigidB = (Rigidbody)view.observed;
|
||||
if (contents.Length >= 1 && contents[0] != null)
|
||||
rigidB.velocity = (Vector3)contents[0];
|
||||
if (contents.Length >= 2 && contents[1] != null)
|
||||
rigidB.angularVelocity = (Vector3)contents[1];
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError("Type of observed is unknown when receiving.");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compares the new data with previously sent data and skips values that didn't change.
|
||||
/// </summary>
|
||||
/// <returns>True if anything has to be sent, false if nothing new or no data</returns>
|
||||
private bool DeltaCompressionWrite(PhotonView view, Hashtable data)
|
||||
{
|
||||
if (view.lastOnSerializeDataSent == null)
|
||||
{
|
||||
return true; // all has to be sent
|
||||
}
|
||||
|
||||
// We can compress as we sent a full update previously (readers can re-use previous values)
|
||||
object[] lastData = view.lastOnSerializeDataSent;
|
||||
object[] currentContent = data[(byte)1] as object[];
|
||||
|
||||
if (currentContent == null)
|
||||
{
|
||||
// no data to be sent
|
||||
return false;
|
||||
}
|
||||
|
||||
if (lastData.Length != currentContent.Length)
|
||||
{
|
||||
// if new data isn't same length as before, we send the complete data-set uncompressed
|
||||
return true;
|
||||
}
|
||||
|
||||
object[] compressedContent = new object[currentContent.Length];
|
||||
int compressedValues = 0;
|
||||
|
||||
List<int> valuesThatAreChangedToNull = new List<int>();
|
||||
for (int index = 0; index < compressedContent.Length; index++)
|
||||
{
|
||||
object newObj = currentContent[index];
|
||||
object oldObj = lastData[index];
|
||||
if (this.ObjectIsSameWithInprecision(newObj, oldObj))
|
||||
{
|
||||
// compress (by using null, instead of value, which is same as before)
|
||||
compressedValues++;
|
||||
// compressedContent[index] is already null (initialized)
|
||||
}
|
||||
else
|
||||
{
|
||||
compressedContent[index] = currentContent[index];
|
||||
|
||||
// value changed, we don't replace it with null
|
||||
// new value is null (like a compressed value): we have to mark it so it STAYS null instead of being replaced with previous value
|
||||
if (newObj == null)
|
||||
{
|
||||
valuesThatAreChangedToNull.Add(index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Only send the list of compressed fields if we actually compressed 1 or more fields.
|
||||
if (compressedValues > 0)
|
||||
{
|
||||
data.Remove((byte)1); // remove the original data (we only send compressed data)
|
||||
|
||||
if (compressedValues == currentContent.Length)
|
||||
{
|
||||
// all values are compressed to null, we have nothing to send
|
||||
return false;
|
||||
}
|
||||
|
||||
data[(byte)2] = compressedContent; // current, compressted data is moved to key 2 to mark it as compressed
|
||||
if (valuesThatAreChangedToNull.Count > 0)
|
||||
{
|
||||
data[(byte)3] = valuesThatAreChangedToNull.ToArray(); // data that is actually null (not just cause we didn't want to send it)
|
||||
}
|
||||
}
|
||||
|
||||
return true; // some data was compressed but we need to send something
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// reads incoming messages created by "OnSerialize"
|
||||
/// </summary>
|
||||
private bool DeltaCompressionRead(PhotonView view, Hashtable data)
|
||||
{
|
||||
if (data.ContainsKey((byte)1))
|
||||
{
|
||||
// we have a full list of data (cause key 1 is used), so return "we have uncompressed all"
|
||||
return true;
|
||||
}
|
||||
|
||||
// Compression was applied as data[(byte)2] exists (this is the data with some fields being compressed to null)
|
||||
// now we also need a previous "full" list of values to restore values that are null in this msg
|
||||
if (view.lastOnSerializeDataReceived == null)
|
||||
{
|
||||
return false; // We dont have a full match yet, we cannot work with missing values: skip this message
|
||||
}
|
||||
|
||||
object[] compressedContents = data[(byte)2] as object[];
|
||||
if (compressedContents == null)
|
||||
{
|
||||
// despite expectation, there is no compressed data in this msg. shouldn't happen. just a null check
|
||||
return false;
|
||||
}
|
||||
|
||||
int[] indexesThatAreChangedToNull = data[(byte)3] as int[];
|
||||
if (indexesThatAreChangedToNull == null)
|
||||
{
|
||||
indexesThatAreChangedToNull = new int[0];
|
||||
}
|
||||
|
||||
object[] lastReceivedData = view.lastOnSerializeDataReceived;
|
||||
for (int index = 0; index < compressedContents.Length; index++)
|
||||
{
|
||||
if (compressedContents[index] == null && !indexesThatAreChangedToNull.Contains(index))
|
||||
{
|
||||
// we replace null values in this received msg unless a index is in the "changed to null" list
|
||||
object lastValue = lastReceivedData[index];
|
||||
compressedContents[index] = lastValue;
|
||||
}
|
||||
}
|
||||
|
||||
data[(byte)1] = compressedContents; // compressedContents are now uncompressed...
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if both objects are almost identical.
|
||||
/// Used to check whether two objects are similar enough to skip an update.
|
||||
/// </summary>
|
||||
bool ObjectIsSameWithInprecision(object one, object two)
|
||||
{
|
||||
if (one == null || two == null)
|
||||
{
|
||||
return one == null && two == null;
|
||||
}
|
||||
|
||||
if (!one.Equals(two))
|
||||
{
|
||||
// if A is not B, lets check if A is almost B
|
||||
if (one is Vector3)
|
||||
{
|
||||
Vector3 a = (Vector3)one;
|
||||
Vector3 b = (Vector3)two;
|
||||
if (a.AlmostEquals(b, PhotonNetwork.precisionForVectorSynchronization))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (one is Vector2)
|
||||
{
|
||||
Vector2 a = (Vector2)one;
|
||||
Vector2 b = (Vector2)two;
|
||||
if (a.AlmostEquals(b, PhotonNetwork.precisionForVectorSynchronization))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (one is Quaternion)
|
||||
{
|
||||
Quaternion a = (Quaternion)one;
|
||||
Quaternion b = (Quaternion)two;
|
||||
if (a.AlmostEquals(b, PhotonNetwork.precisionForQuaternionSynchronization))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (one is float)
|
||||
{
|
||||
float a = (float)one;
|
||||
float b = (float)two;
|
||||
if (a.AlmostEquals(b, PhotonNetwork.precisionForFloatSynchronization))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// one does not equal two
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private Dictionary<Type, Dictionary<PhotonNetworkingMessage, MethodInfo>> cachedMethods = new Dictionary<Type, Dictionary<PhotonNetworkingMessage, MethodInfo>>();
|
||||
|
||||
private MethodInfo GetCachedMethod(MonoBehaviour monob, PhotonNetworkingMessage methodType)
|
||||
{
|
||||
Type type = monob.GetType();
|
||||
if (!this.cachedMethods.ContainsKey(type))
|
||||
{
|
||||
Dictionary<PhotonNetworkingMessage, MethodInfo> newMethodsDict = new Dictionary<PhotonNetworkingMessage, MethodInfo>();
|
||||
this.cachedMethods.Add(type, newMethodsDict);
|
||||
}
|
||||
|
||||
// Get method type list
|
||||
Dictionary<PhotonNetworkingMessage, MethodInfo> methods = this.cachedMethods[type];
|
||||
if (!methods.ContainsKey(methodType))
|
||||
{
|
||||
// Load into cache
|
||||
Type[] argTypes;
|
||||
if (methodType == PhotonNetworkingMessage.OnPhotonSerializeView)
|
||||
{
|
||||
argTypes = new Type[2];
|
||||
argTypes[0] = typeof(PhotonStream);
|
||||
argTypes[1] = typeof(PhotonMessageInfo);
|
||||
}
|
||||
else if (methodType == PhotonNetworkingMessage.OnPhotonInstantiate)
|
||||
{
|
||||
argTypes = new Type[1];
|
||||
argTypes[0] = typeof(PhotonMessageInfo);
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError("Invalid PhotonNetworkingMessage!");
|
||||
return null;
|
||||
}
|
||||
|
||||
MethodInfo metInfo = monob.GetType().GetMethod(
|
||||
methodType + string.Empty,
|
||||
BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance,
|
||||
null,
|
||||
argTypes,
|
||||
null);
|
||||
if (metInfo != null)
|
||||
{
|
||||
methods.Add(methodType, metInfo);
|
||||
}
|
||||
}
|
||||
|
||||
if (methods.ContainsKey(methodType))
|
||||
{
|
||||
return methods[methodType];
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6389c32085f1ef04f88e046b96ab6fc6
|
||||
labels:
|
||||
- Photon
|
||||
- Networking
|
||||
- ExitGames
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
+424
@@ -0,0 +1,424 @@
|
||||
// ----------------------------------------------------------------------------
|
||||
// <copyright file="PhotonClasses.cs" company="Exit Games GmbH">
|
||||
// PhotonNetwork Framework for Unity - Copyright (C) 2011 Exit Games GmbH
|
||||
// </copyright>
|
||||
// <summary>
|
||||
//
|
||||
// </summary>
|
||||
// <author>developer@exitgames.com</author>
|
||||
// ----------------------------------------------------------------------------
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
|
||||
/// <summary>Class for constants. Defines photon-event-codes for PUN usage.</summary>
|
||||
internal class PhotonNetworkMessages
|
||||
{
|
||||
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
|
||||
}
|
||||
|
||||
/// <summary>Enum of "target" options for RPCs. These define which remote clients get your RPC call. </summary>
|
||||
/// \ingroup publicApi
|
||||
public enum PhotonTargets { All, Others, MasterClient, AllBuffered, OthersBuffered } //.MasterClientBuffered? .Server?
|
||||
|
||||
/// <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 PhotonLogLevel { ErrorsOnly, Informational, Full }
|
||||
|
||||
|
||||
namespace Photon
|
||||
{
|
||||
/// <summary>
|
||||
/// This class adds the property photonView, while logging a warning when your game still uses the networkView.
|
||||
/// </summary>
|
||||
public class MonoBehaviour : UnityEngine.MonoBehaviour
|
||||
{
|
||||
public PhotonView photonView
|
||||
{
|
||||
get
|
||||
{
|
||||
return PhotonView.Get(this);
|
||||
}
|
||||
}
|
||||
new public PhotonView networkView
|
||||
{
|
||||
get
|
||||
{
|
||||
Debug.LogWarning("Why are you still using networkView? should be PhotonView?");
|
||||
return PhotonView.Get(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Internally used, the ID of a PhotonView is a "composite" integer number of:
|
||||
/// owner.ID * PhotonNetwork.MAX_VIEW_IDS + internalID
|
||||
/// </summary>
|
||||
public class PhotonViewID
|
||||
{
|
||||
private PhotonPlayer internalOwner;
|
||||
private int internalID = -1; // 1-256 (1-MAX_NETWORKVIEWS)
|
||||
|
||||
public PhotonViewID(int ID, PhotonPlayer owner)
|
||||
{
|
||||
internalID = ID;
|
||||
internalOwner = owner;
|
||||
}
|
||||
|
||||
public int ID
|
||||
{
|
||||
// PLAYERNR*MAX_NETWORKVIEWS + internalID
|
||||
get
|
||||
{
|
||||
if(internalOwner == null)
|
||||
{
|
||||
//Scene ID
|
||||
return internalID;
|
||||
}
|
||||
else
|
||||
{
|
||||
return (internalOwner.ID*PhotonNetwork.MAX_VIEW_IDS) + internalID;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool isMine
|
||||
{
|
||||
get { return owner.isLocal; }
|
||||
}
|
||||
|
||||
public PhotonPlayer owner
|
||||
{
|
||||
get
|
||||
{
|
||||
int ownerNR = ID / PhotonNetwork.MAX_VIEW_IDS;
|
||||
return PhotonPlayer.Find(ownerNR);
|
||||
}
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return this.ID.ToString();
|
||||
}
|
||||
|
||||
public override bool Equals(object p)
|
||||
{
|
||||
PhotonViewID pp = p as PhotonViewID;
|
||||
return (pp != null && this.ID == pp.ID);
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return this.ID;
|
||||
}
|
||||
|
||||
[System.Obsolete("Used for compatibility with Unity networking only.")]
|
||||
public static PhotonViewID unassigned
|
||||
{
|
||||
get
|
||||
{
|
||||
return new PhotonViewID(-1, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Container class for info about a particular message, RPC or update.
|
||||
/// </summary>
|
||||
/// \ingroup publicApi
|
||||
public class PhotonMessageInfo
|
||||
{
|
||||
private int timeInt;
|
||||
public PhotonPlayer sender;
|
||||
public PhotonView photonView;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="PhotonMessageInfo"/> class.
|
||||
/// To create an empty messageinfo only!
|
||||
/// </summary>
|
||||
public PhotonMessageInfo()
|
||||
{
|
||||
this.sender = PhotonNetwork.player;
|
||||
this.timeInt = (int)(PhotonNetwork.time * 1000);
|
||||
this.photonView = null;
|
||||
}
|
||||
|
||||
public PhotonMessageInfo(PhotonPlayer player, int timestamp, PhotonView view)
|
||||
{
|
||||
this.sender = player;
|
||||
this.timeInt = timestamp;
|
||||
this.photonView = view;
|
||||
}
|
||||
|
||||
public double timestamp
|
||||
{
|
||||
get { return ((double)(uint)this.timeInt) / 1000.0f; }
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return string.Format("[PhotonMessageInfo: player='{1}' timestamp={0}]", this.timestamp, this.sender);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This "container" class is used to carry your data as written by OnPhotonSerializeView.
|
||||
/// </summary>
|
||||
/// <seealso cref="PhotonNetworkingMessage"/>
|
||||
/// \ingroup publicApi
|
||||
public class PhotonStream
|
||||
{
|
||||
bool write = false;
|
||||
internal List<object> data;
|
||||
byte currentItem = 0; //Used to track the next item to receive.
|
||||
|
||||
public PhotonStream(bool write, object[] incomingData)
|
||||
{
|
||||
this.write = write;
|
||||
if (incomingData == null)
|
||||
{
|
||||
this.data = new List<object>();
|
||||
}
|
||||
else
|
||||
{
|
||||
this.data = new List<object>(incomingData);
|
||||
}
|
||||
}
|
||||
|
||||
public bool isWriting
|
||||
{
|
||||
get { return this.write; }
|
||||
}
|
||||
|
||||
public bool isReading
|
||||
{
|
||||
get { return !this.write; }
|
||||
}
|
||||
|
||||
public int Count
|
||||
{
|
||||
get
|
||||
{
|
||||
return data.Count;
|
||||
}
|
||||
}
|
||||
|
||||
public object ReceiveNext()
|
||||
{
|
||||
if (this.write)
|
||||
{
|
||||
Debug.LogError("Error: you cannot read this stream that you are writing!");
|
||||
return null;
|
||||
}
|
||||
|
||||
object obj = this.data[this.currentItem];
|
||||
this.currentItem++;
|
||||
return obj;
|
||||
}
|
||||
|
||||
public void SendNext(object obj)
|
||||
{
|
||||
if (!this.write)
|
||||
{
|
||||
Debug.LogError("Error: you cannot write/send to this stream that you are reading!");
|
||||
return;
|
||||
}
|
||||
|
||||
this.data.Add(obj);
|
||||
}
|
||||
|
||||
public object[] ToArray()
|
||||
{
|
||||
return this.data.ToArray();
|
||||
}
|
||||
|
||||
public void Serialize(ref bool myBool)
|
||||
{
|
||||
if (this.write)
|
||||
{
|
||||
this.data.Add(myBool);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (this.data.Count > currentItem)
|
||||
{
|
||||
myBool = (bool)data[currentItem];
|
||||
this.currentItem++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Serialize(ref int myInt)
|
||||
{
|
||||
if (write)
|
||||
{
|
||||
this.data.Add(myInt);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (this.data.Count > currentItem)
|
||||
{
|
||||
myInt = (int)data[currentItem];
|
||||
currentItem++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Serialize(ref string value)
|
||||
{
|
||||
if (write)
|
||||
{
|
||||
this.data.Add(value);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (this.data.Count > currentItem)
|
||||
{
|
||||
value = (string)data[currentItem];
|
||||
currentItem++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Serialize(ref char value)
|
||||
{
|
||||
if (write)
|
||||
{
|
||||
this.data.Add(value);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (this.data.Count > currentItem)
|
||||
{
|
||||
value = (char)data[currentItem];
|
||||
currentItem++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Serialize(ref short value)
|
||||
{
|
||||
if (write)
|
||||
{
|
||||
this.data.Add(value);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (this.data.Count > currentItem)
|
||||
{
|
||||
value = (short)data[currentItem];
|
||||
currentItem++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Serialize(ref float obj)
|
||||
{
|
||||
if (write)
|
||||
{
|
||||
this.data.Add(obj);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (this.data.Count > currentItem)
|
||||
{
|
||||
obj = (float)data[currentItem];
|
||||
currentItem++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Serialize(ref PhotonPlayer obj)
|
||||
{
|
||||
if (write)
|
||||
{
|
||||
this.data.Add(obj);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (this.data.Count > currentItem)
|
||||
{
|
||||
obj = (PhotonPlayer)data[currentItem];
|
||||
currentItem++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Serialize(ref Vector3 obj)
|
||||
{
|
||||
if (write)
|
||||
{
|
||||
this.data.Add(obj);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (this.data.Count > currentItem)
|
||||
{
|
||||
obj = (Vector3)data[currentItem];
|
||||
currentItem++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Serialize(ref Vector2 obj)
|
||||
{
|
||||
if (write)
|
||||
{
|
||||
this.data.Add(obj);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (this.data.Count > currentItem)
|
||||
{
|
||||
obj = (Vector2)data[currentItem];
|
||||
currentItem++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Serialize(ref Quaternion obj)
|
||||
{
|
||||
if (write)
|
||||
{
|
||||
this.data.Add(obj);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (this.data.Count > currentItem)
|
||||
{
|
||||
obj = (Quaternion)data[currentItem];
|
||||
currentItem++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Serialize(ref PhotonViewID obj)
|
||||
{
|
||||
if (write)
|
||||
{
|
||||
this.data.Add(obj);
|
||||
}
|
||||
else
|
||||
{
|
||||
int ID = (int)data[currentItem];
|
||||
currentItem++;
|
||||
|
||||
int internalID = ID % PhotonNetwork.MAX_VIEW_IDS;
|
||||
int actorID = ID / PhotonNetwork.MAX_VIEW_IDS;
|
||||
PhotonPlayer owner = null;
|
||||
if (actorID > 0)
|
||||
{
|
||||
owner = PhotonPlayer.Find(actorID);
|
||||
}
|
||||
|
||||
obj = new PhotonViewID(internalID, owner);
|
||||
}
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f40f16a0227e5c14293e269c875c0f9b
|
||||
labels:
|
||||
- ExitGames
|
||||
- PUN
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
+156
@@ -0,0 +1,156 @@
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// <copyright file="PhotonHandler.cs" company="Exit Games GmbH">
|
||||
// Part of: Photon Unity Networking
|
||||
// </copyright>
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
using System;
|
||||
using ExitGames.Client.Photon;
|
||||
using UnityEngine;
|
||||
|
||||
/// <summary>
|
||||
/// Internal Monobehaviour that allows Photon to run an Update loop.
|
||||
/// </summary>
|
||||
internal class PhotonHandler : Photon.MonoBehaviour, IPhotonPeerListener
|
||||
{
|
||||
public static PhotonHandler SP;
|
||||
|
||||
public int updateInterval;
|
||||
|
||||
public int updateIntervalOnSerialize;
|
||||
|
||||
private int nextSendTickCount = Environment.TickCount;
|
||||
|
||||
private int nextSendTickCountOnSerialize = Environment.TickCount;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
if (SP != null && SP != this)
|
||||
{
|
||||
Debug.LogError("Error: we already have an PhotonMono around!");
|
||||
Destroy(this.gameObject);
|
||||
}
|
||||
|
||||
DontDestroyOnLoad(this);
|
||||
SP = this;
|
||||
|
||||
this.updateInterval = 1000 / PhotonNetwork.sendRate;
|
||||
this.updateIntervalOnSerialize = 1000 / PhotonNetwork.sendRateOnSerialize;
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
if (PhotonNetwork.networkingPeer == null)
|
||||
{
|
||||
Debug.LogError("NetworkPeer broke!");
|
||||
return;
|
||||
}
|
||||
|
||||
if (PhotonNetwork.connectionStateDetailed == PeerState.PeerCreated || PhotonNetwork.connectionStateDetailed == PeerState.Disconnected)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// the messageQueue might be paused. in that case a thread will send acknowledgements only. nothing else to do here.
|
||||
if (!PhotonNetwork.isMessageQueueRunning)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
bool doDispatch = true;
|
||||
while (PhotonNetwork.isMessageQueueRunning && doDispatch)
|
||||
{
|
||||
// DispatchIncomingCommands() returns true of it found any command to dispatch (event, result or state change)
|
||||
Profiler.BeginSample("DispatchIncomingCommands");
|
||||
doDispatch = PhotonNetwork.networkingPeer.DispatchIncomingCommands();
|
||||
Profiler.EndSample();
|
||||
}
|
||||
|
||||
if (PhotonNetwork.isMessageQueueRunning && Environment.TickCount > this.nextSendTickCountOnSerialize)
|
||||
{
|
||||
PhotonNetwork.networkingPeer.RunViewUpdate();
|
||||
this.nextSendTickCountOnSerialize = Environment.TickCount + this.updateIntervalOnSerialize;
|
||||
}
|
||||
|
||||
if (Environment.TickCount > this.nextSendTickCount)
|
||||
{
|
||||
bool doSend = true;
|
||||
while (PhotonNetwork.isMessageQueueRunning && doSend)
|
||||
{
|
||||
// Send all outgoing commands
|
||||
Profiler.BeginSample("SendOutgoingCommands");
|
||||
doSend = PhotonNetwork.networkingPeer.SendOutgoingCommands();
|
||||
Profiler.EndSample();
|
||||
}
|
||||
|
||||
this.nextSendTickCount = Environment.TickCount + this.updateInterval;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Called by Unity when the application is closed. Tries to disconnect.</summary>
|
||||
public void OnApplicationQuit()
|
||||
{
|
||||
PhotonNetwork.Disconnect();
|
||||
}
|
||||
|
||||
/// <summary>Called by Unity after a new level was loaded.</summary>
|
||||
public void OnLevelWasLoaded(int level)
|
||||
{
|
||||
PhotonNetwork.networkingPeer.NewSceneLoaded();
|
||||
}
|
||||
|
||||
public static void StartThread()
|
||||
{
|
||||
System.Threading.Thread sendThread = new System.Threading.Thread(new System.Threading.ThreadStart(MyThread));
|
||||
sendThread.Start();
|
||||
}
|
||||
|
||||
// keeps connection alive while loading
|
||||
public static void MyThread()
|
||||
{
|
||||
while (PhotonNetwork.networkingPeer != null && PhotonNetwork.networkingPeer.IsSendingOnlyAcks)
|
||||
{
|
||||
while (PhotonNetwork.networkingPeer.SendOutgoingCommands())
|
||||
{
|
||||
}
|
||||
|
||||
System.Threading.Thread.Sleep(200);
|
||||
}
|
||||
}
|
||||
|
||||
#region Implementation of IPhotonPeerListener
|
||||
|
||||
public void DebugReturn(DebugLevel level, string message)
|
||||
{
|
||||
if (level == DebugLevel.ERROR)
|
||||
{
|
||||
Debug.LogError(message);
|
||||
}
|
||||
else if (level == DebugLevel.WARNING)
|
||||
{
|
||||
Debug.LogWarning(message);
|
||||
}
|
||||
else if (level == DebugLevel.INFO && PhotonNetwork.logLevel >= PhotonLogLevel.Informational)
|
||||
{
|
||||
Debug.Log(message);
|
||||
}
|
||||
else if (level == DebugLevel.ALL && PhotonNetwork.logLevel == PhotonLogLevel.Full)
|
||||
{
|
||||
Debug.Log(message);
|
||||
}
|
||||
}
|
||||
|
||||
public void OnOperationResponse(OperationResponse operationResponse)
|
||||
{
|
||||
}
|
||||
|
||||
public void OnStatusChanged(StatusCode statusCode)
|
||||
{
|
||||
}
|
||||
|
||||
public void OnEvent(EventData photonEvent)
|
||||
{
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 177bddf229f8d8445a70c0652f03b7df
|
||||
labels:
|
||||
- ExitGames
|
||||
- PUN
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
+92
@@ -0,0 +1,92 @@
|
||||
using ExitGames.Client.Photon;
|
||||
using ExitGames.Client.Photon.Lite;
|
||||
using UnityEngine;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// This MonoBehaviour is a basic GUI for the Photon client's network-simulation feature.
|
||||
/// It can modify lag (fixed delay), jitter (random lag) and packet loss.
|
||||
/// </summary>
|
||||
/// \ingroup optionalGui
|
||||
public class PhotonNetSimSettingsGui : MonoBehaviour
|
||||
{
|
||||
/// <summary>Positioning rect for window.</summary>
|
||||
public Rect WindowRect = new Rect(0, 100, 120, 100);
|
||||
|
||||
/// <summary>Unity GUI Window ID (must be unique or will cause issues).</summary>
|
||||
public int WindowId = 101;
|
||||
|
||||
/// <summary>Shows or hides GUI (does not affect settings).</summary>
|
||||
public bool Visible = true;
|
||||
|
||||
/// <summary>The peer currently in use (to set the network simulation).</summary>
|
||||
public PhotonPeer Peer { get; set; }
|
||||
|
||||
public void Start()
|
||||
{
|
||||
this.Peer = PhotonNetwork.networkingPeer;
|
||||
}
|
||||
|
||||
public void OnGUI()
|
||||
{
|
||||
if (!this.Visible)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.Peer == null)
|
||||
{
|
||||
this.WindowRect = GUILayout.Window(this.WindowId, this.WindowRect, this.NetSimHasNoPeerWindow, "Netw. Sim.");
|
||||
}
|
||||
else
|
||||
{
|
||||
this.WindowRect = GUILayout.Window(this.WindowId, this.WindowRect, this.NetSimWindow, "Netw. Sim.");
|
||||
}
|
||||
}
|
||||
|
||||
private void NetSimHasNoPeerWindow(int windowId)
|
||||
{
|
||||
GUILayout.Label("No peer to communicate with. ");
|
||||
}
|
||||
|
||||
private void NetSimWindow(int windowId)
|
||||
{
|
||||
GUILayout.Label(string.Format("Rtt:{0,4} +/-{1,3}", this.Peer.RoundTripTime, this.Peer.RoundTripTimeVariance));
|
||||
|
||||
bool simEnabled = this.Peer.IsSimulationEnabled;
|
||||
bool newSimEnabled = GUILayout.Toggle(simEnabled, "Simulate");
|
||||
if (newSimEnabled != simEnabled)
|
||||
{
|
||||
this.Peer.IsSimulationEnabled = newSimEnabled;
|
||||
}
|
||||
|
||||
float inOutLag = this.Peer.NetworkSimulationSettings.IncomingLag;
|
||||
GUILayout.Label("Lag " + inOutLag);
|
||||
inOutLag = GUILayout.HorizontalSlider(inOutLag, 0, 500);
|
||||
|
||||
this.Peer.NetworkSimulationSettings.IncomingLag = (int)inOutLag;
|
||||
this.Peer.NetworkSimulationSettings.OutgoingLag = (int)inOutLag;
|
||||
|
||||
float inOutJitter = this.Peer.NetworkSimulationSettings.IncomingJitter;
|
||||
GUILayout.Label("Jit " + inOutJitter);
|
||||
inOutJitter = GUILayout.HorizontalSlider(inOutJitter, 0, 100);
|
||||
|
||||
this.Peer.NetworkSimulationSettings.IncomingJitter = (int)inOutJitter;
|
||||
this.Peer.NetworkSimulationSettings.OutgoingJitter = (int)inOutJitter;
|
||||
|
||||
float loss = this.Peer.NetworkSimulationSettings.IncomingLossPercentage;
|
||||
GUILayout.Label("Loss " + loss);
|
||||
loss = GUILayout.HorizontalSlider(loss, 0, 10);
|
||||
|
||||
this.Peer.NetworkSimulationSettings.IncomingLossPercentage = (int)loss;
|
||||
this.Peer.NetworkSimulationSettings.OutgoingLossPercentage = (int)loss;
|
||||
|
||||
// if anything was clicked, the height of this window is likely changed. reduce it to be layouted again next frame
|
||||
if (GUI.changed)
|
||||
{
|
||||
this.WindowRect.height = 100;
|
||||
}
|
||||
|
||||
GUI.DragWindow();
|
||||
}
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 20f0ed9761910c541857347b670699ca
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
+1683
@@ -0,0 +1,1683 @@
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// <copyright file="PhotonNetwork.cs" company="Exit Games GmbH">
|
||||
// Part of: Photon Unity Networking
|
||||
// </copyright>
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
using ExitGames.Client.Photon;
|
||||
using UnityEngine;
|
||||
|
||||
/// <summary>
|
||||
/// The main class to use the PhotonNetwork plugin.
|
||||
/// This class is static.
|
||||
/// </summary>
|
||||
/// \ingroup publicApi
|
||||
public static class PhotonNetwork
|
||||
{
|
||||
/// <summary>Version number of PUN. Also used in GameVersion to separate client version from each other.</summary>
|
||||
public const string versionPUN = "1.17";
|
||||
|
||||
/// <summary>
|
||||
/// This Monobehaviour allows Photon to run an Update loop.
|
||||
/// </summary>
|
||||
internal static readonly PhotonHandler photonMono;
|
||||
|
||||
/// <summary>
|
||||
/// Photon peer class that implements LoadBalancing in PUN.
|
||||
/// Primary use is internal (by PUN itself).
|
||||
/// </summary>
|
||||
internal static readonly NetworkingPeer networkingPeer;
|
||||
|
||||
/// <summary>
|
||||
/// The maximum amount of assigned PhotonViews PER player (or scene). See the documentation on how to raise this limitation
|
||||
/// </summary>
|
||||
public static readonly int MAX_VIEW_IDS = 1000; // VIEW & PLAYER LIMIT CAN BE EASILY CHANGED, SEE DOCS
|
||||
|
||||
/// <summary>Path to the PhotonServerSettings file.</summary>
|
||||
public const string serverSettingsAssetPath = "Assets/Photon Unity Networking/Resources/PhotonServerSettings.asset";
|
||||
|
||||
/// <summary>Serialized server settings, written by the Setup Wizard for use in ConnectUsingSettings.</summary>
|
||||
internal static ServerSettings PhotonServerSettings = (ServerSettings)Resources.Load(Path.GetFileNameWithoutExtension(PhotonNetwork.serverSettingsAssetPath), typeof(ServerSettings));
|
||||
|
||||
/// <summary>
|
||||
/// The minimum difference that a Vector2 or Vector3(e.g. a transforms rotation) needs to change before we send it via a PhotonView's OnSerialize/ObservingComponent
|
||||
/// Note that this is the sqrMagnitude. E.g. to send only after a 0.01 change on the Y-axix, we use 0.01f*0.01f=0.0001f. As a remedy against float inaccuracy we use 0.000099f instead of 0.0001f.
|
||||
/// </summary>
|
||||
public static float precisionForVectorSynchronization = 0.000099f;
|
||||
|
||||
/// <summary>
|
||||
/// The minimum angle that a rotation needs to change before we send it via a PhotonView's OnSerialize/ObservingComponent
|
||||
/// </summary>
|
||||
public static float precisionForQuaternionSynchronization = 1.0f;
|
||||
|
||||
/// <summary>
|
||||
/// The minimum difference between floats before we send it via a PhotonView's OnSerialize/ObservingComponent
|
||||
/// </summary>
|
||||
public static float precisionForFloatSynchronization = 0.01f;
|
||||
|
||||
|
||||
// "VARIABLES"
|
||||
|
||||
/// <summary>
|
||||
/// Are we connected to the photon server (can be IN or OUTSIDE a room)
|
||||
/// </summary>
|
||||
public static bool connected
|
||||
{
|
||||
get
|
||||
{
|
||||
if (offlineMode)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return connectionState == ConnectionState.Connected;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Simplified connection state
|
||||
/// </summary>
|
||||
public static ConnectionState connectionState
|
||||
{
|
||||
get
|
||||
{
|
||||
if (offlineMode)
|
||||
{
|
||||
return ConnectionState.Connected;
|
||||
}
|
||||
|
||||
if (networkingPeer == null)
|
||||
{
|
||||
return ConnectionState.Disconnected;
|
||||
}
|
||||
|
||||
switch (networkingPeer.PeerState)
|
||||
{
|
||||
case ExitGames.Client.Photon.PeerStateValue.Disconnected:
|
||||
return ConnectionState.Disconnected;
|
||||
case ExitGames.Client.Photon.PeerStateValue.Connecting:
|
||||
return ConnectionState.Connecting;
|
||||
case ExitGames.Client.Photon.PeerStateValue.Connected:
|
||||
return ConnectionState.Connected;
|
||||
case ExitGames.Client.Photon.PeerStateValue.Disconnecting:
|
||||
return ConnectionState.Disconnecting;
|
||||
case ExitGames.Client.Photon.PeerStateValue.InitializingApplication:
|
||||
return ConnectionState.InitializingApplication;
|
||||
}
|
||||
|
||||
return ConnectionState.Disconnected;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Detailed connection state (ignorant of PUN, so it can be "disconnected" while switching servers).
|
||||
/// </summary>
|
||||
public static PeerState connectionStateDetailed
|
||||
{
|
||||
get
|
||||
{
|
||||
if (offlineMode)
|
||||
{
|
||||
return PeerState.Connected;
|
||||
}
|
||||
|
||||
if (networkingPeer == null)
|
||||
{
|
||||
return PeerState.Disconnected;
|
||||
}
|
||||
|
||||
return networkingPeer.State;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the room we're currently in. Null if we aren't in any room.
|
||||
/// </summary>
|
||||
public static Room room
|
||||
{
|
||||
get
|
||||
{
|
||||
if (isOfflineMode)
|
||||
{
|
||||
if (offlineMode_inRoom)
|
||||
{
|
||||
return new Room("OfflineRoom", new Hashtable());
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return networkingPeer.mCurrentGame;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Network log level. Controls how verbose PUN is.
|
||||
/// </summary>
|
||||
public static PhotonLogLevel logLevel = PhotonLogLevel.ErrorsOnly;
|
||||
|
||||
/// <summary>
|
||||
/// The local PhotonPlayer. Always available and represents this player.
|
||||
/// CustomProperties can be set before entering a room and will be synced as well.
|
||||
/// </summary>
|
||||
public static PhotonPlayer player
|
||||
{
|
||||
get
|
||||
{
|
||||
if (networkingPeer == null)
|
||||
{
|
||||
return null; // Surpress ExitApplication errors
|
||||
}
|
||||
|
||||
return networkingPeer.mLocalActor;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The PhotonPlayer of the master client. The master client is the 'virtual owner' of the room. You can use it if you need authorative decision made by one of the players.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The masterClient is null until a room is joined and becomes null again when the room is left.
|
||||
/// </remarks>
|
||||
public static PhotonPlayer masterClient
|
||||
{
|
||||
get
|
||||
{
|
||||
if (networkingPeer == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return networkingPeer.mMasterClient;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This local player's name.
|
||||
/// </summary>
|
||||
/// <remarks>Setting the name will automatically send it, if connected. Setting null, won't change the name.</remarks>
|
||||
public static string playerName
|
||||
{
|
||||
get
|
||||
{
|
||||
return networkingPeer.PlayerName;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
networkingPeer.PlayerName = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The full PhotonPlayer list, including the local player.
|
||||
/// </summary>
|
||||
public static PhotonPlayer[] playerList
|
||||
{
|
||||
get
|
||||
{
|
||||
if (networkingPeer == null)
|
||||
return new PhotonPlayer[0];
|
||||
|
||||
return networkingPeer.mPlayerListCopy;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The other PhotonPlayers, not including our local player.
|
||||
/// </summary>
|
||||
public static PhotonPlayer[] otherPlayers
|
||||
{
|
||||
get
|
||||
{
|
||||
if (networkingPeer == null)
|
||||
return new PhotonPlayer[0];
|
||||
|
||||
return networkingPeer.mOtherPlayerListCopy;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Offline mode can be set to re-use your multiplayer code in singleplayer game modes.
|
||||
/// When this is on PhotonNetwork will not create any connections and there is near to
|
||||
/// no overhead. Mostly usefull for reusing RPC's and PhotonNetwork.Instantiate
|
||||
/// </summary>
|
||||
public static bool offlineMode
|
||||
{
|
||||
get
|
||||
{
|
||||
return isOfflineMode;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
if (value == isOfflineMode)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (value && connected)
|
||||
{
|
||||
Debug.LogError("Can't start OFFLINE mode while connected!");
|
||||
}
|
||||
else
|
||||
{
|
||||
networkingPeer.Disconnect(); // Cleanup (also calls OnLeftRoom to reset stuff)
|
||||
isOfflineMode = value;
|
||||
if (isOfflineMode)
|
||||
{
|
||||
NetworkingPeer.SendMonoMessage(PhotonNetworkingMessage.OnConnectedToPhoton);
|
||||
networkingPeer.ChangeLocalID(1);
|
||||
networkingPeer.mMasterClient = player;
|
||||
}
|
||||
else
|
||||
{
|
||||
networkingPeer.ChangeLocalID(-1);
|
||||
networkingPeer.mMasterClient = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static bool isOfflineMode = false;
|
||||
|
||||
private static bool offlineMode_inRoom = false;
|
||||
|
||||
/// <summary>
|
||||
/// The maximum number of players for a room. Better: Set it in CreateRoom.
|
||||
/// If no room is opened, this will return 0.
|
||||
/// </summary>
|
||||
[System.Obsolete("Used for compatibility with Unity networking only.")]
|
||||
public static int maxConnections
|
||||
{
|
||||
get
|
||||
{
|
||||
if (room == null)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return (int)room.maxPlayers;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
room.maxPlayers = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This setting defines if players in a room should destroy a leaving player's instantiated GameObjects and PhotonViews.
|
||||
///
|
||||
/// When "this client" creates a room/game, autoCleanUpPlayerObjects is copied to that room's properties and used by all
|
||||
/// PUN clients in that room (no matter what their autoCleanUpPlayerObjects value is).
|
||||
///
|
||||
/// If room.AutoCleanUp is enabled in a room, the PUN clients will destroy a player's objects on leave.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// When enabled, the server will clean RPCs, instantiated GameObjects and PhotonViews of the leaving player and joining
|
||||
/// players won't get those at anymore.
|
||||
///
|
||||
/// Once a room is created, this setting can't be changed anymore.
|
||||
///
|
||||
/// Enabled by default.
|
||||
/// </remarks>
|
||||
public static bool autoCleanUpPlayerObjects
|
||||
{
|
||||
get
|
||||
{
|
||||
return m_autoCleanUpPlayerObjects;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (room != null)
|
||||
Debug.LogError("Setting autoCleanUpPlayerObjects while in a room is not supported.");
|
||||
m_autoCleanUpPlayerObjects = value;
|
||||
}
|
||||
}
|
||||
|
||||
private static bool m_autoCleanUpPlayerObjects = true;
|
||||
|
||||
/// <summary>
|
||||
/// Defines if the PhotonNetwork should join the "lobby" when connected to the Master server.
|
||||
/// If this is false, OnConnectedToMaster() will be called when connection to the Master is available.
|
||||
/// OnJoinedLobby() will NOT be called if this is false.
|
||||
///
|
||||
/// Enabled by default.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The room listing will not become available.
|
||||
/// Rooms can be created and joined (randomly) without joining the lobby (and getting sent the room list).
|
||||
/// </remarks>
|
||||
public static bool autoJoinLobby
|
||||
{
|
||||
get
|
||||
{
|
||||
return autoJoinLobbyField;
|
||||
}
|
||||
set
|
||||
{
|
||||
autoJoinLobbyField = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Backing field.
|
||||
/// </summary>
|
||||
private static bool autoJoinLobbyField = true;
|
||||
|
||||
/// <summary>
|
||||
/// Returns true when we are connected to Photon and in the lobby state
|
||||
/// </summary>
|
||||
public static bool insideLobby
|
||||
{
|
||||
get
|
||||
{
|
||||
return networkingPeer.insideLobby;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Defines how many times per second PhotonNetwork should send a package. If you change
|
||||
/// this, do not forget to also change 'sendRateOnSerialize'.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Less packages are less overhead but more delay.
|
||||
/// Setting the sendRate to 50 will create up to 50 packages per second (which is a lot!).
|
||||
/// Keep your target platform in mind: mobile networks are slower and less reliable.
|
||||
/// </remarks>
|
||||
public static int sendRate
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1000 / sendInterval;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
sendInterval = 1000 / value;
|
||||
if (photonMono != null)
|
||||
{
|
||||
photonMono.updateInterval = sendInterval;
|
||||
}
|
||||
|
||||
if (value < sendRateOnSerialize)
|
||||
{
|
||||
// sendRateOnSerialize needs to be <= sendRate
|
||||
sendRateOnSerialize = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Defines how many times per second OnPhotonSerialize should be called on PhotonViews.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Choose this value in relation to 'sendRate'. OnPhotonSerialize will creart the commands to be put into packages.
|
||||
/// A lower rate takes up less performance but will cause more lag.
|
||||
/// </remarks>
|
||||
public static int sendRateOnSerialize
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1000 / sendIntervalOnSerialize;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
if (value > sendRate)
|
||||
{
|
||||
Debug.LogError("Error, can not set the OnSerialize SendRate more often then the overall SendRate");
|
||||
value = sendRate;
|
||||
}
|
||||
|
||||
sendIntervalOnSerialize = 1000 / value;
|
||||
if (photonMono != null)
|
||||
{
|
||||
photonMono.updateIntervalOnSerialize = sendIntervalOnSerialize;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static int sendInterval = 50;
|
||||
|
||||
private static int sendIntervalOnSerialize = 100;
|
||||
|
||||
/// <summary>
|
||||
/// Can be used to pause dispatch of incoming evtents (RPCs, Instantiates and anything else incoming).
|
||||
/// This can be useful if you first want to load a level, then go on receiving data of PhotonViews and RPCs.
|
||||
/// The client will go on receiving and sending acknowledgements for incoming packages and your RPCs/Events.
|
||||
/// This adds "lag" and can cause issues when the pause is longer, as all incoming messages are just queued.
|
||||
/// </summary>
|
||||
public static bool isMessageQueueRunning
|
||||
{
|
||||
get
|
||||
{
|
||||
return m_isMessageQueueRunning;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
if (value == m_isMessageQueueRunning)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
PhotonNetwork.networkingPeer.IsSendingOnlyAcks = !value;
|
||||
m_isMessageQueueRunning = value;
|
||||
if (!value)
|
||||
{
|
||||
PhotonHandler.StartThread(); // Background loading thread: keeps connection alive
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Backup for property isMessageQueueRunning.</summary>
|
||||
private static bool m_isMessageQueueRunning = true;
|
||||
|
||||
/// <summary>
|
||||
/// Used once per dispatch to limit unreliable commands per channel (so after a pause, many channels can still cause a lot of unreliable commands)
|
||||
/// </summary>
|
||||
public static int unreliableCommandsLimit
|
||||
{
|
||||
get
|
||||
{
|
||||
return networkingPeer.LimitOfUnreliableCommands;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
networkingPeer.LimitOfUnreliableCommands = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Photon network time, synched with the server
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// v1.3:
|
||||
/// This time reflects milliseconds since start of the server, cut down to 4 bytes.
|
||||
/// It will overflow every 49 days from a high value to 0. We do not (yet) compensate this overflow.
|
||||
/// Master- and Game-Server will have different time values.
|
||||
/// v1.10:
|
||||
/// Fixed issues with precision for high server-time values. This should update with 15ms precision by default.
|
||||
/// </remarks>
|
||||
public static double time
|
||||
{
|
||||
get
|
||||
{
|
||||
if (offlineMode)
|
||||
{
|
||||
return Time.time;
|
||||
}
|
||||
else
|
||||
{
|
||||
return ((double)(uint)networkingPeer.ServerTimeInMilliSeconds) / 1000.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Are we the master client?
|
||||
/// </summary>
|
||||
public static bool isMasterClient
|
||||
{
|
||||
get
|
||||
{
|
||||
if (offlineMode)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return networkingPeer.mMasterClient == networkingPeer.mLocalActor;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// True if we are in a room (client) and NOT the room's masterclient
|
||||
/// </summary>
|
||||
public static bool isNonMasterClientInRoom
|
||||
{
|
||||
get
|
||||
{
|
||||
return !isMasterClient && room != null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The count of players currently looking for a room.
|
||||
/// This is updated on the MasterServer (only) in 5sec intervals (if any count changed).
|
||||
/// </summary>
|
||||
public static int countOfPlayersOnMaster
|
||||
{
|
||||
get
|
||||
{
|
||||
return networkingPeer.mMasterCount;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The count of players currently inside a room
|
||||
/// This is updated on the MasterServer (only) in 5sec intervals (if any count changed).
|
||||
/// </summary>
|
||||
public static int countOfPlayersInRooms
|
||||
{
|
||||
get
|
||||
{
|
||||
return countOfPlayers;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The count of players currently using this application.
|
||||
/// This is updated on the MasterServer (only) in 5sec intervals (if any count changed).
|
||||
/// </summary>
|
||||
public static int countOfPlayers
|
||||
{
|
||||
get
|
||||
{
|
||||
return networkingPeer.mPeerCount + networkingPeer.mMasterCount;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The count of rooms currently in use.
|
||||
/// When inside the lobby this is based on PhotonNetwork.GetRoomList().Length.
|
||||
/// When not inside the lobby, this value updated on the MasterServer (only) in 5sec intervals (if any count changed).
|
||||
/// </summary>
|
||||
public static int countOfRooms
|
||||
{
|
||||
get
|
||||
{
|
||||
if (insideLobby)
|
||||
{
|
||||
return GetRoomList().Length;
|
||||
}
|
||||
else
|
||||
{
|
||||
return networkingPeer.mGameCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enables or disables the collection of statistics about this client's traffic.
|
||||
/// If you encounter issues with clients, the traffic stats are a good starting point to find solutions.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Only with enabled stats, you can use GetVitalStats
|
||||
/// </remarks>
|
||||
public static bool NetworkStatisticsEnabled
|
||||
{
|
||||
get
|
||||
{
|
||||
return networkingPeer.TrafficStatsEnabled;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
networkingPeer.TrafficStatsEnabled = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resets the traffic stats and re-enables them.
|
||||
/// </summary>
|
||||
public static void NetworkStatisticsReset()
|
||||
{
|
||||
networkingPeer.TrafficStatsReset();
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Only available when NetworkStatisticsEnabled was used to gather some stats.
|
||||
/// </summary>
|
||||
/// <returns>A string with vital networking statistics.</returns>
|
||||
public static string NetworkStatisticsToString()
|
||||
{
|
||||
if (networkingPeer == null || offlineMode)
|
||||
{
|
||||
return "Offline or in OfflineMode. No VitalStats available.";
|
||||
}
|
||||
|
||||
return networkingPeer.VitalStatsToString(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Static constructor used for basic setup.
|
||||
/// </summary>
|
||||
static PhotonNetwork()
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
if (!UnityEditor.EditorApplication.isPlaying || !UnityEditor.EditorApplication.isPlayingOrWillChangePlaymode)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// This can happen when you recompile a script IN play made
|
||||
// This helps to surpress some errors, but will not fix breaking
|
||||
bool doubleInstall = false;
|
||||
GameObject pGO = GameObject.Find("PhotonMono");
|
||||
doubleInstall = pGO != null;
|
||||
if (doubleInstall)
|
||||
{
|
||||
GameObject.Destroy(pGO);
|
||||
Debug.LogWarning("The Unity recompile forced a restart of UnityPhoton!");
|
||||
}
|
||||
|
||||
#endif
|
||||
Application.runInBackground = true;
|
||||
|
||||
// Set up a MonoBheaviour to run Photon, and hide it.
|
||||
GameObject photonGO = new GameObject();
|
||||
photonMono = (PhotonHandler)photonGO.AddComponent<PhotonHandler>();
|
||||
photonGO.name = "PhotonMono";
|
||||
photonGO.hideFlags = UnityEngine.HideFlags.HideInHierarchy;
|
||||
|
||||
// Set up the NetworkingPeer
|
||||
networkingPeer = new NetworkingPeer(photonMono, string.Empty, ExitGames.Client.Photon.ConnectionProtocol.Udp);
|
||||
networkingPeer.LimitOfUnreliableCommands = 20;
|
||||
|
||||
// Local player
|
||||
CustomTypes.Register();
|
||||
}
|
||||
|
||||
// FUNCTIONS
|
||||
|
||||
/// <summary>
|
||||
/// Connect to the configured Photon server:
|
||||
/// Reads PhotonNetwork.serverSettingsAssetPath and connects to cloud or your own server.
|
||||
/// Uses: Connect(string serverAddress, int port, string appID, string gameVersion)
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The PUN Setup Wizard stores your appID in a settings file and applies a server address/port, too.
|
||||
/// </remarks>
|
||||
/// <param name="gameVersion">This client's version number. Users are separated from each other by gameversion (which allows you to make breaking changes).</param>
|
||||
public static void ConnectUsingSettings(string gameVersion)
|
||||
{
|
||||
if (PhotonServerSettings == null)
|
||||
{
|
||||
Debug.LogError("Loading the settings file failed. Check path: " + PhotonNetwork.serverSettingsAssetPath);
|
||||
return;
|
||||
}
|
||||
if (PhotonServerSettings.HostType == ServerSettings.HostingOption.OfflineMode)
|
||||
{
|
||||
offlineMode = true;
|
||||
return;//
|
||||
}
|
||||
else
|
||||
{
|
||||
Connect(PhotonServerSettings.ServerAddress, PhotonServerSettings.ServerPort, PhotonServerSettings.AppID, gameVersion);
|
||||
}
|
||||
}
|
||||
|
||||
[System.Obsolete("This method is obsolete; use ConnectUsingSettings with the gameVersion argument instead")]
|
||||
public static void ConnectUsingSettings()
|
||||
{
|
||||
ConnectUsingSettings("1.0");
|
||||
}
|
||||
|
||||
[System.Obsolete("This method is obsolete; use Connect with the gameVersion argument instead")]
|
||||
public static void Connect(string serverAddress, int port, string uniqueGameID)
|
||||
{
|
||||
Connect(serverAddress, port, uniqueGameID, "1.0");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Connect to the photon server by address, port, appID and game(client) version.
|
||||
/// This method is used by ConnectUsingSettings which applies values from the settings file.
|
||||
/// </summary>
|
||||
/// <param name="serverAddress">The master server's address (either your own or Photon Cloud address).</param>
|
||||
/// <param name="port">The master server's port to connect to.</param>
|
||||
/// <param name="appID">Your application ID (Photon Cloud provides you with a GUID for your game).</param>
|
||||
/// <param name="gameVersion">This client's version number. Users are separated from each other by gameversion (which allows you to make breaking changes).</param>
|
||||
public static void Connect(string serverAddress, int port, string appID, string gameVersion)
|
||||
{
|
||||
if (port <= 0)
|
||||
{
|
||||
Debug.LogError("Aborted Connect: invalid port: " + port);
|
||||
return;
|
||||
}
|
||||
|
||||
if (serverAddress.Length <= 2)
|
||||
{
|
||||
Debug.LogError("Aborted Connect: invalid serverAddress: " + serverAddress);
|
||||
return;
|
||||
}
|
||||
|
||||
if (networkingPeer.PeerState != PeerStateValue.Disconnected)
|
||||
{
|
||||
Debug.LogWarning("Connect() only works when disconnected. Current state: " + networkingPeer.PeerState);
|
||||
return;
|
||||
}
|
||||
|
||||
if (offlineMode)
|
||||
{
|
||||
offlineMode = false; // Cleanup offline mode
|
||||
Debug.LogWarning("Shut down offline mode due to a connect attempt");
|
||||
}
|
||||
|
||||
if (!isMessageQueueRunning)
|
||||
{
|
||||
isMessageQueueRunning = true;
|
||||
Debug.LogWarning("Forced enabling of isMessageQueueRunning because of a Connect()");
|
||||
}
|
||||
|
||||
serverAddress = serverAddress + ":" + port;
|
||||
|
||||
//Debug.Log("Connecting to: " + serverAddress + " app: " + uniqueGameID);
|
||||
networkingPeer.mAppVersion = gameVersion + versionPUN;
|
||||
networkingPeer.Connect(serverAddress, appID, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Disconnect from the photon server (also leaves your multiplayer room, if any).
|
||||
/// OnDisconnectedFromPhoton is called when the disconnect is completed. Then you can re-connect.
|
||||
/// </summary>
|
||||
public static void Disconnect()
|
||||
{
|
||||
if (networkingPeer == null)
|
||||
{
|
||||
return; // Surpress error when quitting playmode in the editor
|
||||
}
|
||||
|
||||
networkingPeer.Disconnect();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Used for compatibility with Unity networking only. Encryption is automatically initialized while connecting.
|
||||
/// </summary>
|
||||
[System.Obsolete("Used for compatibility with Unity networking only. Encryption is automatically initialized while connecting.")]
|
||||
public static void InitializeSecurity()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a room with given name but fails if this room is existing already.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// If you don't want to create a unique room-name, pass null or "" as name and the server will assign a roomName (a GUID as string).
|
||||
/// Call this only on the master server.
|
||||
/// Internally, the master will respond with a server-address (and roomName, if needed). Both are used internally
|
||||
/// to switch to the assigned game server and roomName.
|
||||
///
|
||||
/// PhotonNetwork.autoCleanUpPlayerObjects will become this room's AutoCleanUp property and that's used by all clients that join this room.
|
||||
/// </remarks>
|
||||
/// <param name="roomName">Unique name of the room to create.</param>
|
||||
public static void CreateRoom(string roomName)
|
||||
{
|
||||
Debug.Log("this custom props " + player.customProperties.ToStringFull());
|
||||
if (connectionStateDetailed == PeerState.ConnectedToGameserver || connectionStateDetailed == PeerState.Joining || connectionStateDetailed == PeerState.Joined)
|
||||
{
|
||||
Debug.LogError("CreateRoom aborted: You are already connecting to a room!");
|
||||
}
|
||||
else if (room != null)
|
||||
{
|
||||
Debug.LogError("CreateRoom aborted: You are already in a room!");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (offlineMode)
|
||||
{
|
||||
offlineMode_inRoom = true;
|
||||
NetworkingPeer.SendMonoMessage(PhotonNetworkingMessage.OnCreatedRoom);
|
||||
NetworkingPeer.SendMonoMessage(PhotonNetworkingMessage.OnJoinedRoom);
|
||||
}
|
||||
else
|
||||
{
|
||||
networkingPeer.OpCreateGame(roomName, true, true, 0, PhotonNetwork.autoCleanUpPlayerObjects, null, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a room with given name but fails if this room is existing already.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// If you don't want to create a unique room-name, pass null or "" as name and the server will assign a roomName (a GUID as string).
|
||||
/// Call this only on the master server.
|
||||
/// Internally, the master will respond with a server-address (and roomName, if needed). Both are used internally
|
||||
/// to switch to the assigned game server and roomName
|
||||
/// </remarks>
|
||||
/// <param name="roomName">Unique name of the room to create. Pass null or "" to make the server generate a name.</param>
|
||||
/// <param name="isVisible">Shows (or hides) this room from the lobby's listing of rooms.</param>
|
||||
/// <param name="isOpen">Allows (or disallows) others to join this room.</param>
|
||||
/// <param name="maxPlayers">Max number of players that can join the room.</param>
|
||||
public static void CreateRoom(string roomName, bool isVisible, bool isOpen, int maxPlayers)
|
||||
{
|
||||
CreateRoom(roomName, isVisible, isOpen, maxPlayers, null, null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a room with given name but fails if this room is existing already.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// If you don't want to create a unique room-name, pass null or "" as name and the server will assign a roomName (a GUID as string).
|
||||
/// Call this only on the master server.
|
||||
/// Internally, the master will respond with a server-address (and roomName, if needed). Both are used internally
|
||||
/// to switch to the assigned game server and roomName.
|
||||
///
|
||||
/// PhotonNetwork.autoCleanUpPlayerObjects will become this room's AutoCleanUp property and that's used by all clients that join this room.
|
||||
/// </remarks>
|
||||
/// <param name="roomName">Unique name of the room to create. Pass null or "" to make the server generate a name.</param>
|
||||
/// <param name="isVisible">Shows (or hides) this room from the lobby's listing of rooms.</param>
|
||||
/// <param name="isOpen">Allows (or disallows) others to join this room.</param>
|
||||
/// <param name="maxPlayers">Max number of players that can join the room.</param>
|
||||
/// <param name="customRoomProperties">Custom properties of the new room (set on create, so they are immediately available).</param>
|
||||
/// <param name="propsToListInLobby">Array of custom-property-names that should be forwarded to the lobby (include only the useful ones).</param>
|
||||
public static void CreateRoom(string roomName, bool isVisible, bool isOpen, int maxPlayers, Hashtable customRoomProperties, string[] propsToListInLobby)
|
||||
{
|
||||
if (connectionStateDetailed == PeerState.Joining || connectionStateDetailed == PeerState.Joined || connectionStateDetailed == PeerState.ConnectedToGameserver)
|
||||
{
|
||||
Debug.LogError("CreateRoom aborted: You can only create a room while not currently connected/connecting to a room.");
|
||||
}
|
||||
else if (room != null)
|
||||
{
|
||||
Debug.LogError("CreateRoom aborted: You are already in a room!");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (offlineMode)
|
||||
{
|
||||
offlineMode_inRoom = true;
|
||||
NetworkingPeer.SendMonoMessage(PhotonNetworkingMessage.OnCreatedRoom);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (maxPlayers > 255)
|
||||
{
|
||||
Debug.LogError("Error: CreateRoom called with " + maxPlayers + " maxplayers. This has been reverted to the max of 255 players because internally a 'byte' is used.");
|
||||
maxPlayers = 255;
|
||||
}
|
||||
|
||||
networkingPeer.OpCreateGame(roomName, isVisible, isOpen, (byte)maxPlayers, PhotonNetwork.autoCleanUpPlayerObjects, customRoomProperties, propsToListInLobby);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Join room by room.Name.
|
||||
/// This fails if the room is either full or no longer available (might close at the same time).
|
||||
/// </summary>
|
||||
/// <param name="roomName">The room instance to join (only listedRoom.Name is used).</param>
|
||||
public static void JoinRoom(RoomInfo listedRoom)
|
||||
{
|
||||
if (listedRoom == null)
|
||||
{
|
||||
Debug.LogError("JoinRoom aborted: you passed a NULL room");
|
||||
return;
|
||||
}
|
||||
|
||||
JoinRoom(listedRoom.name);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Join room with given title.
|
||||
/// This fails if the room is either full or no longer available (might close at the same time).
|
||||
/// </summary>
|
||||
/// <param name="roomName">Unique name of the room to create.</param>
|
||||
public static void JoinRoom(string roomName)
|
||||
{
|
||||
if (connectionStateDetailed == PeerState.Joining || connectionStateDetailed == PeerState.Joined || connectionStateDetailed == PeerState.ConnectedToGameserver)
|
||||
{
|
||||
Debug.LogError("JoinRoom aborted: You can only join a room while not currently connected/connecting to a room.");
|
||||
}
|
||||
else if (room != null)
|
||||
{
|
||||
Debug.LogError("JoinRoom aborted: You are already in a room!");
|
||||
}
|
||||
else if (roomName == string.Empty)
|
||||
{
|
||||
Debug.LogError("JoinRoom aborted: You must specifiy a room name!");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (offlineMode)
|
||||
{
|
||||
offlineMode_inRoom = true;
|
||||
NetworkingPeer.SendMonoMessage(PhotonNetworkingMessage.OnJoinedRoom);
|
||||
}
|
||||
else
|
||||
{
|
||||
networkingPeer.OpJoin(roomName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Joins any available room but will fail if none is currently available.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// If this fails, you can still create a room (and make this available for the next who uses JoinRandomRoom).
|
||||
/// Alternatively, try again in a moment.
|
||||
/// </remarks>
|
||||
public static void JoinRandomRoom()
|
||||
{
|
||||
JoinRandomRoom(null, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to join an open room with fitting, custom properties but fails if none is currently available.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// If this fails, you can still create a room (and make this available for the next who uses JoinRandomRoom).
|
||||
/// Alternatively, try again in a moment.
|
||||
/// </remarks>
|
||||
/// <param name="expectedCustomRoomProperties">Filters for rooms that match these custom properties (string keys and values). To ignore, pass null.</param>
|
||||
/// <param name="expectedMaxPlayers">Filters for a particular maxplayer setting. Use 0 to accept any maxPlayer value.</param>
|
||||
public static void JoinRandomRoom(Hashtable expectedCustomRoomProperties, byte expectedMaxPlayers)
|
||||
{
|
||||
if (connectionStateDetailed == PeerState.Joining || connectionStateDetailed == PeerState.Joined || connectionStateDetailed == PeerState.ConnectedToGameserver)
|
||||
{
|
||||
Debug.LogError("JoinRandomRoom aborted: You can only join a room while not currently connected/connecting to a room.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (room != null)
|
||||
{
|
||||
Debug.LogError("JoinRandomRoom aborted: You are already in a room!");
|
||||
return;
|
||||
}
|
||||
|
||||
if (offlineMode)
|
||||
{
|
||||
offlineMode_inRoom = true;
|
||||
NetworkingPeer.SendMonoMessage(PhotonNetworkingMessage.OnJoinedRoom);
|
||||
}
|
||||
else
|
||||
{
|
||||
Hashtable expectedRoomProperties = new Hashtable();
|
||||
expectedRoomProperties.MergeStringKeys(expectedCustomRoomProperties);
|
||||
if (expectedMaxPlayers > 0)
|
||||
{
|
||||
expectedRoomProperties[GameProperties.MaxPlayers] = expectedMaxPlayers;
|
||||
}
|
||||
|
||||
networkingPeer.OpJoinRandomRoom(expectedRoomProperties);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Leave the current room
|
||||
/// </summary>
|
||||
public static void LeaveRoom()
|
||||
{
|
||||
if (!offlineMode && PhotonNetwork.connectionStateDetailed != PeerState.Joined)
|
||||
{
|
||||
UnityEngine.Debug.LogError("PhotonNetwork: Error, you cannot leave a room if you're not in a room!(1)");
|
||||
return;
|
||||
}
|
||||
else if (room == null)
|
||||
{
|
||||
UnityEngine.Debug.LogError("PhotonNetwork: Error, you cannot leave a room if you're not in a room!(2)");
|
||||
return;
|
||||
}
|
||||
|
||||
if (offlineMode)
|
||||
{
|
||||
offlineMode_inRoom = false;
|
||||
NetworkingPeer.SendMonoMessage(PhotonNetworkingMessage.OnLeftRoom);
|
||||
}
|
||||
else
|
||||
{
|
||||
networkingPeer.OpLeave();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets an array of (currently) known rooms as RoomInfo.
|
||||
/// This list is automatically updated every few seconds while this client is in the lobby (on the Master Server).
|
||||
/// Not available while being in a room.
|
||||
/// </summary>
|
||||
/// <remarks>Creates a new instance of the list each time called. Copied from networkingPeer.mGameList.</remarks>
|
||||
/// <returns>RoomInfo[] of current rooms in lobby.</returns>
|
||||
public static RoomInfo[] GetRoomList()
|
||||
{
|
||||
if (offlineMode)
|
||||
{
|
||||
return new RoomInfo[0];
|
||||
}
|
||||
|
||||
if (networkingPeer == null)
|
||||
{
|
||||
return new RoomInfo[0]; // Surpress erorrs when quitting game
|
||||
}
|
||||
|
||||
return networkingPeer.mGameListCopy;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets this (local) player's properties.
|
||||
/// This caches the properties in PhotonNetwork.player.customProperties.
|
||||
/// CreateRoom, JoinRoom and JoinRandomRoom will all apply your player's custom properties when you enter the room.
|
||||
/// While in a room, your properties are synced with the other players.
|
||||
/// If the Hashtable is null, the custom properties will be cleared.
|
||||
/// Custom properties are never cleared automatically, so they carry over to the next room, if you don't change them.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Don't set properties by modifying PhotonNetwork.player.customProperties!
|
||||
/// </remarks>
|
||||
/// <param name="customProperties">Only string-typed keys will be used from this hashtable. If null, custom properties are all deleted.</param>
|
||||
public static void SetPlayerCustomProperties(Hashtable customProperties)
|
||||
{
|
||||
if (customProperties == null)
|
||||
{
|
||||
customProperties = new Hashtable();
|
||||
foreach (object k in PhotonNetwork.player.customProperties.Keys)
|
||||
{
|
||||
customProperties[(string)k] = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (room != null && room.isLocalClientInside)
|
||||
{
|
||||
player.SetCustomProperties(customProperties);
|
||||
}
|
||||
else
|
||||
{
|
||||
player.InternalCacheProperties(customProperties);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Request a new viewID for the local player to manually instantiate and destroy networked objects.
|
||||
/// </summary>
|
||||
/// <returns>New ViewId belonging to this player.</returns>
|
||||
public static PhotonViewID AllocateViewID()
|
||||
{
|
||||
// int playerID = player.ID;
|
||||
int newID = 0;
|
||||
while (networkingPeer.allocatedIDs.ContainsKey(newID))
|
||||
{
|
||||
newID++;
|
||||
}
|
||||
|
||||
if (newID >= MAX_VIEW_IDS)
|
||||
{
|
||||
Debug.LogError("ERROR: Too many view IDs used!");
|
||||
newID = 0;
|
||||
}
|
||||
|
||||
int ID = newID;
|
||||
PhotonViewID viewID = new PhotonViewID(ID, player);
|
||||
|
||||
networkingPeer.allocatedIDs.Add(newID, viewID);
|
||||
return viewID;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unregister a view ID (of manually instantiated and destroyed networked objects).
|
||||
/// </summary>
|
||||
/// <param name="viewID">PhotonViewID instance</param>
|
||||
public static void UnAllocateViewID(PhotonViewID viewID)
|
||||
{
|
||||
UnAllocateViewID(viewID.ID % MAX_VIEW_IDS); //We need only the last bit, not the actor info (actor changes per room)
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unregister a view ID (of manually instantiated and destroyed networked objects).
|
||||
/// </summary>
|
||||
/// <param name="ID">ID of a PhotonView of this player.</param>
|
||||
static void UnAllocateViewID(int ID)
|
||||
{
|
||||
networkingPeer.allocatedIDs.Remove(ID);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Instantiate a prefab over the network. This prefab needs to be located in the root of a "Resources" folder.
|
||||
/// </summary>
|
||||
/// <remarks>Instead of using prefabs in the Resources folder, you can manually Instantiate and assign PhotonViews. See doc.</remarks>
|
||||
/// <param name="prefabName">Name of the prefab to instantiate.</param>
|
||||
/// <param name="position">Position Vector3 to apply on instantiation.</param>
|
||||
/// <param name="rotation">Rotation Quaternion to apply on instantiation.</param>
|
||||
/// <param name="group">The group for this PhotonView.</param>
|
||||
/// <returns>The new instance of a GameObject with initialized PhotonView.</returns>
|
||||
public static GameObject Instantiate(string prefabName, Vector3 position, Quaternion rotation, int group)
|
||||
{
|
||||
return Instantiate(prefabName, position, rotation, group, null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Instantiate a prefab over the network. This prefab needs to be located in the root of a "Resources" folder.
|
||||
/// </summary>
|
||||
/// <remarks>Instead of using prefabs in the Resources folder, you can manually Instantiate and assign PhotonViews. See doc.</remarks>
|
||||
/// <param name="prefabName">Name of the prefab to instantiate.</param>
|
||||
/// <param name="position">Position Vector3 to apply on instantiation.</param>
|
||||
/// <param name="rotation">Rotation Quaternion to apply on instantiation.</param>
|
||||
/// <param name="group">The group for this PhotonView.</param>
|
||||
/// <param name="data">Optional instantiation data. This will be saved to it's PhotonView.instantiationData.</param>
|
||||
/// <returns>The new instance of a GameObject with initialized PhotonView.</returns>
|
||||
public static GameObject Instantiate(string prefabName, Vector3 position, Quaternion rotation, int group, object[] data)
|
||||
{
|
||||
if (!VerifyCanUseNetwork())
|
||||
{
|
||||
Debug.LogError("PhotonNetwork error: Could not Instantiate the prefab [" + prefabName + "] as the game is not connected.");
|
||||
return null;
|
||||
}
|
||||
|
||||
GameObject prefabGo = (GameObject)Resources.Load(prefabName, typeof(GameObject));
|
||||
if (prefabGo == null)
|
||||
{
|
||||
Debug.LogError("PhotonNetwork error: Could not Instantiate the prefab [" + prefabName + "]. Please verify you have this gameobject in a Resources folder (and not in a subfolder)");
|
||||
return null;
|
||||
}
|
||||
|
||||
if (prefabGo.GetComponent<PhotonView>() == null)
|
||||
{
|
||||
Debug.LogError("PhotonNetwork error: Could not Instantiate the prefab [" + prefabName + "] as it has no PhotonView attached to the root.");
|
||||
return null;
|
||||
}
|
||||
|
||||
Component[] views = (Component[])prefabGo.GetComponentsInChildren<PhotonView>(true);
|
||||
PhotonViewID[] viewIDs = new PhotonViewID[views.Length];
|
||||
for (int i = 0; i < viewIDs.Length; i++)
|
||||
{
|
||||
viewIDs[i] = AllocateViewID();
|
||||
}
|
||||
|
||||
// Send to others, create info
|
||||
Hashtable instantiateEvent = networkingPeer.SendInstantiate(prefabName, position, rotation, group, viewIDs, data, false);
|
||||
|
||||
// Instantiate the GO locally (but the same way as if it was done via event). This will also cache the instantiationId
|
||||
return networkingPeer.DoInstantiate(instantiateEvent, networkingPeer.mLocalActor, prefabGo);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Instantiate a scene-owned prefab over the network. The PhotonViews will be controllable by the MasterClient. This prefab needs to be located in the root of a "Resources" folder.
|
||||
/// </summary>
|
||||
/// <remarks>Instead of using prefabs in the Resources folder, you can manually Instantiate and assign PhotonViews. See doc.</remarks>
|
||||
/// <param name="prefabName">Name of the prefab to instantiate.</param>
|
||||
/// <param name="position">Position Vector3 to apply on instantiation.</param>
|
||||
/// <param name="rotation">Rotation Quaternion to apply on instantiation.</param>
|
||||
/// <param name="group">The group for this PhotonView.</param>
|
||||
/// <param name="data">Optional instantiation data. This will be saved to it's PhotonView.instantiationData.</param>
|
||||
/// <returns>The new instance of a GameObject with initialized PhotonView.</returns>
|
||||
public static GameObject InstantiateSceneObject(string prefabName, Vector3 position, Quaternion rotation, int group, object[] data)
|
||||
{
|
||||
if (!VerifyCanUseNetwork())
|
||||
{
|
||||
return null;
|
||||
}
|
||||
if (!isMasterClient)
|
||||
{
|
||||
Debug.LogError("PhotonNetwork error [InstantiateSceneObject]: Only the master client can Instantiate scene objects");
|
||||
return null;
|
||||
}
|
||||
|
||||
GameObject prefabGo = (GameObject)Resources.Load(prefabName, typeof(GameObject));
|
||||
if (prefabGo == null)
|
||||
{
|
||||
Debug.LogError("PhotonNetwork error [InstantiateSceneObject]: Could not Instantiate the prefab [" + prefabName + "]. Please verify you have this gameobject in a Resources folder (and not in a subfolder)");
|
||||
return null;
|
||||
}
|
||||
|
||||
// a scene object instantiated with network visibility has to contain a PhotonView
|
||||
if (prefabGo.GetComponent<PhotonView>() == null)
|
||||
{
|
||||
Debug.LogError("PhotonNetwork error [InstantiateSceneObject]: Could not Instantiate the prefab [" + prefabName + "] as it has no PhotonView attached to the root.");
|
||||
return null;
|
||||
}
|
||||
|
||||
Component[] views = (Component[])prefabGo.GetComponentsInChildren<PhotonView>(true);
|
||||
PhotonViewID[] viewIDs = AllocateSceneViewIDs(views.Length);
|
||||
|
||||
if (viewIDs == null)
|
||||
{
|
||||
Debug.LogError("PhotonNetwork error [InstantiateSceneObject]: Could not Instantiate the prefab [" + prefabName + "] as no ViewIDs are free to use. Max is: " + MAX_VIEW_IDS);
|
||||
return null;
|
||||
}
|
||||
|
||||
// Send to others, create info
|
||||
Hashtable instantiateEvent = networkingPeer.SendInstantiate(prefabName, position, rotation, group, viewIDs, data, true);
|
||||
|
||||
// Instantiate the GO locally (but the same way as if it was done via event). This will also cache the instantiationId
|
||||
return networkingPeer.DoInstantiate(instantiateEvent, networkingPeer.mLocalActor, prefabGo);
|
||||
}
|
||||
|
||||
private static PhotonViewID[] AllocateSceneViewIDs(int number)
|
||||
{
|
||||
PhotonViewID[] viewIDs = new PhotonViewID[number];
|
||||
PhotonView[] photonViews = Resources.FindObjectsOfTypeAll(typeof(PhotonView)) as PhotonView[];
|
||||
|
||||
if (photonViews == null || photonViews.Length == MAX_VIEW_IDS)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
int lastAssignedSceneViewId = MAX_VIEW_IDS;
|
||||
for (int view = 0; view < number; view++)
|
||||
{
|
||||
int id;
|
||||
for (id = lastAssignedSceneViewId - 1; id >= 1; id--)
|
||||
{
|
||||
bool idIsInUse = false;
|
||||
foreach (PhotonView photonView in photonViews)
|
||||
{
|
||||
if (photonView.viewID != null && photonView.viewID.ID == id)
|
||||
{
|
||||
idIsInUse = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!idIsInUse)
|
||||
{
|
||||
viewIDs[view] = new PhotonViewID(id, null);
|
||||
lastAssignedSceneViewId = id;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// no ID was free?!
|
||||
if (lastAssignedSceneViewId != id)
|
||||
{
|
||||
Debug.Log("SceneView ID lookup failed.");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return viewIDs;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The current roundtrip time to the photon server
|
||||
/// </summary>
|
||||
/// <returns>Roundtrip time (to server and back).</returns>
|
||||
public static int GetPing()
|
||||
{
|
||||
return networkingPeer.RoundTripTime;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Can be used to immediately send the RPCs and Instantiates just made,
|
||||
/// so they are on their way to the other players.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This could be useful if you do a RPC to load a level and then load it yourself.
|
||||
/// While loading, no RPCs are sent to others, so this would delay the "load" RPC.
|
||||
/// You can send the RPC to "others", use this method, disable the message queue
|
||||
/// (by isMessageQueueRunning) and then load.
|
||||
/// </remarks>
|
||||
public static void SendOutgoingCommands()
|
||||
{
|
||||
if (!VerifyCanUseNetwork())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
while (networkingPeer.SendOutgoingCommands())
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Request a client to disconnect (KICK). Only the master client can do this.
|
||||
/// </summary>
|
||||
/// <param name="kickPlayer">The PhotonPlayer to kick.</param>
|
||||
public static void CloseConnection(PhotonPlayer kickPlayer)
|
||||
{
|
||||
if (!VerifyCanUseNetwork())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!player.isMasterClient)
|
||||
{
|
||||
Debug.LogError("CloseConnection: Only the masterclient can kick another player.");
|
||||
}
|
||||
|
||||
if (kickPlayer == null)
|
||||
{
|
||||
Debug.LogError("CloseConnection: No such player connected!");
|
||||
}
|
||||
else
|
||||
{
|
||||
int[] rec = new int[1];
|
||||
rec[0] = kickPlayer.ID;
|
||||
networkingPeer.OpRaiseEvent(PhotonNetworkMessages.CloseConnection, null, true, 0, rec);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Destroy supplied PhotonView. This will remove all Buffered RPCs and destroy the GameObject this view is attached to (plus all childs, if any)
|
||||
/// This has the same effect as calling Destroy by passing a GameObject
|
||||
/// </summary>
|
||||
/// <param name="view"></param>
|
||||
public static void Destroy(PhotonView view)
|
||||
{
|
||||
if (view != null && view.isMine)
|
||||
{
|
||||
int ID = networkingPeer.GetInstantiatedObjectsId(view.gameObject);
|
||||
if (ID == -1)
|
||||
{
|
||||
networkingPeer.DestroyPhotonView(view, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
Destroy(view.gameObject);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError("Destroy: Could not destroy view ID [" + view + "]. Does not exist, or is not ours!");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Destroys given GameObject. This GameObject must've been instantiated using PhotonNetwork.Instantiate and must have a PhotonView at it's root.
|
||||
/// This has the same effect as calling Destroy by passing an attached PhotonView from this GameObject
|
||||
/// </summary>
|
||||
/// <param name="go"></param>
|
||||
public static void Destroy(GameObject go)
|
||||
{
|
||||
PhotonView view = go.GetComponent<PhotonView>();
|
||||
if (view == null)
|
||||
{
|
||||
Debug.LogError("Cannot call Destroy(GameObject go); on the gameobject \""+go.name+"\" as it has no PhotonView attached.");
|
||||
}
|
||||
else if (view.isMine)
|
||||
{
|
||||
int ID = networkingPeer.GetInstantiatedObjectsId(go);
|
||||
if (ID == -1)
|
||||
{
|
||||
Debug.LogError("Cannot call Destroy(GameObject go); on the gameobject \"" + go.name + "\" as it was not instantiated using PhotonNetwork.Instantiate.");
|
||||
}
|
||||
else
|
||||
{
|
||||
networkingPeer.RemoveInstantiatedGO(go, false); //Success
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError("Cannot call Destroy(GameObject go); on the gameobject \"" + go.name + "\" as we don't control it (Owner: "+view.owner+").");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Destroy all GameObjects/PhotonViews of this player. can only be called on the local player. The only exception is the master client which call call this for all players.
|
||||
/// </summary>
|
||||
/// <param name="player"></param>
|
||||
public static void DestroyPlayerObjects(PhotonPlayer destroyPlayer)
|
||||
{
|
||||
if (!VerifyCanUseNetwork())
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (player.isMasterClient || destroyPlayer == player)
|
||||
{
|
||||
networkingPeer.DestroyPlayerObjects(destroyPlayer, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError("Couldn't destroy objects for player \"" + destroyPlayer + "\" as we are not the masterclient.");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// MasterClient method only: Destroy ALL instantiated GameObjects
|
||||
/// </summary>
|
||||
public static void RemoveAllInstantiatedObjects()
|
||||
{
|
||||
if (isMasterClient)
|
||||
{
|
||||
networkingPeer.RemoveAllInstantiatedObjects();
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError("Couldn't call RemoveAllInstantiatedObjects as only the master client is allowed to call this.");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Destroy ALL PhotonNetwork.Instantiated GameObjects by given player.
|
||||
/// Can only be called on the local player or MasterClient. The MasterClient can call this for all players.
|
||||
/// </summary>
|
||||
/// <param name="player"></param>
|
||||
public static void RemoveAllInstantiatedObjects(PhotonPlayer targetPlayer)
|
||||
{
|
||||
if (!VerifyCanUseNetwork())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (player.isMasterClient || targetPlayer == player)
|
||||
{
|
||||
networkingPeer.RemoveAllInstantiatedObjectsByPlayer(targetPlayer, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError("Couldn't RemoveAllInstantiatedObjects for player \"" + targetPlayer + "\" as only the master client or the player itself is allowed to call this.");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Internal to send an RPC on given PhotonView. Do not call this directly but use: PhotonView.RPC!
|
||||
/// </summary>
|
||||
/// <param name="view"></param>
|
||||
/// <param name="methodName"></param>
|
||||
/// <param name="target"></param>
|
||||
/// <param name="parameters"></param>
|
||||
internal static void RPC(PhotonView view, string methodName, PhotonTargets target, params object[] parameters)
|
||||
{
|
||||
if (!VerifyCanUseNetwork())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (room == null)
|
||||
{
|
||||
Debug.LogWarning("Cannot send RPCs in Lobby! RPC dropped.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (networkingPeer != null)
|
||||
{
|
||||
networkingPeer.RPC(view, methodName, target, parameters);
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogWarning("Could not execute RPC " + methodName + ". Possible scene loading in progress?");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Internal to send an RPC on given PhotonView. Do not call this directly but use: PhotonView.RPC!
|
||||
/// </summary>
|
||||
/// <param name="view"></param>
|
||||
/// <param name="methodName"></param>
|
||||
/// <param name="targetPlayer"></param>
|
||||
/// <param name="parameters"></param>
|
||||
internal static void RPC(PhotonView view, string methodName, PhotonPlayer targetPlayer, params object[] parameters)
|
||||
{
|
||||
if (!VerifyCanUseNetwork())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (room == null)
|
||||
{
|
||||
Debug.LogWarning("Cannot send RPCs in Lobby, only processed locally");
|
||||
return;
|
||||
}
|
||||
|
||||
if (player == null)
|
||||
{
|
||||
Debug.LogError("Error; Sending RPC to player null! Aborted \"" + methodName + "\"");
|
||||
}
|
||||
|
||||
if (networkingPeer != null)
|
||||
{
|
||||
networkingPeer.RPC(view, methodName, targetPlayer, parameters);
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogWarning("Could not execute RPC " + methodName + ". Possible scene loading in progress?");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Remove ALL buffered RPCs of the local player
|
||||
/// </summary>
|
||||
public static void RemoveRPCs()
|
||||
{
|
||||
if (!VerifyCanUseNetwork())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
RemoveRPCs(player);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Remove ALL buffered RPCs of a player
|
||||
/// </summary>
|
||||
public static void RemoveRPCs(PhotonPlayer targetPlayer)
|
||||
{
|
||||
if (!VerifyCanUseNetwork())
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (!targetPlayer.isLocal && !isMasterClient)
|
||||
{
|
||||
Debug.LogError("Error; Only the MasterClient can call RemoveRPCs for other players.");
|
||||
return;
|
||||
}
|
||||
networkingPeer.RemoveRPCs(targetPlayer.ID);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Remove ALL buffered messages of the local player (RPC's and Instantiation calls)
|
||||
/// Note that this only removed the buffered messages on the server, you will still need to remove the Instantiated GameObjects yourself.
|
||||
/// </summary>
|
||||
public static void RemoveAllBufferedMessages()
|
||||
{
|
||||
if (!VerifyCanUseNetwork())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
RemoveAllBufferedMessages(player);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Remove ALL buffered messages of a player (RPC's and Instantiation calls)
|
||||
/// Note that this only removed the buffered messages on the server, you will still need to remove the Instantiated GameObjects yourself.
|
||||
/// </summary>
|
||||
public static void RemoveAllBufferedMessages(PhotonPlayer targetPlayer)
|
||||
{
|
||||
if (!VerifyCanUseNetwork())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!targetPlayer.isLocal && !isMasterClient)
|
||||
{
|
||||
Debug.LogError("Error; Only the MasterClient can call RemoveAllBufferedMessages for other players.");
|
||||
return;
|
||||
}
|
||||
|
||||
networkingPeer.RemoveCompleteCacheOfPlayer(targetPlayer.ID);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Remove all buffered RPCs on given PhotonView (if they are owned by this player).
|
||||
/// </summary>
|
||||
/// <param name="view"></param>
|
||||
public static void RemoveRPCs(PhotonView view)
|
||||
{
|
||||
if (!VerifyCanUseNetwork())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
networkingPeer.RemoveRPCs(view);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Remove all buffered RPCs with given group
|
||||
/// </summary>
|
||||
/// <param name="group"></param>
|
||||
public static void RemoveRPCsInGroup(int group)
|
||||
{
|
||||
if (!VerifyCanUseNetwork())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
networkingPeer.RemoveRPCsInGroup(group);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enable/disable receiving on given group (applied to PhotonViews)
|
||||
/// </summary>
|
||||
/// <param name="group"></param>
|
||||
/// <param name="enabled"></param>
|
||||
public static void SetReceivingEnabled(int group, bool enabled)
|
||||
{
|
||||
if (!VerifyCanUseNetwork())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
networkingPeer.SetReceivingEnabled(group, enabled);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enable/disable sending on given group (applied to PhotonViews)
|
||||
/// </summary>
|
||||
/// <param name="group"></param>
|
||||
/// <param name="enabled"></param>
|
||||
public static void SetSendingEnabled(int group, bool enabled)
|
||||
{
|
||||
if (!VerifyCanUseNetwork())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
networkingPeer.SetSendingEnabled(group, enabled);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a level prefix to all PhotonViews. If any other client uses a differnt prefix, their messages will be dropped.
|
||||
/// They will also drop your messages! Be aware that PUN never resets this value, you'll have to do so yourself.
|
||||
/// </summary>
|
||||
/// <param name="prefix">Max value is short.MaxValue = 32767</param>
|
||||
public static void SetLevelPrefix(short prefix)
|
||||
{
|
||||
if (!VerifyCanUseNetwork())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
networkingPeer.SetLevelPrefix(prefix);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper function which is called inside this class to erify if certain functions can be used (e.g. RPC when not connected)
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private static bool VerifyCanUseNetwork()
|
||||
{
|
||||
if (networkingPeer != null && (offlineMode || connected))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
Debug.LogError("Cannot send messages when not connected; Either connect to Photon OR use offline mode!");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 88e11b3353de7e94d84b1ec5adbdd15e
|
||||
labels:
|
||||
- Photon
|
||||
- Networking
|
||||
- ExitGames
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
+205
@@ -0,0 +1,205 @@
|
||||
// ----------------------------------------------------------------------------
|
||||
// <copyright file="PhotonPlayer.cs" company="Exit Games GmbH">
|
||||
// PhotonNetwork Framework for Unity - Copyright (C) 2011 Exit Games GmbH
|
||||
// </copyright>
|
||||
// <summary>
|
||||
// Represents a player, identified by actorID (a.k.a. ActorNumber).
|
||||
// Caches properties of a player.
|
||||
// </summary>
|
||||
// <author>developer@exitgames.com</author>
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
using ExitGames.Client.Photon;
|
||||
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
|
||||
/// <summary>
|
||||
/// Summarizes a "player" within a room, identified (in that room) by actorID.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Each player has an actorId (or ID), valid for that room. It's -1 until it's assigned by server.
|
||||
/// Each client can set it's player's custom properties with SetCustomProperties, even before being in a room.
|
||||
/// They are synced when joining a room.
|
||||
/// </remarks>
|
||||
/// \ingroup publicApi
|
||||
public class PhotonPlayer
|
||||
{
|
||||
/// <summary>This player's actorID</summary>
|
||||
public int ID
|
||||
{
|
||||
get { return this.actorID; }
|
||||
}
|
||||
|
||||
/// <summary>Identifier of this player in current room.</summary>
|
||||
private int actorID = -1;
|
||||
|
||||
private string nameField = "";
|
||||
|
||||
/// <summary>Nickname of this player.</summary>
|
||||
public string name {
|
||||
get
|
||||
{
|
||||
return this.nameField;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (!isLocal)
|
||||
{
|
||||
Debug.LogError("Error: Cannot change the name of a remote player!");
|
||||
return;
|
||||
}
|
||||
|
||||
this.nameField = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Only one player is controlled by each client. Others are not local.</summary>
|
||||
public readonly bool isLocal = false;
|
||||
|
||||
/// <summary>
|
||||
/// The player with the lowest actorID is the master and could be used for special tasks.
|
||||
/// </summary>
|
||||
public bool isMasterClient
|
||||
{
|
||||
get { return (PhotonNetwork.networkingPeer.mMasterClient == this); }
|
||||
}
|
||||
|
||||
/// <summary>Cache for custom properties of player.</summary>
|
||||
public Hashtable customProperties { get; private set; }
|
||||
|
||||
/// <summary>Creates a Hashtable with all properties (custom and "well known" ones).</summary>
|
||||
/// <remarks>If used more often, this should be cached.</remarks>
|
||||
public Hashtable allProperties
|
||||
{
|
||||
get
|
||||
{
|
||||
Hashtable allProps = new Hashtable();
|
||||
allProps.Merge(this.customProperties);
|
||||
allProps[ActorProperties.PlayerName] = this.name;
|
||||
return allProps;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a PhotonPlayer instance.
|
||||
/// </summary>
|
||||
/// <param name="isLocal">If this is the local peer's player (or a remote one).</param>
|
||||
/// <param name="actorID">ID or ActorNumber of this player in the current room (a shortcut to identify each player in room)</param>
|
||||
/// <param name="name">Name of the player (a "well known property").</param>
|
||||
public PhotonPlayer(bool isLocal, int actorID, string name)
|
||||
{
|
||||
this.customProperties = new Hashtable();
|
||||
this.isLocal = isLocal;
|
||||
this.actorID = actorID;
|
||||
this.nameField = name;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Internally used to create players from event Join
|
||||
/// </summary>
|
||||
internal protected PhotonPlayer(bool isLocal, int actorID, Hashtable properties)
|
||||
{
|
||||
this.customProperties = new Hashtable();
|
||||
this.isLocal = isLocal;
|
||||
this.actorID = actorID;
|
||||
|
||||
this.InternalCacheProperties(properties);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Caches custom properties for this player.
|
||||
/// </summary>
|
||||
internal void InternalCacheProperties(Hashtable properties)
|
||||
{
|
||||
if (properties == null || properties.Count == 0 || this.customProperties.Equals(properties))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (properties.ContainsKey(ActorProperties.PlayerName))
|
||||
{
|
||||
this.nameField = (string)properties[ActorProperties.PlayerName];
|
||||
}
|
||||
|
||||
this.customProperties.MergeStringKeys(properties);
|
||||
this.customProperties.StripKeysWithNullValues();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gives the name.
|
||||
/// </summary>
|
||||
public override string ToString()
|
||||
{
|
||||
return (this.name == null) ? string.Empty : this.name; // +" " + SupportClass.HashtableToString(this.CustomProperties);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Makes PhotonPlayer comparable
|
||||
/// </summary>
|
||||
public override bool Equals(object p)
|
||||
{
|
||||
PhotonPlayer pp = p as PhotonPlayer;
|
||||
return (pp != null && this.GetHashCode() == pp.GetHashCode());
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return this.ID;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Used internally, to update this client's playerID when assigned.
|
||||
/// </summary>
|
||||
internal void InternalChangeLocalID(int newID)
|
||||
{
|
||||
if (!this.isLocal)
|
||||
{
|
||||
Debug.LogError("ERROR You should never change PhotonPlayer IDs!");
|
||||
return;
|
||||
}
|
||||
|
||||
this.actorID = newID;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the custom properties of this Room with propertiesToSet.
|
||||
/// Only string-typed keys are applied, new properties (string keys) are added, existing are updated
|
||||
/// and if a value is set to null, this will remove the custom property.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This method requires you to be connected and be in a room. Otherwise, the local data is updated only as no remote players are known.
|
||||
/// Local cache is updated immediately, other players are updated through Photon with a fitting operation.
|
||||
/// </remarks>
|
||||
/// <param name="propertiesToSet"></param>
|
||||
public void SetCustomProperties(Hashtable propertiesToSet)
|
||||
{
|
||||
if (propertiesToSet == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// merge (delete null-values)
|
||||
this.customProperties.MergeStringKeys(propertiesToSet); // includes a Equals check (simplifying things)
|
||||
this.customProperties.StripKeysWithNullValues();
|
||||
|
||||
// send (sync) these new values
|
||||
Hashtable customProps = propertiesToSet.StripToStringKeys() as Hashtable;
|
||||
PhotonNetwork.networkingPeer.OpSetCustomPropertiesOfActor(this.actorID, customProps, true, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Try to get a specific player by id.
|
||||
/// </summary>
|
||||
/// <param name="ID">ActorID</param>
|
||||
/// <returns>The player with matching actorID or null, if the actorID is not in use.</returns>
|
||||
public static PhotonPlayer Find(int ID)
|
||||
{
|
||||
foreach (PhotonPlayer player in PhotonNetwork.playerList)
|
||||
{
|
||||
if (player.ID == ID)
|
||||
return player;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e3e4b5bebc687044b9c6c2803c36be3d
|
||||
labels:
|
||||
- ExitGames
|
||||
- PUN
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
+150
@@ -0,0 +1,150 @@
|
||||
using System;
|
||||
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
using ExitGames.Client.Photon;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Basic GUI to show traffic and health statistics of the connection to Photon,
|
||||
/// toggled by shift+tab.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The shown health values can help identify problems with connection losses or performance.
|
||||
/// Example:
|
||||
/// If the time delta between two consecutive SendOutgoingCommands calls is a second or more,
|
||||
/// chances rise for a disconnect being caused by this (because acknowledgements to the server
|
||||
/// need to be sent in due time).
|
||||
/// </remarks>
|
||||
/// \ingroup optionalGui
|
||||
public class PhotonStatsGui : MonoBehaviour
|
||||
{
|
||||
/// <summary>Shows or hides GUI (does not affect if stats are collected).</summary>
|
||||
public bool statsWindowOn = true;
|
||||
|
||||
/// <summary>Option to turn collecting stats on or off (used in Update()).</summary>
|
||||
public bool statsOn = true;
|
||||
|
||||
/// <summary>Shows additional "health" values of connection.</summary>
|
||||
public bool healthStatsVisible;
|
||||
|
||||
/// <summary>Shows additional "lower level" traffic stats.</summary>
|
||||
public bool trafficStatsOn;
|
||||
|
||||
/// <summary>Show buttons to control stats and reset them.</summary>
|
||||
public bool buttonsOn;
|
||||
|
||||
/// <summary>Positioning rect for window.</summary>
|
||||
public Rect statsRect = new Rect(0, 100, 200, 50);
|
||||
|
||||
/// <summary>Unity GUI Window ID (must be unique or will cause issues).</summary>
|
||||
public int WindowId = 100;
|
||||
|
||||
|
||||
public void Start()
|
||||
{
|
||||
this.statsRect.x = Screen.width - this.statsRect.width;
|
||||
}
|
||||
|
||||
/// <summary>Checks for shift+tab input combination (to toggle statsOn).</summary>
|
||||
public void Update()
|
||||
{
|
||||
if (Input.GetKeyDown(KeyCode.Tab) && Input.GetKey(KeyCode.LeftShift))
|
||||
{
|
||||
this.statsWindowOn = !this.statsWindowOn;
|
||||
this.statsOn = true; // enable stats when showing the window
|
||||
}
|
||||
}
|
||||
|
||||
public void OnGUI()
|
||||
{
|
||||
if (PhotonNetwork.networkingPeer.TrafficStatsEnabled != statsOn)
|
||||
{
|
||||
PhotonNetwork.networkingPeer.TrafficStatsEnabled = this.statsOn;
|
||||
}
|
||||
|
||||
if (!this.statsWindowOn)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
this.statsRect = GUILayout.Window(this.WindowId, this.statsRect, this.TrafficStatsWindow, "Messages (shift+tab)");
|
||||
}
|
||||
|
||||
public void TrafficStatsWindow(int windowID)
|
||||
{
|
||||
bool statsToLog = false;
|
||||
TrafficStatsGameLevel gls = PhotonNetwork.networkingPeer.TrafficStatsGameLevel;
|
||||
long elapsedMs = PhotonNetwork.networkingPeer.TrafficStatsElapsedMs / 1000;
|
||||
if (elapsedMs == 0)
|
||||
{
|
||||
elapsedMs = 1;
|
||||
}
|
||||
|
||||
GUILayout.BeginHorizontal();
|
||||
this.buttonsOn = GUILayout.Toggle(this.buttonsOn, "buttons");
|
||||
this.healthStatsVisible = GUILayout.Toggle(this.healthStatsVisible, "health");
|
||||
this.trafficStatsOn = GUILayout.Toggle(this.trafficStatsOn, "traffic");
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
string total = string.Format("Out|In|Sum:\t{0,4} | {1,4} | {2,4}", gls.TotalOutgoingMessageCount, gls.TotalIncomingMessageCount, gls.TotalMessageCount);
|
||||
string elapsedTime = string.Format("{0}sec average:", elapsedMs);
|
||||
string average = string.Format("Out|In|Sum:\t{0,4} | {1,4} | {2,4}", gls.TotalOutgoingMessageCount / elapsedMs, gls.TotalIncomingMessageCount / elapsedMs, gls.TotalMessageCount / elapsedMs);
|
||||
GUILayout.Label(total);
|
||||
GUILayout.Label(elapsedTime);
|
||||
GUILayout.Label(average);
|
||||
|
||||
if (this.buttonsOn)
|
||||
{
|
||||
GUILayout.BeginHorizontal();
|
||||
this.statsOn = GUILayout.Toggle(this.statsOn, "stats on");
|
||||
if (GUILayout.Button("Reset"))
|
||||
{
|
||||
PhotonNetwork.networkingPeer.TrafficStatsReset();
|
||||
PhotonNetwork.networkingPeer.TrafficStatsEnabled = true;
|
||||
}
|
||||
statsToLog = GUILayout.Button("To Log");
|
||||
GUILayout.EndHorizontal();
|
||||
}
|
||||
|
||||
string trafficStatsIn = string.Empty;
|
||||
string trafficStatsOut = string.Empty;
|
||||
if (this.trafficStatsOn)
|
||||
{
|
||||
trafficStatsIn = "Incoming: " + PhotonNetwork.networkingPeer.TrafficStatsIncoming.ToString();
|
||||
trafficStatsOut = "Outgoing: " + PhotonNetwork.networkingPeer.TrafficStatsOutgoing.ToString();
|
||||
GUILayout.Label(trafficStatsIn);
|
||||
GUILayout.Label(trafficStatsOut);
|
||||
}
|
||||
|
||||
string healthStats = string.Empty;
|
||||
if (this.healthStatsVisible)
|
||||
{
|
||||
healthStats = string.Format(
|
||||
"ping: {6}[+/-{7}]ms\nlongest delta between\nsend: {0,4}ms disp: {1,4}ms\nlongest time for:\nev({3}):{2,3}ms op({5}):{4,3}ms",
|
||||
gls.LongestDeltaBetweenSending,
|
||||
gls.LongestDeltaBetweenDispatching,
|
||||
gls.LongestEventCallback,
|
||||
gls.LongestEventCallbackCode,
|
||||
gls.LongestOpResponseCallback,
|
||||
gls.LongestOpResponseCallbackOpCode,
|
||||
PhotonNetwork.networkingPeer.RoundTripTime,
|
||||
PhotonNetwork.networkingPeer.RoundTripTimeVariance);
|
||||
GUILayout.Label(healthStats);
|
||||
}
|
||||
|
||||
if (statsToLog)
|
||||
{
|
||||
string complete = string.Format("{0}\n{1}\n{2}\n{3}\n{4}\n{5}", total, elapsedTime, average, trafficStatsIn, trafficStatsOut, healthStats);
|
||||
Debug.Log(complete);
|
||||
}
|
||||
|
||||
// if anything was clicked, the height of this window is likely changed. reduce it to be layouted again next frame
|
||||
if (GUI.changed)
|
||||
{
|
||||
this.statsRect.height = 100;
|
||||
}
|
||||
|
||||
GUI.DragWindow();
|
||||
}
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2c064e6d46a889146a62999decd6ea26
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
+214
@@ -0,0 +1,214 @@
|
||||
// ----------------------------------------------------------------------------
|
||||
// <copyright file="Room.cs" company="Exit Games GmbH">
|
||||
// PhotonNetwork Framework for Unity - Copyright (C) 2011 Exit Games GmbH
|
||||
// </copyright>
|
||||
// <summary>
|
||||
// Represents a room/game on the server and caches the properties of that.
|
||||
// </summary>
|
||||
// <author>developer@exitgames.com</author>
|
||||
// ----------------------------------------------------------------------------
|
||||
using System;
|
||||
using System.Collections;
|
||||
using ExitGames.Client.Photon;
|
||||
|
||||
/// <summary>
|
||||
/// This class resembles a room that PUN joins (or joined).
|
||||
/// The properties are settable as opposed to those of a RoomInfo and you can close or hide "your" room.
|
||||
/// </summary>
|
||||
/// \ingroup publicApi
|
||||
public class Room : RoomInfo
|
||||
{
|
||||
/// <summary>Count of players in this room.</summary>
|
||||
public new int playerCount
|
||||
{
|
||||
get
|
||||
{
|
||||
if (PhotonNetwork.playerList != null)
|
||||
{
|
||||
return PhotonNetwork.playerList.Length;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>The name of a room. Unique identifier (per Loadbalancing group) for a room/match.</summary>
|
||||
public new string name
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.nameField;
|
||||
}
|
||||
|
||||
internal set
|
||||
{
|
||||
this.nameField = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets a limit of players to this room. This property is shown in lobby, too.
|
||||
/// If the room is full (players count == maxplayers), joining this room will fail.
|
||||
/// </summary>
|
||||
public new int maxPlayers
|
||||
{
|
||||
get
|
||||
{
|
||||
return (int)this.maxPlayersField;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
if (!this.Equals(PhotonNetwork.room))
|
||||
{
|
||||
PhotonNetwork.networkingPeer.DebugReturn(DebugLevel.WARNING, "Can't set room properties when not in that room.");
|
||||
}
|
||||
|
||||
if (value > 255)
|
||||
{
|
||||
UnityEngine.Debug.LogError("Error: room.maxPlayers called with value " + value + ". This has been reverted to the max of 255 players, because internally a 'byte' is used.");
|
||||
value = 255;
|
||||
}
|
||||
|
||||
if (value != this.maxPlayersField && !PhotonNetwork.offlineMode)
|
||||
{
|
||||
PhotonNetwork.networkingPeer.OpSetPropertiesOfRoom(new Hashtable() { { GameProperties.MaxPlayers, (byte)value } }, true, (byte)0);
|
||||
}
|
||||
|
||||
this.maxPlayersField = (byte)value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Defines if the room can be joined.
|
||||
/// This does not affect listing in a lobby but joining the room will fail if not open.
|
||||
/// If not open, the room is excluded from random matchmaking.
|
||||
/// Due to racing conditions, found matches might become closed before they are joined.
|
||||
/// Simply re-connect to master and find another.
|
||||
/// Use property "visible" to not list the room.
|
||||
/// </summary>
|
||||
public new bool open
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.openField;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
if (!this.Equals(PhotonNetwork.room))
|
||||
{
|
||||
PhotonNetwork.networkingPeer.DebugReturn(DebugLevel.WARNING, "Can't set room properties when not in that room.");
|
||||
}
|
||||
|
||||
if (value != this.openField && !PhotonNetwork.offlineMode)
|
||||
{
|
||||
PhotonNetwork.networkingPeer.OpSetPropertiesOfRoom(new Hashtable() { { GameProperties.IsOpen, value } }, true, (byte)0);
|
||||
}
|
||||
|
||||
this.openField = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Defines if the room is listed in its lobby.
|
||||
/// Rooms can be created invisible, or changed to invisible.
|
||||
/// To change if a room can be joined, use property: open.
|
||||
/// </summary>
|
||||
public new bool visible
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.visibleField;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
if (!this.Equals(PhotonNetwork.room))
|
||||
{
|
||||
PhotonNetwork.networkingPeer.DebugReturn(DebugLevel.WARNING, "Can't set room properties when not in that room.");
|
||||
}
|
||||
|
||||
if (value != this.visibleField && !PhotonNetwork.offlineMode)
|
||||
{
|
||||
PhotonNetwork.networkingPeer.OpSetPropertiesOfRoom(new Hashtable() { { GameProperties.IsVisible, value } }, true, (byte)0);
|
||||
}
|
||||
|
||||
this.visibleField = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A list of custom properties that should be forwarded to the lobby and listed there.
|
||||
/// </summary>
|
||||
public string[] propertiesListedInLobby { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets if this room uses autoCleanUp to remove all (buffered) RPCs and instantiated GameObjects when a player leaves.
|
||||
/// </summary>
|
||||
public bool autoCleanUp
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.autoCleanUpField;
|
||||
}
|
||||
}
|
||||
|
||||
internal Room(string roomName, Hashtable properties) : base(roomName, properties)
|
||||
{
|
||||
this.propertiesListedInLobby = new string[0];
|
||||
}
|
||||
|
||||
internal Room(string roomName, Hashtable properties, bool isVisible, bool isOpen, int maxPlayers, bool autoCleanUp, string[] propsListedInLobby) : base(roomName, properties)
|
||||
{
|
||||
this.visibleField = isVisible;
|
||||
this.openField = isOpen;
|
||||
this.autoCleanUpField = autoCleanUp;
|
||||
|
||||
if (maxPlayers > 255)
|
||||
{
|
||||
UnityEngine.Debug.LogError("Error: Room() called with " + maxPlayers + " maxplayers. This has been reverted to the max of 255 players, because internally a 'byte' is used.");
|
||||
maxPlayers = 255;
|
||||
}
|
||||
|
||||
this.maxPlayersField = (byte)maxPlayers;
|
||||
|
||||
if (propsListedInLobby != null)
|
||||
{
|
||||
this.propertiesListedInLobby = propsListedInLobby;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.propertiesListedInLobby = new string[0];
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the custom properties of this Room with propertiesToSet.
|
||||
/// Only string-typed keys are applied, new properties (string keys) are added, existing are updated
|
||||
/// and if a value is set to null, this will remove the custom property.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This method requires you to be connected and be in a room. Otherwise, the local data is updated only as no remote players are known.
|
||||
/// Local cache is updated immediately, other players are updated through Photon with a fitting operation.
|
||||
/// </remarks>
|
||||
/// <param name="propertiesToSet"></param>
|
||||
public void SetCustomProperties(Hashtable propertiesToSet)
|
||||
{
|
||||
if (propertiesToSet == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// merge (delete null-values)
|
||||
this.customProperties.MergeStringKeys(propertiesToSet); // includes a Equals check (simplifying things)
|
||||
this.customProperties.StripKeysWithNullValues();
|
||||
|
||||
// send (sync) these new values
|
||||
Hashtable customProps = propertiesToSet.StripToStringKeys() as Hashtable;
|
||||
PhotonNetwork.networkingPeer.OpSetCustomPropertiesOfRoom(customProps, true, 0);
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 17568a7a5552c09428dd48e73548b8b8
|
||||
labels:
|
||||
- ExitGames
|
||||
- PUN
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
+222
@@ -0,0 +1,222 @@
|
||||
// ----------------------------------------------------------------------------
|
||||
// <copyright file="RoomInfo.cs" company="Exit Games GmbH">
|
||||
// Loadbalancing Framework for Photon - Copyright (C) 2011 Exit Games GmbH
|
||||
// </copyright>
|
||||
// <summary>
|
||||
// This class resembles info about available rooms, as sent by the Master
|
||||
// server's lobby. Consider all values as readonly.
|
||||
// </summary>
|
||||
// <author>developer@exitgames.com</author>
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
|
||||
using ExitGames.Client.Photon;
|
||||
|
||||
/// <summary>
|
||||
/// A simplified room with just the info required to list and join, used for the room listing in the lobby.
|
||||
/// The properties are not settable (open, maxPlayers, etc).
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This class resembles info about available rooms, as sent by the Master server's lobby.
|
||||
/// Consider all values as readonly. None are synced (only updated by events by server).
|
||||
/// </remarks>
|
||||
/// \ingroup publicApi
|
||||
public class RoomInfo
|
||||
{
|
||||
/// <summary>Used internally in lobby, to mark rooms that are no longer listed.</summary>
|
||||
public bool removedFromList { get; internal set; }
|
||||
|
||||
/// <summary>Backing field for property.</summary>
|
||||
private Hashtable customPropertiesField = new Hashtable();
|
||||
|
||||
/// <summary>Backing field for property.</summary>
|
||||
protected byte maxPlayersField = 0;
|
||||
|
||||
/// <summary>Backing field for property.</summary>
|
||||
protected bool openField = true;
|
||||
|
||||
/// <summary>Backing field for property.</summary>
|
||||
protected bool visibleField = true;
|
||||
|
||||
/// <summary>Backing field for property. False unless the GameProperty is set to true (else it's not sent).</summary>
|
||||
protected bool autoCleanUpField = false;
|
||||
|
||||
/// <summary>Backing field for property.</summary>
|
||||
protected string nameField;
|
||||
|
||||
/// <summary>Custom properties of a room. All keys are string-typed and the values depend on the game/application.</summary>
|
||||
public Hashtable customProperties
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.customPropertiesField;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>The name of a room. Unique identifier (per Loadbalancing group) for a room/match.</summary>
|
||||
public string name
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.nameField;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Only used internally in lobby, to display number of players in room (while you're not in).
|
||||
/// </summary>
|
||||
public int playerCount { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// State if the local client is already in the game or still going to join it on gameserver (in lobby always false).
|
||||
/// </summary>
|
||||
public bool isLocalClientInside { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Sets a limit of players to this room. This property is shown in lobby, too.
|
||||
/// If the room is full (players count == maxplayers), joining this room will fail.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// As part of RoomInfo this can't be set.
|
||||
/// As part of a Room (which the player joined), the setter will update the server and all clients.
|
||||
/// </remarks>
|
||||
public byte maxPlayers
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.maxPlayersField;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Defines if the room can be joined.
|
||||
/// This does not affect listing in a lobby but joining the room will fail if not open.
|
||||
/// If not open, the room is excluded from random matchmaking.
|
||||
/// Due to racing conditions, found matches might become closed before they are joined.
|
||||
/// Simply re-connect to master and find another.
|
||||
/// Use property "IsVisible" to not list the room.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// As part of RoomInfo this can't be set.
|
||||
/// As part of a Room (which the player joined), the setter will update the server and all clients.
|
||||
/// </remarks>
|
||||
public bool open
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.openField;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Defines if the room is listed in its lobby.
|
||||
/// Rooms can be created invisible, or changed to invisible.
|
||||
/// To change if a room can be joined, use property: open.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// As part of RoomInfo this can't be set.
|
||||
/// As part of a Room (which the player joined), the setter will update the server and all clients.
|
||||
/// </remarks>
|
||||
public bool visible
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.visibleField;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs a RoomInfo to be used in room listings in lobby.
|
||||
/// </summary>
|
||||
/// <param name="roomName"></param>
|
||||
/// <param name="properties"></param>
|
||||
protected internal RoomInfo(string roomName, Hashtable properties)
|
||||
{
|
||||
this.CacheProperties(properties);
|
||||
|
||||
this.nameField = roomName;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Makes RoomInfo comparable (by name).
|
||||
/// </summary>
|
||||
public override bool Equals(object p)
|
||||
{
|
||||
Room pp = p as Room;
|
||||
return (pp != null && this.nameField.Equals(pp.nameField));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Accompanies Equals, using the name's HashCode as return.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return this.nameField.GetHashCode();
|
||||
}
|
||||
|
||||
/// <summary>Simple printingin method.</summary>
|
||||
/// <returns>String showing the RoomInfo.</returns>
|
||||
public override string ToString()
|
||||
{
|
||||
return string.Format("Room: '{0}' visible: {1} open: {2} max: {3} count: {4}\ncustomProps: {5}", this.nameField, this.visibleField, this.openField, this.maxPlayersField, this.playerCount, SupportClass.DictionaryToString(this.customPropertiesField));
|
||||
}
|
||||
|
||||
/// <summary>Copies "well known" properties to fields (isVisible, etc) and caches the custom properties (string-keys only) in a local hashtable.</summary>
|
||||
/// <param name="propertiesToCache">New or updated properties to store in this RoomInfo.</param>
|
||||
protected internal void CacheProperties(Hashtable propertiesToCache)
|
||||
{
|
||||
if (propertiesToCache == null || propertiesToCache.Count == 0 || this.customPropertiesField.Equals(propertiesToCache))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// check of this game was removed from the list. in that case, we don't
|
||||
// need to read any further properties
|
||||
// list updates will remove this game from the game listing
|
||||
if (propertiesToCache.ContainsKey(GameProperties.Removed))
|
||||
{
|
||||
this.removedFromList = (Boolean)propertiesToCache[GameProperties.Removed];
|
||||
if (this.removedFromList)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// fetch the "well known" properties of the room, if available
|
||||
if (propertiesToCache.ContainsKey(GameProperties.MaxPlayers))
|
||||
{
|
||||
this.maxPlayersField = (byte)propertiesToCache[GameProperties.MaxPlayers];
|
||||
}
|
||||
|
||||
if (propertiesToCache.ContainsKey(GameProperties.IsOpen))
|
||||
{
|
||||
this.openField = (bool)propertiesToCache[GameProperties.IsOpen];
|
||||
}
|
||||
|
||||
if (propertiesToCache.ContainsKey(GameProperties.IsVisible))
|
||||
{
|
||||
this.visibleField = (bool)propertiesToCache[GameProperties.IsVisible];
|
||||
}
|
||||
|
||||
if (propertiesToCache.ContainsKey(GameProperties.PlayerCount))
|
||||
{
|
||||
this.playerCount = (int)((byte)propertiesToCache[GameProperties.PlayerCount]);
|
||||
}
|
||||
|
||||
if (propertiesToCache.ContainsKey(GameProperties.CleanupCacheOnLeave))
|
||||
{
|
||||
this.autoCleanUpField = (bool)propertiesToCache[GameProperties.CleanupCacheOnLeave];
|
||||
}
|
||||
|
||||
//if (propertiesToCache.ContainsKey(GameProperties.PropsListedInLobby))
|
||||
//{
|
||||
// // could be cached but isn't useful
|
||||
//}
|
||||
|
||||
// merge the custom properties (from your application) to the cache (only string-typed keys will be kept)
|
||||
this.customPropertiesField.MergeStringKeys(propertiesToCache);
|
||||
}
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a5ebf89c7ddda704888afd9772a886ff
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
using System.IO;
|
||||
using UnityEngine;
|
||||
|
||||
/// <summary>
|
||||
/// Collection of connection-relevant settings, used internally by PhotonNetwork.ConnectUsingSettings.
|
||||
/// </summary>
|
||||
[System.Serializable]
|
||||
public class ServerSettings : ScriptableObject
|
||||
{
|
||||
public static string DefaultCloudServerUrl = "app.exitgamescloud.com";
|
||||
public static string DefaultServerAddress = "127.0.0.1";
|
||||
public static int DefaultMasterPort = 5055; // default port for master server
|
||||
public static string DefaultAppID = "Master";
|
||||
|
||||
public enum HostingOption { NotSet, PhotonCloud, SelfHosted, OfflineMode }
|
||||
|
||||
public HostingOption HostType = HostingOption.NotSet;
|
||||
public string ServerAddress = DefaultServerAddress;
|
||||
public int ServerPort = 5055;
|
||||
public string AppID = "";
|
||||
|
||||
[HideInInspector]
|
||||
public bool DisableAutoOpenWizard;
|
||||
|
||||
|
||||
public void UseCloud(string cloudAppid)
|
||||
{
|
||||
this.HostType = HostingOption.PhotonCloud;
|
||||
this.AppID = cloudAppid;
|
||||
this.ServerAddress = DefaultCloudServerUrl;
|
||||
this.ServerPort = DefaultMasterPort;
|
||||
}
|
||||
|
||||
public void UseMyServer(string serverAddress, int serverPort, string application)
|
||||
{
|
||||
this.HostType = HostingOption.SelfHosted;
|
||||
this.AppID = (application != null) ? application : DefaultAppID;
|
||||
this.ServerAddress = serverAddress;
|
||||
this.ServerPort = serverPort;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return "ServerSettings: " + HostType + " " + ServerAddress;
|
||||
}
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3b51608f6a3a4584d87dc9aecf104cfd
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 83881a9535fc6564eb9447878708be75
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
userData:
|
||||
BIN
Binary file not shown.
+10
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: aadb37a20a33632429047acaef43658a
|
||||
labels:
|
||||
- ExitGames
|
||||
- PUN
|
||||
MonoAssemblyImporter:
|
||||
serializedVersion: 1
|
||||
iconMap: {}
|
||||
executionOrder: {}
|
||||
userData:
|
||||
+2228
@@ -0,0 +1,2228 @@
|
||||
<?xml version="1.0"?>
|
||||
<doc>
|
||||
<assembly>
|
||||
<name>Photon3Unity3D</name>
|
||||
</assembly>
|
||||
<members>
|
||||
<member name="M:Photon.SocketServer.Security.DiffieHellmanCryptoProvider.#ctor">
|
||||
<summary>
|
||||
Initializes a new instance of the <see cref="T:Photon.SocketServer.Security.DiffieHellmanCryptoProvider"/> class.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:Photon.SocketServer.Security.DiffieHellmanCryptoProvider.DeriveSharedKey(System.Byte[])">
|
||||
<summary>
|
||||
Derives the shared key is generated from the secret agreement between two parties,
|
||||
given a byte array that contains the second party's public key.
|
||||
</summary>
|
||||
<param name="otherPartyPublicKey">
|
||||
The second party's public key.
|
||||
</param>
|
||||
</member>
|
||||
<member name="P:Photon.SocketServer.Security.DiffieHellmanCryptoProvider.PublicKey">
|
||||
<summary>
|
||||
Gets the public key that can be used by another DiffieHellmanCryptoProvider object
|
||||
to generate a shared secret agreement.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:Photon.SocketServer.Security.DiffieHellmanCryptoProvider.SharedKey">
|
||||
<summary>
|
||||
Gets the shared key that is used by the current instance for cryptographic operations.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:ExitGames.Client.Photon.PeerBase.peerID">
|
||||
This ID is assigned by the Realtime Server upon connection.
|
||||
The application does not have to care about this, but it is useful in debugging.
|
||||
</member>
|
||||
<member name="F:ExitGames.Client.Photon.PeerBase.peerConnectionState">
|
||||
<summary>
|
||||
This is the (low level) connection state of the peer. It's internal and based on eNet's states.
|
||||
</summary>
|
||||
<remarks>Applications can read the "high level" state as PhotonPeer.PeerState, which uses a different enum.</remarks>
|
||||
</member>
|
||||
<member name="F:ExitGames.Client.Photon.PeerBase.serverTimeOffset">
|
||||
<summary>
|
||||
The serverTimeOffset is serverTimestamp - localTime. Used to approximate the serverTimestamp with help of localTime
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:ExitGames.Client.Photon.PeerBase.Connect(System.String,System.String,System.Byte)">
|
||||
<summary>nodeId can be ignored by implementations. TCP uses this to control the tcp-proxy</summary>
|
||||
</member>
|
||||
<member name="M:ExitGames.Client.Photon.PeerBase.DispatchIncomingCommands">
|
||||
<summary>
|
||||
Checks the incoming queue and Dispatches received data if possible.
|
||||
</summary>
|
||||
<returns>If a Dispatch happened or not, which shows if more Dispatches might be needed.</returns>
|
||||
</member>
|
||||
<member name="M:ExitGames.Client.Photon.PeerBase.SendOutgoingCommands">
|
||||
<summary>
|
||||
Checks outgoing queues for commands to send and puts them on their way.
|
||||
This creates one package per go in UDP.
|
||||
</summary>
|
||||
<returns>If commands are not sent, cause they didn't fit into the package that's sent.</returns>
|
||||
</member>
|
||||
<member name="F:ExitGames.Client.Photon.PeerBase.mtu">
|
||||
<summary> Maximum Transfer Unit to be used for UDP+TCP</summary>
|
||||
</member>
|
||||
<member name="M:ExitGames.Client.Photon.PeerBase.ExchangeKeysForEncryption">
|
||||
<summary>
|
||||
Internally uses an operation to exchange encryption keys with the server.
|
||||
</summary>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:ExitGames.Client.Photon.PeerBase.NetworkSimRun">
|
||||
<summary>
|
||||
Core of the Network Simulation, which is available in Debug builds.
|
||||
Called by a timer in intervals.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:ExitGames.Client.Photon.PeerBase.TrafficStatsEnabled">
|
||||
<summary>
|
||||
Enables or disables collection of statistics.
|
||||
Setting this to true, also starts the stopwatch to measure the timespan the stats are collected.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:ExitGames.Client.Photon.PeerBase.NetworkSimulationSettings">
|
||||
<summary>
|
||||
Gets the currently used settings for the built-in network simulation.
|
||||
Please check the description of NetworkSimulationSet for more details.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:ExitGames.Client.Photon.PeerBase.BytesOut">
|
||||
<summary>
|
||||
Count of all bytes going out (including headers)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:ExitGames.Client.Photon.PeerBase.BytesIn">
|
||||
<summary>
|
||||
Count of all bytes coming in (including headers)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:ExitGames.Client.Photon.PeerBase.ConnectionStateValue">
|
||||
<summary>
|
||||
This is the replacement for the const values used in eNet like: PS_DISCONNECTED, PS_CONNECTED, etc.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:ExitGames.Client.Photon.PeerBase.ConnectionStateValue.Disconnected">
|
||||
<summary>No connection is available. Use connect.</summary>
|
||||
</member>
|
||||
<member name="F:ExitGames.Client.Photon.PeerBase.ConnectionStateValue.Connecting">
|
||||
<summary>Establishing a connection already. The app should wait for a status callback.</summary>
|
||||
</member>
|
||||
<member name="F:ExitGames.Client.Photon.PeerBase.ConnectionStateValue.Connected">
|
||||
<summary>
|
||||
The low level connection with Photon is established. On connect, the library will automatically
|
||||
send an Init package to select the application it connects to (see also PhotonPeer.Connect()).
|
||||
When the Init is done, IPhotonPeerListener.OnStatusChanged() is called with connect.
|
||||
</summary>
|
||||
<remarks>Please note that calling operations is only possible after the OnStatusChanged() with StatusCode.Connect.</remarks>
|
||||
</member>
|
||||
<member name="F:ExitGames.Client.Photon.PeerBase.ConnectionStateValue.Disconnecting">
|
||||
<summary>Connection going to be ended. Wait for status callback.</summary>
|
||||
</member>
|
||||
<member name="F:ExitGames.Client.Photon.PeerBase.ConnectionStateValue.AcknowledgingDisconnect">
|
||||
<summary>Acknowledging a disconnect from Photon. Wait for status callback.</summary>
|
||||
</member>
|
||||
<member name="F:ExitGames.Client.Photon.PeerBase.ConnectionStateValue.Zombie">
|
||||
<summary>Connection not properly disconnected.</summary>
|
||||
</member>
|
||||
<member name="F:ExitGames.Client.Photon.EnetPeer.channels">
|
||||
<summary>Will contain channel 0xFF and any other.</summary>
|
||||
</member>
|
||||
<member name="F:ExitGames.Client.Photon.EnetPeer.sentReliableCommands">
|
||||
<summary>One list for all channels keeps sent commands (for re-sending).</summary>
|
||||
</member>
|
||||
<member name="F:ExitGames.Client.Photon.EnetPeer.outgoingAcknowledgementsList">
|
||||
<summary>One list for all channels keeps acknowledgements.</summary>
|
||||
</member>
|
||||
<member name="M:ExitGames.Client.Photon.EnetPeer.DispatchIncomingCommands">
|
||||
<summary>
|
||||
Checks the incoming queue and Dispatches received data if possible.
|
||||
</summary>
|
||||
<returns>If a Dispatch happened or not, which shows if more Dispatches might be needed.</returns>
|
||||
</member>
|
||||
<member name="M:ExitGames.Client.Photon.EnetPeer.SendOutgoingCommands">
|
||||
<summary>
|
||||
gathers commands from all (out)queues until udp-packet is full and sends it!
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:ExitGames.Client.Photon.EnetPeer.EnqueueOperation(System.Collections.Generic.Dictionary{System.Byte,System.Object},System.Byte,System.Boolean,System.Byte,System.Boolean,ExitGames.Client.Photon.PeerBase.EgMessageType)">
|
||||
<summary>
|
||||
Checks connected state and channel before operation is serialized and enqueued for sending.
|
||||
</summary>
|
||||
<param name="parameters">operation parameters</param>
|
||||
<param name="opCode">code of operation</param>
|
||||
<param name="sendReliable">send as reliable command</param>
|
||||
<param name="channelId">channel (sequence) for command</param>
|
||||
<param name="encrypt">encrypt or not</param>
|
||||
<param name="messageType">usually EgMessageType.Operation</param>
|
||||
<returns>if operation could be enqueued</returns>
|
||||
</member>
|
||||
<member name="M:ExitGames.Client.Photon.EnetPeer.CreateAndEnqueueCommand(System.Byte,System.Byte[],System.Byte)">
|
||||
<summary>reliable-udp-level function to send some byte[] to the server via un/reliable command</summary>
|
||||
<remarks>only called when a custom operation should be send</remarks>
|
||||
<param name="commandType">(enet) command type</param>
|
||||
<param name="payload">data to carry (operation)</param>
|
||||
<param name="channelNumber">channel in which to send</param>
|
||||
<returns>the invocation ID for this operation (the payload)</returns>
|
||||
</member>
|
||||
<member name="M:ExitGames.Client.Photon.EnetPeer.SerializeOperationToMessage(System.Byte,System.Collections.Generic.Dictionary{System.Byte,System.Object},ExitGames.Client.Photon.PeerBase.EgMessageType,System.Boolean)">
|
||||
<summary> Returns the UDP Payload starting with Magic Number for binary protocol </summary>
|
||||
</member>
|
||||
<member name="M:ExitGames.Client.Photon.EnetPeer.ReceiveIncomingCommands(System.Byte[])">
|
||||
<summary>reads incoming udp-packages to create and queue incoming commands*</summary>
|
||||
</member>
|
||||
<member name="M:ExitGames.Client.Photon.EnetPeer.QueueIncomingCommand(ExitGames.Client.Photon.NCommand)">
|
||||
<summary>queues incoming commands in the correct order as either unreliable, reliable or unsequenced. return value determines if the command is queued / done.</summary>
|
||||
</member>
|
||||
<member name="M:ExitGames.Client.Photon.EnetPeer.RemoveSentReliableCommand(System.Int32,System.Int32)">
|
||||
<summary>removes commands which are acknowledged*</summary>
|
||||
</member>
|
||||
<member name="T:ExitGames.Client.Photon.Lite.LiteEventCode">
|
||||
<summary>
|
||||
Lite - Event codes.
|
||||
These codes are defined by the Lite application's logic on the server side.
|
||||
Other application's won't necessarily use these.
|
||||
</summary>
|
||||
<remarks>If your game is built as extension of Lite, don't re-use these codes for your custom events.</remarks>
|
||||
</member>
|
||||
<member name="F:ExitGames.Client.Photon.Lite.LiteEventCode.Join">
|
||||
<summary>(255) Event Join: someone joined the game</summary>
|
||||
</member>
|
||||
<member name="F:ExitGames.Client.Photon.Lite.LiteEventCode.Leave">
|
||||
<summary>(254) Event Leave: someone left the game</summary>
|
||||
</member>
|
||||
<member name="F:ExitGames.Client.Photon.Lite.LiteEventCode.PropertiesChanged">
|
||||
<summary>(253) Event PropertiesChanged</summary>
|
||||
</member>
|
||||
<member name="T:ExitGames.Client.Photon.Lite.LiteEventKey">
|
||||
<summary>
|
||||
Lite - Keys of event-parameters that are defined by the Lite application logic.
|
||||
To keep things lean (in terms of bandwidth), we use byte keys to identify values in events within Photon.
|
||||
In Lite, you can send custom events by defining a EventCode and some content. This custom content is a Hashtable,
|
||||
which can use any type for keys and values. The parameter for operation RaiseEvent and the resulting
|
||||
Events use key (byte)245 for the custom content. The constant for this is: Data or
|
||||
<see cref="F:ExitGames.Client.Photon.Lite.LiteEventKey.CustomContent" text="LiteEventKey.CustomContent Field"/>.
|
||||
</summary>
|
||||
<remarks>
|
||||
If your game is built as extension of Lite, don't re-use these codes for your custom events.
|
||||
</remarks>
|
||||
</member>
|
||||
<member name="F:ExitGames.Client.Photon.Lite.LiteEventKey.ActorNr">
|
||||
<summary>(254) Playernumber of the player who triggered the event.</summary>
|
||||
</member>
|
||||
<member name="F:ExitGames.Client.Photon.Lite.LiteEventKey.TargetActorNr">
|
||||
<summary>(253) Playernumber of the player who is target of an event (e.g. changed properties).</summary>
|
||||
</member>
|
||||
<member name="F:ExitGames.Client.Photon.Lite.LiteEventKey.ActorList">
|
||||
<summary>(252) List of playernumbers currently in the room.</summary>
|
||||
</member>
|
||||
<member name="F:ExitGames.Client.Photon.Lite.LiteEventKey.Properties">
|
||||
<summary>(251) Set of properties (a Hashtable).</summary>
|
||||
</member>
|
||||
<member name="F:ExitGames.Client.Photon.Lite.LiteEventKey.ActorProperties">
|
||||
<summary>(249) Key for actor (player) property set (Hashtable).</summary>
|
||||
</member>
|
||||
<member name="F:ExitGames.Client.Photon.Lite.LiteEventKey.GameProperties">
|
||||
<summary>(248) Key for game (room) property set (Hashtable).</summary>
|
||||
</member>
|
||||
<member name="F:ExitGames.Client.Photon.Lite.LiteEventKey.Data">
|
||||
<summary>(245) Custom Content of an event (a Hashtable in Lite).</summary>
|
||||
</member>
|
||||
<member name="F:ExitGames.Client.Photon.Lite.LiteEventKey.CustomContent">
|
||||
<summary>
|
||||
(245) The Lite operation RaiseEvent will place the Hashtable with your custom event-content under this key.</summary>
|
||||
<remarks>Alternative for: Data!</remarks>
|
||||
</member>
|
||||
<member name="T:ExitGames.Client.Photon.Lite.LiteOpCode">
|
||||
<summary>
|
||||
Lite - Operation Codes.
|
||||
This enumeration contains the codes that are given to the Lite Application's
|
||||
operations. Instead of sending "Join", this enables us to send the byte 255.
|
||||
</summary>
|
||||
<remarks>
|
||||
Other applications (the MMO demo or your own) could define other operations and other codes.
|
||||
If your game is built as extension of Lite, don't re-use these codes for your custom events.
|
||||
</remarks>
|
||||
</member>
|
||||
<member name="F:ExitGames.Client.Photon.Lite.LiteOpCode.Join">
|
||||
<summary>(255) Code for OpJoin, to get into a room.</summary>
|
||||
</member>
|
||||
<member name="F:ExitGames.Client.Photon.Lite.LiteOpCode.Leave">
|
||||
<summary>(254) Code for OpLeave, to get out of a room.</summary>
|
||||
</member>
|
||||
<member name="F:ExitGames.Client.Photon.Lite.LiteOpCode.RaiseEvent">
|
||||
<summary>(253) Code for OpRaiseEvent (not same as eventCode).</summary>
|
||||
</member>
|
||||
<member name="F:ExitGames.Client.Photon.Lite.LiteOpCode.SetProperties">
|
||||
<summary>(252) Code for OpSetProperties.</summary>
|
||||
</member>
|
||||
<member name="F:ExitGames.Client.Photon.Lite.LiteOpCode.GetProperties">
|
||||
<summary>(251) Operation Code for OpGetProperties.</summary>
|
||||
</member>
|
||||
<member name="T:ExitGames.Client.Photon.Lite.LiteOpKey">
|
||||
<summary>
|
||||
Lite - keys for parameters of operation requests and responses (short: OpKey).
|
||||
</summary>
|
||||
<remarks>
|
||||
These keys match a definition in the Lite application (part of the server SDK).
|
||||
If your game is built as extension of Lite, don't re-use these codes for your custom events.
|
||||
|
||||
These keys are defined per application, so Lite has different keys than MMO or your
|
||||
custom application. This is why these are not an enumeration.
|
||||
Lite and Lite Lobby will use the keys 255 and lower, to give you room for your own codes.
|
||||
|
||||
Keys for operation-parameters could be assigned on a per operation basis, but
|
||||
it makes sense to have fixed keys for values which are used throughout the whole
|
||||
application.
|
||||
</remarks>
|
||||
</member>
|
||||
<member name="F:ExitGames.Client.Photon.Lite.LiteOpKey.Asid">
|
||||
<summary>(255) Code of the room name. Used in OpJoin (Asid = Application Session ID).</summary>
|
||||
</member>
|
||||
<member name="F:ExitGames.Client.Photon.Lite.LiteOpKey.RoomName">
|
||||
<summary>(255) Code of the room name. Used in OpJoin.</summary>
|
||||
<remarks>Alternative for: Asid!</remarks>
|
||||
</member>
|
||||
<member name="F:ExitGames.Client.Photon.Lite.LiteOpKey.GameId">
|
||||
<summary>(255) Code of the game id (a unique room name). Used in OpJoin.</summary>
|
||||
</member>
|
||||
<member name="F:ExitGames.Client.Photon.Lite.LiteOpKey.ActorNr">
|
||||
<summary>(254) Code of the Actor of an operation. Used for property get and set.</summary>
|
||||
</member>
|
||||
<member name="F:ExitGames.Client.Photon.Lite.LiteOpKey.TargetActorNr">
|
||||
<summary>(253) Code of the target Actor of an operation. Used for property set. Is 0 for game</summary>
|
||||
</member>
|
||||
<member name="F:ExitGames.Client.Photon.Lite.LiteOpKey.ActorList">
|
||||
<summary>(252) Code for list of players in a room. Currently not used.</summary>
|
||||
</member>
|
||||
<member name="F:ExitGames.Client.Photon.Lite.LiteOpKey.Properties">
|
||||
<summary>
|
||||
(251) Code for property set (Hashtable). This key is used when sending only one set of properties.
|
||||
If either ActorProperties or GameProperties are used (or both), check those keys.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:ExitGames.Client.Photon.Lite.LiteOpKey.Broadcast">
|
||||
<summary>(250) Code for broadcast parameter of OpSetProperties method.</summary>
|
||||
</member>
|
||||
<member name="F:ExitGames.Client.Photon.Lite.LiteOpKey.ActorProperties">
|
||||
<summary>(249) Code for property set (Hashtable).</summary>
|
||||
</member>
|
||||
<member name="F:ExitGames.Client.Photon.Lite.LiteOpKey.GameProperties">
|
||||
<summary>(248) Code for property set (Hashtable).</summary>
|
||||
</member>
|
||||
<member name="F:ExitGames.Client.Photon.Lite.LiteOpKey.Cache">
|
||||
<summary>(247) Code for caching events while raising them.</summary>
|
||||
</member>
|
||||
<member name="F:ExitGames.Client.Photon.Lite.LiteOpKey.ReceiverGroup">
|
||||
<summary>(246) Code to select the receivers of events (used in Lite, Operation RaiseEvent).</summary>
|
||||
</member>
|
||||
<member name="F:ExitGames.Client.Photon.Lite.LiteOpKey.Data">
|
||||
<summary>(245) Code of data of an event. Used in OpRaiseEvent.</summary>
|
||||
</member>
|
||||
<member name="F:ExitGames.Client.Photon.Lite.LiteOpKey.Code">
|
||||
<summary>(244) Code used when sending some code-related parameter, like OpRaiseEvent's event-code.</summary>
|
||||
<remarks>This is not the same as the Operation's code, which is no longer sent as part of the parameter Dictionary in Photon 3.</remarks>
|
||||
</member>
|
||||
<member name="T:ExitGames.Client.Photon.Lite.LitePropertyTypes">
|
||||
<summary>
|
||||
Lite - Flags for "types of properties", being used as filter in OpGetProperties.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:ExitGames.Client.Photon.Lite.LitePropertyTypes.None">
|
||||
<summary>(0x00) Flag type for no property type.</summary>
|
||||
</member>
|
||||
<member name="F:ExitGames.Client.Photon.Lite.LitePropertyTypes.Game">
|
||||
<summary>(0x01) Flag type for game-attached properties.</summary>
|
||||
</member>
|
||||
<member name="F:ExitGames.Client.Photon.Lite.LitePropertyTypes.Actor">
|
||||
<summary>(0x02) Flag type for actor related propeties.</summary>
|
||||
</member>
|
||||
<member name="F:ExitGames.Client.Photon.Lite.LitePropertyTypes.GameAndActor">
|
||||
<summary>(0x01) Flag type for game AND actor properties. Equal to 'Game'</summary>
|
||||
</member>
|
||||
<member name="T:ExitGames.Client.Photon.Lite.EventCaching">
|
||||
<summary>
|
||||
Lite - OpRaiseEvent allows you to cache events and automatically send them to joining players in a room.
|
||||
Events are cached per event code and player: Event 100 (example!) can be stored once per player.
|
||||
Cached events can be modified, replaced and removed.
|
||||
</summary>
|
||||
<remarks>
|
||||
Caching works only combination with ReceiverGroup options Others and All.
|
||||
</remarks>
|
||||
</member>
|
||||
<member name="F:ExitGames.Client.Photon.Lite.EventCaching.DoNotCache">
|
||||
<summary>Default value (not sent).</summary>
|
||||
</member>
|
||||
<member name="F:ExitGames.Client.Photon.Lite.EventCaching.MergeCache">
|
||||
<summary>Will merge this event's keys with those already cached.</summary>
|
||||
</member>
|
||||
<member name="F:ExitGames.Client.Photon.Lite.EventCaching.ReplaceCache">
|
||||
<summary>Replaces the event cache for this eventCode with this event's content.</summary>
|
||||
</member>
|
||||
<member name="F:ExitGames.Client.Photon.Lite.EventCaching.RemoveCache">
|
||||
<summary>Removes this event (by eventCode) from the cache.</summary>
|
||||
</member>
|
||||
<member name="F:ExitGames.Client.Photon.Lite.EventCaching.AddToRoomCache">
|
||||
<summary>Adds an event to the room's cache.</summary>
|
||||
</member>
|
||||
<member name="F:ExitGames.Client.Photon.Lite.EventCaching.AddToRoomCacheGlobal">
|
||||
<summary>Adds this event to the cache for actor 0 (becoming a "globally owned" event in the cache).</summary>
|
||||
</member>
|
||||
<member name="F:ExitGames.Client.Photon.Lite.EventCaching.RemoveFromRoomCache">
|
||||
<summary>Remove fitting event from the room's cache.</summary>
|
||||
</member>
|
||||
<member name="F:ExitGames.Client.Photon.Lite.EventCaching.RemoveFromRoomCacheForActorsLeft">
|
||||
<summary>Removes events of players who already left the room (cleaning up).</summary>
|
||||
</member>
|
||||
<member name="T:ExitGames.Client.Photon.Lite.ReceiverGroup">
|
||||
<summary>
|
||||
Lite - OpRaiseEvent lets you chose which actors in the room should receive events.
|
||||
By default, events are sent to "Others" but you can overrule this.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:ExitGames.Client.Photon.Lite.ReceiverGroup.Others">
|
||||
<summary>Default value (not sent). Anyone else gets my event.</summary>
|
||||
</member>
|
||||
<member name="F:ExitGames.Client.Photon.Lite.ReceiverGroup.All">
|
||||
<summary>Everyone in the current room (including this peer) will get this event.</summary>
|
||||
</member>
|
||||
<member name="F:ExitGames.Client.Photon.Lite.ReceiverGroup.MasterClient">
|
||||
<summary>The server sends this event only to the actor with the lowest actorNumber.</summary>
|
||||
<remarks>The "master client" does not have special rights but is the one who is in this room the longest time.</remarks>
|
||||
</member>
|
||||
<member name="T:ExitGames.Client.Photon.Lite.LitePeer">
|
||||
<summary>
|
||||
A LitePeer is an extended PhotonPeer and implements the operations offered by the "Lite" Application
|
||||
of the Photon Server SDK.
|
||||
</summary>
|
||||
<remarks>
|
||||
This class is used by our samples and allows rapid development of simple games. You can use rooms and
|
||||
properties and send events. For many games, this is a good start.
|
||||
|
||||
Operations are prefixed as "Op" and are always asynchronous. In most cases, an OperationResult is
|
||||
provided by a later call to OnOperationResult.
|
||||
</remarks>
|
||||
</member>
|
||||
<member name="T:ExitGames.Client.Photon.PhotonPeer">
|
||||
<summary>
|
||||
Instances of the PhotonPeer class are used to connect to a Photon server and communicate with it.
|
||||
</summary>
|
||||
<remarks>
|
||||
A PhotonPeer instance allows communication with the Photon Server, which in turn distributes messages
|
||||
to other PhotonPeer clients.<para></para>
|
||||
An application can use more than one PhotonPeer instance, which are treated as separate users on the
|
||||
server. Each should have its own listener instance, to separate the operations, callbacks and events.
|
||||
</remarks>
|
||||
</member>
|
||||
<member name="M:ExitGames.Client.Photon.PhotonPeer.TrafficStatsReset">
|
||||
<summary>
|
||||
Creates new instances of TrafficStats and starts a new timer for those.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:ExitGames.Client.Photon.PhotonPeer.peerCount">
|
||||
<summary>Used to assign a unique number to each peer of a process. Useful to separate debug output, etc.</summary>
|
||||
</member>
|
||||
<member name="F:ExitGames.Client.Photon.PhotonPeer.peerBase">
|
||||
<summary>Implements the message-protocol, based on the underlying network protocol (udp, tcp, http).</summary>
|
||||
</member>
|
||||
<member name="M:ExitGames.Client.Photon.PhotonPeer.#ctor(ExitGames.Client.Photon.IPhotonPeerListener,ExitGames.Client.Photon.ConnectionProtocol)">
|
||||
<summary>
|
||||
Creates a new PhotonPeer instance to communicate with Photon and selects either UDP or TCP as
|
||||
protocol. We recommend UDP.
|
||||
</summary>
|
||||
<param name="listener">a IPhotonPeerListener implementation</param>
|
||||
<param name="protocolType">Protocol to use to connect to Photon.</param>
|
||||
</member>
|
||||
<member name="M:ExitGames.Client.Photon.PhotonPeer.#ctor(ExitGames.Client.Photon.IPhotonPeerListener)">
|
||||
<summary>
|
||||
Creates a new PhotonPeer instance to communicate with Photon.<para></para>
|
||||
Connection is UDP based, except for Silverlight.
|
||||
</summary>
|
||||
<param name="listener">a IPhotonPeerListener implementation</param>
|
||||
</member>
|
||||
<member name="M:ExitGames.Client.Photon.PhotonPeer.#ctor(ExitGames.Client.Photon.IPhotonPeerListener,System.Boolean)">
|
||||
<summary>
|
||||
Deprecated. Please use: PhotonPeer(IPhotonPeerListener listener, ConnectionProtocol protocolType).
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:ExitGames.Client.Photon.PhotonPeer.Connect(System.String,System.String)">
|
||||
<summary>
|
||||
This method does a DNS lookup (if necessary) and connects to the given serverAddress.
|
||||
|
||||
The return value gives you feedback if the address has the correct format. If so, this
|
||||
starts the process to establish the connection itself, which might take a few seconds.
|
||||
|
||||
When the connection is established, a callback to IPhotonPeerListener.OnStatusChanged
|
||||
will be done. If the connection can't be established, despite having a valid address,
|
||||
the OnStatusChanged is called with an error-value.
|
||||
|
||||
The applicationName defines the application logic to use server-side and it should match the name of
|
||||
one of the apps in your server's config.
|
||||
|
||||
By default, the applicationName is "Lite" but other samples use "LiteLobby" and "MmoDemo" in
|
||||
Connect(). You can setup your own application and name it any way you like.
|
||||
</summary>
|
||||
<param name="serverAddress">
|
||||
Address of the Photon server. Format: ip:port (e.g. 127.0.0.1:5055) or hostname:port (e.g. localhost:5055)
|
||||
</param>
|
||||
<param name="applicationName">
|
||||
The name of the application to use within Photon or the appId of PhotonCloud.
|
||||
Should match a "Name" for an application, as setup in your PhotonServer.config.
|
||||
</param>
|
||||
<returns>
|
||||
true if IP is available (DNS name is resolved) and server is being connected. false on error.
|
||||
</returns>
|
||||
</member>
|
||||
<member name="M:ExitGames.Client.Photon.PhotonPeer.Connect(System.String,System.String,System.Byte)">
|
||||
<summary>
|
||||
Special version of Connect, to be used with a TCP-routing setup.
|
||||
</summary>
|
||||
<param name="serverAddress">
|
||||
Address of the Photon server. Format: ip:port (e.g. 127.0.0.1:5055) or hostname:port (e.g. localhost:5055)
|
||||
</param>
|
||||
<param name="applicationName">
|
||||
The name of the application to use within Photon or the appId of PhotonCloud.
|
||||
Should match a "Name" for an application, as setup in your PhotonServer.config.
|
||||
</param>
|
||||
<param name="node">A node of 0 does not send the routing-request. The response is provided by OnStatusChanged() and maybe a disconnect.</param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:ExitGames.Client.Photon.PhotonPeer.Disconnect">
|
||||
<summary>
|
||||
This method initiates a mutual disconnect between this client and the server.
|
||||
</summary>
|
||||
<remarks>
|
||||
Calling this method does not immediately close a connection. Disconnect lets the server
|
||||
know that this client is no longer listening. For the server, this is a much faster way
|
||||
to detect that the client is gone but it requires the client to send a few final messages.
|
||||
|
||||
On completition, OnStatusChanged is called with the StatusCode.Disconnect.
|
||||
|
||||
If the client is disconnected already or the connection thread is stopped, then there is no callback.
|
||||
|
||||
Lite: The default server logic will leave any joined game and trigger the respective event
|
||||
(<see cref="F:ExitGames.Client.Photon.Lite.LiteEventCode.Leave" text="LiteEventCode.Leave"/>) for the remaining players.
|
||||
</remarks>
|
||||
</member>
|
||||
<member name="M:ExitGames.Client.Photon.PhotonPeer.StopThread">
|
||||
<summary>
|
||||
This method immediately closes a connection (pure client side) and ends related listening Threads.
|
||||
</summary>
|
||||
<remarks>
|
||||
Unlike Disconnect, this method will simply stop to listen to the server. Udp connections will timeout.
|
||||
If the connections was open, this will trigger a callback to OnStatusChanged with code StatusCode.Disconnect.
|
||||
</remarks>
|
||||
</member>
|
||||
<member name="M:ExitGames.Client.Photon.PhotonPeer.FetchServerTimestamp">
|
||||
<summary>
|
||||
This will fetch the server's timestamp and update the approximation for property ServerTimeInMilliseconds.
|
||||
|
||||
The server time approximation will NOT become more accurate by repeated calls. Accuracy currently depends
|
||||
on a single roundtrip which is done as fast as possible.
|
||||
|
||||
The command used for this is immediately acknowledged by the server. This makes sure the roundtrip time is
|
||||
low and the timestamp + rountriptime / 2 is close to the original value.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:ExitGames.Client.Photon.PhotonPeer.EstablishEncryption">
|
||||
<summary>
|
||||
This method creates a public key for this client and exchanges it with the server.
|
||||
</summary>
|
||||
<remarks>
|
||||
Encryption is not instantly available but calls OnStatusChanged when it finishes.
|
||||
Check for StatusCode EncryptionEstablished and EncryptionFailedToEstablish.
|
||||
|
||||
Calling this method sets IsEncryptionAvailable to false.
|
||||
This method must be called before the "encrypt" parameter of OpCustom can be used.
|
||||
</remarks>
|
||||
<returns>If operation could be enqueued for sending</returns>
|
||||
</member>
|
||||
<member name="M:ExitGames.Client.Photon.PhotonPeer.Service">
|
||||
<summary>
|
||||
This method excutes DispatchIncomingCommands and SendOutgoingCommands in your application Thread-context.
|
||||
</summary>
|
||||
<remarks>
|
||||
The Photon client libraries are designed to fit easily into a game or application. The application
|
||||
is in control of the context (thread) in which incoming events and responses are executed and has
|
||||
full control of the creation of UDP/TCP packages.
|
||||
|
||||
Sending packages and dispatching received messages are two separate tasks. Service combines them
|
||||
into one method at the cost of control. It calls DispatchIncomingCommands and SendOutgoingCommands.
|
||||
|
||||
Call this method regularly (2..20 times a second).
|
||||
|
||||
This will Dispatch ANY remaining buffered responses and events AND will send queued outgoing commands.
|
||||
Fewer calls might be more effective if a device cannot send many packets per second, as multiple
|
||||
operations might be combined into one package.
|
||||
</remarks>
|
||||
<example>
|
||||
You could replace Service by:
|
||||
|
||||
while (DispatchIncomingCommands()); //Dispatch until everything is Dispatched...
|
||||
SendOutgoingCommands(); //Send a UDP/TCP package with outgoing messages
|
||||
</example>
|
||||
<seealso cref="M:ExitGames.Client.Photon.PhotonPeer.DispatchIncomingCommands"/>
|
||||
<seealso cref="M:ExitGames.Client.Photon.PhotonPeer.SendOutgoingCommands"/>
|
||||
</member>
|
||||
<member name="M:ExitGames.Client.Photon.PhotonPeer.SendOutgoingCommands">
|
||||
<summary>
|
||||
This method creates a UDP/TCP package for outgoing commands (operations and acknowledgements)
|
||||
and sends them to the server.
|
||||
This method is also called by Service().
|
||||
</summary>
|
||||
<remarks>
|
||||
As the Photon library does not create any UDP/TCP packages by itself. Instead, the application
|
||||
fully controls how many packages are sent and when. A tradeoff, an application will
|
||||
lose connection, if it is no longer calling SendOutgoingCommands or Service.
|
||||
|
||||
If multiple operations and ACKs are waiting to be sent, they will be aggregated into one
|
||||
package. The package fills in this order:
|
||||
ACKs for received commands
|
||||
A "Ping" - only if no reliable data was sent for a while
|
||||
Starting with the lowest Channel-Nr:
|
||||
Reliable Commands in channel
|
||||
Unreliable Commands in channel
|
||||
|
||||
This gives a higher priority to lower channels.
|
||||
|
||||
A longer interval between sends will lower the overhead per sent operation but
|
||||
increase the internal delay (which adds "lag").
|
||||
|
||||
Call this 2..20 times per second (depending on your target platform).
|
||||
</remarks>
|
||||
<returns>The if commands are not yet sent. Udp limits it's package size, Tcp doesnt.</returns>
|
||||
</member>
|
||||
<member name="M:ExitGames.Client.Photon.PhotonPeer.DispatchIncomingCommands">
|
||||
<summary>
|
||||
This method directly causes the callbacks for events, responses and state changes
|
||||
within a IPhotonPeerListener. DispatchIncomingCommands only executes a single received
|
||||
command per call. If a command was dispatched, the return value is true and the method
|
||||
should be called again.
|
||||
This method is called by Service() until currently available commands are dispatched.
|
||||
</summary>
|
||||
<remarks>
|
||||
In general, this method should be called until it returns false. In a few cases, it might
|
||||
make sense to pause dispatching (if a certain state is reached and the app needs to load
|
||||
data, before it should handle new events).
|
||||
|
||||
The callbacks to the peer's IPhotonPeerListener are executed in the same thread that is
|
||||
calling DispatchIncomingCommands. This makes things easier in a game loop: Event execution
|
||||
won't clash with painting objects or the game logic.
|
||||
</remarks>
|
||||
</member>
|
||||
<member name="M:ExitGames.Client.Photon.PhotonPeer.VitalStatsToString(System.Boolean)">
|
||||
<summary>
|
||||
Returns a string of the most interesting connection statistics.
|
||||
When you have issues on the client side, these might contain hints about the issue's cause.
|
||||
</summary>
|
||||
<param name="all">If true, Incoming and Outgoing low-level stats are included in the string.</param>
|
||||
<returns>Stats as string.</returns>
|
||||
</member>
|
||||
<member name="M:ExitGames.Client.Photon.PhotonPeer.OpCustom(System.Byte,System.Collections.Generic.Dictionary{System.Byte,System.Object},System.Boolean)">
|
||||
<summary>
|
||||
Channel-less wrapper for OpCustom().
|
||||
</summary>
|
||||
<param name="customOpCode">Operations are handled by their byte\-typed code. The codes of the
|
||||
"Lite" application are in the struct <see cref="T:ExitGames.Client.Photon.Lite.LiteOpCode"/>.</param>
|
||||
<param name="customOpParameters">Containing parameters as key\-value pair. The key is byte\-typed, while the value is any serializable datatype.</param>
|
||||
<param name="sendReliable">Selects if the operation must be acknowledged or not. If false, the
|
||||
operation is not guaranteed to reach the server.</param>
|
||||
<returns>If operation could be enqueued for sending</returns>
|
||||
</member>
|
||||
<member name="M:ExitGames.Client.Photon.PhotonPeer.OpCustom(System.Byte,System.Collections.Generic.Dictionary{System.Byte,System.Object},System.Boolean,System.Byte)">
|
||||
<summary>
|
||||
Allows the client to send any operation to the Photon Server by setting any opCode and the operation's parameters.
|
||||
</summary>
|
||||
<remarks></remarks>
|
||||
Photon can be extended with new operations which are identified by a single
|
||||
byte, defined server side and known as operation code (opCode). Similarly, the operation's parameters
|
||||
are defined server side as byte keys of values, which a client sends as customOpParameters
|
||||
accordingly.<para></para>
|
||||
This is explained in more detail as "<see cref="!:Operations" text="Custom Operations"/>".
|
||||
<param name="customOpCode">Operations are handled by their byte\-typed code. The codes of the
|
||||
"Lite" application are in the struct <see cref="T:ExitGames.Client.Photon.Lite.LiteOpCode"/>.</param>
|
||||
<param name="customOpParameters">Containing parameters as key\-value pair. The key is byte\-typed, while the value is any serializable datatype.</param>
|
||||
<param name="sendReliable">Selects if the operation must be acknowledged or not. If false, the
|
||||
operation is not guaranteed to reach the server.</param>
|
||||
<param name="channelId">The channel in which this operation should be sent.</param>
|
||||
<returns>If operation could be enqueued for sending</returns>
|
||||
</member>
|
||||
<member name="M:ExitGames.Client.Photon.PhotonPeer.OpCustom(System.Byte,System.Collections.Generic.Dictionary{System.Byte,System.Object},System.Boolean,System.Byte,System.Boolean)">
|
||||
<summary>
|
||||
Allows the client to send any operation to the Photon Server by setting any opCode and the operation's parameters.
|
||||
</summary>
|
||||
<summary>
|
||||
Variant with encryption parameter.
|
||||
|
||||
Use this only after encryption was established by EstablishEncryption and waiting for the OnStateChanged callback.
|
||||
</summary>
|
||||
<param name="customOpCode">Operations are handled by their byte\-typed code. The codes of the
|
||||
"Lite" application are in the struct <see cref="T:ExitGames.Client.Photon.Lite.LiteOpCode"/>.</param>
|
||||
<param name="customOpParameters">Containing parameters as key\-value pair. The key is byte\-typed, while the value is any serializable datatype.</param>
|
||||
<param name="sendReliable">Selects if the operation must be acknowledged or not. If false, the
|
||||
operation is not guaranteed to reach the server.</param>
|
||||
<param name="channelId">The channel in which this operation should be sent.</param>
|
||||
<param name="encrypt">Can only be true, while IsEncryptionAvailable is true, too.</param>
|
||||
<returns>If operation could be enqueued for sending</returns>
|
||||
</member>
|
||||
<member name="M:ExitGames.Client.Photon.PhotonPeer.OpCustom(ExitGames.Client.Photon.OperationRequest,System.Boolean,System.Byte,System.Boolean)">
|
||||
<summary>
|
||||
Allows the client to send any operation to the Photon Server by setting any opCode and the operation's parameters.
|
||||
</summary>
|
||||
<remarks>
|
||||
Variant with an OperationRequest object.
|
||||
|
||||
This variant offers an alternative way to describe a operation request. Operation code and it's parameters
|
||||
are wrapped up in a object. Still, the parameters are a Dictionary.
|
||||
</remarks>
|
||||
<param name="operationRequest">The operation to call on Photon.</param>
|
||||
<param name="sendReliable">Use unreliable (false) if the call might get lost (when it's content is soon outdated).</param>
|
||||
<param name="channelId">Defines the sequence of requests this operation belongs to.</param>
|
||||
<param name="encrypt">Encrypt request before sending. Depends on IsEncryptionAvailable.</param>
|
||||
<returns>If operation could be enqueued for sending</returns>
|
||||
</member>
|
||||
<member name="M:ExitGames.Client.Photon.PhotonPeer.RegisterType(System.Type,System.Byte,ExitGames.Client.Photon.SerializeMethod,ExitGames.Client.Photon.DeserializeMethod)">
|
||||
<summary>
|
||||
Registers new types/classes for de/serialization and the fitting methods to call for this type.
|
||||
</summary>
|
||||
<remarks>
|
||||
SerializeMethod and DeserializeMethod are complementary: Feed the product of serializeMethod to
|
||||
the constructor, to get a comparable instance of the object.
|
||||
|
||||
After registering a Type, it can be used in events and operations and will be serialized like
|
||||
built-in types.
|
||||
</remarks>
|
||||
<param name="customType">Type (class) to register.</param>
|
||||
<param name="code">A byte-code used as shortcut during transfer of this Type.</param>
|
||||
<param name="serializeMethod">Method delegate to create a byte[] from a customType instance.</param>
|
||||
<param name="constructor">Method delegate to create instances of customType's from byte[].</param>
|
||||
<returns>If the Type was registered successfully.</returns>
|
||||
</member>
|
||||
<member name="P:ExitGames.Client.Photon.PhotonPeer.DebugOut">
|
||||
<summary>
|
||||
Sets the level (and amount) of debug output provided by the library.
|
||||
</summary>
|
||||
<remarks>
|
||||
This affects the callbacks to IPhotonPeerListener.DebugReturn.
|
||||
Default Level: Error.
|
||||
</remarks>
|
||||
</member>
|
||||
<member name="P:ExitGames.Client.Photon.PhotonPeer.Listener">
|
||||
<summary>
|
||||
Gets the IPhotonPeerListener of this instance (set in constructor).
|
||||
Can be used in derived classes for Listener.DebugReturn().
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:ExitGames.Client.Photon.PhotonPeer.BytesIn">
|
||||
<summary>
|
||||
Gets count of all bytes coming in (including headers, excluding UDP/TCP overhead)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:ExitGames.Client.Photon.PhotonPeer.BytesOut">
|
||||
<summary>
|
||||
Gets count of all bytes going out (including headers, excluding UDP/TCP overhead)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:ExitGames.Client.Photon.PhotonPeer.ByteCountCurrentDispatch">
|
||||
<summary>
|
||||
Gets the size of the dispatched event or operation-result in bytes.
|
||||
This value is set before OnEvent() or OnOperationResponse() is called (within DispatchIncomingCommands()).
|
||||
</summary>
|
||||
<remarks>
|
||||
Get this value directly in OnEvent() or OnOperationResponse(). Example:
|
||||
void OnEvent(...) {
|
||||
int eventSizeInBytes = this.peer.ByteCountCurrentDispatch;
|
||||
//...
|
||||
|
||||
void OnOperationResponse(...) {
|
||||
int resultSizeInBytes = this.peer.ByteCountCurrentDispatch;
|
||||
//...
|
||||
</remarks>
|
||||
</member>
|
||||
<member name="P:ExitGames.Client.Photon.PhotonPeer.ByteCountLastOperation">
|
||||
<summary>
|
||||
Gets the size of the last serialized operation call in bytes.
|
||||
The value includes all headers for this single operation but excludes those of UDP, Enet Package Headers and TCP.
|
||||
</summary>
|
||||
<remarks>
|
||||
Get this value immediately after calling an operation. Example:
|
||||
this.litepeer.OpJoin("myroom");
|
||||
int opjoinByteCount = this.peer.ByteCountLastOperation;
|
||||
</remarks>
|
||||
</member>
|
||||
<member name="P:ExitGames.Client.Photon.PhotonPeer.TrafficStatsEnabled">
|
||||
<summary>
|
||||
Enables the traffic statistics of a peer: TrafficStatsIncoming, TrafficStatsOutgoing and TrafficstatsGameLevel (nothing else).
|
||||
Default value: false (disabled).
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:ExitGames.Client.Photon.PhotonPeer.TrafficStatsElapsedMs">
|
||||
<summary>
|
||||
Returns the count of milliseconds the stats are enabled for tracking.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:ExitGames.Client.Photon.PhotonPeer.TrafficStatsIncoming">
|
||||
<summary>
|
||||
Gets the byte-count of incoming "low level" messages, which are either Enet Commands or Tcp Messages.
|
||||
These include all headers, except those of the underlying internet protocol Udp or Tcp.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:ExitGames.Client.Photon.PhotonPeer.TrafficStatsOutgoing">
|
||||
<summary>
|
||||
Gets the byte-count of outgoing "low level" messages, which are either Enet Commands or Tcp Messages.
|
||||
These include all headers, except those of the underlying internet protocol Udp or Tcp.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:ExitGames.Client.Photon.PhotonPeer.TrafficStatsGameLevel">
|
||||
<summary>
|
||||
Gets a statistic of incoming and outgoing traffic, split by operation, operation-result and event.
|
||||
Operations are outgoing traffic, results and events are incoming.
|
||||
Includes the per-command header sizes (Udp: Enet Command Header or Tcp: Message Header).
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:ExitGames.Client.Photon.PhotonPeer.PeerState">
|
||||
<summary>
|
||||
This is the (low level) state of the connection to the server of a PhotonPeer.
|
||||
It is managed internally and read-only.
|
||||
</summary>
|
||||
<remarks>
|
||||
Don't mix this up with the StatusCode provided in IPhotonListener.OnStatusChanged().
|
||||
Applications should use the StatusCode of OnStatusChanged() to track their state, as
|
||||
it also covers the higher level initialization between a client and Photon.
|
||||
</remarks>
|
||||
</member>
|
||||
<member name="P:ExitGames.Client.Photon.PhotonPeer.PeerID">
|
||||
<summary>
|
||||
This peer's ID as assigned by the server or 0 if not using UDP. Will be 0xFFFF before the client connects.
|
||||
</summary>
|
||||
<remarks>Used for debugging only. This value is not useful in everyday Photon usage.</remarks>
|
||||
</member>
|
||||
<member name="P:ExitGames.Client.Photon.PhotonPeer.CommandBufferSize">
|
||||
<summary>
|
||||
Initial size internal lists for incoming/outgoing commands (reliable and unreliable).
|
||||
</summary>
|
||||
<remarks>
|
||||
This sets only the initial size. All lists simply grow in size as needed. This means that
|
||||
incoming or outgoing commands can pile up and consume heap size if Service is not called
|
||||
often enough to handle the messages in either direction.
|
||||
|
||||
Configure the WarningSize, to get callbacks when the lists reach a certain size.
|
||||
|
||||
UDP: Incoming and outgoing commands each have separate buffers for reliable and unreliable sending.
|
||||
There are additional buffers for "sent commands" and "ACKs".
|
||||
TCP: Only two buffers exist: incoming and outgoing commands.
|
||||
</remarks>
|
||||
</member>
|
||||
<member name="P:ExitGames.Client.Photon.PhotonPeer.LimitOfUnreliableCommands">
|
||||
<summary>
|
||||
Limits the queue of received unreliable commands within DispatchIncomingCommands before dispatching them.
|
||||
This works only in UDP.
|
||||
This limit is applied when you call DispatchIncomingCommands. If this client (already) received more than
|
||||
LimitOfUnreliableCommands, it will throw away the older ones instead of dispatching them. This can produce
|
||||
bigger gaps for unreliable commands but your client catches up faster.
|
||||
</summary>
|
||||
<remarks>
|
||||
This can be useful when the client couldn't dispatch anything for some time (cause it was in a room but
|
||||
loading a level).
|
||||
If set to 20, the incoming unreliable queues are truncated to 20.
|
||||
If 0, all received unreliable commands will be dispatched.
|
||||
This is a "per channel" value, so each channel can hold up to LimitOfUnreliableCommands commands.
|
||||
This value interacts with DispatchIncomingCommands: If that is called less often, more commands get skipped.
|
||||
</remarks>
|
||||
</member>
|
||||
<member name="P:ExitGames.Client.Photon.PhotonPeer.QueuedIncomingCommands">
|
||||
<summary>
|
||||
Count of all currently received but not-yet-Dispatched reliable commands
|
||||
(events and operation results) from all channels.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:ExitGames.Client.Photon.PhotonPeer.QueuedOutgoingCommands">
|
||||
<summary>
|
||||
Count of all commands currently queued as outgoing, including all channels and reliable, unreliable.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:ExitGames.Client.Photon.PhotonPeer.ChannelCount">
|
||||
<summary>
|
||||
Gets / sets the number of channels available in UDP connections with Photon.
|
||||
Photon Channels are only supported for UDP.
|
||||
The default ChannelCount is 2. Channel IDs start with 0 and 255 is a internal channel.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:ExitGames.Client.Photon.PhotonPeer.WarningSize">
|
||||
<summary>
|
||||
The WarningSize is used test all message queues for congestion (in and out, reliable and unreliable).
|
||||
OnStatusChanged will be called with a warning if a queue holds WarningSize commands or a multiple
|
||||
of it.
|
||||
Default: 100.
|
||||
Example: If command is received, OnStatusChanged will be called when the respective command queue
|
||||
has 100, 200, 300 ... items.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:ExitGames.Client.Photon.PhotonPeer.SentCountAllowance">
|
||||
<summary>
|
||||
Number of send retries before a peer is considered lost/disconnected. Default: 5.
|
||||
The initial timeout countdown of a command is calculated by the current roundTripTime + 4 * roundTripTimeVariance.
|
||||
Please note that the timeout span until a command will be resent is not constant, but based on
|
||||
the roundtrip time at the initial sending, which will be doubled with every failed retry.
|
||||
|
||||
DisconnectTimeout and SentCountAllowance are competing settings: either might trigger a disconnect on the
|
||||
client first, depending on the values and Rountrip Time.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:ExitGames.Client.Photon.PhotonPeer.TimePingInterval">
|
||||
<summary>
|
||||
Sets the milliseconds without reliable command before a ping command (reliable) will be sent (Default: 1000ms).
|
||||
The ping command is used to keep track of the connection in case the client does not send reliable commands
|
||||
by itself.
|
||||
A ping (or reliable commands) will update the RoundTripTime calculation.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:ExitGames.Client.Photon.PhotonPeer.DisconnectTimeout">
|
||||
<summary>
|
||||
Milliseconds after which a reliable UDP command triggers a timeout disconnect, unless acknowledged by server.
|
||||
This value currently only affects UDP connections.
|
||||
DisconnectTimeout is not an exact value for a timeout. The exact timing of the timeout depends on the frequency
|
||||
of Service() calls and commands that are sent with long roundtrip-times and variance are checked less often for
|
||||
re-sending!
|
||||
|
||||
DisconnectTimeout and SentCountAllowance are competing settings: either might trigger a disconnect on the
|
||||
client first, depending on the values and Rountrip Time.
|
||||
Default: 10000 ms.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:ExitGames.Client.Photon.PhotonPeer.ServerTimeInMilliSeconds">
|
||||
<summary>
|
||||
Approximated Environment.TickCount value of server (while connected).
|
||||
</summary>
|
||||
<remarks>
|
||||
UDP: The server's timestamp is automatically fetched after connecting (once). This is done
|
||||
internally by a command which is acknowledged immediately by the server.
|
||||
TCP: The server's timestamp fetched with each ping but set only after connecting (once).
|
||||
|
||||
The approximation will be off by +/- 10ms in most cases. Per peer/client and connection, the
|
||||
offset will be constant (unless FetchServerTimestamp() is used). A constant offset should be
|
||||
better to adjust for. Unfortunately there is no way to find out how much the local value
|
||||
differs from the original.
|
||||
|
||||
The approximation adds RoundtripTime / 2 and uses this.LocalTimeInMilliSeconds to calculate
|
||||
in-between values (this property returns a new value per tick).
|
||||
|
||||
The value sent by Photon equals Environment.TickCount in the logic layer (e.g. Lite).
|
||||
</remarks>
|
||||
<value>
|
||||
0 until connected.
|
||||
While connected, the value is an approximation of the server's current timestamp.
|
||||
</value>
|
||||
</member>
|
||||
<member name="P:ExitGames.Client.Photon.PhotonPeer.LocalTimeInMilliSeconds">
|
||||
<summary>
|
||||
Gets a local timestamp in milliseconds by calling the GetLocalMsTimestampDelegate.
|
||||
See LocalMsTimestampDelegate.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:ExitGames.Client.Photon.PhotonPeer.LocalMsTimestampDelegate">
|
||||
<summary>
|
||||
This setter for a timestamp delegate which then replaces the default Environment.TickCount with any equal function.
|
||||
</summary>
|
||||
<remarks>
|
||||
About Environment.TickCount:
|
||||
The value of this property is derived from the system timer and is stored as a 32-bit signed integer.
|
||||
Consequently, if the system runs continuously, TickCount will increment from zero to Int32..::.MaxValue
|
||||
for approximately 24.9 days, then jump to Int32..::.MinValue, which is a negative number, then increment
|
||||
back to zero during the next 24.9 days.
|
||||
</remarks>
|
||||
<exception cref="T:System.Exception">Exception is thrown peer.PeerState is not PS_DISCONNECTED.</exception>
|
||||
</member>
|
||||
<member name="P:ExitGames.Client.Photon.PhotonPeer.RoundTripTime">
|
||||
<summary>
|
||||
Time until a reliable command is acknowledged by the server.
|
||||
|
||||
The value measures network latency and for UDP it includes the server's ACK-delay (setting in config).
|
||||
In TCP, there is no ACK-delay, so the value is slightly lower (if you use default settings for Photon).
|
||||
|
||||
RoundTripTime is updated constantly. Every reliable command will contribute a fraction to this value.
|
||||
|
||||
This is also the approximate time until a raised event reaches another client or until an operation
|
||||
result is available.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:ExitGames.Client.Photon.PhotonPeer.RoundTripTimeVariance">
|
||||
<summary>
|
||||
Changes of the roundtriptime as variance value. Gives a hint about how much the time is changing.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:ExitGames.Client.Photon.PhotonPeer.TimestampOfLastSocketReceive">
|
||||
<summary>
|
||||
Stores GetLocalMsTimestamp() of the last time anything (!) was received from the server (including
|
||||
low level Ping and ACKs but also events and operation-returns). This is not the time when
|
||||
something was dispatched.
|
||||
If you enable NetworkSimulation, this value is affected as well.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:ExitGames.Client.Photon.PhotonPeer.ServerAddress">
|
||||
<summary>
|
||||
The server address which was used in PhotonPeer.Connect() or null (before Connect() was called).
|
||||
</summary>
|
||||
<remarks>
|
||||
The ServerAddress can only be changed for HTTP connections (to replace one that goes through a Loadbalancer with a direct URL).
|
||||
</remarks>
|
||||
</member>
|
||||
<!-- Badly formed XML comment ignored for member "P:ExitGames.Client.Photon.PhotonPeer.HttpUrlParameters" -->
|
||||
<member name="P:ExitGames.Client.Photon.PhotonPeer.UsedProtocol">
|
||||
<summary>The protocol this Peer uses to connect to Photon.</summary>
|
||||
</member>
|
||||
<member name="P:ExitGames.Client.Photon.PhotonPeer.IsSimulationEnabled">
|
||||
<summary>
|
||||
Gets or sets the network simulation "enabled" setting.
|
||||
Changing this value also locks this peer's sending and when setting false,
|
||||
the internally used queues are executed (so setting to false can take some cycles).
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:ExitGames.Client.Photon.PhotonPeer.NetworkSimulationSettings">
|
||||
<summary>
|
||||
Gets the settings for built-in Network Simulation for this peer instance
|
||||
while IsSimulationEnabled will enable or disable them.
|
||||
Once obtained, the settings can be modified by changing the properties.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:ExitGames.Client.Photon.PhotonPeer.OutgoingStreamBufferSize">
|
||||
<summary>
|
||||
Defines the initial size of an internally used MemoryStream for Tcp.
|
||||
The MemoryStream is used to aggregate operation into (less) send calls,
|
||||
which uses less resoures.
|
||||
</summary>
|
||||
<remarks>
|
||||
The size is not restricing the buffer and does not affect when poutgoing data is actually sent.
|
||||
</remarks>
|
||||
</member>
|
||||
<member name="P:ExitGames.Client.Photon.PhotonPeer.MaximumTransferUnit">
|
||||
<summary>
|
||||
The Maximum Trasfer Unit (MTU) defines the (network-level) packet-content size that is
|
||||
guaranteed to arrive at the server in one piece. The Photon Protocol uses this
|
||||
size to split larger data into packets and for receive-buffers of packets.
|
||||
</summary>
|
||||
<remarks>
|
||||
This value affects the Packet-content. The resulting UDP packages will have additional
|
||||
headers that also count against the package size (so it's bigger than this limit in the end)
|
||||
Setting this value while being connected is not allowed and will throw an Exception.
|
||||
Minimum is 520. Huge values won't speed up connections in most cases!
|
||||
</remarks>
|
||||
</member>
|
||||
<member name="P:ExitGames.Client.Photon.PhotonPeer.IsEncryptionAvailable">
|
||||
<summary>
|
||||
This property is set internally, when OpExchangeKeysForEncryption successfully finished.
|
||||
While it's true, encryption can be used for operations.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:ExitGames.Client.Photon.PhotonPeer.IsSendingOnlyAcks">
|
||||
<summary>
|
||||
TODO: Comment this!
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:ExitGames.Client.Photon.Lite.LitePeer.#ctor(ExitGames.Client.Photon.IPhotonPeerListener)">
|
||||
<summary>
|
||||
Creates a LitePeer instance to connect and communicate with a Photon server.<para></para>
|
||||
Uses UDP as protocol (except in the Silverlight library).
|
||||
</summary>
|
||||
<param name="listener">Your IPhotonPeerListener implementation.</param>
|
||||
</member>
|
||||
<member name="M:ExitGames.Client.Photon.Lite.LitePeer.#ctor">
|
||||
<summary>
|
||||
Creates a LitePeer instance to connect and communicate with a Photon server.<para></para>
|
||||
Uses UDP as protocol (except in the Silverlight library).
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:ExitGames.Client.Photon.Lite.LitePeer.#ctor(ExitGames.Client.Photon.ConnectionProtocol)">
|
||||
<summary>
|
||||
Creates a LitePeer instance to connect and communicate with a Photon server.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:ExitGames.Client.Photon.Lite.LitePeer.#ctor(ExitGames.Client.Photon.IPhotonPeerListener,ExitGames.Client.Photon.ConnectionProtocol)">
|
||||
<summary>
|
||||
Creates a LitePeer instance to communicate with Photon with your selection of protocol.
|
||||
We recommend UDP.
|
||||
</summary>
|
||||
<param name="listener">Your IPhotonPeerListener implementation.</param>
|
||||
<param name="protocolType">Protocol to use to connect to Photon.</param>
|
||||
</member>
|
||||
<member name="M:ExitGames.Client.Photon.Lite.LitePeer.#ctor(ExitGames.Client.Photon.IPhotonPeerListener,System.Boolean)">
|
||||
<summary>
|
||||
Deprecated. Please use: LitePeer(IPhotonPeerListener listener, ConnectionProtocol protocolType).
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:ExitGames.Client.Photon.Lite.LitePeer.OpRaiseEvent(System.Byte,System.Collections.Hashtable,System.Boolean)">
|
||||
<summary>
|
||||
RaiseEvent tells the server to send an event to the other players within the same room.
|
||||
</summary>
|
||||
<remarks>
|
||||
This method is described in one of its overloads.
|
||||
</remarks>
|
||||
<param name="eventCode">Identifies this type of event (and the content). Your game's event codes can start with 0.</param>
|
||||
<param name="customEventContent">Custom data you want to send along (use null, if none).</param>
|
||||
<param name="sendReliable">If this event has to arrive reliably (potentially repeated if it's lost).</param>
|
||||
<returns>If operation could be enqueued for sending</returns>
|
||||
</member>
|
||||
<member name="M:ExitGames.Client.Photon.Lite.LitePeer.OpRaiseEvent(System.Byte,System.Collections.Hashtable,System.Boolean,System.Byte)">
|
||||
<summary>
|
||||
RaiseEvent tells the server to send an event to the other players within the same room.
|
||||
</summary>
|
||||
<remarks>
|
||||
Type and content of the event can be defined by the client side at will. The server only
|
||||
forwards the content and eventCode to others in the same room.
|
||||
|
||||
The eventCode should be used to define the event's type and content respectively.///
|
||||
Lite and Loadbalancing are using a few eventCode values already but those start with 255 and go down.
|
||||
Your eventCodes can start at 1, going up.
|
||||
|
||||
The customEventContent is a Hashtable with any number of key-value pairs of
|
||||
<see cref="!:Serializable Datatypes" text="serializable datatypes"/> or null.
|
||||
Receiving clients can access this Hashtable as Parameter LiteEventKey.Data (see below).
|
||||
|
||||
RaiseEvent can be used reliable or unreliable. Both result in ordered events but the unreliable ones
|
||||
might be lost and allow gaps in the resulting event sequence. On the other hand, they cause less
|
||||
overhead and are optimal for data that is replaced soon.
|
||||
|
||||
Like all operations, RaiseEvent is not done immediately but when you call SendOutgoingCommands.
|
||||
|
||||
It is recommended to keep keys (and data) as simple as possible (e.g. byte or short as key), as
|
||||
the data is typically sent multiple times per second. This easily adds up to a huge amount of data
|
||||
otherwise.
|
||||
</remarks>
|
||||
<example>
|
||||
<code>
|
||||
//send some position data (using byte-keys, as they are small):
|
||||
|
||||
Hashtable evInfo = new Hashtable();
|
||||
Player local = (Player)players[playerLocalID];
|
||||
evInfo.Add((byte)STATUS_PLAYER_POS_X, (int)local.posX);
|
||||
evInfo.Add((byte)STATUS_PLAYER_POS_Y, (int)local.posY);
|
||||
|
||||
peer.OpRaiseEvent(EV_MOVE, evInfo, true); //EV_MOVE = (byte)1
|
||||
|
||||
//receive this custom event in OnEvent():
|
||||
Hashtable data = (Hashtable)photonEvent[LiteEventKey.Data];
|
||||
switch (eventCode) {
|
||||
case EV_MOVE: //1 in this sample
|
||||
p = (Player)players[actorNr];
|
||||
if (p != null) {
|
||||
p.posX = (int)data[(byte)STATUS_PLAYER_POS_X];
|
||||
p.posY = (int)data[(byte)STATUS_PLAYER_POS_Y];
|
||||
}
|
||||
break;
|
||||
</code>
|
||||
|
||||
Events from the Photon Server are internally buffered until they are
|
||||
<see cref="M:ExitGames.Client.Photon.PhotonPeer.DispatchIncomingCommands" text="Dispatched"/>, just
|
||||
like OperationResults.
|
||||
</example>
|
||||
<param name="eventCode">Identifies this type of event (and the content). Your game's event codes can start with 0.</param>
|
||||
<param name="customEventContent">Custom data you want to send along (use null, if none).</param>
|
||||
<param name="sendReliable">If this event has to arrive reliably (potentially repeated if it's lost).</param>
|
||||
<param name="channelId">Number of channel (sequence) to use (starting with 0).</param>
|
||||
<returns>If operation could be enqueued for sending.</returns>
|
||||
</member>
|
||||
<member name="M:ExitGames.Client.Photon.Lite.LitePeer.OpRaiseEvent(System.Byte,System.Collections.Hashtable,System.Boolean,System.Byte,System.Int32[])">
|
||||
<summary>
|
||||
RaiseEvent tells the server to send an event to the other players within the same room.
|
||||
</summary>
|
||||
<remarks>
|
||||
This method is described in one of its overloads.
|
||||
|
||||
This variant has an optional list of targetActors. Use this to send the event only to
|
||||
specific actors in the same room, each identified by an actorNumber (or ID).
|
||||
|
||||
This can be useful to implement private messages inside a room or similar.
|
||||
</remarks>
|
||||
<param name="eventCode">Identifies this type of event (and the content). Your game's event codes can start with 0.</param>
|
||||
<param name="customEventContent">Custom data you want to send along (use null, if none).</param>
|
||||
<param name="sendReliable">If this event has to arrive reliably (potentially repeated if it's lost).</param>
|
||||
<param name="channelId">Number of channel to use (starting with 0).</param>
|
||||
<param name="targetActors">List of actorNumbers that receive this event.</param>
|
||||
<returns>If operation could be enqueued for sending.</returns>
|
||||
</member>
|
||||
<member name="M:ExitGames.Client.Photon.Lite.LitePeer.OpRaiseEvent(System.Byte,System.Collections.Hashtable,System.Boolean,System.Byte,ExitGames.Client.Photon.Lite.EventCaching,ExitGames.Client.Photon.Lite.ReceiverGroup)">
|
||||
<summary>
|
||||
Calls operation RaiseEvent on the server, with full control of event-caching and the target receivers.
|
||||
</summary>
|
||||
<remarks>
|
||||
This method is described in one of its overloads.
|
||||
|
||||
The cache parameter defines if and how this event will be cached server-side. Per event-code, your client
|
||||
can store events and update them and will send cached events to players joining the same room.
|
||||
|
||||
The option EventCaching.DoNotCache matches the default behaviour of RaiseEvent.
|
||||
The option EventCaching.MergeCache will merge the costomEventContent into existing one.
|
||||
Values in the customEventContent Hashtable can be null to remove existing values.
|
||||
|
||||
With the receivers parameter, you can chose who gets this event: Others (default), All (includes you as sender)
|
||||
or MasterClient. The MasterClient is the connected player with the lowest ActorNumber in this room.
|
||||
This player could get some privileges, if needed.
|
||||
|
||||
Read more about Cached Events in the DevNet: http://doc.exitgames.com
|
||||
</remarks>
|
||||
<param name="eventCode">Identifies this type of event (and the content). Your game's event codes can start with 0.</param>
|
||||
<param name="customEventContent">Custom data you want to send along (use null, if none).</param>
|
||||
<param name="sendReliable">If this event has to arrive reliably (potentially repeated if it's lost).</param>
|
||||
<param name="channelId">Number of channel to use (starting with 0).</param>
|
||||
<param name="cache">Events can be cached (merged and removed) for players joining later on.</param>
|
||||
<param name="receivers">Controls who should get this event.</param>
|
||||
<returns>If operation could be enqueued for sending.</returns>
|
||||
</member>
|
||||
<member name="M:ExitGames.Client.Photon.Lite.LitePeer.OpSetPropertiesOfActor(System.Int32,System.Collections.Hashtable,System.Boolean,System.Byte)">
|
||||
<summary>
|
||||
Attaches or updates properties of the specified actor.
|
||||
</summary>
|
||||
<remarks>
|
||||
Please read the general description of <see cref="!:Properties on Photon"/>.
|
||||
</remarks>
|
||||
<param name="properties">Hashtable containing the properties to add or update.</param>
|
||||
<param name="actorNr">the actorNr is used to identify a player/peer in a game</param>
|
||||
<param name="broadcast">true will trigger an event LiteEventKey.PropertiesChanged with the updated properties in it</param>
|
||||
<param name="channelId">Number of channel to use (starting with 0).</param>
|
||||
<returns>If operation could be enqueued for sending</returns>
|
||||
</member>
|
||||
<member name="M:ExitGames.Client.Photon.Lite.LitePeer.OpSetPropertiesOfGame(System.Collections.Hashtable,System.Boolean,System.Byte)">
|
||||
<summary>
|
||||
Attaches or updates properties of the current game.
|
||||
</summary>
|
||||
<remarks>
|
||||
Please read the general description of <see cref="!:Properties on Photon"/>.
|
||||
</remarks>
|
||||
<param name="properties">hashtable containing the properties to add or overwrite</param>
|
||||
<param name="broadcast">true will trigger an event LiteEventKey.PropertiesChanged with the updated
|
||||
properties in it</param>
|
||||
<param name="channelId">Number of channel to use (starting with 0).</param>
|
||||
<returns>If operation could be enqueued for sending</returns>
|
||||
</member>
|
||||
<member name="M:ExitGames.Client.Photon.Lite.LitePeer.OpGetProperties(System.Byte)">
|
||||
<summary>
|
||||
Gets all properties of the game and each actor.
|
||||
</summary>
|
||||
<remarks>
|
||||
Please read the general description of <see cref="!:Properties on Photon"/>.
|
||||
</remarks>
|
||||
<param name="channelId">Number of channel to use (starting with 0).</param>
|
||||
<returns>If operation could be enqueued for sending</returns>
|
||||
</member>
|
||||
<member name="M:ExitGames.Client.Photon.Lite.LitePeer.OpGetPropertiesOfActor(System.Int32[],System.String[],System.Byte)">
|
||||
<summary>
|
||||
Gets selected properties of an actor.
|
||||
</summary>
|
||||
<remarks>
|
||||
Please read the general description of <see cref="!:Properties on Photon"/>.
|
||||
</remarks>
|
||||
<param name="properties">optional, array of property keys to fetch</param>
|
||||
<param name="actorNrList">optional, a list of actornumbers to get the properties of</param>
|
||||
<param name="channelId">Number of channel to use (starting with 0).</param>
|
||||
<returns>If operation could be enqueued for sending</returns>
|
||||
</member>
|
||||
<member name="M:ExitGames.Client.Photon.Lite.LitePeer.OpGetPropertiesOfActor(System.Int32[],System.Byte[],System.Byte)">
|
||||
<summary>
|
||||
Gets selected properties of some actors.
|
||||
</summary>
|
||||
<remarks>
|
||||
Please read the general description of <see cref="!:Properties on Photon"/>.
|
||||
</remarks>
|
||||
<param name="properties">array of property keys to fetch. optional (can be null).</param>
|
||||
<param name="actorNrList">optional, a list of actornumbers to get the properties of</param>
|
||||
<param name="channelId">Number of channel to use (starting with 0).</param>
|
||||
<returns>If operation could be enqueued for sending</returns>
|
||||
</member>
|
||||
<member name="M:ExitGames.Client.Photon.Lite.LitePeer.OpGetPropertiesOfGame(System.String[],System.Byte)">
|
||||
<summary>
|
||||
Gets selected properties of current game.
|
||||
</summary>
|
||||
<remarks>
|
||||
Please read the general description of <see cref="!:Properties on Photon"/>.
|
||||
</remarks>
|
||||
<param name="properties">array of property keys to fetch. optional (can be null).</param>
|
||||
<param name="channelId">Number of channel to use (starting with 0).</param>
|
||||
<returns>If operation could be enqueued for sending</returns>
|
||||
</member>
|
||||
<member name="M:ExitGames.Client.Photon.Lite.LitePeer.OpGetPropertiesOfGame(System.Byte[],System.Byte)">
|
||||
<summary>
|
||||
Gets selected properties of current game.
|
||||
</summary>
|
||||
<remarks>
|
||||
Please read the general description of <see cref="!:Properties on Photon"/>.
|
||||
</remarks>
|
||||
<param name="properties">array of property keys to fetch. optional (can be null).</param>
|
||||
<param name="channelId">Number of channel to use (starting with 0).</param>
|
||||
<returns>If operation could be enqueued for sending</returns>
|
||||
</member>
|
||||
<member name="M:ExitGames.Client.Photon.Lite.LitePeer.OpJoin(System.String)">
|
||||
<summary>
|
||||
This operation will join an existing room by name or create one if the name is not in use yet.
|
||||
|
||||
Rooms (or games) are simply identified by name. We assume that users always want to get into a room - no matter
|
||||
if it existed before or not, so it might be a new one. If you want to make sure a room is created (new, empty),
|
||||
the client side might come up with a unique name for it (make sure the name was not taken yet).
|
||||
|
||||
The application "Lite Lobby" lists room names and effectively allows the user to select a distinct one.
|
||||
|
||||
Each actor (a.k.a. player) in a room will get events that are raised for the room by any player.
|
||||
|
||||
To distinguish the actors, each gets a consecutive actornumber. This is used in events to mark who triggered
|
||||
the event. A client finds out it's own actornumber in the return callback for operation Join. Number 1 is the
|
||||
lowest actornumber in each room and the client with that actornumber created the room.
|
||||
|
||||
Each client could easily send custom data around. If the data should be available to newcomers, it makes sense
|
||||
to use Properties.
|
||||
|
||||
Joining a room will trigger the event <see cref="F:ExitGames.Client.Photon.Lite.LiteEventCode.Join" text="LiteEventCode.Join"/>, which contains
|
||||
the list of actorNumbers of current players inside the room
|
||||
(<see cref="F:ExitGames.Client.Photon.Lite.LiteEventKey.ActorList" text="LiteEventKey.ActorList"/>). This also gives you a count of current
|
||||
players.
|
||||
</summary>
|
||||
<param name="gameName">Any identifying name for a room / game.</param>
|
||||
<returns>If operation could be enqueued for sending</returns>
|
||||
</member>
|
||||
<member name="M:ExitGames.Client.Photon.Lite.LitePeer.OpJoin(System.String,System.Collections.Hashtable,System.Collections.Hashtable,System.Boolean)">
|
||||
<summary>
|
||||
This operation will join an existing room by name or create one if the name is not in use yet.
|
||||
|
||||
Rooms (or games) are simply identified by name. We assume that users always want to get into a room - no matter
|
||||
if it existed before or not, so it might be a new one. If you want to make sure a room is created (new, empty),
|
||||
the client side might come up with a unique name for it (make sure the name was not taken yet).
|
||||
|
||||
The application "Lite Lobby" lists room names and effectively allows the user to select a distinct one.
|
||||
|
||||
Each actor (a.k.a. player) in a room will get events that are raised for the room by any player.
|
||||
|
||||
To distinguish the actors, each gets a consecutive actornumber. This is used in events to mark who triggered
|
||||
the event. A client finds out it's own actornumber in the return callback for operation Join. Number 1 is the
|
||||
lowest actornumber in each room and the client with that actornumber created the room.
|
||||
|
||||
Each client could easily send custom data around. If the data should be available to newcomers, it makes sense
|
||||
to use Properties.
|
||||
|
||||
Joining a room will trigger the event <see cref="F:ExitGames.Client.Photon.Lite.LiteEventCode.Join" text="LiteEventCode.Join"/>, which contains
|
||||
the list of actorNumbers of current players inside the room
|
||||
(<see cref="F:ExitGames.Client.Photon.Lite.LiteEventKey.ActorList" text="LiteEventKey.ActorList"/>). This also gives you a count of current
|
||||
players.
|
||||
</summary>
|
||||
|
||||
<param name="gameName">Any identifying name for a room / game.</param>
|
||||
<param name="gameProperties">optional, set of game properties, by convention: only used if game is new/created</param>
|
||||
<param name="actorProperties">optional, set of actor properties</param>
|
||||
<param name="broadcastActorProperties">optional, broadcast actor proprties in join-event</param>
|
||||
<returns>If operation could be enqueued for sending</returns>
|
||||
</member>
|
||||
<member name="M:ExitGames.Client.Photon.Lite.LitePeer.OpLeave">
|
||||
<summary>
|
||||
Leave operation of the Lite Application (also in Lite Lobby).
|
||||
Leaves a room / game, but keeps the connection. This operations triggers the event <see cref="F:ExitGames.Client.Photon.Lite.LiteEventCode.Leave" text="LiteEventCode.Leave"/>
|
||||
for the remaining clients. The event includes the actorNumber of the player who left in key <see cref="F:ExitGames.Client.Photon.Lite.LiteEventKey.ActorNr" text="LiteEventKey.ActorNr"/>.
|
||||
</summary>
|
||||
<returns>
|
||||
Consecutive invocationID of the OP. Will throw Exception if not connected.
|
||||
</returns>
|
||||
</member>
|
||||
<member name="T:ExitGames.Client.Photon.NCommand">
|
||||
<summary> Internal class for "commands" - the package in which operations are sent.</summary>
|
||||
</member>
|
||||
<member name="M:ExitGames.Client.Photon.NCommand.#ctor(ExitGames.Client.Photon.EnetPeer,System.Byte,System.Byte[],System.Byte)">
|
||||
<summary>this variant does only create outgoing commands and increments . incoming ones are created from a DataInputStream</summary>
|
||||
</member>
|
||||
<member name="M:ExitGames.Client.Photon.NCommand.#ctor(ExitGames.Client.Photon.EnetPeer,System.Byte[],System.Int32@)">
|
||||
<summary>reads the command values (commandHeader and command-values) from incoming bytestream and populates the incoming command*</summary>
|
||||
</member>
|
||||
<member name="T:ExitGames.Client.Photon.SimulationItem">
|
||||
<summary>
|
||||
A simulation item is an action that can be queued to simulate network lag.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:ExitGames.Client.Photon.SimulationItem.stopw">
|
||||
<summary>With this, the actual delay can be measured, compared to the intended lag.</summary>
|
||||
</member>
|
||||
<member name="F:ExitGames.Client.Photon.SimulationItem.TimeToExecute">
|
||||
<summary>Timestamp after which this item must be executed.</summary>
|
||||
</member>
|
||||
<member name="F:ExitGames.Client.Photon.SimulationItem.ActionToExecute">
|
||||
<summary>Action to execute when the lag-time passed.</summary>
|
||||
</member>
|
||||
<member name="M:ExitGames.Client.Photon.SimulationItem.#ctor">
|
||||
<summary>Starts a new Stopwatch</summary>
|
||||
</member>
|
||||
<member name="T:ExitGames.Client.Photon.NetworkSimulationSet">
|
||||
<summary>
|
||||
A set of network simulation settings, enabled (and disabled) by PhotonPeer.IsSimulationEnabled.
|
||||
</summary>
|
||||
<remarks>
|
||||
For performance reasons, the lag and jitter settings can't be produced exactly.
|
||||
In some cases, the resulting lag will be up to 20ms bigger than the lag settings.
|
||||
Even if all settings are 0, simulation will be used. Set PhotonPeer.IsSimulationEnabled
|
||||
to false to disable it if no longer needed.
|
||||
|
||||
All lag, jitter and loss is additional to the current, real network conditions.
|
||||
If the network is slow in reality, this will add even more lag.
|
||||
The jitter values will affect the lag positive and negative, so the lag settings
|
||||
describe the medium lag even with jitter. The jitter influence is: [-jitter..+jitter].
|
||||
Packets "lost" due to OutgoingLossPercentage count for BytesOut and LostPackagesOut.
|
||||
Packets "lost" due to IncomingLossPercentage count for BytesIn and LostPackagesIn.
|
||||
</remarks>
|
||||
</member>
|
||||
<member name="F:ExitGames.Client.Photon.NetworkSimulationSet.isSimulationEnabled">
|
||||
<summary>internal</summary>
|
||||
</member>
|
||||
<member name="F:ExitGames.Client.Photon.NetworkSimulationSet.outgoingLag">
|
||||
<summary>internal</summary>
|
||||
</member>
|
||||
<member name="F:ExitGames.Client.Photon.NetworkSimulationSet.outgoingJitter">
|
||||
<summary>internal</summary>
|
||||
</member>
|
||||
<member name="F:ExitGames.Client.Photon.NetworkSimulationSet.outgoingLossPercentage">
|
||||
<summary>internal</summary>
|
||||
</member>
|
||||
<member name="F:ExitGames.Client.Photon.NetworkSimulationSet.incomingLag">
|
||||
<summary>internal</summary>
|
||||
</member>
|
||||
<member name="F:ExitGames.Client.Photon.NetworkSimulationSet.incomingJitter">
|
||||
<summary>internal</summary>
|
||||
</member>
|
||||
<member name="F:ExitGames.Client.Photon.NetworkSimulationSet.incomingLossPercentage">
|
||||
<summary>internal</summary>
|
||||
</member>
|
||||
<member name="P:ExitGames.Client.Photon.NetworkSimulationSet.IsSimulationEnabled">
|
||||
<summary>This setting overrides all other settings and turns simulation on/off. Default: false.</summary>
|
||||
</member>
|
||||
<member name="P:ExitGames.Client.Photon.NetworkSimulationSet.OutgoingLag">
|
||||
<summary>Outgoing packages delay in ms. Default: 100.</summary>
|
||||
</member>
|
||||
<member name="P:ExitGames.Client.Photon.NetworkSimulationSet.OutgoingJitter">
|
||||
<summary>Randomizes OutgoingLag by [-OutgoingJitter..+OutgoingJitter]. Default: 0.</summary>
|
||||
</member>
|
||||
<member name="P:ExitGames.Client.Photon.NetworkSimulationSet.OutgoingLossPercentage">
|
||||
<summary>Percentage of outgoing packets that should be lost. Between 0..100. Default: 1. TCP ignores this setting.</summary>
|
||||
</member>
|
||||
<member name="P:ExitGames.Client.Photon.NetworkSimulationSet.IncomingLag">
|
||||
<summary>Incoming packages delay in ms. Default: 100.</summary>
|
||||
</member>
|
||||
<member name="P:ExitGames.Client.Photon.NetworkSimulationSet.IncomingJitter">
|
||||
<summary>Randomizes IncomingLag by [-IncomingJitter..+IncomingJitter]. Default: 0.</summary>
|
||||
</member>
|
||||
<member name="P:ExitGames.Client.Photon.NetworkSimulationSet.IncomingLossPercentage">
|
||||
<summary>Percentage of incoming packets that should be lost. Between 0..100. Default: 1. TCP ignores this setting.</summary>
|
||||
</member>
|
||||
<member name="P:ExitGames.Client.Photon.NetworkSimulationSet.LostPackagesOut">
|
||||
<summary>Counts how many outgoing packages actually got lost. TCP connections ignore loss and this stays 0.</summary>
|
||||
</member>
|
||||
<member name="P:ExitGames.Client.Photon.NetworkSimulationSet.LostPackagesIn">
|
||||
<summary>Counts how many incoming packages actually got lost. TCP connections ignore loss and this stays 0.</summary>
|
||||
</member>
|
||||
<member name="T:Photon.SocketServer.Security.OakleyGroups">
|
||||
<summary>
|
||||
Provides classical Diffie-Hellman Modular Exponentiation Groups defined by the
|
||||
OAKLEY Key Determination Protocol (RFC 2412).
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:Photon.SocketServer.Security.OakleyGroups.Generator">
|
||||
<summary>
|
||||
Gets the genrator (N) used by the the well known groups 1,2 and 5.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:Photon.SocketServer.Security.OakleyGroups.OakleyPrime768">
|
||||
<summary>
|
||||
Gets the 768 bit prime for the well known group 1.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:Photon.SocketServer.Security.OakleyGroups.OakleyPrime1024">
|
||||
<summary>
|
||||
Gets the 1024 bit prime for the well known group 2.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:Photon.SocketServer.Security.OakleyGroups.OakleyPrime1536">
|
||||
<summary>
|
||||
Gets the 1536 bit prime for the well known group 5.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:ExitGames.Client.Photon.PeerStateValue">
|
||||
<summary>
|
||||
Value range for a Peer's connection and initialization state, as returned by the PeerState property.
|
||||
</summary>
|
||||
<remarks>
|
||||
While this is not the same as the StatusCode of IPhotonPeerListener.OnStatusChanged(), it directly relates to it.
|
||||
In most cases, it makes more sense to build a game's state on top of the OnStatusChanged() as you get changes.
|
||||
</remarks>
|
||||
</member>
|
||||
<member name="F:ExitGames.Client.Photon.PeerStateValue.Disconnected">
|
||||
<summary>The peer is disconnected and can't call Operations. Call Connect().</summary>
|
||||
</member>
|
||||
<member name="F:ExitGames.Client.Photon.PeerStateValue.Connecting">
|
||||
<summary>The peer is establishing the connection: opening a socket, exchanging packages with Photon.</summary>
|
||||
</member>
|
||||
<member name="F:ExitGames.Client.Photon.PeerStateValue.InitializingApplication">
|
||||
<summary>The connection is established and now sends the application name to Photon.</summary>
|
||||
<remarks>You set the "application name" by calling PhotonPeer.Connect().</remarks>
|
||||
</member>
|
||||
<member name="F:ExitGames.Client.Photon.PeerStateValue.Connected">
|
||||
<summary>The peer is connected and initialized (selected an application). You can now use operations.</summary>
|
||||
</member>
|
||||
<member name="F:ExitGames.Client.Photon.PeerStateValue.Disconnecting">
|
||||
<summary>The peer is disconnecting. It sent a disconnect to the server, which will acknowledge closing the connection.</summary>
|
||||
</member>
|
||||
<member name="T:ExitGames.Client.Photon.ConnectionProtocol">
|
||||
<summary>
|
||||
These are the options that can be used as underlying transport protocol.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:ExitGames.Client.Photon.ConnectionProtocol.Udp">
|
||||
<summary>Use UDP to connect to Photon, which allows you to send operations reliable or unreliable on demand.</summary>
|
||||
</member>
|
||||
<member name="F:ExitGames.Client.Photon.ConnectionProtocol.Tcp">
|
||||
<summary>Use TCP to connect to Photon.</summary>
|
||||
</member>
|
||||
<member name="F:ExitGames.Client.Photon.ConnectionProtocol.Http">
|
||||
<summary>Use HTTP connections to connect a Photon Master (not available in regular Photon SDK).</summary>
|
||||
</member>
|
||||
<member name="T:ExitGames.Client.Photon.DebugLevel">
|
||||
<summary>
|
||||
Level / amount of DebugReturn callbacks. Each debug level includes output for lower ones: OFF, ERROR, WARNING, INFO, ALL.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:ExitGames.Client.Photon.DebugLevel.OFF">
|
||||
<summary>No debug out.</summary>
|
||||
</member>
|
||||
<member name="F:ExitGames.Client.Photon.DebugLevel.ERROR">
|
||||
<summary>Only error descriptions.</summary>
|
||||
</member>
|
||||
<member name="F:ExitGames.Client.Photon.DebugLevel.WARNING">
|
||||
<summary>Warnings and errors.</summary>
|
||||
</member>
|
||||
<member name="F:ExitGames.Client.Photon.DebugLevel.INFO">
|
||||
<summary>Information about internal workflows, warnings and errors.</summary>
|
||||
</member>
|
||||
<member name="F:ExitGames.Client.Photon.DebugLevel.ALL">
|
||||
<summary>Most complete workflow description (but lots of debug output), info, warnings and errors.</summary>
|
||||
</member>
|
||||
<member name="F:ExitGames.Client.Photon.PhotonCodes.Ok">
|
||||
<summary>Result code for any (internal) operation.</summary>
|
||||
</member>
|
||||
<member name="F:ExitGames.Client.Photon.PhotonCodes.ClientKey">
|
||||
<summary>Param code. Used in internal op: InitEncryption.</summary>
|
||||
</member>
|
||||
<member name="F:ExitGames.Client.Photon.PhotonCodes.ModeKey">
|
||||
<summary>Encryption-Mode code. Used in internal op: InitEncryption.</summary>
|
||||
</member>
|
||||
<member name="F:ExitGames.Client.Photon.PhotonCodes.ServerKey">
|
||||
<summary>Param code. Used in internal op: InitEncryption.</summary>
|
||||
</member>
|
||||
<member name="F:ExitGames.Client.Photon.PhotonCodes.InitEncryption">
|
||||
<summary>Code of internal op: InitEncryption.</summary>
|
||||
</member>
|
||||
<member name="T:ExitGames.Client.Photon.StatusCode">
|
||||
<summary>
|
||||
Enumeration of situations that change the peers internal status.
|
||||
Used in calls to OnStatusChanged to inform your application of various situations that might happen.
|
||||
</summary>
|
||||
<remarks>
|
||||
Most of these codes are referenced somewhere else in the documentation when they are relevant to methods.
|
||||
</remarks>
|
||||
</member>
|
||||
<member name="F:ExitGames.Client.Photon.StatusCode.Connect">
|
||||
<summary>the PhotonPeer is connected.<br/>See {@link PhotonListener#OnStatusChanged}*</summary>
|
||||
</member>
|
||||
<member name="F:ExitGames.Client.Photon.StatusCode.Disconnect">
|
||||
<summary>the PhotonPeer just disconnected.<br/>See {@link PhotonListener#OnStatusChanged}*</summary>
|
||||
</member>
|
||||
<member name="F:ExitGames.Client.Photon.StatusCode.Exception">
|
||||
<summary>the PhotonPeer encountered an exception and will disconnect, too.<br/>See {@link PhotonListener#OnStatusChanged}*</summary>
|
||||
</member>
|
||||
<member name="F:ExitGames.Client.Photon.StatusCode.ExceptionOnConnect">
|
||||
<summary>the PhotonPeer encountered an exception while opening the incoming connection to the server. The server could be down / not running or the client has no network or a misconfigured DNS.<br/>See {@link PhotonListener#OnStatusChanged}*</summary>
|
||||
</member>
|
||||
<member name="F:ExitGames.Client.Photon.StatusCode.SecurityExceptionOnConnect">
|
||||
<summary>Used on platforms that throw a security exception on connect. Unity3d does this, e.g., if a webplayer build could not fetch a policy-file from a remote server.</summary>
|
||||
</member>
|
||||
<member name="F:ExitGames.Client.Photon.StatusCode.QueueOutgoingReliableWarning">
|
||||
<summary>PhotonPeer outgoing queue is filling up. send more often.</summary>
|
||||
</member>
|
||||
<member name="F:ExitGames.Client.Photon.StatusCode.QueueOutgoingUnreliableWarning">
|
||||
<summary>PhotonPeer outgoing queue is filling up. send more often.</summary>
|
||||
</member>
|
||||
<member name="F:ExitGames.Client.Photon.StatusCode.SendError">
|
||||
<summary>Sending command failed. Either not connected, or the requested channel is bigger than the number of initialized channels.</summary>
|
||||
</member>
|
||||
<member name="F:ExitGames.Client.Photon.StatusCode.QueueOutgoingAcksWarning">
|
||||
<summary>PhotonPeer outgoing queue is filling up. send more often.</summary>
|
||||
</member>
|
||||
<member name="F:ExitGames.Client.Photon.StatusCode.QueueIncomingReliableWarning">
|
||||
<summary>PhotonPeer incoming queue is filling up. Dispatch more often.</summary>
|
||||
</member>
|
||||
<member name="F:ExitGames.Client.Photon.StatusCode.QueueIncomingUnreliableWarning">
|
||||
<summary>PhotonPeer incoming queue is filling up. Dispatch more often.</summary>
|
||||
</member>
|
||||
<member name="F:ExitGames.Client.Photon.StatusCode.QueueSentWarning">
|
||||
<summary>PhotonPeer incoming queue is filling up. Dispatch more often.</summary>
|
||||
</member>
|
||||
<member name="F:ExitGames.Client.Photon.StatusCode.InternalReceiveException">
|
||||
<summary>Exception, if a server cannot be connected. Most likely, the server is not responding. Ask user to try again later.</summary>
|
||||
</member>
|
||||
<member name="F:ExitGames.Client.Photon.StatusCode.TimeoutDisconnect">
|
||||
<summary>Disconnection due to a timeout (client did no longer receive ACKs from server).</summary>
|
||||
</member>
|
||||
<member name="F:ExitGames.Client.Photon.StatusCode.DisconnectByServer">
|
||||
<summary>Disconnect by server due to timeout (received a disconnect command, cause server misses ACKs of client).</summary>
|
||||
</member>
|
||||
<member name="F:ExitGames.Client.Photon.StatusCode.DisconnectByServerUserLimit">
|
||||
<summary>Disconnect by server due to concurrent user limit reached (received a disconnect command).</summary>
|
||||
</member>
|
||||
<member name="F:ExitGames.Client.Photon.StatusCode.DisconnectByServerLogic">
|
||||
<summary>Disconnect by server due to server's logic (received a disconnect command).</summary>
|
||||
</member>
|
||||
<member name="F:ExitGames.Client.Photon.StatusCode.TcpRouterResponseOk">
|
||||
<summary>Tcp Router Response. Only used when Photon is setup as TCP router! Routing is ok.</summary>
|
||||
</member>
|
||||
<member name="F:ExitGames.Client.Photon.StatusCode.TcpRouterResponseNodeIdUnknown">
|
||||
<summary>Tcp Router Response. Only used when Photon is setup as TCP router! Routing node unknown. Check client connect values.</summary>
|
||||
</member>
|
||||
<member name="F:ExitGames.Client.Photon.StatusCode.TcpRouterResponseEndpointUnknown">
|
||||
<summary>Tcp Router Response. Only used when Photon is setup as TCP router! Routing endpoint unknown.</summary>
|
||||
</member>
|
||||
<member name="F:ExitGames.Client.Photon.StatusCode.TcpRouterResponseNodeNotReady">
|
||||
<summary>Tcp Router Response. Only used when Photon is setup as TCP router! Routing not setup yet. Connect again.</summary>
|
||||
</member>
|
||||
<member name="F:ExitGames.Client.Photon.StatusCode.EncryptionEstablished">
|
||||
<summary>(1048) Value for OnStatusChanged()-call, when the encryption-setup for secure communication finished successfully.</summary>
|
||||
</member>
|
||||
<member name="F:ExitGames.Client.Photon.StatusCode.EncryptionFailedToEstablish">
|
||||
<summary>(1049) Value for OnStatusChanged()-call, when the encryption-setup failed for some reason. Check debug logs.</summary>
|
||||
</member>
|
||||
<member name="T:ExitGames.Client.Photon.IPhotonPeerListener">
|
||||
<summary>
|
||||
Callback interface for the Photon client side. Must be provided to a new PhotonPeer in its constructor.
|
||||
</summary>
|
||||
<remarks>
|
||||
These methods are used by your PhotonPeer instance to keep your app updated. Read each method's
|
||||
description and check out the samples to see how to use them.
|
||||
</remarks>
|
||||
</member>
|
||||
<member name="M:ExitGames.Client.Photon.IPhotonPeerListener.DebugReturn(ExitGames.Client.Photon.DebugLevel,System.String)">
|
||||
<summary>
|
||||
Provides textual descriptions for various error conditions and noteworthy situations.
|
||||
In cases where the application needs to react, a call to OnStatusChanged is used.
|
||||
OnStatusChanged gives "feedback" to the game, DebugReturn provies human readable messages
|
||||
on the background.
|
||||
</summary>
|
||||
<remarks>
|
||||
All debug output of the library will be reported through this method. Print it or put it in a
|
||||
buffer to use it on-screen. Use PhotonPeer.DebugOut to select how verbose the output is.
|
||||
</remarks>
|
||||
<param name="level">DebugLevel (severity) of the message.</param>
|
||||
<param name="message">Debug text. Print to System.Console or screen.</param>
|
||||
</member>
|
||||
<member name="M:ExitGames.Client.Photon.IPhotonPeerListener.OnOperationResponse(ExitGames.Client.Photon.OperationResponse)">
|
||||
<summary>
|
||||
Callback method which gives you (async) responses for called operations.
|
||||
</summary>
|
||||
<remarks>
|
||||
Like methods, operations can have a result. As operation-calls are non-blocking, the response
|
||||
for any operation of this peer is provided by this method.
|
||||
As example: Joining a room on a Lite-based server will return a list of players currently in gamey
|
||||
your actorNumber and some other values.
|
||||
|
||||
This method is used as general callback for all operations. Each response corresponds to a certain
|
||||
"type" of operation by its OperationCode (see: <see cref="!:Operations"/>).<para></para>
|
||||
|
||||
The "Lite Application" uses these OpCodes:
|
||||
* <see cref="F:ExitGames.Client.Photon.Lite.LiteOpCode.Join"/> for OpJoin, contains the actorNr of "this" player
|
||||
* <see cref="F:ExitGames.Client.Photon.Lite.LiteOpCode.Leave"/> when leaving a room
|
||||
* <see cref="F:ExitGames.Client.Photon.Lite.LiteOpCode.RaiseEvent"/> for OpRaiseEvent, if this was sent as reliable command
|
||||
* <see cref="F:ExitGames.Client.Photon.Lite.LiteOpCode.SetProperties"/> for OpSetPropertiesOfActor and OpSetPropertiesOfGame
|
||||
</remarks>
|
||||
<example>
|
||||
When you join a room, the server will assign a consecutive number to each client: the
|
||||
"actorNr" or "player number". This is sent back in the OperationResult's
|
||||
Parameters as value of key <see cref="F:ExitGames.Client.Photon.Lite.LiteEventKey.ActorNr"/>.<para></para>
|
||||
|
||||
Fetch your actorNr of a Join response like this:<para></para>
|
||||
<c>int actorNr = (int)operationResponse[(byte)LiteOpKey.ActorNr];</c>
|
||||
</example>
|
||||
<param name="operationResponse">The response to an operation\-call.</param>
|
||||
</member>
|
||||
<member name="M:ExitGames.Client.Photon.IPhotonPeerListener.OnStatusChanged(ExitGames.Client.Photon.StatusCode)">
|
||||
<summary>
|
||||
OnStatusChanged is called to let the game know when asyncronous actions finished or when errors happen.
|
||||
</summary>
|
||||
<remarks>
|
||||
Not all of the many StatusCode values will apply to your game. Example: If you don't use encryption,
|
||||
the respective status changes are never made.
|
||||
|
||||
The values are all part of the StatusCode enumeration and described value-by-value.
|
||||
</remarks>
|
||||
<param name="statusCode">A code to identify the situation.</param>
|
||||
</member>
|
||||
<member name="M:ExitGames.Client.Photon.IPhotonPeerListener.OnEvent(ExitGames.Client.Photon.EventData)">
|
||||
<summary>
|
||||
Called whenever an event from the Photon Server is dispatched.
|
||||
</summary>
|
||||
<remarks>
|
||||
Events are used for communication between clients and allow the server to update clients over time.
|
||||
The creation of an event is often triggered by an operation (called by this client or an other).
|
||||
|
||||
Each event carries its specific content in its Parameters. Your application knows which content to
|
||||
expect by checking the event's 'type', given by the event's Code.
|
||||
|
||||
Events can be defined and extended server-side.
|
||||
|
||||
If you use the Lite application as base, several events like EvJoin and EvLeave are already defined.
|
||||
For these events and their Parameters, the library provides constants, so check:
|
||||
LiteEventCode and LiteEventKey classes.
|
||||
Lite also allows you to come up with custom events on the fly, purely client-side. To do so, use
|
||||
LitePeer.OpRaiseEvent.<para></para>
|
||||
|
||||
Events are buffered on the client side and must be Dispatched. This way, OnEvent is always taking
|
||||
place in the same thread as a <see cref="M:ExitGames.Client.Photon.PhotonPeer.DispatchIncomingCommands"/> call.
|
||||
</remarks>
|
||||
<param name="eventData">The event currently being dispatched.</param>
|
||||
</member>
|
||||
<member name="T:ExitGames.Client.Photon.SerializeMethod">
|
||||
<summary>
|
||||
Type of serialization methods to add custom type support.
|
||||
Use PhotonPeer.ReisterType() to register new types with serialization and deserialization methods.
|
||||
</summary>
|
||||
<param name="customObject">The method will get objects passed that were registered with it in RegisterType().</param>
|
||||
<returns>Return a byte[] that resembles the object passed in. The framework will surround it with length and type info, so don't include it.</returns>
|
||||
</member>
|
||||
<member name="T:ExitGames.Client.Photon.DeserializeMethod">
|
||||
<summary>
|
||||
Type of deserialization methods to add custom type support.
|
||||
Use PhotonPeer.RegisterType() to register new types with serialization and deserialization methods.
|
||||
</summary>
|
||||
<param name="serializedCustomObject">The framwork passes in the data it got by the associated SerializeMethod. The type code and length are stripped and applied before a DeserializeMethod is called.</param>
|
||||
<returns>Return a object of the type that was associated with this method through RegisterType().</returns>
|
||||
</member>
|
||||
<member name="T:ExitGames.Client.Photon.OperationRequest">
|
||||
<summary>
|
||||
Container for an Operation request, which is a code and parameters.
|
||||
</summary>
|
||||
<remarks>
|
||||
On the lowest level, Photon only allows byte-typed keys for operation parameters.
|
||||
The values of each such parameter can be any serializable datatype: byte, int, hashtable and many more.
|
||||
</remarks>
|
||||
</member>
|
||||
<member name="F:ExitGames.Client.Photon.OperationRequest.OperationCode">
|
||||
<summary>Byte-typed code for an operation - the short identifier for the server's method to call.</summary>
|
||||
</member>
|
||||
<member name="F:ExitGames.Client.Photon.OperationRequest.Parameters">
|
||||
<summary>The parameters of the operation - each identified by a byte-typed code in Photon.</summary>
|
||||
</member>
|
||||
<member name="T:ExitGames.Client.Photon.OperationResponse">
|
||||
<summary>
|
||||
Contains the server's response for an operation called by this peer.
|
||||
The indexer of this class actually provides access to the Parameters Dictionary.
|
||||
</summary>
|
||||
<remarks>
|
||||
The OperationCode defines the type of operation called on Photon and in turn also the Parameters that
|
||||
are set in the request. Those are provided as Dictionary with byte-keys.
|
||||
There are pre-defined constants for various codes defined in the Lite application. Check: LiteOpCode,
|
||||
LiteOpKey, etc.
|
||||
<para></para>
|
||||
An operation's request is summarized by the ReturnCode: a short typed code for "Ok" or
|
||||
some different result. The code's meaning is specific per operation. An optional DebugMessage can be
|
||||
provided to simplify debugging.
|
||||
<para></para>
|
||||
Each call of an operation gets an ID, called the "invocID". This can be matched to the IDs
|
||||
returned with any operation calls. This way, an application could track if a certain OpRaiseEvent
|
||||
call was successful.
|
||||
</remarks>
|
||||
</member>
|
||||
<member name="F:ExitGames.Client.Photon.OperationResponse.OperationCode">
|
||||
<summary>The code for the operation called initially (by this peer).</summary>
|
||||
<remarks>Use enums or constants to be able to handle those codes, like LiteOpCode does.</remarks>
|
||||
</member>
|
||||
<member name="F:ExitGames.Client.Photon.OperationResponse.ReturnCode">
|
||||
<summary>A code that "summarizes" the operation's success or failure. Specific per operation. 0 usually means "ok".</summary>
|
||||
</member>
|
||||
<member name="F:ExitGames.Client.Photon.OperationResponse.DebugMessage">
|
||||
<summary>An optional string sent by the server to provide readable feedback in error-cases. Might be null.</summary>
|
||||
</member>
|
||||
<member name="F:ExitGames.Client.Photon.OperationResponse.Parameters">
|
||||
<summary>A Dictionary of values returned by an operation, using byte-typed keys per value.</summary>
|
||||
</member>
|
||||
<member name="M:ExitGames.Client.Photon.OperationResponse.ToString">
|
||||
<summary>ToString() override.</summary>
|
||||
<returns>Relatively short output of OpCode and returnCode.</returns>
|
||||
</member>
|
||||
<member name="M:ExitGames.Client.Photon.OperationResponse.ToStringFull">
|
||||
<summary>Extensive output of operation results.</summary>
|
||||
<returns>To be used in debug situations only, as it returns a string for each value.</returns>
|
||||
</member>
|
||||
<member name="P:ExitGames.Client.Photon.OperationResponse.Item(System.Byte)">
|
||||
<summary>
|
||||
Alternative access to the Parameters, which wraps up a TryGetValue() call on the Parameters Dictionary.
|
||||
</summary>
|
||||
<param name="parameterCode">The byte-code of a returned value.</param>
|
||||
<returns>The value returned by the server, or null if the key does not exist in Parameters.</returns>
|
||||
</member>
|
||||
<member name="T:ExitGames.Client.Photon.EventData">
|
||||
<summary>
|
||||
Contains all components of a Photon Event.
|
||||
Event Parameters, like OperationRequests and OperationResults, consist of a Dictionary with byte-typed keys per value.
|
||||
</summary>
|
||||
<remarks>
|
||||
The indexer of this class actually provides access to the Parameters Dictionary.
|
||||
The operation RaiseEvent of the Lite application allows you to provide custom event content. Defined in Lite, this
|
||||
CustomContent will be made the value of key LiteEventKey.OperationRaiseEvent which is (byte)42.
|
||||
Enums and constants for the Lite-Application codes are defined in the LitePeer namespace. Check: LiteEventKey, etc.
|
||||
</remarks>
|
||||
</member>
|
||||
<member name="F:ExitGames.Client.Photon.EventData.Code">
|
||||
<summary>The event code identifies the type of event.</summary>
|
||||
</member>
|
||||
<!-- Badly formed XML comment ignored for member "F:ExitGames.Client.Photon.EventData.Parameters" -->
|
||||
<member name="M:ExitGames.Client.Photon.EventData.ToString">
|
||||
<summary>ToString() override.</summary>
|
||||
<returns>Short output of "Event" and it's Code.</returns>
|
||||
</member>
|
||||
<member name="M:ExitGames.Client.Photon.EventData.ToStringFull">
|
||||
<summary>Extensive output of the event content.</summary>
|
||||
<returns>To be used in debug situations only, as it returns a string for each value.</returns>
|
||||
</member>
|
||||
<member name="P:ExitGames.Client.Photon.EventData.Item(System.Byte)">
|
||||
<summary>
|
||||
Alternative access to the Parameters.
|
||||
</summary>
|
||||
<param name="key">The key byte-code of a event value.</param>
|
||||
<returns>The Parameters value, or null if the key does not exist in Parameters.</returns>
|
||||
</member>
|
||||
<member name="T:ExitGames.Client.Photon.GpType">
|
||||
<summary>
|
||||
The gp type.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:ExitGames.Client.Photon.GpType.Unknown">
|
||||
<summary>
|
||||
Unkown type.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:ExitGames.Client.Photon.GpType.Array">
|
||||
<summary>
|
||||
An array of objects.
|
||||
</summary>
|
||||
<remarks>
|
||||
This type is new in version 1.5.
|
||||
</remarks>
|
||||
</member>
|
||||
<member name="F:ExitGames.Client.Photon.GpType.Boolean">
|
||||
<summary>
|
||||
A boolean Value.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:ExitGames.Client.Photon.GpType.Byte">
|
||||
<summary>
|
||||
A byte value.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:ExitGames.Client.Photon.GpType.ByteArray">
|
||||
<summary>
|
||||
An array of bytes.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:ExitGames.Client.Photon.GpType.ObjectArray">
|
||||
<summary>
|
||||
An array of objects.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:ExitGames.Client.Photon.GpType.Short">
|
||||
<summary>
|
||||
A 16-bit integer value.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:ExitGames.Client.Photon.GpType.Float">
|
||||
<summary>
|
||||
A 32-bit floating-point value.
|
||||
</summary>
|
||||
<remarks>
|
||||
This type is new in version 1.5.
|
||||
</remarks>
|
||||
</member>
|
||||
<member name="F:ExitGames.Client.Photon.GpType.Dictionary">
|
||||
<summary>
|
||||
A dictionary
|
||||
</summary>
|
||||
<remarks>
|
||||
This type is new in version 1.6.
|
||||
</remarks>
|
||||
</member>
|
||||
<member name="F:ExitGames.Client.Photon.GpType.Double">
|
||||
<summary>
|
||||
A 64-bit floating-point value.
|
||||
</summary>
|
||||
<remarks>
|
||||
This type is new in version 1.5.
|
||||
</remarks>
|
||||
</member>
|
||||
<member name="F:ExitGames.Client.Photon.GpType.Hashtable">
|
||||
<summary>
|
||||
A Hashtable.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:ExitGames.Client.Photon.GpType.Integer">
|
||||
<summary>
|
||||
A 32-bit integer value.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:ExitGames.Client.Photon.GpType.IntegerArray">
|
||||
<summary>
|
||||
An array of 32-bit integer values.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:ExitGames.Client.Photon.GpType.Long">
|
||||
<summary>
|
||||
A 64-bit integer value.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:ExitGames.Client.Photon.GpType.String">
|
||||
<summary>
|
||||
A string value.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:ExitGames.Client.Photon.GpType.StringArray">
|
||||
<summary>
|
||||
An array of string values.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:ExitGames.Client.Photon.GpType.Vector">
|
||||
<summary>
|
||||
A vector.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:ExitGames.Client.Photon.GpType.Custom">
|
||||
<summary>
|
||||
A costum type
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:ExitGames.Client.Photon.GpType.Null">
|
||||
<summary>
|
||||
Null value don't have types.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:ExitGames.Client.Photon.Protocol">
|
||||
<summary>
|
||||
Provides tools for the Exit Games Protocol
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:ExitGames.Client.Photon.Protocol.Serialize(System.Object)">
|
||||
<summary>
|
||||
Serialize creates a byte-array from the given object and returns it.
|
||||
</summary>
|
||||
<param name="serializedData">The object to serialize</param>
|
||||
<returns>The serialized byte-array</returns>
|
||||
</member>
|
||||
<member name="M:ExitGames.Client.Photon.Protocol.Deserialize(System.Byte[])">
|
||||
<summary>
|
||||
Deserialize returns an object reassembled from the given byte-array.
|
||||
</summary>
|
||||
<param name="serializedData">The byte-array to be Deserialized</param>
|
||||
<returns>The Deserialized object</returns>
|
||||
</member>
|
||||
<member name="M:ExitGames.Client.Photon.Protocol.Serialize(System.IO.MemoryStream,System.Object,System.Boolean)">
|
||||
<summary>
|
||||
Calls the correct serialization method for the passed object.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:ExitGames.Client.Photon.Protocol.Serialize(System.Int16,System.Byte[],System.Int32@)">
|
||||
<summary>
|
||||
Serializes a short typed value into a byte-array (target) starting at the also given targetOffset.
|
||||
The altered offset is known to the caller, because it is given via a referenced parameter.
|
||||
</summary>
|
||||
<param name="value">The short value to be serialized</param>
|
||||
<param name="target">The byte-array to serialize the short to</param>
|
||||
<param name="targetOffset">The offset in the byte-array</param>
|
||||
</member>
|
||||
<member name="M:ExitGames.Client.Photon.Protocol.Serialize(System.Int32,System.Byte[],System.Int32@)">
|
||||
<summary>
|
||||
Serializes an int typed value into a byte-array (target) starting at the also given targetOffset.
|
||||
The altered offset is known to the caller, because it is given via a referenced parameter.
|
||||
</summary>
|
||||
<param name="value">The int value to be serialized</param>
|
||||
<param name="target">The byte-array to serialize the short to</param>
|
||||
<param name="targetOffset">The offset in the byte-array</param>
|
||||
</member>
|
||||
<member name="M:ExitGames.Client.Photon.Protocol.Serialize(System.Single,System.Byte[],System.Int32@)">
|
||||
<summary>
|
||||
Serializes an float typed value into a byte-array (target) starting at the also given targetOffset.
|
||||
The altered offset is known to the caller, because it is given via a referenced parameter.
|
||||
</summary>
|
||||
<param name="value">The float value to be serialized</param>
|
||||
<param name="target">The byte-array to serialize the short to</param>
|
||||
<param name="targetOffset">The offset in the byte-array</param>
|
||||
</member>
|
||||
<member name="M:ExitGames.Client.Photon.Protocol.Deserialize(System.Int16@,System.Byte[],System.Int32@)">
|
||||
<summary>
|
||||
Deserialize fills the given short typed value with the given byte-array (source) starting at the also given offset.
|
||||
The result is placed in a variable (value). There is no need to return a value because the parameter value is given by reference.
|
||||
The altered offset is this way also known to the caller.
|
||||
</summary>
|
||||
<param name="value">The short value to deserialized into</param>
|
||||
<param name="target">The byte-array to deserialize from</param>
|
||||
<param name="targetOffset">The offset in the byte-array</param>
|
||||
</member>
|
||||
<member name="M:ExitGames.Client.Photon.Protocol.DeserializeInteger(System.IO.MemoryStream)">
|
||||
<summary>
|
||||
DeserializeInteger returns an Integer typed value from the given Memorystream.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:ExitGames.Client.Photon.Protocol.Deserialize(System.Int32@,System.Byte[],System.Int32@)">
|
||||
<summary>
|
||||
Deserialize fills the given int typed value with the given byte-array (source) starting at the also given offset.
|
||||
The result is placed in a variable (value). There is no need to return a value because the parameter value is given by reference.
|
||||
The altered offset is this way also known to the caller.
|
||||
</summary>
|
||||
<param name="value">The int value to deserialize into</param>
|
||||
<param name="target">The byte-array to deserialize from</param>
|
||||
<param name="targetOffset">The offset in the byte-array</param>
|
||||
</member>
|
||||
<member name="M:ExitGames.Client.Photon.Protocol.Deserialize(System.Single@,System.Byte[],System.Int32@)">
|
||||
<summary>
|
||||
Deserialize fills the given float typed value with the given byte-array (source) starting at the also given offset.
|
||||
The result is placed in a variable (value). There is no need to return a value because the parameter value is given by reference.
|
||||
The altered offset is this way also known to the caller.
|
||||
</summary>
|
||||
<param name="value">The float value to deserialize</param>
|
||||
<param name="target">The byte-array to deserialize from</param>
|
||||
<param name="targetOffset">The offset in the byte-array</param>
|
||||
</member>
|
||||
<member name="T:ExitGames.Client.Photon.SupportClass">
|
||||
<summary>
|
||||
Contains several (more or less) useful static methods, mostly used for debugging.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:ExitGames.Client.Photon.SupportClass.WriteStackTrace(System.Exception,System.IO.TextWriter)">
|
||||
<summary>
|
||||
Writes the exception's stack trace to the received stream.
|
||||
</summary>
|
||||
<param name="throwable">Exception to obtain information from.</param>
|
||||
<param name="stream">Output sream used to write to.</param>
|
||||
</member>
|
||||
<member name="M:ExitGames.Client.Photon.SupportClass.DictionaryToString(System.Collections.IDictionary)">
|
||||
<summary>
|
||||
This method returns a string, representing the content of the given IDictionary.
|
||||
Returns "null" if parameter is null.
|
||||
</summary>
|
||||
<param name="dictionary">
|
||||
IDictionary to return as string.
|
||||
</param>
|
||||
<returns>
|
||||
The string representation of keys and values in IDictionary.
|
||||
</returns>
|
||||
</member>
|
||||
<member name="M:ExitGames.Client.Photon.SupportClass.DictionaryToString(System.Collections.IDictionary,System.Boolean)">
|
||||
<summary>
|
||||
This method returns a string, representing the content of the given IDictionary.
|
||||
Returns "null" if parameter is null.
|
||||
</summary>
|
||||
<param name="dictionary">IDictionary to return as string.</param>
|
||||
<param name="includeTypes"> </param>
|
||||
</member>
|
||||
<member name="M:ExitGames.Client.Photon.SupportClass.NumberToByteArray(System.Byte[],System.Int32,System.Int16)">
|
||||
<summary>
|
||||
Inserts the number's value into the byte array, using Big-Endian order (a.k.a. Network-byte-order).
|
||||
</summary>
|
||||
<param name="buffer">Byte array to write into.</param>
|
||||
<param name="index">Index of first position to write to.</param>
|
||||
<param name="number">Number to write.</param>
|
||||
</member>
|
||||
<member name="M:ExitGames.Client.Photon.SupportClass.NumberToByteArray(System.Byte[],System.Int32,System.Int32)">
|
||||
<summary>
|
||||
Inserts the number's value into the byte array, using Big-Endian order (a.k.a. Network-byte-order).
|
||||
</summary>
|
||||
<param name="buffer">Byte array to write into.</param>
|
||||
<param name="index">Index of first position to write to.</param>
|
||||
<param name="number">Number to write.</param>
|
||||
</member>
|
||||
<member name="M:ExitGames.Client.Photon.SupportClass.ByteArrayToString(System.Byte[])">
|
||||
<summary>
|
||||
Converts a byte-array to string (useful as debugging output).
|
||||
Uses BitConverter.ToString(list) internally after a null-check of list.
|
||||
</summary>
|
||||
<param name="list">Byte-array to convert to string.</param>
|
||||
<returns>
|
||||
List of bytes as string.
|
||||
</returns>
|
||||
</member>
|
||||
<member name="T:ExitGames.Client.Photon.SupportClass.ThreadSafeRandom">
|
||||
<summary>
|
||||
Class to wrap static access to the random.Next() call in a thread safe manner.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:ExitGames.Client.Photon.TConnect">
|
||||
<summary>
|
||||
Internal class to encapsulate the network i/o functionality for the realtime libary.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:ExitGames.Client.Photon.TConnect.sendTcp(System.Byte[])">
|
||||
<summary>
|
||||
used by TPeer*
|
||||
</summary>
|
||||
<param name="opData">
|
||||
The op Data.
|
||||
</param>
|
||||
</member>
|
||||
<member name="M:ExitGames.Client.Photon.TPeer.DispatchIncomingCommands">
|
||||
<summary>
|
||||
Checks the incoming queue and Dispatches received data if possible. Returns if a Dispatch happened or
|
||||
not, which shows if more Dispatches might be needed.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:ExitGames.Client.Photon.TPeer.SendOutgoingCommands">
|
||||
<summary>
|
||||
gathers commands from all (out)queues until udp-packet is full and sends it!
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:ExitGames.Client.Photon.TPeer.SerializeOperationToMessage(System.Byte,System.Collections.Generic.Dictionary{System.Byte,System.Object},ExitGames.Client.Photon.PeerBase.EgMessageType,System.Boolean)">
|
||||
<summary> Returns the UDP Payload starting with Magic Number for binary protocol </summary>
|
||||
</member>
|
||||
<member name="M:ExitGames.Client.Photon.TPeer.EnqueueMessageAsPayload(System.Boolean,System.Byte[],System.Byte)">
|
||||
<summary>enqueues serialized operations to be sent as tcp stream / package</summary>
|
||||
</member>
|
||||
<member name="M:ExitGames.Client.Photon.TPeer.ReceiveIncomingCommands(System.Byte[])">
|
||||
<summary>reads incoming tcp-packages to create and queue incoming commands*</summary>
|
||||
</member>
|
||||
<member name="T:ExitGames.Client.Photon.TrafficStatsGameLevel">
|
||||
<summary>
|
||||
Only in use as long as PhotonPeer.TrafficStatsEnabled = true;
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:ExitGames.Client.Photon.TrafficStatsGameLevel.OperationByteCount">
|
||||
<summary>Gets sum of outgoing operations in bytes.</summary>
|
||||
</member>
|
||||
<member name="P:ExitGames.Client.Photon.TrafficStatsGameLevel.OperationCount">
|
||||
<summary>Gets count of outgoing operations.</summary>
|
||||
</member>
|
||||
<member name="P:ExitGames.Client.Photon.TrafficStatsGameLevel.ResultByteCount">
|
||||
<summary>Gets sum of byte-cost of incoming operation-results.</summary>
|
||||
</member>
|
||||
<member name="P:ExitGames.Client.Photon.TrafficStatsGameLevel.ResultCount">
|
||||
<summary>Gets count of incoming operation-results.</summary>
|
||||
</member>
|
||||
<member name="P:ExitGames.Client.Photon.TrafficStatsGameLevel.EventByteCount">
|
||||
<summary>Gets sum of byte-cost of incoming events.</summary>
|
||||
</member>
|
||||
<member name="P:ExitGames.Client.Photon.TrafficStatsGameLevel.EventCount">
|
||||
<summary>Gets count of incoming events.</summary>
|
||||
</member>
|
||||
<member name="P:ExitGames.Client.Photon.TrafficStatsGameLevel.LongestOpResponseCallback">
|
||||
<summary>
|
||||
Gets longest time it took to complete a call to OnOperationResponse (in your code).
|
||||
If such a callback takes long, it will lower the network performance and might lead to timeouts.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:ExitGames.Client.Photon.TrafficStatsGameLevel.LongestOpResponseCallbackOpCode">
|
||||
<summary>Gets OperationCode that causes the LongestOpResponseCallback. See that description.</summary>
|
||||
</member>
|
||||
<member name="P:ExitGames.Client.Photon.TrafficStatsGameLevel.LongestEventCallback">
|
||||
<summary>
|
||||
Gets longest time a call to OnEvent (in your code) took.
|
||||
If such a callback takes long, it will lower the network performance and might lead to timeouts.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:ExitGames.Client.Photon.TrafficStatsGameLevel.LongestEventCallbackCode">
|
||||
<summary>Gets EventCode that caused the LongestEventCallback. See that description.</summary>
|
||||
</member>
|
||||
<member name="P:ExitGames.Client.Photon.TrafficStatsGameLevel.LongestDeltaBetweenDispatching">
|
||||
<summary>
|
||||
Gets longest time between subsequent calls to DispatchIncomginCommands in milliseconds.
|
||||
Note: This is not a crucial timing for the networking. Long gaps just add "local lag" to events that are available already.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:ExitGames.Client.Photon.TrafficStatsGameLevel.LongestDeltaBetweenSending">
|
||||
<summary>
|
||||
Gets longest time between subsequent calls to SendOutgoingCommands in milliseconds.
|
||||
Note: This is a crucial value for network stability. Without calling SendOutgoingCommands,
|
||||
nothing will be sent to the server, who might time out this client.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:ExitGames.Client.Photon.TrafficStatsGameLevel.DispatchCalls">
|
||||
<summary>
|
||||
Gets number of calls of DispatchIncomingCommands.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:ExitGames.Client.Photon.TrafficStatsGameLevel.SendOutgoingCommandsCalls">
|
||||
<summary>
|
||||
Gets number of calls of SendOutgoingCommands.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:ExitGames.Client.Photon.TrafficStatsGameLevel.TotalByteCount">
|
||||
<summary>Gets sum of byte-cost of all "logic level" messages.</summary>
|
||||
</member>
|
||||
<member name="P:ExitGames.Client.Photon.TrafficStatsGameLevel.TotalMessageCount">
|
||||
<summary>Gets sum of counted "logic level" messages.</summary>
|
||||
</member>
|
||||
<member name="P:ExitGames.Client.Photon.TrafficStatsGameLevel.TotalIncomingByteCount">
|
||||
<summary>Gets sum of byte-cost of all incoming "logic level" messages.</summary>
|
||||
</member>
|
||||
<member name="P:ExitGames.Client.Photon.TrafficStatsGameLevel.TotalIncomingMessageCount">
|
||||
<summary>Gets sum of counted incoming "logic level" messages.</summary>
|
||||
</member>
|
||||
<member name="P:ExitGames.Client.Photon.TrafficStatsGameLevel.TotalOutgoingByteCount">
|
||||
<summary>Gets sum of byte-cost of all outgoing "logic level" messages (= OperationByteCount).</summary>
|
||||
</member>
|
||||
<member name="P:ExitGames.Client.Photon.TrafficStatsGameLevel.TotalOutgoingMessageCount">
|
||||
<summary>Gets sum of counted outgoing "logic level" messages (= OperationCount).</summary>
|
||||
</member>
|
||||
<member name="P:ExitGames.Client.Photon.TrafficStats.PackageHeaderSize">
|
||||
<summary>Gets the byte-size of per-package headers.</summary>
|
||||
</member>
|
||||
<member name="P:ExitGames.Client.Photon.TrafficStats.TotalPacketBytes">
|
||||
<summary>Gets count of bytes as traffic, excluding UDP/TCP headers (42 bytes / x bytes).</summary>
|
||||
</member>
|
||||
<member name="T:ExitGames.Client.Photon.HttpBase2">
|
||||
<summary>
|
||||
Class to handle Http based connections to a Photon server.
|
||||
Requests are done asynchronous and not queued at all.
|
||||
|
||||
All responses are put into the game's thread-context and
|
||||
all results and state changes are done within calls of
|
||||
Service() or DispatchIncomingCommands().
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:ExitGames.Client.Photon.HttpBase2.Disconnect">
|
||||
<summary>
|
||||
In HTTP connections, Disconnect consists of request with byte[] { 1 }.
|
||||
The response has 0 bytes and is not otherwise marked.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:ExitGames.Client.Photon.HttpBase2.EnqueueErrorDisconnect(ExitGames.Client.Photon.StatusCode)">
|
||||
<summary>
|
||||
Called internally when some error (or timeout) causes a disconnect. this takes care state is set and callbacks are done (once)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:ExitGames.Client.Photon.HttpBase2.Request(System.Byte[],System.String)">
|
||||
<summary>
|
||||
The initial request does not contain data and the UrlParameters must be "?init".
|
||||
Init returns a GUID for use in following requests as UrlParameters "?pid=GUID".
|
||||
Following requests can carry data.
|
||||
</summary>
|
||||
<remarks>
|
||||
Aside from the initial request (a.k.a. connect), requests have a ?pid=guid url-parameter and a binary request body.
|
||||
Responses could be 0 bytes or contain a (short)count-of-response-messages plus messages.
|
||||
</remarks>
|
||||
<param name="data"></param>
|
||||
<param name="urlParamter">The url paramters to append to the server adress uri.</param>
|
||||
</member>
|
||||
<member name="M:ExitGames.Client.Photon.HttpBase2.Request(System.Byte[],System.String,System.Boolean)">
|
||||
<param name="isDisconnect">marks the request as disconnect or "regular" request. If a disconnect is answered, change status to disconnected.</param>
|
||||
</member>
|
||||
<member name="M:ExitGames.Client.Photon.HttpBase2.CheckResult">
|
||||
<summary>
|
||||
Unity restricts access to WWW objects only in the main thread, so this method is called
|
||||
within DispatchIncomingCommands(), which is enqueued in main thread of Unity.
|
||||
</summary>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="P:ExitGames.Client.Photon.HttpBase2.PeerID">
|
||||
<summary>
|
||||
The *pid* for this peer, which is assigned by the server on connect (init).
|
||||
Initially this is Guid.Empty.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:ExitGames.Client.Photon.NConnect">
|
||||
<summary> Internal class to encapsulate the network i/o functionality for the realtime libary.</summary>
|
||||
</member>
|
||||
<member name="M:ExitGames.Client.Photon.NConnect.SendUdpPackage(System.Byte[],System.Int32)">
|
||||
<summary>used by PhotonPeer*</summary>
|
||||
</member>
|
||||
</members>
|
||||
</doc>
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8d4f08d435c4b6343969d8af249460ff
|
||||
labels:
|
||||
- ExitGames
|
||||
- PUN
|
||||
TextScriptImporter:
|
||||
userData:
|
||||
+811
@@ -0,0 +1,811 @@
|
||||
* release_history.txt
|
||||
* Release history for the DotNet Photon and Neutron Client Libraries (DotNet / Unity3D / Windows Phone 7.5)
|
||||
(C) 2012 Exit Games GmbH, http://www.exitgames.com
|
||||
|
||||
Questions? Visit:
|
||||
http://forum.exitgames.com
|
||||
http://doc.exitgames.com
|
||||
http://www.exitgamescloud.com
|
||||
|
||||
|
||||
*** Version 3.0.1.13 (26.9.2012 - rev1731)
|
||||
Fixed: Internals of method DispatchIncomingCommands() for UDP. In some cases this removed commands from a dictionary inside a foreach loop (which causes an Exception due to changing the dictionary)
|
||||
Added: Support for Dictionary<,>[]. This is not a very lean way to send data (especially when using <object,object>) but if needed, it now works
|
||||
Changed: Replaced several foreach loops with for loops (it doesn't change usage but in Unity exports to iOS, foreach uses more memory than for)
|
||||
Added: Doc for public methods in Protocol class (they are useful to quickly write values into an existing byte-array)
|
||||
Fixed: Unity UDP send code: iOS 5 devices will kill a socket when the power button is pressed (screen locked). This case was not detectable by checking socket.Connected.
|
||||
Added: Unity UDP send code: Now tries to open another socket to refresh/keep the connection. This is affected by timeouts still, of course (as are all connections).
|
||||
Internal: locked usage of UDP / enet channels
|
||||
|
||||
|
||||
*** Version 3.0.1.12 (26.07.2012 - rev1683)
|
||||
Changed: The DotNet client libraries are now Thread safe! You could start a background Thread to keep calling SendOutgoingCommands in intervals and still call it from a game loop, too
|
||||
Changed: Due to the thread safety, the demos no longer use excessive locks. This is now solved by the lib, more streamlined and hidden. One Thread is used instead of Timers (which could fire concurrently if execution was longer then their interval)
|
||||
Changed: Moved the enable/disable property fro NetworkSimulationSettings to PhotonPeer.IsSimulationEnabled (this should now be thread safe)
|
||||
Changed: NetworkSimulation will create and keep one thread when you first enable it in a (debug) client. Disabling it, will execute any delayed action immediately (in IsSimulationEnabled!) and pause the simulation thread
|
||||
Changed: All demos are updated. We assigned new event codes (starting at 0, like any developer's code should) and extended the comments. Check them out
|
||||
Changed: All Loadbalancing demos are now using the same DemoBasisCode linked in, so it can be changed in one position. Where needed an extension is made
|
||||
Updated: comments / documentation for LoadBalancing API, Lite API and basic Photon API (basically anything public)
|
||||
Changed: SupportClass.NumberToByteArray is now obsolete. It can be replaced with Protocol.Serialize() easily and that is performing better
|
||||
Fixed: Windows Phone UDP socket was sending a full package of zeros on connect. It didn't break anything but is not needed, of course.
|
||||
Fixed: SupportClass.StripKeysWithNullValues method was prone to throw an exception
|
||||
LoadBalancing API:
|
||||
Changed: LoadBalancingClient.OpLeaveRoom() skips execution when the room is null or the server is not GameServer or the client is disconnecting from GS already
|
||||
Note: LoadBalancingClient.OpLeaveRoom() returns false in those cases and won't change the state, so check return of this method
|
||||
Fixed: workflow for authentication (which should be called only once per connection, instead of "any time we establish encryption)
|
||||
|
||||
*** Version 3.0.1.11 (05.06.2012 - rev1569)
|
||||
Fixed: Udp issue with channels and unreliable commands. Unreliable commands of one channel were discarded, when another channel had unreliable commands, too
|
||||
|
||||
*** Version 3.0.1.10 (04.06.2012 - rev1561)
|
||||
Fixed: TCP connection issues for DotNet and Unity (Silverlight and WindowsPhone are different)
|
||||
Fixed: DotNet+Unity TCP send calls with 0 bytes to send (this was ignored by the socket but useless anyways)
|
||||
Moved: DNS resolution and socket.Connect() are now handled in the connection thread (TCP in DotNet and Unity)
|
||||
Fixed: Issue with (TCP) socket connections being closed directly while connecting. in this case, socket.Receive() might receive 0 bytes instead of blocking until more bytes are available. without sending anything, the socket never updates its .Connected state and never throws a Exception. now we send a ping and thus trigger a exception
|
||||
Fixed: Some documentation errors (due to changed API, etc)
|
||||
Loadbalancing API:
|
||||
Changed: LoadBalancingClient.OnEvent() now uses a join-event's actornumber-list to create Player instances for anyone who wasn't created as Player before
|
||||
Fixed: LoadBalancingClient.OnEvent() handling for join-event does not expect any actor/player properties anymore (which fixes a potential null-reference exception when not even a name is set)
|
||||
|
||||
*** Version 3.0.1.9 (10.05.2012 - rev1512)
|
||||
Fixed: Reference to project in Windows Phone SDK
|
||||
|
||||
*** Version 3.0.1.8 (09.05.2012 - rev1508)
|
||||
Fixed: The OpJoinRandom of the LoadBalancingAPI failed to filter rooms for their custom room properties. Instead, any room matched. This is fixed now.
|
||||
Added: New Demo for Windows Phone: Cloud Basics
|
||||
Changed: The loadbalancing / cloud-based demos are refactored to share a similar codebase
|
||||
|
||||
*** Version 3.0.1.6 (07.05.2012 - rev1489)
|
||||
Note: This is a "stable" release, containing only a few updates. The bulk of changes are in the "odd" numbered releases. Read those updates carefully.
|
||||
|
||||
*** Version 3.0.1.5
|
||||
Changed: adopted the even/odd version numbering system. versions ending on a odd number = intermediate/in-development version, even number = released (that makes 3.0.1.5 a intermediate)
|
||||
Fixed: When NetworkSimulation is disabled, all remaining packages are sent/received immediately (ignoring the former delays)
|
||||
Note: NetworkSimulation should be working nicely now. Be aware that sudden, additional lag might (!) lead to a disconnect. Play with the settings to find out which ones work for you
|
||||
Changed: Protocol class now has a few methods to (effectively) serialize some datatypes to arrays (and into existing arrays)
|
||||
Removed: Surplus public methods from Protocol that were "type-named" like SerializeFloat. The functionality is in still with overloaded methods
|
||||
Added: count of packages (requests) outgoing if TrafficStatsEnabled
|
||||
Demo Realtime:
|
||||
Changed: The commandline arguments are now server:port, protocol (udp,tcp,http), reliable sending, interval dispatch, interval send, interval move. Example: localhost:5055 Udp false 15 25 15
|
||||
Changed: Demo Realtime: If the commandline sets an unknown protocol, the client shows a message and closes gracefully
|
||||
Changed: Demo Realtime: The demo now starts in the grid view (showing something). Local player and player list are created with the Game instance. Player startpoint is randomized.
|
||||
Loadbalancing API:
|
||||
Renamed: LoadBalancingClient.lbPeer to .loadBalancingPeer
|
||||
Fixed: LocalPlayer.SetCustomProperties() usage
|
||||
Added: Service() method, which calls the LoadBalancingClient's Service simply
|
||||
Changed: LoadBalancingClient is no longer extending LoadBalancingPeer but instead using one
|
||||
Changed: the many overloads of Operations are gone in LoadBalancingPeer to streamline the api
|
||||
Changed: ActorProperties are no longer set via JoinRoom, JoinRandomRoom or CreateRoom. instead, set the properties in the LocalPlayer and let the LoadBalancingClient send and sync them where necessary
|
||||
Fixed: MasterClientId is now 0 when there are no more players in the room (it was set to int.max before)
|
||||
Internal:
|
||||
Changed: all DispatchIncomingCommands now use a while loop to dispatch the ActionQueue (in the hope this is the fastest way to do it)
|
||||
Changed: DispatchIncomingCommands now looks for the received unreliable command with lowest unreliable seqNr to dispatch this
|
||||
Changed: DispatchIncomingCommands discards commands if the reliable OR unreliable sequence is beyond the command's sequences
|
||||
Changed: DispatchIncomingCommands now truncates the incoming unreliable commands to limitOfUnreliableCommands (if that's > 0)
|
||||
Changed: the next reliable command to dispatch is now fetched with Dictionary.TryGetValue() (for being faster)
|
||||
Changed: no longer using BinaryReader streams anywhere (this should improve speed and reduce mem usage)
|
||||
Changed: PeerBase accordingly
|
||||
Changed: Unit test MyType de/serialization now supports null-references (as 1 byte being 0)
|
||||
Changed: Protocol.SerializeOperationRequest is now used in the same way, no matter if request is "top level" or inside some other datatype
|
||||
Changed: the peer bases accordingly to use only one SerializeMemStream and lock it
|
||||
Changed: how encryption fits in to the new serialization (it is a special case, as only the operation bytes get encrypted)
|
||||
Added: Protocol.SerializeParameterTable() as requests, events and responses all use the same way to write their parameters
|
||||
Changed: SerializeOperationToMessage parameter order
|
||||
Changed: Order of Protocol methods to make more sense (from byte to more complex types for serialization)
|
||||
New: PhotonDotNet library prototype for windows 8 metro
|
||||
|
||||
*** Version 3.0.1.3 (13.04.2012 - rev1430)
|
||||
Known issues: The Network Simulation is currently not guaranteed to work properly. Please bear with us.
|
||||
Note: the following change might be a breaking one:
|
||||
Changed: When dispatching a server's disconnect-command, the state is changed to ConnectionStateValue.Disconnecting BEFORE any callback due to state change is called. This should disallow game-code from calling any operations immediately.
|
||||
Changed: Many internals. This should result in better performance
|
||||
Changed: Service() now calls SendOutgoingCommands() until send-queues are empty. This might take more time but gets important commands out. If you need more control, Service() can be replaced with DispatchIncomingCommands and SendOutgoingCommands!
|
||||
Added: null check to GetEndpoint() to avoid issues when the host address is null
|
||||
Fixed: queueIncomingCommand() debug out message when a command is being received AND in in-queue (the list it accesses is now a dict)
|
||||
Added: new "vital" stats to TrafficStats
|
||||
Added: LongestOpResponseCallback and LongestOpResponseCallbackOpCode (opcode and time of longest callback)
|
||||
Added: LongestEventCallback and LongestEventCallbackCode (event code and time of longest callback)
|
||||
Added: LongestDeltaBetweenDispatching and LongestDeltaBetweenSending to detect "gaps" between subsequent calls of those
|
||||
Added: DispatchCalls and SendOutgoingCommandsCalls to measure average call-rate
|
||||
Fixed: PeerBase.TrafficStatsEnabledTime now checks if a stopwatch is set, else it returns 0
|
||||
Fixed: TrafficStatsReset() now works as intended (starting a new stopwatch, too)
|
||||
Internal:
|
||||
Changed: name of variable timeLastReceive. is now: timeLastAckReceive (better fit with what it does)
|
||||
Internal: queueOutgoingReliableCommand() to use a lock on the channel it accesses
|
||||
Internal: SerializeOperationRequest() now locks the MemoryStream while using it (avoids threading-issues with calling OPs)
|
||||
Internal: SendUdpPackage() now checks if socket is obsolete (and disconnected for a reason) or not. only if not, a error is logged
|
||||
Internal: EnetChannel now uses Dictionary and Queue for commands (should be faster to access)
|
||||
Internal: simplified access methods in EnetChannel according to changes
|
||||
Internal: outgoingAcknowledgementsList is now a Queue
|
||||
Internal: receiveIncomingCommands() no longer has a local variable sentTime. instead using this.serverSentTime directly
|
||||
Internal: UDP sending is now done with a synchronous socket call (profiling told us: this is cheaper)
|
||||
Internal: re-using the socket arguments for receiving packages (saves some buffer allocation)
|
||||
Internal: socket to non-blocking (maybe not possible on all devices)
|
||||
Removed: initial-HTTP-protocol support (HTTP support not public yet)
|
||||
Added: support for encryption with HTTP protocol
|
||||
|
||||
|
||||
*** Version 3.0.1.2
|
||||
- Added: Rooms now have a "well known" property to list the custom properties that should be available in the lobby. This can be set per room (but most likely makes sense per title/application).
|
||||
- Added: LoadBalancingClient.OpCreateRoom() has a new parameter "propsListedInLobby" and Room.PropsListedInLobby is available to check this list (if needed at all).
|
||||
- Added: GameProperties.PropsListedInLobby as "well known property" key
|
||||
- Changed: LoadBalancingPeer.OpCreateRoom now sets ParameterCode.CleanupCacheOnLeave to true by default. This makes the server clean a player's event cache on leave.
|
||||
- Added: SupportClass.DictionaryToString() will now print values of string[] and optionally leaves out type information.
|
||||
- Note: 3.0.1.1 didn't get it's own SDK, so read that version's changes, too
|
||||
|
||||
*** Version 3.0.1.1
|
||||
- Added: PhotonPeer.TrafficStatsElapsedMs, which gives you the milliseconds that the traffic stats are enabled. This internally uses a stopwatch (for now) which might not be available on all platforms. Please report if this new SDK causes issues.
|
||||
- Added: PhotonPeer.TrafficStatsReset() to reset the traffic stats and the timer. This could be useful to get stats of "in game" versus "out of game". Note: Loadbalancing includes frequent server-switching and each disconnect/reconnect causes a reset.
|
||||
- Changed: In LoadBalancingPeer EventCode.SetProperties is obsolete and replaced with EventCode.PropertiesChanged. Please switch to new constant.
|
||||
- Added: Support in LoadBalancingAPI for Player.IsMasterClient. For this, the Players now get a RoomReference set (when added). The active player with the lowest ID is the master (per room).
|
||||
- Added: Room.MasterClientId, which is updated when new players are added or the current master is removed.
|
||||
- Added: SupportClass.DictionaryToString() has an overload which doesn't "print" the Type per key/value.
|
||||
- Added: Loadbalancing API overload for OpJoinRandomRoom(...) taking additional parameter 'playerProperties'
|
||||
- Added: Loadbalancing API CacheProperties() and Room.GetPlayer() are public now
|
||||
- Added: LoadBalancingClient will now handle ExceptionOnConnect and keep clients from re-connecting if establishing a connection fails
|
||||
- Note: The following changes affect only HTTP, which is an upcoming option for connections. So far, the public server SDKs don't support this. Feel free to contact us about it.
|
||||
- Added: setter for PhotonPeer.ServerAddress to allow setting a http url (even while connected)
|
||||
- Added: PhotonPeer.HttpUrlParameters setting parameters to be added to end of url (must begin with '&')
|
||||
- Added: HttpUrlParameters to PeerBase
|
||||
- Added: HttpUrlParameters is now attached to the end of a URL in http usecase
|
||||
- Added: "Http2" support to Unity library
|
||||
- Internal: method HttpBase.ConnectAsync is no longer needed and Request() is now directly passed to thread
|
||||
|
||||
*** Version 3.0.1.0
|
||||
- Added: Loadbalancing (Cloud) Features
|
||||
- Added: Project with the Loadbalancing sourcecode for DotNet, WindowsPhone and Unity3d (usable without PUN)
|
||||
- Added: Initial, simple Loadbalancing demos for each platform (will update and extend those)
|
||||
- Note: The API of the client libraries didn't change. The new features were added on top of the known API
|
||||
- Added: VS2010 solutions for DotNet and Windows Phone SDKs containing the demos and APIs in the package
|
||||
- Added: readme.txt with initial help to setup the Cloud/Loadbalancing demos
|
||||
- Added: default appId for Loadblanacing demos: "<insert your appid here>"
|
||||
|
||||
*** Version 3.0.0.10
|
||||
- Added: When UDP StartConnection (internal method) fails, callbacks to OnStatusChanged(StatusCode.Disconnect) are now done additionally to the SecurityExceptionOnConnect and ExceptionOnConnect calls. This happens direcly inside PhotonPeer.Connect()!
|
||||
- Changed: When Unity UDP implementation fails to connect due to missing DNS resolution, it now also calls OnStatusChanged(StatusCode.ExceptionOnConnect)
|
||||
- Removed: StatusCode.Exception_Connect value (obsolete, replaced by ExceptionOnConnect, same value)
|
||||
- Fixed: Http connections (DotNet & Unity) now skip results while in disconnected state
|
||||
- Fixed: Http connections (DotNet & Unity) now ignore results after a disconnect and reconnect was done (this applies only to HttpBase, not HttpBase2)
|
||||
- Fixed: misleading debug out (pointing to WindowsPhone while the class is now in general use)
|
||||
- Changed: DotNet UDP connection now only logs socket errors if the connection isn't obsolete (disconnected) already
|
||||
|
||||
*** Version 3.0.0.9
|
||||
- Fixed: issue with HTTP connections and EstablishEncryption()
|
||||
- Changed: ActionQueue is now a Queue<MyAction>, allowing Dequeue in a while loop instead of foreach(i in list) and clear()
|
||||
- Changed: Unity HttpBase DispatchIncomingCommands() to make use of the queue
|
||||
- Fixed: init byte[] length (internal. did not have consequences)
|
||||
- Fixed: LitePeer OpRaiseEvent() was sending encrypted
|
||||
- Internal: ContainsUnreliableSequenceNumber() check if reliable list needed sorting
|
||||
- Fixed: Unity/Silverlight bug with encryption. Their implementation of BigInteger.GetBytes() failed when the 2nd, 3rd or 4th of the first 4 bytes was 0 but the previous wasnt. This led to incompatible secrets.
|
||||
- Changed: TCP socket sending debug output now checks debuglevel (when send is skipped, cause the sender is obsolete already)
|
||||
- Added: caching option RemoveFromRoomCacheForActorsLeft = 7
|
||||
- Internal: Added another http-based communication protocol. Please note: The fitting server's are not yet publicly released. This does not affect UDP or TCP protocols.
|
||||
|
||||
*** Version 3.0.0.8
|
||||
- Fixed: Udp fragment reassembly in case fragments are received out of order and incoming queue was not yet sorted
|
||||
- Fixed: Handling of incoming reliable commands (udp) which were skipped in some cases, if not received in order
|
||||
- Fixed: Network simulation issue which caused lost incoming commands
|
||||
- Fixed: Demo Realtime. protocol is now again Udp, fitting the default server address "localhost:5055" (make sure to build the demo with your server's address if Photon is not on the same machine)
|
||||
|
||||
*** Version 3.0.0.7
|
||||
- Changed: Udp socket usage for Unity 3d lib. Both threads (send (in game loop) and receive (separate)) now have minimal locks while using the socket
|
||||
- Fixed: SendOutgoingCommands now returns true if anything didn't make it into the outgoing UDP package
|
||||
- Internal: TCP connections also skip network simulation when it's turned off
|
||||
|
||||
*** Version 3.0.0.6
|
||||
- Fixed: SendOutgoingCommands now returns true if commands are remaining in outgoing queues (UDP only sends one package per call, TCP will send anything outgoing).
|
||||
- Added: New "RoomCache" for Events. The EventCaching enum allows you to use it. Events in this cache will keep the order in which they arrived in the server. A filter makes deleting them very flexible.
|
||||
- Internal: Ability to make lib send only ACKs and nothing else. This is probably a temp solution as it might be better to make sending and calling ops completely thread safe.
|
||||
- Internal: PhotonPeer.IsSendingOnlyAcks, which is locked with the sending (not changing while sending). This makes SendOutgoingCommands() thread safe, which is good if you need a separate thread to keep connection. You could call operations while sending.
|
||||
- Internal: Unity3d's connection now also syncs socket usage
|
||||
|
||||
*** Version 3.0.0.5
|
||||
- Fixed: ObjectDisposedException in DotNet UDP workflow. This was caused by disconnecting while incoming data was processed (and before the next datagram was accepted)
|
||||
- Added: PhotonPeer.LimitOfUnreliableCommands property. This helps you skip potentially "outdated" unreliable commands (events), which helps if you couldn't dispatch for a while
|
||||
- Internal: Minor performance improvements. Example: The check if network simulation is turned on is done earlier in the workflow, which avoids a bit of overhead
|
||||
|
||||
*** Version 3.0.0.4
|
||||
- Fixed: Tcp connections have been throwing ArgumentNullException in DispatchIncomgingCommands() if they were not connected yet
|
||||
- Internal: Adjusted Http client to server rev2360
|
||||
|
||||
*** Version 3.0.0.3 RC2
|
||||
- Internal: Communication with HTTP server is WIP (Work In Progress - not a publicly available feature)
|
||||
|
||||
*** Version 3.0.0.2
|
||||
- Fixed: OpRaiseEvent overload with EventCaching and ReceiverGroup parameters was not sending the customEventContent as expected. This was always null.
|
||||
- Fixed: Time fetching case where no time was accepted. Servertime is now accepted, if the fetch-time-command was less or equal as the current roundtrip time. Avoids issues if rtt is exceptionally low immediately.
|
||||
- Internal: When using multiple channels, dispatching incoming commands now will continue with the next channel, if one doesn't yet have the next reliable command (reliable sequence of one channel does not affect others)
|
||||
- Internal: Changed protocol for TCP and message headers. This will support bigger message sizes. Also changed debug out related to unknown headers.
|
||||
- Internal: Changed handling of TCP receive-callbacks for unfinished messages in Silverlight and WP. This should fix handling of very big data that's received in multiple "chunks"
|
||||
- Internal: Http messages are now deserialized the same way that content in tcp or udp is handled
|
||||
|
||||
*** Version 3.0.0.1 RC1
|
||||
- Fixed: Packaging of SDK now includes all files in demo folders, except a list of ignored file-endings (xaml and jpg files were missing in previous Silverlight and WindowsPhone SDKs)
|
||||
|
||||
*** Version 3.0.0.0 RC1
|
||||
- Changed: Filenames! Now include a '3' for Photon v3. Update your references! Also, Silverlight libraries now use "Silverlight" in the filename (was: SL)
|
||||
- Changed: Versioning. A dll's version has now 4 digits. The first 2 match Major and Minor number of the Server SDK. The latter 2 are Release and Build respectively
|
||||
- Changed: Silverlight DataTypes (like Hashtable) are now in namespace ExitGames.Client.Photon. This is easier to include (as that namespace is in "using" in most cases)
|
||||
|
||||
*** Version 6.4.5
|
||||
- Changed: Parameters for OpCustom are now of type Dictionary<byte, object>, making sure that only byte-codes are used for parameters
|
||||
- Changed: Most IPhotonPeer names (to match those in server code): EventAction -> OnEvent, OperationResult -> OnOperationResponse, PeerStatusCallback -> OnStatusChanged
|
||||
- Added: SupportClass.DictionaryToString(), which converts the content to string (includes support for Hashtables)
|
||||
- Moved: Definitions of Lite and Lite Lobby specific codes for Parameters, operations and events are now in LitePeer. Will be available as source and could be replaced
|
||||
- Changed: Usage of codes in Lite and Lite Lobby. Now pre-defined codes are starting at 255 and go down. Your events, operations and operation-parameters can now start at 0 and go up without clashing with pre-defined ones
|
||||
- Changed: Constants that are non-exclusive (like event codes and OpKeys, which can be extended) are no longer "defined" as enums but as class of const byte values. Less casting but also less convenient "name" representation in debug output
|
||||
- Added: LiteEventKey.CustomContent as key to access the content you sent via OpRaiseEvent ("Data" seems a bit misleading but is also available)
|
||||
- Changed: Namespace of LitePeer to ExitGames.Client.Photon.Lite (the Lite-specific class is still compiled into the library for convenience but can be ignored quite easily this way)
|
||||
- Added: Property MaximumTransferUnit. The default is 1200 bytes. Usually this is ok. In few cases, it might make sense to lower this value to ~520, which is commonly assumed the minimum MTU. Don't change this, if you don't know why.
|
||||
- Added: New classes to wrap up op-requests (OperationRequest), op-results (OperationResponse) and events (EventData). Those new classes are now used in callback methods OnEvent and OnOperationResponse
|
||||
- Changed: by using the new classes (note above), the client is a bit more like the server in its naming. We didn't want to change every last bit though.
|
||||
- Internal: Changed protocol (to 1.6) so that it does not require any parameter codes internally. Any application can now define any operation, parameter and event codes it wants to.
|
||||
- Changed: Encryption is now triggered by you and resolved by the library. You don't have to look out for the result of EstablishEncryption and use it. Instead: wait for OnPeerStateChanged call with either EncryptionEstablished or EncryptionFailedToEstablish
|
||||
- Removed: InvocationId. This concept was very rarely used but confusing. It's easy to implement, if needed. If you don't know what this means: Nevermind.
|
||||
- Changed: Operation calls now return bool: if they could be enqueued or not. If enqueued (cause you are connected and the data was serializable), then SendOutgoingCommands will send those operations (as before).
|
||||
- Added: Support to de/serialize Dictionary<T1,T2>. If the types are more specific than object, the serialization writes the type-code only once (lean byte usage in protocol)
|
||||
- Added: Support to de/serialize null. Enables you to send a null value, e.g. in a Hashtable
|
||||
- Added: ReceiverGroup enum to select a range of players that get an event via Operation Raise Event
|
||||
- Added: Event Caching. Any event sent via RaiseEvent can now be buffered on the server side and is "repeated" when a new player is joining a room. This is similar to Properties but lets you categorize your info better and works just like regular events, too.
|
||||
- Added: EventCaching enum to select if an event is to be cached and how it's cached: either "not at all" (default), replacing anything cached so far (fast) or "merge" (which will add new and replace old keys with new values). Optionally, a event can be raise with option "remove".
|
||||
- Added: new overload of OpRaiseEvent() with the two new parameters noted above
|
||||
- Added: Support for custom de/serializer methods. By writing 2 methods to convert a object into a byte-array (and back from that), Photon now supports any custom object type (standard datatypes are still supported out of the box)
|
||||
- Added: PhotonPeer.RegisterType() to register serializer and deserialize methods for a certain type. Per object, a length and one byte 'type code' are added to the serialized data
|
||||
- Added: Support for non-strict object[]. Unlike strictly-typed array, here each element will carry its own type.
|
||||
- Note: If you want to use the new Custom Types or the object[], you have to update your server! Older Servers don't support the new features. As long as you don't use these features, the library is compatible with previous servers.
|
||||
- Added: ByteCountCurrentDispatch and ByteCountLastOperation properties to PhotonPeer (the ancestor of LiteGame, etc). A game can now access the size of operation-results and events as well as operation-call size.
|
||||
- Added: Traffic statistic set: PhotonPeer.TrafficStatsGameLevel as "high level" game-related traffic statistic. Counts bytes used by operations, their results and events. This includes overhead for these types of messages, but excludes connection-related overhead
|
||||
- Added: Traffic statistic set: PhotonPeer.TrafficStatsIncoming and PhotonPeer.TrafficStatsOutgoing as low level statistics of the traffic
|
||||
- Added: PhotonPeer.TrafficStatsEnabled which enables two sets of traffic statistics. By default, statistics are turned off.
|
||||
- Added: Classes TrafficStats and TrafficStatsGameLevel for the two statistic cases metioned above
|
||||
- Changed: NetworkSimulation now starts a Thread when it becomes enabled and the thread ends on simulation disable. Disable the NetworkSimulation to stop the thread, as Disconnect does not change the simulation settings!
|
||||
- Internal: Cleanup and renaming of several properties
|
||||
- Internal: Each new peer increases the PeerCount but it is no longer reduced on disconnect (it is existing still, after all)
|
||||
- Internal: Udp commands will be buffered when serialized. This saves some work when re-sending a reliable command
|
||||
- Added: TCP Routing code (not in Silverlight). To be used when running Photon on Azure (can be ignored in regular use)
|
||||
- Added: to StatusCode: TcpRouterResponseOk = 1044, TcpRouterResponseNodeIdUnknown = 1045, TcpRouterResponseEndpointUnknown = 1046 and TcpRouterResponseNodeNotReady = 1047,
|
||||
- Added: override for PhotonPeer.Connect() with node
|
||||
- Internal: DotNet now reads the 2 bytes routing response, if a routing request was made (also, not in Silverlight)
|
||||
- Internal: If TConnect sent a routing request, nothing else will be sent until 2 bytes response are read.
|
||||
- Internal: If the routing-response does not start with ProxyResponseMarkerByte = 0xF1, a debug message is enqueued and TCP will disconnect
|
||||
- Internal: Init request for TCP is now always enqueued instead sent directly. This way, it can be delayed if a routing node is selected
|
||||
- Internal: TPeer EnqueueInit() and SendProxyInit() now create init and routing request respectively
|
||||
- Internal: TConnect.sendTcp() checks isRunning before it tries to send (the socket might close before the NetSim does). This won't be an issue anytime, still INFO-level callback to DebugReturn is done.
|
||||
- Removed: debug out for "send package" situation (even on ALL-level, this is more or less spam)
|
||||
- Internal: updated version numbers of init to 6.4.5
|
||||
- Changed: SupportClass HashtableToString() returns "null" if parameter is null
|
||||
- Internal: Removed SortedCommandList and CommandList classes. Replaced by List<NCommand> and a Sort() where necessary
|
||||
- Internal: EnetPeer.channels is now a Dictionary<byte, Channel> instead of a SortedList
|
||||
- Internal: the channels are initialized with channel 0xff first - this makes 0xff high prio in all foreach usaged
|
||||
- Internal: NCommand class is now IComparable<NCommand> for usage in Sort()
|
||||
|
||||
|
||||
*** Version 6.4.4
|
||||
- Added: PhotonPeer.TimestampOfLastSocketReceive now provides the time when something was received. Can be used warn players of bad communication-timing even before the disconnect timeout will be happening
|
||||
- Fixed: OpGetPropertiesOfActor did use the actorNrList correctly, which always got you all properties of all players
|
||||
|
||||
*** Version 6.4.3
|
||||
- Changed: A udp connection timeout in Unity will now end the socket-handling thread correctly
|
||||
- Changed: The thread for Network simulation is now stopped when the client disconnects and started on connection (instead of keeping it per peer)
|
||||
- Fixed: Exceptions in network simulation, when Disconnect() was called soon after Connect() but before the connection was established.
|
||||
|
||||
*** Version 6.4.2
|
||||
- Fixed: It was possible to send PhotonPeer.FetchServerTimestamp() before being connected properly. Now the method triggers debug output (INFO level) and the callback PeerStatusCallback(StatusCode.SendError)
|
||||
- Internal: Added a lock in the UDP version of SendOutgoingCommands(). It's still illegal to access a peer from multiple threads but the follow-up issues this lock avoids are very difficult to track.
|
||||
- Internal: to stay compatible with all exports of Unity, the use of System.Threading.Interlocked.Exchange was replaced by simply replacing the list's reference instead
|
||||
|
||||
*** Version 6.4.1
|
||||
- Changed: The Unity library now uses the WWW class for Http based requests. Results are checked within DispatchIncomingCommands(). Important: Unity allows handling WWW requests only on the MainThread, so dispatch must be called from this context!
|
||||
- Note: Photon does not support Http requests out of the box. Customers get access to a fitting server on demand
|
||||
- Changed: outgoing list is now replaced on send, instead of calling remove(0) repeatedly (which takes longer). Internal: this uses System.Threading.Interlocked.Exchange to switch to a new outgoing list in one step
|
||||
|
||||
*** Version 6.4.0
|
||||
- Fixed: TCP handling of incoming data. This avoids loss of data (operation-results or events) when a lot of data is incoming.
|
||||
- Changed: PeerStatusCallback() is less often called for queue-length warnings (e.g.: StatusCode.QueueIncomingReliableWarning). Only if a queue has a multiple of PhotonPeer.WarningSize items.
|
||||
- Changed: WarningSize is now 100 by default
|
||||
- Changed: Description of PhotonPeer.WarningSize and PhotonPeer.CommandBufferSize, which really is just the initial size of any buffer. The warnings are there to avoid situations where all heap is used up.
|
||||
- Changed: Naming: StatusCode.Exception_Connect is now Obsolete and replaced with StatusCode.ExceptionOnConnect
|
||||
- Added: Missing summary for StatusCode.SecurityExceptionOnConnect
|
||||
- Added: NetworkSimulationSet.ToString override to provide a better overview
|
||||
- Added: Support for arrays of Hashtables
|
||||
|
||||
*** Version 6.3.1
|
||||
- Fixed: Network simulation now delays incoming packages by IncomingLag and IncomingJitter as expected (it was using the outgoing values, too)
|
||||
|
||||
*** Version 6.3.0
|
||||
- Added: Network simulation (lag, jitter and drop rate) to debug builds
|
||||
- Added: class NetworkSimulationSet with properties to control network simulation
|
||||
- Added: NetworkSimulationSettings.NetworkSimulationSettings property to get current simulation settings
|
||||
- Changed: only the first peerId of a VerifyConnect is accepted in client (avoids surplus peerID changes)
|
||||
- Internal: added PeerBase.SendNetworkSimulated() and PeerBase.ReceiveNetworkSimulated() and a Thread to run delay simulation
|
||||
Siverlight:
|
||||
- Updated: to Silverlight v4.0
|
||||
- Added: Encryption to Silverlight library
|
||||
- Internal: updated internal BigInteger class for Silverlight
|
||||
- Internal: DiffieHellmanCryptoProvider in Silverlight, so it uses AesManaged instead of Rijndael (which is not part of Silverlight 3)
|
||||
- Added: Stopwatch class to DataTypes.cs (for Silverlight only)
|
||||
|
||||
*** Version 6.2.0
|
||||
- Added: "Demo LiteLobby Chatroom" to Unity SDK
|
||||
- Updated: Demo Realtime in Unity client SDK. It's still compatible with the demo on other platforms but cleaned up and much better commented
|
||||
- Updated: Documentation is now clearer on where the Lite logic is used (it runs on Photon but is not the only application logic)
|
||||
- Updated: Documentation for the enumerations in IPhotonListener. The Lite application based ones are better described and it's now clear which ones are essential to the Photon client (not only in Lite)
|
||||
- Updated: Documentation in several other places
|
||||
- Added: StatusCode.SecurityExceptionOnConnect which is thrown if a security exception keeps a socket from connecting (happens in Unity when it's missing a policy file)
|
||||
- Added: PhotonEventKey and PhotonOpParameterKey which contain the fixed byte keys that cannot be re-assigned by applications at will (as these keys are used in the clients and server in their respective context)
|
||||
- Change: PhotonPeer.PeerState is no longer a byte but of type PhotonPeer.PeerStateValue, which makes checking the state simpler. The PeerStateCallback() for state changes is still called as before.
|
||||
- Changed: Property PhotonPeer.PeerState. It now converts the low level ConnectionStateValue to a PeerStateValue, which now includes a state InitializingApplication. See reference for PeerStateValue.
|
||||
- Changed: PeerStateValue enum is now part of the ExitGames.Client.Photon namespace, making it more accessible
|
||||
- Internal: NConnect in DotNet and Unity to catch security exceptions
|
||||
- Internal: from using var to explicit type usage in DiffieHellmanCryptoProvider.cs (Mono Develop friendly)
|
||||
- Internal: made const: ENET_PEER_PACKET_LOSS_SCALE, ENET_PEER_DEFAULT_ROUND_TRIP_TIME and ENET_PEER_PACKET_THROTTLE_INTERVAL
|
||||
- Internal: PeerBase "PeerStateValue peerState" is now: "ConnectionStateValue peerConnectionState" (holding the low level connection state, nothing more)
|
||||
- Internal: added PeerBase.ApplicationIsInitialized, which stores if the init command was answered by Photon (reset on connect/disconnect)
|
||||
- Removed: PhotonDemoServerUrlPort and PhotonDemoServerIpPort of PhotonPeer. All demos now use "localhost:5055" and you should run your own server.
|
||||
- Added: enum ConnectionProtocol to get rid of the "useTcp" parameter in the PhotonPeer constructor (which was less clear than the explicit enum now in use)
|
||||
- Added: overload of PhotonPeer constructor, which is still compatible with the "useTcp" bool parameter (to avoid a breaking change for the time being)
|
||||
- Added: PhotonPeer.UsedProtocol property to find out this peer's protcol
|
||||
- Added: LitePeer.OpLeave() overload without the gameName parameter. That name is not checked in the Lite application (on the server), so it's not really needed
|
||||
|
||||
*** Version 6.1.0
|
||||
- Added: Encryption for Unity and DotNet. Operations (and their responses) can be encrypted after exchanging the public keys with the server
|
||||
- Added: OpExchangeKeysForEncryption(), DeriveSharedKey() and IsEncryptionAvailable to PhotonPeer (and LitePeer inherits these)
|
||||
- Added: OpCustom() will throw an ArgumentException if the operation should be encrypted but keys are not yet exchanged (exchange keys first)
|
||||
- Added: LiteOpCode.ExchangeKeysForEncryption = (byte)95
|
||||
- Added: Overloaded PhotonPeer.OpCustom() with new "encrypt" parameter
|
||||
- Added: property PhotonPeer.IsEncryptionAvailable is true if public-keys are exchanged and the secret is compiled from them
|
||||
- Added: Encryption demo to Realtime Demo. Press E to exchange keys and R to toggle encrypted sending for the move data (even though events are never encrypted)
|
||||
- Changed: PeerBase methods: sendOperation()->EnqueueOperation(...,encrypt), updateRoundTripTimeAndVariance()->UpdateRoundTripTimeAndVariance()
|
||||
- Updated: the Unity client is now a Unity v3.1 project. Make sure to change the server address before you build for iPhone (localhost:5055 won't work on the mobile)
|
||||
- Removed: the outdated, separate iPhone demo (was: Unity v1.7 for iPhone)
|
||||
- Updated: PhotonPeer documentation for Service(), DispatchIncomingCommands() and SendOutgoingCommands()
|
||||
- Added: OpRaiseEvent() overload with parameter TargetActors. Sends optional list of actors that will receive the event (if null, all *other* actors will receive the event, as default)
|
||||
- Internal: Added source BigInteger.cs, DiffieHellmanCryptoProvider.cs and OakleyGroups.cs
|
||||
- Internal: PeerBase.CryptoProvider, PeerBase.ExchangeKeysForEncryption() and PeerBase.DeriveSharedKey()
|
||||
- Internal: EnetPeer.initPhotonPeer() and TPeer.initPhotonPeer() are setting PeerBase.isEncryptionAvailable = false
|
||||
- Internal: De/Serialization methods (and some variables for it) are moved from NConnect to PeerBase and renamed to: SerializeOperationToMessage() and DeserializeMessageAndCallback()
|
||||
- Internal: switched project to allow "unsafe" functions (used by BigInteger)
|
||||
- Internal: renamed PhotonPeer.sendOperation()->EnqueueOperation
|
||||
- Internal: changed assembly version to 6.1.0 and "client version" in init-byte-block to 6,1,0
|
||||
- Internal: moved protocol handling to EnetPeer and TPeer classes (where encryption is added)
|
||||
- Internal: moved InitBlock to (shared) PeerBase (same for UDP/TCP)
|
||||
- Internal: serialization is now done by Protocol.SerializeOpParameters(), which excludes the message header. this makes encryption simpler
|
||||
|
||||
*** Version 6.0.0
|
||||
- Changed: This library requires Photon v2.2.0 and up! (in other words: the libraries are not compatible with older Photon servers, due to servertime changes)
|
||||
- Added: Support for arrays in arrays. Any serializable datatype can now be used in nested arrays. Even arrays of Hashtables are possible.
|
||||
- Added: Realtime Demo optional command line arguments for game config. set all or none: serverAddress, useTcp (true/false), useReliable (true/false), int intervalDispatch, intervalSend (ms), intervalMove (ms)
|
||||
- Note: Realtime Demo commandline might look like this: start demo-realtime.exe localhost:5055 false true 5 25 100
|
||||
- Changed: renamed GetLocalMsTimestamp property to LocalMsTimestampDelegate (it does not have a getter, despite the old name's implication)
|
||||
- Added: PhotonPeer.LocalTimeInMilliSeconds property to use the timestamp delegate to get the current client milliseconds (by default this is Environment.TickCount)
|
||||
- Changed: UDP: The default value for PhotonPeer.RoundTripTime (300ms, used before connecting) is now replaced with the turnaround time of connect. This should lead to accurate RTT values much sooner
|
||||
- Changed: PhotonPeer.ServerTimeInMilliSeconds is no longer updated all the time. Instead it's fetched soon after connect (when initialization won't affect rountrips anymore) and extrapolated. It should be better to be off by a constant value than by a changing value
|
||||
- Changed: PhotonPeer.ServerTimeInMilliSeconds now returns 0 until the server's timestamp is fetched. Updated the documentation with some internals for this.
|
||||
- Added: PhotonPeer.FetchServerTimestamp() to send the time fetch command (this is done automatically as well. this method is here for completeness)
|
||||
- Fixed: roundtrip time calculation is no longer affected by long intervals between Service() or DispatchIncomingCommands() calls (bug of v5.9.0, caused by internal action queues)
|
||||
- Added: internally for UDP, we use a new command to fetch the timestamp which minimizes the latency for that roundtrip. this one is excluded in roundtrip time measuring
|
||||
- Changed: internal: ACKs by the server are again directly executed (other commands which are put into the action queue and dispatched)
|
||||
- Fixed: Peers with TCP as protocol will no longer try to disconnect while not being connected (does not do anything of disconnected or disconnecting)
|
||||
- Changed: Peers with TCP as protocol will clear the outgoing queue when disconnect() is called (while connected. see fix above)
|
||||
- Updated: Silverlight Realtime Demo slightly
|
||||
- Added: PhotonPeer.Listener property to give subclasses access to the IPhotonPeerListener (set in constructor). Can be useful to call Listener.DebugReturn()
|
||||
- Added: LitePeer-Source.cs to demo-realtime. This is the source of a LitePeer and could be used as sample to create custom operations on the client side
|
||||
|
||||
*** Version 5.9.0
|
||||
- Release: of changes in 5.7.6 and 5.7.5
|
||||
|
||||
*** Version 5.7.6
|
||||
- Fixed: a debug output line for TCP connections which did not heed the debug-level.
|
||||
- Changed: PhotonPeer uses less locking internally and will handle incoming data in the game thread (inside DispatchIncomingCommands() or Service()).
|
||||
- Changed: Internally, all commands are put into a (locked) queue which is processed within DispatchIncomingCommands(). Your dispatch interval affects local lag but not the PhotonPeer.RoundTripTime value.
|
||||
- Note: Don't use a peer from multiple threads! It's not thread safe. All callbacks to IPhotonPeerListener methods are happening in your game thread (again: inside DispatchIncomingCommands()).
|
||||
- Changed: removed locks inside the callbacks (according to above change).
|
||||
- Changed: DNS resolution is now done in Connect() unless you provide a valid IP address (if IPAddress.Parse(address) is successful, the IP is used directly).
|
||||
- Fixed: PhotonPeer.Connect() should fail if the IP is unknown or unavailable. Exception: using a localhost might succeed but fail when we try to receive anything.
|
||||
- Updated: Game.cs now initialized the timing intervals. This avoids issues if the client system is having a negative TickCount.
|
||||
- Added: ServerAddress property to PhotonPeer, which might help while developing with several servers and peers.
|
||||
- Changed: This version includes GetLocalMsTimestampDelegate and the PhotonPeer property GetLocalMsTimestamp to set the delegate for local timestamp.
|
||||
|
||||
*** Version 5.7.5
|
||||
- Changed: All precompiled demos now connect to localhost! From now on, you need to run Photon before trying any of the demos (as we don't guarantee that udp.exitgames.com is online anyways)
|
||||
- Changed: OpCustom() now accepts null as parameter Hashtable, which is a shortcut to "no parameters" for simple operations (an empty hashtable is sent though, it does not reduce bandwidth)
|
||||
- Added: new feature: UDP timeout definition by setting PhotonPeer.DisconnectTimeout (individual per command, set in milliseconds, checked when a command is repeated)
|
||||
- Renamed: enum ReturnCode to StatusCode. The StatusCode values are only used for status callbacks (not as operation results)
|
||||
- Changed: parameter type of PeerStatusCallback() from int to StatusCode (to differentiate them from operation ReturnCodes, which are customizable)
|
||||
- Removed: StatusCode.Ok (as it was actually an Operation ReturnCode)
|
||||
- Added: new StatusCallback value: StatusCode.SendError. Used for sending error cases: "not connected" and "channel not available"
|
||||
- Changed: sendOperation() (Udp and Tcp) does not throw an exception while disconnected or for wrong channel (using StatusCode.SendError instead)
|
||||
- Changed: callback DebugReturn() now has the additional parameter (DebugLevel)level, analog to logging
|
||||
- Changed: UDP connection is disconnected when a read exception happens (before we tried to read despite this until a timeout ended it)
|
||||
- Changed: EnetPeer.Disconnect() now ignores calls when peer is disconnected or disconnecting already
|
||||
- Fixed: TCP code tried to detect socket issues by checking for IOExceptions but now checks SocketException instead
|
||||
- Changed: internal threading: Callbacks due to incoming packages and commands are now queued and triggered by dispatch (in game loop)
|
||||
- Changed: dispatch of action-queue as added to DispatchIncomingCommands (in EnetPeer and TPeer)
|
||||
- Changed: internally, there is no locking for outgoing reliable and unreliable command lists anymore
|
||||
- Changed: Realtime Demo timer usage to avoid nullref on form-close
|
||||
- Changed: Realtime Demo propety isReliable is now in the Player class
|
||||
- Changed: Game.cs and Player.cs for all realtime demos. There is now something like a gameloop (Update()) which must be called regularly and makes (pretty) sure just one thread accesses the peer
|
||||
- Changed: all realtime demos to use the new Update() method and use more similar Game and Player classes (cleanup for less differences)
|
||||
- Fixed: RoundtripTimeVariance is now also reset on connect / init, so the resend-timing of reliable udp does not suffer when a peer connects after a disconnect
|
||||
- Fixed: typo in ExitGames.Client.Photon.StatusCode.QueueIncomingUnreliableWarning (was QueueIncomingUneliableWarning)
|
||||
|
||||
*** Version 5.7.4 RC3
|
||||
- Changed: Unity3D lib again has it's own UDP handling (the DotNet one causes browser crashes on web-player exit)
|
||||
|
||||
*** Version 5.7.3 RC3
|
||||
- Changed: Unity3D lib is now identical to DotNet lib (Unity iPhone is compatible with DotNet 2.0 now and this got tested)
|
||||
- Fixed: DNS resolution (did not work for "localhost", which gave two results (IPv4 and IPv6), mixing up things
|
||||
|
||||
*** Version 5.7.2 RC3
|
||||
- Changed: Unity3D lib: the receive thread will now receive until no data is available, then sleep 5ms and check again
|
||||
- Changed: serverTime is now a signed int (as on server) and adds averaged rountripTime/2 when it gets an update
|
||||
- Changed: ServerTimeInMilliSeconds doc (more concrete, explains how server time works)
|
||||
- Added: support for serverTime, RountripTime and RoundtripTimeVariance when using TCP (Silverlight does not allow UDP)
|
||||
- Added: Silverlight supports either URL:Port and IP:Port as server url string
|
||||
|
||||
*** Version 5.7.1 RC2
|
||||
- Added: DotNet "Lobby Demo" which uses the "LiteLobby" application of the server SDK to show running games and their player-count
|
||||
- Changed: the realtime demos to use the more similar Game and Player classes
|
||||
|
||||
*** Version 5.7.0 RC1
|
||||
- Added: documentation: project for Silverlight Hashtable and ArrayList substitutes.
|
||||
- Changed: RealtimeDemo uses same classes Game and Player for Unity3 + Silverlight
|
||||
- Changed: Silverlight: Hashtable and ArrayList are now a separate project / lib
|
||||
- Internal: Silverlight: listener interfaces (Photon and Neutron) now conditionally use ExitGames.Client datatypes from lib
|
||||
- Changed: Photon: connect callback is now deferred to on-init-response (instead of enet-connect) which ensures "no ops before init"
|
||||
- Changed: Unity Realtime demo: using game and player classes merged over from silverlight and re-wrote sample code to display players
|
||||
- Internal: photon projects now have a pre-compile setting "Photon"
|
||||
- Changed: SupportClass Namespace is now compiling into either ExitGames.Client .Photon or .Neutron (to avoid ambiguation)
|
||||
- Added: LitePeer as Lite Application specific peer (with OpJoin and the rest)
|
||||
- Changed: demos accordingly
|
||||
- Changed: case of PhotonPeer methods to first-letter-is-uppercase (as usual in C#)
|
||||
- Removed: nNet-prefix (Connect and Disconnect are self-explanatory)
|
||||
- Renamed: PropertyTypes are now LitePropertyTypes (as they belong to the Lite application)
|
||||
- Changed: Peer state constants with PS_* converted into enum "PeerStateValue"
|
||||
- Removed: URL_RT_SERVER, URL_RT_SERVER_DEV, IP_RT_SERVER and IP_RT_SERVER_DEV
|
||||
- Added: PhotonDemoServerUrlPort and PhotonDemoServerIpPort
|
||||
- Renamed: NPeer to PhotonPeer
|
||||
- Renamed: PhotonPeerListener to IPhotonListener (class and file)
|
||||
- Changed: namespace from Com.ExitGames to ExitGames and ExitGames.Client, ExitGames.Client.Photon and ExitGames.Client.Neutron
|
||||
- Removed: QueueOutgoingUnreliableError, QueueOutgoingAcksError, QueueIncomingReliableError, QueueIncomingUneliableError, QueueSentError (no errors, only warnings)
|
||||
- Removed: error "report" when TCP incoming queue getts fuller
|
||||
- Internal: updates Neutron part to run with Protocol.cs de/serialization (added a serializeParametersNeutron() as there are multiple differences to UDP part)
|
||||
- Changed: projects and scripts to build documentation xml in debug builds
|
||||
- Renamed: demo-photon-SL to demo-realtime-SL (according to other demo realtime implementations)
|
||||
- Changed: many classes and properties are now internal. e.g. Protocol, EnetChannel, EnetPeer (and inner classes), TPeer, SuppportClass.ReadInput()
|
||||
- Updated: AssemblyInfo.cs for photon dotnet and silverlight
|
||||
- Internal: projects to have precompile-flags also in release builds
|
||||
- Updated: build scripts for SDK building
|
||||
- Removed: Compact Framework support
|
||||
|
||||
*** Version 5.6.1
|
||||
- Fixed: 0 element arrays caused bugs
|
||||
- Fixed: double type was cast incorrectly after being read
|
||||
|
||||
*** Version 5.6.0
|
||||
- Added: more supported datatypes: float, double and arrays of all basic datatypes (no arrays of hashtable or arrays)
|
||||
- Internal: changed Photon protocol internally to 1.5. (needs a server update to Photon Server SDK 1.6.1+)!
|
||||
- Changed: Channels for Photon UDP are now priorized (from low to high) getting the lower channels out first
|
||||
- Internal: switched de/serialization at several places from manual shifting to a support function, which should provide endian-correctness (Photon Unity PPC compatibility)
|
||||
- Added: Unity info about "Application.runInBackground = true;" to Unity Appendix in doc
|
||||
- Changed: Photon return values are put into a NEW hashtable on receive. not just a cleared one which was not reference-safe (no more need to deep-copy the data of events)
|
||||
- Added: Photon support for "disconnect-reason" which is sent by server in the enet "reserved" byte
|
||||
- Added: Photon ReturnCode.DisconnectByServerUserLimit and .DisconnectByServerLogic
|
||||
- Removed: NPeer.IncomingReliableCommands (was more or less useless)
|
||||
- Added: QueuedIncomingCommands and QueuedOutgoingCommands as metric for how effective send and dispatch is done
|
||||
- Changed: now throwing exceptions when trying to set init-values at runtime (to be fixed at development-time)
|
||||
- Added: doc for sequencing and updated channel doc, (too) short chapter on custom operations, topic "opCodes: byte versus short", doc for property-related functions
|
||||
- Added: overloaded functions for opGetProperties*() for byte-keys
|
||||
- Fixed: Realtime Demo keypress in input-fields have been used as in-game actions, too
|
||||
- Changed: Realtime Demo game-name is now that of the native samples ("play" with other platform SDKs)
|
||||
- Changed: Silverlight SDK has a different port in the constants NPeer.URL_RT_SERVER* and .IP_RT_SERVER* (as Silverlight uses TCP port 4350)
|
||||
|
||||
*** Version 5.4.1
|
||||
- Added: missing documentation in Unity3d SDK
|
||||
|
||||
*** Version 5.4.0
|
||||
- Change: The timespan until a sent and unacknowledged reliable command is considered lost, is now calculated by
|
||||
current roundTripTime + 4 * roundTripTimeVariance
|
||||
The result of this calculation is doubled with every following resend. The maximum number of retries can still be defined by calling SetSentCountAllowance.
|
||||
- Change: Removed TimeAllowanceInt
|
||||
- Change: removed surplus debug out, adjusted levels for other, output of command sent-time from hex to decimal
|
||||
- Added: fragmentation support: bigger data is now placed into multiple packages and reassembled
|
||||
- Internal: command-buffers are replaced with CommandList and SortedCommandList (major change, but fully internal)
|
||||
- Fixed: possibility of command buffer overflow. now everything is stored and warnings are used as hint for temporary problems
|
||||
- Added: property NPeer.IncomingReliableCommands, which returns the count of reliable commands currently queued
|
||||
- Added: callback on NCommand.CT_DISCONNECT to inform the NPeerListener about a disconnect from server (see above)
|
||||
- Added: disconnect command will be sent by server in case of timeout, connection-limitations or other issues
|
||||
- Added: NPeer ReturnCode.DisconnectByServer is called on server-side disconnect (see description)
|
||||
- Added: call to StopConnection() on disconnect (by server)
|
||||
- Added: NPeer.PeerID property to get ENet's peerID (useful while debugging)
|
||||
- Internal: SupportClass.WriteIntToByteArray() to ease writing ints to byte[]
|
||||
- Internal: added several values to NCommand to store fragments
|
||||
- Added: support for channels. read more about this in the documentation
|
||||
- Added: NPeer.ChannelCount which sets the number of channels while not connected (default: 2)
|
||||
- Changed: opRaiseEvent() and opCustom() now optionally have a channel parameter
|
||||
- Added: Photon properties functions to NPeer (available with Photon Server SDK v1.5.0) and doc
|
||||
- Added: LiteEventKey.SetProperties = 92 for broadcasted property set
|
||||
- Added: LiteOpKey.Broadcast = 13 and .Properties = 12
|
||||
- Added: LiteEventKey.TargetActorNr = 10 (actorNr the properties are attached to) and .Properties = 12 (changed properties)
|
||||
|
||||
|
||||
*** Version 5.3.11
|
||||
- Change: all bytes sent to and from server are treated as unsigned bytes (standard for c#). same for byte-arrays
|
||||
- Change: updated realtime demo to use int for posx,posy but still sending just a byte-value (the field is 16x16, after all)
|
||||
|
||||
*** Version 5.3.10
|
||||
- Change: switched from sbyte-array to byte-array in de/serialization! important: bytes (ev-keys etc) are sbyte. arrays of bytes are unsigned (on client and server)
|
||||
- Change: NeutronListener functions getShadowReturn() and HasbadwordsReturn() now have byte-array return values. please adjust, even if you don't use those
|
||||
- Internal: changed SupportClass for Compact Framework
|
||||
- Internal: getting ticks sitched from expensive "System.DateTime.Now.Ticks / 10000" to cheap "Environment.TickCount"
|
||||
- Change: Unity lib will now give more debug out if serialisation fails
|
||||
|
||||
*** Version 5.3.9
|
||||
- Fixed: result-queue, timeouts and customOps work also fine for Unity build again (were broken due to Neutron Unity webplayer compatibility changes in 5.3.8 for Unity)
|
||||
- Fixed: if the browser is closed and the unity webplayer immediatly can't use http anymore, Neutron now informs the application via NetworkStatusReturn()
|
||||
|
||||
*** Version 5.3.8
|
||||
- Fixed: Neutron Unity now also works fine in webplayer -> Neutron and Photon now both support all platforms of Unity und Unity iPhone
|
||||
- Fixed: default value for parameter encrypt of NeutronGame::RaiseEvent() now is false like for all other RaiseEvent methods and like on all other platforms, instead of true, as it was before
|
||||
|
||||
*** Version 5.3.7
|
||||
- Fixed: .Net UDP issue, where standard MTU settings caused dropped UDP packages
|
||||
- Internal: refactored ACK queue to arraylist
|
||||
|
||||
*** Version 5.3.6
|
||||
- Fixed: NPeer issue with ACKs for repeated commands. this enhances handling of lost packages
|
||||
- Changed: NPeer.opJoin() no longer needs the SID
|
||||
|
||||
*** Version 5.3.5
|
||||
- Known issues: to use Photon on iPhone device, you do need Unity iPhone 1.0.2b1 or higher (current official release is 1.0.1, so please ask for a prerelease or wait until next official release), but of course you can use Photon with Unity iPhone 1.0.1 IDE
|
||||
- Merged: renamed .NET 1.1 NeutronUnity3DiPhone into NeutronUnity3D to replace the old .NET 2.0 lib of that name, which means, that you can use the same .NET 1.1 based lib for Unity and for Unity iPhone now, since 1.1 cpmpatibility fixes are all done now
|
||||
- Fixed: photon is fully compatible to .NET 1.1 now
|
||||
- Internal: optimized UDP package size in Unity3D library (was sending surplus bytes, which were ignored)
|
||||
- Fixed: NPeer.opCustom() now sends the operation given by parameter
|
||||
- Changed: IP_RT_SERVER points to new server IP of udp.exitgames.com
|
||||
- Changed: a new NeutronSession now clears the NetworkLoss state and the sendQueue
|
||||
- Changed: timeout of a HTTP request to 10 seconds. it triggers
|
||||
|
||||
*** Version 5.3.4
|
||||
- Added: prealpha Unity3DiPhone version of Neutron .NET: core lib already functional, but realtime part not usable on device yet
|
||||
- Internal: there are 4 different versions of Neutron.NET now:
|
||||
- Full .NET: .NET 2.0 based, with asnyc realtime part
|
||||
- Compact Framework: .NET 2.0 based, with threaded realtime part
|
||||
- Unity3D: .NET 2.0 based, with Unity www-class based http part and threaded realtime part
|
||||
- Unity3DiPhone: .NET 1.1 based, with Unity www-class based http part and threaded realtime part
|
||||
|
||||
*** Version 5.3.3
|
||||
- New: ReturnCode.RC_RT_EXCEPTION_CONNECT, which covers the cases where a server is not running
|
||||
- New: NPeer can now be created with UDP or TCP (by new bool parameter)
|
||||
- Change: renamed most of the constants for NPeer (in INPeerListener structs)
|
||||
- Note: TCP does not offer ServerTime or RoundTripTime jet
|
||||
|
||||
*** Version 5.3.2
|
||||
- Internal: reverted to threaded model in NConnect (as async UDP is not supported by Unity3D)
|
||||
|
||||
*** Version 5.3.1
|
||||
- New: login(), register(), customOperation() and raiseEvent() (all variants) can be encrypted with additional parameter "encrypt" (overloaded function)
|
||||
- New: encryption uses HTTPs as transfer, by changing the "http:" url to a "https:" url
|
||||
- New: returnCode for failure of encrypted HTTPs requests: RC_SSL_AUTHENTICATION_FAILED (if certificate is not found, valid or expired)
|
||||
- Fixed: Realtime Demo using the older Realtime Server
|
||||
|
||||
*** Version 5.3.0
|
||||
- New: separated libraries into "Compact Framework" (CF) and "Regular Framework" (no name postfix)
|
||||
- Change: libraries are now in "libs" folder as debug/release and in libs/CompactFramework debug/release
|
||||
- Change: libs default URL set to EU/Test. use setServerURL() with Neutron.URL_NEUTRON_* for other Neutron instances
|
||||
- Internal: lib now uses async UDP communication now with "regular" framework
|
||||
- Added: properties serverTimeInMilliSeconds, serverTimeAsTimeSpan and serverTimeAsDateTime for getting the current server time
|
||||
- Removed: serverTimeOffset is now internal only and removed from the API (was only needed to calculate the servertime by yourself, before neutron could do this for you)
|
||||
- Change: debug out for realtime classes is now layered
|
||||
- Change: debug level NPeer.DebugOut is now a NPeer.DebugLevel enum and will include all lower levels in output, default: DebugLevel.ERROR
|
||||
- Fixed: size of realtime demo board
|
||||
- Change: NPeer constructor now always throws an exception if listener is null
|
||||
- Change: EventAction() parameter eventCode is now of type sbyte (was int), which corresponds to type of RaiseEvent (and server-side used type)
|
||||
- Internal: NPeer.opRaiseEvent() now treats eventCode as parameter of operation RaiseEvent (as changed in latest RT server)
|
||||
- Change: NPeer has its own listener (INPeerListener) and several (better named) structs for the constants used with NPeer / realtime
|
||||
- Added: LiteOpKey and LiteOpKey.ActorNumber to have a constant for the only OP key of interest
|
||||
- Change: EventAction() always returns the complete event, which contains a code, the ActorNumber (if any given) and data from raiseEvent (see below)
|
||||
- Change: in custom events, the data from opRaiseEvent() is in placed as value of key: LiteEventKey.EV_RT_KEY_DATA. to get the data use: Hashtable data = (Hashtable)neutronEvent[LiteEventKey.EV_RT_KEY_DATA];
|
||||
|
||||
*** Version 5.2.0
|
||||
- changed library filename to neutron-lib_<server>_<billing>.dll with server "test" and "run" (no debug out) and billing "dummy" and "none"
|
||||
- removed US build of library. please use NeutronSession.SetServerUrl() and the constants: Neutron.URL_NEUTRON_SERVER_*.
|
||||
|
||||
*** Version 5.1.0
|
||||
- added realtime classes to DotNet library: ported NPeer (and internal: NCommand and NConnect) classes
|
||||
- added nPeerReturn() to NeutronListener interface
|
||||
- added constants for realtime returnCodes (RC_RT_*): RC_RT_CONNECT, RC_RT_DISCONNECT and RC_RT_EXCEPTION
|
||||
- added constants for realtime eventCodes (EV_RT_*)
|
||||
- added constants for Neutron servers to Neutron class: URL_NEUTRON_*
|
||||
- added Reamtime Demo
|
||||
- updated samples
|
||||
- added test for UDP to NUnit
|
||||
|
||||
*** Version 5.0.1
|
||||
- New: operation Spectate (including new SpectateReturn) to get events from any game (as admin)
|
||||
- New: SetServerUrl and SetCustomServerUrl now return the URL to debugReturn
|
||||
- Internal: constant "DEBUG_- InternalS" to be used for intern debugging output
|
||||
|
||||
*** Version 5.0.0
|
||||
- New: hasBadwords() as OP and return. Server side check of strings for badwords
|
||||
|
||||
*** Version 5.0.0 RC3
|
||||
- Internal: changed constant values: EV_KEY_PROPERTIES = "Data", EV_KEY_REVISION = "Rev"
|
||||
- New: EV_KEY_CHANNELTYPE for channel-type in property-change events
|
||||
- New: constants for default channels, CHANNEL_APPLICATION_LONGLIFE, CHANNEL_ACTOR_SHORTLIFE, CHANNEL_ACTOR_LONGLIFE and CHANNEL_APPINSTANCE
|
||||
- Change: operations that fail due to missing moderation-rights now return RC_MODERATION_DENIED instead of RC_COMMAND_ACCESS_DENIED
|
||||
- Change: actor-properties can no longer be broadcasted in any way - removed "broadcast" parameter from setActorProperties()
|
||||
- Change: properties now have a revision which is increased on each change. this way outdated updates might be skipped
|
||||
- Change: parameters of GetPropertiesReturn(). property-type is replaced by channel. added revision
|
||||
- Change: EV_PROPERTIES_CHANGE now has a key EV_KEY_OWNERNR if it's a "player property" (the key is missing if it's a game-property)
|
||||
- Internal: changed setProperties and getProperties to new operation-codes using different parameters (with similar results)
|
||||
- New: parameter "textMessage" for NeutronGame.invite() adds personal message to invited players (in EV_INV and gameListInvitations())
|
||||
- New: key EV_KEY_INFO will be added to EV_INV if "textMessage" was used in NeutronGame.invite() (it's not there otherwise)
|
||||
- New: gameListInvitations() has new value parameter {t} to get "textMessage" from NeutronGame.invite()
|
||||
- New: RC_APPINSTANCE_NOT_OPEN is now used for "singleton namebased pools" where a game is full (not able to join / instanciate)
|
||||
- New: gameCreate() with invitations will fail if the chosen game-name is already taken in a "singleton namebased pool"
|
||||
- New: RC_APPINSTANCE_ALREADY_EXISTS for the case above
|
||||
|
||||
*** Version 5.0.0 RC2
|
||||
- Change: gameCreateReturn() now returns RC_APPINSTANCE_NOT_OPEN (instead of RC_AI_TOO_MANY_ACTORSESSIONS) for full games in "singleton" pools
|
||||
- Change: obsolete events EV_TURN, EV_TXTMSG and EV_DATA which could be sent by raiseEvent*() and still handled
|
||||
- Change: switched Neutron URLs to "[..].neutron5.[..]" for test/run libs
|
||||
- Fix: Polling (getEvents operation) again calls sendGameDataReturn() for all errors (as intended for v4.9.2 already)
|
||||
- New: constant NeutronListener.EV_KEY_TYPE as part of event EV_BUDDNOTICE
|
||||
|
||||
*** Version 5.0.0 RC1
|
||||
- New: RaiseEvent (all functions of this name) now has a "filter" parameter. If filter is true, all String-typed values in an event are badword filtered
|
||||
- Change: signature of NeutronGame.raiseEvent(), NeutronGame.raiseEventInChannel(), NeutronSession.raiseEventInChannel(), NeutronSession.raiseEventForActor() start with: byte eventCode, Hashtable event, boolean filter
|
||||
- Change: signature of NeutronSession.raiseEventForActor() is changed to "byte eventCode, Hashtable eventData, boolean filter, String userID, int minutesValid, byte maxTypeCount, byte channel"
|
||||
- Change: NeutronGame.doModerate() is now isModerator()
|
||||
- Change: moved GpOperation.SerializeData() and GpOperation.DeserializeData() to Neutron.SerializeData() and Neutron.DeserializeData().
|
||||
- New: errorCode RC_INVALID_TARGET and RC_PARAMETER_NOT_SUPPLIED added as constant.
|
||||
|
||||
*** Version 4.9.3
|
||||
- New: Errors constants in NeutronListener: RC_FATAL_LOGIC, RC_MATCHMAKING_NOT_COMPLETED, RC_CHANNEL_ACCESS_VIOLATION
|
||||
- New: for game-creation you can now reserve "spots", which are not filled up by Neutron matchmaking. players can be invited to fill the spots, or they can be deblocked later on
|
||||
- New: Parameter reservedSpots in NeutronSession.gameCreate()
|
||||
- New: NeutronGame.setReservedSpots() to modify the number of reserved slots (to make them available to matchmaking again, or block/reserve them)
|
||||
- New: event EV_RESERVED_SPOTS will update the NeutronGame.reservedSpots value after a call to NeutronGame.setReservedSpots()
|
||||
- New: NeutronSession.listBannedPlayers() gives you the list of banned players for a known game - only usable by "admin" users
|
||||
- New: NeutronSession.unbanPlayer() is a modified "kick" operation which allows the respective user to join a certain game again - only usable by "admin" users
|
||||
- New: the event invitation includes now the game's name (in the new key EV_KEY_NAME)
|
||||
- New: NeutronSession.gameListPerPool() has now three options to sort the results: by game-name, player-count or "persistent games first"
|
||||
- Removed: NeutronGame: handoverTurn(), sendData(), sendTextMsg(), getEventHistory() and getEventHistoryReturn(). Obsolete events: EV_TURN, EV_TXTMSG, EV_DATA. Session: getScorePosition()+getScorePositionReturn()
|
||||
- Update: release_history.txt was updated from v4.0. All changes up to v4.0.4 are added to v4.9.3
|
||||
|
||||
*** Version 4.9.2
|
||||
- New: Players can be admins (by list of logins on server) or moderator (by being the first active player of a game)
|
||||
- New: Players may request and become moderator for game: NeutronSession.gameCanModerate(boolean), NeutronSession.canModerate, NeutronGame.doModerate() and NeutronGame.moderatorActorNr
|
||||
- Change: the new value NeutronSession.canModerate will be sent with gameCreate() operations (if set to true)
|
||||
- New: Event key NeutronListener.EV_KEY_MODERATOR to get moderator's actorNr from events
|
||||
- Change: EV_QUIT and EV_KICKED now carry the new key EV_KEY_MODERATOR which tells all players who is the current moderator (by actorNr); this is stored into NeutronGame.moderatorActorNr
|
||||
- New: Players in NeutronGame can have new state PLAYER_KICKED (player-data is updated with EV_KICKED)
|
||||
- New: NeutronGame.kickPlayer() (for moderators) and NeutronSession.kickPlayer() (for admin's who are not active in the game to shutdown)
|
||||
- New: NeutronSession.shutdownGame() can be used by admin-players (for others, this operation will fail)
|
||||
- New: Namebased pools can now be defined as "singleton": only one instance per pool and name will be created; if such a game is full players get an error instead of a new game
|
||||
- New: Errors constants in NeutronListener: RC_ACTORSESSION_KICKED, RC_ACTORSESSION_BANNED, RC_APPINSTANCE_CLOSED, RC_ACTORSESSION_ALREADY_JOINED
|
||||
- Change: NeutronGame.raiseEvent() accepts a "targetActorNr" which defines a single player to get the raised event; leave 0 to target "all players in game" (as before)
|
||||
- New: NeutronGame.quitLocally() to release a NeutronGame instance locally (without having to quit()); used after a player was kicked or game shutdown
|
||||
- Update: NeutronGame.playerGetCount() is updated to simply count all active or inactive players (excluding quit and kicked ones)
|
||||
- Internal: NeutronGame constructor reads new parameter: P_MODERATOR
|
||||
- Change: Polling (getEvents operation) now calls sendGameDataReturn() for all errors (not just RC_ACTORSESSION_EXPIRED and RC_ACTORSESSION_NOT_FOUND); takes care of kicked/banned errors
|
||||
- Fix: Fatal server errors cause a returnCode of NeutronListener.RC_OP_SERVER again; debug test-server libs print out debug text! (during development fatal errors could happen in case of not matching client/server setups)
|
||||
- Change: removed (already deprecated) NeutronListener.gameListPerPoolReturn()
|
||||
- Change / Internal: canModerate is sent as Byte (not bool) as in definition; Code: if ( canModerate ) op.addParameter(Neutron.P_MODERATOR , new Byte((byte)1));
|
||||
- Add: NeutronGame.PLAYER_KICKED is now listed in JavaDoc for NeutronGame.playerGetStatus()
|
||||
- Update: JavaDoc package.html, gameCreateReturn(), gamesListReturn(), EV_DEACTIVATE, kickPlayer(), quitLocally(), RC_ACTORSESSION_KICKED, RC_ACTORSESSION_BANNED, RC_APPINSTANCE_CLOSED, RC_ACTORSESSION_ALREADY_JOINED
|
||||
- Added: Event EV_STATUS (50) includes a key EV_KEY_ISADMIN if the current player has administrator rights; the value is (byte)1 in that case. The key does not exist in any other case (normal users)
|
||||
- Update: JavaDoc gameCreateReturn;
|
||||
- New: Added constant RC_APPINSTANCE_NOT_FOUND = 137 for shutdownGameReturn()
|
||||
- Fix: serializable datatypes are now completely listed in NeutronSession JavaDoc
|
||||
- New: Constant for property-change events: EV_PROPERTIES_CHANGE including new keys: EV_KEY_PROPERTY_TYPE, EV_KEY_PROPERTIES, EV_KEY_ISDIFF
|
||||
- Update: JavaDoc for properties in NeutronSession
|
||||
|
||||
*** Version 4.1.1
|
||||
- Fix: gameListPerPool() defaults to 10 games and no offset if the values are less than 1
|
||||
- Fix: gamesListReturn() JavaDoc description for "listType" is now: 0 = open games; 1 = invitations; 2 = pool's open games list
|
||||
- Update: gameListPerPool() sends "{gn}" as values-parameter if it's null
|
||||
- Update: getPropertiesReturn() gets new parameters: actorNr, userID. These are optional and are available in certain situations only. See JavaDoc
|
||||
- Update: gameListPerPoolReturn() is now deprecated and merged into gamesListReturn() which in turn got a "type" to identify the list-type
|
||||
- New: getListBuddyIgnore() got one more value: 't'. This requests the type of relation to users. useful when getting lists of type "both". this is buddies and ignores.
|
||||
- Change: renamed returned parameters to: count and countOnline. These values are referring to the number in the returned list
|
||||
- Internal: parameter P_USERID = 85; used in getProperties
|
||||
- New: made methods nullpointer resistant: getListBuddyIgnore, buddySet, get/set PlayerProperties, get/set ActorProperties, get/set GameProperties; some methods throw exceptions in debug version
|
||||
|
||||
*** Version 4.1.0
|
||||
- New: Properties. NeutronSession: setActorProperties(), getActorProperties(). NeutronGame: setLocalPlayerProperties(), getPlayerProperties(), getGameProperties(), setGameProperties()
|
||||
- New: Buddylist and Ignorelist in NeutronSession: listBuddies(), listIgnored(), getListBuddyIgnore(), buddySet()
|
||||
- New: Listing of games per pool in NeutronSession: NeutronSession gameListPerPool()
|
||||
- New: Games with password (only usable for named games)
|
||||
- Internal: Changed parameter in buddySet from P_STATUS to P_TYPE
|
||||
|
||||
*** Version 4.0.4
|
||||
- Change: NeutronGame.handoverTurn() and NeutronGame.sendData() are now getting a Hashtable parameter instead of Object
|
||||
- New: RC_ACTORSESSION_BUSY (121) constant to help identify common development error! check in gameCreateReturn()
|
||||
|
||||
*** Version 4.0.3
|
||||
- New: RC_INVALID_CONNECTIONSTRING (74) constant to help identify a common error! check in loginReturn()
|
||||
- Update: list of serializable datatypes in NeutronSession JavaDoc
|
||||
- Fix: Fatal server errors cause a returnCode of NeutronListener.RC_OP_SERVER again; debug test-server libs print out debug text! (during development fatal errors could happen in case of not matching client/server setups)
|
||||
|
||||
*** Version 4.0.2
|
||||
- Internal: Neutron.deserializeData() now returns either the P_DATA part of the deserialized data (if available / serialized by serializeData()) or the resulting hashtable itself
|
||||
|
||||
*** Version 4.0.1
|
||||
- New: NConnectSE connects to server defined by parameter: ipPort (before: fixed host)
|
||||
- New: SE version is now completely independent from Java ME classes (were not used, but had to be present)
|
||||
- Fix: Changed versioning for "ClientLibVersion" in Login/CC
|
||||
*** Version 4.0.0.0
|
||||
|
||||
- Removed methods:
|
||||
- NeutronSession.BuggyGetList - replaced by new GetListBuddyIgnore method;
|
||||
- NeutronSession.ReSubscribe;
|
||||
- NeutrinSession.ConfirmBilling;
|
||||
- NeutronListener.ResubscribeReturn;
|
||||
|
||||
- Added methods:
|
||||
- NeutronSession.GameCreateNamed with password parameter;
|
||||
- NeutronSession.GameListPerPool;
|
||||
- NeutronSession.GetActorProperties;
|
||||
- NeutronSession.SetActorProperties;
|
||||
- NeutronSession.GetListBuddyIgnore - replaces removed BuggyGetList;
|
||||
- NeutronSession.ListBuddies;
|
||||
- NeutronSession.ListIgnore;
|
||||
- NeutronSession.BillingInitPayment;
|
||||
- NeutronSession.BillingProcessPayment;
|
||||
- NeutronGame.Invite;
|
||||
- NeutronGame.GetGameProperties;
|
||||
- NeutronGame.SetGameProperties;
|
||||
- NeutronGame.GetPlayerProperties;
|
||||
- NeutronGame.SetLocatPlayerProperties;
|
||||
- NeutronListener.GameInviteReturn;
|
||||
- NeutronListener.GetPropertiesReturn;
|
||||
- NeutronListener.SetPropertiesReturn;
|
||||
|
||||
- Changed argument list:
|
||||
- NeutronSession.GameCreate - added password parameter;
|
||||
- NeutronListener.GamesListReturn added listType parameter;
|
||||
- NeutronListener.BuddyGetListReturn all buddy related info now in passing in one strings array parrameter;
|
||||
- NeutronListener.BuddySetReturn added type parameter;
|
||||
- NeutronListener.BillingInitPaymentReturn;
|
||||
|
||||
|
||||
- added constants:
|
||||
- OPC_INVITE
|
||||
- OPC_TELLAFRIEND
|
||||
- OPC_LISTGAMES
|
||||
- OPC_SETPROPERTIES
|
||||
- OPC_GETPROPERTIES
|
||||
- P_USERID
|
||||
- P_RESERVE
|
||||
- P_RESULT
|
||||
- P_PROPERTIES
|
||||
- P_BROADCAST
|
||||
- P_ISDIFF
|
||||
- RCB_CHARGING_ERROR
|
||||
- RCB_POST_CHARGING_ERROR
|
||||
- RCB_TIMEOUT
|
||||
- RCB_PRICE_- Changed
|
||||
- RCB_PRICE_INVALID
|
||||
- RCB_FATAL_SERVER_ERROR
|
||||
- RCB_FATAL_LOGIC_ERROR
|
||||
- RCB_NOT_INCLUDED
|
||||
- RCB_WMA_UNAVAILABLE
|
||||
|
||||
*** Version 3.0.2.2
|
||||
- CLS-specifications largely corrected
|
||||
|
||||
*** Version 3.0.1.1
|
||||
- changes in neutron-java-lib integrated
|
||||
|
||||
***
|
||||
- Removed: NeutronGame: playerNames, playerIDs, playerLobbies, playerStats
|
||||
- Change: removed GpOperation.roundtripTime, now using public Neutron.roundtripTime
|
||||
to be sent in operation headers (GpOperation.serializeParameters(), internal)
|
||||
- Change: channelRaiseEvent() is now raiseEventInChannel() and gets the eventCode
|
||||
as seperate parameter value - analog to raiseEventForActor()
|
||||
- Fix: renamed EV_KEY_M_MIPLAYERS to EV_KEY_M_MINPLAYERS (number of min players of game, before start)
|
||||
- Fix: values for EV_KEY_M_MINPLAYERS and EV_KEY_M_MAXPLAYERS corrected (wrong case so far)
|
||||
- Changed: Neutron.millisecondsToWait (current value of polling-interval) is now
|
||||
set in Neutron.receiveResponse() for login, register and alike
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f1672d52d7463df4fa7b3e54a25594d4
|
||||
TextScriptImporter:
|
||||
userData:
|
||||
@@ -0,0 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e3d7998d9d5bb0148b9ff0ee8572c369
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
userData:
|
||||
BIN
Binary file not shown.
+4
@@ -0,0 +1,4 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 574fe5a43da17e04898f591478a39a66
|
||||
NativeFormatImporter:
|
||||
userData:
|
||||
@@ -0,0 +1,234 @@
|
||||
v1.17 (27. September 2012)
|
||||
Note: this version has breaking changes! don't try to use it with clients with older PUN versions
|
||||
Updated: PUN version string to "1.17"
|
||||
Updated: client library (the dll) to v3.0.1.14. This fixes an exception and adds some better iOS 5 udp-socket fixes (see release_history.txt)
|
||||
Fixed: Player list checking when client joins. The client now first checks the local player-list with the list from server. Then calls OnJoinedRoom. (was: the other way round)
|
||||
Fixed: observing a rigidbody via a PhotonView was bugged (velocity and angular velocity were mixed up)
|
||||
Changed: PhotonNetwork.SetLevelPrefix() is now short typed. It practically never happens that you have more than 32k levels (and short saves a bit of traffic)
|
||||
Changed: Reliable delta compression now uses a different format and is a bit leaner
|
||||
Changed: The data you produce in OnPhotonSerialize is sent is now sent completely and uncompressed, if the length of it changes to previous sends. If length doesn't change, we assume the data content and order is same as last time
|
||||
Internal: OnPhotonSerialize data is trasported in a hashtable in: key 1 original, 2 compressed, 3 list of "true" null values (when using compression)
|
||||
Internal: Instead of overriding compressed data[] into Hashtable key 1, this now uses key 2 (and removes key 1). this makes it easy to decide if anything was compressed at all
|
||||
Internal: PhotonView.lastOnSerializeDataSent and .lastOnSerializeDataReceived are now object[]
|
||||
Internal: OnSerializeWrite now uses an int-array to send view ID, timestamp and level-prefix
|
||||
Added: output for ping + variance to PhotonStatsGui (in health values)
|
||||
Added: Event / callback method OnPhotonMaxCccuReached. This is called when the CCU limit for your title is reached (this means: either a Cloud subscription limit or a Photon Server license limit is reached)
|
||||
Changed: OnPhotonMaxCccuReached might be called after authentication. When it was called, PUN will automatically disconnect. The player might re-try later on.
|
||||
|
||||
|
||||
v1.16.2 (3. August 2012)
|
||||
Fixed: version 1.16 didn't compile for non-Editor environments because the ServerSettings used EditorClasses but is needed at runtime
|
||||
Internal: In SendMonoMessage, replaced List<T> with HashSet<T> which has a constant lookup time for .contains
|
||||
Changed: Some foreach into for loops
|
||||
|
||||
v1.16 (3. August 2012)
|
||||
Updated: To being a Unity 3.5.3 package
|
||||
Updated: To Unity 4 compatibility
|
||||
Fixed: In-room player list didn't include players who didn't set any properties (no name and no custom properties)
|
||||
Fixed: PhotonViewInspector now displays owner as null if not set, instead of showing the PV as sceneView
|
||||
Updated: To new client lib. This is now thread safe, which means that a thread could call SendOutgoingCommands in intervals, as fallback when Update() is paused for too long
|
||||
Updated: Usage of the lib's NetworkSimulationSettings property (this is an internal change)
|
||||
Updated: Some links in the Setup Wizard window became outdated and are now fixed
|
||||
Updated: InstantiateSceneObject to use FindObjectsOfType less often, which improves performance
|
||||
Changed: Methods that are intended for PUN-internal use are now becoming internal or private instead of public. Public methods and classes are the ones really meant for game development
|
||||
Internal: RemoveAllInstantiatedObjects now also (re)sets the cacheInstantiationCount to 0
|
||||
Internal: Updated to new account service
|
||||
Internal: PhotonEditor was modified to be extended and customized. Saves if the setup wizard did open at least once. Also gets less updates.
|
||||
Added: JoinRandomRoom overload to use expectedCustomProperties. These can filter which properies a room must match to join it randomly.
|
||||
Changed: Documentation to be generated from code and topic files. This provides a complete reference documentation. The pdf is still the best option for a single-file document.
|
||||
Changed: Documentation was extended. "Timing for RPCs and Loading Levels" and the topics about the GUI elements available is new.
|
||||
Updated: The optional GUIs are now draggable windows and a bit cleaned up
|
||||
Changed: ServerSettings class has another value that needs serialization (maybe this means your serverSettings will have to be re-written after update).
|
||||
Updated: PUN version string to "1.16"
|
||||
|
||||
v1.15 (11. June 2012)
|
||||
Fixed: PhotonMessageInfo.timestamp. The conversion of the sent ms-timestamp to a second-based timestamp double value was imprecise
|
||||
Fixed: Room-filtering for join random room did not work, cause a parameter code was wrong. Now, filtering works as expected.
|
||||
Changed: The Marco Polo Tutorial is no longer packaged but in a sub-folder of PUN. The scene/project for this is complete but in best case, you still work through the tutorial pdf.
|
||||
Added: short paragraph about the tutorial-result being in the PUN package to tutorial text
|
||||
Changed: OnFailedToConnectToPhoton is now called when the connection could not be established, OnConnectionFail is called when a established connection fails. The difference between both is sometimes minimal. In either case, OnDisconnectedFromPhoton is called afterwards, too.
|
||||
Changed: description of PhotonNetworkingMessage.OnDisconnectedFromPhoton, PhotonNetworkingMessage.OnConnectionFail and PhotonNetworkingMessage.OnFailedToConnectToPhoton according to above's changes
|
||||
Added: Warnings to log console when connections fail (showing the current address and a hint what might be wrong)
|
||||
Changed: If a script doesn't write any data to the stream in OnPhotonSerializeView(), then this view's update is not sent. This allows you to skip updates from within your own logic. Simply don't fill anything into the stream.
|
||||
Changed: Only when DeltaCompression is active, copies of sent and received data are cached. You can't change a PhotonView's synchronization method on the fly (that didn't work before, either).
|
||||
Fixed: MarcoPolo-Tutorial: audio was missing
|
||||
Updated: PUN version string to "1.15"
|
||||
Updated: to latest client lib v3.0.1.11 (some fixes from previous builds)
|
||||
|
||||
v1.14 (08. May 2012)
|
||||
Fixed: OnSerializePhotonView is always ONLY called when at least one other player is connected. This is by design. What has changed is that offlineMode will now also no longer run OnSerializePhotonView.
|
||||
Fixed: Duplicate IDs when duplicating Scene PhotonViews (they are now updated correctly).
|
||||
Improved: When connected to the lobby, countOfRooms is based on the room list length for improved update rate.
|
||||
Fixed: When the connection 'breaks', via a disconnect call the network state will be reset properly. This mainly fixes the behaviour of iOS apps going to the background (which drops the connection).
|
||||
Fixed: Bug which kept authorize from being encrypted. Authorize encryption is now enabled by default. The AppId is now only sent in the op authorize (v1.14.2)
|
||||
Updated: PhotonStatsGui. This simple component can be attached to gameobjects and shown with shift+tab. It now shows gaps in send- and dispatch-intervals. If those go beyond a few milliseconds, the game FPS obviously stutters which might cause connection issues.
|
||||
Updated: doc for ActorProperties, ErrorCode, GameProprties, EventCode, ParameterCode, OperationCode.
|
||||
Updated: Internally used client library to latest release v3.0.1.6
|
||||
Updated: PUN version string to "1.14"
|
||||
Internal only:
|
||||
Renamed: OpCreateGame is now OpCreateRoom, OpJoin -> OpJoinRoom, OpJoinRandom->OpJoinRandomRoom OpSetPropertyOfGame -> OpSetPropertyOfRoom
|
||||
Renamed: ParameterCode.ActorProperties -> ParameterCode.PlayerProperties
|
||||
Renamed: ParameterCode.GameId -> ParameterCode.RoomName
|
||||
|
||||
v1.12 (18. April 2012)
|
||||
Fixed: playerList and otherPlayerList are now updated when the local player's id changes. In 1.10, this caused issues when leaving a room
|
||||
Fixed: Extension method for Hashtable StripKeysWithNullValues(), used to remove properties set to null
|
||||
Fixed: Custom properties which are set to null, are now synced and removed everywhere
|
||||
Added: PhotonNetwork.SetPlayerCustomProperties to make actor properties more comfortable
|
||||
|
||||
v1.10 (16. April 2012)
|
||||
Added: Info on how to activate Photon Cloud Subscriptions that are bought through the Assset Store (this currently requires a mail by you). See readme.txt
|
||||
Fixed: OnLeftLobby is now called as expected
|
||||
Fixed: OnLeftRoom is now called as expected (also on disconnect from game server)
|
||||
Fixed: OnSerialize issue with null as object
|
||||
Fixed: PhotonNetwork.time now keeps it's precision even with high values for ServerTimestamp (fixed it's casting). This will update every ~15ms by default.
|
||||
Changed: playerList and otherPlayerList now return Player[] instead of List<Player> (simpler conversion)
|
||||
Changed: Optimized playerList and otherPlayerList. They are now cached and only created when some player is added or removed
|
||||
Added: PhotonNetwork.insideLobby
|
||||
Added: Comments for enum PeerState
|
||||
Added: In PhotonServerSettings you can now chose Offline mode
|
||||
Removed: PhotonNetwork.Instantiate(GameObject go, ...) variant. Use a resource name instead (folders work).
|
||||
Removed: PhotonNetwork.Destroy(int). Use PhotonNetwork.Destroy(PhotonView) instead.
|
||||
Added: Vital Network Statistics. These will help analyze issues with client-to-server communication by provinding (limited) insight in the client's timing. See below.
|
||||
Added: PhotonNetwork.NetworkStatisticsEnabled, .NetworkStatisticsReset and .NetworkStatisticsToString to control and get the vital stats.
|
||||
Fixed: OnFailedToConnectToPhoton() is no longer called for any connection loss but only while the connection is being established. Note: OnDisconnectedFromPhoton is called, too, to let you know when the connection is closed.
|
||||
Added: enum DisconnectCause for OnFailedToConnectToPhoton and OnConnectionFail
|
||||
Added: new callback/MonoEvent OnConnectionFail. This provides a DisconnectCause that hints at the cause for a connection loss. Note: OnDisconnectedFromPhoton is called, too, to let you know when the connection is closed.
|
||||
Added: Wizard now has a button to bring you to the Photon Cloud's Dashboard page (login)
|
||||
Fixed: An issue where Unity recompile (any file) caused the PhotonServerSettings to be wiped if the Wizard was open
|
||||
Updated: documentation JoinGame -> JoinRoom
|
||||
Updated: client library to a intermediate version (not yet released but improved with new features): v3.0.1.305
|
||||
Updated: to client lib v3.0.1.3 and added related release_history.txt
|
||||
Fixed: removed 3.5+ compile warnings about PrefabUtility
|
||||
|
||||
v 1.9.6 (20 March 2012)
|
||||
New: PhotonNetwork.InstantiateSceneObject to spawn scene based objects that persist even if the current master client drops (usefull for AI etc.)
|
||||
Workaround: calling LeaveRoom in Disconnect to prevent a rare bug where players get stuck in room while being disconnected.
|
||||
Improved: offline mode will now also fire OnJoinedRoom after calling CreateRoom
|
||||
Fixed: No null playerName when using offline mode
|
||||
Fixed: MC and ID's not set correctly after switching from offline mode to online
|
||||
|
||||
v1.9.5 (05 March 2012)
|
||||
New: Delta compression has been added to the observe option of reliable PhotonViews. This greatly reduces the network bandwidth.
|
||||
Fixed: OnLeftRoom error.
|
||||
Fixed: Stats timer didn't reset
|
||||
Moved: OnPhotonSerializeView and OnPhotonInstantiate to enums.cs (PhotonNetworkingMessages)
|
||||
|
||||
v1.9 (27 February 2012)
|
||||
Fixed: Bugfix for cleanup after a player left. (bug introduced in 1.8)
|
||||
Fixed: PUN viewID assignment after conversion from Unity Networking
|
||||
Added: More checks to validate PhotonViews (PhotonViewIDs are stripped from Prefabs but GOs in the Hierarchy must have one).
|
||||
Removed: Removed TODO's from PhotonNetwork and made Destroy behaviour more consistent: Players can only destroy objects that they own, the master client can destroy everyones objects.
|
||||
Changed: PhotonNetwork.Instantiate now requires a PhotonView at the root of a prefab
|
||||
Changed: PhotonNetwork.Destroy(GameObject go) required the gameobject to be created via PhotonNetwork.Instantiate
|
||||
Added: Summary and Example for each of the PhotonNetworkingMessage values (each names a "callback" method used by PUN)
|
||||
Added: PhotonNetwork.Instantiate overloads which take a prefab's Name to instantiate. You no longer need to pass a GameObject for a asset that's in the Resouces anyways.
|
||||
Changed: PhotonNetwork.GetRoomList() now returns RoomInfo[] instead of a Room[]. Simply change the type! RoomInfo a different class but behaves like the rooms did.
|
||||
Added: RoomInfo class, as base for Room. The RoomInfo is what you get in room listing: PhotonNetwork.GetRoomList() and you can't modify RoomInfo (you're not yet in those rooms)
|
||||
Added: Room.SetCustomProperties() and PhotonPlayer.SetCustomProperties() to add/update custom properties to players or rooms. The key of those must be string! You can't currently delete customProperties from the server (but set them null). This is likely to change.
|
||||
Added: Room.customProperties and PhotonPlayer.customProperties as getter for the custom properties you set. These sync once set.
|
||||
Changed: Custom room properties are no longer automatically listed in the lobby! see CreateRoom() note below.
|
||||
Added: CreateRoom() overload that takes string[] propsToListInLobby as last parameter. This defines which custom properties of your room get into the lobby. By default no other props get listed. So if you want to set "map" and have that in the lobby, apply it by CreateRoom().
|
||||
Added: Check if values are changed more than a minimum before they are sent. Floating point precision for positions and rotations cause many updates and messages, so these thresholds help skip updates that are too tiny to notice. See note below.
|
||||
Added: PhotonNetwork precisionForVectorSynchronization, precisionForQuaternionSynchronization, precisionForFloatSynchronization properties.
|
||||
Added: Option to not join the lobby and respective callback. Use PhotonNetwork.autoJoinLobby to set and implement OnConnectedToMaster() instead of OnJoinedLobby(). You can join random games, create or join named games just fine, without the lobby.
|
||||
Changed: PhotonNetwork.autoCleanUpPlayerObjects is now done by server and can be set per room. In a room, all clients adhere to the room's setting (as set when the first player calls create). This should solve some rare issues due to racing conditions. The Master is not doing extra work anymore for this.
|
||||
Added: Room.autoCleanUp. This property tells each client if the room actually cleans up buffers for players that leave. Set when the room is created to the then current value of PhotonNetwork.autoCleanUpPlayerObjects.
|
||||
Changed: PhotonNetwork.autoCleanUpPlayerObjects fires an error when changed while in a room
|
||||
Fixed: isMasterClient and PhotonNetwork.masterClient for some rare conditions.
|
||||
Fixed: PhotonPlayer.ToString() returned null, if no name was set. This now returns "".
|
||||
Added: PhotonNetwork.unreliableCommandsLimit which could be used to fine tune how many of the most recent unreliable messages should be dispatched while the rest is skipped. This has a useful default, so you don't really have to care.
|
||||
Added: Initial version of PhotonStatsGui script, which shows messages total and for a interval. This is giving a first impression of the message-usage of your games. This will be extended.
|
||||
Added: Profiler samples to SendOutgoingCommands and DispatchIncomingCommands. These tell you how often they run (in some frames only) and how long.
|
||||
Changed: Internally, SendOutgoingCommands() is now called as long as there are outgoing commands queued. This will produce UDP packets when absolutely needed but stabilizes the connection, especially when joining games and getting a lot of messages.
|
||||
Changed: The connectionStateDetailed is now changed before PUN calls your OnFailedToConnectToPhoton(), so you could re-connect from inside of that method.
|
||||
Updated: To Photon Unity3d client lib v3.0.1.1
|
||||
|
||||
|
||||
v1.8 (25 January 2012)
|
||||
Added: changelog tp PUN package
|
||||
Fixed: a bug that occured when calling a PhotonNetwork.Instantiate in the same frame after calling a PhotonNetwork.Destroy.
|
||||
Changed: InitializeSecurity made obselete. requestSecurity is now true per default, this will encrypt authenticate(the APPID etc.) All normal messages (RPC etc) are NOT encrypted ATM.
|
||||
Removed: instances of GAME to ROOM inside PhotonNetwork.(Please mind isNonMasterClientInGame' -> 'isNonMasterClientInRoom')
|
||||
Added: new statistic: PN.countOfPlayersInRooms
|
||||
Changed: OnPhotonPlayerDisconnected is now called AFTER possible MasterClient switch
|
||||
Changed: OnPhotonPlayerDisconnected is now called AFTER the playerList (and playercount) has been updated: The player is first removed from the playerlist.
|
||||
Changed: OnPhotonRandomJoinFailed is now properly called after RandomJoin failed because an empty room was accidently joined. Previously OnPhotonJoinRoomFailed would be called instead.
|
||||
Changed: PhotonNetwork won't generate a player name. Instead the Worker Demo does this when no name was applied yet. (player names are synced automatically when set)
|
||||
|
||||
v1.7:
|
||||
Changed: renamed "Room" to "Game" in event/callback methods for OnPhotonCreateGameFailed and OnPhotonJoinGameFailed. This is important to adjust!
|
||||
Changed: PhotonViews are now usable via Awake() on any script (previously they were setup between Awake and Start)
|
||||
Fixed: No more broken connection if Join/Create/JoinRandom/LeaveRoom is called during connection or disconnection: an error is logged instead.
|
||||
Changes: cacheInstantiationCount is ONLY reset in LeftRoomCleanup() if autoCleanUpPlayerObjects is true
|
||||
Fixed: cacheInstantiationCount is now caompared to ushort.MaxValue (with u in ushort)
|
||||
Added: New GameVersion argument to Connect*, plus new PUN version. These version strings make sure only clients that use the exact same game version AND PUN version will be able to play together.
|
||||
Added: Information about versioning in documentation
|
||||
Changed: Unregisters allocated viewIDs after PhotonNetwork.Destroy*
|
||||
Fixed: Compatibility with Unity 3.5 (excluding Flash export for the time being)
|
||||
Changed: Destroy was sent twice for views in some cases. Cleaned up. As this was no real bug, this is no fix.
|
||||
Updated: to new client lib (v3.0.0.9)
|
||||
Fixed: Relatively rare encryption issue which led to a disconnect.
|
||||
|
||||
v1.6:
|
||||
Updated: Client library to v3.0.0.8 which brings important fixes and some Unity-targeted performance optimizations
|
||||
Changed: Default update rate is 10/second now, which is a better standard (send-rate stays at 20/second)
|
||||
Changed: During disconnect, operation responses are now ignored. Example: Join a random game, then disconnect before entering the room. This now disconnects you (instead of getting you in the room).
|
||||
Changed: Internals how the PhotonStream works. This is now leaner and faster and is the first step to optimized syncing
|
||||
Note: This is incompatible with previous PUN versions. Don't run separate PUN versions in one game
|
||||
|
||||
v1.5:
|
||||
Fixed: Background thread now starts when message queue is paused (for loading something, by setting isMessageQueueRunning to false)
|
||||
Fixed: Destroy(gameObject) now removes the instantiate from the server's cache
|
||||
Fixed: Some of the Log output was not included in "more verbose" log levels
|
||||
Updated: Client library to that of Photon Unity SDK v3.0.0.7 which uses less memory and gives you some performance if your game causes a lot of traffic
|
||||
Removed: some obsolete values
|
||||
Added: LoadbalancingPeer class and moved aroud some other classes. The goal is to extract some classes for general use in DotNet (without Unity, if needed)
|
||||
Note: If you want to host your own Photon server please update to Photon 3 SDK RC7 (it has some memory fixes, too)
|
||||
Note: Destroy() for views is not yet working for players who join late into existing games. This is not a buffered action. We're on it.
|
||||
|
||||
v1.4.1:
|
||||
Re-Submit same package to asset store.
|
||||
|
||||
v1.4:
|
||||
Fixed: Caching of RPCs and Instantiates. This is a major fix, affecting all situations where players join a room where RPCs and Instantiations were done previously. This fix is "hidden" by the API, so no code changes are necessary in a game.
|
||||
Changed: The new cache is no longer cleaned by the server if someone leaves. The "MasterClient" will delete another user's RPCs and Instantiations, when someone leaves (unless auto cleanup is turned off).
|
||||
Changed: Internals of RPCs and Instantiates. Their events are streamlined and contain only data that's not a default value. This is incompatible with v1.3 clients.
|
||||
Fixed: Position and rotation synchronization is now done local to the object. This helps with positions relative to ancestor objects.
|
||||
Fixed: PhotonNetwork.Destroy().
|
||||
Improved: If you disable the message queue (while loading levels), a thread will keep the connection alive. Timeouts are less frequent this way. Use isMessageQueueRunning.
|
||||
Improved: The framework now discards older incoming unreliable updates. By default, everything past the newest 20 unreliable updates (like pos syncs) gets skipped. Reliable data is not affected.
|
||||
Changed: RPC calls now can be called without any parameters (null), too.
|
||||
Added: PhotonNetwork.SendOutgoingCommands() which is useful to send RPCs before the client will load (and suspend sending) for a while.
|
||||
Updated: To new Photon client library v3.0.0.6.
|
||||
|
||||
v1.3:
|
||||
Changed: MasterClient handover: When leaveing a room, the MasterClient becomes null. It only is available inside a room.
|
||||
Changed: PhotonNetwork.time is now a double with millisecond precision and always positive. It's 0 at server-start and goes up to ~4294967, where it will overflow to 0 again. This happens every ~49 days.
|
||||
Fixed: A call to Disconnect() while not being connected set a state that made it impossible to Connect() later on.
|
||||
Changed: Connect() is only possible when disconnected. Disconnect() is only allowed when the client is connected.
|
||||
Added: enum PhotonNetworkingMessage now contains all method names that could be called by our framework (in no particular order). Check it's description.
|
||||
Changed: A few internals to improve performance and reduce object creation (and save some GC calls). Example: SendMonoMessage().
|
||||
Updated: client library is now from Photon Unity SDK v3.0.0.5
|
||||
Changed: PhotonNetwork will now limit incoming unreliable messages to 20 instead of dispatching everything. This can cause gaps in updates but lets a client catch up much faster after loading a level (which pauses dispatching of incoming events).
|
||||
Fixed: Converter will now make JS scripts extend Photon.MonoBehaviour after conversion.
|
||||
Updated: PhotonView and inspector to also handle scene views on disabled objects. Before, these could collide easily. Please give feedback, if PhotonViews cause errors.
|
||||
|
||||
v1.2:
|
||||
Fixed: DemoWorker, random double spawn bug fixed. Loading the same scene and scripts caused initialization errors
|
||||
Fixed: LevelPrefix bug for newly spawned PhotonViews (after setting the prefix)
|
||||
Fixed: OnDestroy message
|
||||
Fixed: Suppressed error messages when setting a name when not connected.
|
||||
Fixed: Master client handover fixed
|
||||
Fixed: SetSendingEnabled() and SetReceivingEnabled() which was doing the opposite of what you expected.
|
||||
Added: CreateRoom now has parameters for: maxplayers, visible and open
|
||||
Added: Room.maxPlayers, .open and .visible will now be synced and affect the lobby
|
||||
Added: PhotonView OnSerialize now only runs on scripts on active gameobjects
|
||||
Added: PhotonVIew.isMine also returns true on scene objects for the masterclient
|
||||
Added: Server setup wizard, which offers instant access to a cloud account
|
||||
Added: Server settings file
|
||||
|
||||
v1.1:
|
||||
Fixed: Server "Access Denied" issue on start on XP machines.
|
||||
Fixed: observing classes that inherit Monobehaviour, but not directly.
|
||||
Fixed: scene view ID errors when using prefabs (APPLY from scene to project)
|
||||
@@ -0,0 +1,4 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 450bddb39a95688498d5eed8bb939b0b
|
||||
TextScriptImporter:
|
||||
userData:
|
||||
@@ -0,0 +1,65 @@
|
||||
|
||||
Photon Unity Networking
|
||||
This package is a re-implementation of Unity's Networking, using the Photon Cloud Service.
|
||||
Also included: a setup wizard, demo scene, documentation and editor extensions.
|
||||
|
||||
|
||||
Integration
|
||||
This package adds a editor window:
|
||||
Menu -> Windows, Photon Unity Networking
|
||||
|
||||
|
||||
Importing into your project
|
||||
To import this package into your project, skip the folders "Demo Worker" and "MarcoPolo-Tutorial".
|
||||
You can also delete them after import.
|
||||
Everything important is in the folders "Plugins" and "Editor".
|
||||
|
||||
|
||||
Server
|
||||
Exit Games Photon can be run on your servers or you can subscribe to our cloud service.
|
||||
|
||||
The window "Photon Unity Networking" will help you setup a Photon Cloud account.
|
||||
This service is geared towards room-based games and the server cannot be modified.
|
||||
Read more about it: http://www.exitgamescloud.com
|
||||
|
||||
Alternatively, you can download the server SDK and run your own Photon server.
|
||||
The SDK comes with a complete game logic (ready to run, like in Photon Cloud)
|
||||
but you also get the source code for the game logic to modify and extend it.
|
||||
A 100 concurrent user license is free (also for commercial use) per game.
|
||||
Read more about it: http://www.exitgames.com/photon
|
||||
|
||||
|
||||
Subscriptions bought in Asset Store
|
||||
Follow these steps, if you bought a package with Photon Cloud Subscription in the Asset Store:
|
||||
|
||||
• Register a Photon Cloud Account: cloud.exitgames.com
|
||||
• Get your AppID from the Dashboard
|
||||
• Send a Mail to: developer@exitgames.com
|
||||
With:
|
||||
o Your Name and Company (if applicable)
|
||||
o Invoice/Purchase ID from the Asset Store
|
||||
o Photon Cloud AppID
|
||||
|
||||
|
||||
Files
|
||||
The files of the Photon Unity Networking package are:
|
||||
|
||||
Documentation
|
||||
PhotonNetwork-Documentation.pdf
|
||||
Extensions & Source
|
||||
Editor\PhotonNetwork\*.*
|
||||
Plugins\PhotonNetwork\*.*
|
||||
|
||||
Demo Scene
|
||||
DemoWorker\DemoWorker-Scene.unity
|
||||
Tutorial "Marco Polo"
|
||||
MarcoPolo-Tutorial\
|
||||
|
||||
The server-setup will be saved as file (when the Wizard was running)
|
||||
Resources\PhotonServerSettings.asset
|
||||
|
||||
|
||||
Help and more
|
||||
Please read the included pdf.
|
||||
Exit Games Forum: http://forum.exitgames.com/viewforum.php?f=17
|
||||
Online documentation: http://doc.exitgames.com/photon-cloud
|
||||
@@ -0,0 +1,4 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d90864ccbf99d4a449c87472b0a181e8
|
||||
TextScriptImporter:
|
||||
userData:
|
||||
Reference in New Issue
Block a user