This release fixes an issue which arised when running on MC 1.21.3 and later. The bytecode transformer of the server wasn't properly called when loading cloasses. This now happens correctly again.
Adds Scala versions 2.13.13, 3.3.3 and 3.4.0.
Cheers!
This update fixes ScalaPlugin trying to register permissions twice when running on Paper.
This update fixes ScalaPlugins being attempted to load twice when running on Paper.
The detection of the Folia server now relies on the availability of a class that is present in the Folia server implementation, but not in its api. This fixes a bug that incorrectly detected Paper 1.20.x servers as Folia servers.
Paper keeps on changing their plugin bootstrapping and loading code, causing me to have to adapt once again.
This update accomodates for the following changes in Paper:
Even if you don't update Paper, this version of ScalaLoader should still continue to work, because I made the changes to be backwards-compatible.
Cheers!
This update to ScalaLoader contains the following changes:
- Added IScalaLoader#getEventBus() for use by JavaPlugins.
- Added IScalaPlugin#pluginLoader()
- Deprecated ScalaPlugin#getPluginLoader() -> use #pluginLoader() instead.
- New&Improved™ Javadocs available on GitHub Pages!
Cheers!
This update fixes an issue caused by a recent Paper update. If you were having troubles with the class ScalaPluginProviderContext being invalid, this issue should now be resolved.
Hello everybody, it's been a while since this plugin has seen some serious update, but here's a big one.
Paper-405 has broken its PluginLoader api completely, causing me to have to reimplement most of ScalaLoader's functionality again in order to support Paper. So that's exactly what I've done for this update.
This update contains the following changes (some of which are breaking for JavaPlugins):
- On Paper-405 and later, ScalaLoader will load as a Paper Plugin.
- ScalaPlugins will be loaded as Paper Plugins as well:
- You can specify your own Bootstrapper if you want. You can use ScalaLoaderUtils#createInstance(Class) to create your plugin instance if your plugin's main class is an object or has a constructor with zero parameters.
- Be aware that the version of Scala your plugin uses is registered with the ScalaCompatMap. Use xyz.janboerman.scalaloader.paper.ScalaLoader#getScalaVersions()#add(ScalaDependency)
- User-specified PluginLoaders will not be supported.
- To make all of this possible, many of the api methods which previously used an instance of ScalaLoader, ScalaPlugin, ScalaPluginLoader or ScalaPluginClassLoader, will now use IScalaLoader, IScalaPlugin, IScalaPluginLoader and IScalaPluginClassLoader. These interfaces have separate implementations for CraftBukkit/Spigot and for Paper/Folia.
- Bytecode transformations are included for compatibility, so that your xyz.janboerman.scalaloader.plugin.ScalaPlugin will be a sublcass of xyz.janboerman.scalaloader.paper.plugin.ScalaPlugin instead at runtime.
- ScalaPluginEnableEvent and ScalaPluginDisableEvent have been deprecated since they can't be properly implemented on Paper. Use regular PluginEnableEvent and PluginDisableEvent instead.
- ScalaPluginLoader#openUpToJavaPlugin has been deprecated since it won't work on Paper. JavaPlugins should therefore no longer call it if IScalaLoader.isPaperPlugin() returns true. There is no alternative provided for Paper since ScalaPlugins on Paper will be subclasses of JavaPlugin, so the regular dependency mechanism suffices (you still have to make sure your JavaPlugin depends on "ScalaLoader" though).
- ScalaPlugin#getClassLoader() has been depcreated. Use IScalaPlugin#classLoader() instead.
- ScalaPluginDescription has seen several additions - you can now specify your Bootstrapper, and you can specify Folia support for your ScalaPlugin. You can also now specify your maven dependencies right from your Scala code. Be aware that those dependencies will not be loaded yet when your plugin's constructor is called!
- Some methods that were already deprecated in the 0.17.x releases have been removed.
Added the following Scala versions:
Additionally the following internal dependencies have been updated:
Cheers!
Changed in this release:
- Handling of longs and doubles in ConfigurationSerializable classes should be fixed
- False positive UnkownDependencyErrors should no longer occur
- /listscalaplugins command now displays plugin names in red when they're not enabled (and still in aqua if they are).
Added
- ScalaVersion.v2_13_8 and ScalaVersion.v3_1_1
- Made it so that any version of Scala 3 always picks the latest known Scala 2.13.x standard library
- Initial support for scala Maps in the ConfigurationSerialization framework
- Fixed a bug that got introduced in version 0.17.13 (not released on SpigotMC) that would prevent plugins from loading because the loader wouldn't know which URL to use to download the scala standard library from Maven Central.
Known issues:
- A bug in the bytecode generator for the serialization and deserialization methods that would occur if your class (de)serializes a primitive long or double. This bug is also present in previous versions, I just didn't know it yet at the time of those releases.
- java.util.Collection & subclasses
- java.util.Map & subclasses
Happy new year!
- java.util.Collection & subclasses
- java.util.Map & subclasses
Happy new year!
New types supported by the serialization code generator:
- scala.Option (scala.Some and scala.None$)
- scala.util.Either (scala.util.Left and scala.util.Right)
Hello! This update brings the following changes:
Added:
- The ConfigurationSerializatiable-framework now properly deals with Scala tuples.
- ScalaVersion.v3_1_0
Fixed:
- Generated classes that implement ConfigurationSerializable now get registered immediately when they are loaded.
This updates adds v3_0_2 to the ScalaVersion enumeration.
Additionally the ScalaPlugin class now depends on Spigot-API 1.17.1, providing a default (null) BiomeProvider.
Fixed the following issue:
- A ScalaPlugin could still fail to load if it had dependencies on multiple JavaPlugins.
Fixed in this update:
- A bug that prevented ScalaPlugins from loading when depending on other JavaPlugins.
Added:
- A zero-argument constructor for the ScalaPlugin class.
Fixed:
- Generated code for (de)serialization of scala.collections.immutable.WrappedString and scala.collections.immutable.Range
Other:
- Updated ASM dependency to version 9.2
Fixed it so that dependencies that are defined in the plugin.yml don't load their own versions of the bukkit api classes.
Recently Bukkit got a new
library api, where runtime dependencies can be declared in the plugin.yml.
To ease the jump from a JavaPlugin to a ScalaPlugin, ScalaLoader supports this setting too now.
It comes with four benefits over Bukkit's own implementation:
- Bytecode transformations needed for legacy plugin support will get applied for dependencies too. So,for example if a dependency calls Material#values() then only the modern Materials well be returned.
- In addition to Maven Central, the CodeMC maven-public repository is supported out of the box as well!
- It works on all versions of spigot supported by ScalaLoader. That is Spigot 1.8.8 and newer.
- Dependencies that have the Scala standard library as a transitive dependency will use the Scala standard library that was loaded by ScalaLoader at runtime, ensuring that multiple ScalaPlugins remain free to exchange types from the Scala standard library to other ScalaPlugins without class clashes.
Note that this update is meant to ease the migration from a JavaPlugin to a ScalaPlugin. Eventually ScalaLaoder will get its own dependency api according to the design described
here.
Cheers!
Added:
- ScalaVersion.v2_13_6
- Specialized (de)serialization for scala collections: WrappedString and Range.
- Specialized (de)serialization for all java primitives.
- Specialized (de)serialization for all enums.
- Specialized (de)serialization for java.util.UUID, java.math.BigInteger and java.math.BigDecimal.
Changed:
- Made it so that the Scala 3 libraries will use the 2.13.6 library as bootstrap.
Fixed:
Hey everyone. Scala 3 released a few days ago, and this update helps you use it for your ScalaPlugins!
Added in this release:
- v3_0_0 entry in the ScalaVersion enum.
- @CustomScala annotation now has a new method: scalaLibs. This is an array of extra runtime support libraries for your distribution of Scala. You can now pick-and choose which of the scala runtime libs you need. Although it is technically possible to mis-use this mechanism to load other runtime libraries, this is STRONGLY DISCOURAGED!
- Command to show the scalaplugins: /listscalaplugins. This shows at which version of Scala they were compiled, but they are grouped if they are binary compatible.
- Command to dump bytecode and a command to dump bytecode once classes load. This is mainly useful for myself when developing this plugin, but it allowed me to clean up the classloader code by so much.
Fixes:
- Fixed an error that would occur if a ScalaPlugin defined ApiVersion.LEGACY
- If two ScalaPlugins were using compatible versions of the Scala runtime sometimes the oldest version was chosen instead of the newest. Now the newest version is chosen correctly.
Other changes:
- The builtin download urls of the runtime libraries now no loger depend on JFrog's Bintray service which is shutting down - instead they are downloaded from Maven Central. Server admins might need to run /resetScalaUrls to get this change.
- More progress on generating bytecode to convert scala collections to java collections for @ConfigurationSerializable, however this is not used yet - it's still dead code.
The permissions have been updated too:
- scalaloader.resetscalaurls allows access to /resetScalaUrls
- scalaloader.listscalaplugins allows access to /listScalaPlugins
- scalaloader.dumpclass allows access to /dumpclass
- scalaloader.setdebug allows access to /setDebug
That is it! Thanks and enjoy!
Hi all, this release contains the following changes:
- Indroduced ScalaRelease which represents a compability release of Scala. e.g.: 2.13.x
- Fixed a bytecode generation issue where types sometimes would be registered twice at bukkit's ConfigurationSerialization.
- Improved class finding algorithm by making use of the newly introduced ScalaRelease
- Fixed some documentation
That's all!
Hey all, a few small changes with this latest update:
- Enables other plugins to add extra dependencies to ScalaPlugin using ScalaPluginClassLoader#addUrl(URL). This will become deprecated once I add my own custom library loading api.
- Fixed that ScalaVersions 2.12.12 and 2.12.13 were called 1.12.12 and 1.12.13
Cheers!
The .jar file association with the ScalaPluginLoader is now left in place so that ScalaPlugins can be hot-reloaded.
Additionally, ScalaLoader is now registered as a soft dependency of all ScalaPlugins, making it so that when ScalaLoader gets reloaded, so will all ScalaPlugins.
Tested using
PlugWoman.
Unnecessary bytecode transformations are now skipped.
ScalaLoader will now understand to serialize and deserialize your java.util.Map's, just like it already did for java.util.Collection's.
It is no longer needed to specify which classes are the part of the tagged union in the annotation if at the bytecode level they are listed in the permitted subclasses list ("permits" clause in Java).
I used a private fork of CraftBukkit to test this, since Spigot hasn't updated its ASM api version yet. The feature will still work on current spigot, but classes that use this will not get Bukkit's own bytecode transformations applied to them. This will probably change when Java 17 arrives and sealed types are no longer a preview feature.
Edit: this has since been fixed:
https://hub.spigotmc.org/jira/browse/SPIGOT-6414
Now that the configuration serialization api is stabilizing, I added a bunch of javadoc comments to it. So until I fix apidocs in the CI you can generate it yourself using
mvn javadoc:javadoc.
This update breaks the Codec api in a source incompatible way, hence the major version bump. Since the Codec API is still quite new I suspect that nobody uses it yet in production so I wanted to get this update out as quickly as possible.
To use it, update the version of ScalaLoader in your build file to v0.14.0
Thanks!
ScalaLoader's serialization framework will now generate bytecode that converts your java collections into types that can be serialized and deserialized properly.
Additionally, you can now customize the serialization behaviour for types you don't own using the new experimental Codec api.
Cheers!
Hi all,
This update includes the following changes:
- Fixed that classes that are annotated with @ConfigurationSerializable and that contain fields whose types are parameterized couldn't be loaded by the classloader.
- Updated bStats to version 2.2.1, meaning ScalaLoader will no longer try to co-operate with other plugins that send metrics to bStats.
- Cleaned up more of the type conversion code in the configuration serialization api, laying the groundwork for conversions from java collections to yaml lists and back.
Hi all, time for another update.
- Fixed some bytecode generation bugs for classes annotated with @ConfigurationSerializable
- Added bytecode generation for conversion of arrays so that they can be properly deserialized from yaml list.
These code generation updates will open the door for me to start implementing conversion between Scala and Java collections, so that Scala collections will be serialized as yaml lists without plugin authors having to write that boilerplate themselves
That's it, thanks!
Changelog:
- Adds Scala 2.13.5 to the ScalaVersion enum
- Fixed a bug that caused a ClassCastException to be thrown when other plugins listened on ScalaPluginEnableEvent / ScalaPluginDisableEvent.
Hello everyone, time for a new update! Here's the tl;dr changelog:
New:
- Added Scala 2.13.4
- Preliminary configuration serialization api
- Metrics on bStats
Changed:
- ScalaLoader will now run again on Java 8
- Improved compabitbility between ScalaPlugins
And now in more detail:
- v2_13_4 was added to the ScalaVersion enum.
- The configuration serialization api is not completely finished yet, but a new package xyz.janboerman.scalaloader.configurationserialization was added. It contains the annotation @ConfigurationSerializable which can be used to let the classloader generate the serialize(): java.util.Map[String, AnyRef] and static deseralize(map: java.util.Map[String, AnyRef]): MyType methods. It will also register the type to Bukkit's ConfigurationSerialization class when the ScalaPlugin enables by default. @ConfigurationSerializable is most useful for product types whilst @DelegateSerialization is useful for sum types. A more detailed example will follow when I'm done with this feature, but the ScalaExample on the git repository already shows how to use it. The things that are not properly serialized and deserialized yet are: types from the Scala standard library, arrays, arrays and collections of UUIDs, BigIntegers, BigDecimals, Characters, Bytes, Shorts, Longs and Floats.
- ScalaLoader collects metrics and uploads them to bstats.org. In addition to the standard charts, we'll be able to see which Scala versions are most in use by plugins using this pluginloader. Opting out can be done by editing the ./plugins/bStats/config.yml file.
- ScalaLoader is now released as a Multi-Release jar compatible with Java 8 again, but on Java 11 it may use some more effecient methods from the JDK.
- ScalaPlugins that require versions of Scala that are binary compatible with eachother will now use the same (newest) version at runtime. This includes Scala 3.0.0 for the Scala 2.13.x branch.
Changelog:
- Added 1.16 to the ApiVersion enum
- Added Scala 2.13.3 tothe ScalaVersion enum
- Updated to ASM 8
- Improved event-related bytecode transformations
Adds Scala 2.13.2 to the ScalaVersion enum.
2.13 milestone versions that were deprecated for removal have now been removed.
Adds the latest version of the Scala 2.12 series to the ScalaVersion enum.
Cheers!
This update fixes a bug where the primary constructor of a cancellable event wasn't always detected correctly and so the $cancel field wasn't injected in cases where it should have.
Now doesn't try to transform the ScalaPlugin's class files anymore using Bukkit's compatibility layer when ScalaLoader runs on Spigot 1.8.8-1.12.2.
Fixes a ClassCastException that was caused by the ScalaPluginClassLoader when it tried to find to find a class from another ScalaPlugin.
Whilst you could already use Bukkit's native event api, I added an event api specificly for ScalaPlugins that aims to be cleaner. Here are its features.
- extend xyz.janboerman.scalaloader.event.Event without having to provide the HandlerList boilerplate (of course you still can if you want).
- implement xyz.janboerman.scalaloader.event.Cancellable without having to provide isCancelled and setCancelled methods (of course you still can if you want).
- A a more type-safe version of PluginManager#registerEvent. The EventExecutor is type-constrained to the event that is being listenend on.
- Access the event bus right from your ScalaPlugin's main class, no need to call #getServer#getPluginManager, just call #getEventBus
- EventBus#callEvent returns a boolean - indicating whether the event is allowed to happen - always true for non-cancellable events.
All ScalaPlugin classes that use xyz.janboerman.scalaloader.event.{Event, Cancellable, EventExecutor} are transformed at class-load time to use their bukkit counterparts. Because of the way this works, JavaPlugins do not get the transformations - meaning they cannot use these types AT ALL, but using subtypes defined in ScalaPlugins will work just fine.
Some example code (also available on
github):
Code (Scala):
//event definition
import org.
bukkit.
entity.
Player
import org.
bukkit.
Location
import xyz.
janboerman.
scalaloader.
event.
{Cancellable, Event
}
case
class HomeTeleportEvent
(player
: Player, home
: Location
)
extends Event
with Cancellable
Code (Scala):
//code that executes the event
if
(ExamplePlugin.
getEventBus.
callEvent
(HomeTeleportEvent
(player, home
)
)
)
{
player.
teleport
(home
)
player.
sendMessage
(
"Welcome home!"
)
;
}
else
{
player.
sendMessage
(
"Some plugin prevented you from teleporting to your home!"
)
}
Code (Scala):
//event listener
import org.
bukkit.
event.
{EventHandler, Listener
}
object RandomHomeTeleportBlocker
extends Listener
{
@EventHandler
def onTeleportHome
(event
: HomeTeleportEvent
)
: Unit
=
{
event.
setCancelled
(Math.
random
(
)
<
0.5
)
;
}
}
That's it, happy Scala coding!
ScalaLoader's ScalaPluginClassLoader will now make use of Bukkit's bytecode transformation api in order to remove access to legacy constants.
Additionally the ApiVersion and ScalaVersion enums were updated to include new versions (bukkit api version 1.15 and scala version 2.12.10)
Note that as of this release, ScalaLoader requires a Java 11 or higher to run.
Cheers!
- Added Scala 2.13.1 to the ScalaVersion enum
- Updated own dependencies
- Adds Scala 2.13.0 to the ScalaVersion enum.
- ScalaPluginClassLoader can no longer find resources from the parent's classloader, meaning that ScalaPlugins could read ScalaLoader's config. Thanks to EpiCanard for reporting this bug.
ScalaPlugins that bundle Java libraries compiled with '--release 12' will now load correctly.
Cheers!
- Cleaned up some code that instantiates the ScalaPlugin instances
- Added Scala 2.12.8 to the ScalaVersion enum
Classes from ScalaPlugins can now load in parallel!
This extra method (ScalaPluginLoader#openUpToJavaPlugin(ScalaPlugin,JavaPlugin) injects the classes from scala plugins directly into the PluginClassLoader of a JavaPlugin, preventing it from searching the 'global' classes cache of the JavaPluginLoader.
This method does not inject the classes from scala libraries, just the classes from the ScalaPlugins themselves.
This comes with two big benefits:
- PluginLoading should be much faster again (I didn't perform any measurements)
- Plugins that depend on classes that are not available at runtime (e.g. plugin that depend on multiple NMS versions) don't crash when they're loaded if those classes aren't used at runtime.
This will affect JavaPlugins that depend on ScalaPlugins, they are by default not be able to find classes from the ScalaPlugin when used before the ScalaPlugin has used those classes themself.
An extra method to the ScalaPluginLoader was added to forcefully load all classes of a ScalaPlugin, to use it simply call ScalaPluginLoader.getInstance().forceLoadAllClasses(scalaPlugin) in the onEnable of your JavaPlugin. Make sure the JavaPlugin depends on ScalaLoader.
- Fixed a bug where sometimes the module-info.java was considered the best candidate for the main class of a ScalaPlugin
- Fixed a bug was caused when the plugin loader compared two classes that both weren't main classes of the ScalaPlugin
Allows ScalaPlugins to find classes of ScalaPlugins that use a binary compatible version of Scala. Previously the classloaders would only find classes from ScalaPlugins that used the exact same version of Scala.
- Add Scala version 2.12.7 to the ScalaVersion enumeration.
- Update ASM to version 7.0-beta and api level 7 (Opcodes.ASM7) to support the Java 11 class file format.
- Corrected typos.
This error occured at runtime when JavaPlugins try to find classes from a scalaplugin that weren't loaded yet by the ScalaPlugin itself.