public void receiveUpdate(DatagramIn dg, IDistributedObject distObj, UInt16 field_id) { Debug.Log("Receive update for class " + distObj.getClass() + " field ID" + field_id); // first get the array of fields we'll need to unpack string[] t_fields = DCFile.fieldLookup[field_id]; // next, define an empty array of params the size of the number of fields object[] t_params = new object[t_fields.Length]; // unpack the parameters for (int i = 0; i < t_fields.Length; ++i) { t_params[i] = unserializeType(dg, t_fields[i]); } // finally, use reflection to call the function Type t_type = distObj.GetType(); MethodInfo t_method = t_type.GetMethod(DCFile.fieldNameLookup[field_id]); t_method.Invoke(distObj, t_params); }
public object unserializeType(DatagramIn dg, string type_n) { if (type_n.Contains("int")) { int divideBy = 1; if (type_n.Contains("/")) { string[] divideParts = type_n.Split("/".ToCharArray()); divideBy = Int32.Parse(divideParts[1]); type_n = divideParts[0]; } if (divideBy != 1) { object originalPrim = readPrimitive(dg, type_n); double prim = System.Convert.ToDouble(originalPrim); return(prim / divideBy); } } return(readPrimitive(dg, type_n)); }
// read/write *primitive* types from an Astron stream (e.g.: uint16) // distinguished from a higher level type, such as structs, dclasses, // or uint16%360/100, all of which are made up of primitive types public object readPrimitive(DatagramIn dg, string type_n) { switch (type_n) { case "uint8": return(dg.ReadByte()); case "uint16": return(dg.ReadUInt16()); case "uint32": return(dg.ReadUInt32()); case "uint64": return(dg.ReadUInt64()); case "int8": return(dg.ReadSByte()); case "int16": return(dg.ReadInt16()); case "int32": return(dg.ReadInt32()); case "int64": return(dg.ReadInt64()); case "string": return(dg.ReadString()); case "blob": return(dg.ReadBlob()); case "float64": return(dg.ReadDouble()); default: Debug.Log("Reading Error: Type '" + type_n + "' is not a primitive"); return(null); } }
public void unserializeClass(DatagramIn dg, SerializationLevel level, bool owner, bool optionals) { // since it's the same for all the messages, quickly unpack the header UInt32 do_id = dg.ReadUInt32(); UInt32 parent_id = dg.ReadUInt32(); UInt32 zone_id = dg.ReadUInt32(); UInt16 dclass_id = dg.ReadUInt16(); string class_n = DCFile.DCRoot[dclass_id]; // when unpacking a class, there are two phases: // 1) unpacking the required fields (required modifiers are defined by level) // and 2) unpacking optional fields string r_class_n = owner ? class_n + "OV" : class_n; Type t = Type.GetType(r_class_n); IDistributedObject distObj; if (t.IsSubclassOf(typeof(DistributedUnityObject))) { Debug.Log("DistributedUnityObject instantiated of type " + t); GameObject prefab; try { prefab = prefabs[r_class_n]; } catch (Exception e) { Debug.LogException(e); return; } GameObject gameObject = UnityEngine.Object.Instantiate(prefab) as GameObject; distObj = gameObject.GetComponent <MonoBehaviour>() as IDistributedObject; } else { Debug.Log("DistributedObject instantiated of type " + t); distObj = Activator.CreateInstance(t) as IDistributedObject; } distObj.setCR(this); // give it some context distObj.setDoID(do_id); distObj.setLocation(new Location(zone_id, parent_id)); // to unpack required fields, first get a list of all fields UInt16[] field_list = DCFile.classLookup[class_n]; // next, iterate through the fields to find required fields for (int i = 0; i < field_list.Length; ++i) { string[] modifiers = DCFile.fieldModifierLookup[field_list[i]]; if (Array.IndexOf(modifiers, "required") > -1) { if (level == SerializationLevel.REQUIRED) { // go ahead, receive the update receiveUpdate(dg, distObj, field_list[i]); } else if (level == SerializationLevel.REQUIRED_BCAST) { // only if it contains broadcast if (Array.IndexOf(modifiers, "broadcast") > -1) { receiveUpdate(dg, distObj, field_list[i]); } } else if (level == SerializationLevel.REQUIRED_BCAST_OR_OWNRECV) { // it either needs to contain broadcast OR ownrecv if ((Array.IndexOf(modifiers, "broadcast") > -1) || (Array.IndexOf(modifiers, "ownrecv") > -1)) { receiveUpdate(dg, distObj, field_list[i]); } } } } // without optionals, we'd be done // however, unpacking optionals is significantly easier // because we don't care about modifiers. // assume the server is sending fields we understand if (optionals) { UInt16 numOptionals = dg.ReadUInt16(); for (int o = 0; o < numOptionals; ++o) { receiveUpdate(dg, distObj, dg.ReadUInt16()); } } if (owner) { ovId2ov.Add(do_id, distObj); } else { doId2do.Add(do_id, distObj); } }
private void onData(MemoryStream data) { DatagramIn reader = new DatagramIn(data); UInt16 type = reader.ReadUInt16(); switch ((MessageTypes)type) { case MessageTypes.CLIENT_HELLO_RESP: { Debug.Log("Response to client_hello"); if (onHello != null) { onHello(); } break; } case MessageTypes.CLIENT_EJECT: { UInt16 error_code = reader.ReadUInt16(); string reason = reader.ReadString(); Debug.Log("Ejected Code " + error_code + ": " + reason); if (onEject != null) { onEject(error_code, reason); } break; } case MessageTypes.CLIENT_ADD_INTEREST: { UInt32 context = reader.ReadUInt32(); UInt16 interest_id = reader.ReadUInt16(); UInt32 parent_id = reader.ReadUInt32(); UInt32 zone_id = reader.ReadUInt32(); Interest newInterest = new Interest(context, interest_id, zone_id, parent_id); context2interest.Add(context, newInterest); if (onAddInterest != null) { onAddInterest(newInterest); } break; } case MessageTypes.CLIENT_DONE_INTEREST_RESP: { UInt32 context = reader.ReadUInt32(); UInt16 interest_id = reader.ReadUInt16(); if (onDoneInterest != null) { onDoneInterest(context2interest[context]); } break; } case MessageTypes.CLIENT_ENTER_OBJECT_REQUIRED: { unserializeClass(reader, SerializationLevel.REQUIRED_BCAST, false, false); break; } case MessageTypes.CLIENT_ENTER_OBJECT_REQUIRED_OTHER: { unserializeClass(reader, SerializationLevel.REQUIRED_BCAST, false, true); break; } case MessageTypes.CLIENT_ENTER_OBJECT_REQUIRED_OWNER: { unserializeClass(reader, SerializationLevel.REQUIRED_BCAST_OR_OWNRECV, true, false); break; } case MessageTypes.CLIENT_ENTER_OBJECT_REQUIRED_OTHER_OWNER: { unserializeClass(reader, SerializationLevel.REQUIRED_BCAST_OR_OWNRECV, true, true); break; } case MessageTypes.CLIENT_OBJECT_LOCATION: { UInt32 do_id = reader.ReadUInt32(); UInt32 parent_id = reader.ReadUInt32(); UInt32 zone_id = reader.ReadUInt32(); doId2do[do_id].getLocation().changeLocation(zone_id, parent_id); doId2do[do_id].locationChanged(); break; } case MessageTypes.CLIENT_OBJECT_LEAVING: { UInt32 doId = reader.ReadUInt32(); doId2do[doId].leaving(); // freeing the DO from the doId2do map is done by the leaving method // via the removeDOfromMap function // if the leaving method is overriden, // removeDOfromMap should still be called to prevent memory leaks break; } case MessageTypes.CLIENT_OBJECT_SET_FIELD: { UInt32 doId = reader.ReadUInt32(); UInt16 field_id = reader.ReadUInt16(); receiveUpdate(reader, doId2do[doId], field_id); break; } case MessageTypes.CLIENT_OBJECT_SET_FIELDS: { UInt32 doId = reader.ReadUInt32(); IDistributedObject distObj = doId2do[doId]; UInt16 num_fields = reader.ReadUInt16(); for (int i = 0; i < num_fields; ++i) { UInt16 field_id = reader.ReadUInt16(); receiveUpdate(reader, distObj, field_id); } break; } default: { Debug.Log("Unknown message type: " + type); break; } } }