private static IRemoteTechAPIv1 InitializeAPI() { SafeHouse.Logger.Log(string.Format("Looking for RemoteTech")); var loadedAssembly = AssemblyLoader.loadedAssemblies.FirstOrDefault(a => a.assembly.GetName().Name.Equals(REMOTE_TECH_ASSEMBLY)); if (loadedAssembly == null) { return(null); } SafeHouse.Logger.Log(string.Format("Found RemoteTech! Version: {0}.{1}", loadedAssembly.versionMajor, loadedAssembly.versionMinor)); var type = ReflectUtil.GetLoadedTypes(loadedAssembly.assembly).FirstOrDefault(t => t.FullName.Equals(REMOTE_TECH_API)) ?? ReflectUtil.GetLoadedTypes(loadedAssembly.assembly).FirstOrDefault(t => t.FullName.Equals(ALT_REMOTE_TECH_API)); if (type == null) { return(null); } SafeHouse.Logger.Log(string.Format("Found API! {0} ", type.Name)); var methods = type.GetMethods(); var api = new RemoteTechAPI(); try { foreach (var property in api.GetType().GetProperties()) { var method = methods.FirstOrDefault(m => { if (m.Name.Equals(property.Name)) { SafeHouse.Logger.Log(string.Format("Found Endpoint: {0}", m.Name)); return(true); } return(false); }); if (method == null) { throw new ArgumentNullException(property.Name); } var del = Delegate.CreateDelegate(property.PropertyType, type, method.Name); property.SetValue(api, del, null); } } catch (Exception e) { SafeHouse.Logger.Log("Error creating RemoteTech interface: " + e); return(null); } SafeHouse.Logger.Log("RemoteTech interface successfully created."); return(api); }
/// <summary> /// Ensure all classes implementing IDumper have the required static method in /// them, which is something the compiler cannot enforce itself because an Interface /// can't contain static things. /// </summary> /// Since interfaces don't enforce static things, this enforcement /// is being done via this Reflection check upon loading that will make nag messages /// if the CreateFromDump is missing on one of the classes. /// Note, if we ever need this check elsewhere for another "static" thing in an interface, /// It should be possible to make this more generic and make a library method here that /// takes any interface name and any method name and checks to see if it exists. public static void CheckIDumperStatics() { if (staticsAlreadyChecked) { return; } StringBuilder message = new StringBuilder(1000); Type dumperInterface = typeof(IDumper); // It's ugly to be checking ALL KSP mods here, but just in case someone // extends kOS in another mod, it's not safe to check ONLY kOS.dll and kOS.Safe.dll: Assembly[] allKSPAssemblies = AppDomain.CurrentDomain.GetAssemblies(); // All the classes in which the class is derived from IDumper, and instances of the class are // actually constructable because it isn't Abstract: IEnumerable <Type> iDumperClasses = allKSPAssemblies.SelectMany(a => ReflectUtil.GetLoadedTypes(a)).Where( b => dumperInterface.IsAssignableFrom(b) && b.IsClass && !b.IsAbstract); List <string> offendingClasses = new List <string>(); Type[] paramSignature = new Type[] { typeof(SafeSharedObjects), typeof(Dump) }; foreach (Type t in iDumperClasses) { if (t.GetMethod("CreateFromDump", BindingFlags.Public | BindingFlags.Static, null, paramSignature, null) == null) { offendingClasses.Add(t.FullName); } } if (offendingClasses.Count() > 0) { message.Append( "kOS DEV TEAM ERROR.\n " + " This is a kOS source problem that the compiler\n" + " cannot check for because of limitations in C#.\n" + " (So we check it at runtime and give this error\n" + " if it's detected.)\n" + " \n" + " The following class(es) implement IDumper, but\n" + " lack the required CreateFromDump() static method\n" + " that we need all IDumper's to have:\n" + " "); message.Append(string.Join(", ", offendingClasses.ToArray())); Debug.AddNagMessage(Debug.NagType.NAGFOREVER, message.ToString()); } staticsAlreadyChecked = true; }