-
Notifications
You must be signed in to change notification settings - Fork 33
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
Implement auto bus detection in EBS #152
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,6 +5,7 @@ | |
|
||
package net.neoforged.fml.javafmlmod; | ||
|
||
import static org.assertj.core.api.Assertions.as; | ||
import static org.assertj.core.api.Assertions.assertThat; | ||
|
||
import java.util.ArrayList; | ||
|
@@ -170,4 +171,74 @@ public EntryPoint(net.neoforged.bus.api.IEventBus modEventBus) { | |
assertThat(getTranslatedIssues(e.getIssues())).containsOnly("ERROR: testmod (testmod) encountered an error while dispatching the net.neoforged.fml.event.lifecycle.FMLClientSetupEvent event" | ||
+ "\njava.lang.RuntimeException: null"); | ||
} | ||
|
||
@Test | ||
void testEventBusSubscriberAutomaticDetection() throws Exception { | ||
installation.setupProductionClient(); | ||
installation.buildModJar("test.jar") | ||
.withModsToml(builder -> { | ||
builder.unlicensedJavaMod().addMod("testmod", "1.0"); | ||
}) | ||
Comment on lines
+179
to
+181
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There's a shorthand for the testmod mods toml |
||
.addClass("testmod.TestEvent", """ | ||
public class TestEvent extends net.neoforged.bus.api.Event { | ||
}""") | ||
.addClass("testmod.EBSListener", """ | ||
@net.neoforged.fml.common.EventBusSubscriber(bus = net.neoforged.fml.common.EventBusSubscriber.Bus.AUTOMATIC) | ||
public class EBSListener { | ||
@net.neoforged.bus.api.SubscribeEvent | ||
public static void onClientSetup(net.neoforged.fml.event.lifecycle.FMLClientSetupEvent event) { | ||
net.neoforged.fml.javafmlmod.FMLJavaModLanguageProviderTest.EVENTS.add(event); | ||
net.neoforged.fml.loading.FMLLoader.getBindings().getGameBus().post(new TestEvent()); | ||
} | ||
} | ||
""") | ||
.addClass("testmod.EBSListenerGame", """ | ||
@net.neoforged.fml.common.EventBusSubscriber(bus = net.neoforged.fml.common.EventBusSubscriber.Bus.AUTOMATIC) | ||
public class EBSListenerGame { | ||
@net.neoforged.bus.api.SubscribeEvent | ||
public static void onTest(TestEvent event) { | ||
net.neoforged.fml.javafmlmod.FMLJavaModLanguageProviderTest.MESSAGES.add("game listener invoked"); | ||
} | ||
} | ||
""") | ||
.build(); | ||
|
||
var result = launch("forgeclient"); | ||
loadMods(result); | ||
|
||
ModLoader.dispatchParallelEvent("test", Runnable::run, Runnable::run, () -> {}, FMLClientSetupEvent::new); | ||
|
||
assertThat(EVENTS).hasSize(1); | ||
assertThat(MESSAGES).containsExactly("game listener invoked"); | ||
} | ||
|
||
@Test | ||
void testEventBusSubscriberMixedBuses() throws Exception { | ||
installation.setupProductionClient(); | ||
installation.buildModJar("test.jar") | ||
.withModsToml(builder -> { | ||
builder.unlicensedJavaMod().addMod("testmod", "1.0"); | ||
}) | ||
.addClass("testmod.TestEvent", """ | ||
public class TestEvent extends net.neoforged.bus.api.Event { | ||
}""") | ||
.addClass("testmod.EBSListener", """ | ||
@net.neoforged.fml.common.EventBusSubscriber(bus = net.neoforged.fml.common.EventBusSubscriber.Bus.AUTOMATIC) | ||
public class EBSListener { | ||
@net.neoforged.bus.api.SubscribeEvent | ||
public static void onClientSetup(net.neoforged.fml.event.lifecycle.FMLClientSetupEvent event) { | ||
} | ||
|
||
@net.neoforged.bus.api.SubscribeEvent | ||
public static void onGame(TestEvent event) { | ||
} | ||
} | ||
""") | ||
.build(); | ||
|
||
var result = launch("forgeclient"); | ||
loadMods(result); | ||
|
||
assertThat(getTranslatedIssues(ModLoader.getLoadingIssues())).containsExactly("ERROR: Class testmod.EBSListener annotated with @EventBusSubscriber has listeners for both mod and game bus events, which cannot be mixed"); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,6 +8,7 @@ | |
import static org.assertj.core.api.Assertions.assertThat; | ||
import static org.junit.jupiter.api.Assertions.assertNotNull; | ||
|
||
import com.google.common.base.Suppliers; | ||
import com.google.common.io.MoreFiles; | ||
import com.google.common.io.RecursiveDeleteOption; | ||
import cpw.mods.jarhandling.SecureJar; | ||
|
@@ -25,13 +26,16 @@ | |
import java.util.List; | ||
import java.util.Map; | ||
import java.util.function.Function; | ||
import java.util.function.Supplier; | ||
import java.util.jar.Attributes; | ||
import java.util.jar.JarEntry; | ||
import java.util.jar.JarFile; | ||
import java.util.jar.JarOutputStream; | ||
import java.util.jar.Manifest; | ||
import java.util.stream.Collectors; | ||
import java.util.stream.Stream; | ||
import net.neoforged.bus.api.BusBuilder; | ||
import net.neoforged.bus.api.IEventBus; | ||
import net.neoforged.jarjar.metadata.ContainedJarMetadata; | ||
import net.neoforged.jarjar.metadata.Metadata; | ||
import net.neoforged.jarjar.metadata.MetadataIOHandler; | ||
|
@@ -81,6 +85,8 @@ public class SimulatedInstallation implements AutoCloseable { | |
private final Path librariesDir; | ||
// Used for testing running out of a Gradle project. Is the simulated Gradle project root directory. | ||
private final Path projectRoot; | ||
// Simulates NeoForge's game event bus | ||
private final Supplier<IEventBus> gameBus = Suppliers.memoize(() -> BusBuilder.builder().build()); | ||
Comment on lines
+88
to
+89
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hm, you are putting this here because it's usually in the NeoForge jar? |
||
|
||
private static final IdentifiableContent[] SERVER_EXTRA_JAR_CONTENT = { SHARED_ASSETS }; | ||
private static final IdentifiableContent[] CLIENT_EXTRA_JAR_CONTENT = { CLIENT_ASSETS, SHARED_ASSETS }; | ||
|
@@ -96,6 +102,10 @@ public SimulatedInstallation() throws IOException { | |
projectRoot = Files.createTempDirectory("projectRoot"); | ||
} | ||
|
||
public IEventBus getGameBus() { | ||
return gameBus.get(); | ||
} | ||
|
||
public Path getModsFolder() throws IOException { | ||
var modsFolder = gameDir.resolve("mods"); | ||
Files.createDirectories(modsFolder); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Although I understand the idea, but why do we limit this to one bus per listener?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a "limitation" imposed by event bus' class, where all listeners must be of the correct marker interface. And given that game and mod events are fired during different parts of the runtime, I think the limitation makes sense
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oke perfect, was just curious. Thanks for the explanation. Nice work!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Despite the explained "limitation", leaving a class level separation here does not fix #140's main expectations.
Moving further to change the EBS implementation would be better than an incomplete solution imo.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is no raw variant of
addListener
that would support that use case, and reflection based consumers on the neo side is not acceptable, both because of performance concerns and because it will make unregistering those listeners impossible. In any case, I've decided to not proceed with this PR further because more magic will increase confusion.Instead, we should make the bus parameter required and the mod id default to first in the file (instead of all).