Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Split NeoForge common and client sources #1920

Draft
wants to merge 7 commits into
base: 1.21.x
Choose a base branch
from
Draft
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
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,8 @@ abstract class GenerateSourcePatches extends DefaultTask {
@InputFile
public abstract RegularFileProperty getOriginalJar();

@InputDirectory
@PathSensitive(PathSensitivity.RELATIVE)
public abstract DirectoryProperty getModifiedSources();
@InputFile
public abstract RegularFileProperty getModifiedSources();

@Optional
@OutputFile
Expand All @@ -43,7 +42,7 @@ public void generateSourcePatches() throws IOException {
var builder = DiffOperation.builder()
.logTo(getLogger()::lifecycle)
.baseInput(MultiInput.detectedArchive(getOriginalJar().get().getAsFile().toPath()))
.changedInput(MultiInput.folder(getModifiedSources().get().getAsFile().toPath()))
.changedInput(MultiInput.detectedArchive(getModifiedSources().get().getAsFile().toPath()))
.patchesOutput(getPatchesJar().isPresent() ? MultiOutput.detectedArchive(getPatchesJar().get().getAsFile().toPath()) : MultiOutput.folder(getPatchesFolder().getAsFile().get().toPath()))
.autoHeader(true)
.level(io.codechicken.diffpatch.util.LogLevel.WARN)
Expand Down
38 changes: 30 additions & 8 deletions buildSrc/src/main/java/net/neoforged/neodev/NeoDevPlugin.java
Original file line number Diff line number Diff line change
Expand Up @@ -133,12 +133,27 @@ public void apply(Project project) {
task.getRejectsFolder().set(project.getRootProject().file("rejects"));
});

// 5. Unpack jar from 4.
var mcSourcesPath = project.file("src/main/java");
tasks.register("setup", Sync.class, task -> {
task.setGroup(GROUP);
task.from(project.zipTree(applyPatches.flatMap(ApplyPatches::getPatchedJar)));
task.into(mcSourcesPath);
// 5. Split source jar from 4. into client and server.
var splitPatchedSources = tasks.register("splitPatchedSources", SplitMergedSources.class, task -> {
task.setGroup(INTERNAL_GROUP);
task.getMergedJar().set(applyPatches.flatMap(ApplyPatches::getPatchedJar));
task.getCommonJar().set(neoDevBuildDir.map(dir -> dir.file("artifacts/common-patched-sources.jar")));
task.getClientJar().set(neoDevBuildDir.map(dir -> dir.file("artifacts/client-patched-sources.jar")));
});

// 6. Unpack jars from 5.
var setupCommon = tasks.register("setupCommon", Sync.class, task -> {
task.setGroup(INTERNAL_GROUP);
task.from(project.zipTree(splitPatchedSources.flatMap(SplitMergedSources::getCommonJar)));
task.into(project.file("src/main/java"));
});
var setupClient = tasks.register("setupClient", Sync.class, task -> {
task.setGroup(INTERNAL_GROUP);
task.from(project.zipTree(splitPatchedSources.flatMap(SplitMergedSources::getClientJar)));
task.into(project.file("src/client/java"));
});
tasks.register("setup", task -> {
task.dependsOn(setupCommon, setupClient);
});

/*
Expand Down Expand Up @@ -201,19 +216,26 @@ public void apply(Project project) {
* OTHER TASKS
*/

var mergeSources = tasks.register("mergePatchedSources", Zip.class, task -> {
task.setGroup(INTERNAL_GROUP);
task.from(project.files("src/main/java", "src/client/java"));
task.getDestinationDirectory().set(neoDevBuildDir.map(dir -> dir.dir("artifacts/merged-sources")));
task.getArchiveFileName().set("merged-patched-sources.jar");
});

// Generate source patches into a patch archive, based on the jar with injected interfaces.
var genSourcePatches = tasks.register("generateSourcePatches", GenerateSourcePatches.class, task -> {
task.setGroup(INTERNAL_GROUP);
task.getOriginalJar().set(applyInterfaceInjection.flatMap(TransformSources::getOutputJar));
task.getModifiedSources().set(project.file("src/main/java"));
task.getModifiedSources().set(mergeSources.flatMap(AbstractArchiveTask::getArchiveFile));
task.getPatchesJar().set(neoDevBuildDir.map(dir -> dir.file("source-patches.zip")));
});

// Generate source patches that are based on the production environment (without separate interface injection)
var genProductionPatches = tasks.register("generateProductionSourcePatches", GenerateSourcePatches.class, task -> {
task.setGroup(INTERNAL_GROUP);
task.getOriginalJar().set(applyAt.flatMap(TransformSources::getOutputJar));
task.getModifiedSources().set(project.file("src/main/java"));
task.getModifiedSources().set(mergeSources.flatMap(AbstractArchiveTask::getArchiveFile));
task.getPatchesFolder().set(neoDevBuildDir.map(dir -> dir.dir("production-source-patches")));
});

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package net.neoforged.neodev;

import org.gradle.api.DefaultTask;
import org.gradle.api.file.RegularFileProperty;
import org.gradle.api.tasks.InputFile;
import org.gradle.api.tasks.OutputFile;
import org.gradle.api.tasks.TaskAction;

import javax.inject.Inject;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;

abstract class SplitMergedSources extends DefaultTask {
@Inject
public SplitMergedSources() {}

@InputFile
abstract RegularFileProperty getMergedJar();

@OutputFile
abstract RegularFileProperty getCommonJar();

@OutputFile
abstract RegularFileProperty getClientJar();

@TaskAction
public void splitMergedJar() throws IOException {
try (
var merged = new ZipInputStream(new BufferedInputStream(Files.newInputStream(getMergedJar().get().getAsFile().toPath())));
var common = new ZipOutputStream(new BufferedOutputStream(Files.newOutputStream(getCommonJar().get().getAsFile().toPath())));
var client = new ZipOutputStream(new BufferedOutputStream(Files.newOutputStream(getClientJar().get().getAsFile().toPath())))
) {
for (var entry = merged.getNextEntry(); entry != null; entry = merged.getNextEntry()) {
if (entry.isDirectory()) {
continue;
}
var bytes = merged.readAllBytes();
if (new String(bytes).contains("\n@OnlyIn(Dist.CLIENT)")) {
client.putNextEntry(entry);
client.write(bytes);
client.closeEntry();
} else {
common.putNextEntry(entry);
common.write(bytes);
common.closeEntry();
}
}
}
}
}
25 changes: 25 additions & 0 deletions patches/mcp/client/Start.java.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
--- a/mcp/client/Start.java
+++ b/mcp/client/Start.java
@@ -1,3 +_,4 @@
+// TODO: This patch is just a quick fix
package mcp.client;

import java.io.IOException;
@@ -7,7 +_,7 @@

import com.google.gson.JsonElement;
import com.google.gson.JsonParser;
-import net.minecraft.client.main.Main;
+//import net.minecraft.client.main.Main;

public class Start
{
@@ -32,7 +_,7 @@
if (assets == null) {
assets = System.getenv().containsKey("assetDirectory") ? System.getenv("assetDirectory") : "assets";
}
- Main.main(concat(new String[] { "--version", "mcp", "--accessToken", "0", "--assetsDir", assets, "--assetIndex", assetIndex, "--userProperties", "{}" }, args));
+// Main.main(concat(new String[] { "--version", "mcp", "--accessToken", "0", "--assetsDir", assets, "--assetIndex", assetIndex, "--userProperties", "{}" }, args));
}

public static <T> T[] concat(T[] first, T[] second)
3 changes: 1 addition & 2 deletions patches/net/minecraft/client/Options.java.patch
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,10 @@
this.minecraft = p_92138_;
this.optionsFile = new File(p_92139_, "options.txt");
boolean flag = Runtime.getRuntime().maxMemory() >= 1000000000L;
@@ -1264,11 +_,21 @@
@@ -1264,11 +_,20 @@
this.onboardAccessibility = p_168428_.process("onboardAccessibility", this.onboardAccessibility);
p_168428_.process("menuBackgroundBlurriness", this.menuBackgroundBlurriness);

+ net.neoforged.neoforge.forge.snapshots.ForgeSnapshotsMod.processOptions(p_168428_);
+ processOptionsForge(p_168428_);
+ }
+ // FORGE: split off to allow reloading options after mod loading is done
Expand Down
2 changes: 1 addition & 1 deletion patches/net/minecraft/client/gui/Gui.java.patch
Original file line number Diff line number Diff line change
Expand Up @@ -421,7 +421,7 @@
} else {
gui$hearttype = NORMAL;
}
+ gui$hearttype = net.neoforged.neoforge.event.EventHooks.firePlayerHeartTypeEvent(p_168733_, gui$hearttype);
+ gui$hearttype = net.neoforged.neoforge.client.ClientHooks.firePlayerHeartTypeEvent(p_168733_, gui$hearttype);

return gui$hearttype;
+ }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@
LOGGER.warn("Client disconnected with reason: {}", p_350760_.reason().getString());
}

@@ -409,5 +_,10 @@
@@ -409,5 +_,15 @@
@OnlyIn(Dist.CLIENT)
static record PendingRequest(UUID id, URL url, String hash) {
}
Expand All @@ -82,5 +82,10 @@
+ @Override
+ public Connection getConnection() {
+ return connection;
+ }
+
+ @Override
+ public net.minecraft.util.thread.ReentrantBlockableEventLoop<?> getMainThreadEventLoop() {
+ return Minecraft.getInstance();
}
}
2 changes: 1 addition & 1 deletion patches/net/minecraft/stats/RecipeBookSettings.java.patch
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@

- for (RecipeBookType recipebooktype : RecipeBookType.values()) {
+ // Neo: filter out modded RecipeBookTypes when connected to a vanilla server
+ for (RecipeBookType recipebooktype : net.neoforged.neoforge.common.CommonHooks.getFilteredRecipeBookTypeValues()) {
+ for (RecipeBookType recipebooktype : net.neoforged.neoforge.internal.NeoForgeProxy.INSTANCE.getFilteredRecipeBookTypeValues()) {
boolean flag = p_12753_.readBoolean();
boolean flag1 = p_12753_.readBoolean();
if (flag || flag1) {
43 changes: 40 additions & 3 deletions projects/neoforge/build.gradle
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import net.neoforged.jarcompatibilitychecker.gradle.JCCPlugin
import net.neoforged.jarcompatibilitychecker.gradle.CompatibilityTask
import net.neoforged.jarcompatibilitychecker.gradle.ProvideNeoForgeJarTask
import net.neoforged.moddevgradle.dsl.ModModel
import net.neoforged.neodev.GenerateFinalizeSpawnTargets

plugins {
Expand Down Expand Up @@ -32,6 +33,18 @@ sourceSets {
srcDirs rootProject.file('src/main/resources'), rootProject.file('src/generated/resources')
}
}
client {
java {
srcDirs rootProject.file('src/client/java')
}
}
}

java {
registerFeature('client') {
usingSourceSet(sourceSets.client)
disablePublication()
}
}

final checkVersion = JCCPlugin.providePreviousVersion(
Expand All @@ -53,11 +66,17 @@ checkJarCompatibility {
baseJar = createCompatJar.flatMap { it.output }
}

// We don't want to include client in non-client runs,
// however the name of the ModModel must be minecraft for FML to work.
// Since we need both mods to be named minecraft we create them manually.
ext.commonMod = objects.newInstance(ModModel, "minecraft")
commonMod.sourceSet sourceSets.main
ext.joinedMod = objects.newInstance(ModModel, "minecraft")
joinedMod.sourceSet sourceSets.main
joinedMod.sourceSet sourceSets.client

neoDev {
mods {
minecraft {
sourceSet sourceSets.main
}
"neoforge-coremods" {
sourceSet project(":neoforge-coremods").sourceSets.main
}
Expand Down Expand Up @@ -135,6 +154,8 @@ dependencies {
// Must be implementation instead of compileOnly so that running dependent projects such as tests will trigger (re)compilation of coremods.
// (Only needed when compiling through IntelliJ non-delegated builds - otherwise `compileOnly` would work).
implementation(jarJar(project(":neoforge-coremods")))

clientImplementation project(path: ":neoforge", configuration: 'runtimeElements')
}

neoDev {
Expand All @@ -144,17 +165,23 @@ neoDev {
}
client {
client()
sourceSet = sourceSets.client
loadedMods = [joinedMod, neoDev.mods."neoforge-coremods"]
}
server {
server()
loadedMods = [commonMod, neoDev.mods."neoforge-coremods"]
}
gameTestServer {
type = "gameTestServer"
loadedMods = [commonMod, neoDev.mods."neoforge-coremods"]
}
data {
// We perform client and server datagen in a single clientData run to avoid
// having to juggle two generated resources folders and two runs for no additional benefit.
clientData()
sourceSet = sourceSets.main
loadedMods = [joinedMod, neoDev.mods."neoforge-coremods"]
programArguments.addAll '--mod', 'neoforge', '--flat', '--all', '--validate',
'--existing', rootProject.file("src/main/resources").absolutePath,
'--output', rootProject.file("src/generated/resources").absolutePath
Expand Down Expand Up @@ -379,6 +406,16 @@ configurations {
}
}

jar {
from sourceSets.client.output
}
sourcesJar {
from sourceSets.client.allSource
}
javadoc {
source += sourceSets.client.allSource
}

processResources {
inputs.property("version", project.version)
final version = project.version
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
import net.minecraft.client.Options;
import net.minecraft.client.color.block.BlockColors;
import net.minecraft.client.gui.Font;
import net.minecraft.client.gui.Gui;
import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.client.gui.components.LerpingBossEvent;
import net.minecraft.client.gui.components.toasts.Toast;
Expand Down Expand Up @@ -183,8 +184,10 @@
import net.neoforged.neoforge.client.renderstate.RegisterRenderStateModifiersEvent;
import net.neoforged.neoforge.common.NeoForge;
import net.neoforged.neoforge.common.NeoForgeMod;
import net.neoforged.neoforge.event.entity.player.PlayerHeartTypeEvent;
import net.neoforged.neoforge.forge.snapshots.ForgeSnapshotsModClient;
import net.neoforged.neoforge.gametest.GameTestHooks;
import net.neoforged.neoforge.internal.BrandingControl;
import net.neoforged.neoforge.internal.versions.neoforge.NeoForgeVersion;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
Expand Down Expand Up @@ -255,6 +258,18 @@ public static float getGuiFarPlane() {
return 11_000F + depth;
}

/**
* Called by {@link Gui.HeartType#forPlayer} to allow for modification of the displayed heart type in the
* health bar.
*
* @param player The local {@link Player}
* @param heartType The {@link Gui.HeartType} which would be displayed by vanilla
* @return The heart type which should be displayed
*/
public static Gui.HeartType firePlayerHeartTypeEvent(Player player, Gui.HeartType heartType) {
return NeoForge.EVENT_BUS.post(new PlayerHeartTypeEvent(player, heartType)).getType();
}

public static ResourceLocation getArmorTexture(ItemStack armor, EquipmentClientInfo.LayerType type, EquipmentClientInfo.Layer layer, ResourceLocation _default) {
ResourceLocation result = IClientItemExtensions.of(armor).getArmorTexture(armor, type, layer, _default);
return result != null ? result : _default;
Expand Down Expand Up @@ -368,17 +383,15 @@ public static float getDetachedCameraDistance(Camera camera, boolean flipped, fl
public static void renderMainMenu(TitleScreen gui, GuiGraphics guiGraphics, Font font, int width, int height, int alpha) {
ForgeSnapshotsModClient.renderMainMenuWarning(NeoForgeVersion.getVersion(), guiGraphics, font, width, height, alpha);

forgeStatusLine = switch (NeoForgeVersion.getStatus()) {
BrandingControl.setForgeStatusLine(switch (NeoForgeVersion.getStatus()) {
// case FAILED -> " Version check failed";
// case UP_TO_DATE -> "Forge up to date";
// case AHEAD -> "Using non-recommended Forge build, issues may arise.";
case OUTDATED, BETA_OUTDATED -> I18n.get("neoforge.update.newversion", NeoForgeVersion.getTarget());
default -> null;
};
});
}

public static String forgeStatusLine;

@Nullable
public static SoundInstance playSound(SoundEngine manager, SoundInstance sound) {
PlaySoundEvent e = new PlaySoundEvent(manager, sound);
Expand Down Expand Up @@ -1031,16 +1044,6 @@ public static void fireClientTickPost() {
NeoForge.EVENT_BUS.post(new ClientTickEvent.Post());
}

@Nullable
@SuppressWarnings("resource")
public static <T> RegistryLookup<T> resolveLookup(ResourceKey<? extends Registry<T>> key) {
ClientLevel level = Minecraft.getInstance().level;
if (level != null) {
return level.registryAccess().lookup(key).orElse(null);
}
return null;
}

/**
* Fires the {@link GatherEffectScreenTooltipsEvent} and returns the resulting tooltip lines.
* <p>
Expand Down
Loading
Loading