Skip to content

Commit 5067f63

Browse files
committed
Add NeoForge support
1 parent ac6e262 commit 5067f63

File tree

12 files changed

+660
-1
lines changed

12 files changed

+660
-1
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ target/
33
.idea
44
.gradle
55
**/build/
6+
**/run
67
!src/**/build/
78
gradle-app.setting
89
!gradle-wrapper.jar

neoforge/build.gradle

Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
1+
plugins {
2+
id 'java-library'
3+
id 'maven-publish'
4+
id 'idea'
5+
id 'net.neoforged.moddev' version '2.0.92'
6+
}
7+
8+
version = mod_version
9+
group = mod_group_id
10+
11+
repositories {
12+
mavenLocal()
13+
}
14+
15+
base {
16+
archivesName = mod_id
17+
}
18+
19+
java.toolchain.languageVersion = JavaLanguageVersion.of(21)
20+
21+
neoForge {
22+
// Specify the version of NeoForge to use.
23+
version = project.neo_version
24+
25+
parchment {
26+
mappingsVersion = project.parchment_mappings_version
27+
minecraftVersion = project.parchment_minecraft_version
28+
}
29+
30+
// This line is optional. Access Transformers are automatically detected
31+
// accessTransformers.add('src/main/resources/META-INF/accesstransformer.cfg')
32+
33+
// Default run configurations.
34+
// These can be tweaked, removed, or duplicated as needed.
35+
runs {
36+
client {
37+
client()
38+
39+
// Comma-separated list of namespaces to load gametests from. Empty = all namespaces.
40+
systemProperty 'neoforge.enabledGameTestNamespaces', project.mod_id
41+
}
42+
43+
server {
44+
server()
45+
programArgument '--nogui'
46+
systemProperty 'neoforge.enabledGameTestNamespaces', project.mod_id
47+
}
48+
49+
// This run config launches GameTestServer and runs all registered gametests, then exits.
50+
// By default, the server will crash when no gametests are provided.
51+
// The gametest system is also enabled by default for other run configs under the /test command.
52+
gameTestServer {
53+
type = "gameTestServer"
54+
systemProperty 'neoforge.enabledGameTestNamespaces', project.mod_id
55+
}
56+
57+
data {
58+
data()
59+
60+
// example of overriding the workingDirectory set in configureEach above, uncomment if you want to use it
61+
// gameDirectory = project.file('run-data')
62+
63+
// Specify the modid for data generation, where to output the resulting resource, and where to look for existing resources.
64+
programArguments.addAll '--mod', project.mod_id, '--all', '--output', file('src/generated/resources/').getAbsolutePath(), '--existing', file('src/main/resources/').getAbsolutePath()
65+
}
66+
67+
// applies to all the run configs above
68+
configureEach {
69+
// Recommended logging data for a userdev environment
70+
// The markers can be added/remove as needed separated by commas.
71+
// "SCAN": For mods scan.
72+
// "REGISTRIES": For firing of registry events.
73+
// "REGISTRYDUMP": For getting the contents of all registries.
74+
systemProperty 'forge.logging.markers', 'REGISTRIES'
75+
76+
// Recommended logging level for the console
77+
// You can set various levels here.
78+
// Please read: https://stackoverflow.com/questions/2031163/when-to-use-the-different-log-levels
79+
logLevel = org.slf4j.event.Level.DEBUG
80+
}
81+
}
82+
83+
mods {
84+
// define mod <-> source bindings
85+
// these are used to tell the game which sources are for which mod
86+
// mostly optional in a single mod project
87+
// but multi mod projects should define one per mod
88+
"${mod_id}" {
89+
sourceSet(sourceSets.main)
90+
}
91+
}
92+
}
93+
94+
// Include resources generated by data generators.
95+
sourceSets.main.resources { srcDir 'src/generated/resources' }
96+
97+
98+
dependencies {
99+
// Example mod dependency with JEI
100+
// The JEI API is declared for compile time use, while the full JEI artifact is used at runtime
101+
// compileOnly "mezz.jei:jei-${mc_version}-common-api:${jei_version}"
102+
// compileOnly "mezz.jei:jei-${mc_version}-forge-api:${jei_version}"
103+
// runtimeOnly "mezz.jei:jei-${mc_version}-forge:${jei_version}"
104+
105+
// Example mod dependency using a mod jar from ./libs with a flat dir repository
106+
// This maps to ./libs/coolmod-${mc_version}-${coolmod_version}.jar
107+
// The group id is ignored when searching -- in this case, it is "blank"
108+
// implementation "blank:coolmod-${mc_version}:${coolmod_version}"
109+
110+
// Example mod dependency using a file as dependency
111+
// implementation files("libs/coolmod-${mc_version}-${coolmod_version}.jar")
112+
113+
// Example project dependency using a sister or child project:
114+
// implementation project(":myproject")
115+
116+
// For more info:
117+
// http://www.gradle.org/docs/current/userguide/artifact_dependencies_tutorial.html
118+
// http://www.gradle.org/docs/current/userguide/dependency_management.html
119+
120+
// implementation "net.neoforged:neoforge:${neo_version}"
121+
122+
implementation ("net.kyori:adventure-api:4.17.0") {
123+
exclude(module: "adventure-bom")
124+
exclude(module: "annotations")
125+
}
126+
implementation ("net.kyori:adventure-text-serializer-gson:4.17.0") {
127+
exclude(module: "adventure-bom")
128+
exclude(module: "adventure-api")
129+
exclude(module: "annotations")
130+
exclude(module: "auto-service-annotations")
131+
exclude(module: "gson")
132+
}
133+
134+
implementation project(path: ":common", configuration: "shadow")
135+
}
136+
137+
// This block of code expands all declared replace properties in the specified resource targets.
138+
// A missing property will result in an error. Properties are expanded using ${} Groovy notation.
139+
var generateModMetadata = tasks.register("generateModMetadata", ProcessResources) {
140+
var replaceProperties = [
141+
minecraft_version : minecraft_version,
142+
minecraft_version_range: minecraft_version_range,
143+
neo_version : neo_version,
144+
neo_version_range : neo_version_range,
145+
loader_version_range : loader_version_range,
146+
mod_id : mod_id,
147+
mod_name : mod_name,
148+
mod_license : mod_license,
149+
mod_version : mod_version,
150+
mod_authors : mod_authors,
151+
mod_description : mod_description
152+
]
153+
inputs.properties replaceProperties
154+
expand replaceProperties
155+
from "src/main/templates"
156+
into "build/generated/sources/modMetadata"
157+
}
158+
159+
// Include the output of "generateModMetadata" as an input directory for the build
160+
// this works with both building through Gradle and the IDE.
161+
sourceSets.main.resources.srcDir generateModMetadata
162+
// To avoid having to run "generateModMetadata" manually, make it run on every project reload
163+
neoForge.ideSyncTask generateModMetadata
164+
165+
// IDEA no longer automatically downloads sources/javadoc jars for dependencies, so we need to explicitly enable the behavior.
166+
idea {
167+
module {
168+
downloadSources = true
169+
downloadJavadoc = true
170+
}
171+
}
172+
173+
shadowJar {
174+
dependencies {
175+
include(project(":common"))
176+
include(dependency("net.kyori:.*"))
177+
exclude(dependency("net.neoforged:.*"))
178+
exclude(dependency("io.github.llamalad7:mixinextras-neoforge:.*"))
179+
}
180+
181+
relocate "net.kyori", "com.cssbham.cssminecraft.lib.adventure"
182+
183+
archiveFileName = "cssminecraft-neoforge-${project.version}.jar"
184+
185+
minimize()
186+
}

neoforge/gradle.properties

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
# Sets default memory used for gradle commands. Can be overridden by user or command line properties.
2+
org.gradle.jvmargs=-Xmx2G
3+
org.gradle.daemon=true
4+
org.gradle.parallel=true
5+
org.gradle.caching=true
6+
org.gradle.configuration-cache=true
7+
8+
## Environment Properties
9+
# You can find the latest versions here: https://projects.neoforged.net/neoforged/neoforge
10+
# The Minecraft version must agree with the Neo version to get a valid artifact
11+
minecraft_version=1.21.1
12+
# The Minecraft version range can use any release version of Minecraft as bounds.
13+
# Snapshots, pre-releases, and release candidates are not guaranteed to sort properly
14+
# as they do not follow standard versioning conventions.
15+
minecraft_version_range=[1.21.1,1.22)
16+
# The Neo version must agree with the Minecraft version to get a valid artifact
17+
neo_version=21.1.176
18+
# The Neo version range can use any version of Neo as bounds
19+
neo_version_range=[21,)
20+
# The loader version range can only use the major version of FML as bounds
21+
loader_version_range=[4,)
22+
23+
parchment_minecraft_version=1.21.4
24+
parchment_mappings_version=2025.03.23
25+
26+
## Mod Properties
27+
28+
# The unique mod identifier for the mod. Must be lowercase in English locale. Must fit the regex [a-z][a-z0-9_]{1,63}
29+
# Must match the String constant located in the main mod class annotated with @Mod.
30+
mod_id=cssminecraft
31+
# The human-readable display name for the mod.
32+
mod_name=CSS-Minecraft
33+
# The license of the mod. Review your options at https://choosealicense.com/. All Rights Reserved is the default.
34+
mod_license=todo
35+
# The mod version. See https://semver.org/
36+
mod_version=1.0-SNAPSHOT
37+
# The group ID for the mod. It is only important when publishing as an artifact to a Maven repository.
38+
# This should match the base package used for the mod sources.
39+
# See https://maven.apache.org/guides/mini/guide-naming-conventions.html
40+
mod_group_id=com.cssbham.cssminecraft.neoforge
41+
# The authors of the mod. This is a simple text string that is used for display purposes in the mod list.
42+
mod_authors=
43+
# The description of the mod. This is a simple multiline text string that is used for display purposes in the mod list.
44+
mod_description=
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package com.cssbham.cssminecraft.neoforge;
2+
3+
import net.neoforged.fml.common.Mod;
4+
import net.neoforged.neoforge.common.NeoForge;
5+
import net.neoforged.neoforge.event.server.ServerStartingEvent;
6+
import net.neoforged.neoforge.event.server.ServerStoppingEvent;
7+
8+
/**
9+
* Entrypoint for Forge
10+
*/
11+
@Mod(value = "cssminecraft")
12+
public class CSSMinecraftLoader {
13+
14+
private final NeoForgeCSSMinecraftPlugin plugin;
15+
16+
public CSSMinecraftLoader() {
17+
this.plugin = new NeoForgeCSSMinecraftPlugin();
18+
NeoForge.EVENT_BUS.addListener(this::onServerStarted);
19+
}
20+
21+
public void onServerStarted(ServerStartingEvent event) {
22+
this.plugin.setServer(event.getServer());
23+
try {
24+
this.plugin.enable();
25+
} catch (Exception e) {
26+
this.plugin.getLogger().severe("Mod initialisation failed - disabling");
27+
this.plugin.disable();
28+
}
29+
}
30+
31+
public void onServerStopping(ServerStoppingEvent event) {
32+
this.plugin.disable();
33+
}
34+
35+
}
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
package com.cssbham.cssminecraft.neoforge;
2+
3+
import com.cssbham.cssminecraft.common.AbstractCSSMinecraftPlugin;
4+
import com.cssbham.cssminecraft.common.adapter.ServerChatAdapter;
5+
import com.cssbham.cssminecraft.common.command.CommandService;
6+
import com.cssbham.cssminecraft.common.executor.ServerExecutor;
7+
import com.cssbham.cssminecraft.common.logger.Logger;
8+
import com.cssbham.cssminecraft.neoforge.adapter.ForgeServerChatAdapter;
9+
import com.cssbham.cssminecraft.neoforge.command.ForgeCommandService;
10+
import com.cssbham.cssminecraft.neoforge.executor.ForgeServerExecutor;
11+
import com.cssbham.cssminecraft.neoforge.listener.ForgeEventAdapter;
12+
import com.cssbham.cssminecraft.neoforge.logger.ForgeLogger;
13+
import net.minecraft.server.MinecraftServer;
14+
import net.neoforged.fml.loading.FMLPaths;
15+
16+
import java.nio.file.Path;
17+
18+
/**
19+
* Implementation of CSS Minecraft Plugin for Forge
20+
*/
21+
public class NeoForgeCSSMinecraftPlugin extends AbstractCSSMinecraftPlugin {
22+
23+
public static final String MOD_ID = "cssminecraft";
24+
private final ForgeLogger logger;
25+
private ForgeServerChatAdapter serverChatAdapter;
26+
27+
private MinecraftServer server;
28+
private ForgeServerExecutor executor;
29+
private ForgeCommandService commandService;
30+
31+
public NeoForgeCSSMinecraftPlugin() {
32+
this.logger = new ForgeLogger(MOD_ID);
33+
}
34+
35+
@Override
36+
public void enable() {
37+
this.serverChatAdapter = new ForgeServerChatAdapter(server);
38+
this.executor = new ForgeServerExecutor(logger, server);
39+
this.commandService = new ForgeCommandService(logger, executor, serverChatAdapter, server);
40+
41+
super.enable();
42+
43+
ForgeEventAdapter eventAdapter = new ForgeEventAdapter(server, executor);
44+
eventAdapter.bindPlatformToEventBus(super.getEventBus());
45+
}
46+
47+
@Override
48+
public Logger getLogger() {
49+
return logger;
50+
}
51+
52+
@Override
53+
public ServerChatAdapter provideServerChatAdapter() {
54+
return serverChatAdapter;
55+
}
56+
57+
@Override
58+
public Path provideConfigurationPath() {
59+
return FMLPaths.CONFIGDIR.get().resolve(MOD_ID).resolve("config.yml");
60+
}
61+
62+
@Override
63+
public ServerExecutor provideServerExecutor() {
64+
return executor;
65+
}
66+
67+
@Override
68+
public CommandService provideCommandService() {
69+
return commandService;
70+
}
71+
72+
public void setServer(MinecraftServer server) {
73+
this.server = server;
74+
}
75+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package com.cssbham.cssminecraft.neoforge.adapter;
2+
3+
import com.cssbham.cssminecraft.common.adapter.ServerChatAdapter;
4+
import net.kyori.adventure.text.Component;
5+
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
6+
import net.minecraft.core.RegistryAccess;
7+
import net.minecraft.server.MinecraftServer;
8+
import net.minecraft.server.level.ServerPlayer;
9+
10+
import java.util.UUID;
11+
12+
public class ForgeServerChatAdapter implements ServerChatAdapter {
13+
14+
private final MinecraftServer server;
15+
16+
public ForgeServerChatAdapter(MinecraftServer server) {
17+
this.server = server;
18+
}
19+
20+
@Override
21+
public void broadcastMessage(Component message) {
22+
server.getPlayerList().broadcastSystemMessage(componentToMinecraftComponent(message), false);
23+
}
24+
25+
@Override
26+
public void sendMessageToPlayer(UUID user, Component component) {
27+
ServerPlayer player = server.getPlayerList().getPlayer(user);
28+
if (null != player) {
29+
player.sendSystemMessage(componentToMinecraftComponent(component));
30+
}
31+
}
32+
33+
@Override
34+
public void sendMessageToConsole(Component component) {
35+
server.sendSystemMessage(componentToMinecraftComponent(component));
36+
}
37+
38+
public net.minecraft.network.chat.Component componentToMinecraftComponent(Component component) {
39+
return net.minecraft.network.chat.Component.Serializer.fromJson(GsonComponentSerializer.gson().serializeToTree(component), RegistryAccess.EMPTY);
40+
}
41+
42+
}

0 commit comments

Comments
 (0)