/* * Users SHOULD be able to: * Request object creation and assign the object to themselves * Request object ownership change of others' objects if the object is unlocked * Request object deletion of their own objects * * * Users SHOULD NOT be able to: * Request object deletion of others' objects * Create objects and make other players the owner * Request object ownership change of others' objects if the object is locked * Request changing objects' objectID, prefabID, or any other * */ public void ConsiderChangeRequest(MeshPacket p) { if (GetAuthorized() == false) { Debug.LogError("Being asked to change the database when not authorized!"); return; } if (LookupPlayer(p.GetSourcePlayerId()) == null) { Debug.LogError("Change request source player does not exist on the database"); return; } StateChangeTransaction transaction = StateChangeTransaction.ParseSerializedBytes(p.GetContents()); if (transaction.GetChangeType() == StateChange.Addition) { //Check if the desired owner is the packet sender if (p.GetSourcePlayerId() != transaction.GetObjectData().GetOwnerID()) { Debug.LogError("Requested object creation tries to assign to new player: prohibited"); return; } DatabaseChangeResult result = AddObject(transaction.GetObjectData(), true); if (result.success == false) { Debug.LogError("Requested object addition failed: " + result.error); return; } else { game.SpawnObject(result.data); EchoChangeRequest(transaction.GetTransactionID(), result.data, p.GetSourcePlayerId()); } } else if (transaction.GetChangeType() == StateChange.Removal) { //Check if requesting user owns the object if (p.GetSourcePlayerId() != transaction.GetObjectData().GetOwnerID()) { Debug.LogError("User trying to remove an object that doesn't belong to them"); return; } MeshNetworkIdentity localObjectToRemove = LookupObject(transaction.GetObjectData().GetObjectID()); if (localObjectToRemove == null) { Debug.LogError("Couldn't find the object requested to be removed."); return; } DatabaseChangeResult result = RemoveObject(LookupObject(transaction.GetObjectData().GetObjectID()), true); if (result.success == false) { Debug.LogError("Requested object removal failed: " + result.error); return; } else { game.RemoveObject(result.data); EchoChangeRequest(transaction.GetTransactionID(), localObjectToRemove.GetObjectID(), p.GetSourcePlayerId()); } } else if (transaction.GetChangeType() == StateChange.Change) { if (p.GetSourcePlayerId() != transaction.GetObjectData().GetOwnerID()) { Debug.LogError("User trying to change an object that doesn't belong to them"); return; } MeshNetworkIdentity localObjectToChange = LookupObject(transaction.GetObjectData().GetObjectID()); if (localObjectToChange == null) { Debug.LogError("Couldn't find the object requested to be changed."); return; } DatabaseChangeResult result = ChangeObject(LookupObject(transaction.GetObjectData().GetObjectID()), true); if (result.success == false) { Debug.LogError("Requested object change failed: " + result.error); return; } else { EchoChangeRequest(transaction.GetTransactionID(), localObjectToChange.GetObjectID(), p.GetSourcePlayerId()); } } }
//This is called when the authorized database sends an update to this database. //If this object is the authorized database, this should never be called. public void ReceiveDeltaUpdate(DatabaseUpdate dbup) { //TODO: Write safe methods for local addition/deletion etc //TODO: Make sure that network and local references are not confused (StateChange.Change) //TODO: Refactor "override" full update system so that omissions are meaningful foreach (Player p in dbup.playerDelta.Keys) { if (dbup.playerDelta[p] == StateChange.Addition) { AddPlayer(p, false); } else if (dbup.playerDelta[p] == StateChange.Removal) { RemovePlayer(p, false); } else if (dbup.playerDelta[p] == StateChange.Change) { playerList[p.GetUniqueID()].DeepCopyAndApply(p); } else if (dbup.playerDelta[p] == StateChange.Override) //Probably coming from a FullUpdate { Debug.LogError("Received an override update inside a delta update"); } } foreach (MeshNetworkIdentity i in dbup.objectDelta.Keys) { if (dbup.objectDelta[i] == StateChange.Addition) { //If the incoming object is the database, we don't want to create it //(because this script is running off of the already created database!) //We only want to create a recursive link. if (i.GetObjectID() == (ushort)ReservedObjectIDs.DatabaseObject) { DatabaseChangeResult result = AddObject(GetIdentity(), false); if (result.success) { Debug.Log("Successfully added database to database: recursive link achieved"); } } else { DatabaseChangeResult result = AddObject(i, false); if (result.success) { game.SpawnObject(i.GetObjectID()); } } } else if (dbup.objectDelta[i] == StateChange.Removal) { DatabaseChangeResult result = RemoveObject(i, false); if (result.success) { game.RemoveObject(i.GetObjectID()); } } else if (dbup.objectDelta[i] == StateChange.Change) { objectList[i.GetObjectID()].DeepCopyAndApply(i); } else if (dbup.objectDelta[i] == StateChange.Override) //Probably coming from a FullUpdate { Debug.LogError("Received an override update inside a delta update"); } } ushort check = GenerateDatabaseChecksum(playerList, objectList); if (check != dbup.fullHash) { Debug.Log("Database checksum doesn't match: " + check + " vs " + dbup.fullHash + ". Requesting full update."); MeshPacket p = new MeshPacket(new byte[0], PacketType.FullUpdateRequest, GetIdentity().meshnetReference.GetLocalPlayerID(), GetIdentity().GetOwnerID(), GetIdentity().GetObjectID(), GetIdentity().GetObjectID(), GetSubcomponentID()); GetIdentity().RoutePacket(p); } else { //Debug.Log("Delta successful, hash matches"); } }