Skip to content

Commit c63110d

Browse files
committed
Preliminary Fabric, NeoForge support and various other improvements
1 parent bd55e6d commit c63110d

27 files changed

Lines changed: 592 additions & 64 deletions

File tree

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ A battery packed, multi-platform plugin template for Minecraft servers to get yo
66
- [Cloud](https://github.com/Incendo/cloud) for platform-agnostic command registration and handling.
77
- [Configurate](https://github.com/SpongePowered/Configurate) for cross-platform configuration.
88

9-
Currently supporting Bukkit, Bungeecord, Paper and Velocity.
9+
Currently supporting Bukkit, Bungeecord, Fabric, NeoForge, Paper and Velocity.
1010

1111
## License
1212
This project is licensed under the [CC0 1.0 Universal](https://github.com/RealTriassic/plugin-template/blob/main/LICENSE) license, meaning you are free to use this project however you like, including changing the license for your own projects.

bootstrap/bukkit/src/main/java/dev/triassic/template/bukkit/BukkitTemplatePlugin.java

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -61,11 +61,15 @@ public void onEnable() {
6161
)
6262
);
6363

64-
if (this.commandManager.hasCapability(CloudBukkitCapabilities.NATIVE_BRIGADIER)) {
65-
this.commandManager.registerBrigadier();
66-
} else if (this.commandManager.hasCapability(
67-
CloudBukkitCapabilities.ASYNCHRONOUS_COMPLETION)) {
68-
this.commandManager.registerAsynchronousCompletions();
64+
/* Since we are using LegacyPaperCommandManager, we must check and register
65+
platform capabilities ourselves. First we check for Brigadier support, before
66+
resorting to using Asynchronous completion, if Brigadier is not available.
67+
68+
https://cloud.incendo.org/minecraft/paper/#execution-coordinators */
69+
if (commandManager.hasCapability(CloudBukkitCapabilities.NATIVE_BRIGADIER)) {
70+
commandManager.registerBrigadier();
71+
} else if (commandManager.hasCapability(CloudBukkitCapabilities.ASYNCHRONOUS_COMPLETION)) {
72+
commandManager.registerAsynchronousCompletions();
6973
}
7074

7175
this.impl = new TemplateImpl(this);
@@ -74,12 +78,12 @@ public void onEnable() {
7478

7579
/**
7680
* Called when the plugin is disabled.
77-
*
78-
* <p>Cleans up resources to increase the likelihood of a successful reload.</p>
7981
*/
8082
@Override
8183
public void onDisable() {
82-
impl.shutdown();
84+
if (impl != null) {
85+
impl.shutdown();
86+
}
8387

8488
if (adventure != null) {
8589
adventure.close();

bootstrap/bukkit/src/main/resources/plugin.yml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,4 @@ main: dev.triassic.template.bukkit.BukkitTemplatePlugin
44
description: ${description}
55
author: ${author}
66
website: ${url}
7-
api-version: "1.13"
8-
folia-supported: true
7+
api-version: "1.13"

bootstrap/bungeecord/src/main/java/dev/triassic/template/bungee/BungeeTemplatePlugin.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -66,12 +66,12 @@ public void onEnable() {
6666

6767
/**
6868
* Called when the plugin is disabled.
69-
*
70-
* <p>Cleans up resources to increase the likelihood of a successful reload.</p>
7169
*/
7270
@Override
7371
public void onDisable() {
74-
impl.shutdown();
72+
if (impl != null) {
73+
impl.shutdown();
74+
}
7575

7676
if (adventure != null) {
7777
adventure.close();

bootstrap/fabric/build.gradle.kts

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
plugins {
2+
id("conventions.base")
3+
alias(libs.plugins.fabric.loom)
4+
id("com.gradleup.shadow")
5+
}
6+
7+
val shade by configurations.creating
8+
9+
configurations {
10+
implementation {
11+
extendsFrom(shade)
12+
}
13+
}
14+
15+
dependencies {
16+
minecraft(libs.minecraft)
17+
mappings(loom.officialMojangMappings())
18+
modImplementation("net.fabricmc:fabric-loader:0.17.3")
19+
modImplementation("net.fabricmc.fabric-api:fabric-api:0.138.0+1.21.10")
20+
modImplementation("me.lucko:fabric-permissions-api:0.5.0")
21+
include("me.lucko:fabric-permissions-api:0.5.0")
22+
modImplementation(libs.adventure.api)
23+
include(libs.adventure.api)
24+
modImplementation(libs.adventure.minimessage)
25+
include(libs.adventure.minimessage)
26+
include(libs.adventure.fabric)
27+
modImplementation(libs.adventure.fabric)
28+
include(libs.cloud.fabric)
29+
modImplementation(libs.cloud.fabric)
30+
shade(project(mapOf("path" to ":core", "configuration" to "shadow")))
31+
}
32+
33+
tasks {
34+
shadowJar {
35+
configurations = listOf(shade)
36+
archiveVersion.set(project.version.toString())
37+
archiveClassifier.set("shaded")
38+
mergeServiceFiles()
39+
}
40+
41+
remapJar {
42+
dependsOn(shadowJar)
43+
inputFile.set(shadowJar.get().archiveFile)
44+
archiveClassifier.set("")
45+
archiveVersion.set("")
46+
}
47+
}
48+
49+
tasks.named<com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar>("shadowJar") {
50+
exclude("org/incendo/cloud/**")
51+
exclude("META-INF/services/org.incendo.cloud.*")
52+
exclude("org/slf4j/**")
53+
relocate("io.leangen.geantyref", "dev.triassic.template.lib.geantyref")
54+
}
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
/*
2+
* SPDX-License-Identifier: CC0-1.0
3+
*
4+
* Dedicated to the public domain under CC0 1.0 Universal.
5+
*
6+
* You can obtain a full copy of the license at:
7+
* https://creativecommons.org/publicdomain/zero/1.0/
8+
*/
9+
10+
package dev.triassic.template.fabric;
11+
12+
import dev.triassic.template.TemplateImpl;
13+
import dev.triassic.template.TemplatePlugin;
14+
import dev.triassic.template.command.Commander;
15+
import dev.triassic.template.fabric.command.FabricCommander;
16+
import dev.triassic.template.util.PlatformType;
17+
import java.nio.file.Path;
18+
import net.fabricmc.api.DedicatedServerModInitializer;
19+
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents;
20+
import net.fabricmc.loader.api.FabricLoader;
21+
import net.minecraft.server.MinecraftServer;
22+
import org.checkerframework.checker.nullness.qual.NonNull;
23+
import org.incendo.cloud.CommandManager;
24+
import org.incendo.cloud.SenderMapper;
25+
import org.incendo.cloud.execution.ExecutionCoordinator;
26+
import org.incendo.cloud.fabric.FabricServerCommandManager;
27+
import org.slf4j.Logger;
28+
import org.slf4j.LoggerFactory;
29+
30+
/**
31+
* The main entry point for the plugin on the Fabric platform.
32+
*
33+
* <p>It implements {@link TemplatePlugin}
34+
* to provide necessary platform-specific functionality.</p>
35+
*/
36+
public final class FabricTemplatePlugin implements TemplatePlugin, DedicatedServerModInitializer {
37+
38+
private Logger logger;
39+
private FabricServerCommandManager<Commander> commandManager;
40+
private TemplateImpl impl;
41+
42+
@Override
43+
public void onInitializeServer() {
44+
this.logger = LoggerFactory.getLogger(FabricTemplatePlugin.class);
45+
this.commandManager = new FabricServerCommandManager<>(
46+
ExecutionCoordinator.simpleCoordinator(),
47+
SenderMapper.create(
48+
FabricCommander::from,
49+
commander -> ((FabricCommander) commander).source()
50+
)
51+
);
52+
53+
ServerLifecycleEvents.SERVER_STARTING.register(this::onServerStarting);
54+
ServerLifecycleEvents.SERVER_STOPPING.register(this::onServerStopping);
55+
}
56+
57+
/**
58+
* Called when the server is starting.
59+
*
60+
* <p>Initializes the {@link TemplateImpl} instance for the Fabric platform.</p>
61+
*/
62+
private void onServerStarting(final MinecraftServer server) {
63+
this.impl = new TemplateImpl(this);
64+
impl.initialize();
65+
}
66+
67+
/**
68+
* Called when the server is stopping.
69+
*/
70+
private void onServerStopping(final MinecraftServer server) {
71+
if (impl != null) {
72+
impl.shutdown();
73+
}
74+
}
75+
76+
@Override
77+
public @NonNull Logger logger() {
78+
return logger;
79+
}
80+
81+
@Override
82+
public @NonNull Path dataDirectory() {
83+
return FabricLoader.getInstance().getConfigDir();
84+
}
85+
86+
@Override
87+
public @NonNull PlatformType platformType() {
88+
return PlatformType.FABRIC;
89+
}
90+
91+
@Override
92+
public @NonNull CommandManager<Commander> commandManager() {
93+
return this.commandManager;
94+
}
95+
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
/*
2+
* SPDX-License-Identifier: CC0-1.0
3+
*
4+
* Dedicated to the public domain under CC0 1.0 Universal.
5+
*
6+
* You can obtain a full copy of the license at:
7+
* https://creativecommons.org/publicdomain/zero/1.0/
8+
*/
9+
10+
package dev.triassic.template.fabric.command;
11+
12+
import dev.triassic.template.command.Commander;
13+
import me.lucko.fabric.api.permissions.v0.Permissions;
14+
import net.kyori.adventure.audience.Audience;
15+
import net.kyori.adventure.audience.ForwardingAudience;
16+
import net.minecraft.commands.CommandSourceStack;
17+
import org.checkerframework.checker.nullness.qual.NonNull;
18+
import org.checkerframework.framework.qual.DefaultQualifier;
19+
20+
/**
21+
* Represents a Fabric-specific {@link Commander}.
22+
*
23+
* <p>Slightly borrowed from <a href="https://github.com/Hexaoxide/Carbon">Carbon's</a> implementation.</p>
24+
*/
25+
@DefaultQualifier(NonNull.class)
26+
public interface FabricCommander extends Commander, ForwardingAudience.Single {
27+
28+
/**
29+
* Create a new {@link FabricCommander} from a {@link CommandSourceStack}.
30+
*
31+
* @param source the {@link CommandSourceStack}
32+
* @return a new {@link FabricCommander}
33+
*/
34+
static FabricCommander from(final CommandSourceStack source) {
35+
return new FabricCommanderImpl(source);
36+
}
37+
38+
/**
39+
* Gets the underlying {@link CommandSourceStack}.
40+
*
41+
* @return the {@link CommandSourceStack}
42+
*/
43+
CommandSourceStack source();
44+
45+
/**
46+
* A record implementation of {@link FabricCommander}.
47+
*/
48+
record FabricCommanderImpl(CommandSourceStack source) implements FabricCommander {
49+
50+
@Override
51+
public Audience audience() {
52+
return source.audience();
53+
}
54+
55+
@Override
56+
public boolean hasPermission(final String permission) {
57+
return Permissions.check(source, permission);
58+
}
59+
}
60+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
{
2+
"schemaVersion": 1,
3+
"id": "example_mod",
4+
"version": "1.0.0",
5+
"name": "template-plugin",
6+
"description": "testing",
7+
"authors": [
8+
"Me"
9+
],
10+
"contact": {
11+
"homepage": "https://example.com"
12+
},
13+
"license": "UNLICENSED",
14+
"environment": "SERVER",
15+
"entrypoints": {
16+
"main": [
17+
"dev.triassic.template.fabric.FabricTemplatePlugin"
18+
],
19+
"client": []
20+
},
21+
"mixins": [],
22+
"depends": {
23+
"fabricloader": ">=0.16.14",
24+
"fabric-permissions-api-v0": "*",
25+
"minecraft": "~1.21.8",
26+
"java": ">=21",
27+
"cloud": "*"
28+
}
29+
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
plugins {
2+
id("conventions.base")
3+
id("net.neoforged.moddev")
4+
id("com.gradleup.shadow")
5+
}
6+
7+
val shade by configurations.creating
8+
9+
configurations {
10+
implementation {
11+
extendsFrom(shade)
12+
}
13+
}
14+
15+
neoForge {
16+
version = libs.versions.neoforge.get()
17+
validateAccessTransformers = true
18+
}
19+
20+
dependencies {
21+
implementation(libs.adventure.api)
22+
jarJar(libs.adventure.api)
23+
implementation(libs.adventure.minimessage)
24+
jarJar(libs.adventure.minimessage)
25+
jarJar(libs.adventure.neoforge)
26+
implementation(libs.adventure.neoforge)
27+
implementation(libs.cloud.neoforge)
28+
jarJar(libs.cloud.neoforge)
29+
shade(project(mapOf("path" to ":core", "configuration" to "shadow")))
30+
}
31+
32+
tasks {
33+
shadowJar {
34+
configurations = listOf(shade)
35+
archiveVersion.set(project.version.toString())
36+
archiveClassifier.set("shaded")
37+
}
38+
}
39+
40+
val productionJar = tasks.register<Zip>("productionJar") {
41+
archiveClassifier = "final"
42+
archiveExtension = "jar"
43+
destinationDirectory = layout.buildDirectory.dir("libs")
44+
from(tasks.jarJar)
45+
from(zipTree(tasks.shadowJar.flatMap { it.archiveFile }))
46+
}
47+
48+
tasks.assemble {
49+
dependsOn(productionJar)
50+
}
51+
52+
tasks.named<com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar>("shadowJar") {
53+
exclude("org/incendo/cloud/**")
54+
exclude("META-INF/services/org.incendo.cloud.*")
55+
exclude("org/slf4j/**")
56+
relocate("io.leangen.geantyref", "dev.triassic.template.lib.geantyref")
57+
}

0 commit comments

Comments
 (0)