Skip to content
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -254,3 +254,4 @@ locales/
/languages/
/custom-skulls.yml
/permissions.yml
.kotlin/
3 changes: 3 additions & 0 deletions bootstrap/mod/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ dependencies {
api(projects.core)
compileOnly(libs.mixin)
compileOnly(libs.mixinextras)
compileOnly(libs.asm)
compileOnly(libs.adapters)
compileOnlyApi(libs.viaversion)

// Only here to suppress "unknown enum constant EnvType.CLIENT" warnings. DO NOT USE!
compileOnly(libs.fabric.loader)
Expand Down
7 changes: 5 additions & 2 deletions bootstrap/mod/fabric/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,11 @@ dependencies {
shadowBundle(projects.api)
shadowBundle(projects.common)

modImplementation(libs.cloud.fabric)
include(libs.cloud.fabric)
compileOnly(libs.adapters)
include(libs.adapters)
include(libs.adapters.fabric.v1215)
include(libs.adapters.fabric.v1206)

include(libs.fabric.permissions.api)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,18 +31,19 @@
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents;
import net.fabricmc.fabric.api.networking.v1.ServerPlayConnectionEvents;
import net.fabricmc.loader.api.FabricLoader;
import net.minecraft.commands.CommandSourceStack;
import net.minecraft.server.level.ServerPlayer;
import org.geysermc.geyser.GeyserImpl;
import org.geysermc.geyser.adapters.CommandManagerAdapter;
import org.geysermc.geyser.adapters.PlatformAdapters;
import org.geysermc.geyser.command.CommandRegistry;
import org.geysermc.geyser.command.CommandSourceConverter;
import org.geysermc.geyser.command.GeyserCommandSource;
import org.geysermc.geyser.command.standalone.StandaloneCloudCommandManager;
import org.geysermc.geyser.platform.mod.GeyserModBootstrap;
import org.geysermc.geyser.platform.mod.GeyserModUpdateListener;
import org.geysermc.geyser.platform.mod.command.ModCommandSource;
import org.geysermc.geyser.text.ChatColor;
import org.incendo.cloud.CommandManager;
import org.incendo.cloud.execution.ExecutionCoordinator;
import org.incendo.cloud.fabric.FabricServerCommandManager;

public class GeyserFabricBootstrap extends GeyserModBootstrap implements ModInitializer {

Expand All @@ -52,6 +53,12 @@ public GeyserFabricBootstrap() {

@Override
public void onInitialize() {
// We love workarounds! Fabric doesn't allow us to have out adapters init before this, so we'll force it!
FabricLoader.getInstance().getEntrypointContainers("geyser:adapter", ModInitializer.class)
.forEach(entrypoint -> entrypoint.getEntrypoint().onInitialize());

CommandManagerAdapter<?, ?> commandManagerAdapter = PlatformAdapters.getCommandManagerAdapter();

if (isServer()) {
// Set as an event, so we can get the proper IP and port if needed
ServerLifecycleEvents.SERVER_STARTED.register((server) -> {
Expand All @@ -73,22 +80,28 @@ public void onInitialize() {
}
});

ServerPlayConnectionEvents.JOIN.register((handler, $, $$) -> GeyserModUpdateListener.onPlayReady(handler.getPlayer()));
ServerPlayConnectionEvents.JOIN.register((handler, $, $$) -> {
ServerPlayer player = handler.getPlayer();

GeyserModUpdateListener.onPlayReady(player, commandManagerAdapter);
});

this.onGeyserInitialize();

var sourceConverter = CommandSourceConverter.layered(
CommandSourceStack.class,
id -> getServer().getPlayerList().getPlayer(id),
ServerPlayer::createCommandSourceStack,
() -> getServer().createCommandSourceStack(), // NPE if method reference is used, since server is not available yet
ModCommandSource::new
);
CommandManager<GeyserCommandSource> cloud = new FabricServerCommandManager<>(
ExecutionCoordinator.simpleCoordinator(),
sourceConverter
);
this.setCommandRegistry(new CommandRegistry(GeyserImpl.getInstance(), cloud, false)); // applying root permission would be a breaking change because we can't register permission defaults
CommandManager<GeyserCommandSource> cloud;

if (commandManagerAdapter != null) {
cloud = commandManagerAdapter.getCommandManager(
ModCommandSource::new,
CommandSourceConverter::layered,
message -> GeyserImpl.getInstance().getLogger().info(ChatColor.toANSI(message + ChatColor.RESET))
);
} else { // Fallback to the standalone manager, this *shouldn't* happen, since there should be an adapter for all versions of Minecraft this will load on
cloud = new StandaloneCloudCommandManager(GeyserImpl.getInstance());
GeyserImpl.getInstance().getLogger().warning("No CommandManagerAdapter was found. Permissions will be handled by a standalone file. Commands will only be accessible to Geyser users.");
}

this.setCommandRegistry(new CommandRegistry(GeyserImpl.getInstance(), cloud));
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,22 +67,27 @@ public GeyserFabricDumpInfo(MinecraftServer server) {
this.mods = new ArrayList<>();

for (ModContainer mod : FabricLoader.getInstance().getAllMods()) {
ModMetadata meta = mod.getMetadata();
this.mods.add(new ModInfo(
FabricLoader.getInstance().isModLoaded(meta.getId()),
meta.getId(),
meta.getVersion().getFriendlyString(),
meta.getAuthors().stream().map(Person::getName).collect(Collectors.toList()))
);
if (mod.getContainingMod().isPresent()) continue;
this.mods.add(getModInfo(mod));
}
}

public ModInfo getModInfo(ModContainer mod) {
ModMetadata meta = mod.getMetadata();
return new ModInfo(
meta.getId(),
meta.getVersion().getFriendlyString(),
meta.getAuthors().stream().map(Person::getName).collect(Collectors.toList()),
mod.getContainedMods().stream().map(this::getModInfo).collect(Collectors.toList())
);
}

@Getter
@AllArgsConstructor
public static class ModInfo {
public boolean enabled;
public String name;
public String version;
public List<String> authors;
public List<ModInfo> submods;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,11 @@ public boolean testFloodgatePluginPresent(@NonNull GeyserModBootstrap bootstrap)
return false;
}

@Override
public boolean testViaPresent(@NonNull GeyserModBootstrap bootstrap) {
return FabricLoader.getInstance().isModLoaded("viafabric");
}

@Override
public @Nullable InputStream resolveResource(@NonNull String resource) {
// We need to handle this differently, because Fabric shares the classloader across multiple mods
Expand Down
2 changes: 1 addition & 1 deletion bootstrap/mod/fabric/src/main/resources/fabric.mod.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,6 @@
"depends": {
"fabricloader": ">=0.16.7",
"fabric-api": "*",
"minecraft": ">=1.21.6"
"minecraft": ">=1.20.6"
}
}
5 changes: 5 additions & 0 deletions bootstrap/mod/neoforge/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,11 @@ dependencies {
// Include all transitive deps of core via JiJ
includeTransitive(projects.core)

compileOnly(libs.adapters)
include(libs.adapters)
include(libs.adapters.neoforge.v1215)
include(libs.adapters.neoforge.v1206)

modImplementation(libs.cloud.neoforge)
include(libs.cloud.neoforge)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@

package org.geysermc.geyser.platform.neoforge;

import net.minecraft.commands.CommandSourceStack;
import net.minecraft.server.level.ServerPlayer;
import net.neoforged.bus.api.EventPriority;
import net.neoforged.fml.ModContainer;
Expand All @@ -37,24 +36,31 @@
import net.neoforged.neoforge.event.server.ServerStartedEvent;
import net.neoforged.neoforge.event.server.ServerStoppingEvent;
import net.neoforged.neoforge.server.permission.events.PermissionGatherEvent;
import org.geysermc.geyser.GeyserImpl;
import org.geysermc.geyser.adapters.CommandManagerAdapter;
import org.geysermc.geyser.adapters.PlatformAdapters;
import org.geysermc.geyser.api.event.lifecycle.GeyserRegisterPermissionsEvent;
import org.geysermc.geyser.command.CommandSourceConverter;
import org.geysermc.geyser.command.GeyserCommandSource;
import org.geysermc.geyser.command.standalone.StandaloneCloudCommandManager;
import org.geysermc.geyser.platform.mod.GeyserModBootstrap;
import org.geysermc.geyser.platform.mod.GeyserModUpdateListener;
import org.geysermc.geyser.platform.mod.command.ModCommandSource;
import org.geysermc.geyser.text.ChatColor;
import org.incendo.cloud.CommandManager;
import org.incendo.cloud.execution.ExecutionCoordinator;
import org.incendo.cloud.neoforge.NeoForgeServerCommandManager;

import java.util.Objects;

@Mod(ModConstants.MOD_ID)
public class GeyserNeoForgeBootstrap extends GeyserModBootstrap {

private final CommandManagerAdapter<?, ?> commandManagerAdapter;

public GeyserNeoForgeBootstrap(ModContainer container) {
super(new GeyserNeoForgePlatform(container));

commandManagerAdapter = PlatformAdapters.getCommandManagerAdapter();

if (isServer()) {
// Set as an event so we can get the proper IP and port if needed
NeoForge.EVENT_BUS.addListener(this::onServerStarted);
Expand All @@ -69,18 +75,21 @@ public GeyserNeoForgeBootstrap(ModContainer container) {

this.onGeyserInitialize();

var sourceConverter = CommandSourceConverter.layered(
CommandSourceStack.class,
id -> getServer().getPlayerList().getPlayer(id),
ServerPlayer::createCommandSourceStack,
() -> getServer().createCommandSourceStack(),
ModCommandSource::new
);
CommandManager<GeyserCommandSource> cloud = new NeoForgeServerCommandManager<>(
ExecutionCoordinator.simpleCoordinator(),
sourceConverter
);
GeyserNeoForgeCommandRegistry registry = new GeyserNeoForgeCommandRegistry(getGeyser(), cloud);
CommandManager<GeyserCommandSource> cloud;

if (commandManagerAdapter != null) {
cloud = commandManagerAdapter.getCommandManager(
ModCommandSource::new,
CommandSourceConverter::layered,
message -> GeyserImpl.getInstance().getLogger().info(ChatColor.toANSI(message + ChatColor.RESET))
);
} else { // Fallback to the standalone manager, this *shouldn't* happen, since there should be an adapter for all versions of Minecraft this will load on
cloud = new StandaloneCloudCommandManager(GeyserImpl.getInstance());
GeyserImpl.getInstance().getLogger().warning("No CommandManagerAdapter was found. Permissions will be handled by a standalone file. Commands will only be accessible to Geyser users.");
}

GeyserNeoForgeCommandRegistry registry = new GeyserNeoForgeCommandRegistry(GeyserImpl.getInstance(), cloud);

this.setCommandRegistry(registry);
// An auxiliary listener for registering undefined permissions belonging to commands. See javadocs for more info.
NeoForge.EVENT_BUS.addListener(EventPriority.LOWEST, registry::onPermissionGatherForUndefined);
Expand All @@ -105,7 +114,7 @@ private void onClientStopping(GameShuttingDownEvent ignored) {

private void onPlayerJoin(PlayerEvent.PlayerLoggedInEvent event) {
if (event.getEntity() instanceof ServerPlayer player) {
GeyserModUpdateListener.onPlayReady(player);
GeyserModUpdateListener.onPlayReady(player, commandManagerAdapter);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,20 +65,18 @@ public GeyserNeoForgeDumpInfo(MinecraftServer server) {

for (IModInfo mod : ModList.get().getMods()) {
this.mods.add(new ModInfo(
ModList.get().isLoaded(mod.getModId()),
mod.getModId(),
mod.getVersion().toString(),
mod.getModURL().map(URL::toString).orElse("")
mod.getModId(),
mod.getVersion().toString(),
mod.getModURL().map(URL::toString).orElse("")
));
}
}

@Getter
@AllArgsConstructor
public static class ModInfo {
public boolean enabled;
public String name;
public String version;
public String url;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,11 @@ public boolean testFloodgatePluginPresent(@NonNull GeyserModBootstrap bootstrap)
return false;
}

@Override
public boolean testViaPresent(@NonNull GeyserModBootstrap bootstrap) {
return ModList.get().isLoaded("viaforge");
}

@Override
public @Nullable InputStream resolveResource(@NonNull String resource) {
try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,12 @@ config = "geyser_neoforge.mixins.json"
[[dependencies.geyser_neoforge]]
modId="neoforge"
type="required"
versionRange="[21.6.0-beta,)"
versionRange="[20.6.0-beta,)"
ordering="NONE"
side="BOTH"
[[dependencies.geyser_neoforge]]
modId="minecraft"
type="required"
versionRange="[1.21.6,)"
versionRange="[1.20.6,)"
ordering="NONE"
side="BOTH"
Loading
Loading