Entry point
The FlectonePulse interface, dependency injection through Google Guice, project lifecycle and error handling
Work with the API starts from two classes
| Class | What it is for |
|---|---|
net.flectone.pulse.FlectonePulseAPI | Holds the running instance and drives its lifecycle |
net.flectone.pulse.FlectonePulse | Gives dependency injection, reload and access to the platform |
import net.flectone.pulse.FlectonePulse;
import net.flectone.pulse.FlectonePulseAPI;
FlectonePulse flectonePulse = FlectonePulseAPI.getInstance();FlectonePulseAPI
| Method | Returns | What it does |
|---|---|---|
getInstance() | FlectonePulse | Gives the running instance, or null while the project has not loaded |
isDisabling() | boolean | Gives true while the project is shutting down |
While isDisabling() gives true, do not start new tasks and do not touch the database. The project is already winding down at that point
FlectonePulse
| Method | Returns | What it does |
|---|---|---|
get(Class<T>) | T | Gives a component from Guice |
isReady() | boolean | Checks whether the injector is ready |
reload() | void | Rereads the configuration and throws ReloadException on failure |
getLoader() | Object | Gives the native plugin or mod object of the platform |
hook(HookType, Object...) | void | Calls a platform extension point |
onLoad(), onEnable(), onDisable() | void | Internal lifecycle, called by the platform |
throwInitException(Exception) | void | Wraps an error into InitException |
get(Class<T> type)
Gives a component from the injector. Almost every component is declared as an interface, and implementations are marked @Singleton, so repeated calls give you the same object
import net.flectone.pulse.dispatcher.MessageDispatcher;
import net.flectone.pulse.logging.FLogger;
import net.flectone.pulse.platform.registry.ListenerRegistry;
import net.flectone.pulse.service.FPlayerService;
FLogger fLogger = flectonePulse.get(FLogger.class);
FPlayerService fPlayerService = flectonePulse.get(FPlayerService.class);
MessageDispatcher messageDispatcher = flectonePulse.get(MessageDispatcher.class);
ListenerRegistry listenerRegistry = flectonePulse.get(ListenerRegistry.class);Check readiness through isReady() before calling get(), otherwise you get InjectorNotInitializedException
Ask for the interface, not the implementation. Implementations live in closed modules and differ between platforms
// correct
FPlayerService service = flectonePulse.get(FPlayerService.class);
// wrong, there is no FPlayerServiceImpl class in the api artifact
FPlayerServiceImpl service = flectonePulse.get(FPlayerServiceImpl.class);isReady()
Checks whether the dependency injector is up
if (flectonePulse.isReady()) {
FLogger fLogger = flectonePulse.get(FLogger.class);
fLogger.info("API is ready");
}reload()
Reloads the configuration, the same thing the /flectonepulse reload command does
import net.flectone.pulse.exception.ReloadException;
try {
flectonePulse.reload();
getLogger().info("FlectonePulse reloaded");
} catch (ReloadException e) {
getLogger().severe("Reload failed " + e.getMessage());
}Reload drops every listener except those added through registerPermanent(). Details live on the event system page
getLoader()
Gives the native loader object of the current platform. Handy when you need a platform API that FlectonePulse does not abstract
| Platform | Object type |
|---|---|
| Bukkit and Paper | org.bukkit.plugin.java.JavaPlugin |
| BungeeCord | net.md_5.bungee.api.plugin.Plugin |
| Velocity | the Velocity plugin object |
| Fabric and NeoForge | the mod container |
| Hytale | the Hytale mod loader |
JavaPlugin pulsePlugin = (JavaPlugin) flectonePulse.getLoader();hook(HookType type, Object... args)
Extension points through which the core calls the platform layer. The project calls them itself, and you need them by hand only for low level integration
HookType | When it fires |
|---|---|
CONFIGURE_SERIALIZATION | Platform serialization setup |
PRE_NEW_PLAYER_PLACE | Before a new player is placed in the world |
ON_PLAYER_PRE_LOGIN | Player check before login |
ON_PLAYER_LOGIN | Player login |
POST_RESPAWN | After a player respawns |
INIT_PACKET_ADAPTER | Packet adapter startup |
TERMINATE_PACKET_ADAPTER | Normal packet adapter shutdown |
TERMINATE_FAILED_PACKET_ADAPTER | Adapter shutdown after a failed startup |
CLOSE_UIS | Closing every open interface |
SIMPLEVOICE_ENTITY_SOUND_PACKET | Simple Voice Chat entity sound packet |
SIMPLEVOICE_MICROPHONE_PACKET | Simple Voice Chat microphone packet |
import net.flectone.pulse.constant.HookType;
// close every open FlectonePulse interface
flectonePulse.hook(HookType.CLOSE_UIS);throwInitException(Exception e)
Wraps an error into InitException. In normal mode the message is cut down to 25 lines, and in debug mode it stays whole
try {
// risky startup work
} catch (Exception e) {
flectonePulse.throwInitException(e); // always throws InitException
}Debugging
Debug mode turns on with a system property at server startup
java -Dflectonepulse.debug=true -jar server.jarIn this mode FlectonePulse keeps error messages whole and writes detailed startup logs
Exceptions
Every exception lives in the net.flectone.pulse.exception package
| Exception | When it arrives |
|---|---|
InjectorNotInitializedException | get() was called before the injector was ready |
InitException | Failure during project startup |
ReloadException | Failure during a reload() call |
LoadingException | Failure while loading the project |
LibraryLoadException | A library could not be downloaded or attached |
FileLoadException | Failure while reading the configuration |
FileWriteException | Failure while writing the configuration |
ListenerRegistrationException | A broken listener or @Pulse method |
CacheRegistrationException | Failure while registering a cache |
DatabaseNotInitializedException | The database was used before it was connected |
UnsupportedDatabaseOperationException | The chosen database does not support the operation |
ProxyMessageCreateException | Failure while building a proxy message |
SchedulerTaskException | Failure inside a scheduler task |
ReflectionException | Reflection failure in the platform layer |
ReloadException and SchedulerTaskException extend Exception, so you have to handle or rethrow them. Every other one extends RuntimeException