Outdated - The new system makes use of a single 3rdparty.json file. Please see this post for the new tool, but the concepts talked about in this thread are still relevant: https://www.thebuddyforum.com/threads/exilebuddy-3-0-reference-thread.406684/#post-2523724
[About]
As Exilebuddy continues to grow and evolve, we're always looking for better ways to do things so life is easier for everyone. One area that has been in need of improvement is how 3rd party code is distributed by users and loaded by the bot. Right now, users must download compressed files, extract them in a specific location, ensure the folder name is correct for the assembly, and then manage keeping things up-to-date. This works, but is the cause for a lot of inconvenience on both the users and devs, which results in more support issues we have to handle.
This thread will go over a new system we've been working on to greatly simplify the way things are. I should start out by mentioning the current system in place will continue to work as-is and will not change, as we do not want to force this new setup on everyone, but rather let them transition to it at their own pace. However, barring unforeseen side-effects, we'd expect everyone to adopt this system because it will make life easier all around, and requires little extra work for devs to make work.
[Devs]
Please keep in mind the current BosslandGmbH Forum Rules & Guidelines still apply!
There's two main things devs need to do to make use of this new system. First, they need to create a text file, "3rdparty.txt" in their root content folder. The contents of this file simply need to be the exact assembly name of their content, as the bot uses this to create the folder and compile the code.
For example: The current MapRunner plugin is distributed as "MapRunner1.6.2.zip". If you open this file, you'll see a subfolder, "MapRunner". "3rdparty.txt" would go inside the "MapRunner" sub-folder, as the root folder is where all the main content is. The contents of "3rdparty.txt" would simply be "MapRunner".
Another example: The current AIF plugin is distributed as "AdvancedItemFilter 1.0.2.3.zip". If you open this file, you'll see the main content, so "3rdparty.txt" would go into the zip itself and not any other folders. The contents of "3rdparty.txt" would simply be "AdvancedItemFilter".
For any 3rd party content that does not make use of external non-code files, such as images, or data files, their zips would now be compatible and ready to use with the system. 3rd party content which make use of external non-code files will need to update how they reference said files.
To simplify this process, the new ThirdPartyLoader exposes an API function, GetInstance, that allows users to get a ThirdPartyInstance object that stores all the relevant information they will need need. The ThirdPartyInstance object exposes the Name of the instance, the ContentPath and CompiledPath, as well as instances for the various types: BotInstances, PluginInstances, RoutineInstances.
For example, the current AIF code for loading images, works as follows:
This code works in the current setup, because plugins go into the Plugins folder, and the AIF folder should be named, AdvancedItemFilter, so the path should exist if the user extracted correctly. In the new system, this code would not work because the paths are different. This is how the code would look if it were to be compatible with the new system:
In that code, the AIF instance is loaded from the ThirdPartyLoader. Devs should obviously check for null in case their code is not being used from the ThirdPartyLoader. Once the instance is obtained, the ContentPath provides the new root content folder for the assembly, so any data files can be referenced from that.
Those are the only two changes required to make things work. Some plugins might need a few more changes, because there's no post detailing best practices for 3rd party code, but I'll work on making such guides in the near future. The biggest difference is that there's no specific load order for Bots/Plugins/Routines, so if your Routine or Plugin assumed there was a bot already loaded and selected, that would no longer be the case. The solution for that is to defer such logic so it only executes in Start, where the current bot will be valid.
Support has now been added for loading content via folders. This means you can load 3rd party content from folders the same way as the current Bots/Plugins/Routines layout does, without having to make a zip file. The folder layout has to mirror the zip layout; you need a "3rdparty.txt" file in your content folder's root, so the files get copied into the locations they should be.
[End-Users]
End users will simply have to open up the "3rdParty" folder Exilebuddy creates, and copy over compatible zip files of the 3rd party content they want to use. That's it! It's best to start with a clean bot installation, to avoid having old copies of 3rd party content in the Bots/Plugins/Routines folder though. Non-compatible zips (those that do not contain a "3rdparty.txt" file) will simply be ignored.
To update 3rd party content, users will just need to delete the old zip file, then copy over the new one. The bot will take care of cleaning up the old content and extracting the new.
There are no more Bots/Plugins/Routines folders for users to deal with. Content will be auto-extracted to a base path of "3rdParty/ConfigurationName/AssemblyName". A "Content" folder will hold all of the extracted content. A "Compiled" folder will hold the compiled artifacts the bot generates and loads.
This structure is used so people can continue to use multiple bots from the same folder, and it solves the issue of simultaneously running bots at the same time, as each bot will need it's own configuration name regardless. Furthermore, only the active configuration's folder contents will be affected, avoiding an issue where in the current setup, all folders are deleted and any files in use are simply ignored.
Users that wish to make changes to 3rd party source code still can, with a few caveats. First, they must run the bot to have the content extracted. The "Content" folder is deleted and replaced when the 3rd party content zip changes. This is tracked by a file placed in each "Content" directory, "do_not_delete.txt". This text file contains the MD5 hash of the zip file, so when it does not match, the current "Content" folder is deleted, and the new zip archive will be extracted in place of it. If a user deletes the "do_not_delete.txt" file, then the bot will delete the "Content" folder, and re-extract the zip contents for them, making a new "do_not_delete.txt" file with the current content zip hash.
Users that want to use folders instead of zips can now as well. The process is the same, except content from a folder always overwrites existing content for the current configuration. To update content, it's best to delete the old folder, and copy over the new content to avoid any issues with your source folder mixing old and new files that were deleted or renamed. Please keep in mind, you cannot load the same content from a zip and a folder at the same time, since the assembly names would overlap! For any specific 3rd party content, you need to use the zip or the folder.
That's all there is to it.
[Misc]
The standard Windows Zip format needs to be used. Most programs are capable of providing compatible zips, but things like WinZip might allow incompatible formats with some options, likewise with 7-zip if you try to mess with compression. Please test your zips with the built-in windows unzipping feature to see if it'll work. ThirdPartyLoader uses System.IO.Compression's ZipArchive class to handle things.
GuiSettings.Instance.ContentOrder is used to specify the content processing order. The actual loading of content is done in a multithreaded approach to help speed up EB, and cannot be controlled. However, support for loading specific content in order exists again. To do this, content developers simply need to add an empty text file named "3rdparty-required.txt" alongside "3rdparty.txt" and the bot will load that content first synchronously. This is for base library content commonly used by other plugins, such as EXtensions or CommunityLib.
Support has been added to let content developers specify which files are loaded and compiled. This feature was added to help content providers that have a lot of files, which some might be deleted over time and are no longer needed. While using the zip system avoids this issue altogether, the issue can exist when the folder system is used. Content developers simply need to add a text file, "3rdparty-files.txt", alongside their "3rdparty.txt". The contents of this file should be relative paths of the content to include from the root folder. Any files with "3rdparty" in them do not need to be added.
This image provides an example.
Alternatively, here's the source to ThirdPartyFileGenerator, which can be ran from a ready to deploy content distribution that will generate the "3rdparty-files.txt" file for you:
This system is now officially in use, and the old system has been removed.
[About]
As Exilebuddy continues to grow and evolve, we're always looking for better ways to do things so life is easier for everyone. One area that has been in need of improvement is how 3rd party code is distributed by users and loaded by the bot. Right now, users must download compressed files, extract them in a specific location, ensure the folder name is correct for the assembly, and then manage keeping things up-to-date. This works, but is the cause for a lot of inconvenience on both the users and devs, which results in more support issues we have to handle.
This thread will go over a new system we've been working on to greatly simplify the way things are. I should start out by mentioning the current system in place will continue to work as-is and will not change, as we do not want to force this new setup on everyone, but rather let them transition to it at their own pace. However, barring unforeseen side-effects, we'd expect everyone to adopt this system because it will make life easier all around, and requires little extra work for devs to make work.
[Devs]
Please keep in mind the current BosslandGmbH Forum Rules & Guidelines still apply!
There's two main things devs need to do to make use of this new system. First, they need to create a text file, "3rdparty.txt" in their root content folder. The contents of this file simply need to be the exact assembly name of their content, as the bot uses this to create the folder and compile the code.
For example: The current MapRunner plugin is distributed as "MapRunner1.6.2.zip". If you open this file, you'll see a subfolder, "MapRunner". "3rdparty.txt" would go inside the "MapRunner" sub-folder, as the root folder is where all the main content is. The contents of "3rdparty.txt" would simply be "MapRunner".
Another example: The current AIF plugin is distributed as "AdvancedItemFilter 1.0.2.3.zip". If you open this file, you'll see the main content, so "3rdparty.txt" would go into the zip itself and not any other folders. The contents of "3rdparty.txt" would simply be "AdvancedItemFilter".
For any 3rd party content that does not make use of external non-code files, such as images, or data files, their zips would now be compatible and ready to use with the system. 3rd party content which make use of external non-code files will need to update how they reference said files.
To simplify this process, the new ThirdPartyLoader exposes an API function, GetInstance, that allows users to get a ThirdPartyInstance object that stores all the relevant information they will need need. The ThirdPartyInstance object exposes the Name of the instance, the ContentPath and CompiledPath, as well as instances for the various types: BotInstances, PluginInstances, RoutineInstances.
For example, the current AIF code for loading images, works as follows:
Code:
var imageFolderUrl = new Uri(AppDomain.CurrentDomain.BaseDirectory + "Plugins/AdvancedItemFilter/Images", UriKind.RelativeOrAbsolute);
This code works in the current setup, because plugins go into the Plugins folder, and the AIF folder should be named, AdvancedItemFilter, so the path should exist if the user extracted correctly. In the new system, this code would not work because the paths are different. This is how the code would look if it were to be compatible with the new system:
Code:
var instance = ThirdPartyLoader.GetInstance("AdvancedItemFilter");
var imageFolderUrl = new Uri(Path.Combine(instance.ContentPath, "Images"), UriKind.RelativeOrAbsolute);
In that code, the AIF instance is loaded from the ThirdPartyLoader. Devs should obviously check for null in case their code is not being used from the ThirdPartyLoader. Once the instance is obtained, the ContentPath provides the new root content folder for the assembly, so any data files can be referenced from that.
Those are the only two changes required to make things work. Some plugins might need a few more changes, because there's no post detailing best practices for 3rd party code, but I'll work on making such guides in the near future. The biggest difference is that there's no specific load order for Bots/Plugins/Routines, so if your Routine or Plugin assumed there was a bot already loaded and selected, that would no longer be the case. The solution for that is to defer such logic so it only executes in Start, where the current bot will be valid.
Support has now been added for loading content via folders. This means you can load 3rd party content from folders the same way as the current Bots/Plugins/Routines layout does, without having to make a zip file. The folder layout has to mirror the zip layout; you need a "3rdparty.txt" file in your content folder's root, so the files get copied into the locations they should be.
[End-Users]
End users will simply have to open up the "3rdParty" folder Exilebuddy creates, and copy over compatible zip files of the 3rd party content they want to use. That's it! It's best to start with a clean bot installation, to avoid having old copies of 3rd party content in the Bots/Plugins/Routines folder though. Non-compatible zips (those that do not contain a "3rdparty.txt" file) will simply be ignored.
To update 3rd party content, users will just need to delete the old zip file, then copy over the new one. The bot will take care of cleaning up the old content and extracting the new.
There are no more Bots/Plugins/Routines folders for users to deal with. Content will be auto-extracted to a base path of "3rdParty/ConfigurationName/AssemblyName". A "Content" folder will hold all of the extracted content. A "Compiled" folder will hold the compiled artifacts the bot generates and loads.
This structure is used so people can continue to use multiple bots from the same folder, and it solves the issue of simultaneously running bots at the same time, as each bot will need it's own configuration name regardless. Furthermore, only the active configuration's folder contents will be affected, avoiding an issue where in the current setup, all folders are deleted and any files in use are simply ignored.
Users that wish to make changes to 3rd party source code still can, with a few caveats. First, they must run the bot to have the content extracted. The "Content" folder is deleted and replaced when the 3rd party content zip changes. This is tracked by a file placed in each "Content" directory, "do_not_delete.txt". This text file contains the MD5 hash of the zip file, so when it does not match, the current "Content" folder is deleted, and the new zip archive will be extracted in place of it. If a user deletes the "do_not_delete.txt" file, then the bot will delete the "Content" folder, and re-extract the zip contents for them, making a new "do_not_delete.txt" file with the current content zip hash.
Users that want to use folders instead of zips can now as well. The process is the same, except content from a folder always overwrites existing content for the current configuration. To update content, it's best to delete the old folder, and copy over the new content to avoid any issues with your source folder mixing old and new files that were deleted or renamed. Please keep in mind, you cannot load the same content from a zip and a folder at the same time, since the assembly names would overlap! For any specific 3rd party content, you need to use the zip or the folder.
That's all there is to it.
[Misc]
The standard Windows Zip format needs to be used. Most programs are capable of providing compatible zips, but things like WinZip might allow incompatible formats with some options, likewise with 7-zip if you try to mess with compression. Please test your zips with the built-in windows unzipping feature to see if it'll work. ThirdPartyLoader uses System.IO.Compression's ZipArchive class to handle things.
GuiSettings.Instance.ContentOrder is used to specify the content processing order. The actual loading of content is done in a multithreaded approach to help speed up EB, and cannot be controlled. However, support for loading specific content in order exists again. To do this, content developers simply need to add an empty text file named "3rdparty-required.txt" alongside "3rdparty.txt" and the bot will load that content first synchronously. This is for base library content commonly used by other plugins, such as EXtensions or CommunityLib.
Support has been added to let content developers specify which files are loaded and compiled. This feature was added to help content providers that have a lot of files, which some might be deleted over time and are no longer needed. While using the zip system avoids this issue altogether, the issue can exist when the folder system is used. Content developers simply need to add a text file, "3rdparty-files.txt", alongside their "3rdparty.txt". The contents of this file should be relative paths of the content to include from the root folder. Any files with "3rdparty" in them do not need to be added.
This image provides an example.

Alternatively, here's the source to ThirdPartyFileGenerator, which can be ran from a ready to deploy content distribution that will generate the "3rdparty-files.txt" file for you:
Code:
using System;
using System.IO;
using System.Text;
namespace ThirdPartyFileGenerator
{
class Program
{
static void Main(string[] args)
{
var sb = new StringBuilder();
var baseDir = AppDomain.CurrentDomain.BaseDirectory;
foreach (var file in Directory.GetFiles(baseDir, "*.*", SearchOption.AllDirectories))
{
if (file.ToLowerInvariant().Contains("3rdparty"))
continue;
var ext = Path.GetExtension(file).ToLowerInvariant();
if (ext.Equals(".dll") || ext.Equals(".exe"))
continue;
sb.Append(file.Replace(baseDir, ""));
sb.AppendLine();
}
File.WriteAllText("3rdparty-files.txt", sb.ToString());
}
}
}
This system is now officially in use, and the old system has been removed.
Last edited: