Skip to content

Commit 8b5a92b

Browse files
authored
Merge pull request #8 from integr-dev/develop
Enhance event and scripting systems with new features and fixes
2 parents a652e48 + ae96d33 commit 8b5a92b

28 files changed

Lines changed: 1782 additions & 128 deletions

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,4 @@
33
/.gradle/
44
/run/
55
/.kotlin/
6+
/logs/

README.md

Lines changed: 14 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11

2+
<!--suppress CheckImageSize -->
23
<img alt="logo.png" src="logo.png" width="20%"/>
34

45
# Backbone
@@ -7,7 +8,7 @@
78
![GitHub last commit](https://img.shields.io/github/last-commit/integr-dev/backbone)
89
[![GitHub license](https://img.shields.io/github/license/integr-dev/backbone)](https://github.com/integr-dev/backbone/blob/master/LICENSE)
910

10-
Backbone is a powerful and flexible plugin for Spigot-based Minecraft servers, designed to supercharge server customization. Its core philosophy is to enable server administrators and developers to write, test, and update server logic on a live server without requiring restarts, dramatically accelerating the development lifecycle.
11+
Backbone is a powerful and flexible plugin for Spigot-based Minecraft servers, designed to supercharge server customization. Its core philosophy is to enable server administrators and developers to write, test, and update server logic on a live server without requiring restarts, dramatically speeding up the development lifecycle.
1112

1213
Whether you're a server administrator looking to add custom features with simple scripts or a developer prototyping new ideas, Backbone provides the tools you need to be more productive and creative.
1314

@@ -17,7 +18,7 @@ Whether you're a server administrator looking to add custom features with simple
1718
- **Advanced Scripting:** Go beyond simple scripts with support for inter-script imports, Maven dependencies, and custom compiler options.
1819
- **Event System:** A custom event bus that complements Bukkit's event system, offering more control and flexibility within your scripts.
1920
- **Command Framework:** A simple yet powerful command system to create custom commands directly from your scripts.
20-
- **Storage Abstraction:** Easily manage data with a flexible storage system that supports SQLite databases and typed configuration files.
21+
- **Storage Abstraction:** Manage data with a flexible storage system that supports SQLite databases and typed configuration files.
2122
- **GUI Framework:** A declarative GUI framework for creating complex and interactive inventories from your scripts.
2223
- **Text Formatting:** A flexible text formatting system with support for custom alphabets and color codes.
2324
- **Entity Framework:** Custom entity utility for adding custom entities via the goals api.
@@ -26,11 +27,11 @@ Whether you're a server administrator looking to add custom features with simple
2627

2728
## Getting Started
2829

29-
Getting started with Backbone is simple. The primary way to use Backbone is by installing it as a plugin and then creating your own custom features through its scripting engine.
30+
Getting started with Backbone is straightforward. The primary way to use Backbone is by installing it as a plugin and then creating your own custom features through its scripting engine.
3031

3132
### Requirements
3233
- Minecraft Java Edition Server version 1.21 or higher.
33-
- [PlaceholderAPI](https://www.spigotmc.org/resources/placeholderapi.62/) (optional, for placeholder support).
34+
- [PlaceholderAPI](https://modrinth.com/plugin/placeholderapi) (optional, for placeholder support).
3435

3536
### Installation
3637
1. **Download:** Download the latest release from the [official releases page](https://github.com/integr-dev/backbone/releases).
@@ -186,7 +187,7 @@ This will create directories at `storage/mystorage/` and `config/myconfig/` in y
186187

187188
#### Configuration
188189

189-
You can easily manage typed configuration files. Backbone handles the serialization and deserialization of your data classes automatically.
190+
You can manage typed configuration files. Backbone handles the serialization and deserialization of your data classes automatically.
190191

191192
First, define a serializable data class for your configuration:
192193

@@ -215,7 +216,6 @@ configHandler.writeState(currentConfig.copy(settingB = 20))
215216
#### Databases
216217

217218
Backbone provides a simple and efficient way to work with SQLite databases from within your scripts.
218-
219219
```kotlin
220220
// Get a connection to a database file named 'playerdata.db'
221221
val dbConnection = myScriptStorage.database("playerdata.db")
@@ -239,7 +239,7 @@ dbConnection.useConnection {
239239

240240
### Custom Events
241241

242-
Backbone's event system allows you to create and listen for custom events, giving you more control over your script's behavior.
242+
Backbone's event system allows you to create and listen to custom events, giving you more control over your script's behavior.
243243

244244
```kotlin
245245
// Define a custom event
@@ -250,7 +250,7 @@ class MyCustomEvent(val message: String) : Event()
250250
@BackboneEventHandler(EventPriority.THREE_BEFORE)
251251
fun onMyCustomEvent(event: MyCustomEvent) {
252252
println("Received custom event: ${event.message}")
253-
event.setCallback("yay!")
253+
event.callback = "yay!"
254254
}
255255

256256
// Fire the custom event from anywhere in your code
@@ -279,14 +279,14 @@ object MyCommand : Command("mycommand", "My first command") {
279279
}
280280

281281
override suspend fun exec(ctx: Execution) {
282-
// Require a permission for this command
282+
// Require permission for this command
283283
ctx.requirePermission(perm.derive("mycommand")) // "myplugin.mycommand"
284284

285285
val text = ctx.get<String>("text")
286286

287287
ctx.respond("Hello ${ctx.sender.name}: $text")
288288

289-
// To affect server state, dispatch to the main thread for the next tick.
289+
// To affect the server state, dispatch to the main thread for the next tick.
290290
Backbone.dispatchMain {
291291
val player = ctx.getPlayer() // Get the sender as a player (and require it to be one)
292292
player.world.spawnEntity(player.location, EntityType.BEE)
@@ -382,7 +382,7 @@ Backbone allows you to create custom entities with unique AI goals.
382382
// Define a custom entity that is a non-moving zombie
383383
object GuardEntity : CustomEntity<Zombie>("guard", EntityType.ZOMBIE) {
384384
override fun prepare(mob: Zombie) {
385-
// Set up for example armor
385+
// Set up, for example, armor
386386
}
387387

388388
override fun setupGoals(mob: Zombie) {
@@ -398,7 +398,7 @@ override fun onLoad() {
398398
Backbone.Handlers.ENTITY.register(GuardEntity)
399399
}
400400

401-
// You can then spawn the entity for example using a command
401+
// You can then spawn the entity, for example, using a command
402402
// In a command's exec method:
403403
GuardEntity.spawn(ctx.getPlayer().location, ctx.getPlayer().world)
404404
```
@@ -467,7 +467,7 @@ component {
467467

468468
#### Command Feedback Format
469469

470-
You can create a custom `CommandFeedbackFormat` to change how command responses are displayed. Or simply inherit from it to unlock even more customisation via the component system.
470+
You can create a custom `CommandFeedbackFormat` to change how command responses are displayed. Or inherit from it to unlock even more customization via the component system.
471471

472472
```kotlin
473473
val myFormat = CommandFeedbackFormat("MyPlugin", Color.RED)
@@ -486,12 +486,7 @@ You can create your own custom alphabets by implementing the `Alphabet` interfac
486486

487487
```kotlin
488488
object MyAlphabet : Alphabet {
489-
const val ALPHABET = "..." // Your custom alphabet characters
490-
491-
override fun encode(str: String): String {
492-
// Your encoding logic here
493-
return "encoded_string"
494-
}
489+
override val alphabet = "..." // Your custom alphabet characters
495490
}
496491
```
497492

build.gradle.kts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ plugins {
77
}
88

99
group = "net.integr"
10-
version = "1.2.0"
10+
version = "1.4.0"
1111

1212
repositories {
1313
mavenCentral()
@@ -41,7 +41,7 @@ dependencies {
4141

4242
implementation("org.apache.ivy:ivy:2.5.2")
4343

44-
implementation("tools.jackson.core:jackson-databind:3.0.4")
44+
implementation("tools.jackson.core:jackson-databind:3.1.0")
4545
implementation("tools.jackson.dataformat:jackson-dataformat-yaml:3.0.4")
4646
implementation("tools.jackson.module:jackson-module-kotlin:3.0.4")
4747

src/main/kotlin/net/integr/backbone/Backbone.kt

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@ import org.jetbrains.annotations.ApiStatus
3636
* @since 1.0.0
3737
*/
3838
object Backbone {
39-
//TODO: dialogues, command help builder
4039
/**
4140
* Backbones internal storage pool. **Important:** Do not use this.
4241
* Create a new pool instead:
@@ -109,12 +108,15 @@ object Backbone {
109108

110109
/**
111110
* The internally checked plugin instance.
112-
* Null if we are in a testing environment.
111+
* Null if we are not in a plugin environment.
112+
*
113+
* This is used to avoid null checks in the codebase.
114+
* If you are not in a plugin environment, you can safely ignore this.
113115
*
114116
* @since 1.0.0
115117
*/
116118
private val pluginInternal: JavaPlugin? by lazy {
117-
Utils.tryOrNull { JavaPlugin.getPlugin(BackboneServer::class.java) } // For testing purposes
119+
Utils.tryOrNull { JavaPlugin.getPlugin(BackboneServer::class.java) } // For testing purposes we allow null here
118120
}
119121

120122
/**
@@ -144,28 +146,28 @@ object Backbone {
144146

145147
/**
146148
* Registers a listener to the server's plugin manager and the internal event bus.
149+
* 1. Registers the listener with the internal event bus.
150+
* 2. Registers the listener with the plugin manager.
147151
*
148152
* @param listener The listener to register.
149153
*
150154
* @since 1.0.0
151155
*/
152156
fun registerListener(listener: Listener) {
153-
LOGGER.info("Registering listener: ${listener.javaClass.name}")
154-
SERVER.pluginManager.registerEvents(listener, PLUGIN)
155157
EventBus.register(listener)
158+
SERVER.pluginManager.registerEvents(listener, PLUGIN)
156159
}
157160

158161
/**
159162
* Removes a listener from the server's plugin manager and the internal event bus.
160163
*
161-
* @param listener The listener to register.
164+
* @param listener The listener to unregister.
162165
*
163166
* @since 1.0.0
164167
*/
165168
fun unregisterListener(listener: Listener) {
166-
LOGGER.info("Unregistering listener: ${listener.javaClass.name}")
167-
HandlerList.unregisterAll(listener)
168169
EventBus.unregister(listener)
170+
HandlerList.unregisterAll(listener)
169171
}
170172

171173
/**

src/main/kotlin/net/integr/backbone/BackboneLogger.kt

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,26 @@ class BackboneLogger(name: String) : Logger(name, null) {
7171
if (record.level == Level.SEVERE) logFile.appendText(fileMessage + "\n")
7272
}
7373

74+
/**
75+
* Flushes any buffered output.
76+
*
77+
* This implementation is intentionally empty as the handler writes directly to
78+
* the console (via `println`) and file (via `appendText`), both of which handle
79+
* their own flushing automatically.
80+
*
81+
* @since 1.0.0
82+
*/
7483
override fun flush() {}
84+
85+
/**
86+
* Closes the handler and releases any associated resources.
87+
*
88+
* This implementation is intentionally empty as the handler does not maintain
89+
* any resources that require explicit cleanup. The log file is opened and closed
90+
* on each write operation, and console output requires no cleanup.
91+
*
92+
* @since 1.0.0
93+
*/
7594
override fun close() {}
7695
}
7796

src/main/kotlin/net/integr/backbone/Utils.kt

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@
1313

1414
package net.integr.backbone
1515

16+
import net.kyori.adventure.builder.AbstractBuilder
17+
import kotlin.reflect.full.declaredMemberFunctions
18+
1619
/**
1720
* Utility functions for various tasks.
1821
* @since 1.0.0
@@ -54,4 +57,41 @@ object Utils {
5457
fun isUid(string: String): Boolean {
5558
return string.matches("^[a-z0-9]{8}-[a-z0-9]{4}-[a-z0-9]{4}-[a-z0-9]{4}-[a-z0-9]{12}$".toRegex())
5659
}
60+
61+
/**
62+
* Used to more easily get the result of a builder with applied block.
63+
*
64+
* Example:
65+
* ```kotlin
66+
* val builder = Something.builder()
67+
* builder.block()
68+
* val result = builder.build()
69+
* ```
70+
*
71+
* is changed to
72+
*
73+
* ```kotlin
74+
* val result = blockBuild(Something.builder(), block)
75+
* ```
76+
*
77+
* Invokes a builders build method via reflection.
78+
* Does not run any safety checks. It is your job to figure out
79+
* if this will work or not.
80+
*
81+
* @param T the builder class
82+
* @param U the builders result class
83+
* @param builder the builder instance
84+
* @param block the block to apply to the builder
85+
* @since 1.4.0
86+
*/
87+
inline fun <reified T : Any, U> blockBuild(builder: T, block: T.() -> Unit): U {
88+
builder.block()
89+
// Assume a build method is there
90+
val method = builder::class.java.getDeclaredMethod("build")
91+
92+
// It is the users duty to only call this on builders with this signature
93+
@Suppress("UNCHECKED_CAST")
94+
val result = method.invoke(builder) as U
95+
return result
96+
}
5797
}

0 commit comments

Comments
 (0)