internal static void Register(Dec instance) { CachedList = null; SuppressEmptyWarning(); Type registrationType = instance.GetType(); while (true) { var dbType = typeof(Database <>).MakeGenericType(new[] { registrationType }); Databases.Add(dbType); var regFunction = dbType.GetMethod("Register", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic); regFunction.Invoke(null, new[] { instance }); // We'll just rely on Database<T> to generate the relevant errors if we're overwriting something GetLookupFor(registrationType)[instance.DecName] = instance; if (registrationType.GetDecDatabaseStatus() == UtilType.DecDatabaseStatus.Root) { break; } registrationType = registrationType.BaseType; } }
internal static void Unregister(Dec instance) { CachedList = null; Type registrationType = instance.GetType(); while (true) { var dbType = typeof(Database <>).MakeGenericType(new[] { registrationType }); Databases.Add(dbType); var regFunction = dbType.GetMethod("Unregister", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic); regFunction.Invoke(null, new[] { instance }); var lookup = GetLookupFor(registrationType); if (lookup.TryGetValue(instance.DecName) == instance) { // It's possible this fails if we've clobbered the database with accidental overwrites from an xml file, but, well, what can you do I guess lookup.Remove(instance.DecName); } if (registrationType.GetDecDatabaseStatus() == UtilType.DecDatabaseStatus.Root) { break; } registrationType = registrationType.BaseType; } }
public override void WriteDec(Dec value) { if (value != null) { WriteToken($"Dec.Database<{value.GetType().ComposeCSFormatted()}>.Get(\"{value.DecName}\")"); } else { WriteExplicitNull(); } }
/// <summary> /// Deletes an existing dec. /// </summary> /// <remarks> /// This exists mostly for the Composer functionality. It is generally not recommended to use this during actual gameplay. /// /// At this time, this will not unregister existing Indexes. This behavior may change at some point in the future. /// </remarks> public static void Delete(Dec dec) { // Anyone using these functions hopefully knows what they're doing SuppressEmptyWarning(); if (Get(dec.GetType(), dec.DecName) != dec) { Dbg.Err($"Attempting to delete {dec} when it either has already been deleted or never existed"); return; } Unregister(dec); }
/// <summary> /// Renames an existing dec. /// </summary> /// <remarks> /// This exists mostly for the Composer functionality. It is generally not recommended to use this during actual gameplay. /// </remarks> public static void Rename(Dec dec, string decName) { // Anyone using these functions hopefully knows what they're doing SuppressEmptyWarning(); if (Get(dec.GetType(), dec.DecName) != dec) { Dbg.Err($"Attempting to rename what used to be {dec} but is no longer a registered Dec"); return; } if (dec.DecName != decName && Get(dec.GetType().GetDecRootType(), decName) != null) { Dbg.Err($"Attempting to rename {dec} to {decName} when it already exists"); return; } Unregister(dec); dec.DecName = decName; Register(dec); }
internal static object ParseString(string text, Type type, object model, string inputName, int lineNumber) { // Special case: Converter override // This is redundant if we're being called from ParseElement, but we aren't always. if (Converters.ContainsKey(type)) { object result; try { result = Converters[type].FromString(text, type, inputName, lineNumber); } catch (Exception e) { Dbg.Ex(e); if (type.IsValueType) { result = Activator.CreateInstance(type); } else { result = null; } } if (result != null && !type.IsAssignableFrom(result.GetType())) { Dbg.Err($"{inputName}:{lineNumber}: Converter {Converters[type].GetType()} for {type} returned unexpected type {result.GetType()}"); return(null); } return(result); } // Special case: decs if (typeof(Dec).IsAssignableFrom(type)) { if (type.GetDecRootType() == null) { Dbg.Err($"{inputName}:{lineNumber}: Non-hierarchy decs cannot be used as references"); return(null); } if (text == "" || text == null) { // you reference nothing, you get the null return(null); } else { Dec result = Database.Get(type, text); if (result == null) { // This feels very hardcoded, but these are also *by far* the most common errors I've seen, and I haven't come up with a better and more general solution if (text.Contains(" ")) { Dbg.Err($"{inputName}:{lineNumber}: Dec name \"{text}\" is not a valid identifier; consider removing spaces"); } else if (text.Contains("\"")) { Dbg.Err($"{inputName}:{lineNumber}: Dec name \"{text}\" is not a valid identifier; consider removing quotes"); } else if (!Parser.DecNameValidator.IsMatch(text)) { Dbg.Err($"{inputName}:{lineNumber}: Dec name \"{text}\" is not a valid identifier; dec identifiers must be valid C# identifiers"); } else { Dbg.Err($"{inputName}:{lineNumber}: Couldn't find {type} named {text}"); } } return(result); } } // Special case: types if (type == typeof(Type)) { if (text == "") { return(null); } return(UtilType.ParseDecFormatted(text, inputName, lineNumber)); } // Various non-composite-type special-cases if (text != "") { // If we've got text, treat us as an object of appropriate type try { return(TypeDescriptor.GetConverter(type).ConvertFromInvariantString(text)); } catch (System.Exception e) // I would normally not catch System.Exception, but TypeConverter is wrapping FormatException in an Exception for some reason { Dbg.Err($"{inputName}:{lineNumber}: {e.ToString()}"); return(model); } } else if (type == typeof(string)) { // If we don't have text, and we're a string, return "" return(""); } else { // If we don't have text, and we've fallen down to this point, that's an error (and return original value I guess) Dbg.Err($"{inputName}:{lineNumber}: Empty field provided for type {type}"); return(model); } }
public abstract void WriteDec(Dec value);