Kludge
All of my Kotlin plugins use a library I’ve made called Kludge. It’s essentially a large collection of utilities, designed to take advantage of Kotlin’s extension, operator, and property support to simplify a few things. I’ve decided to release it since it could be useful to people.
Feature list
- A global plugin variable, so you don’t have to pass it to things like task builders.
- Text manipulation has never been so easy.
- A rich
replace
function. Never again mess about withTextTemplate
for on-the-fly replacement! Replace a string or regex with a text.- Formatting in the original text is perfectly preserved.
- Optionally enable lossy mode to allow some formatting to be lost in the event that the string to be replaced is spread out over multiple text children (use this for e.g. swear filtering color-code-enabled chat).
- You can’t use regex
$var
references in the replacement text, but I’m working on it!
- Convert to text anything that can be converted by using the
!
operator or thetext()
function, and convert to builder withtextBuilder()
. - Format any text convertibles into text immediately using provided
color
,format
, andstyle
functions, along with individual functions for each color and style, as well asonClick
,onHover
, andonShiftClick
.- This includes
Text
itself!
- This includes
- Use
+
to construct text or aText.Builder
, and-
to remove from aText.Builder
. You can even use+
onText
with a receiver closure. - ALL of this preserves types as much as possible. If you call
!"Text"
, you get aLiteralText
. If you callScoreText#red()
, you get aScoreText
. Etc. -
String
has two extra functions -textByJson
andtextByFormat
. - Join arrays or iterables to a text with
joinToText
.
- A rich
- Builders. Every builder in the API has a
whichamajiggerOf
style function , which you call with a receiver lambda, for Kotlin-style builders. Yes, every builder.-
dataRegistrationOf
,taskOf
, and other similar builders support the global plugin.
-
- Service properties. Why call the
ServiceManager
when you can just delegate a property to it? Just write your property like this:val svc: EconomyService? by Service
and when you call it, it’ll call theServiceManager
for you.- There’s also
UncheckedService
for non-nullable properties. - Use it like a constructor instead of an object to cache the result.
- There’s also
- A couple of
Optional
helpers. Useunwrap()
or the!
operator on anOptional
to convert it to a nullable type, and.optional()
on a nullable type to convert toOptional
. - Call
command()
on yourCommandExecutor
-applicable function to convert it into one, or pass it intoCommandSpec.Builder
directly. - Operator all the things!.
- The Data API:
- Use index getters and setters and the
in
operator forKeys
, classes,Value
s, etc. -
+=
and-=
add and remove data from holders -
%
and%=
work with raw data orfill
-
-=
rolls back a data transaction - Use the bare operator (i.e. without
=
) to get theDataTransactionResult
- Use index getters and setters and the
- Scoreboards:
-
Score
has full numerical functionality -
Team
has+=
,-=
, andin
for members -
Scoreboard
has+=
,-=
, andin
for objectives, and indexers forDisplaySlot
s -
Objective
has+=
,-=
, andin
forScore
s,-=
andin
for names, an indexer to get a score, and an invoker togetOrCreate
a score.
-
- Advancements:
-
ScoreCriterionProgress
has full numerical functionality -
AdvancementCriterion
'sand
andor
functions are now infix -
TreeLayout
has an indexer -
Advancement
now has atoastText
property
-
- Inventories:
-
+=
to add items to an inventory - Indexers for properties, queries, getting slots at indexes or positions, and setting items at indexes or positions.
- Invokers for peeking at items at indexes or positions
- Inventory now has a
slots
property, which fixes ducktyping on theslots()
function - In general just pretend the API was written with Kotlin in mind, and write anything that you think makes sense, and it’ll probably work
-
- Flow Math:
- All the vectory and matrixy types now support all the math operators they can
- The Data API:
- All the static singletons you get from
Sponge
andGameRegistry
now act like objects (you could callCommandManager.register
directly, etc.) -
UUID
hasplayer()
,user()
, andprofile()
functions -
Player
now has astorageInventory
property which gets theMainPlayerInventory
directly -
MessageReceiver
now has all the functions ofChatTypeMessageReceiver
. If the receiver happens to be aChatTypeMessageReceiver
, then its functions get called normally; otherwise, the extraChatType
argument is ignored and theMessageReceiver
functions are called instead. Because even a smart cast is too much boilerplate for message sending. If you care if theChatType
was actually used, the methods returntrue
if it was andfalse
if it wasn’t. -
Vector3d
now haseulerToDirection
anddirectionToEuler
. In addition,Transform
now has a.direction
property. - Command arguments can now be done with a closure. This removes the need to put
GenericArguments.
before your arguments.- Note that any custom
CommandElement
s you use must be prefixed with a+
in the closure. - You can also just generate a
CommandElement
directly, withcommandArgumentsOf
.
- Note that any custom
- Less
Task
noise.
*sync(plugin) { doThing() }
to run on the main server thread,async(plugin) { doThing() }
to run off the main server thread. If you’re already on the main server thread,sync
just executes immediately.-
delay(plugin, 30) { doThing() }
to delay by a certain number of ticks. - Coroutines! Use
task(plugin) { }
to begin a coroutine that usesTask
s for continuations.- Now you can write what you mean.
desync()
to move off the server thread,resync()
to move back on the server thread,delay
anddelayTicks
to wait for a period of time. All of these backend toTask
jumping. - Fully compatible with all other methods of starting or stopping coroutines.
- Now you can write what you mean.
- Supports the global plugin, letting you remove the
plugin
argument.
-
- Less
Item
noise.Player
has agive
function which deposits the item into their inventory and drops whatever didn’t fit on the ground next to them. - Less
ItemStack
noise.-
ItemType
,BlockType
,BlockState
,BlockSnapshot
andLocation
now havetoStack
functions which turn them intoItemStack
s. Optionally, open out a closure to keep customizing the builder. -
ItemStack.Builder
hasdisplayName
andlore
functions.
-
- Other little things like
String#toUUID()
andtypeTokenOf
.
Feel free to suggest more features!
How to include in your plugin
First, enable the shadow plugin if you haven’t already.
How to enable the shadow plugin
- Add to your
plugins
blockid 'com.github.johnrengelman.shadow' version '1.2.4'
. - Set
jar.enabled = false
andbuild.dependsOn shadowJar
. If you have the signing plugin enabled, addsignArchives.dependsOn shadowJar
. - Add to your
configurations
blockcompile.extendsFrom shadow
. - Create a
shadowJar
block:
shadowJar {
classifier = null
configurations = [project.configurations.shadow]
}
Add the Maven repository https://jitpack.io/
and the shadow
dependency com.github.pie-flavor:Kludge
.
- The ‘latest’ version is
master-SNAPSHOT
, but I would advise against using this as the API could break, and this isn’t going to be numerically versioned. Instead, for the version use the shortened commit hash you get from GitHub (eecb6d2
at the time of writing).
To prevent version conflicts with anyone else using it, add relocate 'flavor.pie.kludge', 'my.plugin.package.util'
to your shadowJar
block.
A recommended setting for IntelliJ IDEA is to go to Editor > Code Style > Kotlin > Imports
, and add flavor.pie.kludge
to Packages to Use Import with '*'
.