public static List <object> Serialize( GameEntity playerEntity, EntityState state, GameSnapshot snapshot, SerializationContext context) { var levelEntity = playerEntity.Position.LevelEntity; if (state == EntityState.Added) { var serializedLevel = LevelSnapshot.Serialize(levelEntity, null, null, context); return(PlayerSnapshot.Serialize(playerEntity, state, null, serializedLevel, context)); } else { if (!snapshot.SerializedLevels.TryGetValue(levelEntity.Id, out var serializedLevel)) { var position = playerEntity.Position; var level = context.DbContext.Entry(position).Property(p => p.LevelId); serializedLevel = LevelSnapshot.Serialize (position.LevelEntity, level.IsModified ? EntityState.Added : state, snapshot.LevelSnapshots.GetValueOrDefault(levelEntity.Id), context); snapshot.SerializedLevels[levelEntity.Id] = serializedLevel; } return(PlayerSnapshot.Serialize( playerEntity, state, snapshot.PlayerSnapshots[playerEntity.Id], serializedLevel, context)); } }
// TODO: Perf: Use change notifications instead public void Snapshot(GameDbContext dbContext, GameServices services) { SerializedLevels.Clear(); var snapshotedLevels = new List <int>(); var manager = dbContext.Manager; foreach (var playerEntity in manager.Players) { var context = new SerializationContext(dbContext, playerEntity, services); var levelEntity = playerEntity.Position.LevelEntity; LevelSnapshot levelSnapshot = null; if (!snapshotedLevels.Contains(levelEntity.Id)) { if (!LevelSnapshots.TryGetValue(levelEntity.Id, out levelSnapshot)) { levelSnapshot = new LevelSnapshot(); LevelSnapshots[levelEntity.Id] = levelSnapshot; } levelSnapshot.Snapshot(levelEntity, context); snapshotedLevels.Add(levelEntity.Id); } if (!PlayerSnapshots.TryGetValue(playerEntity.Id, out var playerSnapshot)) { playerSnapshot = new PlayerSnapshot(); PlayerSnapshots[playerEntity.Id] = playerSnapshot; } playerSnapshot.Snapshot(playerEntity, context); } if (snapshotedLevels.Count != LevelSnapshots.Count) { foreach (var levelId in LevelSnapshots.Keys.ToList()) { if (!snapshotedLevels.Contains(levelId)) { LevelSnapshots.Remove(levelId); } } } if (manager.Players.Count != PlayerSnapshots.Count) { foreach (var playerId in PlayerSnapshots.Keys.ToList()) { if (!manager.Players.ContainsEntity(playerId)) { PlayerSnapshots.Remove(playerId); } } } }
public static List <object> Serialize( GameEntity levelEntity, EntityState?state, LevelSnapshot snapshot, SerializationContext context) { var manager = context.Manager; var level = levelEntity.Level; List <object> properties; switch (state) { case null: case EntityState.Added: var knownTerrain = new List <short>(); for (short j = 0; j < level.KnownTerrain.Length; j++) { var feature = level.KnownTerrain[j]; if (feature != (byte)MapFeature.Unexplored) { knownTerrain.Add(j); knownTerrain.Add(feature); } } var wallNeighbours = new List <short>(); for (short j = 0; j < level.WallNeighbours.Length; j++) { if (level.KnownTerrain[j] == (byte)MapFeature.Unexplored) { continue; } var neighbours = level.WallNeighbours[j] & (byte)DirectionFlags.Cross; if (neighbours != (byte)DirectionFlags.None) { wallNeighbours.Add(j); wallNeighbours.Add((byte)neighbours); } } var visibleTerrain = new List <short>(); for (short j = 0; j < level.VisibleTerrain.Length; j++) { var visibility = level.VisibleTerrain[j]; if (visibility != 0) { visibleTerrain.Add(j); visibleTerrain.Add(visibility); } } properties = state == null ? new List <object>(10) : new List <object>(11) { (int)state }; properties.Add(GetActors(levelEntity, manager) .Select(a => LevelActorSnapshot.Serialize(a, null, context)).ToList()); properties.Add(GetItems(levelEntity, manager) .Select(t => LevelItemSnapshot.Serialize(t, null, null, context)).ToList()); properties.Add(GetConnections(levelEntity, manager) .Select(c => ConnectionSnapshot.Serialize(c, null, context)).ToList()); properties.Add(knownTerrain); properties.Add(wallNeighbours); properties.Add(visibleTerrain); properties.Add(level.BranchName); properties.Add(level.Depth); properties.Add(level.Width); properties.Add(level.Height); return(properties); default: var levelEntry = context.DbContext.Entry(level); properties = new List <object> { (int)state }; var i = 2; var serializedActors = GameTransmissionProtocol.Serialize( GetActors(levelEntity, manager), snapshot.ActorsSnapshot, LevelActorSnapshot.Serialize, context); if (serializedActors.Count > 0) { properties.Add(i); properties.Add(serializedActors); } i++; var serializedItems = GameTransmissionProtocol.Serialize( GetItems(levelEntity, manager), snapshot.ItemsSnapshot, LevelItemSnapshot.Serialize, context); if (serializedItems.Count > 0) { properties.Add(i); properties.Add(serializedItems); } i++; var serializedConnections = GameTransmissionProtocol.Serialize( GetConnections(levelEntity, manager), snapshot.ConnectionsSnapshot, ConnectionSnapshot.Serialize, context); if (serializedConnections.Count > 0) { properties.Add(i); properties.Add(serializedConnections); } if (levelEntry.State != EntityState.Unchanged) { i++; var wallNeighboursChanges = new List <object>(); var knownTerrainChanges = new List <object>(level.KnownTerrainChanges.Count * 2); if (level.KnownTerrainChanges.Count > 0) { foreach (var terrainChange in level.KnownTerrainChanges) { knownTerrainChanges.Add(terrainChange.Key); knownTerrainChanges.Add(terrainChange.Value); wallNeighboursChanges.Add(terrainChange.Key); wallNeighboursChanges.Add(level.WallNeighbours[terrainChange.Key] & (byte)DirectionFlags.Cross); } } if (level.TerrainChanges.Count > 0) { foreach (var terrainChange in level.TerrainChanges) { if (level.VisibleTerrain[terrainChange.Key] == 0) { continue; } knownTerrainChanges.Add(terrainChange.Key); knownTerrainChanges.Add(terrainChange.Value); } } if (knownTerrainChanges.Count > 0) { properties.Add(i); properties.Add(knownTerrainChanges); } i++; if (level.WallNeighboursChanges.Count > 0) { foreach (var wallNeighboursChange in level.WallNeighboursChanges) { if (level.VisibleTerrain[wallNeighboursChange.Key] == 0) { continue; } wallNeighboursChanges.Add(wallNeighboursChange.Key); wallNeighboursChanges.Add(wallNeighboursChange.Value & (byte)DirectionFlags.Cross); } } if (wallNeighboursChanges.Count > 0) { properties.Add(i); properties.Add(wallNeighboursChanges); } i++; if (level.VisibleTerrainChanges.Count > 0) { properties.Add(i); var changes = new object[level.VisibleTerrainChanges.Count * 2]; var j = 0; foreach (var visibleTerrainChange in level.VisibleTerrainChanges) { changes[j++] = visibleTerrainChange.Key; changes[j++] = visibleTerrainChange.Value; } properties.Add(changes); } } return(properties.Count > 1 ? properties : null); } }