Beispiel #1
0
 internal void ServerAICSyncOneToAll(AutoConfigBinding targetConfig, object newValue)
 {
     foreach (var user in NetworkUser.readOnlyInstancesList)
     {
         if (user.hasAuthority || (user.connectionToClient != null && Util.ConnectionIsLocal(user.connectionToClient)))
         {
             continue;
         }
         TargetAICSyncOneToAll(user.connectionToClient, targetConfig.modName, targetConfig.configEntry.Definition.Section, targetConfig.configEntry.Definition.Key,
                               TomlTypeConverter.ConvertToString(newValue, targetConfig.propType));
     }
 }
 internal static void Evt_USMSceneLoaded(Scene scene, LoadSceneMode mode)
 {
     AutoConfigBinding.CleanupDirty(false);
 }
Beispiel #3
0
        /// <summary>Binds a property to a BepInEx config file, using reflection and attributes to automatically generate much of the necessary information.</summary>
        public void Bind(PropertyInfo prop, ConfigFile cfl, string modName, string categoryName, AutoConfigAttribute attrib, AutoConfigUpdateActionsAttribute eiattr = null, BindSubDictInfo?subDict = null)
        {
            string errorStr = "AutoItemCfg.Bind on property " + prop.Name + " in category " + categoryName + " failed: ";

            if (!subDict.HasValue)
            {
                if (this.bindings.Exists(x => x.boundProperty == prop))
                {
                    TILER2Plugin._logger.LogError(errorStr + "this property has already been bound.");
                    return;
                }
                if ((attrib.flags & AutoConfigFlags.BindDict) == AutoConfigFlags.BindDict)
                {
                    if (!prop.PropertyType.GetInterfaces().Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IDictionary <,>)))
                    {
                        TILER2Plugin._logger.LogError(errorStr + "BindDict flag cannot be used on property types which don't implement IDictionary.");
                        return;
                    }
                    var kTyp = prop.PropertyType.GetGenericArguments()[1];
                    if (attrib.avb != null && attrib.avbType != kTyp)
                    {
                        TILER2Plugin._logger.LogError(errorStr + "dict value and AcceptableValue types must match (received " + kTyp.Name + " and " + attrib.avbType.Name + ").");
                        return;
                    }
                    if (!TomlTypeConverter.CanConvert(kTyp))
                    {
                        TILER2Plugin._logger.LogError(errorStr + "dict value type cannot be converted by BepInEx.Configuration.TomlTypeConverter (received " + kTyp.Name + ").");
                        return;
                    }
                    var idict = (System.Collections.IDictionary)prop.GetValue(this, null);
                    int ind   = 0;
                    var dkeys = (from object k in idict.Keys
                                 select k).ToList();
                    foreach (object o in dkeys)
                    {
                        Bind(prop, cfl, modName, categoryName, attrib, eiattr, new BindSubDictInfo {
                            key = o, val = idict[o], keyType = kTyp, index = ind
                        });
                        ind++;
                    }
                    return;
                }
            }
            if (!subDict.HasValue)
            {
                if (attrib.avb != null && attrib.avbType != prop.PropertyType)
                {
                    TILER2Plugin._logger.LogError(errorStr + "property and AcceptableValue types must match (received " + prop.PropertyType.Name + " and " + attrib.avbType.Name + ").");
                    return;
                }
                if (!TomlTypeConverter.CanConvert(prop.PropertyType))
                {
                    TILER2Plugin._logger.LogError(errorStr + "property type cannot be converted by BepInEx.Configuration.TomlTypeConverter (received " + prop.PropertyType.Name + ").");
                    return;
                }
            }

            object propObj    = subDict.HasValue ? prop.GetValue(this) : this;
            var    dict       = subDict.HasValue ? (System.Collections.IDictionary)propObj : null;
            var    propGetter = subDict.HasValue ? dict.GetType().GetProperty("Item").GetGetMethod(true)
                : (prop.GetGetMethod(true) ?? prop.DeclaringType.GetProperty(prop.Name)?.GetGetMethod(true));
            var propSetter = subDict.HasValue ? dict.GetType().GetProperty("Item").GetSetMethod(true)
                : (prop.GetSetMethod(true) ?? prop.DeclaringType.GetProperty(prop.Name)?.GetSetMethod(true));
            var propType = subDict.HasValue ? subDict.Value.keyType : prop.PropertyType;

            if (propGetter == null || propSetter == null)
            {
                TILER2Plugin._logger.LogError(errorStr + "property (or IDictionary Item property, if using BindDict flag) must have both a getter and a setter.");
                return;
            }

            string cfgName = attrib.name;

            if (cfgName != null)
            {
                cfgName = ReplaceTags(cfgName, prop, categoryName, subDict);
            }
            else
            {
                cfgName = char.ToUpperInvariant(prop.Name[0]) + prop.Name.Substring(1) + (subDict.HasValue ? ":" + subDict.Value.index : "");
            }

            string cfgDesc = attrib.desc;

            if (cfgDesc != null)
            {
                cfgDesc = ReplaceTags(cfgDesc, prop, categoryName, subDict);
            }
            else
            {
                cfgDesc = "Automatically generated from a C# " + (subDict.HasValue ? "dictionary " : "") + "property.";
            }

            //Matches ConfigFile.Bind<T>(ConfigDefinition configDefinition, T defaultValue, ConfigDescription configDescription)
            var genm = typeof(ConfigFile).GetMethods().First(
                x => x.Name == nameof(ConfigFile.Bind) &&
                x.GetParameters().Length == 3 &&
                x.GetParameters()[0].ParameterType == typeof(ConfigDefinition) &&
                x.GetParameters()[2].ParameterType == typeof(ConfigDescription)
                ).MakeGenericMethod(propType);

            var propValue = subDict.HasValue ? subDict.Value.val : prop.GetValue(this);

            bool allowMismatch = (attrib.flags & AutoConfigFlags.PreventNetMismatch) != AutoConfigFlags.PreventNetMismatch;
            bool deferForever  = (attrib.flags & AutoConfigFlags.DeferForever) == AutoConfigFlags.DeferForever;
            bool deferRun      = (attrib.flags & AutoConfigFlags.DeferUntilEndGame) == AutoConfigFlags.DeferUntilEndGame;
            bool deferStage    = (attrib.flags & AutoConfigFlags.DeferUntilNextStage) == AutoConfigFlags.DeferUntilNextStage;
            bool allowCon      = (attrib.flags & AutoConfigFlags.PreventConCmd) != AutoConfigFlags.PreventConCmd;

            if (deferForever && !allowMismatch)
            {
                cfgDesc += "\nWARNING: THIS SETTING CANNOT BE CHANGED WHILE THE GAME IS RUNNING, AND MUST BE SYNCED MANUALLY FOR MULTIPLAYER!";
            }

            var cfe = (ConfigEntryBase)genm.Invoke(cfl, new[] {
                new ConfigDefinition(categoryName, cfgName),
                propValue,
                new ConfigDescription(cfgDesc, attrib.avb)
            });

            observedFiles[cfl] = System.IO.File.GetLastWriteTime(cfl.ConfigFilePath);

            var newAIC = new AutoConfigBinding {
                boundProperty       = prop,
                allowConCmd         = allowCon && !deferForever && !deferRun,
                allowNetMismatch    = allowMismatch,
                netMismatchCritical = !allowMismatch && deferForever,
                deferType           = deferForever ? AutoConfigBinding.DeferType.NeverAutoUpdate :
                                      (deferRun ? AutoConfigBinding.DeferType.WaitForRunEnd :
                                       (deferStage ? AutoConfigBinding.DeferType.WaitForNextStage :
                                        AutoConfigBinding.DeferType.UpdateImmediately)),
                configEntry          = cfe,
                modName              = modName,
                owner                = this,
                propGetter           = propGetter,
                propSetter           = propSetter,
                propType             = propType,
                onDict               = subDict.HasValue,
                boundKey             = subDict.HasValue ? subDict.Value.key : null,
                updateEventAttribute = eiattr,
                cachedValue          = propValue,
                target               = propObj
            };

            this.bindings.Add(newAIC);

            if (!deferForever)
            {
                var gtyp = typeof(ConfigEntry <>).MakeGenericType(propType);
                var evh  = gtyp.GetEvent("SettingChanged");

                evh.ReflAddEventHandler(cfe, (object obj, EventArgs evtArgs) => {
                    newAIC.UpdateProperty(cfe.BoxedValue);
                });
            }

            if ((attrib.flags & AutoConfigFlags.NoInitialRead) != AutoConfigFlags.NoInitialRead)
            {
                propSetter.Invoke(propObj, subDict.HasValue ? new[] { subDict.Value.key, cfe.BoxedValue } : new[] { cfe.BoxedValue });
                newAIC.cachedValue = cfe.BoxedValue;
            }
        }
 internal static void On_GNMDisconnect(On.RoR2.Networking.GameNetworkManager.orig_Disconnect orig, GameNetworkManager self)
 {
     orig(self);
     AutoConfigBinding.CleanupDirty(true);
 }