public override void Handle(ByteReader data) { A target = Sync.ReadSync <A>(data); B arg0 = Sync.ReadSync <B>(data); C arg1 = Sync.ReadSync <C>(data); int descHash = data.ReadInt32(); var action = func(target, arg0, arg1).Select(t => actionGetter(t)).FirstOrDefault(a => GenText.StableStringHash(a.Method.MethodDesc()) == descHash); action?.Invoke(); }
public static XmlDocument SaveAndReload() { Multiplayer.reloading = true; var worldGridSaved = Find.WorldGrid; var worldRendererSaved = Find.World.renderer; var tweenedPos = new Dictionary <int, Vector3>(); var drawers = new Dictionary <int, MapDrawer>(); var localFactionId = Multiplayer.RealPlayerFaction.loadID; var mapCmds = new Dictionary <int, Queue <ScheduledCommand> >(); var planetRenderMode = Find.World.renderer.wantedMode; var chatWindow = ChatWindow.Opened; var selectedData = new ByteWriter(); Sync.WriteSync(selectedData, Find.Selector.selected.OfType <ISelectable>().ToList()); //RealPlayerFaction = DummyFaction; foreach (Map map in Find.Maps) { drawers[map.uniqueID] = map.mapDrawer; //RebuildRegionsAndRoomsPatch.copyFrom[map.uniqueID] = map.regionGrid; foreach (Pawn p in map.mapPawns.AllPawnsSpawned) { tweenedPos[p.thingIDNumber] = p.drawer.tweener.tweenedPos; } mapCmds[map.uniqueID] = map.AsyncTime().cmds; } mapCmds[ScheduledCommand.Global] = Multiplayer.WorldComp.cmds; Stopwatch watch = Stopwatch.StartNew(); XmlDocument gameDoc = SaveGame(); Log.Message("Saving took " + watch.ElapsedMilliseconds); MapDrawerRegenPatch.copyFrom = drawers; WorldGridCachePatch.copyFrom = worldGridSaved; WorldRendererCachePatch.copyFrom = worldRendererSaved; LoadInMainThread(gameDoc); Multiplayer.RealPlayerFaction = Find.FactionManager.GetById(localFactionId); foreach (Map m in Find.Maps) { foreach (Pawn p in m.mapPawns.AllPawnsSpawned) { if (tweenedPos.TryGetValue(p.thingIDNumber, out Vector3 v)) { p.drawer.tweener.tweenedPos = v; p.drawer.tweener.lastDrawFrame = Time.frameCount; } } m.AsyncTime().cmds = mapCmds[m.uniqueID]; } if (chatWindow != null) { Find.WindowStack.Add_KeepRect(chatWindow); } var selectedReader = new ByteReader(selectedData.ToArray()) { context = new MpContext() { map = Find.CurrentMap } }; Find.Selector.selected = Sync.ReadSync <List <ISelectable> >(selectedReader).NotNull().Cast <object>().ToList(); Find.World.renderer.wantedMode = planetRenderMode; Multiplayer.WorldComp.cmds = mapCmds[ScheduledCommand.Global]; Multiplayer.reloading = false; return(gameDoc); }
public static XmlDocument SaveAndReload() { Multiplayer.reloading = true; var worldGridSaved = Find.WorldGrid; var worldRendererSaved = Find.World.renderer; var tweenedPos = new Dictionary <int, Vector3>(); var drawers = new Dictionary <int, MapDrawer>(); var localFactionId = Multiplayer.RealPlayerFaction.loadID; var mapCmds = new Dictionary <int, Queue <ScheduledCommand> >(); var planetRenderMode = Find.World.renderer.wantedMode; var chatWindow = ChatWindow.Opened; var oldSong = Find.MusicManagerPlay.lastStartedSong; var oldSongTime = Find.MusicManagerPlay.audioSource?.time; var selectedData = new ByteWriter(); Sync.WriteSync(selectedData, Find.Selector.selected.OfType <ISelectable>().ToList()); //RealPlayerFaction = DummyFaction; foreach (Map map in Find.Maps) { drawers[map.uniqueID] = map.mapDrawer; //RebuildRegionsAndRoomsPatch.copyFrom[map.uniqueID] = map.regionGrid; foreach (Pawn p in map.mapPawns.AllPawnsSpawned) { tweenedPos[p.thingIDNumber] = p.drawer.tweener.tweenedPos; } mapCmds[map.uniqueID] = map.AsyncTime().cmds; } mapCmds[ScheduledCommand.Global] = Multiplayer.WorldComp.cmds; Stopwatch watch = Stopwatch.StartNew(); XmlDocument gameDoc = SaveGame(); Log.Message("Saving took " + watch.ElapsedMilliseconds); MapDrawerRegenPatch.copyFrom = drawers; WorldGridCachePatch.copyFrom = worldGridSaved; WorldRendererCachePatch.copyFrom = worldRendererSaved; LoadInMainThread(gameDoc); Multiplayer.RealPlayerFaction = Find.FactionManager.GetById(localFactionId); foreach (Map m in Find.Maps) { foreach (Pawn p in m.mapPawns.AllPawnsSpawned) { if (tweenedPos.TryGetValue(p.thingIDNumber, out Vector3 v)) { p.drawer.tweener.tweenedPos = v; p.drawer.tweener.lastDrawFrame = Time.frameCount; } } m.AsyncTime().cmds = mapCmds[m.uniqueID]; } if (chatWindow != null) { Find.WindowStack.Add_KeepRect(chatWindow); } if (oldSong != null && oldSongTime != null) { // resume previous music track Find.MusicManagerPlay.MusicUpdate(); // seems to need to run for a tick after a reload to avoid null exceptions Find.MusicManagerPlay.ForceStartSong(oldSong, false); Find.MusicManagerPlay.songWasForced = false; // make it look like this song was chosen naturally, so the leadin to the next song is smooth Find.MusicManagerPlay.recentSongs.Dequeue(); Find.MusicManagerPlay.audioSource.time = (float)oldSongTime; } var selectedReader = new ByteReader(selectedData.ToArray()) { context = new MpContext() { map = Find.CurrentMap } }; Find.Selector.selected = Sync.ReadSync <List <ISelectable> >(selectedReader).NotNull().Cast <object>().ToList(); Find.World.renderer.wantedMode = planetRenderMode; Multiplayer.WorldComp.cmds = mapCmds[ScheduledCommand.Global]; Multiplayer.reloading = false; return(gameDoc); }
public static object ReadSyncObject(ByteReader data, SyncType syncType) { MpContext context = data.MpContext(); Map map = context.map; Type type = syncType.type; try { if (typeof(object) == type) { return(null); } if (type.IsByRef) { return(null); } if (syncWorkersEarly.TryGetValue(type, out SyncWorkerEntry syncWorkerEntryEarly)) { object res = null; if (syncWorkerEntryEarly.shouldConstruct || type.IsValueType) { res = Activator.CreateInstance(type); } syncWorkerEntryEarly.Invoke(new ReadingSyncWorker(data), ref res); return(res); } if (syncType.expose) { if (!typeof(IExposable).IsAssignableFrom(type)) { throw new SerializationException($"Type {type} can't be exposed because it isn't IExposable"); } byte[] exposableData = data.ReadPrefixedBytes(); return(ReadExposable.MakeGenericMethod(type).Invoke(null, new[] { exposableData, null })); } if (typeof(ISynchronizable).IsAssignableFrom(type)) { var obj = Activator.CreateInstance(type); ((ISynchronizable)obj).Sync(new ReadingSyncWorker(data)); return(obj); } if (type.IsEnum) { Type enumType = Enum.GetUnderlyingType(type); return(ReadSyncObject(data, enumType)); } if (type.IsArray && type.GetArrayRank() == 1) { Type elementType = type.GetElementType(); ushort length = data.ReadUShort(); Array arr = Array.CreateInstance(elementType, length); for (int i = 0; i < length; i++) { arr.SetValue(ReadSyncObject(data, elementType), i); } return(arr); } if (type.IsGenericType) { var genericTypeDefinition = type.GetGenericTypeDefinition(); if (genericTypeDefinition == typeof(List <>)) { ListType specialList = ReadSync <ListType>(data); if (specialList == ListType.MapAllThings) { return(map.listerThings.AllThings); } if (specialList == ListType.MapAllDesignations) { return(map.designationManager.allDesignations); } Type listType = type.GetGenericArguments()[0]; ushort size = data.ReadUShort(); IList list = (IList)Activator.CreateInstance(type, size); for (int j = 0; j < size; j++) { list.Add(ReadSyncObject(data, listType)); } return(list); } if (genericTypeDefinition == typeof(IEnumerable <>)) { Type element = type.GetGenericArguments()[0]; return(ReadSyncObject(data, typeof(List <>).MakeGenericType(element))); } if (genericTypeDefinition == typeof(Nullable <>)) { bool isNull = data.ReadBool(); if (isNull) { return(null); } bool hasValue = data.ReadBool(); if (!hasValue) { return(Activator.CreateInstance(type)); } Type nullableType = type.GetGenericArguments()[0]; return(Activator.CreateInstance(type, ReadSyncObject(data, nullableType))); } if (genericTypeDefinition == typeof(Dictionary <,>)) { Type[] arguments = type.GetGenericArguments(); Array keys = (Array)ReadSyncObject(data, arguments[0].MakeArrayType()); Array values = (Array)ReadSyncObject(data, arguments[1].MakeArrayType()); IDictionary dictionary = (IDictionary)Activator.CreateInstance(type); for (int i = 0; i < keys.Length; i++) { dictionary.Add(keys.GetValue(i), values.GetValue(i)); } return(dictionary); } } // Def is a special case until the workers can read their own type if (typeof(Def).IsAssignableFrom(type)) { ushort shortHash = data.ReadUShort(); if (shortHash == 0) { return(null); } Def def = (Def)GetDefByIdMethod.MakeGenericMethod(type).Invoke(null, new object[] { shortHash }); if (def == null) { throw new Exception($"Couldn't find {type} with short hash {shortHash}"); } return(def); } // Designators can't be handled by SyncWorkers due to the type change if (typeof(Designator).IsAssignableFrom(type)) { ushort desId = Sync.ReadSync <ushort>(data); type = Sync.designatorTypes[desId]; // Replaces the type! } // Where the magic happens if (syncWorkers.TryGetValue(type, out var syncWorkerEntry)) { object res = null; if (syncWorkerEntry.shouldConstruct || type.IsValueType) { res = Activator.CreateInstance(type); } syncWorkerEntry.Invoke(new ReadingSyncWorker(data), ref res); return(res); } throw new SerializationException("No reader for type " + type); } catch (Exception e) { MpLog.Error($"Error reading type: {type}, {e}"); throw; } }