/// <summary> /// Loads a plugin descriptor file and fills out a new PluginInfo structure. Throws an exception on failure. /// </summary> /// <param name="PluginFile">The path to the plugin file to load</param> /// <param name="LoadedFrom">Where the plugin was loaded from</param> /// <returns>New PluginInfo for the loaded descriptor.</returns> private static PluginInfo LoadPluginDescriptor(FileInfo PluginFileInfo, PluginInfo.LoadedFromType LoadedFrom) { // Load the file up (JSon format) Dictionary <string, object> PluginDescriptorDict; { string FileContent; using (var StreamReader = new StreamReader(PluginFileInfo.FullName)) { FileContent = StreamReader.ReadToEnd(); } // Parse the Json into a dictionary var CaseSensitiveJSonDict = fastJSON.JSON.Instance.ToObject <Dictionary <string, object> >(FileContent); // Convert to a case-insensitive dictionary, so that we can be more tolerant of hand-typed files PluginDescriptorDict = new Dictionary <string, object>(CaseSensitiveJSonDict, StringComparer.InvariantCultureIgnoreCase); } // File version check long PluginVersionNumber; { // Try to get the version of the plugin object PluginVersionObject; if (!PluginDescriptorDict.TryGetValue("FileVersion", out PluginVersionObject)) { if (!PluginDescriptorDict.TryGetValue("PluginFileVersion", out PluginVersionObject)) { throw new BuildException("Plugin descriptor file '{0}' does not contain a valid FileVersion entry", PluginFileInfo.FullName); } } if (!(PluginVersionObject is long)) { throw new BuildException("Unable to parse the version number of the plugin descriptor file '{0}'", PluginFileInfo.FullName); } PluginVersionNumber = (long)PluginVersionObject; if (PluginVersionNumber > LatestPluginDescriptorFileVersion) { throw new BuildException("Plugin descriptor file '{0}' appears to be in a newer version ({1}) of the file format that we can load (max version: {2}).", PluginFileInfo.FullName, PluginVersionNumber, LatestPluginDescriptorFileVersion); } // @todo plugin: Should we also test the engine version here? (we would need to load it from build.properties) } // NOTE: At this point, we can use PluginVersionNumber to handle backwards compatibility when loading the rest of the file! var PluginInfo = new PluginInfo(); PluginInfo.LoadedFrom = LoadedFrom; PluginInfo.Directory = PluginFileInfo.Directory.FullName; PluginInfo.Name = Path.GetFileName(PluginInfo.Directory); // Determine whether the plugin should be enabled by default object EnabledByDefaultObject; if (PluginDescriptorDict.TryGetValue("EnabledByDefault", out EnabledByDefaultObject) && (EnabledByDefaultObject is bool)) { PluginInfo.bEnabledByDefault = (bool)EnabledByDefaultObject; } // This plugin might have some modules that we need to know about. Let's take a look. { object ModulesObject; if (PluginDescriptorDict.TryGetValue("Modules", out ModulesObject)) { if (!(ModulesObject is Array)) { throw new BuildException("Found a 'Modules' entry in plugin descriptor file '{0}', but it doesn't appear to be in the array format that we were expecting.", PluginFileInfo.FullName); } var ModulesArray = (Array)ModulesObject; foreach (var ModuleObject in ModulesArray) { var ModuleDict = new Dictionary <string, object>((Dictionary <string, object>)ModuleObject, StringComparer.InvariantCultureIgnoreCase); var PluginModuleInfo = new PluginInfo.PluginModuleInfo(); // Module name { // All modules require a name to be set object ModuleNameObject; if (!ModuleDict.TryGetValue("Name", out ModuleNameObject)) { throw new BuildException("Found a 'Module' entry with a missing 'Name' field in plugin descriptor file '{0}'", PluginFileInfo.FullName); } string ModuleName = (string)ModuleNameObject; // @todo plugin: Locate this module right now and validate it? Repair case? PluginModuleInfo.Name = ModuleName; } // Module type { // Check to see if the user specified the module's type object ModuleTypeObject; if (!ModuleDict.TryGetValue("Type", out ModuleTypeObject)) { throw new BuildException("Found a Module entry '{0}' with a missing 'Type' field in plugin descriptor file '{1}'", PluginModuleInfo.Name, PluginFileInfo.FullName); } string ModuleTypeString = (string)ModuleTypeObject; // Check to see if this is a valid type bool FoundValidType = false; foreach (PluginInfo.PluginModuleType PossibleType in Enum.GetValues(typeof(PluginInfo.PluginModuleType))) { if (ModuleTypeString.Equals(PossibleType.ToString(), StringComparison.InvariantCultureIgnoreCase)) { FoundValidType = true; PluginModuleInfo.Type = PossibleType; break; } } if (!FoundValidType) { throw new BuildException("Module entry '{0}' specified an unrecognized module Type '{1}' in plugin descriptor file '{0}'", PluginModuleInfo.Name, ModuleTypeString, PluginFileInfo.FullName); } } // Supported platforms PluginModuleInfo.Platforms = new List <UnrealTargetPlatform>(); // look for white and blacklists object WhitelistObject, BlacklistObject; ModuleDict.TryGetValue("WhitelistPlatforms", out WhitelistObject); ModuleDict.TryGetValue("BlacklistPlatforms", out BlacklistObject); if (WhitelistObject != null && BlacklistObject != null) { throw new BuildException("Found a module '{0}' with both blacklist and whitelist platform lists in plugin file '{1}'", PluginModuleInfo.Name, PluginFileInfo.FullName); } // now process the whitelist if (WhitelistObject != null) { if (!(WhitelistObject is Array)) { throw new BuildException("Found a 'WhitelistPlatforms' entry in plugin descriptor file '{0}', but it doesn't appear to be in the array format that we were expecting.", PluginFileInfo.FullName); } // put the whitelist array directly into the plugin's modulelist ConvertPlatformArrayToList((Array)WhitelistObject, ref PluginModuleInfo.Platforms, PluginFileInfo.FullName); } // handle the blacklist (or lack of blacklist and whitelist which means all platforms) else { // start with all platforms supported foreach (UnrealTargetPlatform Platform in Enum.GetValues(typeof(UnrealTargetPlatform))) { PluginModuleInfo.Platforms.Add(Platform); } // if we want to disallow some platforms, then pull them out now if (BlacklistObject != null) { if (!(BlacklistObject is Array)) { throw new BuildException("Found a 'BlacklistPlatforms' entry in plugin descriptor file '{0}', but it doesn't appear to be in the array format that we were expecting.", PluginFileInfo.FullName); } // put the whitelist array directly into the plugin's modulelist List <UnrealTargetPlatform> Blacklist = new List <UnrealTargetPlatform>(); ConvertPlatformArrayToList((Array)BlacklistObject, ref Blacklist, PluginFileInfo.FullName); // now remove them from the module platform list foreach (UnrealTargetPlatform Platform in Blacklist) { PluginModuleInfo.Platforms.Remove(Platform); } } } object ModuleShouldBuild; if (ModuleDict.TryGetValue("bShouldBuild", out ModuleShouldBuild)) { PluginInfo.bShouldBuild = (Int64)ModuleShouldBuild == 1 ? true : false; } else { PluginInfo.bShouldBuild = true; } if (PluginInfo.bShouldBuild) { // add to list of modules PluginInfo.Modules.Add(PluginModuleInfo); } } } else { // Plugin contains no modules array. That's fine. } } return(PluginInfo); }
/// <summary> /// Loads a plugin descriptor file and fills out a new PluginInfo structure. Throws an exception on failure. /// </summary> /// <param name="PluginFile">The path to the plugin file to load</param> /// <param name="LoadedFrom">Where the plugin was loaded from</param> /// <returns>New PluginInfo for the loaded descriptor.</returns> private static PluginInfo LoadPluginDescriptor( FileInfo PluginFileInfo, PluginInfo.LoadedFromType LoadedFrom ) { // Load the file up (JSon format) Dictionary<string, object> PluginDescriptorDict; { string FileContent; using( var StreamReader = new StreamReader( PluginFileInfo.FullName ) ) { FileContent = StreamReader.ReadToEnd(); } // Parse the Json into a dictionary var CaseSensitiveJSonDict = fastJSON.JSON.Instance.ToObject< Dictionary< string, object > >( FileContent ); // Convert to a case-insensitive dictionary, so that we can be more tolerant of hand-typed files PluginDescriptorDict = new Dictionary<string, object>( CaseSensitiveJSonDict, StringComparer.InvariantCultureIgnoreCase ); } // File version check long PluginVersionNumber; { // Try to get the version of the plugin object PluginVersionObject; if( !PluginDescriptorDict.TryGetValue( "FileVersion", out PluginVersionObject ) ) { if( !PluginDescriptorDict.TryGetValue( "PluginFileVersion", out PluginVersionObject ) ) { throw new BuildException( "Plugin descriptor file '{0}' does not contain a valid FileVersion entry", PluginFileInfo.FullName ); } } if( !( PluginVersionObject is long ) ) { throw new BuildException( "Unable to parse the version number of the plugin descriptor file '{0}'", PluginFileInfo.FullName ); } PluginVersionNumber = (long)PluginVersionObject; if( PluginVersionNumber > LatestPluginDescriptorFileVersion ) { throw new BuildException( "Plugin descriptor file '{0}' appears to be in a newer version ({1}) of the file format that we can load (max version: {2}).", PluginFileInfo.FullName, PluginVersionNumber, LatestPluginDescriptorFileVersion ); } // @todo plugin: Should we also test the engine version here? (we would need to load it from build.properties) } // NOTE: At this point, we can use PluginVersionNumber to handle backwards compatibility when loading the rest of the file! var PluginInfo = new PluginInfo(); PluginInfo.LoadedFrom = LoadedFrom; PluginInfo.Directory = PluginFileInfo.Directory.FullName; PluginInfo.Name = Path.GetFileName(PluginInfo.Directory); // Determine whether the plugin should be enabled by default object EnabledByDefaultObject; if(PluginDescriptorDict.TryGetValue("EnabledByDefault", out EnabledByDefaultObject) && (EnabledByDefaultObject is bool)) { PluginInfo.bEnabledByDefault = (bool)EnabledByDefaultObject; } // This plugin might have some modules that we need to know about. Let's take a look. { object ModulesObject; if( PluginDescriptorDict.TryGetValue( "Modules", out ModulesObject ) ) { if( !( ModulesObject is Array ) ) { throw new BuildException( "Found a 'Modules' entry in plugin descriptor file '{0}', but it doesn't appear to be in the array format that we were expecting.", PluginFileInfo.FullName ); } var ModulesArray = (Array)ModulesObject; foreach( var ModuleObject in ModulesArray ) { var ModuleDict = new Dictionary<string,object>( (Dictionary< string, object >)ModuleObject, StringComparer.InvariantCultureIgnoreCase ); var PluginModuleInfo = new PluginInfo.PluginModuleInfo(); // Module name { // All modules require a name to be set object ModuleNameObject; if( !ModuleDict.TryGetValue( "Name", out ModuleNameObject ) ) { throw new BuildException( "Found a 'Module' entry with a missing 'Name' field in plugin descriptor file '{0}'", PluginFileInfo.FullName ); } string ModuleName = (string)ModuleNameObject; // @todo plugin: Locate this module right now and validate it? Repair case? PluginModuleInfo.Name = ModuleName; } // Module type { // Check to see if the user specified the module's type object ModuleTypeObject; if( !ModuleDict.TryGetValue( "Type", out ModuleTypeObject ) ) { throw new BuildException( "Found a Module entry '{0}' with a missing 'Type' field in plugin descriptor file '{1}'", PluginModuleInfo.Name, PluginFileInfo.FullName ); } string ModuleTypeString = (string)ModuleTypeObject; // Check to see if this is a valid type bool FoundValidType = false; foreach( PluginInfo.PluginModuleType PossibleType in Enum.GetValues( typeof( PluginInfo.PluginModuleType ) ) ) { if( ModuleTypeString.Equals( PossibleType.ToString(), StringComparison.InvariantCultureIgnoreCase ) ) { FoundValidType = true; PluginModuleInfo.Type = PossibleType; break; } } if( !FoundValidType ) { throw new BuildException( "Module entry '{0}' specified an unrecognized module Type '{1}' in plugin descriptor file '{0}'", PluginModuleInfo.Name, ModuleTypeString, PluginFileInfo.FullName ); } } // Supported platforms PluginModuleInfo.Platforms = new List<UnrealTargetPlatform>(); // look for white and blacklists object WhitelistObject, BlacklistObject; ModuleDict.TryGetValue( "WhitelistPlatforms", out WhitelistObject ); ModuleDict.TryGetValue( "BlacklistPlatforms", out BlacklistObject ); if (WhitelistObject != null && BlacklistObject != null) { throw new BuildException( "Found a module '{0}' with both blacklist and whitelist platform lists in plugin file '{1}'", PluginModuleInfo.Name, PluginFileInfo.FullName ); } // now process the whitelist if (WhitelistObject != null) { if (!(WhitelistObject is Array)) { throw new BuildException("Found a 'WhitelistPlatforms' entry in plugin descriptor file '{0}', but it doesn't appear to be in the array format that we were expecting.", PluginFileInfo.FullName); } // put the whitelist array directly into the plugin's modulelist ConvertPlatformArrayToList((Array)WhitelistObject, ref PluginModuleInfo.Platforms, PluginFileInfo.FullName); } // handle the blacklist (or lack of blacklist and whitelist which means all platforms) else { // start with all platforms supported foreach (UnrealTargetPlatform Platform in Enum.GetValues( typeof( UnrealTargetPlatform ) ) ) { PluginModuleInfo.Platforms.Add(Platform); } // if we want to disallow some platforms, then pull them out now if (BlacklistObject != null) { if (!(BlacklistObject is Array)) { throw new BuildException("Found a 'BlacklistPlatforms' entry in plugin descriptor file '{0}', but it doesn't appear to be in the array format that we were expecting.", PluginFileInfo.FullName); } // put the whitelist array directly into the plugin's modulelist List<UnrealTargetPlatform> Blacklist = new List<UnrealTargetPlatform>(); ConvertPlatformArrayToList((Array)BlacklistObject, ref Blacklist, PluginFileInfo.FullName); // now remove them from the module platform list foreach (UnrealTargetPlatform Platform in Blacklist) { PluginModuleInfo.Platforms.Remove(Platform); } } } object ModuleShouldBuild; if( ModuleDict.TryGetValue( "bShouldBuild", out ModuleShouldBuild ) ) { PluginInfo.bShouldBuild = (Int64)ModuleShouldBuild == 1 ? true : false; } else { PluginInfo.bShouldBuild = true; } if (PluginInfo.bShouldBuild) { // add to list of modules PluginInfo.Modules.Add(PluginModuleInfo); } } } else { // Plugin contains no modules array. That's fine. } } return PluginInfo; }