sceneID buildIndex byte replaced with scenePath hash and sceneID converted to long to fix #571, #577

This commit is contained in:
vis2k 2019-03-14 11:26:19 +01:00
parent ca69cb9c14
commit 1824e8db80
4 changed files with 32 additions and 30 deletions

View File

@ -32,7 +32,7 @@ public static void OnPostProcessScene()
if (identity.isClient || identity.isServer)
continue;
// valid scene id? then set build index byte
// valid scene id? then set scene path part
// otherwise it might be an unopened scene that still has null
// sceneIds. builds are interrupted if they contain 0 sceneIds,
// but it's still possible that we call LoadScene in Editor
@ -41,7 +41,7 @@ public static void OnPostProcessScene()
// because this function would return afterwards.
if (identity.sceneId != 0)
{
identity.SetSceneIdSceneIndexByteInternal();
identity.SetSceneIdSceneHashPartInternal();
}
else Debug.LogError("Scene " + identity.gameObject.scene.path + " needs to be opened and resaved, because the scene object " + identity.name + " has no valid sceneId yet.");

View File

@ -19,7 +19,7 @@ public static class ClientScene
public static Dictionary<Guid, GameObject> prefabs = new Dictionary<Guid, GameObject>();
// scene id to NetworkIdentity
public static Dictionary<uint, NetworkIdentity> spawnableObjects;
public static Dictionary<ulong, NetworkIdentity> spawnableObjects;
// spawn handlers
internal static Dictionary<Guid, SpawnDelegate> spawnHandlers = new Dictionary<Guid, SpawnDelegate>();
@ -172,7 +172,7 @@ public static void PrepareToSpawnSceneObjects()
.ToDictionary(identity => identity.sceneId, identity => identity);
}
internal static NetworkIdentity SpawnSceneObject(uint sceneId)
internal static NetworkIdentity SpawnSceneObject(ulong sceneId)
{
if (spawnableObjects.TryGetValue(sceneId, out NetworkIdentity identity))
{
@ -441,7 +441,7 @@ internal static void OnSpawnSceneObject(NetworkConnection conn, SpawnSceneObject
{
Debug.LogError("Spawn scene object not found for " + msg.sceneId + " SpawnableObjects.Count=" + spawnableObjects.Count);
// dump the whole spawnable objects dict for easier debugging
foreach (KeyValuePair<uint, NetworkIdentity> kvp in spawnableObjects)
foreach (KeyValuePair<ulong, NetworkIdentity> kvp in spawnableObjects)
Debug.Log("Spawnable: SceneId=" + kvp.Key + " name=" + kvp.Value.name);
return;
}

View File

@ -220,7 +220,7 @@ public override void Serialize(NetworkWriter writer)
class SpawnSceneObjectMessage : MessageBase
{
public uint netId;
public uint sceneId;
public ulong sceneId;
public Vector3 position;
public Quaternion rotation;
public byte[] payload;
@ -228,7 +228,7 @@ class SpawnSceneObjectMessage : MessageBase
public override void Deserialize(NetworkReader reader)
{
netId = reader.ReadPackedUInt32();
sceneId = reader.ReadPackedUInt32();
sceneId = reader.ReadUInt64();
position = reader.ReadVector3();
rotation = reader.ReadQuaternion();
payload = reader.ReadBytesAndSize();
@ -237,7 +237,7 @@ public override void Deserialize(NetworkReader reader)
public override void Serialize(NetworkWriter writer)
{
writer.WritePackedUInt32(netId);
writer.WritePackedUInt32(sceneId);
writer.Write(sceneId);
writer.Write(position);
writer.Write(rotation);
writer.WriteBytesAndSize(payload);

View File

@ -43,7 +43,7 @@ public bool isServer
public Dictionary<int, NetworkConnection> observers;
public uint netId { get; internal set; }
public uint sceneId => m_SceneId;
public ulong sceneId => m_SceneId;
public bool serverOnly { get { return m_ServerOnly; } set { m_ServerOnly = value; } }
public bool localPlayerAuthority { get { return m_LocalPlayerAuthority; } set { m_LocalPlayerAuthority = value; } }
public NetworkConnection clientAuthorityOwner { get; internal set; }
@ -89,11 +89,12 @@ internal set
}
}
// persistent scene id
[SerializeField] uint m_SceneId = 0;
// persistent scene id <sceneHash/32,sceneId/32>
// (see AssignSceneID comments)
[SerializeField] ulong m_SceneId = 0;
// keep track of all sceneIds to detect scene duplicates
static Dictionary<uint, NetworkIdentity> sceneIds = new Dictionary<uint, NetworkIdentity>();
static Dictionary<ulong, NetworkIdentity> sceneIds = new Dictionary<ulong, NetworkIdentity>();
// used when adding players
internal void SetClientOwner(NetworkConnection conn)
@ -261,10 +262,10 @@ void AssignSceneID()
// -> we need to call it before changing.
Undo.RecordObject(this, "Generated SceneId");
// generate random sceneId
// range: 3 bytes to fill 0x00FFFFFF
// generate random sceneId part (0x00000000FFFFFFFF)
// -> exclude '0' because that's for unassigned sceneIDs
m_SceneId = (uint)UnityEngine.Random.Range(1, 0xFFFFFF);
// TODO use 0,uint.max later. Random.Range only has int version.
m_SceneId = (uint)UnityEngine.Random.Range(1, int.MaxValue);
Debug.Log(name + " in scene=" + gameObject.scene.name + " sceneId assigned to: " + m_SceneId.ToString("X") + (duplicate ? " because duplicated" : ""));
}
@ -274,29 +275,30 @@ void AssignSceneID()
sceneIds[m_SceneId] = this;
}
// copy scene build index into sceneId for scene objects.
// copy scene path hash into sceneId for scene objects.
// this is the only way for scene file duplication to not contain
// duplicate sceneIds as it seems.
// -> sceneId before: 0x00AABBCCDD
// -> then we clear the left most byte, so that our 'OR' uses 0x00
// -> then we OR buildIndex into the 0x00 part
// -> sceneId before: 0x00000000AABBCCDD
// -> then we clear the left 4 bytes, so that our 'OR' uses 0x00000000
// -> then we OR the hash into the 0x00000000 part
// -> buildIndex is not enough, because Editor and Build have different
// build indices if there are disabled scenes in build settings, and
// if no scene is in build settings then Editor and Build have
// different indices too (Editor=0, Build=-1)
// => ONLY USE THIS FROM POSTPROCESSSCENE!
public void SetSceneIdSceneIndexByteInternal()
public void SetSceneIdSceneHashPartInternal()
{
// get build index
// -> if the scene is not in build settings, then a build would
// have buildIndex '-1', but pressing Play in the Editor would
// have a buildIndex '0', which would always get sceneIds out of
// sync if we didn't add the scene to build settings.
// -> let's always use at least '0', which is what unity Editor does
// internally as it seems.
byte buildIndex = (byte)Mathf.Max(gameObject.scene.buildIndex, 0);
// get deterministic scene hash
uint pathHash = (uint)gameObject.scene.path.GetStableHashCode();
// shift hash from 0x000000FFFFFFFF to 0xFFFFFFFF00000000
ulong shiftedHash = (ulong)pathHash << 32;
// OR into scene id
m_SceneId = (m_SceneId & 0x00FFFFFF) | (uint)(buildIndex << 24);
m_SceneId = (m_SceneId & 0xFFFFFFFF) | shiftedHash;
// log it. this is incredibly useful to debug sceneId issues.
Debug.Log(name + " in scene=" + gameObject.scene.name + " scene index byte(" + buildIndex.ToString("X") + ") copied into sceneId: " + m_SceneId.ToString("X"));
Debug.Log(name + " in scene=" + gameObject.scene.name + " scene index hash(" + pathHash.ToString("X") + ") copied into sceneId: " + m_SceneId.ToString("X"));
}
void SetupIDs()