// There is a way to do this in which every player related object is destroyed, but server owned objects are a possibility. void ResetGame() { // Reset credits: List <Player> players = GameManager.getPlayersOnTeam(1); foreach (Player player in players) { player.setRandomTrapChoices(); // Resets everyone's traps choices, regardless of team. for (int i = 0; i < player.trapTypes.Length; i++) { player.trapTypes [i] = 255; } } Transform iterator = GameObject.Find("Players").transform; for (int i = 0; i < iterator.childCount; i++) { GameObject plyr = iterator.GetChild(i).gameObject; plyr.GetComponent <Combat>().Kill(OperationNetwork.ServerObject, false); // Overrides phase shift. (Does not record this death). Does not instantly respawn player... hmm.. todo! Note that this could cause an infinite loop as the server player would keep respawning / dieing. } // ALL player made items need to be cleared: iterator = GameObject.Find("PlayerMade").transform; for (int i = 0; i < iterator.childCount; i++) { SyncGameState obj = iterator.GetChild(i).GetComponent <SyncGameState>(); obj.exists = false; } iterator = GameObject.Find("Miscellaneous").transform; for (int i = 0; i < iterator.childCount; i++) { SyncGameState obj = iterator.GetChild(i).GetComponent <SyncGameState>(); obj.exists = false; } }
// Client public TriggerSet(byte[] data, ref int bytePosition, SyncGameState sgg, int tickNumber, bool isPlayerOwner) { short numTriggers = data [bytePosition++]; // It's actually not unviable for it to go >255 because triggers sync for multiple ticks if (numTriggers == 255) { numTriggers = BitConverter.ToInt16(data, bytePosition); bytePosition += 2; } for (int i = 0; i < numTriggers; i++) { byte index = (byte)(data[bytePosition] / 16); int triggerTick = tickNumber - data[bytePosition] % 16; triggerIndecies.Add(index); triggerTickNumbers.Add(triggerTick); bytePosition++; triggerData.Add(sgg.getTriggerData(index, data, ref bytePosition, isPlayerOwner)); } lastTickReceived = tickNumber; }
// INTERP // Note that every "GameState" will be a at least once in standard game play. "a, percent=0" public static void interp(GameState a, GameState b, float percent, bool isThisFirstTick, bool isThisMine) { // Turns out, the most relevant factor is what exists in the world versus what has been removed in a.objectsID. The gameState includes ALL the gameObjects with ALL the objects. // "changedInfo" is not used client side. // It is assumed the world previous is either correct or empty, (this assumption is valid) if (isThisFirstTick) { for (int i = 0; i < a.objectIDs.Count; i++) { if (a.objectIDs [i] >= OperationNetwork.operationObjects.Count) { while (a.objectIDs [i] > OperationNetwork.operationObjects.Count) { // This is called when you connect to a server because the IDs have already shifted OperationNetwork.operationObjects.Add(null); } SyncGameState added = MonoBehaviour.Instantiate(OperationNetwork.instantiatableObjects [a.objectTypes [i]]).GetComponent <SyncGameState> (); added.InitStart(isThisMine); OperationNetwork.operationObjects.Add(added); } else if (OperationNetwork.operationObjects [a.objectIDs [i]] == null) { SyncGameState added = MonoBehaviour.Instantiate(OperationNetwork.instantiatableObjects [a.objectTypes [i]]).GetComponent <SyncGameState> (); added.InitStart(isThisMine); OperationNetwork.operationObjects [a.objectIDs [i]] = added; } else if (OperationNetwork.operationObjects [a.objectIDs [i]].objectType != a.objectTypes [i]) { Debug.LogError("Failure To Destroy! GameState -> interp"); } SyncGameState sgs = OperationNetwork.operationObjects [a.objectIDs [i]]; sgs.objectID = a.objectIDs [i]; //objectType is already set, (and is not really used) if (!a.objectExists [i]) { try { sgs.OnDeath(); } catch (Exception e) { Debug.LogError("Error on death: " + e.StackTrace); } MonoBehaviour.Destroy(sgs.gameObject); OperationNetwork.operationObjects [a.objectIDs [i]] = null; } else { if (b == null || percent == 0) { sgs.interp(a.netInformation [i], null, percent, isThisFirstTick, isThisMine); } else { // Find b: (b must exist as it wasn't destroyed last tick) int bI = b.objectIDs.IndexOf(a.objectIDs [i]); sgs.interp(a.netInformation [i], b.netInformation [bI], percent, isThisFirstTick, isThisMine); } } } } else { // No onDestroy or onFirstTick stuff here, as no destruction / instantiation. for (int i = 0; i < a.objectIDs.Count; i++) { if (OperationNetwork.operationObjects [a.objectIDs [i]]) { SyncGameState sgs = OperationNetwork.operationObjects [a.objectIDs [i]]; if (b == null || percent == 0) { sgs.interp(a.netInformation [i], null, percent, isThisFirstTick, isThisMine); } else { // Find b: (b must exist as it wasn't destroyed last tick) int bI = b.objectIDs.IndexOf(a.objectIDs [i]); sgs.interp(a.netInformation [i], b.netInformation [bI], percent, isThisFirstTick, isThisMine); } } } } // Irrelivant if operation }
public override SyncableType createThis(byte[] data, ref int bytePosition, SyncGameState sgg, int tickNumber, bool isPlayerOwner) { return(new YRotation(data, ref bytePosition)); }
// Static class devoted to methods that were originally in SyncGameState that involve the interpreting & representing of byte data into objects. public static object interpretObject(byte[] data, ref int bytePosition, object type, SyncGameState sgg, int tickNumber, bool isPlayerOwner) { object returnObject = null; if (type is float) { returnObject = BitConverter.ToSingle(data, bytePosition); bytePosition += 4; } else if (type is int) { returnObject = BitConverter.ToInt32(data, bytePosition); bytePosition += 4; } else if (type is short) { returnObject = BitConverter.ToInt16(data, bytePosition); bytePosition += 2; } else if (type is byte) { returnObject = data [bytePosition]; bytePosition += 1; } else if (type is Vector3) // Equals feels like good usage here. { returnObject = OperationNetwork.getVector3(data, bytePosition); bytePosition += 12; } else if (type is bool) { returnObject = BitConverter.ToBoolean(data, bytePosition); bytePosition += 1; } else if (type is Quaternion) { returnObject = OperationNetwork.getQuaternion(data, bytePosition); bytePosition += 16; } else if (type is string) { // All strings have max 255 length. // Just because. byte length = data [bytePosition]; bytePosition += 1; returnObject = Encoding.ASCII.GetString(data, bytePosition, length); bytePosition += length; } else if (type is float[]) { byte length = data [bytePosition]; // Max 255 length bytePosition += 1; returnObject = new float[length]; for (int i = 0; i < length; i++) { ((float[])returnObject) [i] = BitConverter.ToSingle(data, bytePosition); bytePosition += 4; } } else if (type is Vector3[]) { byte length = data [bytePosition]; // Max 255 length bytePosition += 1; returnObject = new Vector3[length]; for (int i = 0; i < length; i++) { ((Vector3[])returnObject) [i] = OperationNetwork.getVector3(data, bytePosition); bytePosition += 12; } } else if (type is Vector3[][]) { // Hitscan data: byte length = data [bytePosition]; bytePosition += 1; returnObject = new Vector3[length][]; for (int i = 0; i < length; i++) { ((Vector3[][])returnObject) [i] = (Vector3[])interpretObject(data, ref bytePosition, new Vector3[0], null, -1, false); } } else if (type is SyncableType) { returnObject = ((SyncableType)type).createThis(data, ref bytePosition, sgg, tickNumber, isPlayerOwner); } else if (type is DamageNumber[]) { byte length = data [bytePosition]; // Max 255 length bytePosition += 1; returnObject = new DamageNumber[length]; for (int i = 0; i < length; i++) { ((DamageNumber[])returnObject) [i] = new DamageNumber(data, ref bytePosition); } } else if (type is byte[]) { byte length = data [bytePosition]; // Max 255 length bytePosition += 1; returnObject = new byte[length]; for (int i = 0; i < length; i++) { ((byte[])returnObject) [i] = data[bytePosition]; bytePosition += 1; } } return(returnObject); }
// Client side: This implementation is to avoid reflection, and to avoid having to write additional code within SyncGameState public abstract SyncableType createThis(byte[] data, ref int bytePosition, SyncGameState sgg, int tickNumber, bool isPlayerOwner);