-
Notifications
You must be signed in to change notification settings - Fork 0
Utlis
The JuliGamesCore has a variety of util classes all over the different modules. On this page, I want to introduce you to some of these classes and their features to help you out with tasks that are already done in the Core. I will split this into two different sections:
- static utils
- non-static utils
The static utils are just classes with public static methods that can help you out with developing using the Core and the non-static ones are classes that are not accessible through
API.get()
orCore.getInstance()
.
Note: I will add "prompts" to this list. This are classes that can be used together with ConversationLIB, but I will not include normal Interpreters here!
I will use the natural order of the modules in the project to sort the different entries here
net.juligames.core.adventure.api.MessageRepresentation
This class is an implementation of the Adventure interface ComponentLike
and can be used for converting between Messages from the Core and Components from Adventure. You can use this implementation by creating an instance of it with the message you want to represent. You should be able to use this MessageRepresentation as a parameter for Component demanding methods now!
Example:
final Audience audience = Audience.empty();
final MessageRecipient messageRecipient = AudienceMessageRecipient.getByPointer(audience);
final Message helloWorld =
API.get().getMessageApi().findBestMessageForRecipient("helloworld.message", messageRecipient);//italy (just an example)
final MessageRepresentation messageRepresentation = new MessageRepresentation(helloWorld);
audience.showTitle(Title.title(messageRepresentation.asComponent(), Component.empty()));
audience.sendMessage(messageRepresentation);
audience.sendActionBar(messageRepresentation);
audience.sendPlayerListHeaderAndFooter(messageRepresentation, Component.empty());
Please note that this example just shows the syntax. You can use a different way to get hold of a Message
object then using findBestMessageForRecipient
!
As we defined above this class is not a "static util", but I suggest using the static factory methods that are provided to avoid the pain we had in the example above. So let us do what we did in the example above but using the factory methods:
Example:
final Audience audience = Audience.empty();
final MessageRepresentation messageRepresentation = MessageRepresentation.represent("helloworld.message", audience);
audience.showTitle(Title.title(messageRepresentation.asComponent(), Component.empty()));
audience.sendMessage(messageRepresentation);
audience.sendActionBar(messageRepresentation);
audience.sendPlayerListHeaderAndFooter(messageRepresentation, Component.empty());
As we see it is much easier to do so, but it is not as dynamic and versatile as the first option. If possible I would suggest using this static approach. We also need to keep in mind that this MessageRepresentation
should not be used for just sending messages.
net.juligames.core.adventure.api.prompt.BackedPrompt
net.juligames.core.adventure.api.prompt.ConfigurationPrompt
net.juligames.core.adventure.api.prompt.DictionaryBackedPrompt
net.juligames.core.adventure.api.prompt.IndexBackedPrompt
net.juligames.core.adventure.api.prompt.MapBackedPrompt
net.juligames.core.adventure.api.prompt.MiniMessagePrompt
net.juligames.core.adventure.api.prompt.NamedTextColorPrompt
net.juligames.core.adventure.api.prompt.SpacePrompt
net.juligames.core.adventure.api.prompt.VoidPrompt
net.juligames.core.adventure.api.LegacyMessageDealer
The LegacyMessageDealer is a utility implementation of CustomMessageDealer
. This implementation allows you to convert legacy messages to miniMessages using Adventure. You might need to give a CustomMessageDealer
as a parameter in different methods. This can be used for example to introduce legacy messages into the message system. We know that only valid MiniMessages with or without replacements are allowed in the message system database, so we need to convert the legacy message to an accepted format.
Example:
API.get().getMessageApi().registerThirdPartyMessage(
"legacyplugin.message1",
"&1 This is a legacy message",
new LegacyMessageDealer(LegacyMessageType.AMPERSAND));
Here we also use the LegacyMessageType (net.juligames.core.api.message.LegacyMessageType)!
net.juligames.core.api.err.dev.TODOException
The TODOException can be used in methods that are still in development but the current version should be compiled. I always recommend using this Exception together with the @TODO
Annotation. The Exception will display the following text: "not implemented yet"!
Example:
/**
* @return if the core is connected and ready for operation
*/
@TODO(doNotcall = true)
public boolean isAlive() {
throw new TODOException();
}
This code is part of the Core since the Michael versions because i still haven't figured out a 100% save way to identify if the connection of the Core is alive or not...
net.juligames.core.api.err.APIException
This exception can be used if an implementation to a service or core is missing. Currently, it is only used internally.
net.juligames.core.api.external.AdventureWebuiEditorAPI
This class is a bit more exciting than what we had above. This class allows you to interact with an AdventureWebUI. You can use this class to start and retrieve sessions and so display and change miniMessages. If you want further information on the adventure-webui API then check out their wiki: Editor-API Wiki.
Example:
final AdventureWebuiEditorAPI adventureWebuiEditorAPI
= new AdventureWebuiEditorAPI(); //default juligames production webui
//generate a link for a new empty session
String link = adventureWebuiEditorAPI.startSessionAndGenerateLink("/yourCommand {token}");
//give the link to the user now
//this would be executed in your "command execution" - to retrieve the session back
String[] args = new String[1]; // the "args"
CompletableFuture<String> stringCompletableFuture = adventureWebuiEditorAPI.retrieveSession(args[0]);
try {
String miniMessage = stringCompletableFuture.get();
} catch (InterruptedException | ExecutionException e) {
throw new RuntimeException(e);
}
This Example shows a way to use this API
net.juligames.core.api.misc.APIUtils This is the primary utils class for the API. Currently, with 1.6 it contains mostly stuff about executing runnables and allowing exceptions.
net.juligames.core.api.misc.DurationFormatUtils
This class allows you to format Durations
to different formats including one localized text format that uses words to describe the duration.
This utility also supports custom formatting and a Token based representation of durations.
Example:
final Duration duration = Duration.ofDays(2); //demo
String hms = DurationFormatUtils.formatDurationHMS(duration.toMillis());
String iso = DurationFormatUtils.formatDurationISO(duration.toMillis());
String words = DurationFormatUtils.formatDurationWords(duration.toMillis(), false, true);
Map<String, String> localisation =
DurationFormatUtils.getLocalisationFromMessageSystem(Locale.forLanguageTag("DE_DE"), AdventureAPI.get().getAdventureTagManager());
String de_de = DurationFormatUtils.formatDurationWords(duration.toMillis(), false, false, AdventureAPI.get().getAdventureTagManager(), Locale.forLanguageTag("DE_DE"));
net.juligames.core.api.misc.EntryInterpretationUtil
This class allows you to interpret or reverse Entries without the need to break them apart and build them back together manually. You can interpret/reverse single Entries, collections, or whole maps. All Maps / Collections returned by the methods in this class are always unmodifiable!
Example:
Map<File, URL> fileURLMap = new HashMap<>();
Map<String, String> stringStringMap = EntryInterpretationUtil.reverseMap(fileURLMap, BuildInInterpreters.fileInterpreter(), BuildInInterpreters.urlInterpreter());
Map<File, URL> fileURLMap1 = EntryInterpretationUtil.interpretMap(stringStringMap, BuildInInterpreters.fileInterpreter(), BuildInInterpreters.urlInterpreter());
assert fileURLMap1.equals(fileURLMap);
Stream<Map.Entry<String, String>> entryStream = fileURLMap.entrySet().stream().map(fileURLEntry -> EntryInterpretationUtil.reverseEntry(fileURLEntry, BuildInInterpreters.fileInterpreter(), BuildInInterpreters.urlInterpreter()));
net.juligames.core.api.misc.GenericHashtableToStringHashtableMapper
This Mapper can be used inside and outside of Streams to work with Hashtables. It acts similarly to the EntryInterpretation we discussed above, but this one is only one-way and was developed before the EntryInterpretationUtil was introduced so there is only limited usage for it now. Because of this I will not include an example for this here, it is very similar to what we have done in the example with the Stream above.
net.juligames.core.api.misc.LoggerMessageRecipient
This class is a bit unconventional and does not fit 100% into this page, but I think it is important to include it somewhere. This class is an implementation of the MessageReciepent used to send messages from the message system. So this class can be used to send messages to a Logger instead of a player. This can be useful for debugging, troubleshooting, or error handling. It should not be used to send messages to the console on platforms that support adventure or have a native address for such messages already implemented. The record wants you to provide a MiniMessageSerializer because not all Core Platforms support adventure. If you set this parameter to null
the messages sent to this LoggerMessageRecipient
will not be parsed. Replacements stored within the Message itself will be replaced and will work, but all formatting we be displayed as "miniMessage"
net.juligames.core.api.misc.ObjectHashtableToStringHashtableMapper
This is also similar to the GenericHashtableToStringHashtableMapper
, but it does not use Interpreters to convert to a String. This function just uses Object#toString
to convert. That makes it usable in a reference style.
You should only use this utility if you really know what you are doing and you know what data is flowing through it.
This is the implementation of the #apply method that is used:
@Override
public Hashtable<String, String> apply(@NotNull Hashtable<Object, Object> objectObjectHashtable) {
final Hashtable<String, String> stringStringHashtable = new Hashtable<>();
objectObjectHashtable.forEach((key, value) -> stringStringHashtable.put(key.toString(), value.toString()));
return stringStringHashtable;
}
net.juligames.core.api.misc.ThrowableDebug
This class is widely used over the core and its associated projects. With the ThrowableDebug it becomes possible to swallow expected exceptions and only print them to the log if the logger has to debug enabled. This relieves you from deciding to swallow an exception fully or printing it and possibly raising the suspicion that the error is a serious problem.
Here are examples of how to utilize this class:
Printing a warning and displaying the stack trace only if debug is requested (real code form core)
@Override
@Nullable
public <T, R> R withExtension(Class<T> dao, ExtensionCallback<R, T, Exception> extensionCallback) {
try {
return jdbi.withExtension(dao, extensionCallback);
} catch (Exception e) {
getLogger().warning("failed to execute extension: " + e.getMessage());
ThrowableDebug.debug(e);
return null;
}
}
Printing cached exceptions:
/**
* This will send the permissible the lacking permission message "paper.permission.lacking"
*/
default void sendLackingPermissionMessageIfPossible() {
if (!wasSuccessful()) {
recipientFromPermissible(permissible()).ifPresent(messageRecipient ->
API.get().getMessageApi().sendMessage(ERROR_KEY, messageRecipient));
API.get().getAPILogger().error("failed to check permission \"" + permissionName() + "\" for " + permissible() + " : " + exceptions());
for (Exception exception : exceptions()) {
ThrowableDebug.debug(exception);
}
}
if (!getResult()) {
recipientFromPermissible(permissible()).ifPresent(messageRecipient ->
API.get().getMessageApi().sendMessage(LACKING_KEY, messageRecipient, new String[]{permissionName()}));
}
}
(The core has more Utilities, but most of them are very dependent on their only usage and so they are not suitable to be listed here)
net.juligames.core.util.ConsumingLogger
This logger logs the individual records not to a printer or a storage unit, it just puts them into a BiConsumer
, that allows you to handle log output functional.
I'm still thinking about moving this file to: de.bentzin.tools.logging within the DevTools project
net.juligames.core.util.ShuffleUtil
The ShuffleUtil allows you to shuffle Collections into a random order. This util is specifically developed to be used with Streams.
Example:
List<String> shuffled = List.of("a", "b", "c", "d", "e").stream().collect(ShuffleUtil.toShuffledList());
If you need assistance with your setup, development, or configuration, feel free to reach out to me via email ©Ture Bentzin 2023