/// <summary> /// Set the mesh from the specified DataNode. /// </summary> static public Mesh DeserializeMesh(this DataNode node) { Mesh mesh = null; int id = node.Get <int>(); if (id != 0 && mCachedMeshes.TryGetValue(id, out mesh) && mesh != null) { return(mesh); } string name = node.GetChild <string>("name"); string path = node.GetChild <string>("path"); if (id == 0) { id = (path + name).GetHashCode(); if (mCachedMeshes.TryGetValue(id, out mesh) && mesh != null) { return(mesh); } } if (!string.IsNullOrEmpty(path)) { mesh = UnityTools.Load <Mesh>(path, name); #if UNITY_EDITOR if (mesh == null) { Debug.LogWarning("Unable to find mesh '" + name + "' in " + path); } #endif } else { mesh = new Mesh(); mesh.name = name; Vector3[] verts = node.GetChild <Vector3[]>("vertices"); if (verts != null) { mesh.vertices = verts; } Vector3[] normals = node.GetChild <Vector3[]>("normals"); if (normals != null) { mesh.normals = normals; } Vector2[] uv1 = node.GetChild <Vector2[]>("uv1"); if (uv1 != null) { mesh.uv = uv1; } Vector2[] uv2 = node.GetChild <Vector2[]>("uv2"); if (uv2 != null) { mesh.uv2 = uv2; } Vector4[] tangents = node.GetChild <Vector4[]>("tangents"); if (tangents != null) { mesh.tangents = tangents; } Color32[] colors = node.GetChild <Color32[]>("colors"); if (colors != null) { mesh.colors32 = colors; } BoneWeight[] weights = node.GetChild <BoneWeight[]>("weights"); if (weights != null) { mesh.boneWeights = weights; } Matrix4x4[] poses = node.GetChild <Matrix4x4[]>("poses"); if (poses != null) { mesh.bindposes = poses; } int[] triangles = node.GetChild <int[]>("triangles"); if (triangles != null) { mesh.triangles = triangles; } mesh.RecalculateBounds(); } mCachedMeshes[id] = mesh; return(mesh); }
/// <summary> /// Serialize the specified material into its DataNode format. /// </summary> static public void Serialize(this Material mat, DataNode node, bool serializeTextures) { if (!mFullSerialization) { return; } node.AddChild("name", mat.name); string path = UnityTools.LocateResource(mat); if (!string.IsNullOrEmpty(path)) { node.AddChild("path", path); return; } Shader s = mat.shader; if (s != null) { node.AddChild("shader", s.name); #if UNITY_EDITOR int props = UnityEditor.ShaderUtil.GetPropertyCount(s); for (int b = 0; b < props; ++b) { string propName = UnityEditor.ShaderUtil.GetPropertyName(s, b); UnityEditor.ShaderUtil.ShaderPropertyType type = UnityEditor.ShaderUtil.GetPropertyType(s, b); if (type == UnityEditor.ShaderUtil.ShaderPropertyType.Color) { node.AddChild(propName, mat.GetColor(propName)); } else if (type == UnityEditor.ShaderUtil.ShaderPropertyType.Vector) { node.AddChild(propName, mat.GetVector(propName)); } else if (type == UnityEditor.ShaderUtil.ShaderPropertyType.TexEnv) { Texture tex = mat.GetTexture(propName); if (tex != null) { DataNode sub = new DataNode(propName, tex.GetInstanceID()); if (serializeTextures) { tex.Serialize(sub); } sub.AddChild("offset", mat.GetTextureOffset(propName)); sub.AddChild("scale", mat.GetTextureScale(propName)); node.children.Add(sub); } } else { node.AddChild(propName, mat.GetFloat(propName)); } } #endif } }
/// <summary> /// Deserialize a previously serialized material. /// </summary> static public Material DeserializeMaterial(this DataNode matNode) { Material mat = null; int id = matNode.Get <int>(); if (mMaterials.TryGetValue(id, out mat) && mat != null) { return(mat); } // Try to load this material string name = matNode.GetChild <string>("name", "Unnamed"); string path = matNode.GetChild <string>("path"); if (id == 0) { id = (path + name).GetHashCode(); if (mMaterials.TryGetValue(id, out mat) && mat != null) { return(mat); } } if (!string.IsNullOrEmpty(path)) { mat = UnityTools.Load <Material>(path); if (mat != null) { mMaterials[id] = mat; return(mat); } } // Material can only be created if there is a shader to work with string shaderName = matNode.GetChild <string>("shader"); Shader shader = Shader.Find(shaderName); if (shader == null) { Debug.LogWarning("Shader '" + shaderName + "' was not found"); shader = Shader.Find("Diffuse"); } // Create a new material mat = new Material(shader); mat.name = name; mMaterials[id] = mat; // Restore material properties for (int b = 0; b < matNode.children.size; ++b) { DataNode prop = matNode.children[b]; if (prop.name == "shader") { continue; } if (prop.children.size != 0) { Texture tex = prop.DeserializeTexture(); if (tex != null) { mat.SetTexture(prop.name, tex); mat.SetTextureOffset(prop.name, prop.GetChild <Vector2>("offset")); mat.SetTextureScale(prop.name, prop.GetChild <Vector2>("scale", Vector2.one)); } } else if (prop.value is Vector4) { mat.SetVector(prop.name, prop.Get <Vector4>()); } else if (prop.value is Color) { mat.SetColor(prop.name, prop.Get <Color>()); } else if (prop.value is float || prop.value is int) { mat.SetFloat(prop.name, prop.Get <float>()); } } return(mat); }
protected virtual void OnSetChannelData(Channel ch, string path, DataNode node) { }
/// <summary> /// Generic component serialization function. You can add custom serialization /// to any component by adding an extension with this signature: /// static public void Serialize (this YourComponentType, DataNode); /// </summary> static public void Serialize(this Component c, DataNode node, Type type = null) { // The 'enabled' flag should only be written down if the behavior is actually disabled Behaviour b = c as Behaviour; if (b != null) { if (!b.enabled) { node.AddChild("enabled", b.enabled); } } else { Collider cd = c as Collider; if (cd != null && !cd.enabled) { node.AddChild("enabled", cd.enabled); } } // Try custom serialization first if (c.Invoke("Serialize", node)) { return; } GameObject go = c.gameObject; if (type == null) { type = c.GetType(); } MonoBehaviour mb = c as MonoBehaviour; if (mb != null) { // For MonoBehaviours we want to serialize serializable fields List <FieldInfo> fields = type.GetSerializableFields(); for (int f = 0; f < fields.size; ++f) { FieldInfo field = fields[f]; object val = field.GetValue(c); if (val == null) { continue; } val = EncodeReference(go, val); if (val == null) { continue; } node.AddChild(field.Name, val); } } else { // Unity components don't have fields, so we should serialize properties instead. List <PropertyInfo> props = type.GetSerializableProperties(); for (int f = 0; f < props.size; ++f) { PropertyInfo prop = props[f]; if (prop.Name == "name" || prop.Name == "tag" || prop.Name == "hideFlags" || prop.Name == "enabled" || prop.Name == "material" || prop.Name == "materials") { continue; } object val = prop.GetValue(c, null); if (val == null) { continue; } val = EncodeReference(go, val); if (val == null) { continue; } node.AddChild(prop.Name, val); } } }
/// <summary> /// Collect all meshes, materials and textures underneath the specified object and serialize them into the DataNode. /// </summary> static public void SerializeSharedResources(this GameObject go, DataNode node, bool includeInactive = false) { mFullSerialization = true; MeshFilter[] filters = go.GetComponentsInChildren <MeshFilter>(includeInactive); MeshRenderer[] rens = go.GetComponentsInChildren <MeshRenderer>(includeInactive); SkinnedMeshRenderer[] sks = go.GetComponentsInChildren <SkinnedMeshRenderer>(includeInactive); List <Material> materials = new List <Material>(); List <Mesh> meshes = new List <Mesh>(); foreach (MeshFilter f in filters) { Mesh m = f.sharedMesh; if (!meshes.Contains(m)) { meshes.Add(m); } } foreach (SkinnedMeshRenderer sk in sks) { Mesh m = sk.sharedMesh; if (!meshes.Contains(m)) { meshes.Add(m); } Material[] mats = sk.sharedMaterials; foreach (Material mt in mats) { if (!materials.Contains(mt)) { materials.Add(mt); } } } foreach (MeshRenderer r in rens) { Material[] mats = r.sharedMaterials; foreach (Material m in mats) { if (!materials.Contains(m)) { materials.Add(m); } } } if (materials.size == 0 && meshes.size == 0) { return; } #if UNITY_EDITOR List <Texture> textures = new List <Texture>(); for (int i = 0; i < materials.size; ++i) { Material mat = materials[i]; Shader s = mat.shader; if (s == null) { continue; } string matPath = UnityTools.LocateResource(mat); if (!string.IsNullOrEmpty(matPath)) { continue; } int props = UnityEditor.ShaderUtil.GetPropertyCount(s); for (int b = 0; b < props; ++b) { string propName = UnityEditor.ShaderUtil.GetPropertyName(s, b); UnityEditor.ShaderUtil.ShaderPropertyType type = UnityEditor.ShaderUtil.GetPropertyType(s, b); if (type != UnityEditor.ShaderUtil.ShaderPropertyType.TexEnv) { continue; } Texture tex = mat.GetTexture(propName); if (tex != null && !textures.Contains(tex)) { textures.Add(tex); } } } for (int i = 0; i < textures.size; ++i) { Texture tex = textures[i]; tex.Serialize(node.AddChild("Texture", tex.GetInstanceID())); } #endif for (int i = 0; i < materials.size; ++i) { Material mat = materials[i]; mat.Serialize(node.AddChild("Material", mat.GetInstanceID()), false); } for (int i = 0; i < meshes.size; ++i) { Mesh mesh = meshes[i]; mesh.Serialize(node.AddChild("Mesh", mesh.GetInstanceID())); } }
/// <summary> /// Set the node's value using its text representation. /// Returns whether the child nodes should be processed or not. /// </summary> bool SetValue(string text, Type type, string[] parts) { if (type == null || type == typeof(void)) { mValue = null; } else if (type == typeof(string)) { mValue = text; } else if (type == typeof(bool)) { bool b = false; if (bool.TryParse(text, out b)) { mValue = b; } } else if (type == typeof(byte)) { byte b; if (byte.TryParse(text, out b)) { mValue = b; } } else if (type == typeof(Int16)) { Int16 b; if (Int16.TryParse(text, out b)) { mValue = b; } } else if (type == typeof(UInt16)) { UInt16 b; if (UInt16.TryParse(text, out b)) { mValue = b; } } else if (type == typeof(Int32)) { Int32 b; if (Int32.TryParse(text, out b)) { mValue = b; } } else if (type == typeof(UInt32)) { UInt32 b; if (UInt32.TryParse(text, out b)) { mValue = b; } } else if (type == typeof(float)) { float b; if (float.TryParse(text, NumberStyles.Float, CultureInfo.InvariantCulture, out b)) { mValue = b; } } else if (type == typeof(double)) { double b; if (double.TryParse(text, NumberStyles.Float, CultureInfo.InvariantCulture, out b)) { mValue = b; } } else if (type == typeof(Vector2)) { if (parts == null) { parts = text.Split(','); } if (parts.Length == 2) { Vector2 v; if (float.TryParse(parts[0], NumberStyles.Float, CultureInfo.InvariantCulture, out v.x) && float.TryParse(parts[1], NumberStyles.Float, CultureInfo.InvariantCulture, out v.y)) { mValue = v; } } } else if (type == typeof(Vector3)) { if (parts == null) { parts = text.Split(','); } if (parts.Length == 3) { Vector3 v; if (float.TryParse(parts[0], NumberStyles.Float, CultureInfo.InvariantCulture, out v.x) && float.TryParse(parts[1], NumberStyles.Float, CultureInfo.InvariantCulture, out v.y) && float.TryParse(parts[2], NumberStyles.Float, CultureInfo.InvariantCulture, out v.z)) { mValue = v; } } } else if (type == typeof(Vector4)) { if (parts == null) { parts = text.Split(','); } if (parts.Length == 4) { Vector4 v; if (float.TryParse(parts[0], NumberStyles.Float, CultureInfo.InvariantCulture, out v.x) && float.TryParse(parts[1], NumberStyles.Float, CultureInfo.InvariantCulture, out v.y) && float.TryParse(parts[2], NumberStyles.Float, CultureInfo.InvariantCulture, out v.z) && float.TryParse(parts[3], NumberStyles.Float, CultureInfo.InvariantCulture, out v.w)) { mValue = v; } } } else if (type == typeof(Quaternion)) { if (parts == null) { parts = text.Split(','); } if (parts.Length == 3) { Vector3 v; if (float.TryParse(parts[0], NumberStyles.Float, CultureInfo.InvariantCulture, out v.x) && float.TryParse(parts[1], NumberStyles.Float, CultureInfo.InvariantCulture, out v.y) && float.TryParse(parts[2], NumberStyles.Float, CultureInfo.InvariantCulture, out v.z)) { mValue = Quaternion.Euler(v); } } else if (parts.Length == 4) { Quaternion v; if (float.TryParse(parts[0], NumberStyles.Float, CultureInfo.InvariantCulture, out v.x) && float.TryParse(parts[1], NumberStyles.Float, CultureInfo.InvariantCulture, out v.y) && float.TryParse(parts[2], NumberStyles.Float, CultureInfo.InvariantCulture, out v.z) && float.TryParse(parts[3], NumberStyles.Float, CultureInfo.InvariantCulture, out v.w)) { mValue = v; } } } else if (type == typeof(Color)) { if (parts == null) { parts = text.Split(','); } if (parts.Length == 4) { Color v; if (float.TryParse(parts[0], NumberStyles.Float, CultureInfo.InvariantCulture, out v.r) && float.TryParse(parts[1], NumberStyles.Float, CultureInfo.InvariantCulture, out v.g) && float.TryParse(parts[2], NumberStyles.Float, CultureInfo.InvariantCulture, out v.b) && float.TryParse(parts[3], NumberStyles.Float, CultureInfo.InvariantCulture, out v.a)) { mValue = v; } } } else if (type == typeof(Rect)) { if (parts == null) { parts = text.Split(','); } if (parts.Length == 4) { Vector4 v; if (float.TryParse(parts[0], NumberStyles.Float, CultureInfo.InvariantCulture, out v.x) && float.TryParse(parts[1], NumberStyles.Float, CultureInfo.InvariantCulture, out v.y) && float.TryParse(parts[2], NumberStyles.Float, CultureInfo.InvariantCulture, out v.z) && float.TryParse(parts[3], NumberStyles.Float, CultureInfo.InvariantCulture, out v.w)) { mValue = new Rect(v.x, v.y, v.z, v.w); } } } else if (type.Implements(typeof(IDataNodeSerializable))) { IDataNodeSerializable ds = (IDataNodeSerializable)type.Create(); ds.Deserialize(this); mValue = ds; return(false); } else if (!type.IsSubclassOf(typeof(Component))) { bool isIList = type.Implements(typeof(System.Collections.IList)); bool isTList = (!isIList && type.Implements(typeof(TList))); mValue = (isTList || isIList) ? type.Create(children.size) : type.Create(); if (mValue == null) { Debug.LogError("Unable to create a " + type); return(true); } if (isTList) { TList list = mValue as TList; Type elemType = type.GetGenericArgument(); if (elemType != null) { for (int i = 0; i < children.size; ++i) { DataNode child = children[i]; if (child.value == null) { child.mValue = child.name; child.mResolved = false; child.ResolveValue(elemType); list.Add(child.mValue); } else if (child.name == "Add") { child.ResolveValue(elemType); list.Add(child.mValue); } else { Debug.LogWarning("Unexpected node in an array: " + child.name); } } return(false); } else { Debug.LogError("Unable to determine the element type of " + type); } } else if (isIList) { // This is for both List<Type> and Type[] arrays. System.Collections.IList list = mValue as System.Collections.IList; Type elemType = type.GetGenericArgument(); if (elemType == null) { elemType = type.GetElementType(); } bool fixedSize = (list.Count == children.size); if (elemType != null) { for (int i = 0; i < children.size; ++i) { DataNode child = children[i]; if (child.value == null) { child.mValue = child.name; child.mResolved = false; child.ResolveValue(elemType); if (fixedSize) { list[i] = child.mValue; } else { list.Add(child.mValue); } } else if (child.name == "Add") { child.ResolveValue(elemType); if (fixedSize) { list[i] = child.mValue; } else { list.Add(child.mValue); } } else { Debug.LogWarning("Unexpected node in an array: " + child.name); } } return(false); } else { Debug.LogError("Unable to determine the element type of " + type); } } else if (type.IsClass) { for (int i = 0; i < children.size; ++i) { DataNode child = children[i]; mValue.SetSerializableField(child.name, child.value); } return(false); } else { Debug.LogError("Unhandled type: " + type); } } return(true); }
/// <summary> /// Load a game object prefab at the specified path. This is equivalent to Resources.Load, but it will /// also consider DataNode-exported binary assets as well, automatically loading them as if they were /// regular prefabs. /// </summary> static public GameObject LoadPrefab(string path) { if (string.IsNullOrEmpty(path)) { return(null); } if (!Application.isPlaying) { return(Resources.Load(path, typeof(GameObject)) as GameObject); } GameObject prefab = null; if (mPrefabRoot == null) { GameObject go = new GameObject("Prefabs"); Object.DontDestroyOnLoad(go); mPrefabRoot = go.transform; mPrefabs.Clear(); } // Try to get it from cache if (mPrefabs.TryGetValue(path, out prefab)) { return(prefab); } if (prefab == null) { // Load it from resources as a Game Object prefab = Resources.Load(path, typeof(GameObject)) as GameObject; if (prefab == null) { // Load it from resources as a binary asset byte[] bytes = UnityTools.LoadBinary(path); if (bytes != null) { // Parse the DataNode hierarchy DataNode data = DataNode.Read(bytes); if (data != null) { // Instantiate and immediately disable the object prefab = data.Instantiate(); if (prefab != null) { mPrefabs.Add(path, prefab); Object.DontDestroyOnLoad(prefab); prefab.transform.parent = mPrefabRoot; prefab.SetActive(false); return(prefab); } } } } } if (prefab == null) { #if UNITY_EDITOR Debug.LogError("[TNet] Attempting to create a game object that can't be found in the Resources folder: [" + path + "]"); #endif prefab = GetDummyObject(); } mPrefabs.Add(path, prefab); return(prefab); }
/// <summary> /// Serialize this game object into a DataNode. /// Note that the prefab references can only be resolved if serialized from within the Unity Editor. /// You can instantiate this game object directly from DataNode format by using DataNode.Instantiate(). /// Ideal usage: save a game object hierarchy into a file. Serializing a game object will also serialize its /// mesh data, making it possible to export entire 3D models. Any references to prefabs or materials located /// in the Resources folder will be kept as references and their hierarchy won't be serialized. /// </summary> static public DataNode Serialize(this GameObject go, bool fullHierarchy = true, bool isRootNode = true) { DataNode root = new DataNode(go.name, go.GetInstanceID()); // Save a reference to a prefab, if there is one string prefab = UnityTools.LocateResource(go, !isRootNode); if (!string.IsNullOrEmpty(prefab)) { root.AddChild("prefab", prefab); } // Save the transform and the object's layer Transform trans = go.transform; root.AddChild("position", trans.localPosition); root.AddChild("rotation", trans.localEulerAngles); root.AddChild("scale", trans.localScale); int layer = go.layer; if (layer != 0) { root.AddChild("layer", go.layer); } // If this was a prefab instance, don't do anything else if (!string.IsNullOrEmpty(prefab)) { return(root); } // Collect all meshes if (isRootNode) { DataNode child = new DataNode("Resources"); #if UNITY_EDITOR go.SerializeSharedResources(child, UnityEditor.PrefabUtility.GetPrefabType(go) == UnityEditor.PrefabType.Prefab); #else go.SerializeSharedResources(child); #endif if (child.children.size != 0) { root.children.Add(child); } mFullSerialization = false; } Component[] comps = go.GetComponents <Component>(); DataNode compRoot = null; for (int i = 0, imax = comps.Length; i < imax; ++i) { Component c = comps[i]; System.Type type = c.GetType(); if (type == typeof(Transform)) { continue; } if (compRoot == null) { compRoot = root.AddChild("Components"); } DataNode child = compRoot.AddChild(Serialization.TypeToName(type), c.GetInstanceID()); c.Serialize(child, type); } if (fullHierarchy && trans.childCount > 0) { DataNode children = root.AddChild("Children"); for (int i = 0, imax = trans.childCount; i < imax; ++i) { GameObject child = trans.GetChild(i).gameObject; if (child.activeInHierarchy) { children.children.Add(child.Serialize(true, false)); } } } if (isRootNode) { mFullSerialization = true; } return(root); }
/// <summary> /// Set a node's value given its hierarchical path. /// </summary> public DataNode SetHierarchy(string path, object obj) { DataNode node = this; if (!string.IsNullOrEmpty(path)) { if (path.IndexOf('\\') == -1 && path.IndexOf('/') == -1) { if (obj == null) { RemoveChild(path); return(null); } node = GetChild(path, true); } else { path = path.Replace("\\", "/"); var names = path.Split('/'); DataNode parent = null; int index = 0; while (node != null && index < names.Length) { bool found = false; for (int i = 0; i < node.children.size; ++i) { if (node.children[i].name == names[index]) { parent = node; node = node.children[i]; ++index; found = true; break; } } if (!found) { // No need to do anything -- the requested path is already missing if (obj == null) { return(parent); } // Add a new node parent = node; node = node.AddChild(names[index]); ++index; } } if (node != null && obj == null) { parent.RemoveChild(names[index - 1]); return(parent); } } } if (obj is DataNode) { DataNode other = (obj as DataNode); node.value = other.value; node.children.Clear(); node.mCache = null; for (int i = 0; i < other.children.size; ++i) { node.children.Add(other.children[i].Clone()); } } else { node.value = obj; } return(node); }
/// <summary> /// Write the values into the stream writer. /// </summary> static void Write(StreamWriter writer, string name, object value, int tab = 0) { bool prefix = false; if (!string.IsNullOrEmpty(name)) { prefix = true; writer.WriteTabs(tab); writer.Write(name); } else if (value != null) { writer.WriteTabs(tab); } if (value != null && !writer.WriteObject(value, prefix)) { var type = value.GetType(); if (value is DataNode) { if (prefix) { writer.Write(" = "); } writer.Write("DataNode"); writer.Write('\n'); var node = (DataNode)value; node.Write(writer, tab + 1); return; } #if !STANDALONE if (value is AnimationCurve) { var ac = value as AnimationCurve; var kfs = ac.keys; type = typeof(Vector4[]); var imax = kfs.Length; var vs = new Vector4[imax]; for (int i = 0; i < imax; ++i) { var kf = kfs[i]; vs[i] = new Vector4(kf.time, kf.value, kf.inTangent, kf.outTangent); } value = vs; } #endif // Save cloth skinning coefficients as a Vector2 array if (value is ClothSkinningCoefficient[]) { var cf = value as ClothSkinningCoefficient[]; type = typeof(Vector2[]); var imax = cf.Length; var vs = new Vector2[imax]; for (int i = 0; i < imax; ++i) { vs[i].x = cf[i].maxDistance; vs[i].y = cf[i].collisionSphereDistance; } value = vs; } if (value is TList) { var list = value as TList; if (prefix) { writer.Write(" = "); } writer.Write(Serialization.TypeToName(type)); if (list.Count > 0) { for (int i = 0, imax = list.Count; i < imax; ++i) { writer.Write('\n'); Write(writer, null, list.Get(i), tab + 1); } } return; } if (value is System.Collections.IList) { var list = value as System.Collections.IList; if (prefix) { writer.Write(" = "); } writer.Write(Serialization.TypeToName(type)); if (list.Count > 0) { for (int i = 0, imax = list.Count; i < imax; ++i) { writer.Write('\n'); Write(writer, null, list[i], tab + 1); } } return; } // IDataNodeSerializable interface has serialization functions if (value is IDataNodeSerializable) { var ser = value as IDataNodeSerializable; var temp = mTemp; mTemp = null; if (temp == null) { temp = new DataNode(); } ser.Serialize(temp); if (prefix) { writer.Write(" = "); } writer.Write(Serialization.TypeToName(type)); for (int i = 0; i < temp.children.size; ++i) { var child = temp.children[i]; writer.Write('\n'); child.Write(writer, tab + 1); } temp.Clear(); mTemp = temp; return; } #if REFLECTION_SUPPORT #if SERIALIZATION_WITHOUT_INTERFACE // Try custom serialization first if (type.HasDataNodeSerialization()) { var temp = mTemp; mTemp = null; if (temp == null) { temp = new DataNode(); } if (value.Invoke("Serialize", temp)) { if (prefix) { writer.Write(" = "); } writer.Write(Serialization.TypeToName(type)); for (int i = 0; i < temp.children.size; ++i) { var child = temp.children[i]; writer.Write('\n'); child.Write(writer, tab + 1); } temp.Clear(); mTemp = temp; return; } } #endif if (prefix) { writer.Write(" = "); } writer.Write(Serialization.TypeToName(type)); var fields = type.GetSerializableFields(); // We have fields to serialize for (int i = 0; i < fields.size; ++i) { var field = fields[i]; var val = field.GetValue(value); if (val != null) { writer.Write('\n'); Write(writer, field.Name, val, tab + 1); } } if (fields.size == 0 || type.IsDefined(typeof(SerializeProperties), true)) { // We don't have fields to serialize, but we may have properties var props = type.GetSerializableProperties(); if (props.size > 0) { for (int i = 0; i < props.size; ++i) { var prop = props[i]; object val = prop.GetValue(value, null); if (val != null) { writer.Write('\n'); Write(writer, prop.Name, val, tab + 1); } } } } #endif } }
/// <summary> /// Write the values into the stream writer. /// </summary> static void Write(StreamWriter writer, string name, object value, int tab = 0) { bool prefix = false; if (!string.IsNullOrEmpty(name)) { prefix = true; writer.WriteTabs(tab); writer.Write(name); } else if (value != null) { writer.WriteTabs(tab); } if (value != null && !writer.WriteObject(value, prefix)) { Type type = value.GetType(); #if !STANDALONE if (value is AnimationCurve) { AnimationCurve ac = value as AnimationCurve; Keyframe[] kfs = ac.keys; type = typeof(Vector4[]); Vector4[] vs = new Vector4[kfs.Length]; for (int i = 0, imax = kfs.Length; i < imax; ++i) { Keyframe kf = kfs[i]; vs[i] = new Vector4(kf.time, kf.value, kf.inTangent, kf.outTangent); } value = vs; } #endif if (value is TList) { TList list = value as TList; if (prefix) { writer.Write(" = "); } writer.Write(Serialization.TypeToName(type)); if (list.Count > 0) { for (int i = 0, imax = list.Count; i < imax; ++i) { writer.Write('\n'); Write(writer, null, list.Get(i), tab + 1); } } return; } if (value is System.Collections.IList) { System.Collections.IList list = value as System.Collections.IList; if (prefix) { writer.Write(" = "); } writer.Write(Serialization.TypeToName(type)); if (list.Count > 0) { for (int i = 0, imax = list.Count; i < imax; ++i) { writer.Write('\n'); Write(writer, null, list[i], tab + 1); } } return; } if (value is IDataNodeSerializable) { IDataNodeSerializable ser = value as IDataNodeSerializable; DataNode node = new DataNode(); ser.Serialize(node); if (prefix) { writer.Write(" = "); } writer.Write(Serialization.TypeToName(type)); for (int i = 0; i < node.children.size; ++i) { DataNode child = node.children[i]; writer.Write('\n'); child.Write(writer, tab + 1); } return; } #if REFLECTION_SUPPORT if (prefix) { writer.Write(" = "); } writer.Write(Serialization.TypeToName(type)); var fields = type.GetSerializableFields(); // We have fields to serialize for (int i = 0; i < fields.size; ++i) { FieldInfo field = fields[i]; object val = field.GetValue(value); if (val != null) { writer.Write('\n'); Write(writer, field.Name, val, tab + 1); } } if (fields.size == 0 || type.IsDefined(typeof(SerializeProperties), true)) { // We don't have fields to serialize, but we may have properties var props = type.GetSerializableProperties(); if (props.size > 0) { for (int i = 0; i < props.size; ++i) { var prop = props[i]; object val = prop.GetValue(value, null); if (val != null) { writer.Write('\n'); Write(writer, prop.Name, val, tab + 1); } } } } #endif } }
/// <summary> /// Process the string values, converting them to proper objects. /// Returns whether child nodes should be processed in turn. /// </summary> public bool ResolveValue(Type type = null) { if (mValue is string) { mResolved = true; string line = mValue as string; // Trim strings wrapped in quotes if (type == typeof(string)) { if (line == "\"\"") { mValue = ""; } else { int len = line.Length; if (len > 2 && line[0] == '"' && line[len - 1] == '"') { mValue = line.Substring(1, len - 2); } } return(true); } // Try to resolve this type as a simple type if (Serialization.ReadObject(line, out mValue, type)) { return(true); } // This type is either a class or an array if (type == null) { type = Serialization.NameToType(line); } if (type == null || type == typeof(void)) { mValue = null; return(true); } else if (type.Implements(typeof(IDataNodeSerializable))) { IDataNodeSerializable ds = (IDataNodeSerializable)type.Create(); ds.Deserialize(this); mValue = ds; return(false); } #if !STANDALONE else if (type == typeof(AnimationCurve)) { if (children.size != 0) { AnimationCurve cv = new AnimationCurve(); Keyframe[] kfs = new Keyframe[children.size]; for (int i = 0; i < children.size; ++i) { DataNode child = children[i]; if (child.value == null) { child.mValue = child.name; child.mResolved = false; child.ResolveValue(typeof(Vector4)); Vector4 v = (Vector4)child.mValue; kfs[i] = new Keyframe(v.x, v.y, v.z, v.w); } else { Vector4 v = (Vector4)child.mValue; kfs[i] = new Keyframe(v.x, v.y, v.z, v.w); } } cv.keys = kfs; mValue = cv; children.Clear(); } return(false); } else if (type == typeof(LayerMask)) { mValue = (LayerMask)Get <int>(); } #endif else #if !STANDALONE if (!type.IsSubclassOf(typeof(Component))) #endif { bool isIList = type.Implements(typeof(System.Collections.IList)); bool isTList = (!isIList && type.Implements(typeof(TList))); mValue = (isTList || isIList) ? type.Create(children.size) : type.Create(); if (mValue == null) { Tools.LogError("Unable to create a " + type); return(true); } if (isTList) { TList list = mValue as TList; Type elemType = type.GetGenericArgument(); if (elemType != null) { for (int i = 0; i < children.size; ++i) { DataNode child = children[i]; if (child.value == null) { child.mValue = child.name; child.mResolved = false; child.ResolveValue(elemType); list.Add(child.mValue); } else if (child.name == "Add") { child.ResolveValue(elemType); list.Add(child.mValue); } else { Tools.LogError("Unexpected node in an array: " + child.name); } } return(false); } else { Tools.LogError("Unable to determine the element type of " + type); } } else if (isIList) { // This is for both List<Type> and Type[] arrays. System.Collections.IList list = mValue as System.Collections.IList; Type elemType = type.GetGenericArgument(); if (elemType == null) { elemType = type.GetElementType(); } bool fixedSize = (list.Count == children.size); if (elemType != null) { for (int i = 0; i < children.size; ++i) { DataNode child = children[i]; if (child.value == null) { child.mValue = child.name; child.mResolved = false; child.ResolveValue(elemType); if (fixedSize) { list[i] = child.mValue; } else { list.Add(child.mValue); } } else if (child.name == "Add") { child.ResolveValue(elemType); if (fixedSize) { list[i] = child.mValue; } else { list.Add(child.mValue); } } else { Tools.LogError("Unexpected node in an array: " + child.name); } } return(false); } else { Tools.LogError("Unable to determine the element type of " + type); } } else { for (int i = 0; i < children.size; ++i) { DataNode child = children[i]; mValue.SetFieldOrPropertyValue(child.name, child.value); } return(false); } } return(true); } return(true); }
protected virtual void OnSetPlayerData(Player p, string path, DataNode node) { }
/// <summary> /// Serialize the entire texture into the specified DataNode. /// </summary> static public void Serialize(this Texture tex, DataNode node) { if (!mFullSerialization) { return; } node.AddChild("name", tex.name); string path = UnityTools.LocateResource(tex); if (!string.IsNullOrEmpty(path)) { node.AddChild("path", path); return; } if (tex is Texture2D) { Texture2D t2 = tex as Texture2D; #if UNITY_EDITOR try { byte[] bytes = t2.EncodeToPNG(); if (bytes != null) { node.AddChild("bytes", bytes); } else { Debug.Log(t2.name + " (" + t2.format + ")", tex); } } catch (Exception) { string assetPath = UnityEditor.AssetDatabase.GetAssetPath(tex); if (!string.IsNullOrEmpty(assetPath)) { UnityEditor.TextureImporter ti = UnityEditor.AssetImporter.GetAtPath(assetPath) as UnityEditor.TextureImporter; ti.isReadable = true; UnityEditor.AssetDatabase.ImportAsset(assetPath); byte[] bytes = t2.EncodeToPNG(); if (bytes != null) { node.AddChild("bytes", bytes); } else { Debug.Log(t2.name + " (" + t2.format + ")", tex); } } } #else node.AddChild("bytes", t2.EncodeToPNG()); #endif node.AddChild("filter", (int)t2.filterMode); node.AddChild("wrap", (int)t2.wrapMode); node.AddChild("af", t2.anisoLevel); return; } Debug.LogWarning("Unable to save a reference to texture '" + tex.name + "' because it's not in the Resources folder.", tex); }
/// <summary> /// Serialize the specified renderer into its DataNode format. /// </summary> static void Serialize(this MeshRenderer ren, DataNode root) { SerializeRenderer(ren, root); }
/// <summary> /// Deserialize the texture that was previously serialized into the DataNode format. /// </summary> static public Texture DeserializeTexture(this DataNode node) { // First try the cache Texture tex = null; int id = node.Get <int>(); if (id != 0 && mTextures.TryGetValue(id, out tex) && tex != null) { return(tex); } // If the texture's ID is unknown, make a dummy one and try going through cache again string name = node.GetChild <string>("name", "Unnamed"); string path = node.GetChild <string>("path"); if (id == 0) { id = (path + name).GetHashCode(); if (mTextures.TryGetValue(id, out tex) && tex != null) { return(tex); } } // Next try to load the texture if (!string.IsNullOrEmpty(path)) { tex = UnityTools.Load <Texture>(path); if (tex != null) { mTextures[id] = tex; return(tex); } } // Lastly, create a new texture Texture2D t2 = new Texture2D(2, 2); t2.name = name; // Try to load the texture's data byte[] bytes = node.GetChild <byte[]>("bytes"); if (bytes != null) { t2.LoadImage(bytes); t2.filterMode = (FilterMode)node.GetChild <int>("filter", (int)t2.filterMode); t2.wrapMode = (TextureWrapMode)node.GetChild <int>("wrap", (int)t2.wrapMode); t2.anisoLevel = node.GetChild <int>("af", t2.anisoLevel); t2.Apply(); } else { #if UNITY_EDITOR Debug.LogWarning("Creating a dummy texture: " + t2.name, t2); #endif t2.SetPixels(new Color[] { Color.clear, Color.clear, Color.clear, Color.clear }); t2.Apply(); } // Add it to cache tex = t2; mTextures[id] = tex; return(tex); }
/// <summary> /// Deserialize a previously serialized renderer. /// </summary> static void Deserialize(this MeshRenderer ren, DataNode data) { Deserialize((Renderer)ren, data); }
/// <summary> /// Write the values into the stream writer. /// </summary> static void Write(StreamWriter writer, int tab, string name, object value, bool writeType) { if (string.IsNullOrEmpty(name) && value == null) { return; } WriteTabs(writer, tab); if (name != null) { writer.Write(Escape(name)); if (value == null) { writer.Write('\n'); return; } } Type type = value.GetType(); if (type == typeof(string)) { if (name != null) { writer.Write(" = \""); } writer.Write((string)value); if (name != null) { writer.Write('"'); } writer.Write('\n'); } else if (type == typeof(bool)) { if (name != null) { writer.Write(" = "); } writer.Write((bool)value ? "true" : "false"); writer.Write('\n'); } else if (type == typeof(Int32) || type == typeof(float) || type == typeof(UInt32) || type == typeof(byte) || type == typeof(short) || type == typeof(ushort)) { if (name != null) { writer.Write(" = "); } writer.Write(value.ToString()); writer.Write('\n'); } else if (type == typeof(Vector2)) { Vector2 v = (Vector2)value; writer.Write(name != null ? " = (" : "("); writer.Write(v.x.ToString(CultureInfo.InvariantCulture)); writer.Write(", "); writer.Write(v.y.ToString(CultureInfo.InvariantCulture)); writer.Write(")\n"); } else if (type == typeof(Vector3)) { Vector3 v = (Vector3)value; writer.Write(name != null ? " = (" : "("); writer.Write(v.x.ToString(CultureInfo.InvariantCulture)); writer.Write(", "); writer.Write(v.y.ToString(CultureInfo.InvariantCulture)); writer.Write(", "); writer.Write(v.z.ToString(CultureInfo.InvariantCulture)); writer.Write(")\n"); } else if (type == typeof(Color)) { Color c = (Color)value; writer.Write(name != null ? " = (" : "("); writer.Write(c.r.ToString(CultureInfo.InvariantCulture)); writer.Write(", "); writer.Write(c.g.ToString(CultureInfo.InvariantCulture)); writer.Write(", "); writer.Write(c.b.ToString(CultureInfo.InvariantCulture)); writer.Write(", "); writer.Write(c.a.ToString(CultureInfo.InvariantCulture)); writer.Write(")\n"); } else if (type == typeof(Color32)) { Color32 c = (Color32)value; writer.Write(name != null ? " = 0x" : "0x"); if (c.a == 255) { int i = (c.r << 16) | (c.g << 8) | c.b; writer.Write(i.ToString("X6")); } else { int i = (c.r << 24) | (c.g << 16) | (c.b << 8) | c.a; writer.Write(i.ToString("X8")); } writer.Write('\n'); } else { if (type == typeof(Vector4)) { Vector4 v = (Vector4)value; if (name != null) { writer.Write(" = "); } writer.Write(Serialization.TypeToName(type)); writer.Write('('); writer.Write(v.x.ToString(CultureInfo.InvariantCulture)); writer.Write(", "); writer.Write(v.y.ToString(CultureInfo.InvariantCulture)); writer.Write(", "); writer.Write(v.z.ToString(CultureInfo.InvariantCulture)); writer.Write(", "); writer.Write(v.w.ToString(CultureInfo.InvariantCulture)); writer.Write(")\n"); } else if (type == typeof(Quaternion)) { Quaternion q = (Quaternion)value; Vector3 v = q.eulerAngles; if (name != null) { writer.Write(" = "); } writer.Write(Serialization.TypeToName(type)); writer.Write('('); writer.Write(v.x.ToString(CultureInfo.InvariantCulture)); writer.Write(", "); writer.Write(v.y.ToString(CultureInfo.InvariantCulture)); writer.Write(", "); writer.Write(v.z.ToString(CultureInfo.InvariantCulture)); writer.Write(")\n"); } else if (type == typeof(Rect)) { Rect r = (Rect)value; if (name != null) { writer.Write(" = "); } writer.Write(Serialization.TypeToName(type)); writer.Write('('); writer.Write(r.x.ToString(CultureInfo.InvariantCulture)); writer.Write(", "); writer.Write(r.y.ToString(CultureInfo.InvariantCulture)); writer.Write(", "); writer.Write(r.width.ToString(CultureInfo.InvariantCulture)); writer.Write(", "); writer.Write(r.height.ToString(CultureInfo.InvariantCulture)); writer.Write(")\n"); } else if (value is TList) { TList list = value as TList; if (name != null) { writer.Write(" = "); } writer.Write(Serialization.TypeToName(type)); writer.Write('\n'); if (list.Count > 0) { for (int i = 0, imax = list.Count; i < imax; ++i) { Write(writer, tab + 1, null, list.Get(i), false); } } } else if (value is System.Collections.IList) { System.Collections.IList list = value as System.Collections.IList; if (name != null) { writer.Write(" = "); } writer.Write(Serialization.TypeToName(type)); writer.Write('\n'); if (list.Count > 0) { for (int i = 0, imax = list.Count; i < imax; ++i) { Write(writer, tab + 1, null, list[i], false); } } } else if (value is IDataNodeSerializable) { IDataNodeSerializable ser = value as IDataNodeSerializable; DataNode node = new DataNode(); ser.Serialize(node); if (name != null) { writer.Write(" = "); } writer.Write(Serialization.TypeToName(type)); writer.Write('\n'); for (int i = 0; i < node.children.size; ++i) { DataNode child = node.children[i]; child.Write(writer, tab + 1); } } else if (value is GameObject) { Debug.LogError("It's not possible to save game objects."); writer.Write('\n'); } else if ((value as Component) != null) { Debug.LogError("It's not possible to save components."); writer.Write('\n'); } else { if (writeType) { if (name != null) { writer.Write(" = "); } writer.Write(Serialization.TypeToName(type)); } writer.Write('\n'); #if REFLECTION_SUPPORT List <FieldInfo> fields = type.GetSerializableFields(); if (fields.size > 0) { for (int i = 0; i < fields.size; ++i) { FieldInfo field = fields[i]; object val = field.GetValue(value); if (val != null) { Write(writer, tab + 1, field.Name, val, true); } } } #endif } } }
/// <summary> /// Serialize the specified material into its DataNode format. /// </summary> static public void Serialize(this Material mat, DataNode node) { mat.Serialize(node, true); }
/// <summary> /// Process a single incoming packet. Returns whether we should keep processing packets or not. /// </summary> bool ProcessPacket(Buffer buffer, IPEndPoint ip) { mPacketSource = ip; BinaryReader reader = buffer.BeginReading(); if (buffer.size == 0) { return(true); } int packetID = reader.ReadByte(); Packet response = (Packet)packetID; #if DEBUG_PACKETS && !STANDALONE if (response != Packet.ResponsePing && response != Packet.Broadcast) { UnityEngine.Debug.Log("Client: " + response + " (" + buffer.size + " bytes) " + ((ip == null) ? "(TCP)" : "(UDP)")); } #endif // Verification step must be passed first if (response == Packet.ResponseID || mTcp.stage == TcpProtocol.Stage.Verifying) { if (mTcp.VerifyResponseID(response, reader)) { mTimeDifference = reader.ReadInt64() - (System.DateTime.UtcNow.Ticks / 10000); #if !UNITY_WEBPLAYER if (mUdp.isActive) { // If we have a UDP listener active, tell the server BeginSend(Packet.RequestSetUDP).Write((ushort)mUdp.listeningPort); EndSend(); } #endif mCanPing = true; if (onConnect != null) { onConnect(true, null); } } return(true); } OnPacket callback; if (packetHandlers.TryGetValue((byte)response, out callback) && callback != null) { callback(response, reader, ip); return(true); } switch (response) { case Packet.Empty: break; case Packet.ForwardToAll: case Packet.ForwardToOthers: case Packet.ForwardToAllSaved: case Packet.ForwardToOthersSaved: case Packet.ForwardToHost: case Packet.BroadcastAdmin: case Packet.Broadcast: { packetSourceID = reader.ReadInt32(); int channelID = reader.ReadInt32(); if (onForwardedPacket != null) { onForwardedPacket(channelID, reader); } break; } case Packet.ForwardToPlayer: { packetSourceID = reader.ReadInt32(); reader.ReadInt32(); // Skip the target player ID int channelID = reader.ReadInt32(); if (onForwardedPacket != null) { onForwardedPacket(channelID, reader); } break; } case Packet.ForwardByName: { packetSourceID = reader.ReadInt32(); reader.ReadString(); // Skip the player name int channelID = reader.ReadInt32(); if (onForwardedPacket != null) { onForwardedPacket(channelID, reader); } break; } case Packet.ResponseSetPlayerData: { int pid = reader.ReadInt32(); Player target = GetPlayer(pid); if (target != null) { string path = reader.ReadString(); DataNode node = target.Set(path, reader.ReadObject()); if (onSetPlayerData != null) { onSetPlayerData(target, path, node); } } else { UnityEngine.Debug.LogError("Not found: " + pid); } break; } case Packet.ResponsePing: { int ping = (int)(mMyTime - mPingTime); if (ip != null) { if (onPing != null && ip != null) { onPing(ip, ping); } } else { mCanPing = true; mPing = ping; } break; } case Packet.ResponseSetUDP: { #if !UNITY_WEBPLAYER // The server has a new port for UDP traffic ushort port = reader.ReadUInt16(); if (port != 0 && mTcp.tcpEndPoint != null) { IPAddress ipa = new IPAddress(mTcp.tcpEndPoint.Address.GetAddressBytes()); mServerUdpEndPoint = new IPEndPoint(ipa, port); // Send the first UDP packet to the server if (mUdp.isActive) { mBuffer = Buffer.Create(); mBuffer.BeginPacket(Packet.RequestActivateUDP).Write(playerID); mBuffer.EndPacket(); mUdp.Send(mBuffer, mServerUdpEndPoint); mBuffer.Recycle(); mBuffer = null; } } else { mServerUdpEndPoint = null; } #endif break; } case Packet.ResponseJoiningChannel: { int channelID = reader.ReadInt32(); int count = reader.ReadInt16(); Channel ch = GetChannel(channelID, true); for (int i = 0; i < count; ++i) { int pid = reader.ReadInt32(); Player p = GetPlayer(pid, true); if (reader.ReadBoolean()) { p.name = reader.ReadString(); p.dataNode = reader.ReadDataNode(); } ch.players.Add(p); } break; } case Packet.ResponseLoadLevel: { // Purposely return after loading a level, ensuring that all future callbacks happen after loading int channelID = reader.ReadInt32(); string scene = reader.ReadString(); if (onLoadLevel != null) { onLoadLevel(channelID, scene); } return(false); } case Packet.ResponsePlayerJoined: { int channelID = reader.ReadInt32(); Channel ch = GetChannel(channelID); if (ch != null) { Player p = GetPlayer(reader.ReadInt32(), true); if (reader.ReadBoolean()) { p.name = reader.ReadString(); p.dataNode = reader.ReadDataNode(); } ch.players.Add(p); if (onPlayerJoin != null) { onPlayerJoin(channelID, p); } } break; } case Packet.ResponsePlayerLeft: { int channelID = reader.ReadInt32(); int playerID = reader.ReadInt32(); Channel ch = GetChannel(channelID); if (ch != null) { Player p = ch.GetPlayer(playerID); ch.players.Remove(p); RebuildPlayerDictionary(); if (onPlayerLeave != null) { onPlayerLeave(channelID, p); } } break; } case Packet.ResponseSetHost: { int channelID = reader.ReadInt32(); int hostID = reader.ReadInt32(); for (int i = 0; i < mChannels.size; ++i) { Channel ch = mChannels[i]; if (ch.id == channelID) { ch.host = GetPlayer(hostID); if (onHostChanged != null) { onHostChanged(ch); } break; } } break; } case Packet.ResponseSetChannelData: { int channelID = reader.ReadInt32(); Channel ch = GetChannel(channelID); if (ch != null) { string path = reader.ReadString(); DataNode node = ch.Set(path, reader.ReadObject()); if (onSetChannelData != null) { onSetChannelData(ch, path, node); } } break; } case Packet.ResponseJoinChannel: { int channelID = reader.ReadInt32(); bool success = reader.ReadBoolean(); string msg = success ? null : reader.ReadString(); // mJoining can contain -2 and -1 when joining random channels if (!mJoining.Remove(channelID)) { for (int i = 0; i < mJoining.size; ++i) { int id = mJoining[i]; if (id < 0) { mJoining.RemoveAt(i); break; } } } #if UNITY_EDITOR if (!success) { UnityEngine.Debug.LogError("ResponseJoinChannel: " + success + ", " + msg); } #endif if (onJoinChannel != null) { onJoinChannel(channelID, success, msg); } break; } case Packet.ResponseLeaveChannel: { int channelID = reader.ReadInt32(); for (int i = 0; i < mChannels.size; ++i) { Channel ch = mChannels[i]; if (ch.id == channelID) { mChannels.RemoveAt(i); break; } } RebuildPlayerDictionary(); if (onLeaveChannel != null) { onLeaveChannel(channelID); } // Purposely exit after receiving a "left channel" notification so that other packets get handled in the next frame. return(false); } case Packet.ResponseRenamePlayer: { Player p = GetPlayer(reader.ReadInt32()); string oldName = p.name; if (p != null) { p.name = reader.ReadString(); } if (onRenamePlayer != null) { onRenamePlayer(p, oldName); } break; } case Packet.ResponseCreateObject: { if (onCreate != null) { int playerID = reader.ReadInt32(); int channelID = reader.ReadInt32(); uint objID = reader.ReadUInt32(); onCreate(channelID, playerID, objID, reader); } break; } case Packet.ResponseDestroyObject: { if (onDestroy != null) { int channelID = reader.ReadInt32(); int count = reader.ReadUInt16(); for (int i = 0; i < count; ++i) { uint val = reader.ReadUInt32(); onDestroy(channelID, val); } } break; } case Packet.ResponseTransferObject: { if (onTransfer != null) { int from = reader.ReadInt32(); int to = reader.ReadInt32(); uint id0 = reader.ReadUInt32(); uint id1 = reader.ReadUInt32(); onTransfer(from, to, id0, id1); } break; } case Packet.Error: { string err = reader.ReadString(); if (onError != null) { onError(err); } if (mTcp.stage != TcpProtocol.Stage.Connected && onConnect != null) { onConnect(false, err); } break; } case Packet.Disconnect: { if (onLeaveChannel != null) { while (mChannels.size > 0) { int index = mChannels.size - 1; Channel ch = mChannels[index]; mChannels.RemoveAt(index); onLeaveChannel(ch.id); } } mChannels.Clear(); mGetChannelsCallbacks.Clear(); mDictionary.Clear(); mTcp.Close(false); mLoadFiles.Clear(); mGetFiles.Clear(); mJoining.Clear(); mIsAdmin = false; if (mLocalServer != null) { mLocalServer.localClient = null; mLocalServer = null; } if (onDisconnect != null) { onDisconnect(); } mConfig = new DataNode("Version", Player.version); break; } case Packet.ResponseGetFileList: { string filename = reader.ReadString(); int size = reader.ReadInt32(); string[] files = null; if (size > 0) { files = new string[size]; for (int i = 0; i < size; ++i) { files[i] = reader.ReadString(); } } OnGetFiles cb = null; if (mGetFiles.TryGetValue(filename, out cb)) { mGetFiles.Remove(filename); } if (cb != null) { try { cb(filename, files); } #if UNITY_EDITOR catch (System.Exception ex) { Debug.LogError(ex.Message + ex.StackTrace); } #else catch (System.Exception) {} #endif } break; } case Packet.ResponseLoadFile: { string filename = reader.ReadString(); int size = reader.ReadInt32(); byte[] data = reader.ReadBytes(size); OnLoadFile cb = null; if (mLoadFiles.TryGetValue(filename, out cb)) { mLoadFiles.Remove(filename); } if (cb != null) { try { cb(filename, data); } #if UNITY_EDITOR catch (System.Exception ex) { Debug.LogError(ex.Message + ex.StackTrace); } #else catch (System.Exception) {} #endif } break; } case Packet.ResponseVerifyAdmin: { int pid = reader.ReadInt32(); Player p = GetPlayer(pid); if (p == player) { mIsAdmin = true; } if (onSetAdmin != null) { onSetAdmin(p); } break; } case Packet.ResponseSetServerData: { string path = reader.ReadString(); object obj = reader.ReadObject(); if (obj != null) { DataNode node = mConfig.SetHierarchy(path, obj); if (onSetServerData != null) { onSetServerData(path, node); } } else { DataNode node = mConfig.RemoveHierarchy(path); if (onSetServerData != null) { onSetServerData(path, node); } } break; } case Packet.ResponseChannelList: { if (mGetChannelsCallbacks.Count != 0) { OnGetChannels cb = mGetChannelsCallbacks.Dequeue(); List <Channel.Info> channels = new List <Channel.Info>(); int count = reader.ReadInt32(); for (int i = 0; i < count; ++i) { Channel.Info info = new Channel.Info(); info.id = reader.ReadInt32(); info.players = reader.ReadUInt16(); info.limit = reader.ReadUInt16(); info.hasPassword = reader.ReadBoolean(); info.isPersistent = reader.ReadBoolean(); info.level = reader.ReadString(); info.data = reader.ReadDataNode(); channels.Add(info); } if (cb != null) { cb(channels); } } break; } case Packet.ResponseLockChannel: { int channelID = reader.ReadInt32(); bool isLocked = reader.ReadBoolean(); Channel ch = GetChannel(channelID); if (ch != null) { ch.isLocked = isLocked; } if (onLockChannel != null) { onLockChannel(channelID, isLocked); } break; } } return(true); }
protected virtual void OnSetServerData(string path, DataNode node) { }