Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
This section will only contain basic functionalities that the core module provides. If you're looking for in-depth explanations of modules, (commands for example) check out the sections dedicated to those modules.
You can find them in this group.
With that out of the way, let's continue our journey of understanding Icicle. Click the next button.
The PostConstruct annotation can be used on methods, to turn them into, well a secondary constructor.
These PostConstruct methods will only be called after the @Bean methods have been handled, and the setters have been auto-wired, but before the bean is registered.
PostConstruct methods should not have parameters!
There are some cases when you don't want to auto-wire only via constructors. For this exact purpose, we have introduced setter autowiring. Just create a setter and put @Autowired on top of it.
Hint: You can have multiple beans auto-wired in the same setter as well.
Remember, when we told you, that services could only have one implementation? Well, that was kind of a lie, we're sorry.
In order to achieve multiple implementations of the same service, you need to meet the @Qualifier
annotation. Using it is pretty straightforward:
Apply it to the implementation
Give it a qualifier (aka. name)
When you auto-wire, apply the same annotation, with the same qualifier
There can be one implementation, which does not use a qualifier. This is basically the default implementation. When you auto-wire and don't specify a qualifier, this is what will be injected.
Let us show you an example. Imagine that we have a service called DemoService, and we have 2 implementations for it:
Modifiers can be used to modify a value passed to a method at runtime using different logic. These modifiers are enabled via our proxy. But let an example speak for itself:
Modifiers can only be used inside Icicle managed beans. Modifiers also require the method to have @ModifiersActive on it (this is to save resources).
The implementation of this modifier is:
Oh. This section is still waiting to be written...
A quick walkthrough thru the basics of localization.
Providing multi-language support is vital for a successful plugin. Icicle provides an easy-to-use system with a built-in script language similar to Excel's.
Localization is done through the TranslationService
.
StringProviders
are the ones that provide the TranslationService
with a string for a key from a file. With this abstraction, the developers can implement any kind of source they can think of, be it a simple file-based one, or maybe a remote solution.
Built-in solutions are the following:
FileStringProvider --> Used for switching between multiple LanguageFiles
If you want to set up your own, do it like this:
LanguageProviders
are the ones responsible for providing a language code for a Player
. Sources can be databases, geolocation, or just a fallback fixed language.
If you want to use the built-in providers, they are the following:
ConstantLanguageProvider --> Always returns a pre-set language (used as fallback)
PlayerLanguageGeoProvider --> returning language-based of geolocation (experimental, relies on external API!!!)
Planned: DatabaseLanguageProvider
If you've decided you want a custom implementation, you can do so like this:
The TranslationService
must be auto-wired. By default - if no providers have been set up - it will use "en" as the language, and will only use the default values.
When first getting keys, the service will automatically append the default values to a translation file of choice (StringProvider
must be set up for this).
By default, the TranslationService does not parse color codes, as it's in the core module, and the core does not depend on Bukkit.
StringCode
is a special Excel formula-like script language, that provides translators with the ability to write logic inside a string, therefore making language-specific tasks easier.
Code must be written between {}, escaping with \ is supported.
The following table shows all the functions you can use & their purpose.
These are just the built-in functions. The system is completely expandable.
TRUE()
Constant true value.
FALSE()
Constant false value.
IF(statement, true, false)
If the statement is true, then the value inside true will be returned, otherwise the value inside false.
OR(statement1, [statement2], ...)
If any of the statements inside the function return true, then the function will return true, otherwise false.
NOT(statement)
Returns the logical opposite of the statement.
AND(statement1, [statement2], ...)
This function will only return true, if all of the statements inside it return true.
EW(value, test, [test2], ...)
Tests whether the value ends with the supplied test values. Will return true/false accordingly.
SW(value, test, [test2], ...)
Tests whether the value starts with the supplied test values. Will return true/false accordingly.
NE(value1, value2)
This function will return true if value1 and value2 do not match.
EQ(value1, value2)
This function will return true if value1 is equal to value2.
LTEQ(number1, number2)
Tests whether number1 is equal to or less than the second number2.
LT(number1, number2)
Tests whether number1 is less than the second number.
GTEQ(number1, number2)
Tests whether number1 is equal to or greater than the second number2.
GT(number1, number2)
Tests whether numbe1 is greater than the second number.
CONCAT(value, [value2], ...)
Concatonates the values inside the function, and returns them.
JOIN(separator, value, [value2], ...)
Joines the values inside the function together with the supplied separator.
SUB(number1, number2)
Subtracts number2 from number1.
ADD(number1, number2)
Adds the two numbers together, and returns the result.
MUL(number1, number2)
Multiplies the two numbers together, and returns the result.
MOD(number1, number2)
Returns the remainder of number1 divided by number2.
DIV(number1, number2)
Divides the first number with the second.
Icicle is a Spring inspired framework designed for Bukkit/Spigot plugin development. It's a new way of thinking about plugin development, and not worrying about the complex systems you have to write for many hours straight.
The aim of this project is to aid you in every single part of plugin development, from basic commands to advanced protocol mechanics.
Even though Icicle can be implemented in many environments, we'll only focus on Minecraft development in this documentation. If you're interested in gaining the basic (non-Minecraft) functionalities of Icicle, please check out the Embedding Icicle page.
If you're already familiar with the concept of beans, or with Spring, then you will have no time picking up Icicle's style.
If you have never heard of the things above, then don't feel disqualified. In this documentation, we will explain everything in a nutshell, so that you will understand the "weird terms" we will reference/rely on.
We've split the documentation into sections. These sections include the complete guide of separate modules, how to extend Icicle, etc. However, if you're new to Icicle (or have no idea about Spring either) we strongly recommend starting with the basics under Icicle Basics.
Create your first Icicle application very easily.
To help your productivity skyrocket, we've decided to make our own development tools, with many in mind for the future.
Currently, our only development tool is our own Gradle Plugin, but don't let this little number fool you, this addon for Gradle will help you more than you can imagine, but let's dive into it further!
We strongly recommend the use of Gradle, but you can get away with Maven or the dependency manager of your choice, but you will lose the helpful features of our plugin.
You want to use Eclipse, I see. Teach you how to do so, I shall.
Fire up Eclipse and create a new Project with CTRL+N
, or by clicking on File -> New -> Other
.
This will bring up a handy little wizard, where the only thing I care about is the Gradle -> Gradle Project
.
a
First of all, we need to create the folder containing our project
Next we'll start creating the project with Gradle. This needs to be unzipped and added to the environment variables. To start the creation process we'll need to execute
This will give us some options which we'll quickly answer. In this demo we'll be using a Kotlin DSL.
After we've finished setting up our basic file structure, we can go ahead and add all the icicle related funky stuff!
With your preferred text editor open up the settings.gradle.kts
file. For the sake of presentation, I'll be using nano.
In there copy-paste the following text:
Inside of your plugins
block, add the icicle plugin with the following bit of code.
Next up, let's create the configuration for the Icicle plugin.
Create a new block, called icicle
and populate it according to the template provided below.
This page introduces the concept of beans and teaches the reader how to use them effectively.
The bean system is the heart of this entire framework (just like in Spring). It is the one responsible for creating your classes automatically, auto-wiring them in the necessary places, and responsible for tying everything together into a cozy ecosystem.
Prepare yourself for a load of "bad words", that may not make sense. This is a very technical page, but you have to endure it because this is the base of the framework.
According to the Java white paper
It is a reusable software component. A bean encapsulates many objects into one object so that we can access this object from multiple places. Moreover, it provides easy maintenance.
In our framework, beans are the objects that form the backbone of your application and that are managed by Icicle's IoC (Inversion of Control) container/system. A bean is an object that is instantiated, assembled, and otherwise managed by Icicle behind the scenes.
In our implementation, the IoC is basically the AbstractIcicleApplication
, but the actual logic is mostly handled by the BeanRegistry
and the BeanManager
.
There's a downside to this system however, and that is, that you cannot easily access bean objects from non-bean objects. For this, you'll have to have static access to the application specifically the BeanRegistry
. If you follow the idiom of the structure, you really won't create non-bean objects. (not including utility classes)
Great, now that you've got a somewhat good idea about beans, let's dive deeper.
Dependency injection is a pattern we can use to implement IoC, where the implementation is setting an object's dependencies behind the scenes, automatically. It also resolves many issues like unresolvable dependencies or circular dependencies.
Connecting objects with other objects, or “injecting” objects into other objects, is done by an "assembler" rather than by the objects themselves. You can think of the job of this system as the Linker in C++ for example, but this is a very cruel comparison.
In our implementation, DI can only be done via constructors & setters. We are not planning to implement field auto-wiring, as it's considered bad practice.
Let's look at an easy example: you have a manager that requires JavaPlugin
to run.
Here the PlayerManagerImpl is automatically created, you don't have to do that.
This is also a @Service
, which means you can auto-wire the same object by only specifying the interfaces it implements.
Since interfaces can be implemented by many classes, Icicle will throw an error if a class is marked with @Service
and implements an interface, that already has an implementation.
We've introduced a new thing here called @Service
, this is basically the same as in Spring, but we'll talk about it later, so don't worry about it for now.
Since natively there's no automatic creation, we'll have multiple classes here.
As in the example, we've introduced a thing called @Service
, but what is it, you may ask?
Well, in this section you will learn about all the types of beans, and how they're related to one another.
We will discuss some advanced bean types here as well, that you won't really need in basic development, but will come into play whilst Extending Icicle. So, don't freak out!
Every bean is basically a subtype of @AutoCreate
(for the Spring guys, it's basically an equivalent of @Component
). Later on different auto-create handlers will add different functionality to them.
So, without further ado, let's look at all the bean types that are by default in the core module:
@AutoCreate - The most basic bean type, it only provides auto-creation, management, and dependency injection.
@Service - A slightly advanced bean. You will probably use this the most. Other than the basic functionalities @AutoCreate provides, this also allows you to auto-wire the bean with all of their interfaces. However, an interface (basically the service) can only have one implementation (the actual class you put the @Service annotation on). If multiple implementations exist for the same service, you will get an error. (If I had to compare it to something, it would be like the fact that you cannot have the same class names in a package).
@GlobalService - Basically the same as @Service
, but the implementations also get registered into the GlobalServiceProvider
(in Bukkit environments to Bukkit's ServicesManager
)
@Config - Reserved for configurations, learn more about them here.
@ConfigurationDriver - Drivers for config types
@MethodValueModifier - Modifier handlers
@MethodAdviceHandler - Beans that handle the registration of Advice
to the ByteBuddy proxy used by the BeanManager
.
@MethodInterceptorHandler - Beans that handle the registration of Interceptors
to the ByteBuddy proxy used by the BeanManager
.
@AnnotationHandler - Beans that specialize in the customization part of the framework. They are what you will use to create new annotations and bean types. (They have 2 sub-types, but we're going to meet them later on, so no need to rush their introduction)
Remember, these bean types are the default in the core, modules can register their own, and you'll meet these specific sub-types in their designated module guide section.
Now we're stepping into the more technical side of Icicle here.
As we've discussed before, we've designed Icicle with customization and expandability in mind. In this section, you'll learn how you can add your own annotations to the framework etc.
This page contains a config file that's for demonstration purposes.
Icicle provides an easy way for multi-file configurations. Our solution also allows you to explain the different configuration fields with comments.
Currently, we only support YAML and Properties as our configuration file, but we're planning to introduce HOCON and TOML.
When you create a config or add a new field to an already existing config, Icicle will create the config file if necessary and updates the default values if needed.
Default values are taken from the field's default values set by you in the class. When the default value and the config set value are different, we'll inject the new value into the field. Basically from now on the contents of the config file controls the values of the fields inside the config bean.
Creating a simple config file is as easy as:
This code will result in the following file:
Implementing Configuration is required. This is what gives you the methods necessary to reload, load, etc. your config.
Even though the interface uses defaults, which throw UnImplementedExceptions, the ConfigDelegator will proxy your config class, and route these methods to the appropriate driver.
The driver is selected based on the extension of the file you provide!
Accessing configuration values can be done in 2 ways.
One is auto-wiring the whole config, and accessing it via the fields
You can auto wire specific values and not the whole config, however, with this, you lose the ability to change or reload those values.
Let's take a look at both of them
With that being said, you now know the configuration system of Icicle. It is easy, isn't it? Let's move forward, and see, how you can make your plugins accessible in many languages!
Module adding & reasons for the usage of them.
Icicle's functionalities are separated into their respective modules. We've done this, so you only get what you really need.
These addons can be accessed via a simple dependency notation in the dependency manager of your choice, but we highly recommend using our Gradle Plugin (you've learned about it here).
In the case of first party addons, you can add them to your project by extending your dependencies
block in your build.gradle.kts
, below is an example where we add the nms
module.
And... bam! You're done. That's all it takes to add a first party addon.
When you want to add a third party module/addon to your project, all you'll need to do is add the addon like you would any otherdependency
, except that instead ofimplementation
, you'll be using addon
. Below this, you can find an example for such an addon.
Create an icicle.yml file in your resources folder if it does not already exist, and open it up.
If there wasn't already a dependencies in that file, then create a new list and add your addon in the following format:
Modules are their own story, and most of them are so complex, they deserve their own sections in this documentation:
Commands System
Oh, so you're not here for the juicy Minecraft-specific stuff, but you want access to the basic functionalities of Icicle in your environment of choice? Well, you're on the right page!
Before we go much further, we recommend you check out this list, which contains all the ports of Icicle in different environments:
That's out of the way let's begin:
Latest Icicle version: N/A Documentation effective from: N/A
------------------------------------------------
Welcome to the official Icicle guide! Whether you came here to learn Icicle from scratch, or you just want to understand a specific module, we hope this guide will be useful for you.
Before you go further, we ask you, to rate the pages of these guides, so we can get a clear idea of what is unclear, and what needs work. You can do it at the bottom of the pages via these 3 simple buttons:
Lastly, we wanna thank GitBook for providing us with an OpenSource License and making this documentation possible.
With that out of the way, you can continue to: Getting Started.
Hesitant to use Icicle, or you simply have questions regarding it? Before asking us on Discord, please, be sure to read through this, as we get these questions a lot.
If you're coming from a Spring background, or you have used dependency injection (beans) before, then you will pick up Icicle very easily.
If all of these sound foreign, then don't feel disqualified. After you've learned the basics, you will adjust to Icicle no-time.
Yes, our goal is to help every plugin developer in the world, and let's face it: everyone hates paywalls.
No, but it may prolong server loading.
Even though Icicle is a complex system, all the time-consuming parts (scanning, registering) are done at startup - when all the other plugins & worlds load.
Yes, every server owner who utilizes Icicle-based plugins needs to install Icicle in the server's plugin directory.
This is so, that all the magic is contained in one place, and will not be unnecessarily duplicated (therefore saving precious memory and storage)
We currently do not have any ways to accept donations, but we're planning to set up a Ko-Fi or Patreon page.
Of course, you can! Open-source projects are all about the community. This generosity of others is what enables Icicle to stay up-to-date with all the developer needs. Please be sure to read our Contribution Guidelines, before contributing.
Believe it or not, reporting bugs are also a big way you can contribute, and make others' lives easier.
G4be_
TOTHTOMI