public static void Init() { SyncMedCare = Sync.Field(typeof(Pawn), "playerSettings", "medCare"); SyncSelfTend = Sync.Field(typeof(Pawn), "playerSettings", "selfTend"); SyncHostilityResponse = Sync.Field(typeof(Pawn), "playerSettings", "hostilityResponse"); SyncFollowDrafted = Sync.Field(typeof(Pawn), "playerSettings", "followDrafted"); SyncFollowFieldwork = Sync.Field(typeof(Pawn), "playerSettings", "followFieldwork"); SyncInteractionMode = Sync.Field(typeof(Pawn), "guest", "interactionMode"); SyncSlaveInteractionMode = Sync.Field(typeof(Pawn), nameof(Pawn.guest), nameof(Pawn_GuestTracker.slaveInteractionMode)); SyncIdeoForConversion = Sync.Field(typeof(Pawn), nameof(Pawn.guest), nameof(Pawn_GuestTracker.ideoForConversion)); SyncBeCarried = Sync.Field(typeof(Pawn), "health", "beCarriedByCaravanIfSick"); SyncPsychicEntropyLimit = Sync.Field(typeof(Pawn), "psychicEntropy", "limitEntropyAmount"); SyncPsychicEntropyTargetFocus = Sync.Field(typeof(Pawn), "psychicEntropy", "targetPsyfocus").SetBufferChanges(); SyncUseWorkPriorities = Sync.Field(null, "Verse.Current/Game/playSettings", "useWorkPriorities").PostApply(UseWorkPriorities_PostApply); SyncAutoHomeArea = Sync.Field(null, "Verse.Current/Game/playSettings", "autoHomeArea"); SyncAutoRebuild = Sync.Field(null, "Verse.Current/Game/playSettings", "autoRebuild"); SyncDefaultCare = Sync.Fields( null, "Verse.Current/Game/playSettings", nameof(PlaySettings.defaultCareForColonyHumanlike), nameof(PlaySettings.defaultCareForColonyPrisoner), nameof(PlaySettings.defaultCareForColonySlave), nameof(PlaySettings.defaultCareForColonyAnimal), nameof(PlaySettings.defaultCareForNeutralAnimal), nameof(PlaySettings.defaultCareForNeutralFaction), nameof(PlaySettings.defaultCareForHostileFaction) ).SetBufferChanges(); SyncQuestDismissed = Sync.Field(typeof(Quest), nameof(Quest.dismissed)); SyncFactionAcceptRoyalFavor = Sync.Field(typeof(Faction), nameof(Faction.allowRoyalFavorRewards)); SyncFactionAcceptGoodwill = Sync.Field(typeof(Faction), nameof(Faction.allowGoodwillRewards)); var thingFilterTarget = new MultiTarget() { { SyncThingFilters.ThingFilterTarget, "Filter" } }; SyncThingFilterHitPoints = Sync.FieldMultiTarget(thingFilterTarget, "AllowedHitPointsPercents").SetBufferChanges(); SyncThingFilterQuality = Sync.FieldMultiTarget(thingFilterTarget, "AllowedQualityLevels").SetBufferChanges(); SyncBillSuspended = Sync.Field(typeof(Bill), "suspended"); SyncIngredientSearchRadius = Sync.Field(typeof(Bill), "ingredientSearchRadius").SetBufferChanges(); SyncBillSkillRange = Sync.Field(typeof(Bill), "allowedSkillRange").SetBufferChanges(); SyncBillIncludeZone = Sync.Field(typeof(Bill_Production), "includeFromZone"); SyncBillIncludeHpRange = Sync.Field(typeof(Bill_Production), "hpRange").SetBufferChanges(); SyncBillIncludeQualityRange = Sync.Field(typeof(Bill_Production), "qualityRange").SetBufferChanges(); SyncBillPawnRestriction = Sync.Field(typeof(Bill), "pawnRestriction"); SyncZoneLabel = Sync.Field(typeof(Zone), "label"); SyncBillProduction = Sync.Fields( typeof(Bill_Production), null, "repeatMode", "repeatCount", "targetCount", "pauseWhenSatisfied", "unpauseWhenYouHave" ); SyncBillIncludeCriteria = Sync.Fields( typeof(Bill_Production), null, "includeEquipped", "includeTainted", "limitToAllowedStuff" ); SyncDrugPolicyEntry = Sync.Fields( typeof(DrugPolicy), "entriesInt/[]", "allowedForAddiction", "allowedForJoy", "allowScheduled", "takeToInventory" ); SyncDrugPolicyEntryBuffered = Sync.Fields( typeof(DrugPolicy), "entriesInt/[]", "daysFrequency", "onlyIfMoodBelow", "onlyIfJoyBelow" ).SetBufferChanges(); // This depends on the order of AutoSlaughterManager.configs being the same on all clients // The array is initialized using DefDatabase<ThingDef>.AllDefs which shouldn't cause problems though SyncAutoSlaughter = Sync.Fields( typeof(AutoSlaughterManager), "configs/[]", "maxTotal", "maxMales", "maxMalesYoung", "maxFemales", "maxFemalesYoung", "allowSlaughterPregnant" ).PostApply(Autoslaughter_PostApply); SyncTradeableCount = Sync.Field(typeof(MpTransferableReference), "CountToTransfer").SetBufferChanges().PostApply(TransferableCount_PostApply); // 1 SyncBillPaused = Sync.Field(typeof(Bill_Production), nameof(Bill_Production.paused)).SetBufferChanges().SetVersion(1); // 2 SyncOutfitLabel = Sync.Field(typeof(Outfit), "label").SetBufferChanges().SetVersion(2); SyncDrugPolicyLabel = Sync.Field(typeof(DrugPolicy), "label").SetBufferChanges().SetVersion(2); SyncFoodRestrictionLabel = Sync.Field(typeof(FoodRestriction), "label").SetBufferChanges().SetVersion(2); SyncStorytellerDef = Sync.Field(typeof(Storyteller), "def").SetHostOnly().PostApply(StorytellerDef_Post).SetVersion(2); SyncStorytellerDifficultyDef = Sync.Field(typeof(Storyteller), "difficultyDef").SetHostOnly().PostApply(StorytellerDifficultyDef_Post).SetVersion(2); SyncStorytellerDifficulty = Sync.Field(typeof(Storyteller), "difficulty").ExposeValue().SetHostOnly().PostApply(StorytellerDifficulty_Post).SetVersion(2); SyncDryadCaste = Sync.Field(typeof(CompTreeConnection), nameof(CompTreeConnection.desiredMode)); SyncDesiredTreeConnectionStrength = Sync.Field(typeof(CompTreeConnection), nameof(CompTreeConnection.desiredConnectionStrength)); SyncAnimalPenAutocut = Sync.Field(typeof(CompAnimalPenMarker), nameof(CompAnimalPenMarker.autoCut)); SyncNeuralSuperchargerMode = Sync.Field(typeof(CompNeuralSupercharger), nameof(CompNeuralSupercharger.autoUseMode)); }
public static SyncDelegate Register(Type type, string nestedType, string method) { return(Sync.RegisterSyncDelegate(type, nestedType, method)); }
public static SyncDelegate Register(Type inType, string nestedType, string methodName, string[] fields) { return(Sync.RegisterSyncDelegate(inType, nestedType, methodName, fields)); }
/// <summary> /// Returns whether the original should be cancelled /// </summary> public bool DoSync(object target, params object[] args) { if (!Multiplayer.ShouldSync) { return(false); } // todo limit per specific target/argument //if (Utils.MillisNow - lastSendTime < minTime) // return true; LoggingByteWriter writer = new LoggingByteWriter(); MpContext context = writer.MpContext(); writer.LogNode("Sync method " + method.FullDescription()); writer.WriteInt32(syncId); Sync.WriteContext(this, writer); Map map = writer.MpContext().map; if (targetType != null) { Sync.WriteSyncObject(writer, target, targetType); if (context.map is Map newMap) { map = newMap; } } for (int i = 0; i < argTypes.Length; i++) { var argType = argTypes[i]; Sync.WriteSyncObject(writer, args[i], argType); if (argType.contextMap && args[i] is Map contextMap) { map = contextMap; } if (context.map is Map newMap) { if (map != null && map != newMap) { throw new Exception($"SyncMethod map mismatch ({map?.uniqueID} and {newMap?.uniqueID})"); } map = newMap; } } int mapId = map?.uniqueID ?? ScheduledCommand.Global; writer.LogNode("Map id: " + mapId); Multiplayer.PacketLog.nodes.Add(writer.current); Multiplayer.Client.SendCommand(CommandType.Sync, mapId, writer.ToArray()); lastSendTime = Utils.MillisNow; return(true); }
public static SyncMethod Register(Type type, string methodOrPropertyName, SyncType[] argTypes = null) { return(Sync.RegisterSyncMethod(type, methodOrPropertyName, argTypes)); }
public void Add(string methodName, params SyncType[] argTypes) { methods.Add(Sync.Method(null, methodName, argTypes)); }
static object ReadSyncObjectInternal(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; } }
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); }
static MultiplayerStatic() { Native.InitLmfPtr(); // UnityEngine.Debug.Log instead of Verse.Log.Message because the server runs on its own thread ServerLog.info = str => UnityEngine.Debug.Log($"MpServerLog: {str}"); ServerLog.error = str => UnityEngine.Debug.Log($"MpServerLog Error: {str}"); NetDebug.Logger = new ServerLog(); SetUsername(); if (SteamManager.Initialized) { SteamIntegration.InitCallbacks(); } Log.Message($"Multiplayer version {MpVersion.Version}"); Log.Message($"Player's username: {Multiplayer.username}"); var persistentObj = new GameObject(); persistentObj.AddComponent <OnMainThread>(); UnityEngine.Object.DontDestroyOnLoad(persistentObj); MpConnectionState.SetImplementation(ConnectionStateEnum.ClientSteam, typeof(ClientSteamState)); MpConnectionState.SetImplementation(ConnectionStateEnum.ClientJoining, typeof(ClientJoiningState)); MpConnectionState.SetImplementation(ConnectionStateEnum.ClientPlaying, typeof(ClientPlayingState)); MultiplayerData.CollectCursorIcons(); PersistentDialog.BindAll(typeof(Multiplayer).Assembly); using (DeepProfilerWrapper.Section("Multiplayer MpPatches")) Multiplayer.harmony.DoAllMpPatches(); using (DeepProfilerWrapper.Section("Multiplayer patches")) DoPatches(); Log.messageQueue.maxMessages = 1000; DoubleLongEvent(() => { MultiplayerData.CollectDefInfos(); Sync.PostInitHandlers(); }, "Loading"); // Right before the events from HandleCommandLine HandleRestartConnect(); HandleCommandLine(); if (Multiplayer.arbiterInstance) { RuntimeHelpers.RunClassConstructor(typeof(Text).TypeHandle); } using (DeepProfilerWrapper.Section("Multiplayer TakeModDataSnapshot")) JoinData.TakeModDataSnapshot(); using (DeepProfilerWrapper.Section("MultiplayerData PrecacheMods")) MultiplayerData.PrecacheMods(); if (GenCommandLine.CommandLineArgPassed("profiler")) { SimpleProfiler.Print("mp_prof_out.txt"); } }
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); }