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));
        }
Beispiel #2
0
 public static SyncDelegate Register(Type type, string nestedType, string method)
 {
     return(Sync.RegisterSyncDelegate(type, nestedType, method));
 }
Beispiel #3
0
 public static SyncDelegate Register(Type inType, string nestedType, string methodName, string[] fields)
 {
     return(Sync.RegisterSyncDelegate(inType, nestedType, methodName, fields));
 }
Beispiel #4
0
        /// <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);
        }
Beispiel #5
0
 public static SyncMethod Register(Type type, string methodOrPropertyName, SyncType[] argTypes = null)
 {
     return(Sync.RegisterSyncMethod(type, methodOrPropertyName, argTypes));
 }
Beispiel #6
0
 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;
            }
        }
Beispiel #8
0
        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);
        }
Beispiel #9
0
        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");
            }
        }
Beispiel #10
0
        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);
        }