4.0.0-RC6 - Blizzard #1082
byRoadrunner
announced in
Releases
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
-
Update 4.0.0-RC6 - Blizzard
We are pleased to announce the sixth release candidate for CloudNet 4.0. This release mainly focuses on the migration from static instance usages to dependency injection - internally as well as for external api consumers. Please see the dedicated information section for dependency injection below for further info. We urge all users to install the update, as we will no longer provide support for RC5. Users who want to switch from 3.4.X to 4.0 can find instructions in the release information for RC1.
Cheers!
(Please remember, CloudNet is provided as-is - we are not responsible for data loss or corruption. You are encouraged to back up your files before any updates!)
Changelog
🐛 Fixes
PlayerExecutor#connectmethod rather than the best matching serviceperms_group_✨ Improvements
CommandPreProcessandCommandPostProcesseventColouredLogFormattertoColoredLogFormatterandConsoleColor.toColouredStringtoConsoleColor.toColoredStringto keep the spelling of color consistent🔗 Links
Dependency Injection
❓ Why DI
There are a few reasons why we deided to go for dependency injection. The top three include:
💡 What to note when using DI
What is DI?
Dependency injection is a design pattern that allows objects to be constructed without needing to know how their dependencies are created. A dependency is an object that another object relies on in order to function properly. In traditional software development, objects are responsible for creating and managing their own dependencies. However, with dependency injection, the responsibility of creating and managing dependencies is shifted to a separate component, known as an injector.
The injector is responsible for providing the necessary dependencies to objects at runtime. This is done by injecting the dependencies directly into the objects that need them, rather than having the objects create or manage the dependencies themselves. By doing so, the objects become less tightly coupled and more flexible, making it easier to change or replace dependencies without affecting the rest of the application.
Constructor injection is the most common form of dependency injection, where dependencies are passed in through the constructor of a class. The class is defined with a constructor that takes the dependencies as arguments, and the injector is responsible for providing these dependencies when the class is instantiated. The target constructor to inject is detected by using either of:
@Inject(dev.derklaro.aerogel.Injectorjakarta.inject.Inject).When the injector constructed the type completely member injection is executed. Member injection will be done on
@Inject(Note that final fields might get ignored from injection)@Injectwill be executed. These methods are allowed to take arguments.@PostConstructwill be executed. These methods are not allowed to take arguments.The injection order of injectable methods and post construct listeners can be constrolled with the
@Orderannotation.A quickstart guide for dependency injection
@Injectannotation markes constructors and classes that should be injected and the@Singletonannotation lets aerogel know that only a single instance of the annotated type should be constructed.⛅ How did we implement it in CloudNet
Because of the little flexibility and many outside influences we have due to the supported Minecraft server/proxy implementation, we had to implement DI to be as flexible as possible.
For this reason, some decisions had to be made that would not have been a problem in a normal standalone application:
🔌 Support for Plugins
Support for plugins can be achieved with the platform inject api. This generates classes during compile time based on annotations added to classes (a list of these annotations is below). It is important that the dependency for the annotation processor is only available at compile time and not at runtime:
The supported annotations
@PlatformPlugin: This annotates the main class of the plugin. Due to the abstraction of CloudNet extended/implemented, the annotated class no longer implements an implementation-specific class (such as JavaPlugin) but always implements the interface PlatformEntrypoint. The following settings can be made via the annotation:platform: The name of the platform for which the annotated class is the entry point. Supported are currently:bukkit,bungeecord,fabric,minestom,nukkit,sponge,velocity&waterdog. Note that for the platform a plugin info file will be generated as well (for example theplugin.ymlfor bukkit). A template file can be created in the resources directory with the name of the output file (see below for options) suffixed with.template. All configurations made in the template file will be copied to the final file and will not get overridden.name: The name of the plugin. CloudNet automatically takes care that the name complies with the platform's policies (and adjusts the name if necessary) and also generates a plugin ID based on the name (if necessary).version: The version of the plugin.pluginFileNames: Sets the output file name for the plugin. By default, the file names used by CloudNet are used, which can be customized during copying to the target service (e.g. plugin.bungeecord.yml). In the array you can specify the names of the files where the plugin info for the platform should be written. Folders are also supported, these are simply specified via slash (e.g.myFolder/plugin.yml).api: An optional api version that is required for the plugin to run. This setting can be interpreted differently or even ignored based on the target platform.description: An optional description of the plugin.homepage: An optional url to the homepage of the plugin.authors: An optional array of the plugin authors.providesScan: An optional set of patterns which should be considered when searching for@ProvidesForannotations. By default the same package in which the plugin main class is located in will be used. Each entry in the given array can be in the formts:<packageName>: In this case the given name will be taken and all classes and sub-packages in the given package will be scanned<type>:<packageName>: The name is used depending on the given type. The type can either be:r,regexp,pattern: the given package name is parsed as a pattern.p,plain: the given package name is used in a literal way and all classes in the given and sub packages will be scanned.g,glob: the given package name is parsed as a simplified glob. The only supported glob chars are:*,?,.and\.commands: An optional array of commands that is provided by the plugin. Depending on the platform the information can be used in different ways or even be igored.dependencies: An optional array of plugin-level dependencies. The given information may not be used based on the plugin.externalDependencies: An optional array of external dependencies that are required for the plugin to run. Based on the platform the information might be ignored.@ProvidesFor: marks an implementation for the given type(s) which should only be present on the specified platform. The following settings can be made via the annotation:platform: The platform on which the binding should be present.types: The types to which the annotated class should get bound (Note that there will be no check if the type is actually assignable to the annotated type).bindGenericSupertypes: If enabled the directly extended superclass and implemented interfaces will be scanned if they contain one of the types given via thetypessetting which is generic. In that case the generic version will be bound based on the extending declaration (for example if in the type arrayMap.classis specified and the class implementsMap<String, String>then the map implementation with type parameters will be bound to the annotated type as well).bindWildcardTypeOfParameterizedTypes: If enabled all generic, parameterized types will be bound fully wildcarded as well (for example if the class implementsMap<String, Map<String, String>>the typeMap<?, ?>will be bound to the type as well).@ConstructionListener: The annotation can be added to the main class of a plugin (the same class as annotated with@PlatformPlugin) and specifies a single class will should get called when the plugin instance is created by the platform. Note that the target class must declare a constructor which takes the platform plugin data (which can vary based on the platform) as it's only argument. Only the constructor in the target class is called, all other steps are left to the constructor to do.Annotations to use with
@PlatformPluginThe following annotations are used in the PlatformPlugin annotation and describe various configuration options for the info generation for each platform. Depending on the target platform, some of the information provided to the annotation might get dropped, or the complete annotation is ignored if unused:
@Command: Allows to specify a command which is provided by the plugin.@Dependency: Allows to specify a dependency on another plugin.@ExternalDependency: Allows to specify an external dependency which is required for the plugin in order to run.@Repository: Sets the repository of the external dependency. Some platform are only allowing dependencies to get downloaded from maven central, in that case the information provided to the annotation is ignored.An example plugin class might look like this:
Which types are bound for which platform by default?
The
InjectionLayerfor the plugin can be injected by using the layer type and requesting an instance calledplugin.Bukkit
Plugin Type
Plugin,PluginBaseandJavaPluginPlatform Types
ServerBukkitSchedulerPluginManagerServicesManagerScoreboardManagerBungeecord
Plugin Type
PluginPlatform Types
ProxyServerProxyConfigTaskSchedulerPluginManagerFabric
Fabric has no bindings by default as there is nothing to bind.
Minestom
Plugin Type
ExtensionPlatform Types
ComponentLoggerTagManagerTeamManagerBiomeManagerBlockManagerRecipeManagerBossBarManagerCommandManagerPacketProcessorInstanceManagerExceptionManagerExtensionManagerBenchmarkManagerSchedulerManagerConnectionManagerGlobalEventHandlerAdvancementManagerDimensionTypeManagerPacketListenerManagerNukkit
Plugin Type
PluginandPluginBasePlatform Types
ServerCommandMapServerSchedulerPluginManagerServiceManagerCraftingManagerResourcePackManagerSponge
Plugin Type
PluginContainerPlatform Types
Scheduler(two variants: one namedsync(for the sync scheduler) and one nameasync(for the async scheduler))GamePlatformSqlManagerDataManagerEventManagerConfigManagerPluginManagerChannelManagerBuilderProviderFactoryProviderMetricsConfigManagerServiceProvider.GameScopedMapStorageUserManagerWorldManagerServerRecipeManagerTeleportHelperCommandManagerPackRepositoryResourceManagerCauseStackManagerGameProfileManagerGameProfileProviderServiceProviderServiceProvider.ServerScopedVelocity
Plugin Type
PluginContainerObjectnamedpluginwhich is the plugin main class instancePlatform Types
ProxyServerSchedulerEventManagerPluginManagerCommandManagerChannelRegistrarWaterdog
Plugin Type
PluginPlatform Types
ProxyServerMainLoggerCommandMapPackManagerLangConfigEventManagerPlayerManagerServerInfoMapPluginManagerWaterdogSchedulerConfigurationManager🔌 Support for Modules
The CloudNet module system (whether on the wrapper or the node) has full support for dependency injection. The module's main class can have dependencies injected into the constructor, and all module tasks have the ability to inject dependencies. No further configuration is required.
An example module task might be:
Commands
The node command system allows injection into command processing methods as well. This does not include suggestion processors or parameter parsers.
🔌 Support for Event Listeners
Event Listeners are allowed to take parameters via injection as well. The main catch here is, that the first parameter of an event listener method still needs to be the event which the method wants to get notified about. All other parameters are looked up when the listener should be invoked. An example listener that takes arguments:
This discussion was created from the release 4.0.0-RC6 - Blizzard.
Beta Was this translation helpful? Give feedback.
All reactions