Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
*.kt text eol=lf
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,4 @@ jobs:
uses: actions/upload-artifact@v3
with:
name: partygames.jar
path: build/libs/partygames-*-dev-all.jar
path: pgame-plugin/build/libs/partygames-*-all.jar
4 changes: 2 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -112,13 +112,13 @@ gradle-app.setting
**/build/

# Common working directory
run/
run

# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored)
!gradle-wrapper.jar

.kotlin

src/main/resources/speedbuilders.zip
pgame-plugin/src/main/resources/speedbuilders.zip

SnifferHuntTreasureMapPlot
243 changes: 239 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,242 @@
## Dependencies
## Structure

The project is divided into two parts: the core API and the plugin for Mester Network.

### Core API

The core API is located in `pgame-api`. It is responsible for any game-related logic, such as loading the world, keeping
track of players, handling game events etc.

By itself it does not contain any minigames, they have to be registered by external plugins.

#### Dependencies

- AdvancedSlimePaper for MC 1.21.4

### Plugin

The plugin is located in `pgame-plugin`. It's the Party Games plugin for Mester Network and contains the specific
minigames for that server and other non-game related logic, including a leveling system.

#### Dependencies

- WorldEdit 7.3.10
- ViaVersion 5.2.1
- ScoreboardLibrary 2.2.2
- PlaceholderAPI 2.11.6
- PlaceholderAPI 2.11.6

## API Usage

### Including the API as dependency

To include the API as a dependency, add the following to your `build.gradle.kts`:

```kotlin
dependencies {
compileOnly(project(":pgame-api"))
}
```

Or if you're working in a different project, compile the API, copy pgame-api/build/libs/pgame-api-<version>-all.jar into
your project's libs folder and add it as a dependency.

```kotlin
dependencies {
compileOnly(files("libs/pgame-api-<version>-all.jar"))
}
```

Next, add `PartyGamesCore` as a dependency in your `paper-plugin.yml`:

```yaml
dependencies:
server:
PartyGamesCore:
load: BEFORE
required: true
join-classpath: true
```

### Registering minigames

To register a minigame, create a class that extends ˙Minigame`.

The base structure of a minigame class is as follows:

```kotlin
class MyMinigame(
game: Game,
) : Minigame(game, "minigame_name")
```

Don't deviate from this structure, it's important for the PartyGamesCore plugin to work properly. The minigame's name
can be anything you want, the convention is one word, using underscores for spaces. It is also case-insensitive so "
minigame_name" and "Minigame_Name" are the same and will result in an error when both are registered.

Next, you need to override `name`, `description` and `start`.

`name` is a `Component` and serves as a display name for the minigame. It is shown when the minigame is about to begin.

`description` is also a `Component` and serves as a description for the minigame.

`start` is a function that is executed when the minigame begins. You can use it to initialize the minigame, give items
to the players, summon mobs, etc.

Here is an example of a simple minigame that gives a stone to every player when the minigame begins:

```kotlin
class MyMinigame(
game: Game,
) : Minigame(game, "my_minigame") {
override fun start() {
super.start()
for (player in game.onlinePlayers) {
player.inventory.addItem(Material.STONE.createItem(1))
}
}

override val name = Component.text("My Minigame")
override val description = Component.text("This is a minigame!")
}
```

To extend the functionality of the minigame, you can override event functions such as `handlePlayerInteract`
or `handleBlockBreak`. To view a full list of events, see
the [Minigame](pgame-api/src/main/kotlin/info/mester/network/partygames/api/Minigame.kt) class.

#### Listening to more events

If you want to add more events to the minigame, you can extend the `Minigame` class and override the event functions.

For example, you might want to listen to the `BlockBreakBlockEvent`. To do that, first extend
the [PartyGamesListener](pgame-api/src/main/kotlin/info/mester/network/partygames/api/PartyGamesListener.kt) file with
the new event:

```kotlin
@EventHandler
fun onBlockBreakBlock(event: BlockBreakBlockEvent) {
// to access the minigame, you can use the getMinigameFromWorld function, which takes a World object and returns a nullable Minigame
// this also means that the event you're listening to MUST have a way to get the world it's happening in
val minigame = getMinigameFromWorld(event.block.world)
minigame?.handleBlockBreakBlock(event) // the question mark is used to only call the function if the minigame is not null
}
```

Then, add this new function to the [Minigame](pgame-api/src/main/kotlin/info/mester/network/partygames/api/Minigame.kt)
class:

```kotlin
open fun handleBlockBreakBlock(event: BlockBreakBlockEvent) {}
```

By marking the function as open, you can override it in your custom minigame class.

### Registering bundles

The API makes a distinction between singular minigames and bundles. A bundle is a collection of at least one minigame,
and this is what's actually playable.

To register a bundle, you first need to register your minigames.

In your plugin's `onEnable` function, first get the PartyGamesCore instance:

```kotlin
val core = PartyGamesCore.getInstance()
```

Then, register your minigames:

```kotlin
core.gameRegistry.registerMinigame(
this, // plugin
MyMinigame::class.qualifiedName!!, // className
"my_minigame", // name
listOf(
// worlds
MinigameWorld("my_minigame", org.bukkit.util.Vector(0.5, 63.0, 0.5)),
),
)
```

Let's break this down:

- `this` is the JavaPlugin instance of your plugin.
- `MyMinigame::class.qualifiedName!!` is the fully qualified name of your minigame class. (something
like `info.mester.network.testminigame.MyMinigame`)
- `"my_minigame"` is the name of your minigame. This HAS to be the same name you used in your minigame class.

The final parameter is a list of `MinigameWorld` objects. Each `MinigameWorld` object has a `name` and a `startPos`
property. You can think of tese worlds as the "maps" for your minigame. So if you specify more worlds, the API will
randomly pick one of them to load your minigame in, essentially providing multiple map layouts for the same minigame.
The `name` property is the name of the AdvancedSlimePaper world for the map, and the `startPos` is the starting position
of the minigame. This is where players will spawn when the minigame begins.

By itself, this minigame is not yet playable, as it is not part of a bundle. You can provide a `registerAs` parameter to
this function to register the minigame as a bundle.

```kotlin
core.gameRegistry.registerMinigame(
this,
MyMinigame::class.qualifiedName!!,
"my_minigame",
listOf(
MinigameWorld("my_minigame", org.bukkit.util.Vector(0.5, 63.0, 0.5)),
),
"My Minigame", // registerAs
)
```

The `registerAs` parameter is the user-friendly display name for the bundle. If you use register a minigame like this, a
bundle with the same name as the minigame will be created automatically.

Alternatively, you can register a bundle manually:

```kotlin
core.gameRegistry.registerBundle(
this, // plugin
listOf("my_minigame"), // minigames
"my_bundle", // name
"My Bundle", // displayName
)
```

This will create a bundle with the name "my_bundle" and use only the "my_minigame" as its minigames. This is mostly
useful if you want to register a bundle that contains multiple minigames.

### Starting a game

To start a game, you need to get the PartyGamesCore instance:

```kotlin
val core = PartyGamesCore.getInstance()
```

Then, you can start a game using the `startGame` function:

```kotlin
core.gameRegistry.startGame(players, "my_bundle")
```

The `players` parameter is a list of `Player` objects, and the `bundleName` parameter is the name of the bundle to start
the game in.

This immediately starts the game. If the bundle contains multiple minigames, their order will be randomly selected.

The `test-minigame` project contains examples of how to write minigames in Kotlin and Java.

### Creating the minigame worlds

Before a minigame can be started, you need to register the worlds you specified in the `worlds` parameter
of `registerMinigame` with AdvancedSlimePaper.

Join the ASP server with the core plugin and your custom plugin, then for each world you want to use, run the following
command:

```text
/swm create <world name> file
```

This will create a new, empty world with the name you specified. The world file will be saved in <server's root>
/slime_worlds/<world name>.slime

Now you can enter this world with `/swm goto <world name>` and start building it to your liking. The world is
periodically auto-saved, but you can always manually save with `/swm save <world name>`. To go back to the main world,
use `/swm goto world`.
103 changes: 9 additions & 94 deletions build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,92 +1,20 @@
plugins {
kotlin("jvm") version "2.1.0"
id("com.github.johnrengelman.shadow") version "8.1.1"
kotlin("jvm") version "2.1.0" apply false
id("io.papermc.paperweight.userdev") version "2.0.0-beta.14" apply false
id("org.sonarqube") version "4.2.1.3168"
id("io.papermc.paperweight.userdev") version "2.0.0-beta.13"
java
}

group = "info.mester.network.partygames"
version = "a1.0"
allprojects {
group = "info.mester.network.partygames"
version = "1.0-SNAPSHOT"

repositories {
mavenCentral()
maven("https://repo.papermc.io/repository/maven-public/")
maven("https://oss.sonatype.org/content/groups/public/")
maven("https://maven.enginehub.org/repo/")
maven("https://repo.rapture.pw/repository/maven-releases/")
maven("https://repo.infernalsuite.com/repository/maven-snapshots/")
maven("https://repo.viaversion.com")
maven("https://haoshoku.xyz:8081/repository/default")
maven("https://repo.extendedclip.com/content/repositories/placeholderapi/")
}

dependencies {
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
implementation(kotlin("reflect"))
// set up paper
paperweight.paperDevBundle("1.21.4-R0.1-SNAPSHOT")

compileOnly("com.squareup.okhttp3:okhttp:4.12.0")
compileOnly("net.objecthunter:exp4j:0.4.8")
// WorldEdit
compileOnly("com.sk89q.worldedit:worldedit-bukkit:7.3.10-SNAPSHOT")
// AdvancedSlimePaper
compileOnly("com.infernalsuite.aswm:api:3.0.0-SNAPSHOT")
// ViaVersion
compileOnly("com.viaversion:viaversion:5.2.1")
// Testing
testImplementation(kotlin("test"))
// ScoreboardLibrary
val scoreboardLibraryVersion = "2.2.2"
implementation("net.megavex:scoreboard-library-api:$scoreboardLibraryVersion")
runtimeOnly("net.megavex:scoreboard-library-implementation:$scoreboardLibraryVersion")
implementation("net.megavex:scoreboard-library-extra-kotlin:$scoreboardLibraryVersion") // Kotlin specific extensions (optional)
runtimeOnly("net.megavex:scoreboard-library-modern:$scoreboardLibraryVersion:mojmap")
// PlaceholderAPI
compileOnly("me.clip:placeholderapi:2.11.6")
// ConfigLib
implementation("de.exlll:configlib-paper:4.5.0")
}
val targetJavaVersion = 21
kotlin {
jvmToolchain(targetJavaVersion)
}

tasks {
processResources {
val props = mapOf("version" to version)
inputs.properties(props)
filteringCharset = "UTF-8"
filesMatching("paper-plugin.yml") {
expand(props)
}
}

build {
dependsOn("shadowJar")
}

register("writeVersion") {
doLast {
val versionFile =
layout.buildDirectory
.file("version.txt")
.get()
.asFile
versionFile.writeText(project.version.toString())
}
}

test {
useJUnitPlatform()
repositories {
mavenCentral()
}
}

tasks.register<Copy>("copyPluginToRun") {
dependsOn("build")
from(buildDir.resolve("libs").resolve("partygames-${project.version}-all.jar"))
into(rootDir.resolve("run").resolve("plugins"))
subprojects {
apply(plugin = "org.jetbrains.kotlin.jvm")
}

sonar {
Expand All @@ -95,16 +23,3 @@ sonar {
property("sonar.projectName", "Bedless Tournament")
}
}

sourceSets {
main {
java {
srcDir("src/main/kotlin")
}
}
test {
java {
srcDir("src/test/kotlin")
}
}
}
2 changes: 2 additions & 0 deletions gradle.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
org.jetbrains.dokka.experimental.gradle.pluginMode=V2Enabled
org.jetbrains.dokka.experimental.gradle.pluginMode.noWarn=true
Loading
Loading